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 <unordered_map> 12 #include <unordered_set> 13 14 #include "src/objects-inl.h" 15 16 #include "src/accessors.h" 17 #include "src/allocation-site-scopes.h" 18 #include "src/api-arguments-inl.h" 19 #include "src/api-natives.h" 20 #include "src/api.h" 21 #include "src/arguments.h" 22 #include "src/base/bits.h" 23 #include "src/base/utils/random-number-generator.h" 24 #include "src/bootstrapper.h" 25 #include "src/code-stubs.h" 26 #include "src/codegen.h" 27 #include "src/compilation-dependencies.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-evaluate.h" 33 #include "src/debug/debug.h" 34 #include "src/deoptimizer.h" 35 #include "src/elements.h" 36 #include "src/execution.h" 37 #include "src/field-index-inl.h" 38 #include "src/field-index.h" 39 #include "src/field-type.h" 40 #include "src/frames-inl.h" 41 #include "src/full-codegen/full-codegen.h" 42 #include "src/globals.h" 43 #include "src/ic/ic.h" 44 #include "src/identity-map.h" 45 #include "src/interpreter/bytecode-array-iterator.h" 46 #include "src/interpreter/bytecode-decoder.h" 47 #include "src/interpreter/interpreter.h" 48 #include "src/isolate-inl.h" 49 #include "src/keys.h" 50 #include "src/list.h" 51 #include "src/log.h" 52 #include "src/lookup.h" 53 #include "src/macro-assembler.h" 54 #include "src/map-updater.h" 55 #include "src/messages.h" 56 #include "src/objects-body-descriptors-inl.h" 57 #include "src/property-descriptor.h" 58 #include "src/prototype.h" 59 #include "src/regexp/jsregexp.h" 60 #include "src/safepoint-table.h" 61 #include "src/snapshot/code-serializer.h" 62 #include "src/source-position-table.h" 63 #include "src/string-builder.h" 64 #include "src/string-search.h" 65 #include "src/string-stream.h" 66 #include "src/utils.h" 67 #include "src/wasm/wasm-module.h" 68 #include "src/wasm/wasm-objects.h" 69 #include "src/zone/zone.h" 70 71 #ifdef ENABLE_DISASSEMBLER 72 #include "src/disasm.h" 73 #include "src/disassembler.h" 74 #include "src/eh-frame.h" 75 #endif 76 77 namespace v8 { 78 namespace internal { 79 80 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) { 81 switch (instance_type) { 82 #define WRITE_TYPE(TYPE) \ 83 case TYPE: \ 84 return os << #TYPE; 85 INSTANCE_TYPE_LIST(WRITE_TYPE) 86 #undef WRITE_TYPE 87 } 88 UNREACHABLE(); 89 return os << "UNKNOWN"; // Keep the compiler happy. 90 } 91 92 Handle<FieldType> Object::OptimalType(Isolate* isolate, 93 Representation representation) { 94 if (representation.IsNone()) return FieldType::None(isolate); 95 if (FLAG_track_field_types) { 96 if (representation.IsHeapObject() && IsHeapObject()) { 97 // We can track only JavaScript objects with stable maps. 98 Handle<Map> map(HeapObject::cast(this)->map(), isolate); 99 if (map->is_stable() && map->IsJSReceiverMap()) { 100 return FieldType::Class(map, isolate); 101 } 102 } 103 } 104 return FieldType::Any(isolate); 105 } 106 107 108 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate, 109 Handle<Object> object, 110 Handle<Context> native_context) { 111 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 112 Handle<JSFunction> constructor; 113 if (object->IsSmi()) { 114 constructor = handle(native_context->number_function(), isolate); 115 } else { 116 int constructor_function_index = 117 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex(); 118 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 119 THROW_NEW_ERROR(isolate, 120 NewTypeError(MessageTemplate::kUndefinedOrNullToObject), 121 JSReceiver); 122 } 123 constructor = handle( 124 JSFunction::cast(native_context->get(constructor_function_index)), 125 isolate); 126 } 127 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); 128 Handle<JSValue>::cast(result)->set_value(*object); 129 return result; 130 } 131 132 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. 133 // static 134 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate, 135 Handle<Object> object) { 136 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 137 if (*object == isolate->heap()->null_value() || 138 object->IsUndefined(isolate)) { 139 return isolate->global_proxy(); 140 } 141 return Object::ToObject(isolate, object); 142 } 143 144 // static 145 MaybeHandle<Object> Object::ConvertToNumber(Isolate* isolate, 146 Handle<Object> input) { 147 while (true) { 148 if (input->IsNumber()) { 149 return input; 150 } 151 if (input->IsString()) { 152 return String::ToNumber(Handle<String>::cast(input)); 153 } 154 if (input->IsOddball()) { 155 return Oddball::ToNumber(Handle<Oddball>::cast(input)); 156 } 157 if (input->IsSymbol()) { 158 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), 159 Object); 160 } 161 ASSIGN_RETURN_ON_EXCEPTION( 162 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), 163 ToPrimitiveHint::kNumber), 164 Object); 165 } 166 } 167 168 // static 169 MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate, 170 Handle<Object> input) { 171 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input), 172 Object); 173 if (input->IsSmi()) return input; 174 return isolate->factory()->NewNumber(DoubleToInteger(input->Number())); 175 } 176 177 // static 178 MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate, 179 Handle<Object> input) { 180 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input), 181 Object); 182 if (input->IsSmi()) return input; 183 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number())); 184 } 185 186 // static 187 MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate, 188 Handle<Object> input) { 189 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input), 190 Object); 191 if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate); 192 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number())); 193 } 194 195 // static 196 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate, 197 Handle<Object> input) { 198 ASSIGN_RETURN_ON_EXCEPTION( 199 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString), 200 Name); 201 if (input->IsName()) return Handle<Name>::cast(input); 202 return ToString(isolate, input); 203 } 204 205 // ES6 7.1.14 206 // static 207 MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate, 208 Handle<Object> value) { 209 // 1. Let key be ToPrimitive(argument, hint String). 210 MaybeHandle<Object> maybe_key = 211 Object::ToPrimitive(value, ToPrimitiveHint::kString); 212 // 2. ReturnIfAbrupt(key). 213 Handle<Object> key; 214 if (!maybe_key.ToHandle(&key)) return key; 215 // 3. If Type(key) is Symbol, then return key. 216 if (key->IsSymbol()) return key; 217 // 4. Return ToString(key). 218 // Extending spec'ed behavior, we'd be happy to return an element index. 219 if (key->IsSmi()) return key; 220 if (key->IsHeapNumber()) { 221 uint32_t uint_value; 222 if (value->ToArrayLength(&uint_value) && 223 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) { 224 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate); 225 } 226 } 227 return Object::ToString(isolate, key); 228 } 229 230 // static 231 MaybeHandle<String> Object::ConvertToString(Isolate* isolate, 232 Handle<Object> input) { 233 while (true) { 234 if (input->IsOddball()) { 235 return handle(Handle<Oddball>::cast(input)->to_string(), isolate); 236 } 237 if (input->IsNumber()) { 238 return isolate->factory()->NumberToString(input); 239 } 240 if (input->IsSymbol()) { 241 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString), 242 String); 243 } 244 ASSIGN_RETURN_ON_EXCEPTION( 245 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), 246 ToPrimitiveHint::kString), 247 String); 248 // The previous isString() check happened in Object::ToString and thus we 249 // put it at the end of the loop in this helper. 250 if (input->IsString()) { 251 return Handle<String>::cast(input); 252 } 253 } 254 } 255 256 namespace { 257 258 bool IsErrorObject(Isolate* isolate, Handle<Object> object) { 259 if (!object->IsJSReceiver()) return false; 260 Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol(); 261 return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol) 262 .FromMaybe(false); 263 } 264 265 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) { 266 return object->IsString() ? Handle<String>::cast(object) 267 : isolate->factory()->empty_string(); 268 } 269 270 Handle<String> NoSideEffectsErrorToString(Isolate* isolate, 271 Handle<Object> input) { 272 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); 273 274 Handle<Name> name_key = isolate->factory()->name_string(); 275 Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key); 276 Handle<String> name_str = AsStringOrEmpty(isolate, name); 277 278 Handle<Name> msg_key = isolate->factory()->message_string(); 279 Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key); 280 Handle<String> msg_str = AsStringOrEmpty(isolate, msg); 281 282 if (name_str->length() == 0) return msg_str; 283 if (msg_str->length() == 0) return name_str; 284 285 IncrementalStringBuilder builder(isolate); 286 builder.AppendString(name_str); 287 builder.AppendCString(": "); 288 builder.AppendString(msg_str); 289 290 return builder.Finish().ToHandleChecked(); 291 } 292 293 } // namespace 294 295 // static 296 Handle<String> Object::NoSideEffectsToString(Isolate* isolate, 297 Handle<Object> input) { 298 DisallowJavascriptExecution no_js(isolate); 299 300 if (input->IsString() || input->IsNumber() || input->IsOddball()) { 301 return Object::ToString(isolate, input).ToHandleChecked(); 302 } else if (input->IsFunction()) { 303 // -- F u n c t i o n 304 Handle<String> fun_str; 305 if (input->IsJSBoundFunction()) { 306 fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input)); 307 } else { 308 DCHECK(input->IsJSFunction()); 309 fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input)); 310 } 311 312 if (fun_str->length() > 128) { 313 IncrementalStringBuilder builder(isolate); 314 builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111)); 315 builder.AppendCString("...<omitted>..."); 316 builder.AppendString(isolate->factory()->NewSubString( 317 fun_str, fun_str->length() - 2, fun_str->length())); 318 319 return builder.Finish().ToHandleChecked(); 320 } 321 return fun_str; 322 } else if (input->IsSymbol()) { 323 // -- S y m b o l 324 Handle<Symbol> symbol = Handle<Symbol>::cast(input); 325 326 IncrementalStringBuilder builder(isolate); 327 builder.AppendCString("Symbol("); 328 if (symbol->name()->IsString()) { 329 builder.AppendString(handle(String::cast(symbol->name()), isolate)); 330 } 331 builder.AppendCharacter(')'); 332 333 return builder.Finish().ToHandleChecked(); 334 } else if (input->IsJSReceiver()) { 335 // -- J S R e c e i v e r 336 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); 337 Handle<Object> to_string = JSReceiver::GetDataProperty( 338 receiver, isolate->factory()->toString_string()); 339 340 if (IsErrorObject(isolate, input) || 341 *to_string == *isolate->error_to_string()) { 342 // When internally formatting error objects, use a side-effects-free 343 // version of Error.prototype.toString independent of the actually 344 // installed toString method. 345 return NoSideEffectsErrorToString(isolate, input); 346 } else if (*to_string == *isolate->object_to_string()) { 347 Handle<Object> ctor = JSReceiver::GetDataProperty( 348 receiver, isolate->factory()->constructor_string()); 349 if (ctor->IsFunction()) { 350 Handle<String> ctor_name; 351 if (ctor->IsJSBoundFunction()) { 352 ctor_name = JSBoundFunction::GetName( 353 isolate, Handle<JSBoundFunction>::cast(ctor)) 354 .ToHandleChecked(); 355 } else if (ctor->IsJSFunction()) { 356 Handle<Object> ctor_name_obj = 357 JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor)); 358 ctor_name = AsStringOrEmpty(isolate, ctor_name_obj); 359 } 360 361 if (ctor_name->length() != 0) { 362 IncrementalStringBuilder builder(isolate); 363 builder.AppendCString("#<"); 364 builder.AppendString(ctor_name); 365 builder.AppendCString(">"); 366 367 return builder.Finish().ToHandleChecked(); 368 } 369 } 370 } 371 } 372 373 // At this point, input is either none of the above or a JSReceiver. 374 375 Handle<JSReceiver> receiver; 376 if (input->IsJSReceiver()) { 377 receiver = Handle<JSReceiver>::cast(input); 378 } else { 379 // This is the only case where Object::ToObject throws. 380 DCHECK(!input->IsSmi()); 381 int constructor_function_index = 382 Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex(); 383 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 384 return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]"); 385 } 386 387 receiver = Object::ToObject(isolate, input, isolate->native_context()) 388 .ToHandleChecked(); 389 } 390 391 Handle<String> builtin_tag = handle(receiver->class_name(), isolate); 392 Handle<Object> tag_obj = JSReceiver::GetDataProperty( 393 receiver, isolate->factory()->to_string_tag_symbol()); 394 Handle<String> tag = 395 tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag; 396 397 IncrementalStringBuilder builder(isolate); 398 builder.AppendCString("[object "); 399 builder.AppendString(tag); 400 builder.AppendCString("]"); 401 402 return builder.Finish().ToHandleChecked(); 403 } 404 405 // static 406 MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate, 407 Handle<Object> input) { 408 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 409 if (input->IsSmi()) { 410 int value = std::max(Smi::cast(*input)->value(), 0); 411 return handle(Smi::FromInt(value), isolate); 412 } 413 double len = DoubleToInteger(input->Number()); 414 if (len <= 0.0) { 415 return handle(Smi::kZero, isolate); 416 } else if (len >= kMaxSafeInteger) { 417 len = kMaxSafeInteger; 418 } 419 return isolate->factory()->NewNumber(len); 420 } 421 422 // static 423 MaybeHandle<Object> Object::ConvertToIndex( 424 Isolate* isolate, Handle<Object> input, 425 MessageTemplate::Template error_index) { 426 if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate); 427 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 428 if (input->IsSmi() && Smi::cast(*input)->value() >= 0) return input; 429 double len = DoubleToInteger(input->Number()) + 0.0; 430 auto js_len = isolate->factory()->NewNumber(len); 431 if (len < 0.0 || len > kMaxSafeInteger) { 432 THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object); 433 } 434 return js_len; 435 } 436 437 bool Object::BooleanValue() { 438 if (IsSmi()) return Smi::cast(this)->value() != 0; 439 DCHECK(IsHeapObject()); 440 Isolate* isolate = HeapObject::cast(this)->GetIsolate(); 441 if (IsBoolean()) return IsTrue(isolate); 442 if (IsNullOrUndefined(isolate)) return false; 443 if (IsUndetectable()) return false; // Undetectable object is false. 444 if (IsString()) return String::cast(this)->length() != 0; 445 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue(); 446 return true; 447 } 448 449 450 namespace { 451 452 // TODO(bmeurer): Maybe we should introduce a marker interface Number, 453 // where we put all these methods at some point? 454 ComparisonResult NumberCompare(double x, double y) { 455 if (std::isnan(x) || std::isnan(y)) { 456 return ComparisonResult::kUndefined; 457 } else if (x < y) { 458 return ComparisonResult::kLessThan; 459 } else if (x > y) { 460 return ComparisonResult::kGreaterThan; 461 } else { 462 return ComparisonResult::kEqual; 463 } 464 } 465 466 467 bool NumberEquals(double x, double y) { 468 // Must check explicitly for NaN's on Windows, but -0 works fine. 469 if (std::isnan(x)) return false; 470 if (std::isnan(y)) return false; 471 return x == y; 472 } 473 474 475 bool NumberEquals(const Object* x, const Object* y) { 476 return NumberEquals(x->Number(), y->Number()); 477 } 478 479 480 bool NumberEquals(Handle<Object> x, Handle<Object> y) { 481 return NumberEquals(*x, *y); 482 } 483 484 } // namespace 485 486 487 // static 488 Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) { 489 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4. 490 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) || 491 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) { 492 return Nothing<ComparisonResult>(); 493 } 494 if (x->IsString() && y->IsString()) { 495 // ES6 section 7.2.11 Abstract Relational Comparison step 5. 496 return Just( 497 String::Compare(Handle<String>::cast(x), Handle<String>::cast(y))); 498 } 499 // ES6 section 7.2.11 Abstract Relational Comparison step 6. 500 if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) { 501 return Nothing<ComparisonResult>(); 502 } 503 return Just(NumberCompare(x->Number(), y->Number())); 504 } 505 506 507 // static 508 Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) { 509 // This is the generic version of Abstract Equality Comparison; a version in 510 // JavaScript land is available in the EqualStub and NotEqualStub. Whenever 511 // you change something functionality wise in here, remember to update the 512 // TurboFan code stubs as well. 513 while (true) { 514 if (x->IsNumber()) { 515 if (y->IsNumber()) { 516 return Just(NumberEquals(x, y)); 517 } else if (y->IsBoolean()) { 518 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 519 } else if (y->IsString()) { 520 return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y)))); 521 } else if (y->IsJSReceiver()) { 522 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 523 .ToHandle(&y)) { 524 return Nothing<bool>(); 525 } 526 } else { 527 return Just(false); 528 } 529 } else if (x->IsString()) { 530 if (y->IsString()) { 531 return Just( 532 String::Equals(Handle<String>::cast(x), Handle<String>::cast(y))); 533 } else if (y->IsNumber()) { 534 x = String::ToNumber(Handle<String>::cast(x)); 535 return Just(NumberEquals(x, y)); 536 } else if (y->IsBoolean()) { 537 x = String::ToNumber(Handle<String>::cast(x)); 538 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 539 } else if (y->IsJSReceiver()) { 540 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 541 .ToHandle(&y)) { 542 return Nothing<bool>(); 543 } 544 } else { 545 return Just(false); 546 } 547 } else if (x->IsBoolean()) { 548 if (y->IsOddball()) { 549 return Just(x.is_identical_to(y)); 550 } else if (y->IsNumber()) { 551 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 552 } else if (y->IsString()) { 553 y = String::ToNumber(Handle<String>::cast(y)); 554 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 555 } else if (y->IsJSReceiver()) { 556 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 557 .ToHandle(&y)) { 558 return Nothing<bool>(); 559 } 560 x = Oddball::ToNumber(Handle<Oddball>::cast(x)); 561 } else { 562 return Just(false); 563 } 564 } else if (x->IsSymbol()) { 565 if (y->IsSymbol()) { 566 return Just(x.is_identical_to(y)); 567 } else if (y->IsJSReceiver()) { 568 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 569 .ToHandle(&y)) { 570 return Nothing<bool>(); 571 } 572 } else { 573 return Just(false); 574 } 575 } else if (x->IsJSReceiver()) { 576 if (y->IsJSReceiver()) { 577 return Just(x.is_identical_to(y)); 578 } else if (y->IsUndetectable()) { 579 return Just(x->IsUndetectable()); 580 } else if (y->IsBoolean()) { 581 y = Oddball::ToNumber(Handle<Oddball>::cast(y)); 582 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x)) 583 .ToHandle(&x)) { 584 return Nothing<bool>(); 585 } 586 } else { 587 return Just(x->IsUndetectable() && y->IsUndetectable()); 588 } 589 } 590 } 591 592 593 bool Object::StrictEquals(Object* that) { 594 if (this->IsNumber()) { 595 if (!that->IsNumber()) return false; 596 return NumberEquals(this, that); 597 } else if (this->IsString()) { 598 if (!that->IsString()) return false; 599 return String::cast(this)->Equals(String::cast(that)); 600 } 601 return this == that; 602 } 603 604 605 // static 606 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) { 607 if (object->IsNumber()) return isolate->factory()->number_string(); 608 if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of()); 609 if (object->IsUndetectable()) { 610 return isolate->factory()->undefined_string(); 611 } 612 if (object->IsString()) return isolate->factory()->string_string(); 613 if (object->IsSymbol()) return isolate->factory()->symbol_string(); 614 if (object->IsString()) return isolate->factory()->string_string(); 615 if (object->IsCallable()) return isolate->factory()->function_string(); 616 return isolate->factory()->object_string(); 617 } 618 619 620 // static 621 MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs, 622 Handle<Object> rhs) { 623 if (!lhs->IsNumber() || !rhs->IsNumber()) { 624 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 625 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 626 } 627 return isolate->factory()->NewNumber(lhs->Number() * rhs->Number()); 628 } 629 630 631 // static 632 MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs, 633 Handle<Object> rhs) { 634 if (!lhs->IsNumber() || !rhs->IsNumber()) { 635 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 636 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 637 } 638 return isolate->factory()->NewNumber(lhs->Number() / rhs->Number()); 639 } 640 641 642 // static 643 MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs, 644 Handle<Object> rhs) { 645 if (!lhs->IsNumber() || !rhs->IsNumber()) { 646 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 647 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 648 } 649 return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number())); 650 } 651 652 653 // static 654 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs, 655 Handle<Object> rhs) { 656 if (lhs->IsNumber() && rhs->IsNumber()) { 657 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 658 } else if (lhs->IsString() && rhs->IsString()) { 659 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 660 Handle<String>::cast(rhs)); 661 } 662 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object); 663 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object); 664 if (lhs->IsString() || rhs->IsString()) { 665 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs), 666 Object); 667 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs), 668 Object); 669 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 670 Handle<String>::cast(rhs)); 671 } 672 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 673 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 674 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 675 } 676 677 678 // static 679 MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs, 680 Handle<Object> rhs) { 681 if (!lhs->IsNumber() || !rhs->IsNumber()) { 682 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 683 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 684 } 685 return isolate->factory()->NewNumber(lhs->Number() - rhs->Number()); 686 } 687 688 689 // static 690 MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs, 691 Handle<Object> rhs) { 692 if (!lhs->IsNumber() || !rhs->IsNumber()) { 693 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 694 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 695 } 696 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) 697 << (NumberToUint32(*rhs) & 0x1F)); 698 } 699 700 701 // static 702 MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs, 703 Handle<Object> rhs) { 704 if (!lhs->IsNumber() || !rhs->IsNumber()) { 705 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 706 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 707 } 708 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >> 709 (NumberToUint32(*rhs) & 0x1F)); 710 } 711 712 713 // static 714 MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate, 715 Handle<Object> lhs, 716 Handle<Object> rhs) { 717 if (!lhs->IsNumber() || !rhs->IsNumber()) { 718 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 719 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 720 } 721 return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >> 722 (NumberToUint32(*rhs) & 0x1F)); 723 } 724 725 726 // static 727 MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs, 728 Handle<Object> rhs) { 729 if (!lhs->IsNumber() || !rhs->IsNumber()) { 730 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 731 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 732 } 733 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) & 734 NumberToInt32(*rhs)); 735 } 736 737 738 // static 739 MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs, 740 Handle<Object> rhs) { 741 if (!lhs->IsNumber() || !rhs->IsNumber()) { 742 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 743 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 744 } 745 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) | 746 NumberToInt32(*rhs)); 747 } 748 749 750 // static 751 MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs, 752 Handle<Object> rhs) { 753 if (!lhs->IsNumber() || !rhs->IsNumber()) { 754 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 755 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 756 } 757 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^ 758 NumberToInt32(*rhs)); 759 } 760 761 // static 762 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate, 763 Handle<Object> callable, 764 Handle<Object> object) { 765 // The {callable} must have a [[Call]] internal method. 766 if (!callable->IsCallable()) return isolate->factory()->false_value(); 767 768 // Check if {callable} is a bound function, and if so retrieve its 769 // [[BoundTargetFunction]] and use that instead of {callable}. 770 if (callable->IsJSBoundFunction()) { 771 Handle<Object> bound_callable( 772 Handle<JSBoundFunction>::cast(callable)->bound_target_function(), 773 isolate); 774 return Object::InstanceOf(isolate, object, bound_callable); 775 } 776 777 // If {object} is not a receiver, return false. 778 if (!object->IsJSReceiver()) return isolate->factory()->false_value(); 779 780 // Get the "prototype" of {callable}; raise an error if it's not a receiver. 781 Handle<Object> prototype; 782 ASSIGN_RETURN_ON_EXCEPTION( 783 isolate, prototype, 784 Object::GetProperty(callable, isolate->factory()->prototype_string()), 785 Object); 786 if (!prototype->IsJSReceiver()) { 787 THROW_NEW_ERROR( 788 isolate, 789 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype), 790 Object); 791 } 792 793 // Return whether or not {prototype} is in the prototype chain of {object}. 794 Maybe<bool> result = JSReceiver::HasInPrototypeChain( 795 isolate, Handle<JSReceiver>::cast(object), prototype); 796 if (result.IsNothing()) return MaybeHandle<Object>(); 797 return isolate->factory()->ToBoolean(result.FromJust()); 798 } 799 800 // static 801 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object, 802 Handle<Object> callable) { 803 // The {callable} must be a receiver. 804 if (!callable->IsJSReceiver()) { 805 THROW_NEW_ERROR(isolate, 806 NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck), 807 Object); 808 } 809 810 // Lookup the @@hasInstance method on {callable}. 811 Handle<Object> inst_of_handler; 812 ASSIGN_RETURN_ON_EXCEPTION( 813 isolate, inst_of_handler, 814 JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable), 815 isolate->factory()->has_instance_symbol()), 816 Object); 817 if (!inst_of_handler->IsUndefined(isolate)) { 818 // Call the {inst_of_handler} on the {callable}. 819 Handle<Object> result; 820 ASSIGN_RETURN_ON_EXCEPTION( 821 isolate, result, 822 Execution::Call(isolate, inst_of_handler, callable, 1, &object), 823 Object); 824 return isolate->factory()->ToBoolean(result->BooleanValue()); 825 } 826 827 // The {callable} must have a [[Call]] internal method. 828 if (!callable->IsCallable()) { 829 THROW_NEW_ERROR( 830 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck), 831 Object); 832 } 833 834 // Fall back to OrdinaryHasInstance with {callable} and {object}. 835 Handle<Object> result; 836 ASSIGN_RETURN_ON_EXCEPTION( 837 isolate, result, 838 JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object); 839 return result; 840 } 841 842 Maybe<bool> Object::IsArray(Handle<Object> object) { 843 if (object->IsJSArray()) return Just(true); 844 if (object->IsJSProxy()) { 845 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object); 846 Isolate* isolate = proxy->GetIsolate(); 847 if (proxy->IsRevoked()) { 848 isolate->Throw(*isolate->factory()->NewTypeError( 849 MessageTemplate::kProxyRevoked, 850 isolate->factory()->NewStringFromAsciiChecked("IsArray"))); 851 return Nothing<bool>(); 852 } 853 return Object::IsArray(handle(proxy->target(), isolate)); 854 } 855 return Just(false); 856 } 857 858 859 // static 860 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver, 861 Handle<Name> name) { 862 Handle<Object> func; 863 Isolate* isolate = receiver->GetIsolate(); 864 ASSIGN_RETURN_ON_EXCEPTION(isolate, func, 865 JSReceiver::GetProperty(receiver, name), Object); 866 if (func->IsNullOrUndefined(isolate)) { 867 return isolate->factory()->undefined_value(); 868 } 869 if (!func->IsCallable()) { 870 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction, 871 func, name, receiver), 872 Object); 873 } 874 return func; 875 } 876 877 namespace { 878 MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath( 879 Isolate* isolate, Handle<Object> object, ElementTypes element_types) { 880 if (element_types != ElementTypes::kAll || !object->IsJSArray()) { 881 return MaybeHandle<FixedArray>(); 882 } 883 Handle<JSArray> array = Handle<JSArray>::cast(object); 884 uint32_t length; 885 if (!array->HasArrayPrototype(isolate) || 886 !array->length()->ToUint32(&length) || !array->HasFastElements() || 887 !JSObject::PrototypeHasNoElements(isolate, *array)) { 888 return MaybeHandle<FixedArray>(); 889 } 890 return array->GetElementsAccessor()->CreateListFromArray(isolate, array); 891 } 892 } // namespace 893 894 // static 895 MaybeHandle<FixedArray> Object::CreateListFromArrayLike( 896 Isolate* isolate, Handle<Object> object, ElementTypes element_types) { 897 // Fast-path for JS_ARRAY_TYPE. 898 MaybeHandle<FixedArray> fast_result = 899 CreateListFromArrayLikeFastPath(isolate, object, element_types); 900 if (!fast_result.is_null()) return fast_result; 901 // 1. ReturnIfAbrupt(object). 902 // 2. (default elementTypes -- not applicable.) 903 // 3. If Type(obj) is not Object, throw a TypeError exception. 904 if (!object->IsJSReceiver()) { 905 THROW_NEW_ERROR(isolate, 906 NewTypeError(MessageTemplate::kCalledOnNonObject, 907 isolate->factory()->NewStringFromAsciiChecked( 908 "CreateListFromArrayLike")), 909 FixedArray); 910 } 911 912 // 4. Let len be ? ToLength(? Get(obj, "length")). 913 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); 914 Handle<Object> raw_length_number; 915 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number, 916 Object::GetLengthFromArrayLike(isolate, receiver), 917 FixedArray); 918 uint32_t len; 919 if (!raw_length_number->ToUint32(&len) || 920 len > static_cast<uint32_t>(FixedArray::kMaxLength)) { 921 THROW_NEW_ERROR(isolate, 922 NewRangeError(MessageTemplate::kInvalidArrayLength), 923 FixedArray); 924 } 925 // 5. Let list be an empty List. 926 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len); 927 // 6. Let index be 0. 928 // 7. Repeat while index < len: 929 for (uint32_t index = 0; index < len; ++index) { 930 // 7a. Let indexName be ToString(index). 931 // 7b. Let next be ? Get(obj, indexName). 932 Handle<Object> next; 933 ASSIGN_RETURN_ON_EXCEPTION(isolate, next, 934 JSReceiver::GetElement(isolate, receiver, index), 935 FixedArray); 936 switch (element_types) { 937 case ElementTypes::kAll: 938 // Nothing to do. 939 break; 940 case ElementTypes::kStringAndSymbol: { 941 // 7c. If Type(next) is not an element of elementTypes, throw a 942 // TypeError exception. 943 if (!next->IsName()) { 944 THROW_NEW_ERROR(isolate, 945 NewTypeError(MessageTemplate::kNotPropertyName, next), 946 FixedArray); 947 } 948 // 7d. Append next as the last element of list. 949 // Internalize on the fly so we can use pointer identity later. 950 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next)); 951 break; 952 } 953 } 954 list->set(index, *next); 955 // 7e. Set index to index + 1. (See loop header.) 956 } 957 // 8. Return list. 958 return list; 959 } 960 961 962 // static 963 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate, 964 Handle<Object> object) { 965 Handle<Object> val; 966 Handle<Object> key = isolate->factory()->length_string(); 967 ASSIGN_RETURN_ON_EXCEPTION( 968 isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object); 969 return Object::ToLength(isolate, val); 970 } 971 972 // static 973 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) { 974 for (; it->IsFound(); it->Next()) { 975 switch (it->state()) { 976 case LookupIterator::NOT_FOUND: 977 case LookupIterator::TRANSITION: 978 UNREACHABLE(); 979 case LookupIterator::JSPROXY: 980 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(), 981 it->GetName()); 982 case LookupIterator::INTERCEPTOR: { 983 Maybe<PropertyAttributes> result = 984 JSObject::GetPropertyAttributesWithInterceptor(it); 985 if (result.IsNothing()) return Nothing<bool>(); 986 if (result.FromJust() != ABSENT) return Just(true); 987 break; 988 } 989 case LookupIterator::ACCESS_CHECK: { 990 if (it->HasAccess()) break; 991 Maybe<PropertyAttributes> result = 992 JSObject::GetPropertyAttributesWithFailedAccessCheck(it); 993 if (result.IsNothing()) return Nothing<bool>(); 994 return Just(result.FromJust() != ABSENT); 995 } 996 case LookupIterator::INTEGER_INDEXED_EXOTIC: 997 // TypedArray out-of-bounds access. 998 return Just(false); 999 case LookupIterator::ACCESSOR: 1000 case LookupIterator::DATA: 1001 return Just(true); 1002 } 1003 } 1004 return Just(false); 1005 } 1006 1007 1008 // static 1009 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) { 1010 for (; it->IsFound(); it->Next()) { 1011 switch (it->state()) { 1012 case LookupIterator::NOT_FOUND: 1013 case LookupIterator::TRANSITION: 1014 UNREACHABLE(); 1015 case LookupIterator::JSPROXY: { 1016 bool was_found; 1017 MaybeHandle<Object> result = 1018 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(), 1019 it->GetName(), it->GetReceiver(), &was_found); 1020 if (!was_found) it->NotFound(); 1021 return result; 1022 } 1023 case LookupIterator::INTERCEPTOR: { 1024 bool done; 1025 Handle<Object> result; 1026 ASSIGN_RETURN_ON_EXCEPTION( 1027 it->isolate(), result, 1028 JSObject::GetPropertyWithInterceptor(it, &done), Object); 1029 if (done) return result; 1030 break; 1031 } 1032 case LookupIterator::ACCESS_CHECK: 1033 if (it->HasAccess()) break; 1034 return JSObject::GetPropertyWithFailedAccessCheck(it); 1035 case LookupIterator::ACCESSOR: 1036 return GetPropertyWithAccessor(it); 1037 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1038 return it->isolate()->factory()->undefined_value(); 1039 case LookupIterator::DATA: 1040 return it->GetDataValue(); 1041 } 1042 } 1043 return it->isolate()->factory()->undefined_value(); 1044 } 1045 1046 1047 // static 1048 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate, 1049 Handle<JSProxy> proxy, 1050 Handle<Name> name, 1051 Handle<Object> receiver, 1052 bool* was_found) { 1053 *was_found = true; 1054 if (receiver->IsJSGlobalObject()) { 1055 THROW_NEW_ERROR( 1056 isolate, 1057 NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name), 1058 Object); 1059 } 1060 1061 DCHECK(!name->IsPrivate()); 1062 STACK_CHECK(isolate, MaybeHandle<Object>()); 1063 Handle<Name> trap_name = isolate->factory()->get_string(); 1064 // 1. Assert: IsPropertyKey(P) is true. 1065 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 1066 Handle<Object> handler(proxy->handler(), isolate); 1067 // 3. If handler is null, throw a TypeError exception. 1068 // 4. Assert: Type(handler) is Object. 1069 if (proxy->IsRevoked()) { 1070 THROW_NEW_ERROR(isolate, 1071 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1072 Object); 1073 } 1074 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 1075 Handle<JSReceiver> target(proxy->target(), isolate); 1076 // 6. Let trap be ? GetMethod(handler, "get"). 1077 Handle<Object> trap; 1078 ASSIGN_RETURN_ON_EXCEPTION( 1079 isolate, trap, 1080 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object); 1081 // 7. If trap is undefined, then 1082 if (trap->IsUndefined(isolate)) { 1083 // 7.a Return target.[[Get]](P, Receiver). 1084 LookupIterator it = 1085 LookupIterator::PropertyOrElement(isolate, receiver, name, target); 1086 MaybeHandle<Object> result = Object::GetProperty(&it); 1087 *was_found = it.IsFound(); 1088 return result; 1089 } 1090 // 8. Let trapResult be ? Call(trap, handler, target, P, Receiver). 1091 Handle<Object> trap_result; 1092 Handle<Object> args[] = {target, name, receiver}; 1093 ASSIGN_RETURN_ON_EXCEPTION( 1094 isolate, trap_result, 1095 Execution::Call(isolate, trap, handler, arraysize(args), args), Object); 1096 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). 1097 PropertyDescriptor target_desc; 1098 Maybe<bool> target_found = 1099 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 1100 MAYBE_RETURN_NULL(target_found); 1101 // 10. If targetDesc is not undefined, then 1102 if (target_found.FromJust()) { 1103 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is 1104 // false and targetDesc.[[Writable]] is false, then 1105 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false, 1106 // throw a TypeError exception. 1107 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && 1108 !target_desc.configurable() && 1109 !target_desc.writable() && 1110 !trap_result->SameValue(*target_desc.value()); 1111 if (inconsistent) { 1112 THROW_NEW_ERROR( 1113 isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, 1114 name, target_desc.value(), trap_result), 1115 Object); 1116 } 1117 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] 1118 // is false and targetDesc.[[Get]] is undefined, then 1119 // 10.b.i. If trapResult is not undefined, throw a TypeError exception. 1120 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 1121 !target_desc.configurable() && 1122 target_desc.get()->IsUndefined(isolate) && 1123 !trap_result->IsUndefined(isolate); 1124 if (inconsistent) { 1125 THROW_NEW_ERROR( 1126 isolate, 1127 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name, 1128 trap_result), 1129 Object); 1130 } 1131 } 1132 // 11. Return trap_result 1133 return trap_result; 1134 } 1135 1136 1137 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) { 1138 for (; it->IsFound(); it->Next()) { 1139 switch (it->state()) { 1140 case LookupIterator::INTERCEPTOR: 1141 case LookupIterator::NOT_FOUND: 1142 case LookupIterator::TRANSITION: 1143 UNREACHABLE(); 1144 case LookupIterator::ACCESS_CHECK: 1145 // Support calling this method without an active context, but refuse 1146 // access to access-checked objects in that case. 1147 if (it->isolate()->context() != nullptr && it->HasAccess()) continue; 1148 // Fall through. 1149 case LookupIterator::JSPROXY: 1150 it->NotFound(); 1151 return it->isolate()->factory()->undefined_value(); 1152 case LookupIterator::ACCESSOR: 1153 // TODO(verwaest): For now this doesn't call into AccessorInfo, since 1154 // clients don't need it. Update once relevant. 1155 it->NotFound(); 1156 return it->isolate()->factory()->undefined_value(); 1157 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1158 return it->isolate()->factory()->undefined_value(); 1159 case LookupIterator::DATA: 1160 return it->GetDataValue(); 1161 } 1162 } 1163 return it->isolate()->factory()->undefined_value(); 1164 } 1165 1166 1167 bool Object::ToInt32(int32_t* value) { 1168 if (IsSmi()) { 1169 *value = Smi::cast(this)->value(); 1170 return true; 1171 } 1172 if (IsHeapNumber()) { 1173 double num = HeapNumber::cast(this)->value(); 1174 if (FastI2D(FastD2I(num)) == num) { 1175 *value = FastD2I(num); 1176 return true; 1177 } 1178 } 1179 return false; 1180 } 1181 1182 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( 1183 Isolate* isolate, Handle<FunctionTemplateInfo> info) { 1184 Object* current_info = info->shared_function_info(); 1185 if (current_info->IsSharedFunctionInfo()) { 1186 return handle(SharedFunctionInfo::cast(current_info), isolate); 1187 } 1188 1189 Handle<Object> class_name(info->class_name(), isolate); 1190 Handle<String> name = class_name->IsString() 1191 ? Handle<String>::cast(class_name) 1192 : isolate->factory()->empty_string(); 1193 Handle<Code> code; 1194 if (info->call_code()->IsCallHandlerInfo() && 1195 CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) { 1196 code = isolate->builtins()->HandleFastApiCall(); 1197 } else { 1198 code = isolate->builtins()->HandleApiCall(); 1199 } 1200 bool is_constructor = !info->remove_prototype(); 1201 Handle<SharedFunctionInfo> result = 1202 isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor); 1203 if (is_constructor) { 1204 result->SetConstructStub(*isolate->builtins()->JSConstructStubApi()); 1205 } 1206 1207 result->set_length(info->length()); 1208 if (class_name->IsString()) result->set_instance_class_name(*class_name); 1209 result->set_api_func_data(*info); 1210 result->DontAdaptArguments(); 1211 DCHECK(result->IsApiFunction()); 1212 1213 info->set_shared_function_info(*result); 1214 return result; 1215 } 1216 1217 bool FunctionTemplateInfo::IsTemplateFor(Map* map) { 1218 // There is a constraint on the object; check. 1219 if (!map->IsJSObjectMap()) return false; 1220 // Fetch the constructor function of the object. 1221 Object* cons_obj = map->GetConstructor(); 1222 if (!cons_obj->IsJSFunction()) return false; 1223 JSFunction* fun = JSFunction::cast(cons_obj); 1224 // Iterate through the chain of inheriting function templates to 1225 // see if the required one occurs. 1226 for (Object* type = fun->shared()->function_data(); 1227 type->IsFunctionTemplateInfo(); 1228 type = FunctionTemplateInfo::cast(type)->parent_template()) { 1229 if (type == this) return true; 1230 } 1231 // Didn't find the required type in the inheritance chain. 1232 return false; 1233 } 1234 1235 1236 // static 1237 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) { 1238 Handle<FixedArray> list = 1239 isolate->factory()->NewFixedArray(kLengthIndex + size); 1240 list->set(kLengthIndex, Smi::kZero); 1241 return Handle<TemplateList>::cast(list); 1242 } 1243 1244 // static 1245 Handle<TemplateList> TemplateList::Add(Isolate* isolate, 1246 Handle<TemplateList> list, 1247 Handle<i::Object> value) { 1248 STATIC_ASSERT(kFirstElementIndex == 1); 1249 int index = list->length() + 1; 1250 Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list); 1251 fixed_array = FixedArray::SetAndGrow(fixed_array, index, value); 1252 fixed_array->set(kLengthIndex, Smi::FromInt(index)); 1253 return Handle<TemplateList>::cast(fixed_array); 1254 } 1255 1256 // static 1257 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor, 1258 Handle<JSReceiver> new_target, 1259 Handle<AllocationSite> site) { 1260 // If called through new, new.target can be: 1261 // - a subclass of constructor, 1262 // - a proxy wrapper around constructor, or 1263 // - the constructor itself. 1264 // If called through Reflect.construct, it's guaranteed to be a constructor. 1265 Isolate* const isolate = constructor->GetIsolate(); 1266 DCHECK(constructor->IsConstructor()); 1267 DCHECK(new_target->IsConstructor()); 1268 DCHECK(!constructor->has_initial_map() || 1269 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE); 1270 1271 Handle<Map> initial_map; 1272 ASSIGN_RETURN_ON_EXCEPTION( 1273 isolate, initial_map, 1274 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject); 1275 Handle<JSObject> result = 1276 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site); 1277 isolate->counters()->constructed_objects()->Increment(); 1278 isolate->counters()->constructed_objects_runtime()->Increment(); 1279 return result; 1280 } 1281 1282 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) { 1283 DCHECK(object->HasFastSmiOrObjectElements() || 1284 object->HasFastStringWrapperElements()); 1285 FixedArray* raw_elems = FixedArray::cast(object->elements()); 1286 Heap* heap = object->GetHeap(); 1287 if (raw_elems->map() != heap->fixed_cow_array_map()) return; 1288 Isolate* isolate = heap->isolate(); 1289 Handle<FixedArray> elems(raw_elems, isolate); 1290 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap( 1291 elems, isolate->factory()->fixed_array_map()); 1292 object->set_elements(*writable_elems); 1293 isolate->counters()->cow_arrays_converted()->Increment(); 1294 } 1295 1296 1297 // ES6 9.5.1 1298 // static 1299 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) { 1300 Isolate* isolate = proxy->GetIsolate(); 1301 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string(); 1302 1303 STACK_CHECK(isolate, MaybeHandle<Object>()); 1304 1305 // 1. Let handler be the value of the [[ProxyHandler]] internal slot. 1306 // 2. If handler is null, throw a TypeError exception. 1307 // 3. Assert: Type(handler) is Object. 1308 // 4. Let target be the value of the [[ProxyTarget]] internal slot. 1309 if (proxy->IsRevoked()) { 1310 THROW_NEW_ERROR(isolate, 1311 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1312 Object); 1313 } 1314 Handle<JSReceiver> target(proxy->target(), isolate); 1315 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 1316 1317 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). 1318 Handle<Object> trap; 1319 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name), 1320 Object); 1321 // 6. If trap is undefined, then return target.[[GetPrototypeOf]](). 1322 if (trap->IsUndefined(isolate)) { 1323 return JSReceiver::GetPrototype(isolate, target); 1324 } 1325 // 7. Let handlerProto be ? Call(trap, handler, target). 1326 Handle<Object> argv[] = {target}; 1327 Handle<Object> handler_proto; 1328 ASSIGN_RETURN_ON_EXCEPTION( 1329 isolate, handler_proto, 1330 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object); 1331 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError. 1332 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) { 1333 THROW_NEW_ERROR(isolate, 1334 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid), 1335 Object); 1336 } 1337 // 9. Let extensibleTarget be ? IsExtensible(target). 1338 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 1339 MAYBE_RETURN_NULL(is_extensible); 1340 // 10. If extensibleTarget is true, return handlerProto. 1341 if (is_extensible.FromJust()) return handler_proto; 1342 // 11. Let targetProto be ? target.[[GetPrototypeOf]](). 1343 Handle<Object> target_proto; 1344 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto, 1345 JSReceiver::GetPrototype(isolate, target), Object); 1346 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError. 1347 if (!handler_proto->SameValue(*target_proto)) { 1348 THROW_NEW_ERROR( 1349 isolate, 1350 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible), 1351 Object); 1352 } 1353 // 13. Return handlerProto. 1354 return handler_proto; 1355 } 1356 1357 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) { 1358 Isolate* isolate = it->isolate(); 1359 Handle<Object> structure = it->GetAccessors(); 1360 Handle<Object> receiver = it->GetReceiver(); 1361 1362 // We should never get here to initialize a const with the hole value since a 1363 // const declaration would conflict with the getter. 1364 DCHECK(!structure->IsForeign()); 1365 1366 // API style callbacks. 1367 if (structure->IsAccessorInfo()) { 1368 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1369 Handle<Name> name = it->GetName(); 1370 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1371 if (!info->IsCompatibleReceiver(*receiver)) { 1372 THROW_NEW_ERROR(isolate, 1373 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, 1374 name, receiver), 1375 Object); 1376 } 1377 1378 v8::AccessorNameGetterCallback call_fun = 1379 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter()); 1380 if (call_fun == nullptr) return isolate->factory()->undefined_value(); 1381 1382 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1383 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver, 1384 Object::ConvertReceiver(isolate, receiver), 1385 Object); 1386 } 1387 1388 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1389 Object::DONT_THROW); 1390 Handle<Object> result = args.Call(call_fun, name); 1391 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1392 if (result.is_null()) return isolate->factory()->undefined_value(); 1393 Handle<Object> reboxed_result = handle(*result, isolate); 1394 if (info->replace_on_access() && receiver->IsJSReceiver()) { 1395 args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>( 1396 &Accessors::ReconfigureToDataProperty), 1397 name, result); 1398 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1399 } 1400 return reboxed_result; 1401 } 1402 1403 // AccessorPair with 'cached' private property. 1404 if (it->TryLookupCachedProperty()) { 1405 return Object::GetProperty(it); 1406 } 1407 1408 // Regular accessor. 1409 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate); 1410 if (getter->IsFunctionTemplateInfo()) { 1411 return Builtins::InvokeApiFunction( 1412 isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, 1413 nullptr, isolate->factory()->undefined_value()); 1414 } else if (getter->IsCallable()) { 1415 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1416 return Object::GetPropertyWithDefinedGetter( 1417 receiver, Handle<JSReceiver>::cast(getter)); 1418 } 1419 // Getter is not a function. 1420 return isolate->factory()->undefined_value(); 1421 } 1422 1423 // static 1424 Address AccessorInfo::redirect(Isolate* isolate, Address address, 1425 AccessorComponent component) { 1426 ApiFunction fun(address); 1427 DCHECK_EQ(ACCESSOR_GETTER, component); 1428 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; 1429 return ExternalReference(&fun, type, isolate).address(); 1430 } 1431 1432 Address AccessorInfo::redirected_getter() const { 1433 Address accessor = v8::ToCData<Address>(getter()); 1434 if (accessor == nullptr) return nullptr; 1435 return redirect(GetIsolate(), accessor, ACCESSOR_GETTER); 1436 } 1437 1438 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate, 1439 Handle<AccessorInfo> info, 1440 Handle<Map> map) { 1441 if (!info->HasExpectedReceiverType()) return true; 1442 if (!map->IsJSObjectMap()) return false; 1443 return FunctionTemplateInfo::cast(info->expected_receiver_type()) 1444 ->IsTemplateFor(*map); 1445 } 1446 1447 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it, 1448 Handle<Object> value, 1449 ShouldThrow should_throw) { 1450 Isolate* isolate = it->isolate(); 1451 Handle<Object> structure = it->GetAccessors(); 1452 Handle<Object> receiver = it->GetReceiver(); 1453 1454 // We should never get here to initialize a const with the hole value since a 1455 // const declaration would conflict with the setter. 1456 DCHECK(!structure->IsForeign()); 1457 1458 // API style callbacks. 1459 if (structure->IsAccessorInfo()) { 1460 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1461 Handle<Name> name = it->GetName(); 1462 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1463 if (!info->IsCompatibleReceiver(*receiver)) { 1464 isolate->Throw(*isolate->factory()->NewTypeError( 1465 MessageTemplate::kIncompatibleMethodReceiver, name, receiver)); 1466 return Nothing<bool>(); 1467 } 1468 1469 // The actual type of call_fun is either v8::AccessorNameSetterCallback or 1470 // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the 1471 // AccessorInfo was created by the API or internally (see accessors.cc). 1472 // Here we handle both cases using GenericNamedPropertySetterCallback and 1473 // its Call method. 1474 GenericNamedPropertySetterCallback call_fun = 1475 v8::ToCData<GenericNamedPropertySetterCallback>(info->setter()); 1476 1477 if (call_fun == nullptr) { 1478 // TODO(verwaest): We should not get here anymore once all AccessorInfos 1479 // are marked as special_data_property. They cannot both be writable and 1480 // not have a setter. 1481 return Just(true); 1482 } 1483 1484 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1485 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1486 isolate, receiver, Object::ConvertReceiver(isolate, receiver), 1487 Nothing<bool>()); 1488 } 1489 1490 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1491 should_throw); 1492 Handle<Object> result = args.Call(call_fun, name, value); 1493 // In the case of AccessorNameSetterCallback, we know that the result value 1494 // cannot have been set, so the result of Call will be null. In the case of 1495 // AccessorNameBooleanSetterCallback, the result will either be null 1496 // (signalling an exception) or a boolean Oddball. 1497 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1498 if (result.is_null()) return Just(true); 1499 DCHECK(result->BooleanValue() || should_throw == DONT_THROW); 1500 return Just(result->BooleanValue()); 1501 } 1502 1503 // Regular accessor. 1504 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); 1505 if (setter->IsFunctionTemplateInfo()) { 1506 Handle<Object> argv[] = {value}; 1507 RETURN_ON_EXCEPTION_VALUE( 1508 isolate, Builtins::InvokeApiFunction( 1509 isolate, false, Handle<FunctionTemplateInfo>::cast(setter), 1510 receiver, arraysize(argv), argv, 1511 isolate->factory()->undefined_value()), 1512 Nothing<bool>()); 1513 return Just(true); 1514 } else if (setter->IsCallable()) { 1515 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1516 return SetPropertyWithDefinedSetter( 1517 receiver, Handle<JSReceiver>::cast(setter), value, should_throw); 1518 } 1519 1520 RETURN_FAILURE(isolate, should_throw, 1521 NewTypeError(MessageTemplate::kNoSetterInCallback, 1522 it->GetName(), it->GetHolder<JSObject>())); 1523 } 1524 1525 1526 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter( 1527 Handle<Object> receiver, 1528 Handle<JSReceiver> getter) { 1529 Isolate* isolate = getter->GetIsolate(); 1530 1531 // Platforms with simulators like arm/arm64 expose a funny issue. If the 1532 // simulator has a separate JS stack pointer from the C++ stack pointer, it 1533 // can miss C++ stack overflows in the stack guard at the start of JavaScript 1534 // functions. It would be very expensive to check the C++ stack pointer at 1535 // that location. The best solution seems to be to break the impasse by 1536 // adding checks at possible recursion points. What's more, we don't put 1537 // this stack check behind the USE_SIMULATOR define in order to keep 1538 // behavior the same between hardware and simulators. 1539 StackLimitCheck check(isolate); 1540 if (check.JsHasOverflowed()) { 1541 isolate->StackOverflow(); 1542 return MaybeHandle<Object>(); 1543 } 1544 1545 return Execution::Call(isolate, getter, receiver, 0, NULL); 1546 } 1547 1548 1549 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver, 1550 Handle<JSReceiver> setter, 1551 Handle<Object> value, 1552 ShouldThrow should_throw) { 1553 Isolate* isolate = setter->GetIsolate(); 1554 1555 Handle<Object> argv[] = { value }; 1556 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver, 1557 arraysize(argv), argv), 1558 Nothing<bool>()); 1559 return Just(true); 1560 } 1561 1562 1563 // static 1564 bool JSObject::AllCanRead(LookupIterator* it) { 1565 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of 1566 // which have already been checked. 1567 DCHECK(it->state() == LookupIterator::ACCESS_CHECK || 1568 it->state() == LookupIterator::INTERCEPTOR); 1569 for (it->Next(); it->IsFound(); it->Next()) { 1570 if (it->state() == LookupIterator::ACCESSOR) { 1571 auto accessors = it->GetAccessors(); 1572 if (accessors->IsAccessorInfo()) { 1573 if (AccessorInfo::cast(*accessors)->all_can_read()) return true; 1574 } 1575 } else if (it->state() == LookupIterator::INTERCEPTOR) { 1576 if (it->GetInterceptor()->all_can_read()) return true; 1577 } else if (it->state() == LookupIterator::JSPROXY) { 1578 // Stop lookupiterating. And no, AllCanNotRead. 1579 return false; 1580 } 1581 } 1582 return false; 1583 } 1584 1585 namespace { 1586 1587 MaybeHandle<Object> GetPropertyWithInterceptorInternal( 1588 LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) { 1589 *done = false; 1590 Isolate* isolate = it->isolate(); 1591 // Make sure that the top context does not change when doing callbacks or 1592 // interceptor calls. 1593 AssertNoContextChange ncc(isolate); 1594 1595 if (interceptor->getter()->IsUndefined(isolate)) { 1596 return isolate->factory()->undefined_value(); 1597 } 1598 1599 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1600 Handle<Object> result; 1601 Handle<Object> receiver = it->GetReceiver(); 1602 if (!receiver->IsJSReceiver()) { 1603 ASSIGN_RETURN_ON_EXCEPTION( 1604 isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object); 1605 } 1606 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1607 *holder, Object::DONT_THROW); 1608 1609 if (it->IsElement()) { 1610 uint32_t index = it->index(); 1611 v8::IndexedPropertyGetterCallback getter = 1612 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); 1613 result = args.Call(getter, index); 1614 } else { 1615 Handle<Name> name = it->name(); 1616 DCHECK(!name->IsPrivate()); 1617 1618 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { 1619 return isolate->factory()->undefined_value(); 1620 } 1621 1622 v8::GenericNamedPropertyGetterCallback getter = 1623 v8::ToCData<v8::GenericNamedPropertyGetterCallback>( 1624 interceptor->getter()); 1625 result = args.Call(getter, name); 1626 } 1627 1628 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1629 if (result.is_null()) return isolate->factory()->undefined_value(); 1630 *done = true; 1631 // Rebox handle before return 1632 return handle(*result, isolate); 1633 } 1634 1635 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal( 1636 LookupIterator* it, Handle<InterceptorInfo> interceptor) { 1637 Isolate* isolate = it->isolate(); 1638 // Make sure that the top context does not change when doing 1639 // callbacks or interceptor calls. 1640 AssertNoContextChange ncc(isolate); 1641 HandleScope scope(isolate); 1642 1643 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1644 if (!it->IsElement() && it->name()->IsSymbol() && 1645 !interceptor->can_intercept_symbols()) { 1646 return Just(ABSENT); 1647 } 1648 Handle<Object> receiver = it->GetReceiver(); 1649 if (!receiver->IsJSReceiver()) { 1650 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1651 Object::ConvertReceiver(isolate, receiver), 1652 Nothing<PropertyAttributes>()); 1653 } 1654 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1655 *holder, Object::DONT_THROW); 1656 if (!interceptor->query()->IsUndefined(isolate)) { 1657 Handle<Object> result; 1658 if (it->IsElement()) { 1659 uint32_t index = it->index(); 1660 v8::IndexedPropertyQueryCallback query = 1661 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query()); 1662 result = args.Call(query, index); 1663 } else { 1664 Handle<Name> name = it->name(); 1665 DCHECK(!name->IsPrivate()); 1666 v8::GenericNamedPropertyQueryCallback query = 1667 v8::ToCData<v8::GenericNamedPropertyQueryCallback>( 1668 interceptor->query()); 1669 result = args.Call(query, name); 1670 } 1671 if (!result.is_null()) { 1672 int32_t value; 1673 CHECK(result->ToInt32(&value)); 1674 return Just(static_cast<PropertyAttributes>(value)); 1675 } 1676 } else if (!interceptor->getter()->IsUndefined(isolate)) { 1677 // TODO(verwaest): Use GetPropertyWithInterceptor? 1678 Handle<Object> result; 1679 if (it->IsElement()) { 1680 uint32_t index = it->index(); 1681 v8::IndexedPropertyGetterCallback getter = 1682 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); 1683 result = args.Call(getter, index); 1684 } else { 1685 Handle<Name> name = it->name(); 1686 DCHECK(!name->IsPrivate()); 1687 v8::GenericNamedPropertyGetterCallback getter = 1688 v8::ToCData<v8::GenericNamedPropertyGetterCallback>( 1689 interceptor->getter()); 1690 result = args.Call(getter, name); 1691 } 1692 if (!result.is_null()) return Just(DONT_ENUM); 1693 } 1694 1695 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1696 return Just(ABSENT); 1697 } 1698 1699 Maybe<bool> SetPropertyWithInterceptorInternal( 1700 LookupIterator* it, Handle<InterceptorInfo> interceptor, 1701 Object::ShouldThrow should_throw, Handle<Object> value) { 1702 Isolate* isolate = it->isolate(); 1703 // Make sure that the top context does not change when doing callbacks or 1704 // interceptor calls. 1705 AssertNoContextChange ncc(isolate); 1706 1707 if (interceptor->setter()->IsUndefined(isolate)) return Just(false); 1708 1709 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1710 bool result; 1711 Handle<Object> receiver = it->GetReceiver(); 1712 if (!receiver->IsJSReceiver()) { 1713 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1714 Object::ConvertReceiver(isolate, receiver), 1715 Nothing<bool>()); 1716 } 1717 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1718 *holder, should_throw); 1719 1720 if (it->IsElement()) { 1721 uint32_t index = it->index(); 1722 v8::IndexedPropertySetterCallback setter = 1723 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter()); 1724 // TODO(neis): In the future, we may want to actually return the 1725 // interceptor's result, which then should be a boolean. 1726 result = !args.Call(setter, index, value).is_null(); 1727 } else { 1728 Handle<Name> name = it->name(); 1729 DCHECK(!name->IsPrivate()); 1730 1731 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { 1732 return Just(false); 1733 } 1734 1735 v8::GenericNamedPropertySetterCallback setter = 1736 v8::ToCData<v8::GenericNamedPropertySetterCallback>( 1737 interceptor->setter()); 1738 result = !args.Call(setter, name, value).is_null(); 1739 } 1740 1741 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 1742 return Just(result); 1743 } 1744 1745 Maybe<bool> DefinePropertyWithInterceptorInternal( 1746 LookupIterator* it, Handle<InterceptorInfo> interceptor, 1747 Object::ShouldThrow should_throw, PropertyDescriptor& desc) { 1748 Isolate* isolate = it->isolate(); 1749 // Make sure that the top context does not change when doing callbacks or 1750 // interceptor calls. 1751 AssertNoContextChange ncc(isolate); 1752 1753 if (interceptor->definer()->IsUndefined(isolate)) return Just(false); 1754 1755 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1756 bool result; 1757 Handle<Object> receiver = it->GetReceiver(); 1758 if (!receiver->IsJSReceiver()) { 1759 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1760 Object::ConvertReceiver(isolate, receiver), 1761 Nothing<bool>()); 1762 } 1763 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1764 *holder, should_throw); 1765 1766 std::unique_ptr<v8::PropertyDescriptor> descriptor( 1767 new v8::PropertyDescriptor()); 1768 if (PropertyDescriptor::IsAccessorDescriptor(&desc)) { 1769 descriptor.reset(new v8::PropertyDescriptor( 1770 v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set()))); 1771 } else if (PropertyDescriptor::IsDataDescriptor(&desc)) { 1772 if (desc.has_writable()) { 1773 descriptor.reset(new v8::PropertyDescriptor( 1774 v8::Utils::ToLocal(desc.value()), desc.writable())); 1775 } else { 1776 descriptor.reset( 1777 new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value()))); 1778 } 1779 } 1780 if (desc.has_enumerable()) { 1781 descriptor->set_enumerable(desc.enumerable()); 1782 } 1783 if (desc.has_configurable()) { 1784 descriptor->set_configurable(desc.configurable()); 1785 } 1786 1787 if (it->IsElement()) { 1788 uint32_t index = it->index(); 1789 v8::IndexedPropertyDefinerCallback definer = 1790 v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer()); 1791 result = !args.Call(definer, index, *descriptor).is_null(); 1792 } else { 1793 Handle<Name> name = it->name(); 1794 DCHECK(!name->IsPrivate()); 1795 1796 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { 1797 return Just(false); 1798 } 1799 1800 v8::GenericNamedPropertyDefinerCallback definer = 1801 v8::ToCData<v8::GenericNamedPropertyDefinerCallback>( 1802 interceptor->definer()); 1803 result = !args.Call(definer, name, *descriptor).is_null(); 1804 } 1805 1806 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 1807 return Just(result); 1808 } 1809 1810 } // namespace 1811 1812 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( 1813 LookupIterator* it) { 1814 Isolate* isolate = it->isolate(); 1815 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1816 Handle<InterceptorInfo> interceptor = 1817 it->GetInterceptorForFailedAccessCheck(); 1818 if (interceptor.is_null()) { 1819 while (AllCanRead(it)) { 1820 if (it->state() == LookupIterator::ACCESSOR) { 1821 return GetPropertyWithAccessor(it); 1822 } 1823 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 1824 bool done; 1825 Handle<Object> result; 1826 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 1827 GetPropertyWithInterceptor(it, &done), Object); 1828 if (done) return result; 1829 } 1830 1831 } else { 1832 Handle<Object> result; 1833 bool done; 1834 ASSIGN_RETURN_ON_EXCEPTION( 1835 isolate, result, 1836 GetPropertyWithInterceptorInternal(it, interceptor, &done), Object); 1837 if (done) return result; 1838 } 1839 1840 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns 1841 // undefined. 1842 Handle<Name> name = it->GetName(); 1843 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) { 1844 return it->factory()->undefined_value(); 1845 } 1846 1847 isolate->ReportFailedAccessCheck(checked); 1848 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1849 return it->factory()->undefined_value(); 1850 } 1851 1852 1853 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck( 1854 LookupIterator* it) { 1855 Isolate* isolate = it->isolate(); 1856 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1857 Handle<InterceptorInfo> interceptor = 1858 it->GetInterceptorForFailedAccessCheck(); 1859 if (interceptor.is_null()) { 1860 while (AllCanRead(it)) { 1861 if (it->state() == LookupIterator::ACCESSOR) { 1862 return Just(it->property_attributes()); 1863 } 1864 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 1865 auto result = GetPropertyAttributesWithInterceptor(it); 1866 if (isolate->has_scheduled_exception()) break; 1867 if (result.IsJust() && result.FromJust() != ABSENT) return result; 1868 } 1869 } else { 1870 Maybe<PropertyAttributes> result = 1871 GetPropertyAttributesWithInterceptorInternal(it, interceptor); 1872 if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>(); 1873 if (result.FromMaybe(ABSENT) != ABSENT) return result; 1874 } 1875 isolate->ReportFailedAccessCheck(checked); 1876 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1877 return Just(ABSENT); 1878 } 1879 1880 1881 // static 1882 bool JSObject::AllCanWrite(LookupIterator* it) { 1883 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) { 1884 if (it->state() == LookupIterator::ACCESSOR) { 1885 Handle<Object> accessors = it->GetAccessors(); 1886 if (accessors->IsAccessorInfo()) { 1887 if (AccessorInfo::cast(*accessors)->all_can_write()) return true; 1888 } 1889 } 1890 } 1891 return false; 1892 } 1893 1894 1895 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck( 1896 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) { 1897 Isolate* isolate = it->isolate(); 1898 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1899 Handle<InterceptorInfo> interceptor = 1900 it->GetInterceptorForFailedAccessCheck(); 1901 if (interceptor.is_null()) { 1902 if (AllCanWrite(it)) { 1903 return SetPropertyWithAccessor(it, value, should_throw); 1904 } 1905 } else { 1906 Maybe<bool> result = SetPropertyWithInterceptorInternal( 1907 it, interceptor, should_throw, value); 1908 if (isolate->has_pending_exception()) return Nothing<bool>(); 1909 if (result.IsJust()) return result; 1910 } 1911 isolate->ReportFailedAccessCheck(checked); 1912 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1913 return Just(true); 1914 } 1915 1916 1917 void JSObject::SetNormalizedProperty(Handle<JSObject> object, 1918 Handle<Name> name, 1919 Handle<Object> value, 1920 PropertyDetails details) { 1921 DCHECK(!object->HasFastProperties()); 1922 if (!name->IsUniqueName()) { 1923 name = object->GetIsolate()->factory()->InternalizeString( 1924 Handle<String>::cast(name)); 1925 } 1926 1927 if (object->IsJSGlobalObject()) { 1928 Handle<GlobalDictionary> dictionary(object->global_dictionary()); 1929 1930 int entry = dictionary->FindEntry(name); 1931 if (entry == GlobalDictionary::kNotFound) { 1932 Isolate* isolate = object->GetIsolate(); 1933 auto cell = isolate->factory()->NewPropertyCell(); 1934 cell->set_value(*value); 1935 auto cell_type = value->IsUndefined(isolate) 1936 ? PropertyCellType::kUndefined 1937 : PropertyCellType::kConstant; 1938 details = details.set_cell_type(cell_type); 1939 value = cell; 1940 dictionary = GlobalDictionary::Add(dictionary, name, value, details); 1941 object->set_properties(*dictionary); 1942 } else { 1943 Handle<PropertyCell> cell = 1944 PropertyCell::PrepareForValue(dictionary, entry, value, details); 1945 cell->set_value(*value); 1946 } 1947 } else { 1948 Handle<NameDictionary> dictionary(object->property_dictionary()); 1949 1950 int entry = dictionary->FindEntry(name); 1951 if (entry == NameDictionary::kNotFound) { 1952 dictionary = NameDictionary::Add(dictionary, name, value, details); 1953 object->set_properties(*dictionary); 1954 } else { 1955 PropertyDetails original_details = dictionary->DetailsAt(entry); 1956 int enumeration_index = original_details.dictionary_index(); 1957 DCHECK(enumeration_index > 0); 1958 details = details.set_index(enumeration_index); 1959 dictionary->SetEntry(entry, name, value, details); 1960 } 1961 } 1962 } 1963 1964 // static 1965 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate, 1966 Handle<JSReceiver> object, 1967 Handle<Object> proto) { 1968 PrototypeIterator iter(isolate, object, kStartAtReceiver); 1969 while (true) { 1970 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); 1971 if (iter.IsAtEnd()) return Just(false); 1972 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { 1973 return Just(true); 1974 } 1975 } 1976 } 1977 1978 namespace { 1979 1980 bool HasExcludedProperty( 1981 const ScopedVector<Handle<Object>>* excluded_properties, 1982 Handle<Object> search_element) { 1983 // TODO(gsathya): Change this to be a hashtable. 1984 for (int i = 0; i < excluded_properties->length(); i++) { 1985 if (search_element->SameValue(*excluded_properties->at(i))) { 1986 return true; 1987 } 1988 } 1989 1990 return false; 1991 } 1992 1993 MUST_USE_RESULT Maybe<bool> FastAssign( 1994 Handle<JSReceiver> target, Handle<Object> source, 1995 const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) { 1996 // Non-empty strings are the only non-JSReceivers that need to be handled 1997 // explicitly by Object.assign. 1998 if (!source->IsJSReceiver()) { 1999 return Just(!source->IsString() || String::cast(*source)->length() == 0); 2000 } 2001 2002 // If the target is deprecated, the object will be updated on first store. If 2003 // the source for that store equals the target, this will invalidate the 2004 // cached representation of the source. Preventively upgrade the target. 2005 // Do this on each iteration since any property load could cause deprecation. 2006 if (target->map()->is_deprecated()) { 2007 JSObject::MigrateInstance(Handle<JSObject>::cast(target)); 2008 } 2009 2010 Isolate* isolate = target->GetIsolate(); 2011 Handle<Map> map(JSReceiver::cast(*source)->map(), isolate); 2012 2013 if (!map->IsJSObjectMap()) return Just(false); 2014 if (!map->OnlyHasSimpleProperties()) return Just(false); 2015 2016 Handle<JSObject> from = Handle<JSObject>::cast(source); 2017 if (from->elements() != isolate->heap()->empty_fixed_array()) { 2018 return Just(false); 2019 } 2020 2021 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 2022 int length = map->NumberOfOwnDescriptors(); 2023 2024 bool stable = true; 2025 2026 for (int i = 0; i < length; i++) { 2027 Handle<Name> next_key(descriptors->GetKey(i), isolate); 2028 Handle<Object> prop_value; 2029 // Directly decode from the descriptor array if |from| did not change shape. 2030 if (stable) { 2031 PropertyDetails details = descriptors->GetDetails(i); 2032 if (!details.IsEnumerable()) continue; 2033 if (details.kind() == kData) { 2034 if (details.location() == kDescriptor) { 2035 prop_value = handle(descriptors->GetValue(i), isolate); 2036 } else { 2037 Representation representation = details.representation(); 2038 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 2039 prop_value = JSObject::FastPropertyAt(from, representation, index); 2040 } 2041 } else { 2042 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2043 isolate, prop_value, JSReceiver::GetProperty(from, next_key), 2044 Nothing<bool>()); 2045 stable = from->map() == *map; 2046 } 2047 } else { 2048 // If the map did change, do a slower lookup. We are still guaranteed that 2049 // the object has a simple shape, and that the key is a name. 2050 LookupIterator it(from, next_key, from, 2051 LookupIterator::OWN_SKIP_INTERCEPTOR); 2052 if (!it.IsFound()) continue; 2053 DCHECK(it.state() == LookupIterator::DATA || 2054 it.state() == LookupIterator::ACCESSOR); 2055 if (!it.IsEnumerable()) continue; 2056 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2057 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); 2058 } 2059 2060 if (use_set) { 2061 LookupIterator it(target, next_key, target); 2062 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA; 2063 Maybe<bool> result = Object::SetProperty( 2064 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED); 2065 if (result.IsNothing()) return result; 2066 if (stable && call_to_js) stable = from->map() == *map; 2067 } else { 2068 if (excluded_properties != nullptr && 2069 HasExcludedProperty(excluded_properties, next_key)) { 2070 continue; 2071 } 2072 2073 // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue). 2074 bool success; 2075 LookupIterator it = LookupIterator::PropertyOrElement( 2076 isolate, target, next_key, &success, LookupIterator::OWN); 2077 CHECK(success); 2078 CHECK( 2079 JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR) 2080 .FromJust()); 2081 } 2082 } 2083 2084 return Just(true); 2085 } 2086 } // namespace 2087 2088 // static 2089 Maybe<bool> JSReceiver::SetOrCopyDataProperties( 2090 Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source, 2091 const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) { 2092 Maybe<bool> fast_assign = 2093 FastAssign(target, source, excluded_properties, use_set); 2094 if (fast_assign.IsNothing()) return Nothing<bool>(); 2095 if (fast_assign.FromJust()) return Just(true); 2096 2097 Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked(); 2098 // 3b. Let keys be ? from.[[OwnPropertyKeys]](). 2099 Handle<FixedArray> keys; 2100 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2101 isolate, keys, 2102 KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, 2103 GetKeysConversion::kKeepNumbers), 2104 Nothing<bool>()); 2105 2106 // 4. Repeat for each element nextKey of keys in List order, 2107 for (int j = 0; j < keys->length(); ++j) { 2108 Handle<Object> next_key(keys->get(j), isolate); 2109 // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey). 2110 PropertyDescriptor desc; 2111 Maybe<bool> found = 2112 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); 2113 if (found.IsNothing()) return Nothing<bool>(); 2114 // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then 2115 if (found.FromJust() && desc.enumerable()) { 2116 // 4a ii 1. Let propValue be ? Get(from, nextKey). 2117 Handle<Object> prop_value; 2118 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2119 isolate, prop_value, 2120 Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>()); 2121 2122 if (use_set) { 2123 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). 2124 Handle<Object> status; 2125 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2126 isolate, status, Runtime::SetObjectProperty( 2127 isolate, target, next_key, prop_value, STRICT), 2128 Nothing<bool>()); 2129 } else { 2130 if (excluded_properties != nullptr && 2131 HasExcludedProperty(excluded_properties, next_key)) { 2132 continue; 2133 } 2134 2135 // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue). 2136 bool success; 2137 LookupIterator it = LookupIterator::PropertyOrElement( 2138 isolate, target, next_key, &success, LookupIterator::OWN); 2139 CHECK(success); 2140 CHECK(JSObject::CreateDataProperty(&it, prop_value, 2141 Object::THROW_ON_ERROR) 2142 .FromJust()); 2143 } 2144 } 2145 } 2146 2147 return Just(true); 2148 } 2149 2150 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) { 2151 DisallowHeapAllocation no_alloc; 2152 if (IsSmi()) { 2153 Context* native_context = isolate->context()->native_context(); 2154 return native_context->number_function()->initial_map(); 2155 } 2156 2157 // The object is either a number, a string, a symbol, a boolean, a real JS 2158 // object, or a Harmony proxy. 2159 HeapObject* heap_object = HeapObject::cast(this); 2160 return heap_object->map()->GetPrototypeChainRootMap(isolate); 2161 } 2162 2163 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) { 2164 DisallowHeapAllocation no_alloc; 2165 if (IsJSReceiverMap()) { 2166 return this; 2167 } 2168 int constructor_function_index = GetConstructorFunctionIndex(); 2169 if (constructor_function_index != Map::kNoConstructorFunctionIndex) { 2170 Context* native_context = isolate->context()->native_context(); 2171 JSFunction* constructor_function = 2172 JSFunction::cast(native_context->get(constructor_function_index)); 2173 return constructor_function->initial_map(); 2174 } 2175 return isolate->heap()->null_value()->map(); 2176 } 2177 2178 namespace { 2179 2180 // Returns a non-SMI for JSObjects, but returns the hash code for simple 2181 // objects. This avoids a double lookup in the cases where we know we will 2182 // add the hash to the JSObject if it does not already exist. 2183 Object* GetSimpleHash(Object* object) { 2184 // The object is either a Smi, a HeapNumber, a name, an odd-ball, a real JS 2185 // object, or a Harmony proxy. 2186 if (object->IsSmi()) { 2187 uint32_t hash = 2188 ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed); 2189 return Smi::FromInt(hash & Smi::kMaxValue); 2190 } 2191 if (object->IsHeapNumber()) { 2192 double num = HeapNumber::cast(object)->value(); 2193 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue); 2194 if (i::IsMinusZero(num)) num = 0; 2195 if (IsSmiDouble(num)) { 2196 return Smi::FromInt(FastD2I(num))->GetHash(); 2197 } 2198 uint32_t hash = ComputeLongHash(double_to_uint64(num)); 2199 return Smi::FromInt(hash & Smi::kMaxValue); 2200 } 2201 if (object->IsName()) { 2202 uint32_t hash = Name::cast(object)->Hash(); 2203 return Smi::FromInt(hash); 2204 } 2205 if (object->IsOddball()) { 2206 uint32_t hash = Oddball::cast(object)->to_string()->Hash(); 2207 return Smi::FromInt(hash); 2208 } 2209 DCHECK(object->IsJSReceiver()); 2210 // Simply return the receiver as it is guaranteed to not be a SMI. 2211 return object; 2212 } 2213 2214 } // namespace 2215 2216 Object* Object::GetHash() { 2217 Object* hash = GetSimpleHash(this); 2218 if (hash->IsSmi()) return hash; 2219 2220 DisallowHeapAllocation no_gc; 2221 DCHECK(IsJSReceiver()); 2222 JSReceiver* receiver = JSReceiver::cast(this); 2223 Isolate* isolate = receiver->GetIsolate(); 2224 return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate)); 2225 } 2226 2227 Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) { 2228 Object* hash = GetSimpleHash(*object); 2229 if (hash->IsSmi()) return Smi::cast(hash); 2230 2231 DCHECK(object->IsJSReceiver()); 2232 return JSReceiver::GetOrCreateIdentityHash(isolate, 2233 Handle<JSReceiver>::cast(object)); 2234 } 2235 2236 2237 bool Object::SameValue(Object* other) { 2238 if (other == this) return true; 2239 2240 // The object is either a number, a name, an odd-ball, 2241 // a real JS object, or a Harmony proxy. 2242 if (IsNumber() && other->IsNumber()) { 2243 double this_value = Number(); 2244 double other_value = other->Number(); 2245 // SameValue(NaN, NaN) is true. 2246 if (this_value != other_value) { 2247 return std::isnan(this_value) && std::isnan(other_value); 2248 } 2249 // SameValue(0.0, -0.0) is false. 2250 return (std::signbit(this_value) == std::signbit(other_value)); 2251 } 2252 if (IsString() && other->IsString()) { 2253 return String::cast(this)->Equals(String::cast(other)); 2254 } 2255 return false; 2256 } 2257 2258 2259 bool Object::SameValueZero(Object* other) { 2260 if (other == this) return true; 2261 2262 // The object is either a number, a name, an odd-ball, 2263 // a real JS object, or a Harmony proxy. 2264 if (IsNumber() && other->IsNumber()) { 2265 double this_value = Number(); 2266 double other_value = other->Number(); 2267 // +0 == -0 is true 2268 return this_value == other_value || 2269 (std::isnan(this_value) && std::isnan(other_value)); 2270 } 2271 if (IsString() && other->IsString()) { 2272 return String::cast(this)->Equals(String::cast(other)); 2273 } 2274 return false; 2275 } 2276 2277 2278 MaybeHandle<Object> Object::ArraySpeciesConstructor( 2279 Isolate* isolate, Handle<Object> original_array) { 2280 Handle<Object> default_species = isolate->array_function(); 2281 if (original_array->IsJSArray() && 2282 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) && 2283 isolate->IsArraySpeciesLookupChainIntact()) { 2284 return default_species; 2285 } 2286 Handle<Object> constructor = isolate->factory()->undefined_value(); 2287 Maybe<bool> is_array = Object::IsArray(original_array); 2288 MAYBE_RETURN_NULL(is_array); 2289 if (is_array.FromJust()) { 2290 ASSIGN_RETURN_ON_EXCEPTION( 2291 isolate, constructor, 2292 Object::GetProperty(original_array, 2293 isolate->factory()->constructor_string()), 2294 Object); 2295 if (constructor->IsConstructor()) { 2296 Handle<Context> constructor_context; 2297 ASSIGN_RETURN_ON_EXCEPTION( 2298 isolate, constructor_context, 2299 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)), 2300 Object); 2301 if (*constructor_context != *isolate->native_context() && 2302 *constructor == constructor_context->array_function()) { 2303 constructor = isolate->factory()->undefined_value(); 2304 } 2305 } 2306 if (constructor->IsJSReceiver()) { 2307 ASSIGN_RETURN_ON_EXCEPTION( 2308 isolate, constructor, 2309 JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor), 2310 isolate->factory()->species_symbol()), 2311 Object); 2312 if (constructor->IsNull(isolate)) { 2313 constructor = isolate->factory()->undefined_value(); 2314 } 2315 } 2316 } 2317 if (constructor->IsUndefined(isolate)) { 2318 return default_species; 2319 } else { 2320 if (!constructor->IsConstructor()) { 2321 THROW_NEW_ERROR(isolate, 2322 NewTypeError(MessageTemplate::kSpeciesNotConstructor), 2323 Object); 2324 } 2325 return constructor; 2326 } 2327 } 2328 2329 bool Object::IterationHasObservableEffects() { 2330 // Check that this object is an array. 2331 if (!IsJSArray()) return true; 2332 JSArray* spread_array = JSArray::cast(this); 2333 Isolate* isolate = spread_array->GetIsolate(); 2334 2335 // Check that we have the original ArrayPrototype. 2336 JSObject* array_proto = JSObject::cast(spread_array->map()->prototype()); 2337 if (!isolate->is_initial_array_prototype(array_proto)) return true; 2338 2339 // Check that the ArrayPrototype hasn't been modified in a way that would 2340 // affect iteration. 2341 if (!isolate->IsArrayIteratorLookupChainIntact()) return true; 2342 2343 // Check that the map of the initial array iterator hasn't changed. 2344 Map* iterator_map = isolate->initial_array_iterator_prototype()->map(); 2345 if (!isolate->is_initial_array_iterator_prototype_map(iterator_map)) { 2346 return true; 2347 } 2348 2349 // For FastPacked kinds, iteration will have the same effect as simply 2350 // accessing each property in order. 2351 ElementsKind array_kind = spread_array->GetElementsKind(); 2352 if (IsFastPackedElementsKind(array_kind)) return false; 2353 2354 // For FastHoley kinds, an element access on a hole would cause a lookup on 2355 // the prototype. This could have different results if the prototype has been 2356 // changed. 2357 if (IsFastHoleyElementsKind(array_kind) && 2358 isolate->IsFastArrayConstructorPrototypeChainIntact()) { 2359 return false; 2360 } 2361 return true; 2362 } 2363 2364 void Object::ShortPrint(FILE* out) { 2365 OFStream os(out); 2366 os << Brief(this); 2367 } 2368 2369 2370 void Object::ShortPrint(StringStream* accumulator) { 2371 std::ostringstream os; 2372 os << Brief(this); 2373 accumulator->Add(os.str().c_str()); 2374 } 2375 2376 2377 void Object::ShortPrint(std::ostream& os) { os << Brief(this); } 2378 2379 2380 std::ostream& operator<<(std::ostream& os, const Brief& v) { 2381 if (v.value->IsSmi()) { 2382 Smi::cast(v.value)->SmiPrint(os); 2383 } else { 2384 // TODO(svenpanne) Const-correct HeapObjectShortPrint! 2385 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value)); 2386 obj->HeapObjectShortPrint(os); 2387 } 2388 return os; 2389 } 2390 2391 void Smi::SmiPrint(std::ostream& os) const { // NOLINT 2392 os << value(); 2393 } 2394 2395 2396 // Should a word be prefixed by 'a' or 'an' in order to read naturally in 2397 // English? Returns false for non-ASCII or words that don't start with 2398 // a capital letter. The a/an rule follows pronunciation in English. 2399 // We don't use the BBC's overcorrect "an historic occasion" though if 2400 // you speak a dialect you may well say "an 'istoric occasion". 2401 static bool AnWord(String* str) { 2402 if (str->length() == 0) return false; // A nothing. 2403 int c0 = str->Get(0); 2404 int c1 = str->length() > 1 ? str->Get(1) : 0; 2405 if (c0 == 'U') { 2406 if (c1 > 'Z') { 2407 return true; // An Umpire, but a UTF8String, a U. 2408 } 2409 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { 2410 return true; // An Ape, an ABCBook. 2411 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && 2412 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || 2413 c0 == 'S' || c0 == 'X')) { 2414 return true; // An MP3File, an M. 2415 } 2416 return false; 2417 } 2418 2419 2420 Handle<String> String::SlowFlatten(Handle<ConsString> cons, 2421 PretenureFlag pretenure) { 2422 DCHECK(cons->second()->length() != 0); 2423 2424 // TurboFan can create cons strings with empty first parts. 2425 while (cons->first()->length() == 0) { 2426 // We do not want to call this function recursively. Therefore we call 2427 // String::Flatten only in those cases where String::SlowFlatten is not 2428 // called again. 2429 if (cons->second()->IsConsString() && !cons->second()->IsFlat()) { 2430 cons = handle(ConsString::cast(cons->second())); 2431 } else { 2432 return String::Flatten(handle(cons->second())); 2433 } 2434 } 2435 2436 DCHECK(AllowHeapAllocation::IsAllowed()); 2437 Isolate* isolate = cons->GetIsolate(); 2438 int length = cons->length(); 2439 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure 2440 : TENURED; 2441 Handle<SeqString> result; 2442 if (cons->IsOneByteRepresentation()) { 2443 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString( 2444 length, tenure).ToHandleChecked(); 2445 DisallowHeapAllocation no_gc; 2446 WriteToFlat(*cons, flat->GetChars(), 0, length); 2447 result = flat; 2448 } else { 2449 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString( 2450 length, tenure).ToHandleChecked(); 2451 DisallowHeapAllocation no_gc; 2452 WriteToFlat(*cons, flat->GetChars(), 0, length); 2453 result = flat; 2454 } 2455 cons->set_first(*result); 2456 cons->set_second(isolate->heap()->empty_string()); 2457 DCHECK(result->IsFlat()); 2458 return result; 2459 } 2460 2461 2462 2463 bool String::MakeExternal(v8::String::ExternalStringResource* resource) { 2464 // Externalizing twice leaks the external resource, so it's 2465 // prohibited by the API. 2466 DCHECK(!this->IsExternalString()); 2467 DCHECK(!resource->IsCompressible()); 2468 #ifdef ENABLE_SLOW_DCHECKS 2469 if (FLAG_enable_slow_asserts) { 2470 // Assert that the resource and the string are equivalent. 2471 DCHECK(static_cast<size_t>(this->length()) == resource->length()); 2472 ScopedVector<uc16> smart_chars(this->length()); 2473 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2474 DCHECK(memcmp(smart_chars.start(), 2475 resource->data(), 2476 resource->length() * sizeof(smart_chars[0])) == 0); 2477 } 2478 #endif // DEBUG 2479 int size = this->Size(); // Byte size of the original string. 2480 // Abort if size does not allow in-place conversion. 2481 if (size < ExternalString::kShortSize) return false; 2482 Heap* heap = GetHeap(); 2483 bool is_one_byte = this->IsOneByteRepresentation(); 2484 bool is_internalized = this->IsInternalizedString(); 2485 bool has_pointers = StringShape(this).IsIndirect(); 2486 2487 // Morph the string to an external string by replacing the map and 2488 // reinitializing the fields. This won't work if the space the existing 2489 // string occupies is too small for a regular external string. 2490 // Instead, we resort to a short external string instead, omitting 2491 // the field caching the address of the backing store. When we encounter 2492 // short external strings in generated code, we need to bailout to runtime. 2493 Map* new_map; 2494 if (size < ExternalString::kSize) { 2495 new_map = is_internalized 2496 ? (is_one_byte 2497 ? heap->short_external_internalized_string_with_one_byte_data_map() 2498 : heap->short_external_internalized_string_map()) 2499 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map() 2500 : heap->short_external_string_map()); 2501 } else { 2502 new_map = is_internalized 2503 ? (is_one_byte 2504 ? heap->external_internalized_string_with_one_byte_data_map() 2505 : heap->external_internalized_string_map()) 2506 : (is_one_byte ? heap->external_string_with_one_byte_data_map() 2507 : heap->external_string_map()); 2508 } 2509 2510 // Byte size of the external String object. 2511 int new_size = this->SizeFromMap(new_map); 2512 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, 2513 ClearRecordedSlots::kNo); 2514 if (has_pointers) { 2515 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size); 2516 } 2517 2518 // We are storing the new map using release store after creating a filler for 2519 // the left-over space to avoid races with the sweeper thread. 2520 this->synchronized_set_map(new_map); 2521 2522 ExternalTwoByteString* self = ExternalTwoByteString::cast(this); 2523 self->set_resource(resource); 2524 if (is_internalized) self->Hash(); // Force regeneration of the hash value. 2525 2526 heap->AdjustLiveBytes(this, new_size - size); 2527 return true; 2528 } 2529 2530 2531 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) { 2532 // Externalizing twice leaks the external resource, so it's 2533 // prohibited by the API. 2534 DCHECK(!this->IsExternalString()); 2535 DCHECK(!resource->IsCompressible()); 2536 #ifdef ENABLE_SLOW_DCHECKS 2537 if (FLAG_enable_slow_asserts) { 2538 // Assert that the resource and the string are equivalent. 2539 DCHECK(static_cast<size_t>(this->length()) == resource->length()); 2540 if (this->IsTwoByteRepresentation()) { 2541 ScopedVector<uint16_t> smart_chars(this->length()); 2542 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2543 DCHECK(String::IsOneByte(smart_chars.start(), this->length())); 2544 } 2545 ScopedVector<char> smart_chars(this->length()); 2546 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2547 DCHECK(memcmp(smart_chars.start(), 2548 resource->data(), 2549 resource->length() * sizeof(smart_chars[0])) == 0); 2550 } 2551 #endif // DEBUG 2552 int size = this->Size(); // Byte size of the original string. 2553 // Abort if size does not allow in-place conversion. 2554 if (size < ExternalString::kShortSize) return false; 2555 Heap* heap = GetHeap(); 2556 bool is_internalized = this->IsInternalizedString(); 2557 bool has_pointers = StringShape(this).IsIndirect(); 2558 2559 // Morph the string to an external string by replacing the map and 2560 // reinitializing the fields. This won't work if the space the existing 2561 // string occupies is too small for a regular external string. 2562 // Instead, we resort to a short external string instead, omitting 2563 // the field caching the address of the backing store. When we encounter 2564 // short external strings in generated code, we need to bailout to runtime. 2565 Map* new_map; 2566 if (size < ExternalString::kSize) { 2567 new_map = is_internalized 2568 ? heap->short_external_one_byte_internalized_string_map() 2569 : heap->short_external_one_byte_string_map(); 2570 } else { 2571 new_map = is_internalized 2572 ? heap->external_one_byte_internalized_string_map() 2573 : heap->external_one_byte_string_map(); 2574 } 2575 2576 // Byte size of the external String object. 2577 int new_size = this->SizeFromMap(new_map); 2578 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, 2579 ClearRecordedSlots::kNo); 2580 if (has_pointers) { 2581 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size); 2582 } 2583 2584 // We are storing the new map using release store after creating a filler for 2585 // the left-over space to avoid races with the sweeper thread. 2586 this->synchronized_set_map(new_map); 2587 2588 ExternalOneByteString* self = ExternalOneByteString::cast(this); 2589 self->set_resource(resource); 2590 if (is_internalized) self->Hash(); // Force regeneration of the hash value. 2591 2592 heap->AdjustLiveBytes(this, new_size - size); 2593 return true; 2594 } 2595 2596 void String::StringShortPrint(StringStream* accumulator, bool show_details) { 2597 int len = length(); 2598 if (len > kMaxShortPrintLength) { 2599 accumulator->Add("<Very long string[%u]>", len); 2600 return; 2601 } 2602 2603 if (!LooksValid()) { 2604 accumulator->Add("<Invalid String>"); 2605 return; 2606 } 2607 2608 StringCharacterStream stream(this); 2609 2610 bool truncated = false; 2611 if (len > kMaxShortPrintLength) { 2612 len = kMaxShortPrintLength; 2613 truncated = true; 2614 } 2615 bool one_byte = true; 2616 for (int i = 0; i < len; i++) { 2617 uint16_t c = stream.GetNext(); 2618 2619 if (c < 32 || c >= 127) { 2620 one_byte = false; 2621 } 2622 } 2623 stream.Reset(this); 2624 if (one_byte) { 2625 if (show_details) accumulator->Add("<String[%u]: ", length()); 2626 for (int i = 0; i < len; i++) { 2627 accumulator->Put(static_cast<char>(stream.GetNext())); 2628 } 2629 if (show_details) accumulator->Put('>'); 2630 } else { 2631 // Backslash indicates that the string contains control 2632 // characters and that backslashes are therefore escaped. 2633 if (show_details) accumulator->Add("<String[%u]\\: ", length()); 2634 for (int i = 0; i < len; i++) { 2635 uint16_t c = stream.GetNext(); 2636 if (c == '\n') { 2637 accumulator->Add("\\n"); 2638 } else if (c == '\r') { 2639 accumulator->Add("\\r"); 2640 } else if (c == '\\') { 2641 accumulator->Add("\\\\"); 2642 } else if (c < 32 || c > 126) { 2643 accumulator->Add("\\x%02x", c); 2644 } else { 2645 accumulator->Put(static_cast<char>(c)); 2646 } 2647 } 2648 if (truncated) { 2649 accumulator->Put('.'); 2650 accumulator->Put('.'); 2651 accumulator->Put('.'); 2652 } 2653 if (show_details) accumulator->Put('>'); 2654 } 2655 return; 2656 } 2657 2658 2659 void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT 2660 if (end < 0) end = length(); 2661 StringCharacterStream stream(this, start); 2662 for (int i = start; i < end && stream.HasMore(); i++) { 2663 os << AsUC16(stream.GetNext()); 2664 } 2665 } 2666 2667 2668 void JSObject::JSObjectShortPrint(StringStream* accumulator) { 2669 switch (map()->instance_type()) { 2670 case JS_ARRAY_TYPE: { 2671 double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate()) 2672 ? 0 2673 : JSArray::cast(this)->length()->Number(); 2674 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length)); 2675 break; 2676 } 2677 case JS_BOUND_FUNCTION_TYPE: { 2678 JSBoundFunction* bound_function = JSBoundFunction::cast(this); 2679 accumulator->Add("<JS BoundFunction"); 2680 accumulator->Add( 2681 " (BoundTargetFunction %p)>", 2682 reinterpret_cast<void*>(bound_function->bound_target_function())); 2683 break; 2684 } 2685 case JS_WEAK_MAP_TYPE: { 2686 accumulator->Add("<JS WeakMap>"); 2687 break; 2688 } 2689 case JS_WEAK_SET_TYPE: { 2690 accumulator->Add("<JS WeakSet>"); 2691 break; 2692 } 2693 case JS_REGEXP_TYPE: { 2694 accumulator->Add("<JS RegExp>"); 2695 break; 2696 } 2697 case JS_FUNCTION_TYPE: { 2698 JSFunction* function = JSFunction::cast(this); 2699 Object* fun_name = function->shared()->DebugName(); 2700 bool printed = false; 2701 if (fun_name->IsString()) { 2702 String* str = String::cast(fun_name); 2703 if (str->length() > 0) { 2704 accumulator->Add("<JS Function "); 2705 accumulator->Put(str); 2706 printed = true; 2707 } 2708 } 2709 if (!printed) { 2710 accumulator->Add("<JS Function"); 2711 } 2712 if (FLAG_trace_file_names) { 2713 Object* source_name = 2714 Script::cast(function->shared()->script())->name(); 2715 if (source_name->IsString()) { 2716 String* str = String::cast(source_name); 2717 if (str->length() > 0) { 2718 accumulator->Add(" <"); 2719 accumulator->Put(str); 2720 accumulator->Add(">"); 2721 } 2722 } 2723 } 2724 accumulator->Add(" (SharedFunctionInfo %p)", 2725 reinterpret_cast<void*>(function->shared())); 2726 accumulator->Put('>'); 2727 break; 2728 } 2729 case JS_GENERATOR_OBJECT_TYPE: { 2730 accumulator->Add("<JS Generator>"); 2731 break; 2732 } 2733 // All other JSObjects are rather similar to each other (JSObject, 2734 // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue). 2735 default: { 2736 Map* map_of_this = map(); 2737 Heap* heap = GetHeap(); 2738 Object* constructor = map_of_this->GetConstructor(); 2739 bool printed = false; 2740 if (constructor->IsHeapObject() && 2741 !heap->Contains(HeapObject::cast(constructor))) { 2742 accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); 2743 } else { 2744 bool global_object = IsJSGlobalProxy(); 2745 if (constructor->IsJSFunction()) { 2746 if (!heap->Contains(JSFunction::cast(constructor)->shared())) { 2747 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); 2748 } else { 2749 Object* constructor_name = 2750 JSFunction::cast(constructor)->shared()->name(); 2751 if (constructor_name->IsString()) { 2752 String* str = String::cast(constructor_name); 2753 if (str->length() > 0) { 2754 bool vowel = AnWord(str); 2755 accumulator->Add("<%sa%s ", 2756 global_object ? "Global Object: " : "", 2757 vowel ? "n" : ""); 2758 accumulator->Put(str); 2759 accumulator->Add(" with %smap %p", 2760 map_of_this->is_deprecated() ? "deprecated " : "", 2761 map_of_this); 2762 printed = true; 2763 } 2764 } 2765 } 2766 } 2767 if (!printed) { 2768 accumulator->Add("<JS %sObject", global_object ? "Global " : ""); 2769 } 2770 } 2771 if (IsJSValue()) { 2772 accumulator->Add(" value = "); 2773 JSValue::cast(this)->value()->ShortPrint(accumulator); 2774 } 2775 accumulator->Put('>'); 2776 break; 2777 } 2778 } 2779 } 2780 2781 2782 void JSObject::PrintElementsTransition( 2783 FILE* file, Handle<JSObject> object, 2784 ElementsKind from_kind, Handle<FixedArrayBase> from_elements, 2785 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) { 2786 if (from_kind != to_kind) { 2787 OFStream os(file); 2788 os << "elements transition [" << ElementsKindToString(from_kind) << " -> " 2789 << ElementsKindToString(to_kind) << "] in "; 2790 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true); 2791 PrintF(file, " for "); 2792 object->ShortPrint(file); 2793 PrintF(file, " from "); 2794 from_elements->ShortPrint(file); 2795 PrintF(file, " to "); 2796 to_elements->ShortPrint(file); 2797 PrintF(file, "\n"); 2798 } 2799 } 2800 2801 2802 // static 2803 MaybeHandle<JSFunction> Map::GetConstructorFunction( 2804 Handle<Map> map, Handle<Context> native_context) { 2805 if (map->IsPrimitiveMap()) { 2806 int const constructor_function_index = map->GetConstructorFunctionIndex(); 2807 if (constructor_function_index != kNoConstructorFunctionIndex) { 2808 return handle( 2809 JSFunction::cast(native_context->get(constructor_function_index))); 2810 } 2811 } 2812 return MaybeHandle<JSFunction>(); 2813 } 2814 2815 2816 void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind, 2817 PropertyAttributes attributes) { 2818 OFStream os(file); 2819 os << "[reconfiguring]"; 2820 Name* name = instance_descriptors()->GetKey(modify_index); 2821 if (name->IsString()) { 2822 String::cast(name)->PrintOn(file); 2823 } else { 2824 os << "{symbol " << static_cast<void*>(name) << "}"; 2825 } 2826 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: "; 2827 os << attributes << " ["; 2828 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true); 2829 os << "]\n"; 2830 } 2831 2832 void Map::PrintGeneralization( 2833 FILE* file, const char* reason, int modify_index, int split, 2834 int descriptors, bool descriptor_to_field, 2835 Representation old_representation, Representation new_representation, 2836 MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value, 2837 MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) { 2838 OFStream os(file); 2839 os << "[generalizing]"; 2840 Name* name = instance_descriptors()->GetKey(modify_index); 2841 if (name->IsString()) { 2842 String::cast(name)->PrintOn(file); 2843 } else { 2844 os << "{symbol " << static_cast<void*>(name) << "}"; 2845 } 2846 os << ":"; 2847 if (descriptor_to_field) { 2848 os << "c"; 2849 } else { 2850 os << old_representation.Mnemonic() << "{"; 2851 if (old_field_type.is_null()) { 2852 os << Brief(*(old_value.ToHandleChecked())); 2853 } else { 2854 old_field_type.ToHandleChecked()->PrintTo(os); 2855 } 2856 os << "}"; 2857 } 2858 os << "->" << new_representation.Mnemonic() << "{"; 2859 if (new_field_type.is_null()) { 2860 os << Brief(*(new_value.ToHandleChecked())); 2861 } else { 2862 new_field_type.ToHandleChecked()->PrintTo(os); 2863 } 2864 os << "} ("; 2865 if (strlen(reason) > 0) { 2866 os << reason; 2867 } else { 2868 os << "+" << (descriptors - split) << " maps"; 2869 } 2870 os << ") ["; 2871 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true); 2872 os << "]\n"; 2873 } 2874 2875 2876 void JSObject::PrintInstanceMigration(FILE* file, 2877 Map* original_map, 2878 Map* new_map) { 2879 PrintF(file, "[migrating]"); 2880 DescriptorArray* o = original_map->instance_descriptors(); 2881 DescriptorArray* n = new_map->instance_descriptors(); 2882 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) { 2883 Representation o_r = o->GetDetails(i).representation(); 2884 Representation n_r = n->GetDetails(i).representation(); 2885 if (!o_r.Equals(n_r)) { 2886 String::cast(o->GetKey(i))->PrintOn(file); 2887 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic()); 2888 } else if (o->GetDetails(i).location() == kDescriptor && 2889 n->GetDetails(i).location() == kField) { 2890 Name* name = o->GetKey(i); 2891 if (name->IsString()) { 2892 String::cast(name)->PrintOn(file); 2893 } else { 2894 PrintF(file, "{symbol %p}", static_cast<void*>(name)); 2895 } 2896 PrintF(file, " "); 2897 } 2898 } 2899 PrintF(file, "\n"); 2900 } 2901 2902 2903 void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT 2904 Heap* heap = GetHeap(); 2905 Isolate* isolate = heap->isolate(); 2906 if (!heap->Contains(this)) { 2907 os << "!!!INVALID POINTER!!!"; 2908 return; 2909 } 2910 if (!heap->Contains(map())) { 2911 os << "!!!INVALID MAP!!!"; 2912 return; 2913 } 2914 2915 os << this << " "; 2916 2917 if (IsString()) { 2918 HeapStringAllocator allocator; 2919 StringStream accumulator(&allocator); 2920 String::cast(this)->StringShortPrint(&accumulator); 2921 os << accumulator.ToCString().get(); 2922 return; 2923 } 2924 if (IsJSObject()) { 2925 HeapStringAllocator allocator; 2926 StringStream accumulator(&allocator); 2927 JSObject::cast(this)->JSObjectShortPrint(&accumulator); 2928 os << accumulator.ToCString().get(); 2929 return; 2930 } 2931 switch (map()->instance_type()) { 2932 case MAP_TYPE: 2933 os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind()) 2934 << ")>"; 2935 break; 2936 case FIXED_ARRAY_TYPE: 2937 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>"; 2938 break; 2939 case FIXED_DOUBLE_ARRAY_TYPE: 2940 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length() 2941 << "]>"; 2942 break; 2943 case BYTE_ARRAY_TYPE: 2944 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>"; 2945 break; 2946 case BYTECODE_ARRAY_TYPE: 2947 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>"; 2948 break; 2949 case TRANSITION_ARRAY_TYPE: 2950 os << "<TransitionArray[" << TransitionArray::cast(this)->length() 2951 << "]>"; 2952 break; 2953 case FREE_SPACE_TYPE: 2954 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>"; 2955 break; 2956 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \ 2957 case FIXED_##TYPE##_ARRAY_TYPE: \ 2958 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \ 2959 << "]>"; \ 2960 break; 2961 2962 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT) 2963 #undef TYPED_ARRAY_SHORT_PRINT 2964 2965 case SHARED_FUNCTION_INFO_TYPE: { 2966 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this); 2967 std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString(); 2968 if (debug_name[0] != 0) { 2969 os << "<SharedFunctionInfo " << debug_name.get() << ">"; 2970 } else { 2971 os << "<SharedFunctionInfo>"; 2972 } 2973 break; 2974 } 2975 case JS_MESSAGE_OBJECT_TYPE: 2976 os << "<JSMessageObject>"; 2977 break; 2978 #define MAKE_STRUCT_CASE(NAME, Name, name) \ 2979 case NAME##_TYPE: \ 2980 os << "<" #Name ">"; \ 2981 break; 2982 STRUCT_LIST(MAKE_STRUCT_CASE) 2983 #undef MAKE_STRUCT_CASE 2984 case CODE_TYPE: { 2985 Code* code = Code::cast(this); 2986 os << "<Code: " << Code::Kind2String(code->kind()) << ">"; 2987 break; 2988 } 2989 case ODDBALL_TYPE: { 2990 if (IsUndefined(isolate)) { 2991 os << "<undefined>"; 2992 } else if (IsTheHole(isolate)) { 2993 os << "<the hole>"; 2994 } else if (IsNull(isolate)) { 2995 os << "<null>"; 2996 } else if (IsTrue(isolate)) { 2997 os << "<true>"; 2998 } else if (IsFalse(isolate)) { 2999 os << "<false>"; 3000 } else { 3001 os << "<Odd Oddball: "; 3002 os << Oddball::cast(this)->to_string()->ToCString().get(); 3003 os << ">"; 3004 } 3005 break; 3006 } 3007 case SYMBOL_TYPE: { 3008 Symbol* symbol = Symbol::cast(this); 3009 symbol->SymbolShortPrint(os); 3010 break; 3011 } 3012 case HEAP_NUMBER_TYPE: { 3013 os << "<Number: "; 3014 HeapNumber::cast(this)->HeapNumberPrint(os); 3015 os << ">"; 3016 break; 3017 } 3018 case MUTABLE_HEAP_NUMBER_TYPE: { 3019 os << "<MutableNumber: "; 3020 HeapNumber::cast(this)->HeapNumberPrint(os); 3021 os << '>'; 3022 break; 3023 } 3024 case JS_PROXY_TYPE: 3025 os << "<JSProxy>"; 3026 break; 3027 case FOREIGN_TYPE: 3028 os << "<Foreign>"; 3029 break; 3030 case CELL_TYPE: { 3031 os << "Cell for "; 3032 HeapStringAllocator allocator; 3033 StringStream accumulator(&allocator); 3034 Cell::cast(this)->value()->ShortPrint(&accumulator); 3035 os << accumulator.ToCString().get(); 3036 break; 3037 } 3038 case PROPERTY_CELL_TYPE: { 3039 os << "PropertyCell for "; 3040 HeapStringAllocator allocator; 3041 StringStream accumulator(&allocator); 3042 PropertyCell* cell = PropertyCell::cast(this); 3043 cell->value()->ShortPrint(&accumulator); 3044 os << accumulator.ToCString().get(); 3045 break; 3046 } 3047 case WEAK_CELL_TYPE: { 3048 os << "WeakCell for "; 3049 HeapStringAllocator allocator; 3050 StringStream accumulator(&allocator); 3051 WeakCell::cast(this)->value()->ShortPrint(&accumulator); 3052 os << accumulator.ToCString().get(); 3053 break; 3054 } 3055 default: 3056 os << "<Other heap object (" << map()->instance_type() << ")>"; 3057 break; 3058 } 3059 } 3060 3061 3062 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); } 3063 3064 3065 void HeapObject::IterateBody(ObjectVisitor* v) { 3066 Map* m = map(); 3067 IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v); 3068 } 3069 3070 3071 void HeapObject::IterateBody(InstanceType type, int object_size, 3072 ObjectVisitor* v) { 3073 IterateBodyFast<ObjectVisitor>(type, object_size, v); 3074 } 3075 3076 3077 struct CallIsValidSlot { 3078 template <typename BodyDescriptor> 3079 static bool apply(HeapObject* obj, int offset, int) { 3080 return BodyDescriptor::IsValidSlot(obj, offset); 3081 } 3082 }; 3083 3084 3085 bool HeapObject::IsValidSlot(int offset) { 3086 DCHECK_NE(0, offset); 3087 return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(), 3088 this, offset, 0); 3089 } 3090 3091 3092 bool HeapNumber::HeapNumberBooleanValue() { 3093 return DoubleToBoolean(value()); 3094 } 3095 3096 3097 void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT 3098 os << value(); 3099 } 3100 3101 3102 #define FIELD_ADDR_CONST(p, offset) \ 3103 (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag) 3104 3105 #define READ_INT32_FIELD(p, offset) \ 3106 (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset))) 3107 3108 #define READ_INT64_FIELD(p, offset) \ 3109 (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset))) 3110 3111 #define READ_BYTE_FIELD(p, offset) \ 3112 (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset))) 3113 3114 String* JSReceiver::class_name() { 3115 if (IsFunction()) { 3116 return GetHeap()->Function_string(); 3117 } 3118 Object* maybe_constructor = map()->GetConstructor(); 3119 if (maybe_constructor->IsJSFunction()) { 3120 JSFunction* constructor = JSFunction::cast(maybe_constructor); 3121 return String::cast(constructor->shared()->instance_class_name()); 3122 } 3123 // If the constructor is not present, return "Object". 3124 return GetHeap()->Object_string(); 3125 } 3126 3127 3128 // static 3129 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) { 3130 Isolate* isolate = receiver->GetIsolate(); 3131 3132 // If the object was instantiated simply with base == new.target, the 3133 // constructor on the map provides the most accurate name. 3134 // Don't provide the info for prototypes, since their constructors are 3135 // reclaimed and replaced by Object in OptimizeAsPrototype. 3136 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() && 3137 !receiver->map()->is_prototype_map()) { 3138 Object* maybe_constructor = receiver->map()->GetConstructor(); 3139 if (maybe_constructor->IsJSFunction()) { 3140 JSFunction* constructor = JSFunction::cast(maybe_constructor); 3141 String* name = String::cast(constructor->shared()->name()); 3142 if (name->length() == 0) name = constructor->shared()->inferred_name(); 3143 if (name->length() != 0 && 3144 !name->Equals(isolate->heap()->Object_string())) { 3145 return handle(name, isolate); 3146 } 3147 } 3148 } 3149 3150 Handle<Object> maybe_tag = JSReceiver::GetDataProperty( 3151 receiver, isolate->factory()->to_string_tag_symbol()); 3152 if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag); 3153 3154 PrototypeIterator iter(isolate, receiver); 3155 if (iter.IsAtEnd()) return handle(receiver->class_name()); 3156 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter); 3157 LookupIterator it(receiver, isolate->factory()->constructor_string(), start, 3158 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); 3159 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it); 3160 Handle<String> result = isolate->factory()->Object_string(); 3161 if (maybe_constructor->IsJSFunction()) { 3162 JSFunction* constructor = JSFunction::cast(*maybe_constructor); 3163 String* name = String::cast(constructor->shared()->name()); 3164 if (name->length() == 0) name = constructor->shared()->inferred_name(); 3165 if (name->length() > 0) result = handle(name, isolate); 3166 } 3167 3168 return result.is_identical_to(isolate->factory()->Object_string()) 3169 ? handle(receiver->class_name()) 3170 : result; 3171 } 3172 3173 Handle<Context> JSReceiver::GetCreationContext() { 3174 JSReceiver* receiver = this; 3175 while (receiver->IsJSBoundFunction()) { 3176 receiver = JSBoundFunction::cast(receiver)->bound_target_function(); 3177 } 3178 Object* constructor = receiver->map()->GetConstructor(); 3179 JSFunction* function; 3180 if (constructor->IsJSFunction()) { 3181 function = JSFunction::cast(constructor); 3182 } else { 3183 // Functions have null as a constructor, 3184 // but any JSFunction knows its context immediately. 3185 CHECK(receiver->IsJSFunction()); 3186 function = JSFunction::cast(receiver); 3187 } 3188 3189 return function->has_context() 3190 ? Handle<Context>(function->context()->native_context()) 3191 : Handle<Context>::null(); 3192 } 3193 3194 Handle<Object> Map::WrapFieldType(Handle<FieldType> type) { 3195 if (type->IsClass()) return Map::WeakCellForMap(type->AsClass()); 3196 return type; 3197 } 3198 3199 FieldType* Map::UnwrapFieldType(Object* wrapped_type) { 3200 Object* value = wrapped_type; 3201 if (value->IsWeakCell()) { 3202 if (WeakCell::cast(value)->cleared()) return FieldType::None(); 3203 value = WeakCell::cast(value)->value(); 3204 } 3205 return FieldType::cast(value); 3206 } 3207 3208 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name, 3209 Handle<FieldType> type, 3210 PropertyAttributes attributes, 3211 PropertyConstness constness, 3212 Representation representation, 3213 TransitionFlag flag) { 3214 DCHECK(DescriptorArray::kNotFound == 3215 map->instance_descriptors()->Search( 3216 *name, map->NumberOfOwnDescriptors())); 3217 3218 // Ensure the descriptor array does not get too big. 3219 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { 3220 return MaybeHandle<Map>(); 3221 } 3222 3223 Isolate* isolate = map->GetIsolate(); 3224 3225 // Compute the new index for new field. 3226 int index = map->NextFreePropertyIndex(); 3227 3228 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) { 3229 representation = Representation::Tagged(); 3230 type = FieldType::Any(isolate); 3231 } 3232 3233 Handle<Object> wrapped_type(WrapFieldType(type)); 3234 3235 DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable); 3236 Descriptor d = Descriptor::DataField(name, index, attributes, constness, 3237 representation, wrapped_type); 3238 Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag); 3239 int unused_property_fields = new_map->unused_property_fields() - 1; 3240 if (unused_property_fields < 0) { 3241 unused_property_fields += JSObject::kFieldsAdded; 3242 } 3243 new_map->set_unused_property_fields(unused_property_fields); 3244 return new_map; 3245 } 3246 3247 3248 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map, 3249 Handle<Name> name, 3250 Handle<Object> constant, 3251 PropertyAttributes attributes, 3252 TransitionFlag flag) { 3253 // Ensure the descriptor array does not get too big. 3254 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { 3255 return MaybeHandle<Map>(); 3256 } 3257 3258 if (FLAG_track_constant_fields) { 3259 Isolate* isolate = map->GetIsolate(); 3260 Representation representation = constant->OptimalRepresentation(); 3261 Handle<FieldType> type = constant->OptimalType(isolate, representation); 3262 return CopyWithField(map, name, type, attributes, kConst, representation, 3263 flag); 3264 } else { 3265 // Allocate new instance descriptors with (name, constant) added. 3266 Descriptor d = Descriptor::DataConstant(name, 0, constant, attributes); 3267 Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag); 3268 return new_map; 3269 } 3270 } 3271 3272 const char* Representation::Mnemonic() const { 3273 switch (kind_) { 3274 case kNone: return "v"; 3275 case kTagged: return "t"; 3276 case kSmi: return "s"; 3277 case kDouble: return "d"; 3278 case kInteger32: return "i"; 3279 case kHeapObject: return "h"; 3280 case kExternal: return "x"; 3281 default: 3282 UNREACHABLE(); 3283 return NULL; 3284 } 3285 } 3286 3287 bool Map::TransitionRemovesTaggedField(Map* target) { 3288 int inobject = GetInObjectProperties(); 3289 int target_inobject = target->GetInObjectProperties(); 3290 for (int i = target_inobject; i < inobject; i++) { 3291 FieldIndex index = FieldIndex::ForPropertyIndex(this, i); 3292 if (!IsUnboxedDoubleField(index)) return true; 3293 } 3294 return false; 3295 } 3296 3297 bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) { 3298 int inobject = GetInObjectProperties(); 3299 int target_inobject = target->GetInObjectProperties(); 3300 int limit = Min(inobject, target_inobject); 3301 for (int i = 0; i < limit; i++) { 3302 FieldIndex index = FieldIndex::ForPropertyIndex(target, i); 3303 if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) { 3304 return true; 3305 } 3306 } 3307 return false; 3308 } 3309 3310 bool Map::TransitionRequiresSynchronizationWithGC(Map* target) { 3311 return TransitionRemovesTaggedField(target) || 3312 TransitionChangesTaggedFieldToUntaggedField(target); 3313 } 3314 3315 bool Map::InstancesNeedRewriting(Map* target) { 3316 int target_number_of_fields = target->NumberOfFields(); 3317 int target_inobject = target->GetInObjectProperties(); 3318 int target_unused = target->unused_property_fields(); 3319 int old_number_of_fields; 3320 3321 return InstancesNeedRewriting(target, target_number_of_fields, 3322 target_inobject, target_unused, 3323 &old_number_of_fields); 3324 } 3325 3326 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields, 3327 int target_inobject, int target_unused, 3328 int* old_number_of_fields) { 3329 // If fields were added (or removed), rewrite the instance. 3330 *old_number_of_fields = NumberOfFields(); 3331 DCHECK(target_number_of_fields >= *old_number_of_fields); 3332 if (target_number_of_fields != *old_number_of_fields) return true; 3333 3334 // If smi descriptors were replaced by double descriptors, rewrite. 3335 DescriptorArray* old_desc = instance_descriptors(); 3336 DescriptorArray* new_desc = target->instance_descriptors(); 3337 int limit = NumberOfOwnDescriptors(); 3338 for (int i = 0; i < limit; i++) { 3339 if (new_desc->GetDetails(i).representation().IsDouble() != 3340 old_desc->GetDetails(i).representation().IsDouble()) { 3341 return true; 3342 } 3343 } 3344 3345 // If no fields were added, and no inobject properties were removed, setting 3346 // the map is sufficient. 3347 if (target_inobject == GetInObjectProperties()) return false; 3348 // In-object slack tracking may have reduced the object size of the new map. 3349 // In that case, succeed if all existing fields were inobject, and they still 3350 // fit within the new inobject size. 3351 DCHECK(target_inobject < GetInObjectProperties()); 3352 if (target_number_of_fields <= target_inobject) { 3353 DCHECK(target_number_of_fields + target_unused == target_inobject); 3354 return false; 3355 } 3356 // Otherwise, properties will need to be moved to the backing store. 3357 return true; 3358 } 3359 3360 3361 // static 3362 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map, 3363 Handle<Map> new_map, 3364 Isolate* isolate) { 3365 DCHECK(old_map->is_prototype_map()); 3366 DCHECK(new_map->is_prototype_map()); 3367 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate); 3368 new_map->set_prototype_info(old_map->prototype_info()); 3369 old_map->set_prototype_info(Smi::kZero); 3370 if (FLAG_trace_prototype_users) { 3371 PrintF("Moving prototype_info %p from map %p to map %p.\n", 3372 reinterpret_cast<void*>(new_map->prototype_info()), 3373 reinterpret_cast<void*>(*old_map), 3374 reinterpret_cast<void*>(*new_map)); 3375 } 3376 if (was_registered) { 3377 if (new_map->prototype_info()->IsPrototypeInfo()) { 3378 // The new map isn't registered with its prototype yet; reflect this fact 3379 // in the PrototypeInfo it just inherited from the old map. 3380 PrototypeInfo::cast(new_map->prototype_info()) 3381 ->set_registry_slot(PrototypeInfo::UNREGISTERED); 3382 } 3383 JSObject::LazyRegisterPrototypeUser(new_map, isolate); 3384 } 3385 } 3386 3387 namespace { 3388 // To migrate a fast instance to a fast map: 3389 // - First check whether the instance needs to be rewritten. If not, simply 3390 // change the map. 3391 // - Otherwise, allocate a fixed array large enough to hold all fields, in 3392 // addition to unused space. 3393 // - Copy all existing properties in, in the following order: backing store 3394 // properties, unused fields, inobject properties. 3395 // - If all allocation succeeded, commit the state atomically: 3396 // * Copy inobject properties from the backing store back into the object. 3397 // * Trim the difference in instance size of the object. This also cleanly 3398 // frees inobject properties that moved to the backing store. 3399 // * If there are properties left in the backing store, trim of the space used 3400 // to temporarily store the inobject properties. 3401 // * If there are properties left in the backing store, install the backing 3402 // store. 3403 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { 3404 Isolate* isolate = object->GetIsolate(); 3405 Handle<Map> old_map(object->map()); 3406 // In case of a regular transition. 3407 if (new_map->GetBackPointer() == *old_map) { 3408 // If the map does not add named properties, simply set the map. 3409 if (old_map->NumberOfOwnDescriptors() == 3410 new_map->NumberOfOwnDescriptors()) { 3411 object->synchronized_set_map(*new_map); 3412 return; 3413 } 3414 3415 PropertyDetails details = new_map->GetLastDescriptorDetails(); 3416 // Either new_map adds an kDescriptor property, or a kField property for 3417 // which there is still space, and which does not require a mutable double 3418 // box (an out-of-object double). 3419 if (details.location() == kDescriptor || 3420 (old_map->unused_property_fields() > 0 && 3421 ((FLAG_unbox_double_fields && object->properties()->length() == 0) || 3422 !details.representation().IsDouble()))) { 3423 object->synchronized_set_map(*new_map); 3424 return; 3425 } 3426 3427 // If there is still space in the object, we need to allocate a mutable 3428 // double box. 3429 if (old_map->unused_property_fields() > 0) { 3430 FieldIndex index = 3431 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded()); 3432 DCHECK(details.representation().IsDouble()); 3433 DCHECK(!new_map->IsUnboxedDoubleField(index)); 3434 Handle<Object> value = isolate->factory()->NewMutableHeapNumber(); 3435 object->RawFastPropertyAtPut(index, *value); 3436 object->synchronized_set_map(*new_map); 3437 return; 3438 } 3439 3440 // This migration is a transition from a map that has run out of property 3441 // space. Extend the backing store. 3442 int grow_by = new_map->unused_property_fields() + 1; 3443 Handle<FixedArray> old_storage = handle(object->properties(), isolate); 3444 Handle<FixedArray> new_storage = 3445 isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by); 3446 3447 // Properly initialize newly added property. 3448 Handle<Object> value; 3449 if (details.representation().IsDouble()) { 3450 value = isolate->factory()->NewMutableHeapNumber(); 3451 } else { 3452 value = isolate->factory()->uninitialized_value(); 3453 } 3454 DCHECK_EQ(kField, details.location()); 3455 DCHECK_EQ(kData, details.kind()); 3456 int target_index = details.field_index() - new_map->GetInObjectProperties(); 3457 DCHECK(target_index >= 0); // Must be a backing store index. 3458 new_storage->set(target_index, *value); 3459 3460 // From here on we cannot fail and we shouldn't GC anymore. 3461 DisallowHeapAllocation no_allocation; 3462 3463 // Set the new property value and do the map transition. 3464 object->set_properties(*new_storage); 3465 object->synchronized_set_map(*new_map); 3466 return; 3467 } 3468 3469 int old_number_of_fields; 3470 int number_of_fields = new_map->NumberOfFields(); 3471 int inobject = new_map->GetInObjectProperties(); 3472 int unused = new_map->unused_property_fields(); 3473 3474 // Nothing to do if no functions were converted to fields and no smis were 3475 // converted to doubles. 3476 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject, 3477 unused, &old_number_of_fields)) { 3478 object->synchronized_set_map(*new_map); 3479 return; 3480 } 3481 3482 int total_size = number_of_fields + unused; 3483 int external = total_size - inobject; 3484 3485 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size); 3486 3487 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); 3488 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors()); 3489 int old_nof = old_map->NumberOfOwnDescriptors(); 3490 int new_nof = new_map->NumberOfOwnDescriptors(); 3491 3492 // This method only supports generalizing instances to at least the same 3493 // number of properties. 3494 DCHECK(old_nof <= new_nof); 3495 3496 for (int i = 0; i < old_nof; i++) { 3497 PropertyDetails details = new_descriptors->GetDetails(i); 3498 if (details.location() != kField) continue; 3499 DCHECK_EQ(kData, details.kind()); 3500 PropertyDetails old_details = old_descriptors->GetDetails(i); 3501 Representation old_representation = old_details.representation(); 3502 Representation representation = details.representation(); 3503 Handle<Object> value; 3504 if (old_details.location() == kDescriptor) { 3505 if (old_details.kind() == kAccessor) { 3506 // In case of kAccessor -> kData property reconfiguration, the property 3507 // must already be prepared for data of certain type. 3508 DCHECK(!details.representation().IsNone()); 3509 if (details.representation().IsDouble()) { 3510 value = isolate->factory()->NewMutableHeapNumber(); 3511 } else { 3512 value = isolate->factory()->uninitialized_value(); 3513 } 3514 } else { 3515 DCHECK_EQ(kData, old_details.kind()); 3516 value = handle(old_descriptors->GetValue(i), isolate); 3517 DCHECK(!old_representation.IsDouble() && !representation.IsDouble()); 3518 } 3519 } else { 3520 DCHECK_EQ(kField, old_details.location()); 3521 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i); 3522 if (object->IsUnboxedDoubleField(index)) { 3523 uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index); 3524 value = isolate->factory()->NewHeapNumberFromBits( 3525 old_bits, representation.IsDouble() ? MUTABLE : IMMUTABLE); 3526 3527 } else { 3528 value = handle(object->RawFastPropertyAt(index), isolate); 3529 if (!old_representation.IsDouble() && representation.IsDouble()) { 3530 DCHECK_IMPLIES(old_representation.IsNone(), 3531 value->IsUninitialized(isolate)); 3532 value = Object::NewStorageFor(isolate, value, representation); 3533 } else if (old_representation.IsDouble() && 3534 !representation.IsDouble()) { 3535 value = Object::WrapForRead(isolate, value, old_representation); 3536 } 3537 } 3538 } 3539 DCHECK(!(representation.IsDouble() && value->IsSmi())); 3540 int target_index = new_descriptors->GetFieldIndex(i) - inobject; 3541 if (target_index < 0) target_index += total_size; 3542 array->set(target_index, *value); 3543 } 3544 3545 for (int i = old_nof; i < new_nof; i++) { 3546 PropertyDetails details = new_descriptors->GetDetails(i); 3547 if (details.location() != kField) continue; 3548 DCHECK_EQ(kData, details.kind()); 3549 Handle<Object> value; 3550 if (details.representation().IsDouble()) { 3551 value = isolate->factory()->NewMutableHeapNumber(); 3552 } else { 3553 value = isolate->factory()->uninitialized_value(); 3554 } 3555 int target_index = new_descriptors->GetFieldIndex(i) - inobject; 3556 if (target_index < 0) target_index += total_size; 3557 array->set(target_index, *value); 3558 } 3559 3560 // From here on we cannot fail and we shouldn't GC anymore. 3561 DisallowHeapAllocation no_allocation; 3562 3563 Heap* heap = isolate->heap(); 3564 3565 heap->NotifyObjectLayoutChange(*object, no_allocation); 3566 3567 // Copy (real) inobject properties. If necessary, stop at number_of_fields to 3568 // avoid overwriting |one_pointer_filler_map|. 3569 int limit = Min(inobject, number_of_fields); 3570 for (int i = 0; i < limit; i++) { 3571 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); 3572 Object* value = array->get(external + i); 3573 // Can't use JSObject::FastPropertyAtPut() because proper map was not set 3574 // yet. 3575 if (new_map->IsUnboxedDoubleField(index)) { 3576 DCHECK(value->IsMutableHeapNumber()); 3577 // Ensure that all bits of the double value are preserved. 3578 object->RawFastDoublePropertyAsBitsAtPut( 3579 index, HeapNumber::cast(value)->value_as_bits()); 3580 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) { 3581 // Transition from tagged to untagged slot. 3582 heap->ClearRecordedSlot(*object, 3583 HeapObject::RawField(*object, index.offset())); 3584 } else { 3585 DCHECK(!heap->HasRecordedSlot( 3586 *object, HeapObject::RawField(*object, index.offset()))); 3587 } 3588 } else { 3589 object->RawFastPropertyAtPut(index, value); 3590 } 3591 } 3592 3593 3594 // If there are properties in the new backing store, trim it to the correct 3595 // size and install the backing store into the object. 3596 if (external > 0) { 3597 heap->RightTrimFixedArray(*array, inobject); 3598 object->set_properties(*array); 3599 } 3600 3601 // Create filler object past the new instance size. 3602 int new_instance_size = new_map->instance_size(); 3603 int instance_size_delta = old_map->instance_size() - new_instance_size; 3604 DCHECK(instance_size_delta >= 0); 3605 3606 if (instance_size_delta > 0) { 3607 Address address = object->address(); 3608 heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta, 3609 ClearRecordedSlots::kYes); 3610 heap->AdjustLiveBytes(*object, -instance_size_delta); 3611 } 3612 3613 // We are storing the new map using release store after creating a filler for 3614 // the left-over space to avoid races with the sweeper thread. 3615 object->synchronized_set_map(*new_map); 3616 } 3617 3618 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map, 3619 int expected_additional_properties) { 3620 // The global object is always normalized. 3621 DCHECK(!object->IsJSGlobalObject()); 3622 // JSGlobalProxy must never be normalized 3623 DCHECK(!object->IsJSGlobalProxy()); 3624 3625 Isolate* isolate = object->GetIsolate(); 3626 HandleScope scope(isolate); 3627 Handle<Map> map(object->map()); 3628 3629 // Allocate new content. 3630 int real_size = map->NumberOfOwnDescriptors(); 3631 int property_count = real_size; 3632 if (expected_additional_properties > 0) { 3633 property_count += expected_additional_properties; 3634 } else { 3635 // Make space for two more properties. 3636 property_count += NameDictionary::kInitialCapacity; 3637 } 3638 Handle<NameDictionary> dictionary = 3639 NameDictionary::New(isolate, property_count); 3640 3641 Handle<DescriptorArray> descs(map->instance_descriptors()); 3642 for (int i = 0; i < real_size; i++) { 3643 PropertyDetails details = descs->GetDetails(i); 3644 Handle<Name> key(descs->GetKey(i)); 3645 Handle<Object> value; 3646 if (details.location() == kField) { 3647 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 3648 if (details.kind() == kData) { 3649 if (object->IsUnboxedDoubleField(index)) { 3650 double old_value = object->RawFastDoublePropertyAt(index); 3651 value = isolate->factory()->NewHeapNumber(old_value); 3652 } else { 3653 value = handle(object->RawFastPropertyAt(index), isolate); 3654 if (details.representation().IsDouble()) { 3655 DCHECK(value->IsMutableHeapNumber()); 3656 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value); 3657 value = isolate->factory()->NewHeapNumber(old->value()); 3658 } 3659 } 3660 } else { 3661 DCHECK_EQ(kAccessor, details.kind()); 3662 value = handle(object->RawFastPropertyAt(index), isolate); 3663 } 3664 3665 } else { 3666 DCHECK_EQ(kDescriptor, details.location()); 3667 value = handle(descs->GetValue(i), isolate); 3668 } 3669 DCHECK(!value.is_null()); 3670 PropertyDetails d(details.kind(), details.attributes(), i + 1, 3671 PropertyCellType::kNoCell); 3672 dictionary = NameDictionary::Add(dictionary, key, value, d); 3673 } 3674 3675 // Copy the next enumeration index from instance descriptor. 3676 dictionary->SetNextEnumerationIndex(real_size + 1); 3677 3678 // From here on we cannot fail and we shouldn't GC anymore. 3679 DisallowHeapAllocation no_allocation; 3680 3681 Heap* heap = isolate->heap(); 3682 heap->NotifyObjectLayoutChange(*object, no_allocation); 3683 3684 // Resize the object in the heap if necessary. 3685 int new_instance_size = new_map->instance_size(); 3686 int instance_size_delta = map->instance_size() - new_instance_size; 3687 DCHECK(instance_size_delta >= 0); 3688 3689 if (instance_size_delta > 0) { 3690 heap->CreateFillerObjectAt(object->address() + new_instance_size, 3691 instance_size_delta, ClearRecordedSlots::kYes); 3692 heap->AdjustLiveBytes(*object, -instance_size_delta); 3693 } 3694 3695 // We are storing the new map using release store after creating a filler for 3696 // the left-over space to avoid races with the sweeper thread. 3697 object->synchronized_set_map(*new_map); 3698 3699 object->set_properties(*dictionary); 3700 3701 // Ensure that in-object space of slow-mode object does not contain random 3702 // garbage. 3703 int inobject_properties = new_map->GetInObjectProperties(); 3704 if (inobject_properties) { 3705 Heap* heap = isolate->heap(); 3706 heap->ClearRecordedSlotRange( 3707 object->address() + map->GetInObjectPropertyOffset(0), 3708 object->address() + new_instance_size); 3709 3710 for (int i = 0; i < inobject_properties; i++) { 3711 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); 3712 object->RawFastPropertyAtPut(index, Smi::kZero); 3713 } 3714 } 3715 3716 isolate->counters()->props_to_dictionary()->Increment(); 3717 3718 #ifdef DEBUG 3719 if (FLAG_trace_normalization) { 3720 OFStream os(stdout); 3721 os << "Object properties have been normalized:\n"; 3722 object->Print(os); 3723 } 3724 #endif 3725 } 3726 3727 } // namespace 3728 3729 // static 3730 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map, 3731 Isolate* isolate) { 3732 if (!old_map->is_prototype_map()) return; 3733 3734 InvalidatePrototypeChains(*old_map); 3735 3736 // If the map was registered with its prototype before, ensure that it 3737 // registers with its new prototype now. This preserves the invariant that 3738 // when a map on a prototype chain is registered with its prototype, then 3739 // all prototypes further up the chain are also registered with their 3740 // respective prototypes. 3741 UpdatePrototypeUserRegistration(old_map, new_map, isolate); 3742 } 3743 3744 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, 3745 int expected_additional_properties) { 3746 if (object->map() == *new_map) return; 3747 Handle<Map> old_map(object->map()); 3748 NotifyMapChange(old_map, new_map, new_map->GetIsolate()); 3749 3750 if (old_map->is_dictionary_map()) { 3751 // For slow-to-fast migrations JSObject::MigrateSlowToFast() 3752 // must be used instead. 3753 CHECK(new_map->is_dictionary_map()); 3754 3755 // Slow-to-slow migration is trivial. 3756 object->set_map(*new_map); 3757 } else if (!new_map->is_dictionary_map()) { 3758 MigrateFastToFast(object, new_map); 3759 if (old_map->is_prototype_map()) { 3760 DCHECK(!old_map->is_stable()); 3761 DCHECK(new_map->is_stable()); 3762 // Clear out the old descriptor array to avoid problems to sharing 3763 // the descriptor array without using an explicit. 3764 old_map->InitializeDescriptors( 3765 old_map->GetHeap()->empty_descriptor_array(), 3766 LayoutDescriptor::FastPointerLayout()); 3767 // Ensure that no transition was inserted for prototype migrations. 3768 DCHECK_EQ( 3769 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions())); 3770 DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate())); 3771 } 3772 } else { 3773 MigrateFastToSlow(object, new_map, expected_additional_properties); 3774 } 3775 3776 // Careful: Don't allocate here! 3777 // For some callers of this method, |object| might be in an inconsistent 3778 // state now: the new map might have a new elements_kind, but the object's 3779 // elements pointer hasn't been updated yet. Callers will fix this, but in 3780 // the meantime, (indirectly) calling JSObjectVerify() must be avoided. 3781 // When adding code here, add a DisallowHeapAllocation too. 3782 } 3783 3784 void JSObject::ForceSetPrototype(Handle<JSObject> object, 3785 Handle<Object> proto) { 3786 // object.__proto__ = proto; 3787 Handle<Map> old_map = Handle<Map>(object->map()); 3788 Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype"); 3789 Map::SetPrototype(new_map, proto, FAST_PROTOTYPE); 3790 JSObject::MigrateToMap(object, new_map); 3791 } 3792 3793 int Map::NumberOfFields() { 3794 DescriptorArray* descriptors = instance_descriptors(); 3795 int result = 0; 3796 for (int i = 0; i < NumberOfOwnDescriptors(); i++) { 3797 if (descriptors->GetDetails(i).location() == kField) result++; 3798 } 3799 return result; 3800 } 3801 3802 void DescriptorArray::GeneralizeAllFields() { 3803 int length = number_of_descriptors(); 3804 for (int i = 0; i < length; i++) { 3805 PropertyDetails details = GetDetails(i); 3806 details = details.CopyWithRepresentation(Representation::Tagged()); 3807 if (details.location() == kField) { 3808 DCHECK_EQ(kData, details.kind()); 3809 details = details.CopyWithConstness(kMutable); 3810 SetValue(i, FieldType::Any()); 3811 } 3812 set(ToDetailsIndex(i), details.AsSmi()); 3813 } 3814 } 3815 3816 Handle<Map> Map::CopyGeneralizeAllFields(Handle<Map> map, 3817 ElementsKind elements_kind, 3818 int modify_index, PropertyKind kind, 3819 PropertyAttributes attributes, 3820 const char* reason) { 3821 Isolate* isolate = map->GetIsolate(); 3822 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 3823 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 3824 Handle<DescriptorArray> descriptors = 3825 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors); 3826 descriptors->GeneralizeAllFields(); 3827 3828 Handle<LayoutDescriptor> new_layout_descriptor( 3829 LayoutDescriptor::FastPointerLayout(), isolate); 3830 Handle<Map> new_map = CopyReplaceDescriptors( 3831 map, descriptors, new_layout_descriptor, OMIT_TRANSITION, 3832 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION); 3833 3834 // Unless the instance is being migrated, ensure that modify_index is a field. 3835 if (modify_index >= 0) { 3836 PropertyDetails details = descriptors->GetDetails(modify_index); 3837 if (details.constness() != kMutable || details.location() != kField || 3838 details.attributes() != attributes) { 3839 int field_index = details.location() == kField 3840 ? details.field_index() 3841 : new_map->NumberOfFields(); 3842 Descriptor d = Descriptor::DataField( 3843 handle(descriptors->GetKey(modify_index), isolate), field_index, 3844 attributes, Representation::Tagged()); 3845 descriptors->Replace(modify_index, &d); 3846 if (details.location() != kField) { 3847 int unused_property_fields = new_map->unused_property_fields() - 1; 3848 if (unused_property_fields < 0) { 3849 unused_property_fields += JSObject::kFieldsAdded; 3850 } 3851 new_map->set_unused_property_fields(unused_property_fields); 3852 } 3853 } else { 3854 DCHECK(details.attributes() == attributes); 3855 } 3856 3857 if (FLAG_trace_generalization) { 3858 MaybeHandle<FieldType> field_type = FieldType::None(isolate); 3859 if (details.location() == kField) { 3860 field_type = handle( 3861 map->instance_descriptors()->GetFieldType(modify_index), isolate); 3862 } 3863 map->PrintGeneralization( 3864 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(), 3865 new_map->NumberOfOwnDescriptors(), details.location() == kDescriptor, 3866 details.representation(), Representation::Tagged(), field_type, 3867 MaybeHandle<Object>(), FieldType::Any(isolate), 3868 MaybeHandle<Object>()); 3869 } 3870 } 3871 new_map->set_elements_kind(elements_kind); 3872 return new_map; 3873 } 3874 3875 3876 void Map::DeprecateTransitionTree() { 3877 if (is_deprecated()) return; 3878 Object* transitions = raw_transitions(); 3879 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 3880 for (int i = 0; i < num_transitions; ++i) { 3881 TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree(); 3882 } 3883 deprecate(); 3884 dependent_code()->DeoptimizeDependentCodeGroup( 3885 GetIsolate(), DependentCode::kTransitionGroup); 3886 NotifyLeafMapLayoutChange(); 3887 } 3888 3889 3890 // Installs |new_descriptors| over the current instance_descriptors to ensure 3891 // proper sharing of descriptor arrays. 3892 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors, 3893 LayoutDescriptor* new_layout_descriptor) { 3894 Isolate* isolate = GetIsolate(); 3895 // Don't overwrite the empty descriptor array or initial map's descriptors. 3896 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) { 3897 return; 3898 } 3899 3900 DescriptorArray* to_replace = instance_descriptors(); 3901 isolate->heap()->incremental_marking()->IterateBlackObject(to_replace); 3902 Map* current = this; 3903 while (current->instance_descriptors() == to_replace) { 3904 Object* next = current->GetBackPointer(); 3905 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map. 3906 current->SetEnumLength(kInvalidEnumCacheSentinel); 3907 current->UpdateDescriptors(new_descriptors, new_layout_descriptor); 3908 current = Map::cast(next); 3909 } 3910 set_owns_descriptors(false); 3911 } 3912 3913 3914 Map* Map::FindRootMap() { 3915 Map* result = this; 3916 Isolate* isolate = GetIsolate(); 3917 while (true) { 3918 Object* back = result->GetBackPointer(); 3919 if (back->IsUndefined(isolate)) { 3920 // Initial map always owns descriptors and doesn't have unused entries 3921 // in the descriptor array. 3922 DCHECK(result->owns_descriptors()); 3923 DCHECK_EQ(result->NumberOfOwnDescriptors(), 3924 result->instance_descriptors()->number_of_descriptors()); 3925 return result; 3926 } 3927 result = Map::cast(back); 3928 } 3929 } 3930 3931 3932 Map* Map::FindFieldOwner(int descriptor) { 3933 DisallowHeapAllocation no_allocation; 3934 DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location()); 3935 Map* result = this; 3936 Isolate* isolate = GetIsolate(); 3937 while (true) { 3938 Object* back = result->GetBackPointer(); 3939 if (back->IsUndefined(isolate)) break; 3940 Map* parent = Map::cast(back); 3941 if (parent->NumberOfOwnDescriptors() <= descriptor) break; 3942 result = parent; 3943 } 3944 return result; 3945 } 3946 3947 void Map::UpdateFieldType(int descriptor, Handle<Name> name, 3948 PropertyConstness new_constness, 3949 Representation new_representation, 3950 Handle<Object> new_wrapped_type) { 3951 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell()); 3952 // We store raw pointers in the queue, so no allocations are allowed. 3953 DisallowHeapAllocation no_allocation; 3954 PropertyDetails details = instance_descriptors()->GetDetails(descriptor); 3955 if (details.location() != kField) return; 3956 DCHECK_EQ(kData, details.kind()); 3957 3958 Zone zone(GetIsolate()->allocator(), ZONE_NAME); 3959 ZoneQueue<Map*> backlog(&zone); 3960 backlog.push(this); 3961 3962 while (!backlog.empty()) { 3963 Map* current = backlog.front(); 3964 backlog.pop(); 3965 3966 Object* transitions = current->raw_transitions(); 3967 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 3968 for (int i = 0; i < num_transitions; ++i) { 3969 Map* target = TransitionArray::GetTarget(transitions, i); 3970 backlog.push(target); 3971 } 3972 DescriptorArray* descriptors = current->instance_descriptors(); 3973 PropertyDetails details = descriptors->GetDetails(descriptor); 3974 3975 // Currently constness change implies map change. 3976 DCHECK_EQ(new_constness, details.constness()); 3977 3978 // It is allowed to change representation here only from None to something. 3979 DCHECK(details.representation().Equals(new_representation) || 3980 details.representation().IsNone()); 3981 3982 // Skip if already updated the shared descriptor. 3983 if (descriptors->GetValue(descriptor) != *new_wrapped_type) { 3984 DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable); 3985 Descriptor d = Descriptor::DataField( 3986 name, descriptors->GetFieldIndex(descriptor), details.attributes(), 3987 new_constness, new_representation, new_wrapped_type); 3988 descriptors->Replace(descriptor, &d); 3989 } 3990 } 3991 } 3992 3993 bool FieldTypeIsCleared(Representation rep, FieldType* type) { 3994 return type->IsNone() && rep.IsHeapObject(); 3995 } 3996 3997 3998 // static 3999 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1, 4000 Handle<FieldType> type1, 4001 Representation rep2, 4002 Handle<FieldType> type2, 4003 Isolate* isolate) { 4004 // Cleared field types need special treatment. They represent lost knowledge, 4005 // so we must be conservative, so their generalization with any other type 4006 // is "Any". 4007 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) { 4008 return FieldType::Any(isolate); 4009 } 4010 if (type1->NowIs(type2)) return type2; 4011 if (type2->NowIs(type1)) return type1; 4012 return FieldType::Any(isolate); 4013 } 4014 4015 4016 // static 4017 void Map::GeneralizeField(Handle<Map> map, int modify_index, 4018 PropertyConstness new_constness, 4019 Representation new_representation, 4020 Handle<FieldType> new_field_type) { 4021 Isolate* isolate = map->GetIsolate(); 4022 4023 // Check if we actually need to generalize the field type at all. 4024 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 4025 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); 4026 PropertyConstness old_constness = old_details.constness(); 4027 Representation old_representation = old_details.representation(); 4028 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index), 4029 isolate); 4030 4031 if (old_constness == new_constness && 4032 old_representation.Equals(new_representation) && 4033 !FieldTypeIsCleared(new_representation, *new_field_type) && 4034 // Checking old_field_type for being cleared is not necessary because 4035 // the NowIs check below would fail anyway in that case. 4036 new_field_type->NowIs(old_field_type)) { 4037 DCHECK(GeneralizeFieldType(old_representation, old_field_type, 4038 new_representation, new_field_type, isolate) 4039 ->NowIs(old_field_type)); 4040 return; 4041 } 4042 4043 // Determine the field owner. 4044 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate); 4045 Handle<DescriptorArray> descriptors( 4046 field_owner->instance_descriptors(), isolate); 4047 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index)); 4048 4049 new_field_type = 4050 Map::GeneralizeFieldType(old_representation, old_field_type, 4051 new_representation, new_field_type, isolate); 4052 4053 PropertyDetails details = descriptors->GetDetails(modify_index); 4054 Handle<Name> name(descriptors->GetKey(modify_index)); 4055 4056 Handle<Object> wrapped_type(WrapFieldType(new_field_type)); 4057 field_owner->UpdateFieldType(modify_index, name, new_constness, 4058 new_representation, wrapped_type); 4059 field_owner->dependent_code()->DeoptimizeDependentCodeGroup( 4060 isolate, DependentCode::kFieldOwnerGroup); 4061 4062 if (FLAG_trace_generalization) { 4063 map->PrintGeneralization( 4064 stdout, "field type generalization", modify_index, 4065 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false, 4066 details.representation(), details.representation(), old_field_type, 4067 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>()); 4068 } 4069 } 4070 4071 // TODO(ishell): remove. 4072 // static 4073 Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index, 4074 PropertyKind new_kind, 4075 PropertyAttributes new_attributes, 4076 Representation new_representation, 4077 Handle<FieldType> new_field_type) { 4078 DCHECK_EQ(kData, new_kind); // Only kData case is supported. 4079 MapUpdater mu(map->GetIsolate(), map); 4080 return mu.ReconfigureToDataField(modify_index, new_attributes, kConst, 4081 new_representation, new_field_type); 4082 } 4083 4084 // TODO(ishell): remove. 4085 // static 4086 Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map, 4087 ElementsKind new_elements_kind) { 4088 MapUpdater mu(map->GetIsolate(), map); 4089 return mu.ReconfigureElementsKind(new_elements_kind); 4090 } 4091 4092 // Generalize all fields and update the transition tree. 4093 Handle<Map> Map::GeneralizeAllFields(Handle<Map> map) { 4094 Isolate* isolate = map->GetIsolate(); 4095 Handle<FieldType> any_type = FieldType::Any(isolate); 4096 4097 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 4098 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) { 4099 PropertyDetails details = descriptors->GetDetails(i); 4100 if (details.location() == kField) { 4101 DCHECK_EQ(kData, details.kind()); 4102 MapUpdater mu(isolate, map); 4103 map = mu.ReconfigureToDataField(i, details.attributes(), kMutable, 4104 Representation::Tagged(), any_type); 4105 } 4106 } 4107 return map; 4108 } 4109 4110 4111 // static 4112 MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) { 4113 DisallowHeapAllocation no_allocation; 4114 DisallowDeoptimization no_deoptimization(old_map->GetIsolate()); 4115 4116 if (!old_map->is_deprecated()) return old_map; 4117 4118 // Check the state of the root map. 4119 Map* root_map = old_map->FindRootMap(); 4120 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>(); 4121 4122 ElementsKind from_kind = root_map->elements_kind(); 4123 ElementsKind to_kind = old_map->elements_kind(); 4124 if (from_kind != to_kind) { 4125 // Try to follow existing elements kind transitions. 4126 root_map = root_map->LookupElementsTransitionMap(to_kind); 4127 if (root_map == NULL) return MaybeHandle<Map>(); 4128 // From here on, use the map with correct elements kind as root map. 4129 } 4130 Map* new_map = root_map->TryReplayPropertyTransitions(*old_map); 4131 if (new_map == nullptr) return MaybeHandle<Map>(); 4132 return handle(new_map); 4133 } 4134 4135 Map* Map::TryReplayPropertyTransitions(Map* old_map) { 4136 DisallowHeapAllocation no_allocation; 4137 DisallowDeoptimization no_deoptimization(GetIsolate()); 4138 4139 int root_nof = NumberOfOwnDescriptors(); 4140 4141 int old_nof = old_map->NumberOfOwnDescriptors(); 4142 DescriptorArray* old_descriptors = old_map->instance_descriptors(); 4143 4144 Map* new_map = this; 4145 for (int i = root_nof; i < old_nof; ++i) { 4146 PropertyDetails old_details = old_descriptors->GetDetails(i); 4147 Map* transition = TransitionArray::SearchTransition( 4148 new_map, old_details.kind(), old_descriptors->GetKey(i), 4149 old_details.attributes()); 4150 if (transition == NULL) return nullptr; 4151 new_map = transition; 4152 DescriptorArray* new_descriptors = new_map->instance_descriptors(); 4153 4154 PropertyDetails new_details = new_descriptors->GetDetails(i); 4155 DCHECK_EQ(old_details.kind(), new_details.kind()); 4156 DCHECK_EQ(old_details.attributes(), new_details.attributes()); 4157 if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) { 4158 return nullptr; 4159 } 4160 DCHECK(IsGeneralizableTo(old_details.location(), new_details.location())); 4161 if (!old_details.representation().fits_into(new_details.representation())) { 4162 return nullptr; 4163 } 4164 if (new_details.location() == kField) { 4165 if (new_details.kind() == kData) { 4166 FieldType* new_type = new_descriptors->GetFieldType(i); 4167 // Cleared field types need special treatment. They represent lost 4168 // knowledge, so we must first generalize the new_type to "Any". 4169 if (FieldTypeIsCleared(new_details.representation(), new_type)) { 4170 return nullptr; 4171 } 4172 DCHECK_EQ(kData, old_details.kind()); 4173 if (old_details.location() == kField) { 4174 FieldType* old_type = old_descriptors->GetFieldType(i); 4175 if (FieldTypeIsCleared(old_details.representation(), old_type) || 4176 !old_type->NowIs(new_type)) { 4177 return nullptr; 4178 } 4179 } else { 4180 DCHECK_EQ(kDescriptor, old_details.location()); 4181 DCHECK(!FLAG_track_constant_fields); 4182 Object* old_value = old_descriptors->GetValue(i); 4183 if (!new_type->NowContains(old_value)) { 4184 return nullptr; 4185 } 4186 } 4187 4188 } else { 4189 DCHECK_EQ(kAccessor, new_details.kind()); 4190 #ifdef DEBUG 4191 FieldType* new_type = new_descriptors->GetFieldType(i); 4192 DCHECK(new_type->IsAny()); 4193 #endif 4194 UNREACHABLE(); 4195 } 4196 } else { 4197 DCHECK_EQ(kDescriptor, new_details.location()); 4198 Object* old_value = old_descriptors->GetValue(i); 4199 Object* new_value = new_descriptors->GetValue(i); 4200 if (old_details.location() == kField || old_value != new_value) { 4201 return nullptr; 4202 } 4203 } 4204 } 4205 if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr; 4206 return new_map; 4207 } 4208 4209 4210 // static 4211 Handle<Map> Map::Update(Handle<Map> map) { 4212 if (!map->is_deprecated()) return map; 4213 MapUpdater mu(map->GetIsolate(), map); 4214 return mu.Update(); 4215 } 4216 4217 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it, 4218 ShouldThrow should_throw, 4219 Handle<Object> value) { 4220 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 4221 return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(), 4222 should_throw, value); 4223 } 4224 4225 MaybeHandle<Object> Object::SetProperty(Handle<Object> object, 4226 Handle<Name> name, Handle<Object> value, 4227 LanguageMode language_mode, 4228 StoreFromKeyed store_mode) { 4229 LookupIterator it(object, name); 4230 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode)); 4231 return value; 4232 } 4233 4234 4235 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it, 4236 Handle<Object> value, 4237 LanguageMode language_mode, 4238 StoreFromKeyed store_mode, 4239 bool* found) { 4240 it->UpdateProtector(); 4241 DCHECK(it->IsFound()); 4242 ShouldThrow should_throw = 4243 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4244 4245 // Make sure that the top context does not change when doing callbacks or 4246 // interceptor calls. 4247 AssertNoContextChange ncc(it->isolate()); 4248 4249 do { 4250 switch (it->state()) { 4251 case LookupIterator::NOT_FOUND: 4252 UNREACHABLE(); 4253 4254 case LookupIterator::ACCESS_CHECK: 4255 if (it->HasAccess()) break; 4256 // Check whether it makes sense to reuse the lookup iterator. Here it 4257 // might still call into setters up the prototype chain. 4258 return JSObject::SetPropertyWithFailedAccessCheck(it, value, 4259 should_throw); 4260 4261 case LookupIterator::JSPROXY: 4262 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(), 4263 value, it->GetReceiver(), language_mode); 4264 4265 case LookupIterator::INTERCEPTOR: { 4266 if (it->HolderIsReceiverOrHiddenPrototype()) { 4267 Maybe<bool> result = 4268 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 4269 if (result.IsNothing() || result.FromJust()) return result; 4270 } else { 4271 Maybe<PropertyAttributes> maybe_attributes = 4272 JSObject::GetPropertyAttributesWithInterceptor(it); 4273 if (!maybe_attributes.IsJust()) return Nothing<bool>(); 4274 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) { 4275 return WriteToReadOnlyProperty(it, value, should_throw); 4276 } 4277 if (maybe_attributes.FromJust() == ABSENT) break; 4278 *found = false; 4279 return Nothing<bool>(); 4280 } 4281 break; 4282 } 4283 4284 case LookupIterator::ACCESSOR: { 4285 if (it->IsReadOnly()) { 4286 return WriteToReadOnlyProperty(it, value, should_throw); 4287 } 4288 Handle<Object> accessors = it->GetAccessors(); 4289 if (accessors->IsAccessorInfo() && 4290 !it->HolderIsReceiverOrHiddenPrototype() && 4291 AccessorInfo::cast(*accessors)->is_special_data_property()) { 4292 *found = false; 4293 return Nothing<bool>(); 4294 } 4295 return SetPropertyWithAccessor(it, value, should_throw); 4296 } 4297 case LookupIterator::INTEGER_INDEXED_EXOTIC: 4298 // TODO(verwaest): We should throw an exception if holder is receiver. 4299 return Just(true); 4300 4301 case LookupIterator::DATA: 4302 if (it->IsReadOnly()) { 4303 return WriteToReadOnlyProperty(it, value, should_throw); 4304 } 4305 if (it->HolderIsReceiverOrHiddenPrototype()) { 4306 return SetDataProperty(it, value); 4307 } 4308 // Fall through. 4309 case LookupIterator::TRANSITION: 4310 *found = false; 4311 return Nothing<bool>(); 4312 } 4313 it->Next(); 4314 } while (it->IsFound()); 4315 4316 *found = false; 4317 return Nothing<bool>(); 4318 } 4319 4320 4321 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value, 4322 LanguageMode language_mode, 4323 StoreFromKeyed store_mode) { 4324 if (it->IsFound()) { 4325 bool found = true; 4326 Maybe<bool> result = 4327 SetPropertyInternal(it, value, language_mode, store_mode, &found); 4328 if (found) return result; 4329 } 4330 4331 // If the receiver is the JSGlobalObject, the store was contextual. In case 4332 // the property did not exist yet on the global object itself, we have to 4333 // throw a reference error in strict mode. In sloppy mode, we continue. 4334 if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) { 4335 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError( 4336 MessageTemplate::kNotDefined, it->name())); 4337 return Nothing<bool>(); 4338 } 4339 4340 ShouldThrow should_throw = 4341 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4342 return AddDataProperty(it, value, NONE, should_throw, store_mode); 4343 } 4344 4345 4346 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, 4347 LanguageMode language_mode, 4348 StoreFromKeyed store_mode) { 4349 Isolate* isolate = it->isolate(); 4350 4351 if (it->IsFound()) { 4352 bool found = true; 4353 Maybe<bool> result = 4354 SetPropertyInternal(it, value, language_mode, store_mode, &found); 4355 if (found) return result; 4356 } 4357 4358 it->UpdateProtector(); 4359 4360 // The property either doesn't exist on the holder or exists there as a data 4361 // property. 4362 4363 ShouldThrow should_throw = 4364 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4365 4366 if (!it->GetReceiver()->IsJSReceiver()) { 4367 return WriteToReadOnlyProperty(it, value, should_throw); 4368 } 4369 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 4370 4371 LookupIterator::Configuration c = LookupIterator::OWN; 4372 LookupIterator own_lookup = 4373 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c) 4374 : LookupIterator(receiver, it->name(), c); 4375 4376 for (; own_lookup.IsFound(); own_lookup.Next()) { 4377 switch (own_lookup.state()) { 4378 case LookupIterator::ACCESS_CHECK: 4379 if (!own_lookup.HasAccess()) { 4380 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value, 4381 should_throw); 4382 } 4383 break; 4384 4385 case LookupIterator::ACCESSOR: 4386 if (own_lookup.GetAccessors()->IsAccessorInfo()) { 4387 if (own_lookup.IsReadOnly()) { 4388 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 4389 } 4390 return JSObject::SetPropertyWithAccessor(&own_lookup, value, 4391 should_throw); 4392 } 4393 // Fall through. 4394 case LookupIterator::INTEGER_INDEXED_EXOTIC: 4395 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 4396 should_throw); 4397 4398 case LookupIterator::DATA: { 4399 if (own_lookup.IsReadOnly()) { 4400 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 4401 } 4402 return SetDataProperty(&own_lookup, value); 4403 } 4404 4405 case LookupIterator::INTERCEPTOR: 4406 case LookupIterator::JSPROXY: { 4407 PropertyDescriptor desc; 4408 Maybe<bool> owned = 4409 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc); 4410 MAYBE_RETURN(owned, Nothing<bool>()); 4411 if (!owned.FromJust()) { 4412 return JSReceiver::CreateDataProperty(&own_lookup, value, 4413 should_throw); 4414 } 4415 if (PropertyDescriptor::IsAccessorDescriptor(&desc) || 4416 !desc.writable()) { 4417 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 4418 should_throw); 4419 } 4420 4421 PropertyDescriptor value_desc; 4422 value_desc.set_value(value); 4423 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 4424 &value_desc, should_throw); 4425 } 4426 4427 case LookupIterator::NOT_FOUND: 4428 case LookupIterator::TRANSITION: 4429 UNREACHABLE(); 4430 } 4431 } 4432 4433 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode); 4434 } 4435 4436 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate, 4437 Handle<Object> receiver, 4438 Handle<Object> name, 4439 Handle<Object> value, 4440 ShouldThrow should_throw) { 4441 RETURN_FAILURE( 4442 isolate, should_throw, 4443 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name, 4444 Object::TypeOf(isolate, receiver), receiver)); 4445 } 4446 4447 4448 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it, 4449 Handle<Object> value, 4450 ShouldThrow should_throw) { 4451 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), 4452 it->GetName(), value, should_throw); 4453 } 4454 4455 4456 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate, 4457 Handle<Object> receiver, 4458 Handle<Object> name, 4459 Handle<Object> value, 4460 ShouldThrow should_throw) { 4461 RETURN_FAILURE(isolate, should_throw, 4462 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name, 4463 Object::TypeOf(isolate, receiver), receiver)); 4464 } 4465 4466 4467 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate, 4468 Handle<Object> name, 4469 Handle<Object> value, 4470 ShouldThrow should_throw) { 4471 RETURN_FAILURE(isolate, should_throw, 4472 NewTypeError(MessageTemplate::kRedefineDisallowed, name)); 4473 } 4474 4475 4476 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { 4477 // Proxies are handled elsewhere. Other non-JSObjects cannot have own 4478 // properties. 4479 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); 4480 4481 // Store on the holder which may be hidden behind the receiver. 4482 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); 4483 4484 Handle<Object> to_assign = value; 4485 // Convert the incoming value to a number for storing into typed arrays. 4486 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) { 4487 if (!value->IsNumber() && !value->IsUndefined(it->isolate())) { 4488 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 4489 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>()); 4490 // We have to recheck the length. However, it can only change if the 4491 // underlying buffer was neutered, so just check that. 4492 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) { 4493 return Just(true); 4494 // TODO(neis): According to the spec, this should throw a TypeError. 4495 } 4496 } 4497 } 4498 4499 // Possibly migrate to the most up-to-date map that will be able to store 4500 // |value| under it->name(). 4501 it->PrepareForDataProperty(to_assign); 4502 4503 // Write the property value. 4504 it->WriteDataValue(to_assign, false); 4505 4506 #if VERIFY_HEAP 4507 if (FLAG_verify_heap) { 4508 receiver->JSObjectVerify(); 4509 } 4510 #endif 4511 return Just(true); 4512 } 4513 4514 4515 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, 4516 PropertyAttributes attributes, 4517 ShouldThrow should_throw, 4518 StoreFromKeyed store_mode) { 4519 if (!it->GetReceiver()->IsJSObject()) { 4520 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) { 4521 RETURN_FAILURE(it->isolate(), should_throw, 4522 NewTypeError(MessageTemplate::kProxyPrivate)); 4523 } 4524 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(), 4525 value, should_throw); 4526 } 4527 4528 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state()); 4529 4530 Handle<JSObject> receiver = it->GetStoreTarget(); 4531 4532 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) 4533 // instead. If the prototype is Null, the proxy is detached. 4534 if (receiver->IsJSGlobalProxy()) return Just(true); 4535 4536 Isolate* isolate = it->isolate(); 4537 4538 if (it->ExtendingNonExtensible(receiver)) { 4539 RETURN_FAILURE( 4540 isolate, should_throw, 4541 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName())); 4542 } 4543 4544 if (it->IsElement()) { 4545 if (receiver->IsJSArray()) { 4546 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 4547 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) { 4548 RETURN_FAILURE(array->GetIsolate(), should_throw, 4549 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, 4550 isolate->factory()->length_string(), 4551 Object::TypeOf(isolate, array), array)); 4552 } 4553 4554 if (FLAG_trace_external_array_abuse && 4555 array->HasFixedTypedArrayElements()) { 4556 CheckArrayAbuse(array, "typed elements write", it->index(), true); 4557 } 4558 4559 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) { 4560 CheckArrayAbuse(array, "elements write", it->index(), false); 4561 } 4562 } 4563 4564 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value, 4565 attributes, should_throw); 4566 JSObject::ValidateElements(receiver); 4567 return result; 4568 } else { 4569 it->UpdateProtector(); 4570 // Migrate to the most up-to-date map that will be able to store |value| 4571 // under it->name() with |attributes|. 4572 it->PrepareTransitionToDataProperty(receiver, value, attributes, 4573 store_mode); 4574 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); 4575 it->ApplyTransitionToDataProperty(receiver); 4576 4577 // Write the property value. 4578 it->WriteDataValue(value, true); 4579 4580 #if VERIFY_HEAP 4581 if (FLAG_verify_heap) { 4582 receiver->JSObjectVerify(); 4583 } 4584 #endif 4585 } 4586 4587 return Just(true); 4588 } 4589 4590 4591 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { 4592 // Only supports adding slack to owned descriptors. 4593 DCHECK(map->owns_descriptors()); 4594 4595 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 4596 int old_size = map->NumberOfOwnDescriptors(); 4597 if (slack <= descriptors->NumberOfSlackDescriptors()) return; 4598 4599 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 4600 descriptors, old_size, slack); 4601 4602 DisallowHeapAllocation no_allocation; 4603 // The descriptors are still the same, so keep the layout descriptor. 4604 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor(); 4605 4606 if (old_size == 0) { 4607 map->UpdateDescriptors(*new_descriptors, layout_descriptor); 4608 return; 4609 } 4610 4611 // If the source descriptors had an enum cache we copy it. This ensures 4612 // that the maps to which we push the new descriptor array back can rely 4613 // on a cache always being available once it is set. If the map has more 4614 // enumerated descriptors than available in the original cache, the cache 4615 // will be lazily replaced by the extended cache when needed. 4616 if (descriptors->HasEnumCache()) { 4617 new_descriptors->CopyEnumCacheFrom(*descriptors); 4618 } 4619 4620 Isolate* isolate = map->GetIsolate(); 4621 // Replace descriptors by new_descriptors in all maps that share it. 4622 isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors); 4623 4624 Map* current = *map; 4625 while (current->instance_descriptors() == *descriptors) { 4626 Object* next = current->GetBackPointer(); 4627 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map. 4628 current->UpdateDescriptors(*new_descriptors, layout_descriptor); 4629 current = Map::cast(next); 4630 } 4631 map->UpdateDescriptors(*new_descriptors, layout_descriptor); 4632 } 4633 4634 // static 4635 Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) { 4636 Isolate* isolate = prototype->GetIsolate(); 4637 Handle<Map> map(isolate->native_context()->object_function()->initial_map(), 4638 isolate); 4639 if (map->prototype() == *prototype) return map; 4640 if (prototype->IsNull(isolate)) { 4641 return isolate->slow_object_with_null_prototype_map(); 4642 } 4643 if (prototype->IsJSObject()) { 4644 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype); 4645 if (!js_prototype->map()->is_prototype_map()) { 4646 JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE); 4647 } 4648 Handle<PrototypeInfo> info = 4649 Map::GetOrCreatePrototypeInfo(js_prototype, isolate); 4650 // TODO(verwaest): Use inobject slack tracking for this map. 4651 if (info->HasObjectCreateMap()) { 4652 map = handle(info->ObjectCreateMap(), isolate); 4653 } else { 4654 map = Map::CopyInitialMap(map); 4655 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 4656 PrototypeInfo::SetObjectCreateMap(info, map); 4657 } 4658 return map; 4659 } 4660 4661 return Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); 4662 } 4663 4664 template <class T> 4665 static int AppendUniqueCallbacks(Handle<TemplateList> callbacks, 4666 Handle<typename T::Array> array, 4667 int valid_descriptors) { 4668 int nof_callbacks = callbacks->length(); 4669 4670 Isolate* isolate = array->GetIsolate(); 4671 // Ensure the keys are unique names before writing them into the 4672 // instance descriptor. Since it may cause a GC, it has to be done before we 4673 // temporarily put the heap in an invalid state while appending descriptors. 4674 for (int i = 0; i < nof_callbacks; ++i) { 4675 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i))); 4676 if (entry->name()->IsUniqueName()) continue; 4677 Handle<String> key = 4678 isolate->factory()->InternalizeString( 4679 Handle<String>(String::cast(entry->name()))); 4680 entry->set_name(*key); 4681 } 4682 4683 // Fill in new callback descriptors. Process the callbacks from 4684 // back to front so that the last callback with a given name takes 4685 // precedence over previously added callbacks with that name. 4686 for (int i = nof_callbacks - 1; i >= 0; i--) { 4687 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i))); 4688 Handle<Name> key(Name::cast(entry->name())); 4689 // Check if a descriptor with this name already exists before writing. 4690 if (!T::Contains(key, entry, valid_descriptors, array)) { 4691 T::Insert(key, entry, valid_descriptors, array); 4692 valid_descriptors++; 4693 } 4694 } 4695 4696 return valid_descriptors; 4697 } 4698 4699 struct DescriptorArrayAppender { 4700 typedef DescriptorArray Array; 4701 static bool Contains(Handle<Name> key, 4702 Handle<AccessorInfo> entry, 4703 int valid_descriptors, 4704 Handle<DescriptorArray> array) { 4705 DisallowHeapAllocation no_gc; 4706 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound; 4707 } 4708 static void Insert(Handle<Name> key, 4709 Handle<AccessorInfo> entry, 4710 int valid_descriptors, 4711 Handle<DescriptorArray> array) { 4712 DisallowHeapAllocation no_gc; 4713 Descriptor d = 4714 Descriptor::AccessorConstant(key, entry, entry->property_attributes()); 4715 array->Append(&d); 4716 } 4717 }; 4718 4719 4720 struct FixedArrayAppender { 4721 typedef FixedArray Array; 4722 static bool Contains(Handle<Name> key, 4723 Handle<AccessorInfo> entry, 4724 int valid_descriptors, 4725 Handle<FixedArray> array) { 4726 for (int i = 0; i < valid_descriptors; i++) { 4727 if (*key == AccessorInfo::cast(array->get(i))->name()) return true; 4728 } 4729 return false; 4730 } 4731 static void Insert(Handle<Name> key, 4732 Handle<AccessorInfo> entry, 4733 int valid_descriptors, 4734 Handle<FixedArray> array) { 4735 DisallowHeapAllocation no_gc; 4736 array->set(valid_descriptors, *entry); 4737 } 4738 }; 4739 4740 4741 void Map::AppendCallbackDescriptors(Handle<Map> map, 4742 Handle<Object> descriptors) { 4743 int nof = map->NumberOfOwnDescriptors(); 4744 Handle<DescriptorArray> array(map->instance_descriptors()); 4745 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors); 4746 DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length()); 4747 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof); 4748 map->SetNumberOfOwnDescriptors(nof); 4749 } 4750 4751 4752 int AccessorInfo::AppendUnique(Handle<Object> descriptors, 4753 Handle<FixedArray> array, 4754 int valid_descriptors) { 4755 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors); 4756 DCHECK_GE(array->length(), callbacks->length() + valid_descriptors); 4757 return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array, 4758 valid_descriptors); 4759 } 4760 4761 4762 static bool ContainsMap(MapHandleList* maps, Map* map) { 4763 DCHECK_NOT_NULL(map); 4764 for (int i = 0; i < maps->length(); ++i) { 4765 if (!maps->at(i).is_null() && *maps->at(i) == map) return true; 4766 } 4767 return false; 4768 } 4769 4770 Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) { 4771 DisallowHeapAllocation no_allocation; 4772 DisallowDeoptimization no_deoptimization(GetIsolate()); 4773 4774 ElementsKind kind = elements_kind(); 4775 bool packed = IsFastPackedElementsKind(kind); 4776 4777 Map* transition = nullptr; 4778 if (IsTransitionableFastElementsKind(kind)) { 4779 // Check the state of the root map. 4780 Map* root_map = FindRootMap(); 4781 if (!EquivalentToForTransition(root_map)) return nullptr; 4782 root_map = root_map->LookupElementsTransitionMap(kind); 4783 DCHECK_NOT_NULL(root_map); 4784 // Starting from the next existing elements kind transition try to 4785 // replay the property transitions that does not involve instance rewriting 4786 // (ElementsTransitionAndStoreStub does not support that). 4787 for (root_map = root_map->ElementsTransitionMap(); 4788 root_map != nullptr && root_map->has_fast_elements(); 4789 root_map = root_map->ElementsTransitionMap()) { 4790 Map* current = root_map->TryReplayPropertyTransitions(this); 4791 if (current == nullptr) continue; 4792 if (InstancesNeedRewriting(current)) continue; 4793 4794 if (ContainsMap(candidates, current) && 4795 (packed || !IsFastPackedElementsKind(current->elements_kind()))) { 4796 transition = current; 4797 packed = packed && IsFastPackedElementsKind(current->elements_kind()); 4798 } 4799 } 4800 } 4801 return transition; 4802 } 4803 4804 4805 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { 4806 // Ensure we are requested to search elements kind transition "near the root". 4807 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(), 4808 map->NumberOfOwnDescriptors()); 4809 Map* current_map = map; 4810 4811 ElementsKind kind = map->elements_kind(); 4812 while (kind != to_kind) { 4813 Map* next_map = current_map->ElementsTransitionMap(); 4814 if (next_map == nullptr) return current_map; 4815 kind = next_map->elements_kind(); 4816 current_map = next_map; 4817 } 4818 4819 DCHECK_EQ(to_kind, current_map->elements_kind()); 4820 return current_map; 4821 } 4822 4823 4824 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { 4825 Map* to_map = FindClosestElementsTransition(this, to_kind); 4826 if (to_map->elements_kind() == to_kind) return to_map; 4827 return nullptr; 4828 } 4829 4830 4831 bool Map::IsMapInArrayPrototypeChain() { 4832 Isolate* isolate = GetIsolate(); 4833 if (isolate->initial_array_prototype()->map() == this) { 4834 return true; 4835 } 4836 4837 if (isolate->initial_object_prototype()->map() == this) { 4838 return true; 4839 } 4840 4841 return false; 4842 } 4843 4844 4845 Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) { 4846 Isolate* isolate = map->GetIsolate(); 4847 if (map->weak_cell_cache()->IsWeakCell()) { 4848 return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache())); 4849 } 4850 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map); 4851 map->set_weak_cell_cache(*weak_cell); 4852 return weak_cell; 4853 } 4854 4855 4856 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map, 4857 ElementsKind to_kind) { 4858 DCHECK(IsTransitionElementsKind(map->elements_kind())); 4859 4860 Handle<Map> current_map = map; 4861 4862 ElementsKind kind = map->elements_kind(); 4863 TransitionFlag flag; 4864 if (map->is_prototype_map()) { 4865 flag = OMIT_TRANSITION; 4866 } else { 4867 flag = INSERT_TRANSITION; 4868 if (IsFastElementsKind(kind)) { 4869 while (kind != to_kind && !IsTerminalElementsKind(kind)) { 4870 kind = GetNextTransitionElementsKind(kind); 4871 current_map = Map::CopyAsElementsKind(current_map, kind, flag); 4872 } 4873 } 4874 } 4875 4876 // In case we are exiting the fast elements kind system, just add the map in 4877 // the end. 4878 if (kind != to_kind) { 4879 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag); 4880 } 4881 4882 DCHECK(current_map->elements_kind() == to_kind); 4883 return current_map; 4884 } 4885 4886 4887 Handle<Map> Map::TransitionElementsTo(Handle<Map> map, 4888 ElementsKind to_kind) { 4889 ElementsKind from_kind = map->elements_kind(); 4890 if (from_kind == to_kind) return map; 4891 4892 Isolate* isolate = map->GetIsolate(); 4893 Context* native_context = isolate->context()->native_context(); 4894 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) { 4895 if (*map == native_context->fast_aliased_arguments_map()) { 4896 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); 4897 return handle(native_context->slow_aliased_arguments_map()); 4898 } 4899 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) { 4900 if (*map == native_context->slow_aliased_arguments_map()) { 4901 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); 4902 return handle(native_context->fast_aliased_arguments_map()); 4903 } 4904 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { 4905 // Reuse map transitions for JSArrays. 4906 DisallowHeapAllocation no_gc; 4907 if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) { 4908 Object* maybe_transitioned_map = 4909 native_context->get(Context::ArrayMapIndex(to_kind)); 4910 if (maybe_transitioned_map->IsMap()) { 4911 return handle(Map::cast(maybe_transitioned_map), isolate); 4912 } 4913 } 4914 } 4915 4916 DCHECK(!map->IsUndefined(isolate)); 4917 // Check if we can go back in the elements kind transition chain. 4918 if (IsHoleyElementsKind(from_kind) && 4919 to_kind == GetPackedElementsKind(from_kind) && 4920 map->GetBackPointer()->IsMap() && 4921 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) { 4922 return handle(Map::cast(map->GetBackPointer())); 4923 } 4924 4925 bool allow_store_transition = IsTransitionElementsKind(from_kind); 4926 // Only store fast element maps in ascending generality. 4927 if (IsFastElementsKind(to_kind)) { 4928 allow_store_transition = 4929 allow_store_transition && IsTransitionableFastElementsKind(from_kind) && 4930 IsMoreGeneralElementsKindTransition(from_kind, to_kind); 4931 } 4932 4933 if (!allow_store_transition) { 4934 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION); 4935 } 4936 4937 return Map::ReconfigureElementsKind(map, to_kind); 4938 } 4939 4940 4941 // static 4942 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) { 4943 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind)); 4944 4945 if (closest_map->elements_kind() == kind) { 4946 return closest_map; 4947 } 4948 4949 return AddMissingElementsTransitions(closest_map, kind); 4950 } 4951 4952 4953 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, 4954 ElementsKind to_kind) { 4955 Handle<Map> map(object->map()); 4956 return Map::TransitionElementsTo(map, to_kind); 4957 } 4958 4959 4960 void JSProxy::Revoke(Handle<JSProxy> proxy) { 4961 Isolate* isolate = proxy->GetIsolate(); 4962 if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value()); 4963 DCHECK(proxy->IsRevoked()); 4964 } 4965 4966 4967 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy, 4968 Handle<Name> name) { 4969 DCHECK(!name->IsPrivate()); 4970 STACK_CHECK(isolate, Nothing<bool>()); 4971 // 1. (Assert) 4972 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 4973 Handle<Object> handler(proxy->handler(), isolate); 4974 // 3. If handler is null, throw a TypeError exception. 4975 // 4. Assert: Type(handler) is Object. 4976 if (proxy->IsRevoked()) { 4977 isolate->Throw(*isolate->factory()->NewTypeError( 4978 MessageTemplate::kProxyRevoked, isolate->factory()->has_string())); 4979 return Nothing<bool>(); 4980 } 4981 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 4982 Handle<JSReceiver> target(proxy->target(), isolate); 4983 // 6. Let trap be ? GetMethod(handler, "has"). 4984 Handle<Object> trap; 4985 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 4986 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), 4987 isolate->factory()->has_string()), 4988 Nothing<bool>()); 4989 // 7. If trap is undefined, then 4990 if (trap->IsUndefined(isolate)) { 4991 // 7a. Return target.[[HasProperty]](P). 4992 return JSReceiver::HasProperty(target, name); 4993 } 4994 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, target, P)). 4995 Handle<Object> trap_result_obj; 4996 Handle<Object> args[] = {target, name}; 4997 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 4998 isolate, trap_result_obj, 4999 Execution::Call(isolate, trap, handler, arraysize(args), args), 5000 Nothing<bool>()); 5001 bool boolean_trap_result = trap_result_obj->BooleanValue(); 5002 // 9. If booleanTrapResult is false, then: 5003 if (!boolean_trap_result) { 5004 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P). 5005 PropertyDescriptor target_desc; 5006 Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor( 5007 isolate, target, name, &target_desc); 5008 MAYBE_RETURN(target_found, Nothing<bool>()); 5009 // 9b. If targetDesc is not undefined, then: 5010 if (target_found.FromJust()) { 5011 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError 5012 // exception. 5013 if (!target_desc.configurable()) { 5014 isolate->Throw(*isolate->factory()->NewTypeError( 5015 MessageTemplate::kProxyHasNonConfigurable, name)); 5016 return Nothing<bool>(); 5017 } 5018 // 9b ii. Let extensibleTarget be ? IsExtensible(target). 5019 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 5020 MAYBE_RETURN(extensible_target, Nothing<bool>()); 5021 // 9b iii. If extensibleTarget is false, throw a TypeError exception. 5022 if (!extensible_target.FromJust()) { 5023 isolate->Throw(*isolate->factory()->NewTypeError( 5024 MessageTemplate::kProxyHasNonExtensible, name)); 5025 return Nothing<bool>(); 5026 } 5027 } 5028 } 5029 // 10. Return booleanTrapResult. 5030 return Just(boolean_trap_result); 5031 } 5032 5033 5034 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name, 5035 Handle<Object> value, Handle<Object> receiver, 5036 LanguageMode language_mode) { 5037 DCHECK(!name->IsPrivate()); 5038 Isolate* isolate = proxy->GetIsolate(); 5039 STACK_CHECK(isolate, Nothing<bool>()); 5040 Factory* factory = isolate->factory(); 5041 Handle<String> trap_name = factory->set_string(); 5042 ShouldThrow should_throw = 5043 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 5044 5045 if (proxy->IsRevoked()) { 5046 isolate->Throw( 5047 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 5048 return Nothing<bool>(); 5049 } 5050 Handle<JSReceiver> target(proxy->target(), isolate); 5051 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 5052 5053 Handle<Object> trap; 5054 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5055 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 5056 if (trap->IsUndefined(isolate)) { 5057 LookupIterator it = 5058 LookupIterator::PropertyOrElement(isolate, receiver, name, target); 5059 return Object::SetSuperProperty(&it, value, language_mode, 5060 Object::MAY_BE_STORE_FROM_KEYED); 5061 } 5062 5063 Handle<Object> trap_result; 5064 Handle<Object> args[] = {target, name, value, receiver}; 5065 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5066 isolate, trap_result, 5067 Execution::Call(isolate, trap, handler, arraysize(args), args), 5068 Nothing<bool>()); 5069 if (!trap_result->BooleanValue()) { 5070 RETURN_FAILURE(isolate, should_throw, 5071 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 5072 trap_name, name)); 5073 } 5074 5075 // Enforce the invariant. 5076 PropertyDescriptor target_desc; 5077 Maybe<bool> owned = 5078 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 5079 MAYBE_RETURN(owned, Nothing<bool>()); 5080 if (owned.FromJust()) { 5081 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && 5082 !target_desc.configurable() && 5083 !target_desc.writable() && 5084 !value->SameValue(*target_desc.value()); 5085 if (inconsistent) { 5086 isolate->Throw(*isolate->factory()->NewTypeError( 5087 MessageTemplate::kProxySetFrozenData, name)); 5088 return Nothing<bool>(); 5089 } 5090 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 5091 !target_desc.configurable() && 5092 target_desc.set()->IsUndefined(isolate); 5093 if (inconsistent) { 5094 isolate->Throw(*isolate->factory()->NewTypeError( 5095 MessageTemplate::kProxySetFrozenAccessor, name)); 5096 return Nothing<bool>(); 5097 } 5098 } 5099 return Just(true); 5100 } 5101 5102 5103 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy, 5104 Handle<Name> name, 5105 LanguageMode language_mode) { 5106 DCHECK(!name->IsPrivate()); 5107 ShouldThrow should_throw = 5108 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 5109 Isolate* isolate = proxy->GetIsolate(); 5110 STACK_CHECK(isolate, Nothing<bool>()); 5111 Factory* factory = isolate->factory(); 5112 Handle<String> trap_name = factory->deleteProperty_string(); 5113 5114 if (proxy->IsRevoked()) { 5115 isolate->Throw( 5116 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 5117 return Nothing<bool>(); 5118 } 5119 Handle<JSReceiver> target(proxy->target(), isolate); 5120 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 5121 5122 Handle<Object> trap; 5123 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5124 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 5125 if (trap->IsUndefined(isolate)) { 5126 return JSReceiver::DeletePropertyOrElement(target, name, language_mode); 5127 } 5128 5129 Handle<Object> trap_result; 5130 Handle<Object> args[] = {target, name}; 5131 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5132 isolate, trap_result, 5133 Execution::Call(isolate, trap, handler, arraysize(args), args), 5134 Nothing<bool>()); 5135 if (!trap_result->BooleanValue()) { 5136 RETURN_FAILURE(isolate, should_throw, 5137 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 5138 trap_name, name)); 5139 } 5140 5141 // Enforce the invariant. 5142 PropertyDescriptor target_desc; 5143 Maybe<bool> owned = 5144 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 5145 MAYBE_RETURN(owned, Nothing<bool>()); 5146 if (owned.FromJust() && !target_desc.configurable()) { 5147 isolate->Throw(*factory->NewTypeError( 5148 MessageTemplate::kProxyDeletePropertyNonConfigurable, name)); 5149 return Nothing<bool>(); 5150 } 5151 return Just(true); 5152 } 5153 5154 5155 // static 5156 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target, 5157 Handle<Object> handler) { 5158 if (!target->IsJSReceiver()) { 5159 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 5160 JSProxy); 5161 } 5162 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) { 5163 THROW_NEW_ERROR(isolate, 5164 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked), 5165 JSProxy); 5166 } 5167 if (!handler->IsJSReceiver()) { 5168 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 5169 JSProxy); 5170 } 5171 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) { 5172 THROW_NEW_ERROR(isolate, 5173 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked), 5174 JSProxy); 5175 } 5176 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target), 5177 Handle<JSReceiver>::cast(handler)); 5178 } 5179 5180 5181 // static 5182 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) { 5183 DCHECK(proxy->map()->is_constructor()); 5184 if (proxy->IsRevoked()) { 5185 THROW_NEW_ERROR(proxy->GetIsolate(), 5186 NewTypeError(MessageTemplate::kProxyRevoked), Context); 5187 } 5188 Handle<JSReceiver> target(JSReceiver::cast(proxy->target())); 5189 return JSReceiver::GetFunctionRealm(target); 5190 } 5191 5192 5193 // static 5194 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm( 5195 Handle<JSBoundFunction> function) { 5196 DCHECK(function->map()->is_constructor()); 5197 return JSReceiver::GetFunctionRealm( 5198 handle(function->bound_target_function())); 5199 } 5200 5201 // static 5202 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate, 5203 Handle<JSBoundFunction> function) { 5204 Handle<String> prefix = isolate->factory()->bound__string(); 5205 if (!function->bound_target_function()->IsJSFunction()) return prefix; 5206 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()), 5207 isolate); 5208 Handle<Object> target_name = JSFunction::GetName(isolate, target); 5209 if (!target_name->IsString()) return prefix; 5210 Factory* factory = isolate->factory(); 5211 return factory->NewConsString(prefix, Handle<String>::cast(target_name)); 5212 } 5213 5214 // static 5215 Handle<Object> JSFunction::GetName(Isolate* isolate, 5216 Handle<JSFunction> function) { 5217 if (function->shared()->name_should_print_as_anonymous()) { 5218 return isolate->factory()->anonymous_string(); 5219 } 5220 return handle(function->shared()->name(), isolate); 5221 } 5222 5223 // static 5224 MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate, 5225 Handle<JSFunction> function) { 5226 int length = 0; 5227 if (function->shared()->is_compiled()) { 5228 length = function->shared()->length(); 5229 } else { 5230 // If the function isn't compiled yet, the length is not computed 5231 // correctly yet. Compile it now and return the right length. 5232 if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) { 5233 length = function->shared()->length(); 5234 } 5235 if (isolate->has_pending_exception()) return MaybeHandle<Smi>(); 5236 } 5237 return handle(Smi::FromInt(length), isolate); 5238 } 5239 5240 // static 5241 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) { 5242 DCHECK(function->map()->is_constructor()); 5243 return handle(function->context()->native_context()); 5244 } 5245 5246 5247 // static 5248 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) { 5249 DCHECK(object->map()->is_constructor()); 5250 DCHECK(!object->IsJSFunction()); 5251 return object->GetCreationContext(); 5252 } 5253 5254 5255 // static 5256 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) { 5257 if (receiver->IsJSProxy()) { 5258 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver)); 5259 } 5260 5261 if (receiver->IsJSFunction()) { 5262 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver)); 5263 } 5264 5265 if (receiver->IsJSBoundFunction()) { 5266 return JSBoundFunction::GetFunctionRealm( 5267 Handle<JSBoundFunction>::cast(receiver)); 5268 } 5269 5270 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver)); 5271 } 5272 5273 5274 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) { 5275 PropertyDescriptor desc; 5276 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor( 5277 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc); 5278 MAYBE_RETURN(found, Nothing<PropertyAttributes>()); 5279 if (!found.FromJust()) return Just(ABSENT); 5280 return Just(desc.ToAttributes()); 5281 } 5282 5283 5284 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { 5285 DCHECK(object->map()->GetInObjectProperties() == 5286 map->GetInObjectProperties()); 5287 ElementsKind obj_kind = object->map()->elements_kind(); 5288 ElementsKind map_kind = map->elements_kind(); 5289 if (map_kind != obj_kind) { 5290 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind); 5291 if (IsDictionaryElementsKind(obj_kind)) { 5292 to_kind = obj_kind; 5293 } 5294 if (IsDictionaryElementsKind(to_kind)) { 5295 NormalizeElements(object); 5296 } else { 5297 TransitionElementsKind(object, to_kind); 5298 } 5299 map = Map::ReconfigureElementsKind(map, to_kind); 5300 } 5301 JSObject::MigrateToMap(object, map); 5302 } 5303 5304 5305 void JSObject::MigrateInstance(Handle<JSObject> object) { 5306 Handle<Map> original_map(object->map()); 5307 Handle<Map> map = Map::Update(original_map); 5308 map->set_migration_target(true); 5309 MigrateToMap(object, map); 5310 if (FLAG_trace_migration) { 5311 object->PrintInstanceMigration(stdout, *original_map, *map); 5312 } 5313 #if VERIFY_HEAP 5314 if (FLAG_verify_heap) { 5315 object->JSObjectVerify(); 5316 } 5317 #endif 5318 } 5319 5320 5321 // static 5322 bool JSObject::TryMigrateInstance(Handle<JSObject> object) { 5323 Isolate* isolate = object->GetIsolate(); 5324 DisallowDeoptimization no_deoptimization(isolate); 5325 Handle<Map> original_map(object->map(), isolate); 5326 Handle<Map> new_map; 5327 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) { 5328 return false; 5329 } 5330 JSObject::MigrateToMap(object, new_map); 5331 if (FLAG_trace_migration) { 5332 object->PrintInstanceMigration(stdout, *original_map, object->map()); 5333 } 5334 #if VERIFY_HEAP 5335 if (FLAG_verify_heap) { 5336 object->JSObjectVerify(); 5337 } 5338 #endif 5339 return true; 5340 } 5341 5342 5343 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name, 5344 Handle<Object> value, 5345 PropertyAttributes attributes) { 5346 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR); 5347 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); 5348 #ifdef DEBUG 5349 uint32_t index; 5350 DCHECK(!object->IsJSProxy()); 5351 DCHECK(!name->AsArrayIndex(&index)); 5352 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); 5353 DCHECK(maybe.IsJust()); 5354 DCHECK(!it.IsFound()); 5355 DCHECK(object->map()->is_extensible() || name->IsPrivate()); 5356 #endif 5357 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR, 5358 CERTAINLY_NOT_STORE_FROM_KEYED) 5359 .IsJust()); 5360 } 5361 5362 5363 // Reconfigures a property to a data property with attributes, even if it is not 5364 // reconfigurable. 5365 // Requires a LookupIterator that does not look at the prototype chain beyond 5366 // hidden prototypes. 5367 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes( 5368 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 5369 AccessorInfoHandling handling) { 5370 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes( 5371 it, value, attributes, THROW_ON_ERROR, handling)); 5372 return value; 5373 } 5374 5375 5376 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( 5377 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 5378 ShouldThrow should_throw, AccessorInfoHandling handling) { 5379 it->UpdateProtector(); 5380 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 5381 5382 for (; it->IsFound(); it->Next()) { 5383 switch (it->state()) { 5384 case LookupIterator::JSPROXY: 5385 case LookupIterator::NOT_FOUND: 5386 case LookupIterator::TRANSITION: 5387 UNREACHABLE(); 5388 5389 case LookupIterator::ACCESS_CHECK: 5390 if (!it->HasAccess()) { 5391 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 5392 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 5393 return Just(true); 5394 } 5395 break; 5396 5397 // If there's an interceptor, try to store the property with the 5398 // interceptor. 5399 // In case of success, the attributes will have been reset to the default 5400 // attributes of the interceptor, rather than the incoming attributes. 5401 // 5402 // TODO(verwaest): JSProxy afterwards verify the attributes that the 5403 // JSProxy claims it has, and verifies that they are compatible. If not, 5404 // they throw. Here we should do the same. 5405 case LookupIterator::INTERCEPTOR: 5406 if (handling == DONT_FORCE_FIELD) { 5407 Maybe<bool> result = 5408 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 5409 if (result.IsNothing() || result.FromJust()) return result; 5410 } 5411 break; 5412 5413 case LookupIterator::ACCESSOR: { 5414 Handle<Object> accessors = it->GetAccessors(); 5415 5416 // Special handling for AccessorInfo, which behaves like a data 5417 // property. 5418 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) { 5419 PropertyAttributes current_attributes = it->property_attributes(); 5420 // Ensure the context isn't changed after calling into accessors. 5421 AssertNoContextChange ncc(it->isolate()); 5422 5423 // Update the attributes before calling the setter. The setter may 5424 // later change the shape of the property. 5425 if (current_attributes != attributes) { 5426 it->TransitionToAccessorPair(accessors, attributes); 5427 } 5428 5429 return JSObject::SetPropertyWithAccessor(it, value, should_throw); 5430 } 5431 5432 it->ReconfigureDataProperty(value, attributes); 5433 return Just(true); 5434 } 5435 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5436 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value, 5437 should_throw); 5438 5439 case LookupIterator::DATA: { 5440 // Regular property update if the attributes match. 5441 if (it->property_attributes() == attributes) { 5442 return SetDataProperty(it, value); 5443 } 5444 5445 // Special case: properties of typed arrays cannot be reconfigured to 5446 // non-writable nor to non-enumerable. 5447 if (it->IsElement() && object->HasFixedTypedArrayElements()) { 5448 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), 5449 value, should_throw); 5450 } 5451 5452 // Reconfigure the data property if the attributes mismatch. 5453 it->ReconfigureDataProperty(value, attributes); 5454 5455 return Just(true); 5456 } 5457 } 5458 } 5459 5460 return AddDataProperty(it, value, attributes, should_throw, 5461 CERTAINLY_NOT_STORE_FROM_KEYED); 5462 } 5463 5464 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( 5465 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, 5466 PropertyAttributes attributes) { 5467 DCHECK(!value->IsTheHole(object->GetIsolate())); 5468 LookupIterator it(object, name, object, LookupIterator::OWN); 5469 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5470 } 5471 5472 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes( 5473 Handle<JSObject> object, uint32_t index, Handle<Object> value, 5474 PropertyAttributes attributes) { 5475 Isolate* isolate = object->GetIsolate(); 5476 LookupIterator it(isolate, object, index, object, LookupIterator::OWN); 5477 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5478 } 5479 5480 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes( 5481 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, 5482 PropertyAttributes attributes) { 5483 Isolate* isolate = object->GetIsolate(); 5484 LookupIterator it = LookupIterator::PropertyOrElement( 5485 isolate, object, name, object, LookupIterator::OWN); 5486 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5487 } 5488 5489 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( 5490 LookupIterator* it) { 5491 return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor()); 5492 } 5493 5494 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes( 5495 LookupIterator* it) { 5496 for (; it->IsFound(); it->Next()) { 5497 switch (it->state()) { 5498 case LookupIterator::NOT_FOUND: 5499 case LookupIterator::TRANSITION: 5500 UNREACHABLE(); 5501 case LookupIterator::JSPROXY: 5502 return JSProxy::GetPropertyAttributes(it); 5503 case LookupIterator::INTERCEPTOR: { 5504 Maybe<PropertyAttributes> result = 5505 JSObject::GetPropertyAttributesWithInterceptor(it); 5506 if (!result.IsJust()) return result; 5507 if (result.FromJust() != ABSENT) return result; 5508 break; 5509 } 5510 case LookupIterator::ACCESS_CHECK: 5511 if (it->HasAccess()) break; 5512 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it); 5513 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5514 return Just(ABSENT); 5515 case LookupIterator::ACCESSOR: 5516 case LookupIterator::DATA: 5517 return Just(it->property_attributes()); 5518 } 5519 } 5520 return Just(ABSENT); 5521 } 5522 5523 5524 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) { 5525 Handle<FixedArray> array( 5526 isolate->factory()->NewFixedArray(kEntries, TENURED)); 5527 return Handle<NormalizedMapCache>::cast(array); 5528 } 5529 5530 5531 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map, 5532 PropertyNormalizationMode mode) { 5533 DisallowHeapAllocation no_gc; 5534 Object* value = FixedArray::get(GetIndex(fast_map)); 5535 if (!value->IsMap() || 5536 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) { 5537 return MaybeHandle<Map>(); 5538 } 5539 return handle(Map::cast(value)); 5540 } 5541 5542 5543 void NormalizedMapCache::Set(Handle<Map> fast_map, 5544 Handle<Map> normalized_map) { 5545 DisallowHeapAllocation no_gc; 5546 DCHECK(normalized_map->is_dictionary_map()); 5547 FixedArray::set(GetIndex(fast_map), *normalized_map); 5548 } 5549 5550 5551 void NormalizedMapCache::Clear() { 5552 int entries = length(); 5553 for (int i = 0; i != entries; i++) { 5554 set_undefined(i); 5555 } 5556 } 5557 5558 5559 void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object, 5560 Handle<Name> name, 5561 Handle<Code> code) { 5562 Handle<Map> map(object->map()); 5563 Map::UpdateCodeCache(map, name, code); 5564 } 5565 5566 5567 void JSObject::NormalizeProperties(Handle<JSObject> object, 5568 PropertyNormalizationMode mode, 5569 int expected_additional_properties, 5570 const char* reason) { 5571 if (!object->HasFastProperties()) return; 5572 5573 Handle<Map> map(object->map()); 5574 Handle<Map> new_map = Map::Normalize(map, mode, reason); 5575 5576 MigrateToMap(object, new_map, expected_additional_properties); 5577 } 5578 5579 5580 void JSObject::MigrateSlowToFast(Handle<JSObject> object, 5581 int unused_property_fields, 5582 const char* reason) { 5583 if (object->HasFastProperties()) return; 5584 DCHECK(!object->IsJSGlobalObject()); 5585 Isolate* isolate = object->GetIsolate(); 5586 Factory* factory = isolate->factory(); 5587 Handle<NameDictionary> dictionary(object->property_dictionary()); 5588 5589 // Make sure we preserve dictionary representation if there are too many 5590 // descriptors. 5591 int number_of_elements = dictionary->NumberOfElements(); 5592 if (number_of_elements > kMaxNumberOfDescriptors) return; 5593 5594 Handle<FixedArray> iteration_order; 5595 if (number_of_elements != dictionary->NextEnumerationIndex()) { 5596 iteration_order = 5597 NameDictionary::DoGenerateNewEnumerationIndices(dictionary); 5598 } else { 5599 iteration_order = NameDictionary::IterationIndices(dictionary); 5600 } 5601 5602 int instance_descriptor_length = iteration_order->length(); 5603 int number_of_fields = 0; 5604 5605 // Compute the length of the instance descriptor. 5606 for (int i = 0; i < instance_descriptor_length; i++) { 5607 int index = Smi::cast(iteration_order->get(i))->value(); 5608 DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index))); 5609 5610 PropertyKind kind = dictionary->DetailsAt(index).kind(); 5611 if (kind == kData) { 5612 if (FLAG_track_constant_fields) { 5613 number_of_fields += 1; 5614 } else { 5615 Object* value = dictionary->ValueAt(index); 5616 if (!value->IsJSFunction()) { 5617 number_of_fields += 1; 5618 } 5619 } 5620 } 5621 } 5622 5623 Handle<Map> old_map(object->map(), isolate); 5624 5625 int inobject_props = old_map->GetInObjectProperties(); 5626 5627 // Allocate new map. 5628 Handle<Map> new_map = Map::CopyDropDescriptors(old_map); 5629 new_map->set_dictionary_map(false); 5630 5631 NotifyMapChange(old_map, new_map, isolate); 5632 5633 #if TRACE_MAPS 5634 if (FLAG_trace_maps) { 5635 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n", 5636 reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map), 5637 reason); 5638 } 5639 #endif 5640 5641 if (instance_descriptor_length == 0) { 5642 DisallowHeapAllocation no_gc; 5643 DCHECK_LE(unused_property_fields, inobject_props); 5644 // Transform the object. 5645 new_map->set_unused_property_fields(inobject_props); 5646 object->synchronized_set_map(*new_map); 5647 object->set_properties(isolate->heap()->empty_fixed_array()); 5648 // Check that it really works. 5649 DCHECK(object->HasFastProperties()); 5650 return; 5651 } 5652 5653 // Allocate the instance descriptor. 5654 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate( 5655 isolate, instance_descriptor_length, 0, TENURED); 5656 5657 int number_of_allocated_fields = 5658 number_of_fields + unused_property_fields - inobject_props; 5659 if (number_of_allocated_fields < 0) { 5660 // There is enough inobject space for all fields (including unused). 5661 number_of_allocated_fields = 0; 5662 unused_property_fields = inobject_props - number_of_fields; 5663 } 5664 5665 // Allocate the fixed array for the fields. 5666 Handle<FixedArray> fields = factory->NewFixedArray( 5667 number_of_allocated_fields); 5668 5669 // Fill in the instance descriptor and the fields. 5670 int current_offset = 0; 5671 for (int i = 0; i < instance_descriptor_length; i++) { 5672 int index = Smi::cast(iteration_order->get(i))->value(); 5673 Object* k = dictionary->KeyAt(index); 5674 DCHECK(dictionary->IsKey(k)); 5675 // Dictionary keys are internalized upon insertion. 5676 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild. 5677 CHECK(k->IsUniqueName()); 5678 Handle<Name> key(Name::cast(k), isolate); 5679 5680 Object* value = dictionary->ValueAt(index); 5681 5682 PropertyDetails details = dictionary->DetailsAt(index); 5683 DCHECK_EQ(kField, details.location()); 5684 DCHECK_EQ(kMutable, details.constness()); 5685 int enumeration_index = details.dictionary_index(); 5686 5687 Descriptor d; 5688 if (details.kind() == kData) { 5689 if (!FLAG_track_constant_fields && value->IsJSFunction()) { 5690 d = Descriptor::DataConstant(key, handle(value, isolate), 5691 details.attributes()); 5692 } else { 5693 d = Descriptor::DataField( 5694 key, current_offset, details.attributes(), kDefaultFieldConstness, 5695 // TODO(verwaest): value->OptimalRepresentation(); 5696 Representation::Tagged(), FieldType::Any(isolate)); 5697 } 5698 } else { 5699 DCHECK_EQ(kAccessor, details.kind()); 5700 d = Descriptor::AccessorConstant(key, handle(value, isolate), 5701 details.attributes()); 5702 } 5703 details = d.GetDetails(); 5704 if (details.location() == kField) { 5705 if (current_offset < inobject_props) { 5706 object->InObjectPropertyAtPut(current_offset, value, 5707 UPDATE_WRITE_BARRIER); 5708 } else { 5709 int offset = current_offset - inobject_props; 5710 fields->set(offset, value); 5711 } 5712 current_offset += details.field_width_in_words(); 5713 } 5714 descriptors->Set(enumeration_index - 1, &d); 5715 } 5716 DCHECK(current_offset == number_of_fields); 5717 5718 descriptors->Sort(); 5719 5720 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New( 5721 new_map, descriptors, descriptors->number_of_descriptors()); 5722 5723 DisallowHeapAllocation no_gc; 5724 new_map->InitializeDescriptors(*descriptors, *layout_descriptor); 5725 new_map->set_unused_property_fields(unused_property_fields); 5726 5727 // Transform the object. 5728 object->synchronized_set_map(*new_map); 5729 5730 object->set_properties(*fields); 5731 DCHECK(object->IsJSObject()); 5732 5733 // Check that it really works. 5734 DCHECK(object->HasFastProperties()); 5735 } 5736 5737 5738 void JSObject::ResetElements(Handle<JSObject> object) { 5739 Isolate* isolate = object->GetIsolate(); 5740 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map()); 5741 if (object->map()->has_dictionary_elements()) { 5742 Handle<SeededNumberDictionary> new_elements = 5743 SeededNumberDictionary::New(isolate, 0); 5744 object->set_elements(*new_elements); 5745 } else { 5746 object->set_elements(object->map()->GetInitialElements()); 5747 } 5748 } 5749 5750 5751 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) { 5752 if (dictionary->requires_slow_elements()) return; 5753 dictionary->set_requires_slow_elements(); 5754 if (map()->is_prototype_map()) { 5755 // If this object is a prototype (the callee will check), invalidate any 5756 // prototype chains involving it. 5757 InvalidatePrototypeChains(map()); 5758 } 5759 } 5760 5761 5762 Handle<SeededNumberDictionary> JSObject::NormalizeElements( 5763 Handle<JSObject> object) { 5764 DCHECK(!object->HasFixedTypedArrayElements()); 5765 Isolate* isolate = object->GetIsolate(); 5766 bool is_arguments = object->HasSloppyArgumentsElements(); 5767 { 5768 DisallowHeapAllocation no_gc; 5769 FixedArrayBase* elements = object->elements(); 5770 5771 if (is_arguments) { 5772 FixedArray* parameter_map = FixedArray::cast(elements); 5773 elements = FixedArrayBase::cast(parameter_map->get(1)); 5774 } 5775 5776 if (elements->IsDictionary()) { 5777 return handle(SeededNumberDictionary::cast(elements), isolate); 5778 } 5779 } 5780 5781 DCHECK(object->HasFastSmiOrObjectElements() || 5782 object->HasFastDoubleElements() || 5783 object->HasFastArgumentsElements() || 5784 object->HasFastStringWrapperElements()); 5785 5786 Handle<SeededNumberDictionary> dictionary = 5787 object->GetElementsAccessor()->Normalize(object); 5788 5789 // Switch to using the dictionary as the backing storage for elements. 5790 ElementsKind target_kind = is_arguments 5791 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS 5792 : object->HasFastStringWrapperElements() 5793 ? SLOW_STRING_WRAPPER_ELEMENTS 5794 : DICTIONARY_ELEMENTS; 5795 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); 5796 // Set the new map first to satify the elements type assert in set_elements(). 5797 JSObject::MigrateToMap(object, new_map); 5798 5799 if (is_arguments) { 5800 FixedArray::cast(object->elements())->set(1, *dictionary); 5801 } else { 5802 object->set_elements(*dictionary); 5803 } 5804 5805 isolate->counters()->elements_to_dictionary()->Increment(); 5806 5807 #ifdef DEBUG 5808 if (FLAG_trace_normalization) { 5809 OFStream os(stdout); 5810 os << "Object elements have been normalized:\n"; 5811 object->Print(os); 5812 } 5813 #endif 5814 5815 DCHECK(object->HasDictionaryElements() || 5816 object->HasSlowArgumentsElements() || 5817 object->HasSlowStringWrapperElements()); 5818 return dictionary; 5819 } 5820 5821 5822 template <typename ProxyType> 5823 static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate, 5824 Handle<ProxyType> proxy) { 5825 Object* maybe_hash = proxy->hash(); 5826 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash); 5827 5828 Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue)); 5829 proxy->set_hash(hash); 5830 return hash; 5831 } 5832 5833 // static 5834 Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) { 5835 if (object->IsJSGlobalProxy()) { 5836 return JSGlobalProxy::cast(*object)->hash(); 5837 } 5838 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol(); 5839 return *JSReceiver::GetDataProperty(object, hash_code_symbol); 5840 } 5841 5842 // static 5843 Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate, 5844 Handle<JSObject> object) { 5845 if (object->IsJSGlobalProxy()) { 5846 return GetOrCreateIdentityHashHelper(isolate, 5847 Handle<JSGlobalProxy>::cast(object)); 5848 } 5849 5850 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol(); 5851 LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN); 5852 if (it.IsFound()) { 5853 DCHECK_EQ(LookupIterator::DATA, it.state()); 5854 Object* maybe_hash = *it.GetDataValue(); 5855 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash); 5856 } 5857 5858 Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue)); 5859 CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR, 5860 CERTAINLY_NOT_STORE_FROM_KEYED) 5861 .IsJust()); 5862 return hash; 5863 } 5864 5865 // static 5866 Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) { 5867 return proxy->hash(); 5868 } 5869 5870 Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) { 5871 return GetOrCreateIdentityHashHelper(isolate, proxy); 5872 } 5873 5874 5875 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it, 5876 ShouldThrow should_throw) { 5877 Isolate* isolate = it->isolate(); 5878 // Make sure that the top context does not change when doing callbacks or 5879 // interceptor calls. 5880 AssertNoContextChange ncc(isolate); 5881 5882 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 5883 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); 5884 if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>(); 5885 5886 Handle<JSObject> holder = it->GetHolder<JSObject>(); 5887 Handle<Object> receiver = it->GetReceiver(); 5888 if (!receiver->IsJSReceiver()) { 5889 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 5890 Object::ConvertReceiver(isolate, receiver), 5891 Nothing<bool>()); 5892 } 5893 5894 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 5895 *holder, should_throw); 5896 Handle<Object> result; 5897 if (it->IsElement()) { 5898 uint32_t index = it->index(); 5899 v8::IndexedPropertyDeleterCallback deleter = 5900 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter()); 5901 result = args.Call(deleter, index); 5902 } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) { 5903 return Nothing<bool>(); 5904 } else { 5905 Handle<Name> name = it->name(); 5906 DCHECK(!name->IsPrivate()); 5907 v8::GenericNamedPropertyDeleterCallback deleter = 5908 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>( 5909 interceptor->deleter()); 5910 result = args.Call(deleter, name); 5911 } 5912 5913 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 5914 if (result.is_null()) return Nothing<bool>(); 5915 5916 DCHECK(result->IsBoolean()); 5917 // Rebox CustomArguments::kReturnValueOffset before returning. 5918 return Just(result->IsTrue(isolate)); 5919 } 5920 5921 5922 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object, 5923 Handle<Name> name, int entry) { 5924 DCHECK(!object->HasFastProperties()); 5925 Isolate* isolate = object->GetIsolate(); 5926 5927 if (object->IsJSGlobalObject()) { 5928 // If we have a global object, invalidate the cell and swap in a new one. 5929 Handle<GlobalDictionary> dictionary( 5930 JSObject::cast(*object)->global_dictionary()); 5931 DCHECK_NE(GlobalDictionary::kNotFound, entry); 5932 5933 auto cell = PropertyCell::InvalidateEntry(dictionary, entry); 5934 cell->set_value(isolate->heap()->the_hole_value()); 5935 cell->set_property_details( 5936 PropertyDetails::Empty(PropertyCellType::kUninitialized)); 5937 } else { 5938 Handle<NameDictionary> dictionary(object->property_dictionary()); 5939 DCHECK_NE(NameDictionary::kNotFound, entry); 5940 5941 NameDictionary::DeleteProperty(dictionary, entry); 5942 Handle<NameDictionary> new_properties = 5943 NameDictionary::Shrink(dictionary, name); 5944 object->set_properties(*new_properties); 5945 } 5946 } 5947 5948 5949 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it, 5950 LanguageMode language_mode) { 5951 it->UpdateProtector(); 5952 5953 Isolate* isolate = it->isolate(); 5954 5955 if (it->state() == LookupIterator::JSPROXY) { 5956 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(), 5957 it->GetName(), language_mode); 5958 } 5959 5960 if (it->GetReceiver()->IsJSProxy()) { 5961 if (it->state() != LookupIterator::NOT_FOUND) { 5962 DCHECK_EQ(LookupIterator::DATA, it->state()); 5963 DCHECK(it->name()->IsPrivate()); 5964 it->Delete(); 5965 } 5966 return Just(true); 5967 } 5968 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); 5969 5970 for (; it->IsFound(); it->Next()) { 5971 switch (it->state()) { 5972 case LookupIterator::JSPROXY: 5973 case LookupIterator::NOT_FOUND: 5974 case LookupIterator::TRANSITION: 5975 UNREACHABLE(); 5976 case LookupIterator::ACCESS_CHECK: 5977 if (it->HasAccess()) break; 5978 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 5979 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 5980 return Just(false); 5981 case LookupIterator::INTERCEPTOR: { 5982 ShouldThrow should_throw = 5983 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 5984 Maybe<bool> result = 5985 JSObject::DeletePropertyWithInterceptor(it, should_throw); 5986 // An exception was thrown in the interceptor. Propagate. 5987 if (isolate->has_pending_exception()) return Nothing<bool>(); 5988 // Delete with interceptor succeeded. Return result. 5989 // TODO(neis): In strict mode, we should probably throw if the 5990 // interceptor returns false. 5991 if (result.IsJust()) return result; 5992 break; 5993 } 5994 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5995 return Just(true); 5996 case LookupIterator::DATA: 5997 case LookupIterator::ACCESSOR: { 5998 if (!it->IsConfigurable()) { 5999 // Fail if the property is not configurable. 6000 if (is_strict(language_mode)) { 6001 isolate->Throw(*isolate->factory()->NewTypeError( 6002 MessageTemplate::kStrictDeleteProperty, it->GetName(), 6003 receiver)); 6004 return Nothing<bool>(); 6005 } 6006 return Just(false); 6007 } 6008 6009 it->Delete(); 6010 6011 return Just(true); 6012 } 6013 } 6014 } 6015 6016 return Just(true); 6017 } 6018 6019 6020 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index, 6021 LanguageMode language_mode) { 6022 LookupIterator it(object->GetIsolate(), object, index, object, 6023 LookupIterator::OWN); 6024 return DeleteProperty(&it, language_mode); 6025 } 6026 6027 6028 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object, 6029 Handle<Name> name, 6030 LanguageMode language_mode) { 6031 LookupIterator it(object, name, object, LookupIterator::OWN); 6032 return DeleteProperty(&it, language_mode); 6033 } 6034 6035 6036 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object, 6037 Handle<Name> name, 6038 LanguageMode language_mode) { 6039 LookupIterator it = LookupIterator::PropertyOrElement( 6040 name->GetIsolate(), object, name, object, LookupIterator::OWN); 6041 return DeleteProperty(&it, language_mode); 6042 } 6043 6044 // ES6 19.1.2.4 6045 // static 6046 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object, 6047 Handle<Object> key, 6048 Handle<Object> attributes) { 6049 // 1. If Type(O) is not Object, throw a TypeError exception. 6050 if (!object->IsJSReceiver()) { 6051 Handle<String> fun_name = 6052 isolate->factory()->InternalizeUtf8String("Object.defineProperty"); 6053 THROW_NEW_ERROR_RETURN_FAILURE( 6054 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name)); 6055 } 6056 // 2. Let key be ToPropertyKey(P). 6057 // 3. ReturnIfAbrupt(key). 6058 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key)); 6059 // 4. Let desc be ToPropertyDescriptor(Attributes). 6060 // 5. ReturnIfAbrupt(desc). 6061 PropertyDescriptor desc; 6062 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) { 6063 return isolate->heap()->exception(); 6064 } 6065 // 6. Let success be DefinePropertyOrThrow(O,key, desc). 6066 Maybe<bool> success = DefineOwnProperty( 6067 isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR); 6068 // 7. ReturnIfAbrupt(success). 6069 MAYBE_RETURN(success, isolate->heap()->exception()); 6070 CHECK(success.FromJust()); 6071 // 8. Return O. 6072 return *object; 6073 } 6074 6075 6076 // ES6 19.1.2.3.1 6077 // static 6078 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate, 6079 Handle<Object> object, 6080 Handle<Object> properties) { 6081 // 1. If Type(O) is not Object, throw a TypeError exception. 6082 if (!object->IsJSReceiver()) { 6083 Handle<String> fun_name = 6084 isolate->factory()->InternalizeUtf8String("Object.defineProperties"); 6085 THROW_NEW_ERROR(isolate, 6086 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name), 6087 Object); 6088 } 6089 // 2. Let props be ToObject(Properties). 6090 // 3. ReturnIfAbrupt(props). 6091 Handle<JSReceiver> props; 6092 ASSIGN_RETURN_ON_EXCEPTION(isolate, props, 6093 Object::ToObject(isolate, properties), Object); 6094 6095 // 4. Let keys be props.[[OwnPropertyKeys]](). 6096 // 5. ReturnIfAbrupt(keys). 6097 Handle<FixedArray> keys; 6098 ASSIGN_RETURN_ON_EXCEPTION( 6099 isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly, 6100 ALL_PROPERTIES), 6101 Object); 6102 // 6. Let descriptors be an empty List. 6103 int capacity = keys->length(); 6104 std::vector<PropertyDescriptor> descriptors(capacity); 6105 size_t descriptors_index = 0; 6106 // 7. Repeat for each element nextKey of keys in List order, 6107 for (int i = 0; i < keys->length(); ++i) { 6108 Handle<Object> next_key(keys->get(i), isolate); 6109 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey). 6110 // 7b. ReturnIfAbrupt(propDesc). 6111 bool success = false; 6112 LookupIterator it = LookupIterator::PropertyOrElement( 6113 isolate, props, next_key, &success, LookupIterator::OWN); 6114 DCHECK(success); 6115 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 6116 if (!maybe.IsJust()) return MaybeHandle<Object>(); 6117 PropertyAttributes attrs = maybe.FromJust(); 6118 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true: 6119 if (attrs == ABSENT) continue; 6120 if (attrs & DONT_ENUM) continue; 6121 // 7c i. Let descObj be Get(props, nextKey). 6122 // 7c ii. ReturnIfAbrupt(descObj). 6123 Handle<Object> desc_obj; 6124 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it), 6125 Object); 6126 // 7c iii. Let desc be ToPropertyDescriptor(descObj). 6127 success = PropertyDescriptor::ToPropertyDescriptor( 6128 isolate, desc_obj, &descriptors[descriptors_index]); 6129 // 7c iv. ReturnIfAbrupt(desc). 6130 if (!success) return MaybeHandle<Object>(); 6131 // 7c v. Append the pair (a two element List) consisting of nextKey and 6132 // desc to the end of descriptors. 6133 descriptors[descriptors_index].set_name(next_key); 6134 descriptors_index++; 6135 } 6136 // 8. For each pair from descriptors in list order, 6137 for (size_t i = 0; i < descriptors_index; ++i) { 6138 PropertyDescriptor* desc = &descriptors[i]; 6139 // 8a. Let P be the first element of pair. 6140 // 8b. Let desc be the second element of pair. 6141 // 8c. Let status be DefinePropertyOrThrow(O, P, desc). 6142 Maybe<bool> status = 6143 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object), 6144 desc->name(), desc, THROW_ON_ERROR); 6145 // 8d. ReturnIfAbrupt(status). 6146 if (!status.IsJust()) return MaybeHandle<Object>(); 6147 CHECK(status.FromJust()); 6148 } 6149 // 9. Return o. 6150 return object; 6151 } 6152 6153 6154 // static 6155 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate, 6156 Handle<JSReceiver> object, 6157 Handle<Object> key, 6158 PropertyDescriptor* desc, 6159 ShouldThrow should_throw) { 6160 if (object->IsJSArray()) { 6161 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object), 6162 key, desc, should_throw); 6163 } 6164 if (object->IsJSProxy()) { 6165 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object), 6166 key, desc, should_throw); 6167 } 6168 if (object->IsJSTypedArray()) { 6169 return JSTypedArray::DefineOwnProperty( 6170 isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw); 6171 } 6172 // TODO(neis): Special case for JSModuleNamespace? 6173 6174 // OrdinaryDefineOwnProperty, by virtue of calling 6175 // DefineOwnPropertyIgnoreAttributes, can handle arguments 6176 // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc). 6177 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key, 6178 desc, should_throw); 6179 } 6180 6181 6182 // static 6183 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, 6184 Handle<JSObject> object, 6185 Handle<Object> key, 6186 PropertyDescriptor* desc, 6187 ShouldThrow should_throw) { 6188 bool success = false; 6189 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... 6190 LookupIterator it = LookupIterator::PropertyOrElement( 6191 isolate, object, key, &success, LookupIterator::OWN); 6192 DCHECK(success); // ...so creating a LookupIterator can't fail. 6193 6194 // Deal with access checks first. 6195 if (it.state() == LookupIterator::ACCESS_CHECK) { 6196 if (!it.HasAccess()) { 6197 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); 6198 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6199 return Just(true); 6200 } 6201 it.Next(); 6202 } 6203 6204 // Handle interceptor 6205 if (it.state() == LookupIterator::INTERCEPTOR) { 6206 if (it.HolderIsReceiverOrHiddenPrototype()) { 6207 Maybe<bool> result = DefinePropertyWithInterceptorInternal( 6208 &it, it.GetInterceptor(), should_throw, *desc); 6209 if (result.IsNothing() || result.FromJust()) { 6210 return result; 6211 } 6212 } 6213 } 6214 6215 return OrdinaryDefineOwnProperty(&it, desc, should_throw); 6216 } 6217 6218 6219 // ES6 9.1.6.1 6220 // static 6221 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it, 6222 PropertyDescriptor* desc, 6223 ShouldThrow should_throw) { 6224 Isolate* isolate = it->isolate(); 6225 // 1. Let current be O.[[GetOwnProperty]](P). 6226 // 2. ReturnIfAbrupt(current). 6227 PropertyDescriptor current; 6228 MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>()); 6229 6230 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset 6231 // the iterator every time. Currently, the reasons why we need it are: 6232 // - handle interceptors correctly 6233 // - handle accessors correctly (which might change the holder's map) 6234 it->Restart(); 6235 // 3. Let extensible be the value of the [[Extensible]] internal slot of O. 6236 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 6237 bool extensible = JSObject::IsExtensible(object); 6238 6239 return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc, 6240 ¤t, should_throw); 6241 } 6242 6243 6244 // ES6 9.1.6.2 6245 // static 6246 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor( 6247 Isolate* isolate, bool extensible, PropertyDescriptor* desc, 6248 PropertyDescriptor* current, Handle<Name> property_name, 6249 ShouldThrow should_throw) { 6250 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, 6251 // Extensible, Desc, Current). 6252 return ValidateAndApplyPropertyDescriptor( 6253 isolate, NULL, extensible, desc, current, should_throw, property_name); 6254 } 6255 6256 6257 // ES6 9.1.6.3 6258 // static 6259 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor( 6260 Isolate* isolate, LookupIterator* it, bool extensible, 6261 PropertyDescriptor* desc, PropertyDescriptor* current, 6262 ShouldThrow should_throw, Handle<Name> property_name) { 6263 // We either need a LookupIterator, or a property name. 6264 DCHECK((it == NULL) != property_name.is_null()); 6265 Handle<JSObject> object; 6266 if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver()); 6267 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc); 6268 bool desc_is_accessor_descriptor = 6269 PropertyDescriptor::IsAccessorDescriptor(desc); 6270 bool desc_is_generic_descriptor = 6271 PropertyDescriptor::IsGenericDescriptor(desc); 6272 // 1. (Assert) 6273 // 2. If current is undefined, then 6274 if (current->is_empty()) { 6275 // 2a. If extensible is false, return false. 6276 if (!extensible) { 6277 RETURN_FAILURE(isolate, should_throw, 6278 NewTypeError(MessageTemplate::kDefineDisallowed, 6279 it != NULL ? it->GetName() : property_name)); 6280 } 6281 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then: 6282 // (This is equivalent to !IsAccessorDescriptor(desc).) 6283 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) == 6284 !desc_is_accessor_descriptor); 6285 if (!desc_is_accessor_descriptor) { 6286 // 2c i. If O is not undefined, create an own data property named P of 6287 // object O whose [[Value]], [[Writable]], [[Enumerable]] and 6288 // [[Configurable]] attribute values are described by Desc. If the value 6289 // of an attribute field of Desc is absent, the attribute of the newly 6290 // created property is set to its default value. 6291 if (it != NULL) { 6292 if (!desc->has_writable()) desc->set_writable(false); 6293 if (!desc->has_enumerable()) desc->set_enumerable(false); 6294 if (!desc->has_configurable()) desc->set_configurable(false); 6295 Handle<Object> value( 6296 desc->has_value() 6297 ? desc->value() 6298 : Handle<Object>::cast(isolate->factory()->undefined_value())); 6299 MaybeHandle<Object> result = 6300 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, 6301 desc->ToAttributes()); 6302 if (result.is_null()) return Nothing<bool>(); 6303 } 6304 } else { 6305 // 2d. Else Desc must be an accessor Property Descriptor, 6306 DCHECK(desc_is_accessor_descriptor); 6307 // 2d i. If O is not undefined, create an own accessor property named P 6308 // of object O whose [[Get]], [[Set]], [[Enumerable]] and 6309 // [[Configurable]] attribute values are described by Desc. If the value 6310 // of an attribute field of Desc is absent, the attribute of the newly 6311 // created property is set to its default value. 6312 if (it != NULL) { 6313 if (!desc->has_enumerable()) desc->set_enumerable(false); 6314 if (!desc->has_configurable()) desc->set_configurable(false); 6315 Handle<Object> getter( 6316 desc->has_get() 6317 ? desc->get() 6318 : Handle<Object>::cast(isolate->factory()->null_value())); 6319 Handle<Object> setter( 6320 desc->has_set() 6321 ? desc->set() 6322 : Handle<Object>::cast(isolate->factory()->null_value())); 6323 MaybeHandle<Object> result = 6324 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes()); 6325 if (result.is_null()) return Nothing<bool>(); 6326 } 6327 } 6328 // 2e. Return true. 6329 return Just(true); 6330 } 6331 // 3. Return true, if every field in Desc is absent. 6332 // 4. Return true, if every field in Desc also occurs in current and the 6333 // value of every field in Desc is the same value as the corresponding field 6334 // in current when compared using the SameValue algorithm. 6335 if ((!desc->has_enumerable() || 6336 desc->enumerable() == current->enumerable()) && 6337 (!desc->has_configurable() || 6338 desc->configurable() == current->configurable()) && 6339 (!desc->has_value() || 6340 (current->has_value() && current->value()->SameValue(*desc->value()))) && 6341 (!desc->has_writable() || 6342 (current->has_writable() && current->writable() == desc->writable())) && 6343 (!desc->has_get() || 6344 (current->has_get() && current->get()->SameValue(*desc->get()))) && 6345 (!desc->has_set() || 6346 (current->has_set() && current->set()->SameValue(*desc->set())))) { 6347 return Just(true); 6348 } 6349 // 5. If the [[Configurable]] field of current is false, then 6350 if (!current->configurable()) { 6351 // 5a. Return false, if the [[Configurable]] field of Desc is true. 6352 if (desc->has_configurable() && desc->configurable()) { 6353 RETURN_FAILURE(isolate, should_throw, 6354 NewTypeError(MessageTemplate::kRedefineDisallowed, 6355 it != NULL ? it->GetName() : property_name)); 6356 } 6357 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the 6358 // [[Enumerable]] fields of current and Desc are the Boolean negation of 6359 // each other. 6360 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) { 6361 RETURN_FAILURE(isolate, should_throw, 6362 NewTypeError(MessageTemplate::kRedefineDisallowed, 6363 it != NULL ? it->GetName() : property_name)); 6364 } 6365 } 6366 6367 bool current_is_data_descriptor = 6368 PropertyDescriptor::IsDataDescriptor(current); 6369 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required. 6370 if (desc_is_generic_descriptor) { 6371 // Nothing to see here. 6372 6373 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have 6374 // different results, then: 6375 } else if (current_is_data_descriptor != desc_is_data_descriptor) { 6376 // 7a. Return false, if the [[Configurable]] field of current is false. 6377 if (!current->configurable()) { 6378 RETURN_FAILURE(isolate, should_throw, 6379 NewTypeError(MessageTemplate::kRedefineDisallowed, 6380 it != NULL ? it->GetName() : property_name)); 6381 } 6382 // 7b. If IsDataDescriptor(current) is true, then: 6383 if (current_is_data_descriptor) { 6384 // 7b i. If O is not undefined, convert the property named P of object O 6385 // from a data property to an accessor property. Preserve the existing 6386 // values of the converted property's [[Configurable]] and [[Enumerable]] 6387 // attributes and set the rest of the property's attributes to their 6388 // default values. 6389 // --> Folded into step 10. 6390 } else { 6391 // 7c i. If O is not undefined, convert the property named P of object O 6392 // from an accessor property to a data property. Preserve the existing 6393 // values of the converted propertys [[Configurable]] and [[Enumerable]] 6394 // attributes and set the rest of the propertys attributes to their 6395 // default values. 6396 // --> Folded into step 10. 6397 } 6398 6399 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both 6400 // true, then: 6401 } else if (current_is_data_descriptor && desc_is_data_descriptor) { 6402 // 8a. If the [[Configurable]] field of current is false, then: 6403 if (!current->configurable()) { 6404 // 8a i. Return false, if the [[Writable]] field of current is false and 6405 // the [[Writable]] field of Desc is true. 6406 if (!current->writable() && desc->has_writable() && desc->writable()) { 6407 RETURN_FAILURE( 6408 isolate, should_throw, 6409 NewTypeError(MessageTemplate::kRedefineDisallowed, 6410 it != NULL ? it->GetName() : property_name)); 6411 } 6412 // 8a ii. If the [[Writable]] field of current is false, then: 6413 if (!current->writable()) { 6414 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and 6415 // SameValue(Desc.[[Value]], current.[[Value]]) is false. 6416 if (desc->has_value() && !desc->value()->SameValue(*current->value())) { 6417 RETURN_FAILURE( 6418 isolate, should_throw, 6419 NewTypeError(MessageTemplate::kRedefineDisallowed, 6420 it != NULL ? it->GetName() : property_name)); 6421 } 6422 } 6423 } 6424 } else { 6425 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) 6426 // are both true, 6427 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) && 6428 desc_is_accessor_descriptor); 6429 // 9a. If the [[Configurable]] field of current is false, then: 6430 if (!current->configurable()) { 6431 // 9a i. Return false, if the [[Set]] field of Desc is present and 6432 // SameValue(Desc.[[Set]], current.[[Set]]) is false. 6433 if (desc->has_set() && !desc->set()->SameValue(*current->set())) { 6434 RETURN_FAILURE( 6435 isolate, should_throw, 6436 NewTypeError(MessageTemplate::kRedefineDisallowed, 6437 it != NULL ? it->GetName() : property_name)); 6438 } 6439 // 9a ii. Return false, if the [[Get]] field of Desc is present and 6440 // SameValue(Desc.[[Get]], current.[[Get]]) is false. 6441 if (desc->has_get() && !desc->get()->SameValue(*current->get())) { 6442 RETURN_FAILURE( 6443 isolate, should_throw, 6444 NewTypeError(MessageTemplate::kRedefineDisallowed, 6445 it != NULL ? it->GetName() : property_name)); 6446 } 6447 } 6448 } 6449 6450 // 10. If O is not undefined, then: 6451 if (it != NULL) { 6452 // 10a. For each field of Desc that is present, set the corresponding 6453 // attribute of the property named P of object O to the value of the field. 6454 PropertyAttributes attrs = NONE; 6455 6456 if (desc->has_enumerable()) { 6457 attrs = static_cast<PropertyAttributes>( 6458 attrs | (desc->enumerable() ? NONE : DONT_ENUM)); 6459 } else { 6460 attrs = static_cast<PropertyAttributes>( 6461 attrs | (current->enumerable() ? NONE : DONT_ENUM)); 6462 } 6463 if (desc->has_configurable()) { 6464 attrs = static_cast<PropertyAttributes>( 6465 attrs | (desc->configurable() ? NONE : DONT_DELETE)); 6466 } else { 6467 attrs = static_cast<PropertyAttributes>( 6468 attrs | (current->configurable() ? NONE : DONT_DELETE)); 6469 } 6470 if (desc_is_data_descriptor || 6471 (desc_is_generic_descriptor && current_is_data_descriptor)) { 6472 if (desc->has_writable()) { 6473 attrs = static_cast<PropertyAttributes>( 6474 attrs | (desc->writable() ? NONE : READ_ONLY)); 6475 } else { 6476 attrs = static_cast<PropertyAttributes>( 6477 attrs | (current->writable() ? NONE : READ_ONLY)); 6478 } 6479 Handle<Object> value( 6480 desc->has_value() ? desc->value() 6481 : current->has_value() 6482 ? current->value() 6483 : Handle<Object>::cast( 6484 isolate->factory()->undefined_value())); 6485 MaybeHandle<Object> result = 6486 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs); 6487 if (result.is_null()) return Nothing<bool>(); 6488 } else { 6489 DCHECK(desc_is_accessor_descriptor || 6490 (desc_is_generic_descriptor && 6491 PropertyDescriptor::IsAccessorDescriptor(current))); 6492 Handle<Object> getter( 6493 desc->has_get() 6494 ? desc->get() 6495 : current->has_get() 6496 ? current->get() 6497 : Handle<Object>::cast(isolate->factory()->null_value())); 6498 Handle<Object> setter( 6499 desc->has_set() 6500 ? desc->set() 6501 : current->has_set() 6502 ? current->set() 6503 : Handle<Object>::cast(isolate->factory()->null_value())); 6504 MaybeHandle<Object> result = 6505 JSObject::DefineAccessor(it, getter, setter, attrs); 6506 if (result.is_null()) return Nothing<bool>(); 6507 } 6508 } 6509 6510 // 11. Return true. 6511 return Just(true); 6512 } 6513 6514 6515 // static 6516 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it, 6517 Handle<Object> value, 6518 ShouldThrow should_throw) { 6519 DCHECK(!it->check_prototype_chain()); 6520 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 6521 Isolate* isolate = receiver->GetIsolate(); 6522 6523 if (receiver->IsJSObject()) { 6524 return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut. 6525 } 6526 6527 PropertyDescriptor new_desc; 6528 new_desc.set_value(value); 6529 new_desc.set_writable(true); 6530 new_desc.set_enumerable(true); 6531 new_desc.set_configurable(true); 6532 6533 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 6534 &new_desc, should_throw); 6535 } 6536 6537 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it, 6538 Handle<Object> value, 6539 ShouldThrow should_throw) { 6540 DCHECK(it->GetReceiver()->IsJSObject()); 6541 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>()); 6542 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 6543 Isolate* isolate = receiver->GetIsolate(); 6544 6545 if (it->IsFound()) { 6546 Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it); 6547 MAYBE_RETURN(attributes, Nothing<bool>()); 6548 if ((attributes.FromJust() & DONT_DELETE) != 0) { 6549 RETURN_FAILURE( 6550 isolate, should_throw, 6551 NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName())); 6552 } 6553 } else { 6554 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) { 6555 RETURN_FAILURE( 6556 isolate, should_throw, 6557 NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName())); 6558 } 6559 } 6560 6561 RETURN_ON_EXCEPTION_VALUE(it->isolate(), 6562 DefineOwnPropertyIgnoreAttributes(it, value, NONE), 6563 Nothing<bool>()); 6564 6565 return Just(true); 6566 } 6567 6568 6569 // TODO(jkummerow): Consider unification with FastAsArrayLength() in 6570 // accessors.cc. 6571 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) { 6572 DCHECK(value->IsNumber() || value->IsName()); 6573 if (value->ToArrayLength(length)) return true; 6574 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length); 6575 return false; 6576 } 6577 6578 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) { 6579 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32; 6580 } 6581 6582 6583 // ES6 9.4.2.1 6584 // static 6585 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o, 6586 Handle<Object> name, 6587 PropertyDescriptor* desc, 6588 ShouldThrow should_throw) { 6589 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.) 6590 // 2. If P is "length", then: 6591 // TODO(jkummerow): Check if we need slow string comparison. 6592 if (*name == isolate->heap()->length_string()) { 6593 // 2a. Return ArraySetLength(A, Desc). 6594 return ArraySetLength(isolate, o, desc, should_throw); 6595 } 6596 // 3. Else if P is an array index, then: 6597 uint32_t index = 0; 6598 if (PropertyKeyToArrayIndex(name, &index)) { 6599 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 6600 PropertyDescriptor old_len_desc; 6601 Maybe<bool> success = GetOwnPropertyDescriptor( 6602 isolate, o, isolate->factory()->length_string(), &old_len_desc); 6603 // 3b. (Assert) 6604 DCHECK(success.FromJust()); 6605 USE(success); 6606 // 3c. Let oldLen be oldLenDesc.[[Value]]. 6607 uint32_t old_len = 0; 6608 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 6609 // 3d. Let index be ToUint32(P). 6610 // (Already done above.) 6611 // 3e. (Assert) 6612 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false, 6613 // return false. 6614 if (index >= old_len && old_len_desc.has_writable() && 6615 !old_len_desc.writable()) { 6616 RETURN_FAILURE(isolate, should_throw, 6617 NewTypeError(MessageTemplate::kDefineDisallowed, name)); 6618 } 6619 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc). 6620 Maybe<bool> succeeded = 6621 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 6622 // 3h. Assert: succeeded is not an abrupt completion. 6623 // In our case, if should_throw == THROW_ON_ERROR, it can be! 6624 // 3i. If succeeded is false, return false. 6625 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded; 6626 // 3j. If index >= oldLen, then: 6627 if (index >= old_len) { 6628 // 3j i. Set oldLenDesc.[[Value]] to index + 1. 6629 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1)); 6630 // 3j ii. Let succeeded be 6631 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc). 6632 succeeded = OrdinaryDefineOwnProperty(isolate, o, 6633 isolate->factory()->length_string(), 6634 &old_len_desc, should_throw); 6635 // 3j iii. Assert: succeeded is true. 6636 DCHECK(succeeded.FromJust()); 6637 USE(succeeded); 6638 } 6639 // 3k. Return true. 6640 return Just(true); 6641 } 6642 6643 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc). 6644 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 6645 } 6646 6647 6648 // Part of ES6 9.4.2.4 ArraySetLength. 6649 // static 6650 bool JSArray::AnythingToArrayLength(Isolate* isolate, 6651 Handle<Object> length_object, 6652 uint32_t* output) { 6653 // Fast path: check numbers and strings that can be converted directly 6654 // and unobservably. 6655 if (length_object->ToArrayLength(output)) return true; 6656 if (length_object->IsString() && 6657 Handle<String>::cast(length_object)->AsArrayIndex(output)) { 6658 return true; 6659 } 6660 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength". 6661 // 3. Let newLen be ToUint32(Desc.[[Value]]). 6662 Handle<Object> uint32_v; 6663 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) { 6664 // 4. ReturnIfAbrupt(newLen). 6665 return false; 6666 } 6667 // 5. Let numberLen be ToNumber(Desc.[[Value]]). 6668 Handle<Object> number_v; 6669 if (!Object::ToNumber(length_object).ToHandle(&number_v)) { 6670 // 6. ReturnIfAbrupt(newLen). 6671 return false; 6672 } 6673 // 7. If newLen != numberLen, throw a RangeError exception. 6674 if (uint32_v->Number() != number_v->Number()) { 6675 Handle<Object> exception = 6676 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength); 6677 isolate->Throw(*exception); 6678 return false; 6679 } 6680 CHECK(uint32_v->ToArrayLength(output)); 6681 return true; 6682 } 6683 6684 6685 // ES6 9.4.2.4 6686 // static 6687 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a, 6688 PropertyDescriptor* desc, 6689 ShouldThrow should_throw) { 6690 // 1. If the [[Value]] field of Desc is absent, then 6691 if (!desc->has_value()) { 6692 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc). 6693 return OrdinaryDefineOwnProperty( 6694 isolate, a, isolate->factory()->length_string(), desc, should_throw); 6695 } 6696 // 2. Let newLenDesc be a copy of Desc. 6697 // (Actual copying is not necessary.) 6698 PropertyDescriptor* new_len_desc = desc; 6699 // 3. - 7. Convert Desc.[[Value]] to newLen. 6700 uint32_t new_len = 0; 6701 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) { 6702 DCHECK(isolate->has_pending_exception()); 6703 return Nothing<bool>(); 6704 } 6705 // 8. Set newLenDesc.[[Value]] to newLen. 6706 // (Done below, if needed.) 6707 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 6708 PropertyDescriptor old_len_desc; 6709 Maybe<bool> success = GetOwnPropertyDescriptor( 6710 isolate, a, isolate->factory()->length_string(), &old_len_desc); 6711 // 10. (Assert) 6712 DCHECK(success.FromJust()); 6713 USE(success); 6714 // 11. Let oldLen be oldLenDesc.[[Value]]. 6715 uint32_t old_len = 0; 6716 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 6717 // 12. If newLen >= oldLen, then 6718 if (new_len >= old_len) { 6719 // 8. Set newLenDesc.[[Value]] to newLen. 6720 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc). 6721 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len)); 6722 return OrdinaryDefineOwnProperty(isolate, a, 6723 isolate->factory()->length_string(), 6724 new_len_desc, should_throw); 6725 } 6726 // 13. If oldLenDesc.[[Writable]] is false, return false. 6727 if (!old_len_desc.writable()) { 6728 RETURN_FAILURE(isolate, should_throw, 6729 NewTypeError(MessageTemplate::kRedefineDisallowed, 6730 isolate->factory()->length_string())); 6731 } 6732 // 14. If newLenDesc.[[Writable]] is absent or has the value true, 6733 // let newWritable be true. 6734 bool new_writable = false; 6735 if (!new_len_desc->has_writable() || new_len_desc->writable()) { 6736 new_writable = true; 6737 } else { 6738 // 15. Else, 6739 // 15a. Need to defer setting the [[Writable]] attribute to false in case 6740 // any elements cannot be deleted. 6741 // 15b. Let newWritable be false. (It's initialized as "false" anyway.) 6742 // 15c. Set newLenDesc.[[Writable]] to true. 6743 // (Not needed.) 6744 } 6745 // Most of steps 16 through 19 is implemented by JSArray::SetLength. 6746 JSArray::SetLength(a, new_len); 6747 // Steps 19d-ii, 20. 6748 if (!new_writable) { 6749 PropertyDescriptor readonly; 6750 readonly.set_writable(false); 6751 Maybe<bool> success = OrdinaryDefineOwnProperty( 6752 isolate, a, isolate->factory()->length_string(), &readonly, 6753 should_throw); 6754 DCHECK(success.FromJust()); 6755 USE(success); 6756 } 6757 uint32_t actual_new_len = 0; 6758 CHECK(a->length()->ToArrayLength(&actual_new_len)); 6759 // Steps 19d-v, 21. Return false if there were non-deletable elements. 6760 bool result = actual_new_len == new_len; 6761 if (!result) { 6762 RETURN_FAILURE( 6763 isolate, should_throw, 6764 NewTypeError(MessageTemplate::kStrictDeleteProperty, 6765 isolate->factory()->NewNumberFromUint(actual_new_len - 1), 6766 a)); 6767 } 6768 return Just(result); 6769 } 6770 6771 6772 // ES6 9.5.6 6773 // static 6774 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy, 6775 Handle<Object> key, 6776 PropertyDescriptor* desc, 6777 ShouldThrow should_throw) { 6778 STACK_CHECK(isolate, Nothing<bool>()); 6779 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) { 6780 return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc, 6781 should_throw); 6782 } 6783 Handle<String> trap_name = isolate->factory()->defineProperty_string(); 6784 // 1. Assert: IsPropertyKey(P) is true. 6785 DCHECK(key->IsName() || key->IsNumber()); 6786 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 6787 Handle<Object> handler(proxy->handler(), isolate); 6788 // 3. If handler is null, throw a TypeError exception. 6789 // 4. Assert: Type(handler) is Object. 6790 if (proxy->IsRevoked()) { 6791 isolate->Throw(*isolate->factory()->NewTypeError( 6792 MessageTemplate::kProxyRevoked, trap_name)); 6793 return Nothing<bool>(); 6794 } 6795 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 6796 Handle<JSReceiver> target(proxy->target(), isolate); 6797 // 6. Let trap be ? GetMethod(handler, "defineProperty"). 6798 Handle<Object> trap; 6799 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 6800 isolate, trap, 6801 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 6802 Nothing<bool>()); 6803 // 7. If trap is undefined, then: 6804 if (trap->IsUndefined(isolate)) { 6805 // 7a. Return target.[[DefineOwnProperty]](P, Desc). 6806 return JSReceiver::DefineOwnProperty(isolate, target, key, desc, 6807 should_throw); 6808 } 6809 // 8. Let descObj be FromPropertyDescriptor(Desc). 6810 Handle<Object> desc_obj = desc->ToObject(isolate); 6811 // 9. Let booleanTrapResult be 6812 // ToBoolean(? Call(trap, handler, target, P, descObj)). 6813 Handle<Name> property_name = 6814 key->IsName() 6815 ? Handle<Name>::cast(key) 6816 : Handle<Name>::cast(isolate->factory()->NumberToString(key)); 6817 // Do not leak private property names. 6818 DCHECK(!property_name->IsPrivate()); 6819 Handle<Object> trap_result_obj; 6820 Handle<Object> args[] = {target, property_name, desc_obj}; 6821 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 6822 isolate, trap_result_obj, 6823 Execution::Call(isolate, trap, handler, arraysize(args), args), 6824 Nothing<bool>()); 6825 // 10. If booleanTrapResult is false, return false. 6826 if (!trap_result_obj->BooleanValue()) { 6827 RETURN_FAILURE(isolate, should_throw, 6828 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 6829 trap_name, property_name)); 6830 } 6831 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P). 6832 PropertyDescriptor target_desc; 6833 Maybe<bool> target_found = 6834 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc); 6835 MAYBE_RETURN(target_found, Nothing<bool>()); 6836 // 12. Let extensibleTarget be ? IsExtensible(target). 6837 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target); 6838 MAYBE_RETURN(maybe_extensible, Nothing<bool>()); 6839 bool extensible_target = maybe_extensible.FromJust(); 6840 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] 6841 // is false, then: 6842 // 13a. Let settingConfigFalse be true. 6843 // 14. Else let settingConfigFalse be false. 6844 bool setting_config_false = desc->has_configurable() && !desc->configurable(); 6845 // 15. If targetDesc is undefined, then 6846 if (!target_found.FromJust()) { 6847 // 15a. If extensibleTarget is false, throw a TypeError exception. 6848 if (!extensible_target) { 6849 isolate->Throw(*isolate->factory()->NewTypeError( 6850 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name)); 6851 return Nothing<bool>(); 6852 } 6853 // 15b. If settingConfigFalse is true, throw a TypeError exception. 6854 if (setting_config_false) { 6855 isolate->Throw(*isolate->factory()->NewTypeError( 6856 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 6857 return Nothing<bool>(); 6858 } 6859 } else { 6860 // 16. Else targetDesc is not undefined, 6861 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, 6862 // targetDesc) is false, throw a TypeError exception. 6863 Maybe<bool> valid = 6864 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc, 6865 &target_desc, property_name, DONT_THROW); 6866 MAYBE_RETURN(valid, Nothing<bool>()); 6867 if (!valid.FromJust()) { 6868 isolate->Throw(*isolate->factory()->NewTypeError( 6869 MessageTemplate::kProxyDefinePropertyIncompatible, property_name)); 6870 return Nothing<bool>(); 6871 } 6872 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is 6873 // true, throw a TypeError exception. 6874 if (setting_config_false && target_desc.configurable()) { 6875 isolate->Throw(*isolate->factory()->NewTypeError( 6876 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 6877 return Nothing<bool>(); 6878 } 6879 } 6880 // 17. Return true. 6881 return Just(true); 6882 } 6883 6884 6885 // static 6886 Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy, 6887 Handle<Symbol> private_name, 6888 PropertyDescriptor* desc, 6889 ShouldThrow should_throw) { 6890 // Despite the generic name, this can only add private data properties. 6891 if (!PropertyDescriptor::IsDataDescriptor(desc) || 6892 desc->ToAttributes() != DONT_ENUM) { 6893 RETURN_FAILURE(isolate, should_throw, 6894 NewTypeError(MessageTemplate::kProxyPrivate)); 6895 } 6896 DCHECK(proxy->map()->is_dictionary_map()); 6897 Handle<Object> value = 6898 desc->has_value() 6899 ? desc->value() 6900 : Handle<Object>::cast(isolate->factory()->undefined_value()); 6901 6902 LookupIterator it(proxy, private_name, proxy); 6903 6904 if (it.IsFound()) { 6905 DCHECK_EQ(LookupIterator::DATA, it.state()); 6906 DCHECK_EQ(DONT_ENUM, it.property_attributes()); 6907 it.WriteDataValue(value, false); 6908 return Just(true); 6909 } 6910 6911 Handle<NameDictionary> dict(proxy->property_dictionary()); 6912 PropertyDetails details(kData, DONT_ENUM, 0, PropertyCellType::kNoCell); 6913 Handle<NameDictionary> result = 6914 NameDictionary::Add(dict, private_name, value, details); 6915 if (!dict.is_identical_to(result)) proxy->set_properties(*result); 6916 return Just(true); 6917 } 6918 6919 6920 // static 6921 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate, 6922 Handle<JSReceiver> object, 6923 Handle<Object> key, 6924 PropertyDescriptor* desc) { 6925 bool success = false; 6926 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... 6927 LookupIterator it = LookupIterator::PropertyOrElement( 6928 isolate, object, key, &success, LookupIterator::OWN); 6929 DCHECK(success); // ...so creating a LookupIterator can't fail. 6930 return GetOwnPropertyDescriptor(&it, desc); 6931 } 6932 6933 namespace { 6934 6935 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it, 6936 PropertyDescriptor* desc) { 6937 bool has_access = true; 6938 if (it->state() == LookupIterator::ACCESS_CHECK) { 6939 has_access = it->HasAccess() || JSObject::AllCanRead(it); 6940 it->Next(); 6941 } 6942 6943 if (has_access && it->state() == LookupIterator::INTERCEPTOR) { 6944 Isolate* isolate = it->isolate(); 6945 Handle<InterceptorInfo> interceptor = it->GetInterceptor(); 6946 if (!interceptor->descriptor()->IsUndefined(isolate)) { 6947 Handle<Object> result; 6948 Handle<JSObject> holder = it->GetHolder<JSObject>(); 6949 6950 Handle<Object> receiver = it->GetReceiver(); 6951 if (!receiver->IsJSReceiver()) { 6952 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 6953 isolate, receiver, Object::ConvertReceiver(isolate, receiver), 6954 Nothing<bool>()); 6955 } 6956 6957 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 6958 *holder, Object::DONT_THROW); 6959 if (it->IsElement()) { 6960 uint32_t index = it->index(); 6961 v8::IndexedPropertyDescriptorCallback descriptorCallback = 6962 v8::ToCData<v8::IndexedPropertyDescriptorCallback>( 6963 interceptor->descriptor()); 6964 6965 result = args.Call(descriptorCallback, index); 6966 } else { 6967 Handle<Name> name = it->name(); 6968 DCHECK(!name->IsPrivate()); 6969 v8::GenericNamedPropertyDescriptorCallback descriptorCallback = 6970 v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>( 6971 interceptor->descriptor()); 6972 result = args.Call(descriptorCallback, name); 6973 } 6974 if (!result.is_null()) { 6975 // Request successfully intercepted, try to set the property 6976 // descriptor. 6977 Utils::ApiCheck( 6978 PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc), 6979 it->IsElement() ? "v8::IndexedPropertyDescriptorCallback" 6980 : "v8::NamedPropertyDescriptorCallback", 6981 "Invalid property descriptor."); 6982 6983 return Just(true); 6984 } 6985 } 6986 } 6987 it->Restart(); 6988 return Just(false); 6989 } 6990 } // namespace 6991 6992 // ES6 9.1.5.1 6993 // Returns true on success, false if the property didn't exist, nothing if 6994 // an exception was thrown. 6995 // static 6996 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it, 6997 PropertyDescriptor* desc) { 6998 Isolate* isolate = it->isolate(); 6999 // "Virtual" dispatch. 7000 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) { 7001 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(), 7002 it->GetName(), desc); 7003 } 7004 7005 Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc); 7006 MAYBE_RETURN(intercepted, Nothing<bool>()); 7007 if (intercepted.FromJust()) { 7008 return Just(true); 7009 } 7010 7011 // Request was not intercepted, continue as normal. 7012 // 1. (Assert) 7013 // 2. If O does not have an own property with key P, return undefined. 7014 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it); 7015 MAYBE_RETURN(maybe, Nothing<bool>()); 7016 PropertyAttributes attrs = maybe.FromJust(); 7017 if (attrs == ABSENT) return Just(false); 7018 DCHECK(!isolate->has_pending_exception()); 7019 7020 // 3. Let D be a newly created Property Descriptor with no fields. 7021 DCHECK(desc->is_empty()); 7022 // 4. Let X be O's own property whose key is P. 7023 // 5. If X is a data property, then 7024 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR && 7025 it->GetAccessors()->IsAccessorPair(); 7026 if (!is_accessor_pair) { 7027 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute. 7028 Handle<Object> value; 7029 if (!Object::GetProperty(it).ToHandle(&value)) { 7030 DCHECK(isolate->has_pending_exception()); 7031 return Nothing<bool>(); 7032 } 7033 desc->set_value(value); 7034 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute 7035 desc->set_writable((attrs & READ_ONLY) == 0); 7036 } else { 7037 // 6. Else X is an accessor property, so 7038 Handle<AccessorPair> accessors = 7039 Handle<AccessorPair>::cast(it->GetAccessors()); 7040 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute. 7041 desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER)); 7042 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute. 7043 desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER)); 7044 } 7045 7046 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute. 7047 desc->set_enumerable((attrs & DONT_ENUM) == 0); 7048 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute. 7049 desc->set_configurable((attrs & DONT_DELETE) == 0); 7050 // 9. Return D. 7051 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) != 7052 PropertyDescriptor::IsDataDescriptor(desc)); 7053 return Just(true); 7054 } 7055 7056 7057 // ES6 9.5.5 7058 // static 7059 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate, 7060 Handle<JSProxy> proxy, 7061 Handle<Name> name, 7062 PropertyDescriptor* desc) { 7063 DCHECK(!name->IsPrivate()); 7064 STACK_CHECK(isolate, Nothing<bool>()); 7065 7066 Handle<String> trap_name = 7067 isolate->factory()->getOwnPropertyDescriptor_string(); 7068 // 1. (Assert) 7069 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 7070 Handle<Object> handler(proxy->handler(), isolate); 7071 // 3. If handler is null, throw a TypeError exception. 7072 // 4. Assert: Type(handler) is Object. 7073 if (proxy->IsRevoked()) { 7074 isolate->Throw(*isolate->factory()->NewTypeError( 7075 MessageTemplate::kProxyRevoked, trap_name)); 7076 return Nothing<bool>(); 7077 } 7078 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 7079 Handle<JSReceiver> target(proxy->target(), isolate); 7080 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor"). 7081 Handle<Object> trap; 7082 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7083 isolate, trap, 7084 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 7085 Nothing<bool>()); 7086 // 7. If trap is undefined, then 7087 if (trap->IsUndefined(isolate)) { 7088 // 7a. Return target.[[GetOwnProperty]](P). 7089 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc); 7090 } 7091 // 8. Let trapResultObj be ? Call(trap, handler, target, P). 7092 Handle<Object> trap_result_obj; 7093 Handle<Object> args[] = {target, name}; 7094 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7095 isolate, trap_result_obj, 7096 Execution::Call(isolate, trap, handler, arraysize(args), args), 7097 Nothing<bool>()); 7098 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a 7099 // TypeError exception. 7100 if (!trap_result_obj->IsJSReceiver() && 7101 !trap_result_obj->IsUndefined(isolate)) { 7102 isolate->Throw(*isolate->factory()->NewTypeError( 7103 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name)); 7104 return Nothing<bool>(); 7105 } 7106 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). 7107 PropertyDescriptor target_desc; 7108 Maybe<bool> found = 7109 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 7110 MAYBE_RETURN(found, Nothing<bool>()); 7111 // 11. If trapResultObj is undefined, then 7112 if (trap_result_obj->IsUndefined(isolate)) { 7113 // 11a. If targetDesc is undefined, return undefined. 7114 if (!found.FromJust()) return Just(false); 7115 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError 7116 // exception. 7117 if (!target_desc.configurable()) { 7118 isolate->Throw(*isolate->factory()->NewTypeError( 7119 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name)); 7120 return Nothing<bool>(); 7121 } 7122 // 11c. Let extensibleTarget be ? IsExtensible(target). 7123 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 7124 MAYBE_RETURN(extensible_target, Nothing<bool>()); 7125 // 11d. (Assert) 7126 // 11e. If extensibleTarget is false, throw a TypeError exception. 7127 if (!extensible_target.FromJust()) { 7128 isolate->Throw(*isolate->factory()->NewTypeError( 7129 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name)); 7130 return Nothing<bool>(); 7131 } 7132 // 11f. Return undefined. 7133 return Just(false); 7134 } 7135 // 12. Let extensibleTarget be ? IsExtensible(target). 7136 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 7137 MAYBE_RETURN(extensible_target, Nothing<bool>()); 7138 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj). 7139 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj, 7140 desc)) { 7141 DCHECK(isolate->has_pending_exception()); 7142 return Nothing<bool>(); 7143 } 7144 // 14. Call CompletePropertyDescriptor(resultDesc). 7145 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc); 7146 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget, 7147 // resultDesc, targetDesc). 7148 Maybe<bool> valid = 7149 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(), 7150 desc, &target_desc, name, DONT_THROW); 7151 MAYBE_RETURN(valid, Nothing<bool>()); 7152 // 16. If valid is false, throw a TypeError exception. 7153 if (!valid.FromJust()) { 7154 isolate->Throw(*isolate->factory()->NewTypeError( 7155 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name)); 7156 return Nothing<bool>(); 7157 } 7158 // 17. If resultDesc.[[Configurable]] is false, then 7159 if (!desc->configurable()) { 7160 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true: 7161 if (target_desc.is_empty() || target_desc.configurable()) { 7162 // 17a i. Throw a TypeError exception. 7163 isolate->Throw(*isolate->factory()->NewTypeError( 7164 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable, 7165 name)); 7166 return Nothing<bool>(); 7167 } 7168 } 7169 // 18. Return resultDesc. 7170 return Just(true); 7171 } 7172 7173 7174 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, 7175 ElementsKind kind, 7176 Object* object) { 7177 Isolate* isolate = elements->GetIsolate(); 7178 if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) { 7179 int length = IsJSArray() 7180 ? Smi::cast(JSArray::cast(this)->length())->value() 7181 : elements->length(); 7182 for (int i = 0; i < length; ++i) { 7183 Object* element = elements->get(i); 7184 if (!element->IsTheHole(isolate) && element == object) return true; 7185 } 7186 } else { 7187 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS); 7188 Object* key = 7189 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object); 7190 if (!key->IsUndefined(isolate)) return true; 7191 } 7192 return false; 7193 } 7194 7195 7196 // Check whether this object references another object. 7197 bool JSObject::ReferencesObject(Object* obj) { 7198 Map* map_of_this = map(); 7199 Heap* heap = GetHeap(); 7200 DisallowHeapAllocation no_allocation; 7201 7202 // Is the object the constructor for this object? 7203 if (map_of_this->GetConstructor() == obj) { 7204 return true; 7205 } 7206 7207 // Is the object the prototype for this object? 7208 if (map_of_this->prototype() == obj) { 7209 return true; 7210 } 7211 7212 // Check if the object is among the named properties. 7213 Object* key = SlowReverseLookup(obj); 7214 if (!key->IsUndefined(heap->isolate())) { 7215 return true; 7216 } 7217 7218 // Check if the object is among the indexed properties. 7219 ElementsKind kind = GetElementsKind(); 7220 switch (kind) { 7221 // Raw pixels and external arrays do not reference other 7222 // objects. 7223 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 7224 case TYPE##_ELEMENTS: \ 7225 break; 7226 7227 TYPED_ARRAYS(TYPED_ARRAY_CASE) 7228 #undef TYPED_ARRAY_CASE 7229 7230 case FAST_DOUBLE_ELEMENTS: 7231 case FAST_HOLEY_DOUBLE_ELEMENTS: 7232 break; 7233 case FAST_SMI_ELEMENTS: 7234 case FAST_HOLEY_SMI_ELEMENTS: 7235 break; 7236 case FAST_ELEMENTS: 7237 case FAST_HOLEY_ELEMENTS: 7238 case DICTIONARY_ELEMENTS: 7239 case FAST_STRING_WRAPPER_ELEMENTS: 7240 case SLOW_STRING_WRAPPER_ELEMENTS: { 7241 FixedArray* elements = FixedArray::cast(this->elements()); 7242 if (ReferencesObjectFromElements(elements, kind, obj)) return true; 7243 break; 7244 } 7245 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 7246 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 7247 FixedArray* parameter_map = FixedArray::cast(elements()); 7248 // Check the mapped parameters. 7249 int length = parameter_map->length(); 7250 for (int i = 2; i < length; ++i) { 7251 Object* value = parameter_map->get(i); 7252 if (!value->IsTheHole(heap->isolate()) && value == obj) return true; 7253 } 7254 // Check the arguments. 7255 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); 7256 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : 7257 FAST_HOLEY_ELEMENTS; 7258 if (ReferencesObjectFromElements(arguments, kind, obj)) return true; 7259 break; 7260 } 7261 case NO_ELEMENTS: 7262 break; 7263 } 7264 7265 // For functions check the context. 7266 if (IsJSFunction()) { 7267 // Get the constructor function for arguments array. 7268 Map* arguments_map = 7269 heap->isolate()->context()->native_context()->sloppy_arguments_map(); 7270 JSFunction* arguments_function = 7271 JSFunction::cast(arguments_map->GetConstructor()); 7272 7273 // Get the context and don't check if it is the native context. 7274 JSFunction* f = JSFunction::cast(this); 7275 Context* context = f->context(); 7276 if (context->IsNativeContext()) { 7277 return false; 7278 } 7279 7280 // Check the non-special context slots. 7281 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) { 7282 // Only check JS objects. 7283 if (context->get(i)->IsJSObject()) { 7284 JSObject* ctxobj = JSObject::cast(context->get(i)); 7285 // If it is an arguments array check the content. 7286 if (ctxobj->map()->GetConstructor() == arguments_function) { 7287 if (ctxobj->ReferencesObject(obj)) { 7288 return true; 7289 } 7290 } else if (ctxobj == obj) { 7291 return true; 7292 } 7293 } 7294 } 7295 7296 // Check the context extension (if any) if it can have references. 7297 if (context->has_extension() && !context->IsCatchContext()) { 7298 // With harmony scoping, a JSFunction may have a script context. 7299 // TODO(mvstanton): walk into the ScopeInfo. 7300 if (context->IsScriptContext()) { 7301 return false; 7302 } 7303 7304 return context->extension_object()->ReferencesObject(obj); 7305 } 7306 } 7307 7308 // No references to object. 7309 return false; 7310 } 7311 7312 7313 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver, 7314 IntegrityLevel level, 7315 ShouldThrow should_throw) { 7316 DCHECK(level == SEALED || level == FROZEN); 7317 7318 if (receiver->IsJSObject()) { 7319 Handle<JSObject> object = Handle<JSObject>::cast(receiver); 7320 if (!object->HasSloppyArgumentsElements()) { // Fast path. 7321 if (level == SEALED) { 7322 return JSObject::PreventExtensionsWithTransition<SEALED>(object, 7323 should_throw); 7324 } else { 7325 return JSObject::PreventExtensionsWithTransition<FROZEN>(object, 7326 should_throw); 7327 } 7328 } 7329 } 7330 7331 Isolate* isolate = receiver->GetIsolate(); 7332 7333 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw), 7334 Nothing<bool>()); 7335 7336 Handle<FixedArray> keys; 7337 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7338 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>()); 7339 7340 PropertyDescriptor no_conf; 7341 no_conf.set_configurable(false); 7342 7343 PropertyDescriptor no_conf_no_write; 7344 no_conf_no_write.set_configurable(false); 7345 no_conf_no_write.set_writable(false); 7346 7347 if (level == SEALED) { 7348 for (int i = 0; i < keys->length(); ++i) { 7349 Handle<Object> key(keys->get(i), isolate); 7350 MAYBE_RETURN( 7351 DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR), 7352 Nothing<bool>()); 7353 } 7354 return Just(true); 7355 } 7356 7357 for (int i = 0; i < keys->length(); ++i) { 7358 Handle<Object> key(keys->get(i), isolate); 7359 PropertyDescriptor current_desc; 7360 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( 7361 isolate, receiver, key, ¤t_desc); 7362 MAYBE_RETURN(owned, Nothing<bool>()); 7363 if (owned.FromJust()) { 7364 PropertyDescriptor desc = 7365 PropertyDescriptor::IsAccessorDescriptor(¤t_desc) 7366 ? no_conf 7367 : no_conf_no_write; 7368 MAYBE_RETURN( 7369 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR), 7370 Nothing<bool>()); 7371 } 7372 } 7373 return Just(true); 7374 } 7375 7376 7377 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object, 7378 IntegrityLevel level) { 7379 DCHECK(level == SEALED || level == FROZEN); 7380 Isolate* isolate = object->GetIsolate(); 7381 7382 Maybe<bool> extensible = JSReceiver::IsExtensible(object); 7383 MAYBE_RETURN(extensible, Nothing<bool>()); 7384 if (extensible.FromJust()) return Just(false); 7385 7386 Handle<FixedArray> keys; 7387 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7388 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>()); 7389 7390 for (int i = 0; i < keys->length(); ++i) { 7391 Handle<Object> key(keys->get(i), isolate); 7392 PropertyDescriptor current_desc; 7393 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( 7394 isolate, object, key, ¤t_desc); 7395 MAYBE_RETURN(owned, Nothing<bool>()); 7396 if (owned.FromJust()) { 7397 if (current_desc.configurable()) return Just(false); 7398 if (level == FROZEN && 7399 PropertyDescriptor::IsDataDescriptor(¤t_desc) && 7400 current_desc.writable()) { 7401 return Just(false); 7402 } 7403 } 7404 } 7405 return Just(true); 7406 } 7407 7408 7409 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, 7410 ShouldThrow should_throw) { 7411 if (object->IsJSProxy()) { 7412 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object), 7413 should_throw); 7414 } 7415 DCHECK(object->IsJSObject()); 7416 return JSObject::PreventExtensions(Handle<JSObject>::cast(object), 7417 should_throw); 7418 } 7419 7420 7421 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy, 7422 ShouldThrow should_throw) { 7423 Isolate* isolate = proxy->GetIsolate(); 7424 STACK_CHECK(isolate, Nothing<bool>()); 7425 Factory* factory = isolate->factory(); 7426 Handle<String> trap_name = factory->preventExtensions_string(); 7427 7428 if (proxy->IsRevoked()) { 7429 isolate->Throw( 7430 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 7431 return Nothing<bool>(); 7432 } 7433 Handle<JSReceiver> target(proxy->target(), isolate); 7434 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 7435 7436 Handle<Object> trap; 7437 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7438 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 7439 if (trap->IsUndefined(isolate)) { 7440 return JSReceiver::PreventExtensions(target, should_throw); 7441 } 7442 7443 Handle<Object> trap_result; 7444 Handle<Object> args[] = {target}; 7445 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7446 isolate, trap_result, 7447 Execution::Call(isolate, trap, handler, arraysize(args), args), 7448 Nothing<bool>()); 7449 if (!trap_result->BooleanValue()) { 7450 RETURN_FAILURE( 7451 isolate, should_throw, 7452 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 7453 } 7454 7455 // Enforce the invariant. 7456 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 7457 MAYBE_RETURN(target_result, Nothing<bool>()); 7458 if (target_result.FromJust()) { 7459 isolate->Throw(*factory->NewTypeError( 7460 MessageTemplate::kProxyPreventExtensionsExtensible)); 7461 return Nothing<bool>(); 7462 } 7463 return Just(true); 7464 } 7465 7466 7467 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, 7468 ShouldThrow should_throw) { 7469 Isolate* isolate = object->GetIsolate(); 7470 7471 if (!object->HasSloppyArgumentsElements()) { 7472 return PreventExtensionsWithTransition<NONE>(object, should_throw); 7473 } 7474 7475 if (object->IsAccessCheckNeeded() && 7476 !isolate->MayAccess(handle(isolate->context()), object)) { 7477 isolate->ReportFailedAccessCheck(object); 7478 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 7479 RETURN_FAILURE(isolate, should_throw, 7480 NewTypeError(MessageTemplate::kNoAccess)); 7481 } 7482 7483 if (!object->map()->is_extensible()) return Just(true); 7484 7485 if (object->IsJSGlobalProxy()) { 7486 PrototypeIterator iter(isolate, object); 7487 if (iter.IsAtEnd()) return Just(true); 7488 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); 7489 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter), 7490 should_throw); 7491 } 7492 7493 if (!object->HasFixedTypedArrayElements()) { 7494 // If there are fast elements we normalize. 7495 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); 7496 DCHECK(object->HasDictionaryElements() || 7497 object->HasSlowArgumentsElements()); 7498 7499 // Make sure that we never go back to fast case. 7500 object->RequireSlowElements(*dictionary); 7501 } 7502 7503 // Do a map transition, other objects with this map may still 7504 // be extensible. 7505 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. 7506 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions"); 7507 7508 new_map->set_is_extensible(false); 7509 JSObject::MigrateToMap(object, new_map); 7510 DCHECK(!object->map()->is_extensible()); 7511 7512 return Just(true); 7513 } 7514 7515 7516 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) { 7517 if (object->IsJSProxy()) { 7518 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object)); 7519 } 7520 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object))); 7521 } 7522 7523 7524 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) { 7525 Isolate* isolate = proxy->GetIsolate(); 7526 STACK_CHECK(isolate, Nothing<bool>()); 7527 Factory* factory = isolate->factory(); 7528 Handle<String> trap_name = factory->isExtensible_string(); 7529 7530 if (proxy->IsRevoked()) { 7531 isolate->Throw( 7532 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 7533 return Nothing<bool>(); 7534 } 7535 Handle<JSReceiver> target(proxy->target(), isolate); 7536 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 7537 7538 Handle<Object> trap; 7539 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7540 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 7541 if (trap->IsUndefined(isolate)) { 7542 return JSReceiver::IsExtensible(target); 7543 } 7544 7545 Handle<Object> trap_result; 7546 Handle<Object> args[] = {target}; 7547 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7548 isolate, trap_result, 7549 Execution::Call(isolate, trap, handler, arraysize(args), args), 7550 Nothing<bool>()); 7551 7552 // Enforce the invariant. 7553 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 7554 MAYBE_RETURN(target_result, Nothing<bool>()); 7555 if (target_result.FromJust() != trap_result->BooleanValue()) { 7556 isolate->Throw( 7557 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent, 7558 factory->ToBoolean(target_result.FromJust()))); 7559 return Nothing<bool>(); 7560 } 7561 return target_result; 7562 } 7563 7564 7565 bool JSObject::IsExtensible(Handle<JSObject> object) { 7566 Isolate* isolate = object->GetIsolate(); 7567 if (object->IsAccessCheckNeeded() && 7568 !isolate->MayAccess(handle(isolate->context()), object)) { 7569 return true; 7570 } 7571 if (object->IsJSGlobalProxy()) { 7572 PrototypeIterator iter(isolate, *object); 7573 if (iter.IsAtEnd()) return false; 7574 DCHECK(iter.GetCurrent()->IsJSGlobalObject()); 7575 return iter.GetCurrent<JSObject>()->map()->is_extensible(); 7576 } 7577 return object->map()->is_extensible(); 7578 } 7579 7580 namespace { 7581 7582 template <typename Dictionary> 7583 void DictionaryDetailsAtPut(Isolate* isolate, Handle<Dictionary> dictionary, 7584 int entry, PropertyDetails details) { 7585 dictionary->DetailsAtPut(entry, details); 7586 } 7587 7588 template <> 7589 void DictionaryDetailsAtPut<GlobalDictionary>( 7590 Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry, 7591 PropertyDetails details) { 7592 Object* value = dictionary->ValueAt(entry); 7593 DCHECK(value->IsPropertyCell()); 7594 value = PropertyCell::cast(value)->value(); 7595 if (value->IsTheHole(isolate)) return; 7596 PropertyCell::PrepareForValue(dictionary, entry, handle(value, isolate), 7597 details); 7598 } 7599 7600 template <typename Dictionary> 7601 void ApplyAttributesToDictionary(Isolate* isolate, 7602 Handle<Dictionary> dictionary, 7603 const PropertyAttributes attributes) { 7604 int capacity = dictionary->Capacity(); 7605 for (int i = 0; i < capacity; i++) { 7606 Object* k = dictionary->KeyAt(i); 7607 if (dictionary->IsKey(isolate, k) && 7608 !(k->IsSymbol() && Symbol::cast(k)->is_private())) { 7609 PropertyDetails details = dictionary->DetailsAt(i); 7610 int attrs = attributes; 7611 // READ_ONLY is an invalid attribute for JS setters/getters. 7612 if ((attributes & READ_ONLY) && details.kind() == kAccessor) { 7613 Object* v = dictionary->ValueAt(i); 7614 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value(); 7615 if (v->IsAccessorPair()) attrs &= ~READ_ONLY; 7616 } 7617 details = details.CopyAddAttributes( 7618 static_cast<PropertyAttributes>(attrs)); 7619 DictionaryDetailsAtPut<Dictionary>(isolate, dictionary, i, details); 7620 } 7621 } 7622 } 7623 7624 } // namespace 7625 7626 template <PropertyAttributes attrs> 7627 Maybe<bool> JSObject::PreventExtensionsWithTransition( 7628 Handle<JSObject> object, ShouldThrow should_throw) { 7629 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN); 7630 7631 // Sealing/freezing sloppy arguments should be handled elsewhere. 7632 DCHECK(!object->HasSloppyArgumentsElements()); 7633 7634 Isolate* isolate = object->GetIsolate(); 7635 if (object->IsAccessCheckNeeded() && 7636 !isolate->MayAccess(handle(isolate->context()), object)) { 7637 isolate->ReportFailedAccessCheck(object); 7638 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 7639 RETURN_FAILURE(isolate, should_throw, 7640 NewTypeError(MessageTemplate::kNoAccess)); 7641 } 7642 7643 if (attrs == NONE && !object->map()->is_extensible()) return Just(true); 7644 7645 if (object->IsJSGlobalProxy()) { 7646 PrototypeIterator iter(isolate, object); 7647 if (iter.IsAtEnd()) return Just(true); 7648 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); 7649 return PreventExtensionsWithTransition<attrs>( 7650 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw); 7651 } 7652 7653 Handle<SeededNumberDictionary> new_element_dictionary; 7654 if (!object->HasFixedTypedArrayElements() && 7655 !object->HasDictionaryElements() && 7656 !object->HasSlowStringWrapperElements()) { 7657 int length = 7658 object->IsJSArray() 7659 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() 7660 : object->elements()->length(); 7661 new_element_dictionary = 7662 length == 0 ? isolate->factory()->empty_slow_element_dictionary() 7663 : object->GetElementsAccessor()->Normalize(object); 7664 } 7665 7666 Handle<Symbol> transition_marker; 7667 if (attrs == NONE) { 7668 transition_marker = isolate->factory()->nonextensible_symbol(); 7669 } else if (attrs == SEALED) { 7670 transition_marker = isolate->factory()->sealed_symbol(); 7671 } else { 7672 DCHECK(attrs == FROZEN); 7673 transition_marker = isolate->factory()->frozen_symbol(); 7674 } 7675 7676 Handle<Map> old_map(object->map(), isolate); 7677 Map* transition = 7678 TransitionArray::SearchSpecial(*old_map, *transition_marker); 7679 if (transition != NULL) { 7680 Handle<Map> transition_map(transition, isolate); 7681 DCHECK(transition_map->has_dictionary_elements() || 7682 transition_map->has_fixed_typed_array_elements() || 7683 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS); 7684 DCHECK(!transition_map->is_extensible()); 7685 JSObject::MigrateToMap(object, transition_map); 7686 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) { 7687 // Create a new descriptor array with the appropriate property attributes 7688 Handle<Map> new_map = Map::CopyForPreventExtensions( 7689 old_map, attrs, transition_marker, "CopyForPreventExtensions"); 7690 JSObject::MigrateToMap(object, new_map); 7691 } else { 7692 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map()); 7693 // Slow path: need to normalize properties for safety 7694 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, 7695 "SlowPreventExtensions"); 7696 7697 // Create a new map, since other objects with this map may be extensible. 7698 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. 7699 Handle<Map> new_map = 7700 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions"); 7701 new_map->set_is_extensible(false); 7702 if (!new_element_dictionary.is_null()) { 7703 ElementsKind new_kind = 7704 IsStringWrapperElementsKind(old_map->elements_kind()) 7705 ? SLOW_STRING_WRAPPER_ELEMENTS 7706 : DICTIONARY_ELEMENTS; 7707 new_map->set_elements_kind(new_kind); 7708 } 7709 JSObject::MigrateToMap(object, new_map); 7710 7711 if (attrs != NONE) { 7712 if (object->IsJSGlobalObject()) { 7713 Handle<GlobalDictionary> dictionary(object->global_dictionary(), 7714 isolate); 7715 ApplyAttributesToDictionary(isolate, dictionary, attrs); 7716 } else { 7717 Handle<NameDictionary> dictionary(object->property_dictionary(), 7718 isolate); 7719 ApplyAttributesToDictionary(isolate, dictionary, attrs); 7720 } 7721 } 7722 } 7723 7724 // Both seal and preventExtensions always go through without modifications to 7725 // typed array elements. Freeze works only if there are no actual elements. 7726 if (object->HasFixedTypedArrayElements()) { 7727 if (attrs == FROZEN && 7728 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) { 7729 isolate->Throw(*isolate->factory()->NewTypeError( 7730 MessageTemplate::kCannotFreezeArrayBufferView)); 7731 return Nothing<bool>(); 7732 } 7733 return Just(true); 7734 } 7735 7736 DCHECK(object->map()->has_dictionary_elements() || 7737 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS); 7738 if (!new_element_dictionary.is_null()) { 7739 object->set_elements(*new_element_dictionary); 7740 } 7741 7742 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) { 7743 Handle<SeededNumberDictionary> dictionary(object->element_dictionary(), 7744 isolate); 7745 // Make sure we never go back to the fast case 7746 object->RequireSlowElements(*dictionary); 7747 if (attrs != NONE) { 7748 ApplyAttributesToDictionary(isolate, dictionary, attrs); 7749 } 7750 } 7751 7752 return Just(true); 7753 } 7754 7755 7756 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object, 7757 Representation representation, 7758 FieldIndex index) { 7759 Isolate* isolate = object->GetIsolate(); 7760 if (object->IsUnboxedDoubleField(index)) { 7761 double value = object->RawFastDoublePropertyAt(index); 7762 return isolate->factory()->NewHeapNumber(value); 7763 } 7764 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate); 7765 return Object::WrapForRead(isolate, raw_value, representation); 7766 } 7767 7768 template <class ContextObject> 7769 class JSObjectWalkVisitor { 7770 public: 7771 JSObjectWalkVisitor(ContextObject* site_context, bool copying, 7772 JSObject::DeepCopyHints hints) 7773 : site_context_(site_context), 7774 copying_(copying), 7775 hints_(hints) {} 7776 7777 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object); 7778 7779 protected: 7780 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty( 7781 Handle<JSObject> object, 7782 Handle<JSObject> value) { 7783 Handle<AllocationSite> current_site = site_context()->EnterNewScope(); 7784 MaybeHandle<JSObject> copy_of_value = StructureWalk(value); 7785 site_context()->ExitScope(current_site, value); 7786 return copy_of_value; 7787 } 7788 7789 inline ContextObject* site_context() { return site_context_; } 7790 inline Isolate* isolate() { return site_context()->isolate(); } 7791 7792 inline bool copying() const { return copying_; } 7793 7794 private: 7795 ContextObject* site_context_; 7796 const bool copying_; 7797 const JSObject::DeepCopyHints hints_; 7798 }; 7799 7800 template <class ContextObject> 7801 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk( 7802 Handle<JSObject> object) { 7803 Isolate* isolate = this->isolate(); 7804 bool copying = this->copying(); 7805 bool shallow = hints_ == JSObject::kObjectIsShallow; 7806 7807 if (!shallow) { 7808 StackLimitCheck check(isolate); 7809 7810 if (check.HasOverflowed()) { 7811 isolate->StackOverflow(); 7812 return MaybeHandle<JSObject>(); 7813 } 7814 } 7815 7816 if (object->map()->is_deprecated()) { 7817 JSObject::MigrateInstance(object); 7818 } 7819 7820 Handle<JSObject> copy; 7821 if (copying) { 7822 // JSFunction objects are not allowed to be in normal boilerplates at all. 7823 DCHECK(!object->IsJSFunction()); 7824 Handle<AllocationSite> site_to_pass; 7825 if (site_context()->ShouldCreateMemento(object)) { 7826 site_to_pass = site_context()->current(); 7827 } 7828 copy = isolate->factory()->CopyJSObjectWithAllocationSite( 7829 object, site_to_pass); 7830 } else { 7831 copy = object; 7832 } 7833 7834 DCHECK(copying || copy.is_identical_to(object)); 7835 7836 ElementsKind kind = copy->GetElementsKind(); 7837 if (copying && IsFastSmiOrObjectElementsKind(kind) && 7838 FixedArray::cast(copy->elements())->map() == 7839 isolate->heap()->fixed_cow_array_map()) { 7840 isolate->counters()->cow_arrays_created_runtime()->Increment(); 7841 } 7842 7843 if (!shallow) { 7844 HandleScope scope(isolate); 7845 7846 // Deep copy own properties. 7847 if (copy->HasFastProperties()) { 7848 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors()); 7849 int limit = copy->map()->NumberOfOwnDescriptors(); 7850 for (int i = 0; i < limit; i++) { 7851 PropertyDetails details = descriptors->GetDetails(i); 7852 if (details.location() != kField) continue; 7853 DCHECK_EQ(kData, details.kind()); 7854 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i); 7855 if (object->IsUnboxedDoubleField(index)) { 7856 if (copying) { 7857 // Ensure that all bits of the double value are preserved. 7858 uint64_t value = object->RawFastDoublePropertyAsBitsAt(index); 7859 copy->RawFastDoublePropertyAsBitsAtPut(index, value); 7860 } 7861 } else { 7862 Handle<Object> value(object->RawFastPropertyAt(index), isolate); 7863 if (value->IsJSObject()) { 7864 ASSIGN_RETURN_ON_EXCEPTION( 7865 isolate, value, 7866 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 7867 JSObject); 7868 if (copying) { 7869 copy->FastPropertyAtPut(index, *value); 7870 } 7871 } else { 7872 if (copying) { 7873 Representation representation = details.representation(); 7874 value = Object::NewStorageFor(isolate, value, representation); 7875 copy->FastPropertyAtPut(index, *value); 7876 } 7877 } 7878 } 7879 } 7880 } else { 7881 // Only deep copy fields from the object literal expression. 7882 // In particular, don't try to copy the length attribute of 7883 // an array. 7884 PropertyFilter filter = static_cast<PropertyFilter>( 7885 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE); 7886 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter); 7887 accumulator.CollectOwnPropertyNames(copy, copy); 7888 Handle<FixedArray> names = accumulator.GetKeys(); 7889 for (int i = 0; i < names->length(); i++) { 7890 DCHECK(names->get(i)->IsName()); 7891 Handle<Name> name(Name::cast(names->get(i))); 7892 Handle<Object> value = 7893 JSObject::GetProperty(copy, name).ToHandleChecked(); 7894 if (value->IsJSObject()) { 7895 Handle<JSObject> result; 7896 ASSIGN_RETURN_ON_EXCEPTION( 7897 isolate, result, 7898 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 7899 JSObject); 7900 if (copying) { 7901 // Creating object copy for literals. No strict mode needed. 7902 JSObject::SetProperty(copy, name, result, SLOPPY).Assert(); 7903 } 7904 } 7905 } 7906 } 7907 7908 // Deep copy own elements. 7909 switch (kind) { 7910 case FAST_ELEMENTS: 7911 case FAST_HOLEY_ELEMENTS: { 7912 Handle<FixedArray> elements(FixedArray::cast(copy->elements())); 7913 if (elements->map() == isolate->heap()->fixed_cow_array_map()) { 7914 #ifdef DEBUG 7915 for (int i = 0; i < elements->length(); i++) { 7916 DCHECK(!elements->get(i)->IsJSObject()); 7917 } 7918 #endif 7919 } else { 7920 for (int i = 0; i < elements->length(); i++) { 7921 Handle<Object> value(elements->get(i), isolate); 7922 if (value->IsJSObject()) { 7923 Handle<JSObject> result; 7924 ASSIGN_RETURN_ON_EXCEPTION( 7925 isolate, result, 7926 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 7927 JSObject); 7928 if (copying) { 7929 elements->set(i, *result); 7930 } 7931 } 7932 } 7933 } 7934 break; 7935 } 7936 case DICTIONARY_ELEMENTS: { 7937 Handle<SeededNumberDictionary> element_dictionary( 7938 copy->element_dictionary()); 7939 int capacity = element_dictionary->Capacity(); 7940 for (int i = 0; i < capacity; i++) { 7941 Object* k = element_dictionary->KeyAt(i); 7942 if (element_dictionary->IsKey(isolate, k)) { 7943 Handle<Object> value(element_dictionary->ValueAt(i), isolate); 7944 if (value->IsJSObject()) { 7945 Handle<JSObject> result; 7946 ASSIGN_RETURN_ON_EXCEPTION( 7947 isolate, result, 7948 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 7949 JSObject); 7950 if (copying) { 7951 element_dictionary->ValueAtPut(i, *result); 7952 } 7953 } 7954 } 7955 } 7956 break; 7957 } 7958 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 7959 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 7960 UNIMPLEMENTED(); 7961 break; 7962 case FAST_STRING_WRAPPER_ELEMENTS: 7963 case SLOW_STRING_WRAPPER_ELEMENTS: 7964 UNREACHABLE(); 7965 break; 7966 7967 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 7968 case TYPE##_ELEMENTS: \ 7969 7970 TYPED_ARRAYS(TYPED_ARRAY_CASE) 7971 #undef TYPED_ARRAY_CASE 7972 // Typed elements cannot be created using an object literal. 7973 UNREACHABLE(); 7974 break; 7975 7976 case FAST_SMI_ELEMENTS: 7977 case FAST_HOLEY_SMI_ELEMENTS: 7978 case FAST_DOUBLE_ELEMENTS: 7979 case FAST_HOLEY_DOUBLE_ELEMENTS: 7980 case NO_ELEMENTS: 7981 // No contained objects, nothing to do. 7982 break; 7983 } 7984 } 7985 7986 return copy; 7987 } 7988 7989 7990 MaybeHandle<JSObject> JSObject::DeepWalk( 7991 Handle<JSObject> object, 7992 AllocationSiteCreationContext* site_context) { 7993 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false, 7994 kNoHints); 7995 MaybeHandle<JSObject> result = v.StructureWalk(object); 7996 Handle<JSObject> for_assert; 7997 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object)); 7998 return result; 7999 } 8000 8001 8002 MaybeHandle<JSObject> JSObject::DeepCopy( 8003 Handle<JSObject> object, 8004 AllocationSiteUsageContext* site_context, 8005 DeepCopyHints hints) { 8006 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints); 8007 MaybeHandle<JSObject> copy = v.StructureWalk(object); 8008 Handle<JSObject> for_assert; 8009 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object)); 8010 return copy; 8011 } 8012 8013 // static 8014 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver, 8015 ToPrimitiveHint hint) { 8016 Isolate* const isolate = receiver->GetIsolate(); 8017 Handle<Object> exotic_to_prim; 8018 ASSIGN_RETURN_ON_EXCEPTION( 8019 isolate, exotic_to_prim, 8020 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object); 8021 if (!exotic_to_prim->IsUndefined(isolate)) { 8022 Handle<Object> hint_string = 8023 isolate->factory()->ToPrimitiveHintString(hint); 8024 Handle<Object> result; 8025 ASSIGN_RETURN_ON_EXCEPTION( 8026 isolate, result, 8027 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string), 8028 Object); 8029 if (result->IsPrimitive()) return result; 8030 THROW_NEW_ERROR(isolate, 8031 NewTypeError(MessageTemplate::kCannotConvertToPrimitive), 8032 Object); 8033 } 8034 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString) 8035 ? OrdinaryToPrimitiveHint::kString 8036 : OrdinaryToPrimitiveHint::kNumber); 8037 } 8038 8039 8040 // static 8041 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive( 8042 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) { 8043 Isolate* const isolate = receiver->GetIsolate(); 8044 Handle<String> method_names[2]; 8045 switch (hint) { 8046 case OrdinaryToPrimitiveHint::kNumber: 8047 method_names[0] = isolate->factory()->valueOf_string(); 8048 method_names[1] = isolate->factory()->toString_string(); 8049 break; 8050 case OrdinaryToPrimitiveHint::kString: 8051 method_names[0] = isolate->factory()->toString_string(); 8052 method_names[1] = isolate->factory()->valueOf_string(); 8053 break; 8054 } 8055 for (Handle<String> name : method_names) { 8056 Handle<Object> method; 8057 ASSIGN_RETURN_ON_EXCEPTION(isolate, method, 8058 JSReceiver::GetProperty(receiver, name), Object); 8059 if (method->IsCallable()) { 8060 Handle<Object> result; 8061 ASSIGN_RETURN_ON_EXCEPTION( 8062 isolate, result, Execution::Call(isolate, method, receiver, 0, NULL), 8063 Object); 8064 if (result->IsPrimitive()) return result; 8065 } 8066 } 8067 THROW_NEW_ERROR(isolate, 8068 NewTypeError(MessageTemplate::kCannotConvertToPrimitive), 8069 Object); 8070 } 8071 8072 8073 // TODO(cbruni/jkummerow): Consider moving this into elements.cc. 8074 bool JSObject::HasEnumerableElements() { 8075 // TODO(cbruni): cleanup 8076 JSObject* object = this; 8077 switch (object->GetElementsKind()) { 8078 case FAST_SMI_ELEMENTS: 8079 case FAST_ELEMENTS: 8080 case FAST_DOUBLE_ELEMENTS: { 8081 int length = object->IsJSArray() 8082 ? Smi::cast(JSArray::cast(object)->length())->value() 8083 : object->elements()->length(); 8084 return length > 0; 8085 } 8086 case FAST_HOLEY_SMI_ELEMENTS: 8087 case FAST_HOLEY_ELEMENTS: { 8088 FixedArray* elements = FixedArray::cast(object->elements()); 8089 int length = object->IsJSArray() 8090 ? Smi::cast(JSArray::cast(object)->length())->value() 8091 : elements->length(); 8092 Isolate* isolate = GetIsolate(); 8093 for (int i = 0; i < length; i++) { 8094 if (!elements->is_the_hole(isolate, i)) return true; 8095 } 8096 return false; 8097 } 8098 case FAST_HOLEY_DOUBLE_ELEMENTS: { 8099 int length = object->IsJSArray() 8100 ? Smi::cast(JSArray::cast(object)->length())->value() 8101 : object->elements()->length(); 8102 // Zero-length arrays would use the empty FixedArray... 8103 if (length == 0) return false; 8104 // ...so only cast to FixedDoubleArray otherwise. 8105 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements()); 8106 for (int i = 0; i < length; i++) { 8107 if (!elements->is_the_hole(i)) return true; 8108 } 8109 return false; 8110 } 8111 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 8112 case TYPE##_ELEMENTS: 8113 8114 TYPED_ARRAYS(TYPED_ARRAY_CASE) 8115 #undef TYPED_ARRAY_CASE 8116 { 8117 int length = object->elements()->length(); 8118 return length > 0; 8119 } 8120 case DICTIONARY_ELEMENTS: { 8121 SeededNumberDictionary* elements = 8122 SeededNumberDictionary::cast(object->elements()); 8123 return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0; 8124 } 8125 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 8126 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 8127 // We're approximating non-empty arguments objects here. 8128 return true; 8129 case FAST_STRING_WRAPPER_ELEMENTS: 8130 case SLOW_STRING_WRAPPER_ELEMENTS: 8131 if (String::cast(JSValue::cast(object)->value())->length() > 0) { 8132 return true; 8133 } 8134 return object->elements()->length() > 0; 8135 case NO_ELEMENTS: 8136 return false; 8137 } 8138 UNREACHABLE(); 8139 return true; 8140 } 8141 8142 8143 int Map::NumberOfDescribedProperties(DescriptorFlag which, 8144 PropertyFilter filter) { 8145 int result = 0; 8146 DescriptorArray* descs = instance_descriptors(); 8147 int limit = which == ALL_DESCRIPTORS 8148 ? descs->number_of_descriptors() 8149 : NumberOfOwnDescriptors(); 8150 for (int i = 0; i < limit; i++) { 8151 if ((descs->GetDetails(i).attributes() & filter) == 0 && 8152 !descs->GetKey(i)->FilterKey(filter)) { 8153 result++; 8154 } 8155 } 8156 return result; 8157 } 8158 8159 8160 int Map::NextFreePropertyIndex() { 8161 int free_index = 0; 8162 int number_of_own_descriptors = NumberOfOwnDescriptors(); 8163 DescriptorArray* descs = instance_descriptors(); 8164 for (int i = 0; i < number_of_own_descriptors; i++) { 8165 PropertyDetails details = descs->GetDetails(i); 8166 if (details.location() == kField) { 8167 int candidate = details.field_index() + details.field_width_in_words(); 8168 if (candidate > free_index) free_index = candidate; 8169 } 8170 } 8171 return free_index; 8172 } 8173 8174 8175 bool Map::OnlyHasSimpleProperties() { 8176 // Wrapped string elements aren't explicitly stored in the elements backing 8177 // store, but are loaded indirectly from the underlying string. 8178 return !IsStringWrapperElementsKind(elements_kind()) && 8179 !IsSpecialReceiverMap() && !has_hidden_prototype() && 8180 !is_dictionary_map(); 8181 } 8182 8183 MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries( 8184 Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries, 8185 Handle<FixedArray>* result) { 8186 Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate); 8187 8188 if (!map->IsJSObjectMap()) return Just(false); 8189 if (!map->OnlyHasSimpleProperties()) return Just(false); 8190 8191 Handle<JSObject> object(JSObject::cast(*receiver)); 8192 8193 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 8194 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 8195 int number_of_own_elements = 8196 object->GetElementsAccessor()->GetCapacity(*object, object->elements()); 8197 Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray( 8198 number_of_own_descriptors + number_of_own_elements); 8199 int count = 0; 8200 8201 if (object->elements() != isolate->heap()->empty_fixed_array()) { 8202 MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries( 8203 isolate, object, values_or_entries, get_entries, &count, 8204 ENUMERABLE_STRINGS), 8205 Nothing<bool>()); 8206 } 8207 8208 bool stable = object->map() == *map; 8209 8210 for (int index = 0; index < number_of_own_descriptors; index++) { 8211 Handle<Name> next_key(descriptors->GetKey(index), isolate); 8212 if (!next_key->IsString()) continue; 8213 Handle<Object> prop_value; 8214 8215 // Directly decode from the descriptor array if |from| did not change shape. 8216 if (stable) { 8217 PropertyDetails details = descriptors->GetDetails(index); 8218 if (!details.IsEnumerable()) continue; 8219 if (details.kind() == kData) { 8220 if (details.location() == kDescriptor) { 8221 prop_value = handle(descriptors->GetValue(index), isolate); 8222 } else { 8223 Representation representation = details.representation(); 8224 FieldIndex field_index = FieldIndex::ForDescriptor(*map, index); 8225 prop_value = 8226 JSObject::FastPropertyAt(object, representation, field_index); 8227 } 8228 } else { 8229 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8230 isolate, prop_value, JSReceiver::GetProperty(object, next_key), 8231 Nothing<bool>()); 8232 stable = object->map() == *map; 8233 } 8234 } else { 8235 // If the map did change, do a slower lookup. We are still guaranteed that 8236 // the object has a simple shape, and that the key is a name. 8237 LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR); 8238 if (!it.IsFound()) continue; 8239 DCHECK(it.state() == LookupIterator::DATA || 8240 it.state() == LookupIterator::ACCESSOR); 8241 if (!it.IsEnumerable()) continue; 8242 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8243 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); 8244 } 8245 8246 if (get_entries) { 8247 prop_value = MakeEntryPair(isolate, next_key, prop_value); 8248 } 8249 8250 values_or_entries->set(count, *prop_value); 8251 count++; 8252 } 8253 8254 if (count < values_or_entries->length()) values_or_entries->Shrink(count); 8255 *result = values_or_entries; 8256 return Just(true); 8257 } 8258 8259 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, 8260 Handle<JSReceiver> object, 8261 PropertyFilter filter, 8262 bool get_entries) { 8263 Handle<FixedArray> values_or_entries; 8264 if (filter == ENUMERABLE_STRINGS) { 8265 Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries( 8266 isolate, object, get_entries, &values_or_entries); 8267 if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>(); 8268 if (fast_values_or_entries.FromJust()) return values_or_entries; 8269 } 8270 8271 PropertyFilter key_filter = 8272 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE); 8273 8274 Handle<FixedArray> keys; 8275 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8276 isolate, keys, 8277 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter, 8278 GetKeysConversion::kConvertToString), 8279 MaybeHandle<FixedArray>()); 8280 8281 values_or_entries = isolate->factory()->NewFixedArray(keys->length()); 8282 int length = 0; 8283 8284 for (int i = 0; i < keys->length(); ++i) { 8285 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate)); 8286 8287 if (filter & ONLY_ENUMERABLE) { 8288 PropertyDescriptor descriptor; 8289 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor( 8290 isolate, object, key, &descriptor); 8291 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>()); 8292 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue; 8293 } 8294 8295 Handle<Object> value; 8296 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8297 isolate, value, JSReceiver::GetPropertyOrElement(object, key), 8298 MaybeHandle<FixedArray>()); 8299 8300 if (get_entries) { 8301 Handle<FixedArray> entry_storage = 8302 isolate->factory()->NewUninitializedFixedArray(2); 8303 entry_storage->set(0, *key); 8304 entry_storage->set(1, *value); 8305 value = isolate->factory()->NewJSArrayWithElements(entry_storage, 8306 FAST_ELEMENTS, 2); 8307 } 8308 8309 values_or_entries->set(length, *value); 8310 length++; 8311 } 8312 if (length < values_or_entries->length()) values_or_entries->Shrink(length); 8313 return values_or_entries; 8314 } 8315 8316 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object, 8317 PropertyFilter filter) { 8318 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false); 8319 } 8320 8321 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object, 8322 PropertyFilter filter) { 8323 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true); 8324 } 8325 8326 bool Map::DictionaryElementsInPrototypeChainOnly() { 8327 if (IsDictionaryElementsKind(elements_kind())) { 8328 return false; 8329 } 8330 8331 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) { 8332 // Be conservative, don't walk into proxies. 8333 if (iter.GetCurrent()->IsJSProxy()) return true; 8334 // String wrappers have non-configurable, non-writable elements. 8335 if (iter.GetCurrent()->IsStringWrapper()) return true; 8336 JSObject* current = iter.GetCurrent<JSObject>(); 8337 8338 if (current->HasDictionaryElements() && 8339 current->element_dictionary()->requires_slow_elements()) { 8340 return true; 8341 } 8342 8343 if (current->HasSlowArgumentsElements()) { 8344 FixedArray* parameter_map = FixedArray::cast(current->elements()); 8345 Object* arguments = parameter_map->get(1); 8346 if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) { 8347 return true; 8348 } 8349 } 8350 } 8351 8352 return false; 8353 } 8354 8355 8356 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object, 8357 Handle<Name> name, 8358 Handle<Object> getter, 8359 Handle<Object> setter, 8360 PropertyAttributes attributes) { 8361 Isolate* isolate = object->GetIsolate(); 8362 8363 LookupIterator it = LookupIterator::PropertyOrElement( 8364 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 8365 return DefineAccessor(&it, getter, setter, attributes); 8366 } 8367 8368 8369 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it, 8370 Handle<Object> getter, 8371 Handle<Object> setter, 8372 PropertyAttributes attributes) { 8373 Isolate* isolate = it->isolate(); 8374 8375 it->UpdateProtector(); 8376 8377 if (it->state() == LookupIterator::ACCESS_CHECK) { 8378 if (!it->HasAccess()) { 8379 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 8380 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 8381 return isolate->factory()->undefined_value(); 8382 } 8383 it->Next(); 8384 } 8385 8386 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 8387 // Ignore accessors on typed arrays. 8388 if (it->IsElement() && object->HasFixedTypedArrayElements()) { 8389 return it->factory()->undefined_value(); 8390 } 8391 8392 DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) || 8393 getter->IsNull(isolate) || getter->IsFunctionTemplateInfo()); 8394 DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) || 8395 setter->IsNull(isolate) || setter->IsFunctionTemplateInfo()); 8396 it->TransitionToAccessorProperty(getter, setter, attributes); 8397 8398 return isolate->factory()->undefined_value(); 8399 } 8400 8401 8402 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object, 8403 Handle<AccessorInfo> info) { 8404 Isolate* isolate = object->GetIsolate(); 8405 Handle<Name> name(Name::cast(info->name()), isolate); 8406 8407 LookupIterator it = LookupIterator::PropertyOrElement( 8408 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 8409 8410 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that 8411 // the FailedAccessCheckCallbackFunction doesn't throw an exception. 8412 // 8413 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can 8414 // remove reliance on default return values. 8415 if (it.state() == LookupIterator::ACCESS_CHECK) { 8416 if (!it.HasAccess()) { 8417 isolate->ReportFailedAccessCheck(object); 8418 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 8419 return it.factory()->undefined_value(); 8420 } 8421 it.Next(); 8422 } 8423 8424 // Ignore accessors on typed arrays. 8425 if (it.IsElement() && object->HasFixedTypedArrayElements()) { 8426 return it.factory()->undefined_value(); 8427 } 8428 8429 CHECK(GetPropertyAttributes(&it).IsJust()); 8430 8431 // ES5 forbids turning a property into an accessor if it's not 8432 // configurable. See 8.6.1 (Table 5). 8433 if (it.IsFound() && !it.IsConfigurable()) { 8434 return it.factory()->undefined_value(); 8435 } 8436 8437 it.TransitionToAccessorPair(info, info->property_attributes()); 8438 8439 return object; 8440 } 8441 8442 Object* JSObject::SlowReverseLookup(Object* value) { 8443 if (HasFastProperties()) { 8444 int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); 8445 DescriptorArray* descs = map()->instance_descriptors(); 8446 bool value_is_number = value->IsNumber(); 8447 for (int i = 0; i < number_of_own_descriptors; i++) { 8448 PropertyDetails details = descs->GetDetails(i); 8449 if (details.location() == kField) { 8450 DCHECK_EQ(kData, details.kind()); 8451 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i); 8452 if (IsUnboxedDoubleField(field_index)) { 8453 if (value_is_number) { 8454 double property = RawFastDoublePropertyAt(field_index); 8455 if (property == value->Number()) { 8456 return descs->GetKey(i); 8457 } 8458 } 8459 } else { 8460 Object* property = RawFastPropertyAt(field_index); 8461 if (field_index.is_double()) { 8462 DCHECK(property->IsMutableHeapNumber()); 8463 if (value_is_number && property->Number() == value->Number()) { 8464 return descs->GetKey(i); 8465 } 8466 } else if (property == value) { 8467 return descs->GetKey(i); 8468 } 8469 } 8470 } else { 8471 DCHECK_EQ(kDescriptor, details.location()); 8472 if (details.kind() == kData) { 8473 if (descs->GetValue(i) == value) { 8474 return descs->GetKey(i); 8475 } 8476 } 8477 } 8478 } 8479 return GetHeap()->undefined_value(); 8480 } else if (IsJSGlobalObject()) { 8481 return global_dictionary()->SlowReverseLookup(value); 8482 } else { 8483 return property_dictionary()->SlowReverseLookup(value); 8484 } 8485 } 8486 8487 8488 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) { 8489 Isolate* isolate = map->GetIsolate(); 8490 Handle<Map> result = 8491 isolate->factory()->NewMap(map->instance_type(), instance_size); 8492 Handle<Object> prototype(map->prototype(), isolate); 8493 Map::SetPrototype(result, prototype); 8494 result->set_constructor_or_backpointer(map->GetConstructor()); 8495 result->set_bit_field(map->bit_field()); 8496 result->set_bit_field2(map->bit_field2()); 8497 int new_bit_field3 = map->bit_field3(); 8498 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); 8499 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); 8500 new_bit_field3 = EnumLengthBits::update(new_bit_field3, 8501 kInvalidEnumCacheSentinel); 8502 new_bit_field3 = Deprecated::update(new_bit_field3, false); 8503 if (!map->is_dictionary_map()) { 8504 new_bit_field3 = IsUnstable::update(new_bit_field3, false); 8505 } 8506 result->set_bit_field3(new_bit_field3); 8507 return result; 8508 } 8509 8510 8511 Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode, 8512 const char* reason) { 8513 DCHECK(!fast_map->is_dictionary_map()); 8514 8515 Isolate* isolate = fast_map->GetIsolate(); 8516 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(), 8517 isolate); 8518 bool use_cache = 8519 !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate); 8520 Handle<NormalizedMapCache> cache; 8521 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache); 8522 8523 Handle<Map> new_map; 8524 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) { 8525 #ifdef VERIFY_HEAP 8526 if (FLAG_verify_heap) new_map->DictionaryMapVerify(); 8527 #endif 8528 #ifdef ENABLE_SLOW_DCHECKS 8529 if (FLAG_enable_slow_asserts) { 8530 // The cached map should match newly created normalized map bit-by-bit, 8531 // except for the code cache, which can contain some ics which can be 8532 // applied to the shared map, dependent code and weak cell cache. 8533 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode); 8534 8535 if (new_map->is_prototype_map()) { 8536 // For prototype maps, the PrototypeInfo is not copied. 8537 DCHECK(memcmp(fresh->address(), new_map->address(), 8538 kTransitionsOrPrototypeInfoOffset) == 0); 8539 DCHECK(fresh->raw_transitions() == Smi::kZero); 8540 STATIC_ASSERT(kDescriptorsOffset == 8541 kTransitionsOrPrototypeInfoOffset + kPointerSize); 8542 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset), 8543 HeapObject::RawField(*new_map, kDescriptorsOffset), 8544 kCodeCacheOffset - kDescriptorsOffset) == 0); 8545 } else { 8546 DCHECK(memcmp(fresh->address(), new_map->address(), 8547 Map::kCodeCacheOffset) == 0); 8548 } 8549 STATIC_ASSERT(Map::kDependentCodeOffset == 8550 Map::kCodeCacheOffset + kPointerSize); 8551 STATIC_ASSERT(Map::kWeakCellCacheOffset == 8552 Map::kDependentCodeOffset + kPointerSize); 8553 int offset = Map::kWeakCellCacheOffset + kPointerSize; 8554 DCHECK(memcmp(fresh->address() + offset, 8555 new_map->address() + offset, 8556 Map::kSize - offset) == 0); 8557 } 8558 #endif 8559 } else { 8560 new_map = Map::CopyNormalized(fast_map, mode); 8561 if (use_cache) { 8562 cache->Set(fast_map, new_map); 8563 isolate->counters()->maps_normalized()->Increment(); 8564 } 8565 #if TRACE_MAPS 8566 if (FLAG_trace_maps) { 8567 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n", 8568 reinterpret_cast<void*>(*fast_map), 8569 reinterpret_cast<void*>(*new_map), reason); 8570 } 8571 #endif 8572 } 8573 fast_map->NotifyLeafMapLayoutChange(); 8574 return new_map; 8575 } 8576 8577 8578 Handle<Map> Map::CopyNormalized(Handle<Map> map, 8579 PropertyNormalizationMode mode) { 8580 int new_instance_size = map->instance_size(); 8581 if (mode == CLEAR_INOBJECT_PROPERTIES) { 8582 new_instance_size -= map->GetInObjectProperties() * kPointerSize; 8583 } 8584 8585 Handle<Map> result = RawCopy(map, new_instance_size); 8586 8587 if (mode != CLEAR_INOBJECT_PROPERTIES) { 8588 result->SetInObjectProperties(map->GetInObjectProperties()); 8589 } 8590 8591 result->set_dictionary_map(true); 8592 result->set_migration_target(false); 8593 result->set_construction_counter(kNoSlackTracking); 8594 8595 #ifdef VERIFY_HEAP 8596 if (FLAG_verify_heap) result->DictionaryMapVerify(); 8597 #endif 8598 8599 return result; 8600 } 8601 8602 // Return an immutable prototype exotic object version of the input map. 8603 // Never even try to cache it in the transition tree, as it is intended 8604 // for the global object and its prototype chain, and excluding it saves 8605 // memory on the map transition tree. 8606 8607 // static 8608 Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) { 8609 Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype"); 8610 new_map->set_immutable_proto(true); 8611 return new_map; 8612 } 8613 8614 Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size, 8615 int in_object_properties, 8616 int unused_property_fields) { 8617 #ifdef DEBUG 8618 Isolate* isolate = map->GetIsolate(); 8619 // Strict function maps have Function as a constructor but the 8620 // Function's initial map is a sloppy function map. Same holds for 8621 // GeneratorFunction / AsyncFunction and its initial map. 8622 Object* constructor = map->GetConstructor(); 8623 DCHECK(constructor->IsJSFunction()); 8624 DCHECK(*map == JSFunction::cast(constructor)->initial_map() || 8625 *map == *isolate->strict_function_map() || 8626 *map == *isolate->generator_function_map() || 8627 *map == *isolate->async_function_map()); 8628 #endif 8629 // Initial maps must always own their descriptors and it's descriptor array 8630 // does not contain descriptors that do not belong to the map. 8631 DCHECK(map->owns_descriptors()); 8632 DCHECK_EQ(map->NumberOfOwnDescriptors(), 8633 map->instance_descriptors()->number_of_descriptors()); 8634 8635 Handle<Map> result = RawCopy(map, instance_size); 8636 8637 // Please note instance_type and instance_size are set when allocated. 8638 result->SetInObjectProperties(in_object_properties); 8639 result->set_unused_property_fields(unused_property_fields); 8640 8641 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 8642 if (number_of_own_descriptors > 0) { 8643 // The copy will use the same descriptors array. 8644 result->UpdateDescriptors(map->instance_descriptors(), 8645 map->GetLayoutDescriptor()); 8646 result->SetNumberOfOwnDescriptors(number_of_own_descriptors); 8647 8648 DCHECK_EQ(result->NumberOfFields(), 8649 in_object_properties - unused_property_fields); 8650 } 8651 8652 return result; 8653 } 8654 8655 8656 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) { 8657 Handle<Map> result = RawCopy(map, map->instance_size()); 8658 8659 // Please note instance_type and instance_size are set when allocated. 8660 if (map->IsJSObjectMap()) { 8661 result->SetInObjectProperties(map->GetInObjectProperties()); 8662 result->set_unused_property_fields(map->unused_property_fields()); 8663 } 8664 result->ClearCodeCache(map->GetHeap()); 8665 map->NotifyLeafMapLayoutChange(); 8666 return result; 8667 } 8668 8669 8670 Handle<Map> Map::ShareDescriptor(Handle<Map> map, 8671 Handle<DescriptorArray> descriptors, 8672 Descriptor* descriptor) { 8673 // Sanity check. This path is only to be taken if the map owns its descriptor 8674 // array, implying that its NumberOfOwnDescriptors equals the number of 8675 // descriptors in the descriptor array. 8676 DCHECK_EQ(map->NumberOfOwnDescriptors(), 8677 map->instance_descriptors()->number_of_descriptors()); 8678 8679 Handle<Map> result = CopyDropDescriptors(map); 8680 Handle<Name> name = descriptor->GetKey(); 8681 8682 // Ensure there's space for the new descriptor in the shared descriptor array. 8683 if (descriptors->NumberOfSlackDescriptors() == 0) { 8684 int old_size = descriptors->number_of_descriptors(); 8685 if (old_size == 0) { 8686 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1); 8687 } else { 8688 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors); 8689 EnsureDescriptorSlack(map, slack); 8690 descriptors = handle(map->instance_descriptors()); 8691 } 8692 } 8693 8694 Handle<LayoutDescriptor> layout_descriptor = 8695 FLAG_unbox_double_fields 8696 ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails()) 8697 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate()); 8698 8699 { 8700 DisallowHeapAllocation no_gc; 8701 descriptors->Append(descriptor); 8702 result->InitializeDescriptors(*descriptors, *layout_descriptor); 8703 } 8704 8705 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1); 8706 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION); 8707 8708 return result; 8709 } 8710 8711 8712 #if TRACE_MAPS 8713 8714 // static 8715 void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) { 8716 if (FLAG_trace_maps) { 8717 PrintF("[TraceMaps: %s from= %p to= %p name= ", what, 8718 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to)); 8719 name->NameShortPrint(); 8720 PrintF(" ]\n"); 8721 } 8722 } 8723 8724 8725 // static 8726 void Map::TraceAllTransitions(Map* map) { 8727 Object* transitions = map->raw_transitions(); 8728 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 8729 for (int i = -0; i < num_transitions; ++i) { 8730 Map* target = TransitionArray::GetTarget(transitions, i); 8731 Name* key = TransitionArray::GetKey(transitions, i); 8732 Map::TraceTransition("Transition", map, target, key); 8733 Map::TraceAllTransitions(target); 8734 } 8735 } 8736 8737 #endif // TRACE_MAPS 8738 8739 8740 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child, 8741 Handle<Name> name, SimpleTransitionFlag flag) { 8742 if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) { 8743 parent->set_owns_descriptors(false); 8744 } else { 8745 // |parent| is initial map and it must keep the ownership, there must be no 8746 // descriptors in the descriptors array that do not belong to the map. 8747 DCHECK(parent->owns_descriptors()); 8748 DCHECK_EQ(parent->NumberOfOwnDescriptors(), 8749 parent->instance_descriptors()->number_of_descriptors()); 8750 } 8751 if (parent->is_prototype_map()) { 8752 DCHECK(child->is_prototype_map()); 8753 #if TRACE_MAPS 8754 Map::TraceTransition("NoTransition", *parent, *child, *name); 8755 #endif 8756 } else { 8757 TransitionArray::Insert(parent, name, child, flag); 8758 #if TRACE_MAPS 8759 Map::TraceTransition("Transition", *parent, *child, *name); 8760 #endif 8761 } 8762 } 8763 8764 8765 Handle<Map> Map::CopyReplaceDescriptors( 8766 Handle<Map> map, Handle<DescriptorArray> descriptors, 8767 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag, 8768 MaybeHandle<Name> maybe_name, const char* reason, 8769 SimpleTransitionFlag simple_flag) { 8770 DCHECK(descriptors->IsSortedNoDuplicates()); 8771 8772 Handle<Map> result = CopyDropDescriptors(map); 8773 8774 if (!map->is_prototype_map()) { 8775 if (flag == INSERT_TRANSITION && 8776 TransitionArray::CanHaveMoreTransitions(map)) { 8777 result->InitializeDescriptors(*descriptors, *layout_descriptor); 8778 8779 Handle<Name> name; 8780 CHECK(maybe_name.ToHandle(&name)); 8781 ConnectTransition(map, result, name, simple_flag); 8782 } else { 8783 descriptors->GeneralizeAllFields(); 8784 result->InitializeDescriptors(*descriptors, 8785 LayoutDescriptor::FastPointerLayout()); 8786 } 8787 } else { 8788 result->InitializeDescriptors(*descriptors, *layout_descriptor); 8789 } 8790 #if TRACE_MAPS 8791 if (FLAG_trace_maps && 8792 // Mirror conditions above that did not call ConnectTransition(). 8793 (map->is_prototype_map() || 8794 !(flag == INSERT_TRANSITION && 8795 TransitionArray::CanHaveMoreTransitions(map)))) { 8796 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n", 8797 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result), 8798 reason); 8799 } 8800 #endif 8801 8802 return result; 8803 } 8804 8805 8806 // Creates transition tree starting from |split_map| and adding all descriptors 8807 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors(). 8808 // The way how it is done is tricky because of GC and special descriptors 8809 // marking logic. 8810 Handle<Map> Map::AddMissingTransitions( 8811 Handle<Map> split_map, Handle<DescriptorArray> descriptors, 8812 Handle<LayoutDescriptor> full_layout_descriptor) { 8813 DCHECK(descriptors->IsSortedNoDuplicates()); 8814 int split_nof = split_map->NumberOfOwnDescriptors(); 8815 int nof_descriptors = descriptors->number_of_descriptors(); 8816 DCHECK_LT(split_nof, nof_descriptors); 8817 8818 // Start with creating last map which will own full descriptors array. 8819 // This is necessary to guarantee that GC will mark the whole descriptor 8820 // array if any of the allocations happening below fail. 8821 // Number of unused properties is temporarily incorrect and the layout 8822 // descriptor could unnecessarily be in slow mode but we will fix after 8823 // all the other intermediate maps are created. 8824 Handle<Map> last_map = CopyDropDescriptors(split_map); 8825 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor); 8826 last_map->set_unused_property_fields(0); 8827 8828 // During creation of intermediate maps we violate descriptors sharing 8829 // invariant since the last map is not yet connected to the transition tree 8830 // we create here. But it is safe because GC never trims map's descriptors 8831 // if there are no dead transitions from that map and this is exactly the 8832 // case for all the intermediate maps we create here. 8833 Handle<Map> map = split_map; 8834 for (int i = split_nof; i < nof_descriptors - 1; ++i) { 8835 Handle<Map> new_map = CopyDropDescriptors(map); 8836 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor); 8837 map = new_map; 8838 } 8839 map->NotifyLeafMapLayoutChange(); 8840 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors, 8841 full_layout_descriptor); 8842 return last_map; 8843 } 8844 8845 8846 // Since this method is used to rewrite an existing transition tree, it can 8847 // always insert transitions without checking. 8848 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child, 8849 int new_descriptor, 8850 Handle<DescriptorArray> descriptors, 8851 Handle<LayoutDescriptor> full_layout_descriptor) { 8852 DCHECK(descriptors->IsSortedNoDuplicates()); 8853 8854 child->set_instance_descriptors(*descriptors); 8855 child->SetNumberOfOwnDescriptors(new_descriptor + 1); 8856 8857 int unused_property_fields = parent->unused_property_fields(); 8858 PropertyDetails details = descriptors->GetDetails(new_descriptor); 8859 if (details.location() == kField) { 8860 unused_property_fields = parent->unused_property_fields() - 1; 8861 if (unused_property_fields < 0) { 8862 unused_property_fields += JSObject::kFieldsAdded; 8863 } 8864 } 8865 child->set_unused_property_fields(unused_property_fields); 8866 8867 if (FLAG_unbox_double_fields) { 8868 Handle<LayoutDescriptor> layout_descriptor = 8869 LayoutDescriptor::AppendIfFastOrUseFull(parent, details, 8870 full_layout_descriptor); 8871 child->set_layout_descriptor(*layout_descriptor); 8872 #ifdef VERIFY_HEAP 8873 // TODO(ishell): remove these checks from VERIFY_HEAP mode. 8874 if (FLAG_verify_heap) { 8875 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); 8876 } 8877 #else 8878 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); 8879 #endif 8880 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child)); 8881 } 8882 8883 Handle<Name> name = handle(descriptors->GetKey(new_descriptor)); 8884 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION); 8885 } 8886 8887 8888 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind, 8889 TransitionFlag flag) { 8890 Map* maybe_elements_transition_map = NULL; 8891 if (flag == INSERT_TRANSITION) { 8892 // Ensure we are requested to add elements kind transition "near the root". 8893 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(), 8894 map->NumberOfOwnDescriptors()); 8895 8896 maybe_elements_transition_map = map->ElementsTransitionMap(); 8897 DCHECK(maybe_elements_transition_map == NULL || 8898 (maybe_elements_transition_map->elements_kind() == 8899 DICTIONARY_ELEMENTS && 8900 kind == DICTIONARY_ELEMENTS)); 8901 DCHECK(!IsFastElementsKind(kind) || 8902 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind)); 8903 DCHECK(kind != map->elements_kind()); 8904 } 8905 8906 bool insert_transition = flag == INSERT_TRANSITION && 8907 TransitionArray::CanHaveMoreTransitions(map) && 8908 maybe_elements_transition_map == NULL; 8909 8910 if (insert_transition) { 8911 Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind"); 8912 new_map->set_elements_kind(kind); 8913 8914 Isolate* isolate = map->GetIsolate(); 8915 Handle<Name> name = isolate->factory()->elements_transition_symbol(); 8916 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION); 8917 return new_map; 8918 } 8919 8920 // Create a new free-floating map only if we are not allowed to store it. 8921 Handle<Map> new_map = Copy(map, "CopyAsElementsKind"); 8922 new_map->set_elements_kind(kind); 8923 return new_map; 8924 } 8925 8926 8927 Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map, 8928 LanguageMode language_mode, FunctionKind kind) { 8929 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type()); 8930 // Initial map for sloppy mode function is stored in the function 8931 // constructor. Initial maps for strict mode are cached as special transitions 8932 // using |strict_function_transition_symbol| as a key. 8933 if (language_mode == SLOPPY) return initial_map; 8934 Isolate* isolate = initial_map->GetIsolate(); 8935 8936 int map_index = Context::FunctionMapIndex(language_mode, kind); 8937 Handle<Map> function_map( 8938 Map::cast(isolate->native_context()->get(map_index))); 8939 8940 STATIC_ASSERT(LANGUAGE_END == 2); 8941 DCHECK_EQ(STRICT, language_mode); 8942 Handle<Symbol> transition_symbol = 8943 isolate->factory()->strict_function_transition_symbol(); 8944 Map* maybe_transition = 8945 TransitionArray::SearchSpecial(*initial_map, *transition_symbol); 8946 if (maybe_transition != NULL) { 8947 return handle(maybe_transition, isolate); 8948 } 8949 initial_map->NotifyLeafMapLayoutChange(); 8950 8951 // Create new map taking descriptors from the |function_map| and all 8952 // the other details from the |initial_map|. 8953 Handle<Map> map = 8954 Map::CopyInitialMap(function_map, initial_map->instance_size(), 8955 initial_map->GetInObjectProperties(), 8956 initial_map->unused_property_fields()); 8957 map->SetConstructor(initial_map->GetConstructor()); 8958 map->set_prototype(initial_map->prototype()); 8959 8960 if (TransitionArray::CanHaveMoreTransitions(initial_map)) { 8961 Map::ConnectTransition(initial_map, map, transition_symbol, 8962 SPECIAL_TRANSITION); 8963 } 8964 return map; 8965 } 8966 8967 8968 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) { 8969 DCHECK(!map->is_prototype_map()); 8970 Handle<Map> new_map = CopyDropDescriptors(map); 8971 8972 if (map->owns_descriptors()) { 8973 // In case the map owned its own descriptors, share the descriptors and 8974 // transfer ownership to the new map. 8975 // The properties did not change, so reuse descriptors. 8976 new_map->InitializeDescriptors(map->instance_descriptors(), 8977 map->GetLayoutDescriptor()); 8978 } else { 8979 // In case the map did not own its own descriptors, a split is forced by 8980 // copying the map; creating a new descriptor array cell. 8981 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 8982 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 8983 Handle<DescriptorArray> new_descriptors = 8984 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors); 8985 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 8986 map->GetIsolate()); 8987 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); 8988 } 8989 8990 #if TRACE_MAPS 8991 if (FLAG_trace_maps) { 8992 PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n", 8993 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map), 8994 reason); 8995 } 8996 #endif 8997 8998 return new_map; 8999 } 9000 9001 9002 Handle<Map> Map::Copy(Handle<Map> map, const char* reason) { 9003 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 9004 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9005 Handle<DescriptorArray> new_descriptors = 9006 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors); 9007 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9008 map->GetIsolate()); 9009 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9010 OMIT_TRANSITION, MaybeHandle<Name>(), reason, 9011 SPECIAL_TRANSITION); 9012 } 9013 9014 9015 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) { 9016 Handle<Map> copy = 9017 Copy(handle(isolate->object_function()->initial_map()), "MapCreate"); 9018 9019 // Check that we do not overflow the instance size when adding the extra 9020 // inobject properties. If the instance size overflows, we allocate as many 9021 // properties as we can as inobject properties. 9022 int max_extra_properties = 9023 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2; 9024 9025 if (inobject_properties > max_extra_properties) { 9026 inobject_properties = max_extra_properties; 9027 } 9028 9029 int new_instance_size = 9030 JSObject::kHeaderSize + kPointerSize * inobject_properties; 9031 9032 // Adjust the map with the extra inobject properties. 9033 copy->SetInObjectProperties(inobject_properties); 9034 copy->set_unused_property_fields(inobject_properties); 9035 copy->set_instance_size(new_instance_size); 9036 copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy)); 9037 return copy; 9038 } 9039 9040 9041 Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map, 9042 PropertyAttributes attrs_to_add, 9043 Handle<Symbol> transition_marker, 9044 const char* reason) { 9045 int num_descriptors = map->NumberOfOwnDescriptors(); 9046 Isolate* isolate = map->GetIsolate(); 9047 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes( 9048 handle(map->instance_descriptors(), isolate), num_descriptors, 9049 attrs_to_add); 9050 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9051 isolate); 9052 Handle<Map> new_map = CopyReplaceDescriptors( 9053 map, new_desc, new_layout_descriptor, INSERT_TRANSITION, 9054 transition_marker, reason, SPECIAL_TRANSITION); 9055 new_map->set_is_extensible(false); 9056 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) { 9057 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind()) 9058 ? SLOW_STRING_WRAPPER_ELEMENTS 9059 : DICTIONARY_ELEMENTS; 9060 new_map->set_elements_kind(new_kind); 9061 } 9062 return new_map; 9063 } 9064 9065 namespace { 9066 9067 bool CanHoldValue(DescriptorArray* descriptors, int descriptor, 9068 PropertyConstness constness, Object* value) { 9069 PropertyDetails details = descriptors->GetDetails(descriptor); 9070 if (details.location() == kField) { 9071 if (details.kind() == kData) { 9072 return IsGeneralizableTo(constness, details.constness()) && 9073 value->FitsRepresentation(details.representation()) && 9074 descriptors->GetFieldType(descriptor)->NowContains(value); 9075 } else { 9076 DCHECK_EQ(kAccessor, details.kind()); 9077 return false; 9078 } 9079 9080 } else { 9081 DCHECK_EQ(kDescriptor, details.location()); 9082 DCHECK_EQ(kConst, details.constness()); 9083 if (details.kind() == kData) { 9084 DCHECK(!FLAG_track_constant_fields); 9085 DCHECK(descriptors->GetValue(descriptor) != value || 9086 value->FitsRepresentation(details.representation())); 9087 return descriptors->GetValue(descriptor) == value; 9088 } else { 9089 DCHECK_EQ(kAccessor, details.kind()); 9090 return false; 9091 } 9092 } 9093 UNREACHABLE(); 9094 return false; 9095 } 9096 9097 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor, 9098 PropertyConstness constness, 9099 Handle<Object> value) { 9100 if (CanHoldValue(map->instance_descriptors(), descriptor, constness, 9101 *value)) { 9102 return map; 9103 } 9104 9105 Isolate* isolate = map->GetIsolate(); 9106 PropertyAttributes attributes = 9107 map->instance_descriptors()->GetDetails(descriptor).attributes(); 9108 Representation representation = value->OptimalRepresentation(); 9109 Handle<FieldType> type = value->OptimalType(isolate, representation); 9110 9111 MapUpdater mu(isolate, map); 9112 return mu.ReconfigureToDataField(descriptor, attributes, constness, 9113 representation, type); 9114 } 9115 9116 } // namespace 9117 9118 // static 9119 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, 9120 PropertyConstness constness, 9121 Handle<Object> value) { 9122 // Dictionaries can store any property value. 9123 DCHECK(!map->is_dictionary_map()); 9124 // Update to the newest map before storing the property. 9125 return UpdateDescriptorForValue(Update(map), descriptor, constness, value); 9126 } 9127 9128 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, 9129 Handle<Object> value, 9130 PropertyAttributes attributes, 9131 PropertyConstness constness, 9132 StoreFromKeyed store_mode) { 9133 RuntimeCallTimerScope stats_scope( 9134 *map, map->is_prototype_map() 9135 ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty 9136 : &RuntimeCallStats::Map_TransitionToDataProperty); 9137 9138 DCHECK(name->IsUniqueName()); 9139 DCHECK(!map->is_dictionary_map()); 9140 9141 // Migrate to the newest map before storing the property. 9142 map = Update(map); 9143 9144 Map* maybe_transition = 9145 TransitionArray::SearchTransition(*map, kData, *name, attributes); 9146 if (maybe_transition != NULL) { 9147 Handle<Map> transition(maybe_transition); 9148 int descriptor = transition->LastAdded(); 9149 9150 DCHECK_EQ(attributes, transition->instance_descriptors() 9151 ->GetDetails(descriptor) 9152 .attributes()); 9153 9154 return UpdateDescriptorForValue(transition, descriptor, constness, value); 9155 } 9156 9157 TransitionFlag flag = INSERT_TRANSITION; 9158 MaybeHandle<Map> maybe_map; 9159 if (!FLAG_track_constant_fields && value->IsJSFunction()) { 9160 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag); 9161 } else if (!map->TooManyFastProperties(store_mode)) { 9162 Isolate* isolate = name->GetIsolate(); 9163 Representation representation = value->OptimalRepresentation(); 9164 Handle<FieldType> type = value->OptimalType(isolate, representation); 9165 maybe_map = Map::CopyWithField(map, name, type, attributes, constness, 9166 representation, flag); 9167 } 9168 9169 Handle<Map> result; 9170 if (!maybe_map.ToHandle(&result)) { 9171 #if TRACE_MAPS 9172 if (FLAG_trace_maps) { 9173 Vector<char> name_buffer = Vector<char>::New(100); 9174 name->NameShortPrint(name_buffer); 9175 Vector<char> buffer = Vector<char>::New(128); 9176 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start()); 9177 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start()); 9178 } 9179 #endif 9180 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, 9181 "TooManyFastProperties"); 9182 } 9183 9184 return result; 9185 } 9186 9187 9188 Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor, 9189 PropertyKind kind, 9190 PropertyAttributes attributes) { 9191 // Dictionaries have to be reconfigured in-place. 9192 DCHECK(!map->is_dictionary_map()); 9193 9194 if (!map->GetBackPointer()->IsMap()) { 9195 // There is no benefit from reconstructing transition tree for maps without 9196 // back pointers. 9197 return CopyGeneralizeAllFields(map, map->elements_kind(), descriptor, kind, 9198 attributes, 9199 "GenAll_AttributesMismatchProtoMap"); 9200 } 9201 9202 if (FLAG_trace_generalization) { 9203 map->PrintReconfiguration(stdout, descriptor, kind, attributes); 9204 } 9205 9206 Isolate* isolate = map->GetIsolate(); 9207 9208 MapUpdater mu(isolate, map); 9209 DCHECK_EQ(kData, kind); // Only kData case is supported so far. 9210 Handle<Map> new_map = mu.ReconfigureToDataField( 9211 descriptor, attributes, kDefaultFieldConstness, Representation::None(), 9212 FieldType::None(isolate)); 9213 return new_map; 9214 } 9215 9216 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map, 9217 Handle<Name> name, int descriptor, 9218 Handle<Object> getter, 9219 Handle<Object> setter, 9220 PropertyAttributes attributes) { 9221 RuntimeCallTimerScope stats_scope( 9222 isolate, 9223 map->is_prototype_map() 9224 ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty 9225 : &RuntimeCallStats::Map_TransitionToAccessorProperty); 9226 9227 // At least one of the accessors needs to be a new value. 9228 DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate)); 9229 DCHECK(name->IsUniqueName()); 9230 9231 // Dictionary maps can always have additional data properties. 9232 if (map->is_dictionary_map()) return map; 9233 9234 // Migrate to the newest map before transitioning to the new property. 9235 map = Update(map); 9236 9237 PropertyNormalizationMode mode = map->is_prototype_map() 9238 ? KEEP_INOBJECT_PROPERTIES 9239 : CLEAR_INOBJECT_PROPERTIES; 9240 9241 Map* maybe_transition = 9242 TransitionArray::SearchTransition(*map, kAccessor, *name, attributes); 9243 if (maybe_transition != NULL) { 9244 Handle<Map> transition(maybe_transition, isolate); 9245 DescriptorArray* descriptors = transition->instance_descriptors(); 9246 int descriptor = transition->LastAdded(); 9247 DCHECK(descriptors->GetKey(descriptor)->Equals(*name)); 9248 9249 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind()); 9250 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes()); 9251 9252 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate); 9253 if (!maybe_pair->IsAccessorPair()) { 9254 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair"); 9255 } 9256 9257 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair); 9258 if (!pair->Equals(*getter, *setter)) { 9259 return Map::Normalize(map, mode, "TransitionToDifferentAccessor"); 9260 } 9261 9262 return transition; 9263 } 9264 9265 Handle<AccessorPair> pair; 9266 DescriptorArray* old_descriptors = map->instance_descriptors(); 9267 if (descriptor != DescriptorArray::kNotFound) { 9268 if (descriptor != map->LastAdded()) { 9269 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast"); 9270 } 9271 PropertyDetails old_details = old_descriptors->GetDetails(descriptor); 9272 if (old_details.kind() != kAccessor) { 9273 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors"); 9274 } 9275 9276 if (old_details.attributes() != attributes) { 9277 return Map::Normalize(map, mode, "AccessorsWithAttributes"); 9278 } 9279 9280 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate); 9281 if (!maybe_pair->IsAccessorPair()) { 9282 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair"); 9283 } 9284 9285 Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair); 9286 if (current_pair->Equals(*getter, *setter)) return map; 9287 9288 bool overwriting_accessor = false; 9289 if (!getter->IsNull(isolate) && 9290 !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) && 9291 current_pair->get(ACCESSOR_GETTER) != *getter) { 9292 overwriting_accessor = true; 9293 } 9294 if (!setter->IsNull(isolate) && 9295 !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) && 9296 current_pair->get(ACCESSOR_SETTER) != *setter) { 9297 overwriting_accessor = true; 9298 } 9299 if (overwriting_accessor) { 9300 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors"); 9301 } 9302 9303 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair)); 9304 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors || 9305 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) { 9306 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors"); 9307 } else { 9308 pair = isolate->factory()->NewAccessorPair(); 9309 } 9310 9311 pair->SetComponents(*getter, *setter); 9312 9313 TransitionFlag flag = INSERT_TRANSITION; 9314 Descriptor d = Descriptor::AccessorConstant(name, pair, attributes); 9315 return Map::CopyInsertDescriptor(map, &d, flag); 9316 } 9317 9318 9319 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, 9320 Descriptor* descriptor, 9321 TransitionFlag flag) { 9322 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 9323 9324 // Share descriptors only if map owns descriptors and it not an initial map. 9325 if (flag == INSERT_TRANSITION && map->owns_descriptors() && 9326 !map->GetBackPointer()->IsUndefined(map->GetIsolate()) && 9327 TransitionArray::CanHaveMoreTransitions(map)) { 9328 return ShareDescriptor(map, descriptors, descriptor); 9329 } 9330 9331 int nof = map->NumberOfOwnDescriptors(); 9332 Handle<DescriptorArray> new_descriptors = 9333 DescriptorArray::CopyUpTo(descriptors, nof, 1); 9334 new_descriptors->Append(descriptor); 9335 9336 Handle<LayoutDescriptor> new_layout_descriptor = 9337 FLAG_unbox_double_fields 9338 ? LayoutDescriptor::New(map, new_descriptors, nof + 1) 9339 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate()); 9340 9341 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9342 flag, descriptor->GetKey(), "CopyAddDescriptor", 9343 SIMPLE_PROPERTY_TRANSITION); 9344 } 9345 9346 9347 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map, 9348 Descriptor* descriptor, 9349 TransitionFlag flag) { 9350 Handle<DescriptorArray> old_descriptors(map->instance_descriptors()); 9351 9352 // We replace the key if it is already present. 9353 int index = old_descriptors->SearchWithCache(map->GetIsolate(), 9354 *descriptor->GetKey(), *map); 9355 if (index != DescriptorArray::kNotFound) { 9356 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag); 9357 } 9358 return CopyAddDescriptor(map, descriptor, flag); 9359 } 9360 9361 9362 Handle<DescriptorArray> DescriptorArray::CopyUpTo( 9363 Handle<DescriptorArray> desc, 9364 int enumeration_index, 9365 int slack) { 9366 return DescriptorArray::CopyUpToAddAttributes( 9367 desc, enumeration_index, NONE, slack); 9368 } 9369 9370 9371 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes( 9372 Handle<DescriptorArray> desc, 9373 int enumeration_index, 9374 PropertyAttributes attributes, 9375 int slack) { 9376 if (enumeration_index + slack == 0) { 9377 return desc->GetIsolate()->factory()->empty_descriptor_array(); 9378 } 9379 9380 int size = enumeration_index; 9381 9382 Handle<DescriptorArray> descriptors = 9383 DescriptorArray::Allocate(desc->GetIsolate(), size, slack); 9384 9385 if (attributes != NONE) { 9386 for (int i = 0; i < size; ++i) { 9387 Object* value = desc->GetValue(i); 9388 Name* key = desc->GetKey(i); 9389 PropertyDetails details = desc->GetDetails(i); 9390 // Bulk attribute changes never affect private properties. 9391 if (!key->IsPrivate()) { 9392 int mask = DONT_DELETE | DONT_ENUM; 9393 // READ_ONLY is an invalid attribute for JS setters/getters. 9394 if (details.kind() != kAccessor || !value->IsAccessorPair()) { 9395 mask |= READ_ONLY; 9396 } 9397 details = details.CopyAddAttributes( 9398 static_cast<PropertyAttributes>(attributes & mask)); 9399 } 9400 descriptors->Set(i, key, value, details); 9401 } 9402 } else { 9403 for (int i = 0; i < size; ++i) { 9404 descriptors->CopyFrom(i, *desc); 9405 } 9406 } 9407 9408 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort(); 9409 9410 return descriptors; 9411 } 9412 9413 9414 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) { 9415 for (int i = 0; i < nof_descriptors; i++) { 9416 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) { 9417 return false; 9418 } 9419 PropertyDetails details = GetDetails(i); 9420 PropertyDetails other_details = desc->GetDetails(i); 9421 if (details.kind() != other_details.kind() || 9422 details.location() != other_details.location() || 9423 !details.representation().Equals(other_details.representation())) { 9424 return false; 9425 } 9426 } 9427 return true; 9428 } 9429 9430 9431 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map, 9432 Handle<DescriptorArray> descriptors, 9433 Descriptor* descriptor, 9434 int insertion_index, 9435 TransitionFlag flag) { 9436 Handle<Name> key = descriptor->GetKey(); 9437 DCHECK(*key == descriptors->GetKey(insertion_index)); 9438 9439 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 9440 descriptors, map->NumberOfOwnDescriptors()); 9441 9442 new_descriptors->Replace(insertion_index, descriptor); 9443 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New( 9444 map, new_descriptors, new_descriptors->number_of_descriptors()); 9445 9446 SimpleTransitionFlag simple_flag = 9447 (insertion_index == descriptors->number_of_descriptors() - 1) 9448 ? SIMPLE_PROPERTY_TRANSITION 9449 : PROPERTY_TRANSITION; 9450 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9451 flag, key, "CopyReplaceDescriptor", 9452 simple_flag); 9453 } 9454 9455 // Helper class to manage a Map's code cache. The layout depends on the number 9456 // of entries; this is worthwhile because most code caches are very small, 9457 // but some are huge (thousands of entries). 9458 // For zero entries, the EmptyFixedArray is used. 9459 // For one entry, we use a 2-element FixedArray containing [name, code]. 9460 // For 2..100 entries, we use a FixedArray with linear lookups, the layout is: 9461 // [0] - number of slots that are currently in use 9462 // [1] - first name 9463 // [2] - first code 9464 // [3] - second name 9465 // [4] - second code 9466 // etc. 9467 // For more than 128 entries, we use a CodeCacheHashTable. 9468 class CodeCache : public AllStatic { 9469 public: 9470 // Returns the new cache, to be stored on the map. 9471 static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache, 9472 Handle<Name> name, Handle<Code> code) { 9473 int length = cache->length(); 9474 if (length == 0) return PutFirstElement(isolate, name, code); 9475 if (length == kEntrySize) { 9476 return PutSecondElement(isolate, cache, name, code); 9477 } 9478 if (length <= kLinearMaxSize) { 9479 Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code); 9480 if (!result.is_null()) return result; 9481 // Fall through if linear storage is getting too large. 9482 } 9483 return PutHashTableElement(isolate, cache, name, code); 9484 } 9485 9486 static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) { 9487 int length = cache->length(); 9488 if (length == 0) return nullptr; 9489 if (length == kEntrySize) return OneElementLookup(cache, name, flags); 9490 if (!cache->IsCodeCacheHashTable()) { 9491 return LinearLookup(cache, name, flags); 9492 } else { 9493 return CodeCacheHashTable::cast(cache)->Lookup(name, flags); 9494 } 9495 } 9496 9497 private: 9498 static const int kNameIndex = 0; 9499 static const int kCodeIndex = 1; 9500 static const int kEntrySize = 2; 9501 9502 static const int kLinearUsageIndex = 0; 9503 static const int kLinearReservedSlots = 1; 9504 static const int kLinearInitialCapacity = 2; 9505 static const int kLinearMaxSize = 257; // == LinearSizeFor(128); 9506 9507 static const int kHashTableInitialCapacity = 200; // Number of entries. 9508 9509 static int LinearSizeFor(int entries) { 9510 return kLinearReservedSlots + kEntrySize * entries; 9511 } 9512 9513 static int LinearNewSize(int old_size) { 9514 int old_entries = (old_size - kLinearReservedSlots) / kEntrySize; 9515 return LinearSizeFor(old_entries * 2); 9516 } 9517 9518 static Code* OneElementLookup(FixedArray* cache, Name* name, 9519 Code::Flags flags) { 9520 DCHECK_EQ(cache->length(), kEntrySize); 9521 if (cache->get(kNameIndex) != name) return nullptr; 9522 Code* maybe_code = Code::cast(cache->get(kCodeIndex)); 9523 if (maybe_code->flags() != flags) return nullptr; 9524 return maybe_code; 9525 } 9526 9527 static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) { 9528 DCHECK_GE(cache->length(), kEntrySize); 9529 DCHECK(!cache->IsCodeCacheHashTable()); 9530 int usage = GetLinearUsage(cache); 9531 for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) { 9532 if (cache->get(i + kNameIndex) != name) continue; 9533 Code* code = Code::cast(cache->get(i + kCodeIndex)); 9534 if (code->flags() == flags) return code; 9535 } 9536 return nullptr; 9537 } 9538 9539 static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name, 9540 Handle<Code> code) { 9541 Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize); 9542 cache->set(kNameIndex, *name); 9543 cache->set(kCodeIndex, *code); 9544 return cache; 9545 } 9546 9547 static Handle<FixedArray> PutSecondElement(Isolate* isolate, 9548 Handle<FixedArray> cache, 9549 Handle<Name> name, 9550 Handle<Code> code) { 9551 DCHECK_EQ(cache->length(), kEntrySize); 9552 Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray( 9553 LinearSizeFor(kLinearInitialCapacity)); 9554 new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex)); 9555 new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex)); 9556 new_cache->set(LinearSizeFor(1) + kNameIndex, *name); 9557 new_cache->set(LinearSizeFor(1) + kCodeIndex, *code); 9558 new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2))); 9559 return new_cache; 9560 } 9561 9562 static Handle<FixedArray> PutLinearElement(Isolate* isolate, 9563 Handle<FixedArray> cache, 9564 Handle<Name> name, 9565 Handle<Code> code) { 9566 int length = cache->length(); 9567 int usage = GetLinearUsage(*cache); 9568 DCHECK_LE(usage, length); 9569 // Check if we need to grow. 9570 if (usage == length) { 9571 int new_length = LinearNewSize(length); 9572 if (new_length > kLinearMaxSize) return Handle<FixedArray>::null(); 9573 Handle<FixedArray> new_cache = 9574 isolate->factory()->NewFixedArray(new_length); 9575 for (int i = kLinearReservedSlots; i < length; i++) { 9576 new_cache->set(i, cache->get(i)); 9577 } 9578 cache = new_cache; 9579 } 9580 // Store new entry. 9581 DCHECK_GE(cache->length(), usage + kEntrySize); 9582 cache->set(usage + kNameIndex, *name); 9583 cache->set(usage + kCodeIndex, *code); 9584 cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize)); 9585 return cache; 9586 } 9587 9588 static Handle<FixedArray> PutHashTableElement(Isolate* isolate, 9589 Handle<FixedArray> cache, 9590 Handle<Name> name, 9591 Handle<Code> code) { 9592 // Check if we need to transition from linear to hash table storage. 9593 if (!cache->IsCodeCacheHashTable()) { 9594 // Check that the initial hash table capacity is large enough. 9595 DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128)); 9596 STATIC_ASSERT(kHashTableInitialCapacity > 128); 9597 9598 int length = cache->length(); 9599 // Only migrate from linear storage when it's full. 9600 DCHECK_EQ(length, GetLinearUsage(*cache)); 9601 DCHECK_EQ(length, kLinearMaxSize); 9602 Handle<CodeCacheHashTable> table = 9603 CodeCacheHashTable::New(isolate, kHashTableInitialCapacity); 9604 HandleScope scope(isolate); 9605 for (int i = kLinearReservedSlots; i < length; i += kEntrySize) { 9606 Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate); 9607 Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate); 9608 CodeCacheHashTable::Put(table, old_name, old_code); 9609 } 9610 cache = table; 9611 } 9612 // Store new entry. 9613 DCHECK(cache->IsCodeCacheHashTable()); 9614 return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache), 9615 name, code); 9616 } 9617 9618 static inline int GetLinearUsage(FixedArray* linear_cache) { 9619 DCHECK_GT(linear_cache->length(), kEntrySize); 9620 return Smi::cast(linear_cache->get(kLinearUsageIndex))->value(); 9621 } 9622 }; 9623 9624 void Map::UpdateCodeCache(Handle<Map> map, 9625 Handle<Name> name, 9626 Handle<Code> code) { 9627 Isolate* isolate = map->GetIsolate(); 9628 Handle<FixedArray> cache(map->code_cache(), isolate); 9629 Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code); 9630 map->set_code_cache(*new_cache); 9631 } 9632 9633 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) { 9634 return CodeCache::Lookup(code_cache(), name, flags); 9635 } 9636 9637 9638 // The key in the code cache hash table consists of the property name and the 9639 // code object. The actual match is on the name and the code flags. If a key 9640 // is created using the flags and not a code object it can only be used for 9641 // lookup not to create a new entry. 9642 class CodeCacheHashTableKey : public HashTableKey { 9643 public: 9644 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags) 9645 : name_(name), flags_(flags), code_() { 9646 DCHECK(name_->IsUniqueName()); 9647 } 9648 9649 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code) 9650 : name_(name), flags_(code->flags()), code_(code) { 9651 DCHECK(name_->IsUniqueName()); 9652 } 9653 9654 bool IsMatch(Object* other) override { 9655 DCHECK(other->IsFixedArray()); 9656 FixedArray* pair = FixedArray::cast(other); 9657 Name* name = Name::cast(pair->get(0)); 9658 Code::Flags flags = Code::cast(pair->get(1))->flags(); 9659 if (flags != flags_) return false; 9660 DCHECK(name->IsUniqueName()); 9661 return *name_ == name; 9662 } 9663 9664 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) { 9665 return name->Hash() ^ flags; 9666 } 9667 9668 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); } 9669 9670 uint32_t HashForObject(Object* obj) override { 9671 FixedArray* pair = FixedArray::cast(obj); 9672 Name* name = Name::cast(pair->get(0)); 9673 Code* code = Code::cast(pair->get(1)); 9674 return NameFlagsHashHelper(name, code->flags()); 9675 } 9676 9677 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override { 9678 Handle<Code> code = code_.ToHandleChecked(); 9679 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2); 9680 pair->set(0, *name_); 9681 pair->set(1, *code); 9682 return pair; 9683 } 9684 9685 private: 9686 Handle<Name> name_; 9687 Code::Flags flags_; 9688 // TODO(jkummerow): We should be able to get by without this. 9689 MaybeHandle<Code> code_; 9690 }; 9691 9692 9693 Handle<CodeCacheHashTable> CodeCacheHashTable::Put( 9694 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) { 9695 CodeCacheHashTableKey key(name, code); 9696 9697 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key); 9698 9699 int entry = new_cache->FindInsertionEntry(key.Hash()); 9700 Handle<Object> k = key.AsHandle(cache->GetIsolate()); 9701 9702 new_cache->set(EntryToIndex(entry), *k); 9703 new_cache->ElementAdded(); 9704 return new_cache; 9705 } 9706 9707 Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) { 9708 DisallowHeapAllocation no_alloc; 9709 CodeCacheHashTableKey key(handle(name), flags); 9710 int entry = FindEntry(&key); 9711 if (entry == kNotFound) return nullptr; 9712 return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1)); 9713 } 9714 9715 Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index, 9716 Handle<Object> value) { 9717 if (index < array->length()) { 9718 array->set(index, *value); 9719 return array; 9720 } 9721 int capacity = array->length(); 9722 do { 9723 capacity = JSObject::NewElementsCapacity(capacity); 9724 } while (capacity <= index); 9725 Handle<FixedArray> new_array = 9726 array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity); 9727 array->CopyTo(0, *new_array, 0, array->length()); 9728 new_array->FillWithHoles(array->length(), new_array->length()); 9729 new_array->set(index, *value); 9730 return new_array; 9731 } 9732 9733 void FixedArray::Shrink(int new_length) { 9734 DCHECK(0 <= new_length && new_length <= length()); 9735 if (new_length < length()) { 9736 GetHeap()->RightTrimFixedArray(this, length() - new_length); 9737 } 9738 } 9739 9740 9741 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) { 9742 DisallowHeapAllocation no_gc; 9743 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc); 9744 for (int index = 0; index < len; index++) { 9745 dest->set(dest_pos+index, get(pos+index), mode); 9746 } 9747 } 9748 9749 #ifdef DEBUG 9750 bool FixedArray::IsEqualTo(FixedArray* other) { 9751 if (length() != other->length()) return false; 9752 for (int i = 0 ; i < length(); ++i) { 9753 if (get(i) != other->get(i)) return false; 9754 } 9755 return true; 9756 } 9757 #endif 9758 9759 9760 // static 9761 void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index, 9762 Handle<HeapObject> value) { 9763 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything. 9764 Handle<WeakCell> cell = 9765 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value)) 9766 : array->GetIsolate()->factory()->NewWeakCell(value); 9767 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell); 9768 if (FLAG_trace_weak_arrays) { 9769 PrintF("[WeakFixedArray: storing at index %d ]\n", index); 9770 } 9771 array->set_last_used_index(index); 9772 } 9773 9774 9775 // static 9776 Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array, 9777 Handle<HeapObject> value, 9778 int* assigned_index) { 9779 Handle<WeakFixedArray> array = 9780 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) 9781 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) 9782 : Handle<WeakFixedArray>::cast(maybe_array); 9783 // Try to store the new entry if there's room. Optimize for consecutive 9784 // accesses. 9785 int first_index = array->last_used_index(); 9786 int length = array->Length(); 9787 if (length > 0) { 9788 for (int i = first_index;;) { 9789 if (array->IsEmptySlot((i))) { 9790 WeakFixedArray::Set(array, i, value); 9791 if (assigned_index != NULL) *assigned_index = i; 9792 return array; 9793 } 9794 if (FLAG_trace_weak_arrays) { 9795 PrintF("[WeakFixedArray: searching for free slot]\n"); 9796 } 9797 i = (i + 1) % length; 9798 if (i == first_index) break; 9799 } 9800 } 9801 9802 // No usable slot found, grow the array. 9803 int new_length = length == 0 ? 1 : length + (length >> 1) + 4; 9804 Handle<WeakFixedArray> new_array = 9805 Allocate(array->GetIsolate(), new_length, array); 9806 if (FLAG_trace_weak_arrays) { 9807 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length); 9808 } 9809 WeakFixedArray::Set(new_array, length, value); 9810 if (assigned_index != NULL) *assigned_index = length; 9811 return new_array; 9812 } 9813 9814 9815 template <class CompactionCallback> 9816 void WeakFixedArray::Compact() { 9817 FixedArray* array = FixedArray::cast(this); 9818 int new_length = kFirstIndex; 9819 for (int i = kFirstIndex; i < array->length(); i++) { 9820 Object* element = array->get(i); 9821 if (element->IsSmi()) continue; 9822 if (WeakCell::cast(element)->cleared()) continue; 9823 Object* value = WeakCell::cast(element)->value(); 9824 CompactionCallback::Callback(value, i - kFirstIndex, 9825 new_length - kFirstIndex); 9826 array->set(new_length++, element); 9827 } 9828 array->Shrink(new_length); 9829 set_last_used_index(0); 9830 } 9831 9832 9833 void WeakFixedArray::Iterator::Reset(Object* maybe_array) { 9834 if (maybe_array->IsWeakFixedArray()) { 9835 list_ = WeakFixedArray::cast(maybe_array); 9836 index_ = 0; 9837 #ifdef DEBUG 9838 last_used_index_ = list_->last_used_index(); 9839 #endif // DEBUG 9840 } 9841 } 9842 9843 9844 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value, 9845 int old_index, 9846 int new_index) { 9847 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map()); 9848 Map* map = Map::cast(value); 9849 DCHECK(map->prototype_info()->IsPrototypeInfo()); 9850 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info()); 9851 DCHECK_EQ(old_index, proto_info->registry_slot()); 9852 proto_info->set_registry_slot(new_index); 9853 } 9854 9855 9856 template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>(); 9857 template void 9858 WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>(); 9859 9860 9861 bool WeakFixedArray::Remove(Handle<HeapObject> value) { 9862 if (Length() == 0) return false; 9863 // Optimize for the most recently added element to be removed again. 9864 int first_index = last_used_index(); 9865 for (int i = first_index;;) { 9866 if (Get(i) == *value) { 9867 Clear(i); 9868 // Users of WeakFixedArray should make sure that there are no duplicates. 9869 return true; 9870 } 9871 i = (i + 1) % Length(); 9872 if (i == first_index) return false; 9873 } 9874 UNREACHABLE(); 9875 } 9876 9877 9878 // static 9879 Handle<WeakFixedArray> WeakFixedArray::Allocate( 9880 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) { 9881 DCHECK(0 <= size); 9882 Handle<FixedArray> result = 9883 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex); 9884 int index = 0; 9885 if (!initialize_from.is_null()) { 9886 DCHECK(initialize_from->Length() <= size); 9887 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from); 9888 // Copy the entries without compacting, since the PrototypeInfo relies on 9889 // the index of the entries not to change. 9890 while (index < raw_source->length()) { 9891 result->set(index, raw_source->get(index)); 9892 index++; 9893 } 9894 } 9895 while (index < result->length()) { 9896 result->set(index, Smi::kZero); 9897 index++; 9898 } 9899 return Handle<WeakFixedArray>::cast(result); 9900 } 9901 9902 9903 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj, 9904 AddMode mode) { 9905 int length = array->Length(); 9906 array = EnsureSpace(array, length + 1); 9907 if (mode == kReloadLengthAfterAllocation) { 9908 DCHECK(array->Length() <= length); 9909 length = array->Length(); 9910 } 9911 array->Set(length, *obj); 9912 array->SetLength(length + 1); 9913 return array; 9914 } 9915 9916 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1, 9917 Handle<Object> obj2, AddMode mode) { 9918 int length = array->Length(); 9919 array = EnsureSpace(array, length + 2); 9920 if (mode == kReloadLengthAfterAllocation) { 9921 length = array->Length(); 9922 } 9923 array->Set(length, *obj1); 9924 array->Set(length + 1, *obj2); 9925 array->SetLength(length + 2); 9926 return array; 9927 } 9928 9929 Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) { 9930 Handle<ArrayList> result = Handle<ArrayList>::cast( 9931 isolate->factory()->NewFixedArray(size + kFirstIndex)); 9932 result->SetLength(0); 9933 return result; 9934 } 9935 9936 bool ArrayList::IsFull() { 9937 int capacity = length(); 9938 return kFirstIndex + Length() == capacity; 9939 } 9940 9941 namespace { 9942 9943 Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array, 9944 int length) { 9945 int capacity = array->length(); 9946 if (capacity < length) { 9947 Isolate* isolate = array->GetIsolate(); 9948 int new_capacity = length; 9949 new_capacity = new_capacity + Max(new_capacity / 2, 2); 9950 int grow_by = new_capacity - capacity; 9951 array = Handle<ArrayList>::cast( 9952 isolate->factory()->CopyFixedArrayAndGrow(array, grow_by)); 9953 } 9954 return array; 9955 } 9956 9957 } // namespace 9958 9959 Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) { 9960 const bool empty = (array->length() == 0); 9961 auto ret = Handle<ArrayList>::cast( 9962 EnsureSpaceInFixedArray(array, kFirstIndex + length)); 9963 if (empty) ret->SetLength(0); 9964 return ret; 9965 } 9966 9967 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures( 9968 Handle<RegExpMatchInfo> match_info, int capture_count) { 9969 DCHECK_GE(match_info->length(), kLastMatchOverhead); 9970 const int required_length = kFirstCaptureIndex + capture_count; 9971 Handle<FixedArray> result = 9972 EnsureSpaceInFixedArray(match_info, required_length); 9973 return Handle<RegExpMatchInfo>::cast(result); 9974 } 9975 9976 // static 9977 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in, 9978 Handle<Object> receiver, 9979 Handle<JSFunction> function, 9980 Handle<AbstractCode> code, 9981 int offset, int flags) { 9982 const int frame_count = in->FrameCount(); 9983 const int new_length = LengthFor(frame_count + 1); 9984 Handle<FrameArray> array = EnsureSpace(in, new_length); 9985 array->SetReceiver(frame_count, *receiver); 9986 array->SetFunction(frame_count, *function); 9987 array->SetCode(frame_count, *code); 9988 array->SetOffset(frame_count, Smi::FromInt(offset)); 9989 array->SetFlags(frame_count, Smi::FromInt(flags)); 9990 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1)); 9991 return array; 9992 } 9993 9994 // static 9995 Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in, 9996 Handle<Object> wasm_instance, 9997 int wasm_function_index, 9998 Handle<AbstractCode> code, 9999 int offset, int flags) { 10000 const int frame_count = in->FrameCount(); 10001 const int new_length = LengthFor(frame_count + 1); 10002 Handle<FrameArray> array = EnsureSpace(in, new_length); 10003 array->SetWasmInstance(frame_count, *wasm_instance); 10004 array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index)); 10005 array->SetCode(frame_count, *code); 10006 array->SetOffset(frame_count, Smi::FromInt(offset)); 10007 array->SetFlags(frame_count, Smi::FromInt(flags)); 10008 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1)); 10009 return array; 10010 } 10011 10012 void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); } 10013 10014 // static 10015 Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array, 10016 int length) { 10017 return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length)); 10018 } 10019 10020 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate, 10021 int number_of_descriptors, 10022 int slack, 10023 PretenureFlag pretenure) { 10024 DCHECK(0 <= number_of_descriptors); 10025 Factory* factory = isolate->factory(); 10026 // Do not use DescriptorArray::cast on incomplete object. 10027 int size = number_of_descriptors + slack; 10028 if (size == 0) return factory->empty_descriptor_array(); 10029 // Allocate the array of keys. 10030 Handle<FixedArray> result = 10031 factory->NewFixedArray(LengthFor(size), pretenure); 10032 10033 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); 10034 result->set(kEnumCacheIndex, Smi::kZero); 10035 return Handle<DescriptorArray>::cast(result); 10036 } 10037 10038 void DescriptorArray::ClearEnumCache() { set(kEnumCacheIndex, Smi::kZero); } 10039 10040 void DescriptorArray::Replace(int index, Descriptor* descriptor) { 10041 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index)); 10042 Set(index, descriptor); 10043 } 10044 10045 10046 // static 10047 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors, 10048 Isolate* isolate, 10049 Handle<FixedArray> new_cache, 10050 Handle<FixedArray> new_index_cache) { 10051 DCHECK(!descriptors->IsEmpty()); 10052 FixedArray* bridge_storage; 10053 bool needs_new_enum_cache = !descriptors->HasEnumCache(); 10054 if (needs_new_enum_cache) { 10055 bridge_storage = *isolate->factory()->NewFixedArray( 10056 DescriptorArray::kEnumCacheBridgeLength); 10057 } else { 10058 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex)); 10059 } 10060 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache); 10061 bridge_storage->set( 10062 kEnumCacheBridgeIndicesCacheIndex, 10063 new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache); 10064 if (needs_new_enum_cache) { 10065 descriptors->set(kEnumCacheIndex, bridge_storage); 10066 } 10067 } 10068 10069 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) { 10070 PropertyDetails details = src->GetDetails(index); 10071 Set(index, src->GetKey(index), src->GetValue(index), details); 10072 } 10073 10074 void DescriptorArray::Sort() { 10075 // In-place heap sort. 10076 int len = number_of_descriptors(); 10077 // Reset sorting since the descriptor array might contain invalid pointers. 10078 for (int i = 0; i < len; ++i) SetSortedKey(i, i); 10079 // Bottom-up max-heap construction. 10080 // Index of the last node with children 10081 const int max_parent_index = (len / 2) - 1; 10082 for (int i = max_parent_index; i >= 0; --i) { 10083 int parent_index = i; 10084 const uint32_t parent_hash = GetSortedKey(i)->Hash(); 10085 while (parent_index <= max_parent_index) { 10086 int child_index = 2 * parent_index + 1; 10087 uint32_t child_hash = GetSortedKey(child_index)->Hash(); 10088 if (child_index + 1 < len) { 10089 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash(); 10090 if (right_child_hash > child_hash) { 10091 child_index++; 10092 child_hash = right_child_hash; 10093 } 10094 } 10095 if (child_hash <= parent_hash) break; 10096 SwapSortedKeys(parent_index, child_index); 10097 // Now element at child_index could be < its children. 10098 parent_index = child_index; // parent_hash remains correct. 10099 } 10100 } 10101 10102 // Extract elements and create sorted array. 10103 for (int i = len - 1; i > 0; --i) { 10104 // Put max element at the back of the array. 10105 SwapSortedKeys(0, i); 10106 // Shift down the new top element. 10107 int parent_index = 0; 10108 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash(); 10109 const int max_parent_index = (i / 2) - 1; 10110 while (parent_index <= max_parent_index) { 10111 int child_index = parent_index * 2 + 1; 10112 uint32_t child_hash = GetSortedKey(child_index)->Hash(); 10113 if (child_index + 1 < i) { 10114 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash(); 10115 if (right_child_hash > child_hash) { 10116 child_index++; 10117 child_hash = right_child_hash; 10118 } 10119 } 10120 if (child_hash <= parent_hash) break; 10121 SwapSortedKeys(parent_index, child_index); 10122 parent_index = child_index; 10123 } 10124 } 10125 DCHECK(IsSortedNoDuplicates()); 10126 } 10127 10128 10129 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) { 10130 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair(); 10131 copy->set_getter(pair->getter()); 10132 copy->set_setter(pair->setter()); 10133 return copy; 10134 } 10135 10136 Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair, 10137 AccessorComponent component) { 10138 Object* accessor = accessor_pair->get(component); 10139 if (accessor->IsFunctionTemplateInfo()) { 10140 return ApiNatives::InstantiateFunction( 10141 handle(FunctionTemplateInfo::cast(accessor))) 10142 .ToHandleChecked(); 10143 } 10144 Isolate* isolate = accessor_pair->GetIsolate(); 10145 if (accessor->IsNull(isolate)) { 10146 return isolate->factory()->undefined_value(); 10147 } 10148 return handle(accessor, isolate); 10149 } 10150 10151 Handle<DeoptimizationInputData> DeoptimizationInputData::New( 10152 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) { 10153 return Handle<DeoptimizationInputData>::cast( 10154 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count), 10155 pretenure)); 10156 } 10157 10158 10159 Handle<DeoptimizationOutputData> DeoptimizationOutputData::New( 10160 Isolate* isolate, 10161 int number_of_deopt_points, 10162 PretenureFlag pretenure) { 10163 Handle<FixedArray> result; 10164 if (number_of_deopt_points == 0) { 10165 result = isolate->factory()->empty_fixed_array(); 10166 } else { 10167 result = isolate->factory()->NewFixedArray( 10168 LengthOfFixedArray(number_of_deopt_points), pretenure); 10169 } 10170 return Handle<DeoptimizationOutputData>::cast(result); 10171 } 10172 10173 SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) { 10174 if (index == -1) { 10175 return SharedFunctionInfo::cast(SharedFunctionInfo()); 10176 } else { 10177 return SharedFunctionInfo::cast(LiteralArray()->get(index)); 10178 } 10179 } 10180 10181 int HandlerTable::LookupRange(int pc_offset, int* data_out, 10182 CatchPrediction* prediction_out) { 10183 int innermost_handler = -1; 10184 #ifdef DEBUG 10185 // Assuming that ranges are well nested, we don't need to track the innermost 10186 // offsets. This is just to verify that the table is actually well nested. 10187 int innermost_start = std::numeric_limits<int>::min(); 10188 int innermost_end = std::numeric_limits<int>::max(); 10189 #endif 10190 for (int i = 0; i < length(); i += kRangeEntrySize) { 10191 int start_offset = Smi::cast(get(i + kRangeStartIndex))->value(); 10192 int end_offset = Smi::cast(get(i + kRangeEndIndex))->value(); 10193 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value(); 10194 int handler_offset = HandlerOffsetField::decode(handler_field); 10195 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 10196 int handler_data = Smi::cast(get(i + kRangeDataIndex))->value(); 10197 if (pc_offset >= start_offset && pc_offset < end_offset) { 10198 DCHECK_GE(start_offset, innermost_start); 10199 DCHECK_LT(end_offset, innermost_end); 10200 innermost_handler = handler_offset; 10201 #ifdef DEBUG 10202 innermost_start = start_offset; 10203 innermost_end = end_offset; 10204 #endif 10205 if (data_out) *data_out = handler_data; 10206 if (prediction_out) *prediction_out = prediction; 10207 } 10208 } 10209 return innermost_handler; 10210 } 10211 10212 10213 // TODO(turbofan): Make sure table is sorted and use binary search. 10214 int HandlerTable::LookupReturn(int pc_offset) { 10215 for (int i = 0; i < length(); i += kReturnEntrySize) { 10216 int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value(); 10217 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value(); 10218 if (pc_offset == return_offset) { 10219 return HandlerOffsetField::decode(handler_field); 10220 } 10221 } 10222 return -1; 10223 } 10224 10225 10226 #ifdef DEBUG 10227 bool DescriptorArray::IsEqualTo(DescriptorArray* other) { 10228 if (IsEmpty()) return other->IsEmpty(); 10229 if (other->IsEmpty()) return false; 10230 if (length() != other->length()) return false; 10231 for (int i = 0; i < length(); ++i) { 10232 if (get(i) != other->get(i)) return false; 10233 } 10234 return true; 10235 } 10236 #endif 10237 10238 // static 10239 Handle<String> String::Trim(Handle<String> string, TrimMode mode) { 10240 Isolate* const isolate = string->GetIsolate(); 10241 string = String::Flatten(string); 10242 int const length = string->length(); 10243 10244 // Perform left trimming if requested. 10245 int left = 0; 10246 UnicodeCache* unicode_cache = isolate->unicode_cache(); 10247 if (mode == kTrim || mode == kTrimLeft) { 10248 while (left < length && 10249 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { 10250 left++; 10251 } 10252 } 10253 10254 // Perform right trimming if requested. 10255 int right = length; 10256 if (mode == kTrim || mode == kTrimRight) { 10257 while ( 10258 right > left && 10259 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { 10260 right--; 10261 } 10262 } 10263 10264 return isolate->factory()->NewSubString(string, left, right); 10265 } 10266 10267 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); } 10268 10269 // static 10270 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { 10271 if (name->IsString()) return Handle<String>::cast(name); 10272 // ES6 section 9.2.11 SetFunctionName, step 4. 10273 Isolate* const isolate = name->GetIsolate(); 10274 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); 10275 if (description->IsUndefined(isolate)) { 10276 return isolate->factory()->empty_string(); 10277 } 10278 IncrementalStringBuilder builder(isolate); 10279 builder.AppendCharacter('['); 10280 builder.AppendString(Handle<String>::cast(description)); 10281 builder.AppendCharacter(']'); 10282 return builder.Finish(); 10283 } 10284 10285 // static 10286 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name, 10287 Handle<String> prefix) { 10288 Handle<String> name_string; 10289 Isolate* const isolate = name->GetIsolate(); 10290 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name), 10291 String); 10292 IncrementalStringBuilder builder(isolate); 10293 builder.AppendString(prefix); 10294 builder.AppendCharacter(' '); 10295 builder.AppendString(name_string); 10296 return builder.Finish(); 10297 } 10298 10299 namespace { 10300 10301 bool AreDigits(const uint8_t* s, int from, int to) { 10302 for (int i = from; i < to; i++) { 10303 if (s[i] < '0' || s[i] > '9') return false; 10304 } 10305 10306 return true; 10307 } 10308 10309 10310 int ParseDecimalInteger(const uint8_t* s, int from, int to) { 10311 DCHECK(to - from < 10); // Overflow is not possible. 10312 DCHECK(from < to); 10313 int d = s[from] - '0'; 10314 10315 for (int i = from + 1; i < to; i++) { 10316 d = 10 * d + (s[i] - '0'); 10317 } 10318 10319 return d; 10320 } 10321 10322 } // namespace 10323 10324 10325 // static 10326 Handle<Object> String::ToNumber(Handle<String> subject) { 10327 Isolate* const isolate = subject->GetIsolate(); 10328 10329 // Flatten {subject} string first. 10330 subject = String::Flatten(subject); 10331 10332 // Fast array index case. 10333 uint32_t index; 10334 if (subject->AsArrayIndex(&index)) { 10335 return isolate->factory()->NewNumberFromUint(index); 10336 } 10337 10338 // Fast case: short integer or some sorts of junk values. 10339 if (subject->IsSeqOneByteString()) { 10340 int len = subject->length(); 10341 if (len == 0) return handle(Smi::kZero, isolate); 10342 10343 DisallowHeapAllocation no_gc; 10344 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars(); 10345 bool minus = (data[0] == '-'); 10346 int start_pos = (minus ? 1 : 0); 10347 10348 if (start_pos == len) { 10349 return isolate->factory()->nan_value(); 10350 } else if (data[start_pos] > '9') { 10351 // Fast check for a junk value. A valid string may start from a 10352 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit 10353 // or the 'I' character ('Infinity'). All of that have codes not greater 10354 // than '9' except 'I' and . 10355 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { 10356 return isolate->factory()->nan_value(); 10357 } 10358 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 10359 // The maximal/minimal smi has 10 digits. If the string has less digits 10360 // we know it will fit into the smi-data type. 10361 int d = ParseDecimalInteger(data, start_pos, len); 10362 if (minus) { 10363 if (d == 0) return isolate->factory()->minus_zero_value(); 10364 d = -d; 10365 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize && 10366 (len == 1 || data[0] != '0')) { 10367 // String hash is not calculated yet but all the data are present. 10368 // Update the hash field to speed up sequential convertions. 10369 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); 10370 #ifdef DEBUG 10371 subject->Hash(); // Force hash calculation. 10372 DCHECK_EQ(static_cast<int>(subject->hash_field()), 10373 static_cast<int>(hash)); 10374 #endif 10375 subject->set_hash_field(hash); 10376 } 10377 return handle(Smi::FromInt(d), isolate); 10378 } 10379 } 10380 10381 // Slower case. 10382 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY; 10383 return isolate->factory()->NewNumber( 10384 StringToDouble(isolate->unicode_cache(), subject, flags)); 10385 } 10386 10387 10388 String::FlatContent String::GetFlatContent() { 10389 DCHECK(!AllowHeapAllocation::IsAllowed()); 10390 int length = this->length(); 10391 StringShape shape(this); 10392 String* string = this; 10393 int offset = 0; 10394 if (shape.representation_tag() == kConsStringTag) { 10395 ConsString* cons = ConsString::cast(string); 10396 if (cons->second()->length() != 0) { 10397 return FlatContent(); 10398 } 10399 string = cons->first(); 10400 shape = StringShape(string); 10401 } else if (shape.representation_tag() == kSlicedStringTag) { 10402 SlicedString* slice = SlicedString::cast(string); 10403 offset = slice->offset(); 10404 string = slice->parent(); 10405 shape = StringShape(string); 10406 DCHECK(shape.representation_tag() != kConsStringTag && 10407 shape.representation_tag() != kSlicedStringTag); 10408 } 10409 if (shape.representation_tag() == kThinStringTag) { 10410 ThinString* thin = ThinString::cast(string); 10411 string = thin->actual(); 10412 shape = StringShape(string); 10413 DCHECK(!shape.IsCons()); 10414 DCHECK(!shape.IsSliced()); 10415 } 10416 if (shape.encoding_tag() == kOneByteStringTag) { 10417 const uint8_t* start; 10418 if (shape.representation_tag() == kSeqStringTag) { 10419 start = SeqOneByteString::cast(string)->GetChars(); 10420 } else { 10421 start = ExternalOneByteString::cast(string)->GetChars(); 10422 } 10423 return FlatContent(start + offset, length); 10424 } else { 10425 DCHECK(shape.encoding_tag() == kTwoByteStringTag); 10426 const uc16* start; 10427 if (shape.representation_tag() == kSeqStringTag) { 10428 start = SeqTwoByteString::cast(string)->GetChars(); 10429 } else { 10430 start = ExternalTwoByteString::cast(string)->GetChars(); 10431 } 10432 return FlatContent(start + offset, length); 10433 } 10434 } 10435 10436 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls, 10437 RobustnessFlag robust_flag, 10438 int offset, int length, 10439 int* length_return) { 10440 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { 10441 return std::unique_ptr<char[]>(); 10442 } 10443 // Negative length means the to the end of the string. 10444 if (length < 0) length = kMaxInt - offset; 10445 10446 // Compute the size of the UTF-8 string. Start at the specified offset. 10447 StringCharacterStream stream(this, offset); 10448 int character_position = offset; 10449 int utf8_bytes = 0; 10450 int last = unibrow::Utf16::kNoPreviousCharacter; 10451 while (stream.HasMore() && character_position++ < offset + length) { 10452 uint16_t character = stream.GetNext(); 10453 utf8_bytes += unibrow::Utf8::Length(character, last); 10454 last = character; 10455 } 10456 10457 if (length_return) { 10458 *length_return = utf8_bytes; 10459 } 10460 10461 char* result = NewArray<char>(utf8_bytes + 1); 10462 10463 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset. 10464 stream.Reset(this, offset); 10465 character_position = offset; 10466 int utf8_byte_position = 0; 10467 last = unibrow::Utf16::kNoPreviousCharacter; 10468 while (stream.HasMore() && character_position++ < offset + length) { 10469 uint16_t character = stream.GetNext(); 10470 if (allow_nulls == DISALLOW_NULLS && character == 0) { 10471 character = ' '; 10472 } 10473 utf8_byte_position += 10474 unibrow::Utf8::Encode(result + utf8_byte_position, character, last); 10475 last = character; 10476 } 10477 result[utf8_byte_position] = 0; 10478 return std::unique_ptr<char[]>(result); 10479 } 10480 10481 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls, 10482 RobustnessFlag robust_flag, 10483 int* length_return) { 10484 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); 10485 } 10486 10487 10488 const uc16* String::GetTwoByteData(unsigned start) { 10489 DCHECK(!IsOneByteRepresentationUnderneath()); 10490 switch (StringShape(this).representation_tag()) { 10491 case kSeqStringTag: 10492 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); 10493 case kExternalStringTag: 10494 return ExternalTwoByteString::cast(this)-> 10495 ExternalTwoByteStringGetData(start); 10496 case kSlicedStringTag: { 10497 SlicedString* slice = SlicedString::cast(this); 10498 return slice->parent()->GetTwoByteData(start + slice->offset()); 10499 } 10500 case kConsStringTag: 10501 case kThinStringTag: 10502 UNREACHABLE(); 10503 return NULL; 10504 } 10505 UNREACHABLE(); 10506 return NULL; 10507 } 10508 10509 10510 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { 10511 return reinterpret_cast<uc16*>( 10512 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start; 10513 } 10514 10515 10516 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) { 10517 Relocatable* current = isolate->relocatable_top(); 10518 while (current != NULL) { 10519 current->PostGarbageCollection(); 10520 current = current->prev_; 10521 } 10522 } 10523 10524 10525 // Reserve space for statics needing saving and restoring. 10526 int Relocatable::ArchiveSpacePerThread() { 10527 return sizeof(Relocatable*); // NOLINT 10528 } 10529 10530 10531 // Archive statics that are thread-local. 10532 char* Relocatable::ArchiveState(Isolate* isolate, char* to) { 10533 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top(); 10534 isolate->set_relocatable_top(NULL); 10535 return to + ArchiveSpacePerThread(); 10536 } 10537 10538 10539 // Restore statics that are thread-local. 10540 char* Relocatable::RestoreState(Isolate* isolate, char* from) { 10541 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from)); 10542 return from + ArchiveSpacePerThread(); 10543 } 10544 10545 10546 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) { 10547 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage); 10548 Iterate(v, top); 10549 return thread_storage + ArchiveSpacePerThread(); 10550 } 10551 10552 10553 void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) { 10554 Iterate(v, isolate->relocatable_top()); 10555 } 10556 10557 10558 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) { 10559 Relocatable* current = top; 10560 while (current != NULL) { 10561 current->IterateInstance(v); 10562 current = current->prev_; 10563 } 10564 } 10565 10566 10567 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str) 10568 : Relocatable(isolate), 10569 str_(str.location()), 10570 length_(str->length()) { 10571 PostGarbageCollection(); 10572 } 10573 10574 10575 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input) 10576 : Relocatable(isolate), 10577 str_(0), 10578 is_one_byte_(true), 10579 length_(input.length()), 10580 start_(input.start()) {} 10581 10582 10583 void FlatStringReader::PostGarbageCollection() { 10584 if (str_ == NULL) return; 10585 Handle<String> str(str_); 10586 DCHECK(str->IsFlat()); 10587 DisallowHeapAllocation no_gc; 10588 // This does not actually prevent the vector from being relocated later. 10589 String::FlatContent content = str->GetFlatContent(); 10590 DCHECK(content.IsFlat()); 10591 is_one_byte_ = content.IsOneByte(); 10592 if (is_one_byte_) { 10593 start_ = content.ToOneByteVector().start(); 10594 } else { 10595 start_ = content.ToUC16Vector().start(); 10596 } 10597 } 10598 10599 10600 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) { 10601 DCHECK(cons_string != NULL); 10602 root_ = cons_string; 10603 consumed_ = offset; 10604 // Force stack blown condition to trigger restart. 10605 depth_ = 1; 10606 maximum_depth_ = kStackSize + depth_; 10607 DCHECK(StackBlown()); 10608 } 10609 10610 10611 String* ConsStringIterator::Continue(int* offset_out) { 10612 DCHECK(depth_ != 0); 10613 DCHECK_EQ(0, *offset_out); 10614 bool blew_stack = StackBlown(); 10615 String* string = NULL; 10616 // Get the next leaf if there is one. 10617 if (!blew_stack) string = NextLeaf(&blew_stack); 10618 // Restart search from root. 10619 if (blew_stack) { 10620 DCHECK(string == NULL); 10621 string = Search(offset_out); 10622 } 10623 // Ensure future calls return null immediately. 10624 if (string == NULL) Reset(NULL); 10625 return string; 10626 } 10627 10628 10629 String* ConsStringIterator::Search(int* offset_out) { 10630 ConsString* cons_string = root_; 10631 // Reset the stack, pushing the root string. 10632 depth_ = 1; 10633 maximum_depth_ = 1; 10634 frames_[0] = cons_string; 10635 const int consumed = consumed_; 10636 int offset = 0; 10637 while (true) { 10638 // Loop until the string is found which contains the target offset. 10639 String* string = cons_string->first(); 10640 int length = string->length(); 10641 int32_t type; 10642 if (consumed < offset + length) { 10643 // Target offset is in the left branch. 10644 // Keep going if we're still in a ConString. 10645 type = string->map()->instance_type(); 10646 if ((type & kStringRepresentationMask) == kConsStringTag) { 10647 cons_string = ConsString::cast(string); 10648 PushLeft(cons_string); 10649 continue; 10650 } 10651 // Tell the stack we're done descending. 10652 AdjustMaximumDepth(); 10653 } else { 10654 // Descend right. 10655 // Update progress through the string. 10656 offset += length; 10657 // Keep going if we're still in a ConString. 10658 string = cons_string->second(); 10659 type = string->map()->instance_type(); 10660 if ((type & kStringRepresentationMask) == kConsStringTag) { 10661 cons_string = ConsString::cast(string); 10662 PushRight(cons_string); 10663 continue; 10664 } 10665 // Need this to be updated for the current string. 10666 length = string->length(); 10667 // Account for the possibility of an empty right leaf. 10668 // This happens only if we have asked for an offset outside the string. 10669 if (length == 0) { 10670 // Reset so future operations will return null immediately. 10671 Reset(NULL); 10672 return NULL; 10673 } 10674 // Tell the stack we're done descending. 10675 AdjustMaximumDepth(); 10676 // Pop stack so next iteration is in correct place. 10677 Pop(); 10678 } 10679 DCHECK(length != 0); 10680 // Adjust return values and exit. 10681 consumed_ = offset + length; 10682 *offset_out = consumed - offset; 10683 return string; 10684 } 10685 UNREACHABLE(); 10686 return NULL; 10687 } 10688 10689 10690 String* ConsStringIterator::NextLeaf(bool* blew_stack) { 10691 while (true) { 10692 // Tree traversal complete. 10693 if (depth_ == 0) { 10694 *blew_stack = false; 10695 return NULL; 10696 } 10697 // We've lost track of higher nodes. 10698 if (StackBlown()) { 10699 *blew_stack = true; 10700 return NULL; 10701 } 10702 // Go right. 10703 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)]; 10704 String* string = cons_string->second(); 10705 int32_t type = string->map()->instance_type(); 10706 if ((type & kStringRepresentationMask) != kConsStringTag) { 10707 // Pop stack so next iteration is in correct place. 10708 Pop(); 10709 int length = string->length(); 10710 // Could be a flattened ConsString. 10711 if (length == 0) continue; 10712 consumed_ += length; 10713 return string; 10714 } 10715 cons_string = ConsString::cast(string); 10716 PushRight(cons_string); 10717 // Need to traverse all the way left. 10718 while (true) { 10719 // Continue left. 10720 string = cons_string->first(); 10721 type = string->map()->instance_type(); 10722 if ((type & kStringRepresentationMask) != kConsStringTag) { 10723 AdjustMaximumDepth(); 10724 int length = string->length(); 10725 if (length == 0) break; // Skip empty left-hand sides of ConsStrings. 10726 consumed_ += length; 10727 return string; 10728 } 10729 cons_string = ConsString::cast(string); 10730 PushLeft(cons_string); 10731 } 10732 } 10733 UNREACHABLE(); 10734 return NULL; 10735 } 10736 10737 10738 uint16_t ConsString::ConsStringGet(int index) { 10739 DCHECK(index >= 0 && index < this->length()); 10740 10741 // Check for a flattened cons string 10742 if (second()->length() == 0) { 10743 String* left = first(); 10744 return left->Get(index); 10745 } 10746 10747 String* string = String::cast(this); 10748 10749 while (true) { 10750 if (StringShape(string).IsCons()) { 10751 ConsString* cons_string = ConsString::cast(string); 10752 String* left = cons_string->first(); 10753 if (left->length() > index) { 10754 string = left; 10755 } else { 10756 index -= left->length(); 10757 string = cons_string->second(); 10758 } 10759 } else { 10760 return string->Get(index); 10761 } 10762 } 10763 10764 UNREACHABLE(); 10765 return 0; 10766 } 10767 10768 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); } 10769 10770 uint16_t SlicedString::SlicedStringGet(int index) { 10771 return parent()->Get(offset() + index); 10772 } 10773 10774 10775 template <typename sinkchar> 10776 void String::WriteToFlat(String* src, 10777 sinkchar* sink, 10778 int f, 10779 int t) { 10780 String* source = src; 10781 int from = f; 10782 int to = t; 10783 while (true) { 10784 DCHECK(0 <= from && from <= to && to <= source->length()); 10785 switch (StringShape(source).full_representation_tag()) { 10786 case kOneByteStringTag | kExternalStringTag: { 10787 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from, 10788 to - from); 10789 return; 10790 } 10791 case kTwoByteStringTag | kExternalStringTag: { 10792 const uc16* data = 10793 ExternalTwoByteString::cast(source)->GetChars(); 10794 CopyChars(sink, 10795 data + from, 10796 to - from); 10797 return; 10798 } 10799 case kOneByteStringTag | kSeqStringTag: { 10800 CopyChars(sink, 10801 SeqOneByteString::cast(source)->GetChars() + from, 10802 to - from); 10803 return; 10804 } 10805 case kTwoByteStringTag | kSeqStringTag: { 10806 CopyChars(sink, 10807 SeqTwoByteString::cast(source)->GetChars() + from, 10808 to - from); 10809 return; 10810 } 10811 case kOneByteStringTag | kConsStringTag: 10812 case kTwoByteStringTag | kConsStringTag: { 10813 ConsString* cons_string = ConsString::cast(source); 10814 String* first = cons_string->first(); 10815 int boundary = first->length(); 10816 if (to - boundary >= boundary - from) { 10817 // Right hand side is longer. Recurse over left. 10818 if (from < boundary) { 10819 WriteToFlat(first, sink, from, boundary); 10820 if (from == 0 && cons_string->second() == first) { 10821 CopyChars(sink + boundary, sink, boundary); 10822 return; 10823 } 10824 sink += boundary - from; 10825 from = 0; 10826 } else { 10827 from -= boundary; 10828 } 10829 to -= boundary; 10830 source = cons_string->second(); 10831 } else { 10832 // Left hand side is longer. Recurse over right. 10833 if (to > boundary) { 10834 String* second = cons_string->second(); 10835 // When repeatedly appending to a string, we get a cons string that 10836 // is unbalanced to the left, a list, essentially. We inline the 10837 // common case of sequential one-byte right child. 10838 if (to - boundary == 1) { 10839 sink[boundary - from] = static_cast<sinkchar>(second->Get(0)); 10840 } else if (second->IsSeqOneByteString()) { 10841 CopyChars(sink + boundary - from, 10842 SeqOneByteString::cast(second)->GetChars(), 10843 to - boundary); 10844 } else { 10845 WriteToFlat(second, 10846 sink + boundary - from, 10847 0, 10848 to - boundary); 10849 } 10850 to = boundary; 10851 } 10852 source = first; 10853 } 10854 break; 10855 } 10856 case kOneByteStringTag | kSlicedStringTag: 10857 case kTwoByteStringTag | kSlicedStringTag: { 10858 SlicedString* slice = SlicedString::cast(source); 10859 unsigned offset = slice->offset(); 10860 WriteToFlat(slice->parent(), sink, from + offset, to + offset); 10861 return; 10862 } 10863 case kOneByteStringTag | kThinStringTag: 10864 case kTwoByteStringTag | kThinStringTag: 10865 source = ThinString::cast(source)->actual(); 10866 break; 10867 } 10868 } 10869 } 10870 10871 10872 10873 template <typename SourceChar> 10874 static void CalculateLineEndsImpl(Isolate* isolate, 10875 List<int>* line_ends, 10876 Vector<const SourceChar> src, 10877 bool include_ending_line) { 10878 const int src_len = src.length(); 10879 UnicodeCache* cache = isolate->unicode_cache(); 10880 for (int i = 0; i < src_len - 1; i++) { 10881 SourceChar current = src[i]; 10882 SourceChar next = src[i + 1]; 10883 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i); 10884 } 10885 10886 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) { 10887 line_ends->Add(src_len - 1); 10888 } 10889 if (include_ending_line) { 10890 // Include one character beyond the end of script. The rewriter uses that 10891 // position for the implicit return statement. 10892 line_ends->Add(src_len); 10893 } 10894 } 10895 10896 10897 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src, 10898 bool include_ending_line) { 10899 src = Flatten(src); 10900 // Rough estimate of line count based on a roughly estimated average 10901 // length of (unpacked) code. 10902 int line_count_estimate = src->length() >> 4; 10903 List<int> line_ends(line_count_estimate); 10904 Isolate* isolate = src->GetIsolate(); 10905 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid. 10906 // Dispatch on type of strings. 10907 String::FlatContent content = src->GetFlatContent(); 10908 DCHECK(content.IsFlat()); 10909 if (content.IsOneByte()) { 10910 CalculateLineEndsImpl(isolate, 10911 &line_ends, 10912 content.ToOneByteVector(), 10913 include_ending_line); 10914 } else { 10915 CalculateLineEndsImpl(isolate, 10916 &line_ends, 10917 content.ToUC16Vector(), 10918 include_ending_line); 10919 } 10920 } 10921 int line_count = line_ends.length(); 10922 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count); 10923 for (int i = 0; i < line_count; i++) { 10924 array->set(i, Smi::FromInt(line_ends[i])); 10925 } 10926 return array; 10927 } 10928 10929 10930 // Compares the contents of two strings by reading and comparing 10931 // int-sized blocks of characters. 10932 template <typename Char> 10933 static inline bool CompareRawStringContents(const Char* const a, 10934 const Char* const b, 10935 int length) { 10936 return CompareChars(a, b, length) == 0; 10937 } 10938 10939 10940 template<typename Chars1, typename Chars2> 10941 class RawStringComparator : public AllStatic { 10942 public: 10943 static inline bool compare(const Chars1* a, const Chars2* b, int len) { 10944 DCHECK(sizeof(Chars1) != sizeof(Chars2)); 10945 for (int i = 0; i < len; i++) { 10946 if (a[i] != b[i]) { 10947 return false; 10948 } 10949 } 10950 return true; 10951 } 10952 }; 10953 10954 10955 template<> 10956 class RawStringComparator<uint16_t, uint16_t> { 10957 public: 10958 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) { 10959 return CompareRawStringContents(a, b, len); 10960 } 10961 }; 10962 10963 10964 template<> 10965 class RawStringComparator<uint8_t, uint8_t> { 10966 public: 10967 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) { 10968 return CompareRawStringContents(a, b, len); 10969 } 10970 }; 10971 10972 10973 class StringComparator { 10974 class State { 10975 public: 10976 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {} 10977 10978 void Init(String* string) { 10979 ConsString* cons_string = String::VisitFlat(this, string); 10980 iter_.Reset(cons_string); 10981 if (cons_string != NULL) { 10982 int offset; 10983 string = iter_.Next(&offset); 10984 String::VisitFlat(this, string, offset); 10985 } 10986 } 10987 10988 inline void VisitOneByteString(const uint8_t* chars, int length) { 10989 is_one_byte_ = true; 10990 buffer8_ = chars; 10991 length_ = length; 10992 } 10993 10994 inline void VisitTwoByteString(const uint16_t* chars, int length) { 10995 is_one_byte_ = false; 10996 buffer16_ = chars; 10997 length_ = length; 10998 } 10999 11000 void Advance(int consumed) { 11001 DCHECK(consumed <= length_); 11002 // Still in buffer. 11003 if (length_ != consumed) { 11004 if (is_one_byte_) { 11005 buffer8_ += consumed; 11006 } else { 11007 buffer16_ += consumed; 11008 } 11009 length_ -= consumed; 11010 return; 11011 } 11012 // Advance state. 11013 int offset; 11014 String* next = iter_.Next(&offset); 11015 DCHECK_EQ(0, offset); 11016 DCHECK(next != NULL); 11017 String::VisitFlat(this, next); 11018 } 11019 11020 ConsStringIterator iter_; 11021 bool is_one_byte_; 11022 int length_; 11023 union { 11024 const uint8_t* buffer8_; 11025 const uint16_t* buffer16_; 11026 }; 11027 11028 private: 11029 DISALLOW_COPY_AND_ASSIGN(State); 11030 }; 11031 11032 public: 11033 inline StringComparator() {} 11034 11035 template<typename Chars1, typename Chars2> 11036 static inline bool Equals(State* state_1, State* state_2, int to_check) { 11037 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_); 11038 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_); 11039 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check); 11040 } 11041 11042 bool Equals(String* string_1, String* string_2) { 11043 int length = string_1->length(); 11044 state_1_.Init(string_1); 11045 state_2_.Init(string_2); 11046 while (true) { 11047 int to_check = Min(state_1_.length_, state_2_.length_); 11048 DCHECK(to_check > 0 && to_check <= length); 11049 bool is_equal; 11050 if (state_1_.is_one_byte_) { 11051 if (state_2_.is_one_byte_) { 11052 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check); 11053 } else { 11054 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check); 11055 } 11056 } else { 11057 if (state_2_.is_one_byte_) { 11058 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check); 11059 } else { 11060 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check); 11061 } 11062 } 11063 // Looping done. 11064 if (!is_equal) return false; 11065 length -= to_check; 11066 // Exit condition. Strings are equal. 11067 if (length == 0) return true; 11068 state_1_.Advance(to_check); 11069 state_2_.Advance(to_check); 11070 } 11071 } 11072 11073 private: 11074 State state_1_; 11075 State state_2_; 11076 11077 DISALLOW_COPY_AND_ASSIGN(StringComparator); 11078 }; 11079 11080 11081 bool String::SlowEquals(String* other) { 11082 DisallowHeapAllocation no_gc; 11083 // Fast check: negative check with lengths. 11084 int len = length(); 11085 if (len != other->length()) return false; 11086 if (len == 0) return true; 11087 11088 // Fast check: if at least one ThinString is involved, dereference it/them 11089 // and restart. 11090 if (this->IsThinString() || other->IsThinString()) { 11091 if (other->IsThinString()) other = ThinString::cast(other)->actual(); 11092 if (this->IsThinString()) { 11093 return ThinString::cast(this)->actual()->Equals(other); 11094 } else { 11095 return this->Equals(other); 11096 } 11097 } 11098 11099 // Fast check: if hash code is computed for both strings 11100 // a fast negative check can be performed. 11101 if (HasHashCode() && other->HasHashCode()) { 11102 #ifdef ENABLE_SLOW_DCHECKS 11103 if (FLAG_enable_slow_asserts) { 11104 if (Hash() != other->Hash()) { 11105 bool found_difference = false; 11106 for (int i = 0; i < len; i++) { 11107 if (Get(i) != other->Get(i)) { 11108 found_difference = true; 11109 break; 11110 } 11111 } 11112 DCHECK(found_difference); 11113 } 11114 } 11115 #endif 11116 if (Hash() != other->Hash()) return false; 11117 } 11118 11119 // We know the strings are both non-empty. Compare the first chars 11120 // before we try to flatten the strings. 11121 if (this->Get(0) != other->Get(0)) return false; 11122 11123 if (IsSeqOneByteString() && other->IsSeqOneByteString()) { 11124 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars(); 11125 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(); 11126 return CompareRawStringContents(str1, str2, len); 11127 } 11128 11129 StringComparator comparator; 11130 return comparator.Equals(this, other); 11131 } 11132 11133 11134 bool String::SlowEquals(Handle<String> one, Handle<String> two) { 11135 // Fast check: negative check with lengths. 11136 int one_length = one->length(); 11137 if (one_length != two->length()) return false; 11138 if (one_length == 0) return true; 11139 11140 // Fast check: if at least one ThinString is involved, dereference it/them 11141 // and restart. 11142 if (one->IsThinString() || two->IsThinString()) { 11143 if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual()); 11144 if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual()); 11145 return String::Equals(one, two); 11146 } 11147 11148 // Fast check: if hash code is computed for both strings 11149 // a fast negative check can be performed. 11150 if (one->HasHashCode() && two->HasHashCode()) { 11151 #ifdef ENABLE_SLOW_DCHECKS 11152 if (FLAG_enable_slow_asserts) { 11153 if (one->Hash() != two->Hash()) { 11154 bool found_difference = false; 11155 for (int i = 0; i < one_length; i++) { 11156 if (one->Get(i) != two->Get(i)) { 11157 found_difference = true; 11158 break; 11159 } 11160 } 11161 DCHECK(found_difference); 11162 } 11163 } 11164 #endif 11165 if (one->Hash() != two->Hash()) return false; 11166 } 11167 11168 // We know the strings are both non-empty. Compare the first chars 11169 // before we try to flatten the strings. 11170 if (one->Get(0) != two->Get(0)) return false; 11171 11172 one = String::Flatten(one); 11173 two = String::Flatten(two); 11174 11175 DisallowHeapAllocation no_gc; 11176 String::FlatContent flat1 = one->GetFlatContent(); 11177 String::FlatContent flat2 = two->GetFlatContent(); 11178 11179 if (flat1.IsOneByte() && flat2.IsOneByte()) { 11180 return CompareRawStringContents(flat1.ToOneByteVector().start(), 11181 flat2.ToOneByteVector().start(), 11182 one_length); 11183 } else { 11184 for (int i = 0; i < one_length; i++) { 11185 if (flat1.Get(i) != flat2.Get(i)) return false; 11186 } 11187 return true; 11188 } 11189 } 11190 11191 11192 // static 11193 ComparisonResult String::Compare(Handle<String> x, Handle<String> y) { 11194 // A few fast case tests before we flatten. 11195 if (x.is_identical_to(y)) { 11196 return ComparisonResult::kEqual; 11197 } else if (y->length() == 0) { 11198 return x->length() == 0 ? ComparisonResult::kEqual 11199 : ComparisonResult::kGreaterThan; 11200 } else if (x->length() == 0) { 11201 return ComparisonResult::kLessThan; 11202 } 11203 11204 int const d = x->Get(0) - y->Get(0); 11205 if (d < 0) { 11206 return ComparisonResult::kLessThan; 11207 } else if (d > 0) { 11208 return ComparisonResult::kGreaterThan; 11209 } 11210 11211 // Slow case. 11212 x = String::Flatten(x); 11213 y = String::Flatten(y); 11214 11215 DisallowHeapAllocation no_gc; 11216 ComparisonResult result = ComparisonResult::kEqual; 11217 int prefix_length = x->length(); 11218 if (y->length() < prefix_length) { 11219 prefix_length = y->length(); 11220 result = ComparisonResult::kGreaterThan; 11221 } else if (y->length() > prefix_length) { 11222 result = ComparisonResult::kLessThan; 11223 } 11224 int r; 11225 String::FlatContent x_content = x->GetFlatContent(); 11226 String::FlatContent y_content = y->GetFlatContent(); 11227 if (x_content.IsOneByte()) { 11228 Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); 11229 if (y_content.IsOneByte()) { 11230 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 11231 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11232 } else { 11233 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 11234 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11235 } 11236 } else { 11237 Vector<const uc16> x_chars = x_content.ToUC16Vector(); 11238 if (y_content.IsOneByte()) { 11239 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 11240 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11241 } else { 11242 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 11243 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11244 } 11245 } 11246 if (r < 0) { 11247 result = ComparisonResult::kLessThan; 11248 } else if (r > 0) { 11249 result = ComparisonResult::kGreaterThan; 11250 } 11251 return result; 11252 } 11253 11254 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver, 11255 Handle<Object> search, Handle<Object> position) { 11256 if (receiver->IsNullOrUndefined(isolate)) { 11257 THROW_NEW_ERROR_RETURN_FAILURE( 11258 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, 11259 isolate->factory()->NewStringFromAsciiChecked( 11260 "String.prototype.indexOf"))); 11261 } 11262 Handle<String> receiver_string; 11263 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string, 11264 Object::ToString(isolate, receiver)); 11265 11266 Handle<String> search_string; 11267 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string, 11268 Object::ToString(isolate, search)); 11269 11270 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 11271 Object::ToInteger(isolate, position)); 11272 11273 uint32_t index = receiver_string->ToValidIndex(*position); 11274 return Smi::FromInt( 11275 String::IndexOf(isolate, receiver_string, search_string, index)); 11276 } 11277 11278 namespace { 11279 11280 template <typename T> 11281 int SearchString(Isolate* isolate, String::FlatContent receiver_content, 11282 Vector<T> pat_vector, int start_index) { 11283 if (receiver_content.IsOneByte()) { 11284 return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector, 11285 start_index); 11286 } 11287 return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector, 11288 start_index); 11289 } 11290 11291 } // namespace 11292 11293 int String::IndexOf(Isolate* isolate, Handle<String> receiver, 11294 Handle<String> search, int start_index) { 11295 DCHECK(0 <= start_index); 11296 DCHECK(start_index <= receiver->length()); 11297 11298 uint32_t search_length = search->length(); 11299 if (search_length == 0) return start_index; 11300 11301 uint32_t receiver_length = receiver->length(); 11302 if (start_index + search_length > receiver_length) return -1; 11303 11304 receiver = String::Flatten(receiver); 11305 search = String::Flatten(search); 11306 11307 DisallowHeapAllocation no_gc; // ensure vectors stay valid 11308 // Extract flattened substrings of cons strings before getting encoding. 11309 String::FlatContent receiver_content = receiver->GetFlatContent(); 11310 String::FlatContent search_content = search->GetFlatContent(); 11311 11312 // dispatch on type of strings 11313 if (search_content.IsOneByte()) { 11314 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector(); 11315 return SearchString<const uint8_t>(isolate, receiver_content, pat_vector, 11316 start_index); 11317 } 11318 Vector<const uc16> pat_vector = search_content.ToUC16Vector(); 11319 return SearchString<const uc16>(isolate, receiver_content, pat_vector, 11320 start_index); 11321 } 11322 11323 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match, 11324 Handle<String> replacement) { 11325 Factory* factory = isolate->factory(); 11326 11327 const int replacement_length = replacement->length(); 11328 const int captures_length = match->CaptureCount(); 11329 11330 replacement = String::Flatten(replacement); 11331 11332 Handle<String> dollar_string = 11333 factory->LookupSingleCharacterStringFromCode('$'); 11334 int next = String::IndexOf(isolate, replacement, dollar_string, 0); 11335 if (next < 0) { 11336 return replacement; 11337 } 11338 11339 IncrementalStringBuilder builder(isolate); 11340 11341 if (next > 0) { 11342 builder.AppendString(factory->NewSubString(replacement, 0, next)); 11343 } 11344 11345 while (true) { 11346 int pos = next + 1; 11347 if (pos < replacement_length) { 11348 const uint16_t peek = replacement->Get(pos); 11349 if (peek == '$') { // $$ 11350 pos++; 11351 builder.AppendCharacter('$'); 11352 } else if (peek == '&') { // $& - match 11353 pos++; 11354 builder.AppendString(match->GetMatch()); 11355 } else if (peek == '`') { // $` - prefix 11356 pos++; 11357 builder.AppendString(match->GetPrefix()); 11358 } else if (peek == '\'') { // $' - suffix 11359 pos++; 11360 builder.AppendString(match->GetSuffix()); 11361 } else if (peek >= '0' && peek <= '9') { 11362 // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99 11363 int scaled_index = (peek - '0'); 11364 int advance = 1; 11365 11366 if (pos + 1 < replacement_length) { 11367 const uint16_t next_peek = replacement->Get(pos + 1); 11368 if (next_peek >= '0' && next_peek <= '9') { 11369 const int new_scaled_index = scaled_index * 10 + (next_peek - '0'); 11370 if (new_scaled_index < captures_length) { 11371 scaled_index = new_scaled_index; 11372 advance = 2; 11373 } 11374 } 11375 } 11376 11377 if (scaled_index != 0 && scaled_index < captures_length) { 11378 bool capture_exists; 11379 Handle<String> capture; 11380 ASSIGN_RETURN_ON_EXCEPTION( 11381 isolate, capture, 11382 match->GetCapture(scaled_index, &capture_exists), String); 11383 if (capture_exists) builder.AppendString(capture); 11384 pos += advance; 11385 } else { 11386 builder.AppendCharacter('$'); 11387 } 11388 } else { 11389 builder.AppendCharacter('$'); 11390 } 11391 } else { 11392 builder.AppendCharacter('$'); 11393 } 11394 11395 // Go the the next $ in the replacement. 11396 next = String::IndexOf(isolate, replacement, dollar_string, pos); 11397 11398 // Return if there are no more $ characters in the replacement. If we 11399 // haven't reached the end, we need to append the suffix. 11400 if (next < 0) { 11401 if (pos < replacement_length) { 11402 builder.AppendString( 11403 factory->NewSubString(replacement, pos, replacement_length)); 11404 } 11405 return builder.Finish(); 11406 } 11407 11408 // Append substring between the previous and the next $ character. 11409 if (next > pos) { 11410 builder.AppendString(factory->NewSubString(replacement, pos, next)); 11411 } 11412 } 11413 11414 UNREACHABLE(); 11415 return MaybeHandle<String>(); 11416 } 11417 11418 namespace { // for String.Prototype.lastIndexOf 11419 11420 template <typename schar, typename pchar> 11421 int StringMatchBackwards(Vector<const schar> subject, 11422 Vector<const pchar> pattern, int idx) { 11423 int pattern_length = pattern.length(); 11424 DCHECK(pattern_length >= 1); 11425 DCHECK(idx + pattern_length <= subject.length()); 11426 11427 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 11428 for (int i = 0; i < pattern_length; i++) { 11429 uc16 c = pattern[i]; 11430 if (c > String::kMaxOneByteCharCode) { 11431 return -1; 11432 } 11433 } 11434 } 11435 11436 pchar pattern_first_char = pattern[0]; 11437 for (int i = idx; i >= 0; i--) { 11438 if (subject[i] != pattern_first_char) continue; 11439 int j = 1; 11440 while (j < pattern_length) { 11441 if (pattern[j] != subject[i + j]) { 11442 break; 11443 } 11444 j++; 11445 } 11446 if (j == pattern_length) { 11447 return i; 11448 } 11449 } 11450 return -1; 11451 } 11452 11453 } // namespace 11454 11455 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver, 11456 Handle<Object> search, Handle<Object> position) { 11457 if (receiver->IsNullOrUndefined(isolate)) { 11458 THROW_NEW_ERROR_RETURN_FAILURE( 11459 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, 11460 isolate->factory()->NewStringFromAsciiChecked( 11461 "String.prototype.lastIndexOf"))); 11462 } 11463 Handle<String> receiver_string; 11464 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string, 11465 Object::ToString(isolate, receiver)); 11466 11467 Handle<String> search_string; 11468 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string, 11469 Object::ToString(isolate, search)); 11470 11471 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 11472 Object::ToNumber(position)); 11473 11474 uint32_t start_index; 11475 11476 if (position->IsNaN()) { 11477 start_index = receiver_string->length(); 11478 } else { 11479 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 11480 Object::ToInteger(isolate, position)); 11481 start_index = receiver_string->ToValidIndex(*position); 11482 } 11483 11484 uint32_t pattern_length = search_string->length(); 11485 uint32_t receiver_length = receiver_string->length(); 11486 11487 if (start_index + pattern_length > receiver_length) { 11488 start_index = receiver_length - pattern_length; 11489 } 11490 11491 if (pattern_length == 0) { 11492 return Smi::FromInt(start_index); 11493 } 11494 11495 receiver_string = String::Flatten(receiver_string); 11496 search_string = String::Flatten(search_string); 11497 11498 int last_index = -1; 11499 DisallowHeapAllocation no_gc; // ensure vectors stay valid 11500 11501 String::FlatContent receiver_content = receiver_string->GetFlatContent(); 11502 String::FlatContent search_content = search_string->GetFlatContent(); 11503 11504 if (search_content.IsOneByte()) { 11505 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector(); 11506 if (receiver_content.IsOneByte()) { 11507 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(), 11508 pat_vector, start_index); 11509 } else { 11510 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(), 11511 pat_vector, start_index); 11512 } 11513 } else { 11514 Vector<const uc16> pat_vector = search_content.ToUC16Vector(); 11515 if (receiver_content.IsOneByte()) { 11516 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(), 11517 pat_vector, start_index); 11518 } else { 11519 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(), 11520 pat_vector, start_index); 11521 } 11522 } 11523 return Smi::FromInt(last_index); 11524 } 11525 11526 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) { 11527 int slen = length(); 11528 // Can't check exact length equality, but we can check bounds. 11529 int str_len = str.length(); 11530 if (!allow_prefix_match && 11531 (str_len < slen || 11532 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) { 11533 return false; 11534 } 11535 int i; 11536 size_t remaining_in_str = static_cast<size_t>(str_len); 11537 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start()); 11538 for (i = 0; i < slen && remaining_in_str > 0; i++) { 11539 size_t cursor = 0; 11540 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor); 11541 DCHECK(cursor > 0 && cursor <= remaining_in_str); 11542 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) { 11543 if (i > slen - 1) return false; 11544 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false; 11545 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false; 11546 } else { 11547 if (Get(i) != r) return false; 11548 } 11549 utf8_data += cursor; 11550 remaining_in_str -= cursor; 11551 } 11552 return (allow_prefix_match || i == slen) && remaining_in_str == 0; 11553 } 11554 11555 11556 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) { 11557 int slen = length(); 11558 if (str.length() != slen) return false; 11559 DisallowHeapAllocation no_gc; 11560 FlatContent content = GetFlatContent(); 11561 if (content.IsOneByte()) { 11562 return CompareChars(content.ToOneByteVector().start(), 11563 str.start(), slen) == 0; 11564 } 11565 for (int i = 0; i < slen; i++) { 11566 if (Get(i) != static_cast<uint16_t>(str[i])) return false; 11567 } 11568 return true; 11569 } 11570 11571 11572 bool String::IsTwoByteEqualTo(Vector<const uc16> str) { 11573 int slen = length(); 11574 if (str.length() != slen) return false; 11575 DisallowHeapAllocation no_gc; 11576 FlatContent content = GetFlatContent(); 11577 if (content.IsTwoByte()) { 11578 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0; 11579 } 11580 for (int i = 0; i < slen; i++) { 11581 if (Get(i) != str[i]) return false; 11582 } 11583 return true; 11584 } 11585 11586 11587 uint32_t String::ComputeAndSetHash() { 11588 // Should only be called if hash code has not yet been computed. 11589 DCHECK(!HasHashCode()); 11590 11591 // Store the hash code in the object. 11592 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed()); 11593 set_hash_field(field); 11594 11595 // Check the hash code is there. 11596 DCHECK(HasHashCode()); 11597 uint32_t result = field >> kHashShift; 11598 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed. 11599 return result; 11600 } 11601 11602 11603 bool String::ComputeArrayIndex(uint32_t* index) { 11604 int length = this->length(); 11605 if (length == 0 || length > kMaxArrayIndexSize) return false; 11606 StringCharacterStream stream(this); 11607 return StringToArrayIndex(&stream, index); 11608 } 11609 11610 11611 bool String::SlowAsArrayIndex(uint32_t* index) { 11612 if (length() <= kMaxCachedArrayIndexLength) { 11613 Hash(); // force computation of hash code 11614 uint32_t field = hash_field(); 11615 if ((field & kIsNotArrayIndexMask) != 0) return false; 11616 // Isolate the array index form the full hash field. 11617 *index = ArrayIndexValueBits::decode(field); 11618 return true; 11619 } else { 11620 return ComputeArrayIndex(index); 11621 } 11622 } 11623 11624 11625 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) { 11626 Heap* heap = string->GetHeap(); 11627 if (new_length == 0) return heap->isolate()->factory()->empty_string(); 11628 11629 int new_size, old_size; 11630 int old_length = string->length(); 11631 if (old_length <= new_length) return string; 11632 11633 if (string->IsSeqOneByteString()) { 11634 old_size = SeqOneByteString::SizeFor(old_length); 11635 new_size = SeqOneByteString::SizeFor(new_length); 11636 } else { 11637 DCHECK(string->IsSeqTwoByteString()); 11638 old_size = SeqTwoByteString::SizeFor(old_length); 11639 new_size = SeqTwoByteString::SizeFor(new_length); 11640 } 11641 11642 int delta = old_size - new_size; 11643 11644 Address start_of_string = string->address(); 11645 DCHECK_OBJECT_ALIGNED(start_of_string); 11646 DCHECK_OBJECT_ALIGNED(start_of_string + new_size); 11647 11648 // Sizes are pointer size aligned, so that we can use filler objects 11649 // that are a multiple of pointer size. 11650 heap->CreateFillerObjectAt(start_of_string + new_size, delta, 11651 ClearRecordedSlots::kNo); 11652 heap->AdjustLiveBytes(*string, -delta); 11653 11654 // We are storing the new length using release store after creating a filler 11655 // for the left-over space to avoid races with the sweeper thread. 11656 string->synchronized_set_length(new_length); 11657 11658 return string; 11659 } 11660 11661 11662 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { 11663 // For array indexes mix the length into the hash as an array index could 11664 // be zero. 11665 DCHECK(length > 0); 11666 DCHECK(length <= String::kMaxArrayIndexSize); 11667 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 11668 (1 << String::kArrayIndexValueBits)); 11669 11670 value <<= String::ArrayIndexValueBits::kShift; 11671 value |= length << String::ArrayIndexLengthBits::kShift; 11672 11673 DCHECK((value & String::kIsNotArrayIndexMask) == 0); 11674 DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength, 11675 (value & String::kContainsCachedArrayIndexMask) == 0); 11676 return value; 11677 } 11678 11679 11680 uint32_t StringHasher::GetHashField() { 11681 if (length_ <= String::kMaxHashCalcLength) { 11682 if (is_array_index_) { 11683 return MakeArrayIndexHash(array_index_, length_); 11684 } 11685 return (GetHashCore(raw_running_hash_) << String::kHashShift) | 11686 String::kIsNotArrayIndexMask; 11687 } else { 11688 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask; 11689 } 11690 } 11691 11692 11693 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, 11694 uint32_t seed, 11695 int* utf16_length_out) { 11696 int vector_length = chars.length(); 11697 // Handle some edge cases 11698 if (vector_length <= 1) { 11699 DCHECK(vector_length == 0 || 11700 static_cast<uint8_t>(chars.start()[0]) <= 11701 unibrow::Utf8::kMaxOneByteChar); 11702 *utf16_length_out = vector_length; 11703 return HashSequentialString(chars.start(), vector_length, seed); 11704 } 11705 // Start with a fake length which won't affect computation. 11706 // It will be updated later. 11707 StringHasher hasher(String::kMaxArrayIndexSize, seed); 11708 size_t remaining = static_cast<size_t>(vector_length); 11709 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start()); 11710 int utf16_length = 0; 11711 bool is_index = true; 11712 DCHECK(hasher.is_array_index_); 11713 while (remaining > 0) { 11714 size_t consumed = 0; 11715 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed); 11716 DCHECK(consumed > 0 && consumed <= remaining); 11717 stream += consumed; 11718 remaining -= consumed; 11719 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode; 11720 utf16_length += is_two_characters ? 2 : 1; 11721 // No need to keep hashing. But we do need to calculate utf16_length. 11722 if (utf16_length > String::kMaxHashCalcLength) continue; 11723 if (is_two_characters) { 11724 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c); 11725 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c); 11726 hasher.AddCharacter(c1); 11727 hasher.AddCharacter(c2); 11728 if (is_index) is_index = hasher.UpdateIndex(c1); 11729 if (is_index) is_index = hasher.UpdateIndex(c2); 11730 } else { 11731 hasher.AddCharacter(c); 11732 if (is_index) is_index = hasher.UpdateIndex(c); 11733 } 11734 } 11735 *utf16_length_out = static_cast<int>(utf16_length); 11736 // Must set length here so that hash computation is correct. 11737 hasher.length_ = utf16_length; 11738 return hasher.GetHashField(); 11739 } 11740 11741 11742 void IteratingStringHasher::VisitConsString(ConsString* cons_string) { 11743 // Run small ConsStrings through ConsStringIterator. 11744 if (cons_string->length() < 64) { 11745 ConsStringIterator iter(cons_string); 11746 int offset; 11747 String* string; 11748 while (nullptr != (string = iter.Next(&offset))) { 11749 DCHECK_EQ(0, offset); 11750 String::VisitFlat(this, string, 0); 11751 } 11752 return; 11753 } 11754 // Slow case. 11755 const int max_length = String::kMaxHashCalcLength; 11756 int length = std::min(cons_string->length(), max_length); 11757 if (cons_string->HasOnlyOneByteChars()) { 11758 uint8_t* buffer = new uint8_t[length]; 11759 String::WriteToFlat(cons_string, buffer, 0, length); 11760 AddCharacters(buffer, length); 11761 delete[] buffer; 11762 } else { 11763 uint16_t* buffer = new uint16_t[length]; 11764 String::WriteToFlat(cons_string, buffer, 0, length); 11765 AddCharacters(buffer, length); 11766 delete[] buffer; 11767 } 11768 } 11769 11770 11771 void String::PrintOn(FILE* file) { 11772 int length = this->length(); 11773 for (int i = 0; i < length; i++) { 11774 PrintF(file, "%c", Get(i)); 11775 } 11776 } 11777 11778 11779 int Map::Hash() { 11780 // For performance reasons we only hash the 3 most variable fields of a map: 11781 // constructor, prototype and bit_field2. For predictability reasons we 11782 // use objects' offsets in respective pages for hashing instead of raw 11783 // addresses. 11784 11785 // Shift away the tag. 11786 int hash = ObjectAddressForHashing(GetConstructor()) >> 2; 11787 11788 // XOR-ing the prototype and constructor directly yields too many zero bits 11789 // when the two pointers are close (which is fairly common). 11790 // To avoid this we shift the prototype bits relatively to the constructor. 11791 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits); 11792 11793 return hash ^ (hash >> 16) ^ bit_field2(); 11794 } 11795 11796 11797 namespace { 11798 11799 bool CheckEquivalent(Map* first, Map* second) { 11800 return first->GetConstructor() == second->GetConstructor() && 11801 first->prototype() == second->prototype() && 11802 first->instance_type() == second->instance_type() && 11803 first->bit_field() == second->bit_field() && 11804 first->is_extensible() == second->is_extensible() && 11805 first->new_target_is_base() == second->new_target_is_base() && 11806 first->has_hidden_prototype() == second->has_hidden_prototype(); 11807 } 11808 11809 } // namespace 11810 11811 11812 bool Map::EquivalentToForTransition(Map* other) { 11813 if (!CheckEquivalent(this, other)) return false; 11814 if (instance_type() == JS_FUNCTION_TYPE) { 11815 // JSFunctions require more checks to ensure that sloppy function is 11816 // not equvalent to strict function. 11817 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors()); 11818 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(), 11819 nof); 11820 } 11821 return true; 11822 } 11823 11824 11825 bool Map::EquivalentToForNormalization(Map* other, 11826 PropertyNormalizationMode mode) { 11827 int properties = 11828 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties(); 11829 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() && 11830 GetInObjectProperties() == properties && 11831 JSObject::GetInternalFieldCount(this) == 11832 JSObject::GetInternalFieldCount(other); 11833 } 11834 11835 11836 bool JSFunction::Inlines(SharedFunctionInfo* candidate) { 11837 DisallowHeapAllocation no_gc; 11838 if (shared() == candidate) return true; 11839 if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false; 11840 DeoptimizationInputData* const data = 11841 DeoptimizationInputData::cast(code()->deoptimization_data()); 11842 if (data->length() == 0) return false; 11843 FixedArray* const literals = data->LiteralArray(); 11844 int const inlined_count = data->InlinedFunctionCount()->value(); 11845 for (int i = 0; i < inlined_count; ++i) { 11846 if (SharedFunctionInfo::cast(literals->get(i)) == candidate) { 11847 return true; 11848 } 11849 } 11850 return false; 11851 } 11852 11853 void JSFunction::MarkForBaseline() { 11854 Isolate* isolate = GetIsolate(); 11855 set_code_no_write_barrier( 11856 isolate->builtins()->builtin(Builtins::kCompileBaseline)); 11857 // No write barrier required, since the builtin is part of the root set. 11858 if (FLAG_mark_shared_functions_for_tier_up) { 11859 shared()->set_marked_for_tier_up(true); 11860 } 11861 } 11862 11863 void JSFunction::MarkForOptimization() { 11864 Isolate* isolate = GetIsolate(); 11865 DCHECK(!IsOptimized()); 11866 DCHECK(shared()->allows_lazy_compilation() || 11867 !shared()->optimization_disabled()); 11868 set_code_no_write_barrier( 11869 isolate->builtins()->builtin(Builtins::kCompileOptimized)); 11870 // No write barrier required, since the builtin is part of the root set. 11871 if (FLAG_mark_shared_functions_for_tier_up) { 11872 shared()->set_marked_for_tier_up(true); 11873 } 11874 } 11875 11876 11877 void JSFunction::AttemptConcurrentOptimization() { 11878 Isolate* isolate = GetIsolate(); 11879 if (!isolate->concurrent_recompilation_enabled() || 11880 isolate->bootstrapper()->IsActive()) { 11881 MarkForOptimization(); 11882 return; 11883 } 11884 DCHECK(!IsInOptimizationQueue()); 11885 DCHECK(!IsOptimized()); 11886 DCHECK(shared()->allows_lazy_compilation() || 11887 !shared()->optimization_disabled()); 11888 DCHECK(isolate->concurrent_recompilation_enabled()); 11889 if (FLAG_trace_concurrent_recompilation) { 11890 PrintF(" ** Marking "); 11891 ShortPrint(); 11892 PrintF(" for concurrent recompilation.\n"); 11893 } 11894 11895 set_code_no_write_barrier( 11896 isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent)); 11897 // No write barrier required, since the builtin is part of the root set. 11898 if (FLAG_mark_shared_functions_for_tier_up) { 11899 // TODO(leszeks): The compilation isn't concurrent if we trigger it using 11900 // this bit. 11901 shared()->set_marked_for_tier_up(true); 11902 } 11903 } 11904 11905 // static 11906 void SharedFunctionInfo::AddToOptimizedCodeMap( 11907 Handle<SharedFunctionInfo> shared, Handle<Context> native_context, 11908 Handle<Code> code, BailoutId osr_ast_id) { 11909 Isolate* isolate = shared->GetIsolate(); 11910 if (isolate->serializer_enabled()) return; 11911 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION); 11912 DCHECK(native_context->IsNativeContext()); 11913 STATIC_ASSERT(kEntryLength == 2); 11914 Handle<FixedArray> new_code_map; 11915 int entry; 11916 11917 if (!osr_ast_id.IsNone()) { 11918 Context::AddToOptimizedCodeMap(native_context, shared, code, osr_ast_id); 11919 return; 11920 } 11921 11922 DCHECK(osr_ast_id.IsNone()); 11923 if (shared->OptimizedCodeMapIsCleared()) { 11924 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED); 11925 entry = kEntriesStart; 11926 } else { 11927 Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate); 11928 entry = shared->SearchOptimizedCodeMapEntry(*native_context); 11929 if (entry >= kEntriesStart) { 11930 // Just set the code of the entry. 11931 Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code); 11932 old_code_map->set(entry + kCachedCodeOffset, *code_cell); 11933 return; 11934 } 11935 11936 // Can we reuse an entry? 11937 DCHECK(entry < kEntriesStart); 11938 int length = old_code_map->length(); 11939 for (int i = kEntriesStart; i < length; i += kEntryLength) { 11940 if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) { 11941 new_code_map = old_code_map; 11942 entry = i; 11943 break; 11944 } 11945 } 11946 11947 if (entry < kEntriesStart) { 11948 // Copy old optimized code map and append one new entry. 11949 new_code_map = isolate->factory()->CopyFixedArrayAndGrow( 11950 old_code_map, kEntryLength, TENURED); 11951 // TODO(mstarzinger): Temporary workaround. The allocation above might 11952 // have flushed the optimized code map and the copy we created is full of 11953 // holes. For now we just give up on adding the entry and pretend it got 11954 // flushed. 11955 if (shared->OptimizedCodeMapIsCleared()) return; 11956 entry = old_code_map->length(); 11957 } 11958 } 11959 11960 Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code); 11961 WeakCell* context_cell = native_context->self_weak_cell(); 11962 11963 new_code_map->set(entry + kContextOffset, context_cell); 11964 new_code_map->set(entry + kCachedCodeOffset, *code_cell); 11965 11966 #ifdef DEBUG 11967 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) { 11968 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset)); 11969 DCHECK(cell->cleared() || cell->value()->IsNativeContext()); 11970 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset)); 11971 DCHECK(cell->cleared() || 11972 (cell->value()->IsCode() && 11973 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION)); 11974 } 11975 #endif 11976 11977 FixedArray* old_code_map = shared->optimized_code_map(); 11978 if (old_code_map != *new_code_map) { 11979 shared->set_optimized_code_map(*new_code_map); 11980 } 11981 } 11982 11983 11984 void SharedFunctionInfo::ClearOptimizedCodeMap() { 11985 FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array(); 11986 set_optimized_code_map(empty_fixed_array, SKIP_WRITE_BARRIER); 11987 } 11988 11989 11990 void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code, 11991 const char* reason) { 11992 DisallowHeapAllocation no_gc; 11993 Isolate* isolate = GetIsolate(); 11994 bool found = false; 11995 11996 if (!OptimizedCodeMapIsCleared()) { 11997 Heap* heap = isolate->heap(); 11998 FixedArray* code_map = optimized_code_map(); 11999 int length = code_map->length(); 12000 for (int src = kEntriesStart; src < length; src += kEntryLength) { 12001 DCHECK(WeakCell::cast(code_map->get(src))->cleared() || 12002 WeakCell::cast(code_map->get(src))->value()->IsNativeContext()); 12003 found = WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() == 12004 optimized_code; 12005 if (found) { 12006 if (FLAG_trace_opt) { 12007 PrintF("[evicting entry from optimizing code map (%s) for ", reason); 12008 ShortPrint(); 12009 PrintF("]\n"); 12010 } 12011 // Just clear the code. 12012 code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(), 12013 SKIP_WRITE_BARRIER); 12014 } 12015 } 12016 } 12017 12018 if (!found) { 12019 // We didn't find the code in here. It must be osr'd code. 12020 isolate->EvictOSROptimizedCode(optimized_code, reason); 12021 } 12022 } 12023 12024 // static 12025 void JSFunction::EnsureLiterals(Handle<JSFunction> function) { 12026 Handle<SharedFunctionInfo> shared(function->shared()); 12027 Isolate* isolate = shared->GetIsolate(); 12028 12029 FeedbackVectorState state = function->GetFeedbackVectorState(isolate); 12030 switch (state) { 12031 case TOP_LEVEL_SCRIPT_NEEDS_VECTOR: { 12032 // A top level script didn't get it's literals installed. 12033 Handle<FeedbackVector> feedback_vector = 12034 FeedbackVector::New(isolate, shared); 12035 Handle<Cell> new_cell = 12036 isolate->factory()->NewOneClosureCell(feedback_vector); 12037 function->set_feedback_vector_cell(*new_cell); 12038 break; 12039 } 12040 case NEEDS_VECTOR: { 12041 Handle<FeedbackVector> feedback_vector = 12042 FeedbackVector::New(isolate, shared); 12043 function->feedback_vector_cell()->set_value(*feedback_vector); 12044 break; 12045 } 12046 case HAS_VECTOR: 12047 // Nothing to do. 12048 break; 12049 } 12050 } 12051 12052 static void GetMinInobjectSlack(Map* map, void* data) { 12053 int slack = map->unused_property_fields(); 12054 if (*reinterpret_cast<int*>(data) > slack) { 12055 *reinterpret_cast<int*>(data) = slack; 12056 } 12057 } 12058 12059 12060 static void ShrinkInstanceSize(Map* map, void* data) { 12061 int slack = *reinterpret_cast<int*>(data); 12062 map->SetInObjectProperties(map->GetInObjectProperties() - slack); 12063 map->set_unused_property_fields(map->unused_property_fields() - slack); 12064 map->set_instance_size(map->instance_size() - slack * kPointerSize); 12065 map->set_construction_counter(Map::kNoSlackTracking); 12066 12067 // Visitor id might depend on the instance size, recalculate it. 12068 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map)); 12069 } 12070 12071 static void StopSlackTracking(Map* map, void* data) { 12072 map->set_construction_counter(Map::kNoSlackTracking); 12073 } 12074 12075 void Map::CompleteInobjectSlackTracking() { 12076 // Has to be an initial map. 12077 DCHECK(GetBackPointer()->IsUndefined(GetIsolate())); 12078 12079 int slack = unused_property_fields(); 12080 TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack); 12081 if (slack != 0) { 12082 // Resize the initial map and all maps in its transition tree. 12083 TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack); 12084 } else { 12085 TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr); 12086 } 12087 } 12088 12089 12090 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) { 12091 DisallowHeapAllocation no_gc; 12092 if (!object->HasFastProperties()) return false; 12093 if (object->IsJSGlobalProxy()) return false; 12094 if (object->GetIsolate()->bootstrapper()->IsActive()) return false; 12095 return !object->map()->is_prototype_map() || 12096 !object->map()->should_be_fast_prototype_map(); 12097 } 12098 12099 // static 12100 void JSObject::MakePrototypesFast(Handle<Object> receiver, 12101 WhereToStart where_to_start, 12102 Isolate* isolate) { 12103 if (!receiver->IsJSReceiver()) return; 12104 for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver), 12105 where_to_start); 12106 !iter.IsAtEnd(); iter.Advance()) { 12107 Handle<Object> current = PrototypeIterator::GetCurrent(iter); 12108 if (!current->IsJSObject()) return; 12109 Handle<JSObject> current_obj = Handle<JSObject>::cast(current); 12110 Map* current_map = current_obj->map(); 12111 if (current_map->is_prototype_map()) { 12112 // If the map is already marked as should be fast, we're done. Its 12113 // prototypes will have been marked already as well. 12114 if (current_map->should_be_fast_prototype_map()) return; 12115 Handle<Map> map(current_map); 12116 Map::SetShouldBeFastPrototypeMap(map, true, isolate); 12117 JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE); 12118 } 12119 } 12120 } 12121 12122 // static 12123 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, 12124 PrototypeOptimizationMode mode) { 12125 if (object->IsJSGlobalObject()) return; 12126 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { 12127 // First normalize to ensure all JSFunctions are DATA_CONSTANT. 12128 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, 12129 "NormalizeAsPrototype"); 12130 } 12131 Handle<Map> previous_map(object->map()); 12132 if (object->map()->is_prototype_map()) { 12133 if (object->map()->should_be_fast_prototype_map() && 12134 !object->HasFastProperties()) { 12135 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); 12136 } 12137 } else { 12138 if (object->map() == *previous_map) { 12139 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); 12140 JSObject::MigrateToMap(object, new_map); 12141 } 12142 object->map()->set_is_prototype_map(true); 12143 12144 // Replace the pointer to the exact constructor with the Object function 12145 // from the same context if undetectable from JS. This is to avoid keeping 12146 // memory alive unnecessarily. 12147 Object* maybe_constructor = object->map()->GetConstructor(); 12148 if (maybe_constructor->IsJSFunction()) { 12149 JSFunction* constructor = JSFunction::cast(maybe_constructor); 12150 Isolate* isolate = object->GetIsolate(); 12151 if (!constructor->shared()->IsApiFunction() && 12152 object->class_name() == isolate->heap()->Object_string()) { 12153 Context* context = constructor->context()->native_context(); 12154 JSFunction* object_function = context->object_function(); 12155 object->map()->SetConstructor(object_function); 12156 } 12157 } 12158 } 12159 } 12160 12161 12162 // static 12163 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { 12164 if (!object->map()->is_prototype_map()) return; 12165 if (!object->map()->should_be_fast_prototype_map()) return; 12166 OptimizeAsPrototype(object, FAST_PROTOTYPE); 12167 } 12168 12169 12170 // static 12171 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) { 12172 // Contract: In line with InvalidatePrototypeChains()'s requirements, 12173 // leaf maps don't need to register as users, only prototypes do. 12174 DCHECK(user->is_prototype_map()); 12175 12176 Handle<Map> current_user = user; 12177 Handle<PrototypeInfo> current_user_info = 12178 Map::GetOrCreatePrototypeInfo(user, isolate); 12179 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) { 12180 // Walk up the prototype chain as far as links haven't been registered yet. 12181 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) { 12182 break; 12183 } 12184 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter); 12185 // Proxies on the prototype chain are not supported. They make it 12186 // impossible to make any assumptions about the prototype chain anyway. 12187 if (maybe_proto->IsJSProxy()) return; 12188 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto); 12189 Handle<PrototypeInfo> proto_info = 12190 Map::GetOrCreatePrototypeInfo(proto, isolate); 12191 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); 12192 int slot = 0; 12193 Handle<WeakFixedArray> new_array = 12194 WeakFixedArray::Add(maybe_registry, current_user, &slot); 12195 current_user_info->set_registry_slot(slot); 12196 if (!maybe_registry.is_identical_to(new_array)) { 12197 proto_info->set_prototype_users(*new_array); 12198 } 12199 if (FLAG_trace_prototype_users) { 12200 PrintF("Registering %p as a user of prototype %p (map=%p).\n", 12201 reinterpret_cast<void*>(*current_user), 12202 reinterpret_cast<void*>(*proto), 12203 reinterpret_cast<void*>(proto->map())); 12204 } 12205 12206 current_user = handle(proto->map(), isolate); 12207 current_user_info = proto_info; 12208 } 12209 } 12210 12211 12212 // Can be called regardless of whether |user| was actually registered with 12213 // |prototype|. Returns true when there was a registration. 12214 // static 12215 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) { 12216 DCHECK(user->is_prototype_map()); 12217 // If it doesn't have a PrototypeInfo, it was never registered. 12218 if (!user->prototype_info()->IsPrototypeInfo()) return false; 12219 // If it had no prototype before, see if it had users that might expect 12220 // registration. 12221 if (!user->prototype()->IsJSObject()) { 12222 Object* users = 12223 PrototypeInfo::cast(user->prototype_info())->prototype_users(); 12224 return users->IsWeakFixedArray(); 12225 } 12226 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate); 12227 Handle<PrototypeInfo> user_info = 12228 Map::GetOrCreatePrototypeInfo(user, isolate); 12229 int slot = user_info->registry_slot(); 12230 if (slot == PrototypeInfo::UNREGISTERED) return false; 12231 DCHECK(prototype->map()->is_prototype_map()); 12232 Object* maybe_proto_info = prototype->map()->prototype_info(); 12233 // User knows its registry slot, prototype info and user registry must exist. 12234 DCHECK(maybe_proto_info->IsPrototypeInfo()); 12235 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), 12236 isolate); 12237 Object* maybe_registry = proto_info->prototype_users(); 12238 DCHECK(maybe_registry->IsWeakFixedArray()); 12239 DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user); 12240 WeakFixedArray::cast(maybe_registry)->Clear(slot); 12241 if (FLAG_trace_prototype_users) { 12242 PrintF("Unregistering %p as a user of prototype %p.\n", 12243 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); 12244 } 12245 return true; 12246 } 12247 12248 12249 static void InvalidatePrototypeChainsInternal(Map* map) { 12250 DCHECK(map->is_prototype_map()); 12251 if (FLAG_trace_prototype_users) { 12252 PrintF("Invalidating prototype map %p 's cell\n", 12253 reinterpret_cast<void*>(map)); 12254 } 12255 Object* maybe_proto_info = map->prototype_info(); 12256 if (!maybe_proto_info->IsPrototypeInfo()) return; 12257 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); 12258 Object* maybe_cell = proto_info->validity_cell(); 12259 if (maybe_cell->IsCell()) { 12260 // Just set the value; the cell will be replaced lazily. 12261 Cell* cell = Cell::cast(maybe_cell); 12262 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); 12263 } 12264 12265 WeakFixedArray::Iterator iterator(proto_info->prototype_users()); 12266 // For now, only maps register themselves as users. 12267 Map* user; 12268 while ((user = iterator.Next<Map>())) { 12269 // Walk the prototype chain (backwards, towards leaf objects) if necessary. 12270 InvalidatePrototypeChainsInternal(user); 12271 } 12272 } 12273 12274 12275 // static 12276 void JSObject::InvalidatePrototypeChains(Map* map) { 12277 DisallowHeapAllocation no_gc; 12278 InvalidatePrototypeChainsInternal(map); 12279 } 12280 12281 12282 // static 12283 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype, 12284 Isolate* isolate) { 12285 Object* maybe_proto_info = prototype->map()->prototype_info(); 12286 if (maybe_proto_info->IsPrototypeInfo()) { 12287 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); 12288 } 12289 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); 12290 prototype->map()->set_prototype_info(*proto_info); 12291 return proto_info; 12292 } 12293 12294 12295 // static 12296 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map, 12297 Isolate* isolate) { 12298 Object* maybe_proto_info = prototype_map->prototype_info(); 12299 if (maybe_proto_info->IsPrototypeInfo()) { 12300 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); 12301 } 12302 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); 12303 prototype_map->set_prototype_info(*proto_info); 12304 return proto_info; 12305 } 12306 12307 // static 12308 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value, 12309 Isolate* isolate) { 12310 if (value == false && !map->prototype_info()->IsPrototypeInfo()) { 12311 // "False" is the implicit default value, so there's nothing to do. 12312 return; 12313 } 12314 GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value); 12315 } 12316 12317 // static 12318 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, 12319 Isolate* isolate) { 12320 Handle<Object> maybe_prototype; 12321 if (map->IsJSGlobalObjectMap()) { 12322 DCHECK(map->is_prototype_map()); 12323 // Global object is prototype of a global proxy and therefore we can 12324 // use its validity cell for guarding global object's prototype change. 12325 maybe_prototype = isolate->global_object(); 12326 } else { 12327 maybe_prototype = 12328 handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate); 12329 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); 12330 } 12331 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); 12332 // Ensure the prototype is registered with its own prototypes so its cell 12333 // will be invalidated when necessary. 12334 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), 12335 isolate); 12336 Handle<PrototypeInfo> proto_info = 12337 GetOrCreatePrototypeInfo(prototype, isolate); 12338 Object* maybe_cell = proto_info->validity_cell(); 12339 // Return existing cell if it's still valid. 12340 if (maybe_cell->IsCell()) { 12341 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); 12342 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { 12343 return cell; 12344 } 12345 } 12346 // Otherwise create a new cell. 12347 Handle<Cell> cell = isolate->factory()->NewCell( 12348 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); 12349 proto_info->set_validity_cell(*cell); 12350 return cell; 12351 } 12352 12353 // static 12354 Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype, 12355 Isolate* isolate) { 12356 DCHECK(!prototype.is_null()); 12357 Handle<PrototypeInfo> proto_info = 12358 GetOrCreatePrototypeInfo(prototype, isolate); 12359 Object* maybe_cell = proto_info->weak_cell(); 12360 // Return existing cell if it's already created. 12361 if (maybe_cell->IsWeakCell()) { 12362 Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate); 12363 DCHECK(!cell->cleared()); 12364 return cell; 12365 } 12366 // Otherwise create a new cell. 12367 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype); 12368 proto_info->set_weak_cell(*cell); 12369 return cell; 12370 } 12371 12372 // static 12373 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, 12374 PrototypeOptimizationMode proto_mode) { 12375 RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype); 12376 12377 bool is_hidden = false; 12378 if (prototype->IsJSObject()) { 12379 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); 12380 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); 12381 12382 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor(); 12383 if (maybe_constructor->IsJSFunction()) { 12384 JSFunction* constructor = JSFunction::cast(maybe_constructor); 12385 Object* data = constructor->shared()->function_data(); 12386 is_hidden = (data->IsFunctionTemplateInfo() && 12387 FunctionTemplateInfo::cast(data)->hidden_prototype()) || 12388 prototype->IsJSGlobalObject(); 12389 } 12390 } 12391 map->set_has_hidden_prototype(is_hidden); 12392 12393 WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate()) 12394 ? SKIP_WRITE_BARRIER 12395 : UPDATE_WRITE_BARRIER; 12396 map->set_prototype(*prototype, wb_mode); 12397 } 12398 12399 12400 Handle<Object> CacheInitialJSArrayMaps( 12401 Handle<Context> native_context, Handle<Map> initial_map) { 12402 // Replace all of the cached initial array maps in the native context with 12403 // the appropriate transitioned elements kind maps. 12404 Handle<Map> current_map = initial_map; 12405 ElementsKind kind = current_map->elements_kind(); 12406 DCHECK_EQ(GetInitialFastElementsKind(), kind); 12407 native_context->set(Context::ArrayMapIndex(kind), *current_map); 12408 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1; 12409 i < kFastElementsKindCount; ++i) { 12410 Handle<Map> new_map; 12411 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); 12412 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) { 12413 new_map = handle(maybe_elements_transition); 12414 } else { 12415 new_map = Map::CopyAsElementsKind( 12416 current_map, next_kind, INSERT_TRANSITION); 12417 } 12418 DCHECK_EQ(next_kind, new_map->elements_kind()); 12419 native_context->set(Context::ArrayMapIndex(next_kind), *new_map); 12420 current_map = new_map; 12421 } 12422 return initial_map; 12423 } 12424 12425 12426 void JSFunction::SetInstancePrototype(Handle<JSFunction> function, 12427 Handle<Object> value) { 12428 Isolate* isolate = function->GetIsolate(); 12429 12430 DCHECK(value->IsJSReceiver()); 12431 12432 // Now some logic for the maps of the objects that are created by using this 12433 // function as a constructor. 12434 if (function->has_initial_map()) { 12435 // If the function has allocated the initial map replace it with a 12436 // copy containing the new prototype. Also complete any in-object 12437 // slack tracking that is in progress at this point because it is 12438 // still tracking the old copy. 12439 function->CompleteInobjectSlackTrackingIfActive(); 12440 12441 Handle<Map> initial_map(function->initial_map(), isolate); 12442 12443 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() && 12444 initial_map->instance_type() == JS_OBJECT_TYPE) { 12445 // Put the value in the initial map field until an initial map is needed. 12446 // At that point, a new initial map is created and the prototype is put 12447 // into the initial map where it belongs. 12448 function->set_prototype_or_initial_map(*value); 12449 } else { 12450 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype"); 12451 JSFunction::SetInitialMap(function, new_map, value); 12452 12453 // If the function is used as the global Array function, cache the 12454 // updated initial maps (and transitioned versions) in the native context. 12455 Handle<Context> native_context(function->context()->native_context(), 12456 isolate); 12457 Handle<Object> array_function( 12458 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate); 12459 if (array_function->IsJSFunction() && 12460 *function == JSFunction::cast(*array_function)) { 12461 CacheInitialJSArrayMaps(native_context, new_map); 12462 } 12463 } 12464 12465 // Deoptimize all code that embeds the previous initial map. 12466 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( 12467 isolate, DependentCode::kInitialMapChangedGroup); 12468 } else { 12469 // Put the value in the initial map field until an initial map is 12470 // needed. At that point, a new initial map is created and the 12471 // prototype is put into the initial map where it belongs. 12472 function->set_prototype_or_initial_map(*value); 12473 if (value->IsJSObject()) { 12474 // Optimize as prototype to detach it from its transition tree. 12475 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), 12476 FAST_PROTOTYPE); 12477 } 12478 } 12479 isolate->heap()->ClearInstanceofCache(); 12480 } 12481 12482 12483 void JSFunction::SetPrototype(Handle<JSFunction> function, 12484 Handle<Object> value) { 12485 DCHECK(function->IsConstructor() || 12486 IsGeneratorFunction(function->shared()->kind())); 12487 Handle<Object> construct_prototype = value; 12488 12489 // If the value is not a JSReceiver, store the value in the map's 12490 // constructor field so it can be accessed. Also, set the prototype 12491 // used for constructing objects to the original object prototype. 12492 // See ECMA-262 13.2.2. 12493 if (!value->IsJSReceiver()) { 12494 // Copy the map so this does not affect unrelated functions. 12495 // Remove map transitions because they point to maps with a 12496 // different prototype. 12497 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype"); 12498 12499 JSObject::MigrateToMap(function, new_map); 12500 new_map->SetConstructor(*value); 12501 new_map->set_non_instance_prototype(true); 12502 Isolate* isolate = new_map->GetIsolate(); 12503 12504 construct_prototype = handle( 12505 IsGeneratorFunction(function->shared()->kind()) 12506 ? function->context() 12507 ->native_context() 12508 ->initial_generator_prototype() 12509 : function->context()->native_context()->initial_object_prototype(), 12510 isolate); 12511 } else { 12512 function->map()->set_non_instance_prototype(false); 12513 } 12514 12515 return SetInstancePrototype(function, construct_prototype); 12516 } 12517 12518 12519 bool JSFunction::RemovePrototype() { 12520 Context* native_context = context()->native_context(); 12521 Map* no_prototype_map = 12522 is_strict(shared()->language_mode()) 12523 ? native_context->strict_function_without_prototype_map() 12524 : native_context->sloppy_function_without_prototype_map(); 12525 12526 if (map() == no_prototype_map) return true; 12527 12528 #ifdef DEBUG 12529 if (map() != (is_strict(shared()->language_mode()) 12530 ? native_context->strict_function_map() 12531 : native_context->sloppy_function_map())) { 12532 return false; 12533 } 12534 #endif 12535 12536 set_map(no_prototype_map); 12537 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value()); 12538 return true; 12539 } 12540 12541 12542 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map, 12543 Handle<Object> prototype) { 12544 if (map->prototype() != *prototype) { 12545 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 12546 } 12547 function->set_prototype_or_initial_map(*map); 12548 map->SetConstructor(*function); 12549 #if TRACE_MAPS 12550 if (FLAG_trace_maps) { 12551 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n", 12552 reinterpret_cast<void*>(*map), function->shared()->unique_id(), 12553 function->shared()->DebugName()->ToCString().get()); 12554 } 12555 #endif 12556 } 12557 12558 12559 #ifdef DEBUG 12560 namespace { 12561 12562 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) { 12563 switch (instance_type) { 12564 case JS_API_OBJECT_TYPE: 12565 case JS_ARRAY_BUFFER_TYPE: 12566 case JS_ARRAY_TYPE: 12567 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE: 12568 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 12569 case JS_DATA_VIEW_TYPE: 12570 case JS_DATE_TYPE: 12571 case JS_FUNCTION_TYPE: 12572 case JS_GENERATOR_OBJECT_TYPE: 12573 case JS_MAP_ITERATOR_TYPE: 12574 case JS_MAP_TYPE: 12575 case JS_MESSAGE_OBJECT_TYPE: 12576 case JS_OBJECT_TYPE: 12577 case JS_ERROR_TYPE: 12578 case JS_ARGUMENTS_TYPE: 12579 case JS_PROMISE_TYPE: 12580 case JS_REGEXP_TYPE: 12581 case JS_SET_ITERATOR_TYPE: 12582 case JS_SET_TYPE: 12583 case JS_SPECIAL_API_OBJECT_TYPE: 12584 case JS_TYPED_ARRAY_TYPE: 12585 case JS_VALUE_TYPE: 12586 case JS_WEAK_MAP_TYPE: 12587 case JS_WEAK_SET_TYPE: 12588 return true; 12589 12590 case BYTECODE_ARRAY_TYPE: 12591 case BYTE_ARRAY_TYPE: 12592 case CELL_TYPE: 12593 case CODE_TYPE: 12594 case FILLER_TYPE: 12595 case FIXED_ARRAY_TYPE: 12596 case FIXED_DOUBLE_ARRAY_TYPE: 12597 case FOREIGN_TYPE: 12598 case FREE_SPACE_TYPE: 12599 case HEAP_NUMBER_TYPE: 12600 case JS_BOUND_FUNCTION_TYPE: 12601 case JS_GLOBAL_OBJECT_TYPE: 12602 case JS_GLOBAL_PROXY_TYPE: 12603 case JS_PROXY_TYPE: 12604 case MAP_TYPE: 12605 case MUTABLE_HEAP_NUMBER_TYPE: 12606 case ODDBALL_TYPE: 12607 case PROPERTY_CELL_TYPE: 12608 case SHARED_FUNCTION_INFO_TYPE: 12609 case SYMBOL_TYPE: 12610 case WEAK_CELL_TYPE: 12611 12612 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 12613 case FIXED_##TYPE##_ARRAY_TYPE: 12614 #undef TYPED_ARRAY_CASE 12615 12616 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: 12617 STRUCT_LIST(MAKE_STRUCT_CASE) 12618 #undef MAKE_STRUCT_CASE 12619 // We must not end up here for these instance types at all. 12620 UNREACHABLE(); 12621 // Fall through. 12622 default: 12623 return false; 12624 } 12625 } 12626 12627 } // namespace 12628 #endif 12629 12630 12631 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { 12632 DCHECK(function->IsConstructor() || 12633 IsResumableFunction(function->shared()->kind())); 12634 if (function->has_initial_map()) return; 12635 Isolate* isolate = function->GetIsolate(); 12636 12637 // The constructor should be compiled for the optimization hints to be 12638 // available. 12639 Compiler::Compile(function, Compiler::CLEAR_EXCEPTION); 12640 12641 // First create a new map with the size and number of in-object properties 12642 // suggested by the function. 12643 InstanceType instance_type; 12644 if (IsResumableFunction(function->shared()->kind())) { 12645 instance_type = JS_GENERATOR_OBJECT_TYPE; 12646 } else { 12647 instance_type = JS_OBJECT_TYPE; 12648 } 12649 int instance_size; 12650 int in_object_properties; 12651 function->CalculateInstanceSize(instance_type, 0, &instance_size, 12652 &in_object_properties); 12653 12654 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size); 12655 12656 // Fetch or allocate prototype. 12657 Handle<Object> prototype; 12658 if (function->has_instance_prototype()) { 12659 prototype = handle(function->instance_prototype(), isolate); 12660 } else { 12661 prototype = isolate->factory()->NewFunctionPrototype(function); 12662 } 12663 map->SetInObjectProperties(in_object_properties); 12664 map->set_unused_property_fields(in_object_properties); 12665 DCHECK(map->has_fast_object_elements()); 12666 12667 // Finally link initial map and constructor function. 12668 DCHECK(prototype->IsJSReceiver()); 12669 JSFunction::SetInitialMap(function, map, prototype); 12670 map->StartInobjectSlackTracking(); 12671 } 12672 12673 12674 // static 12675 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate, 12676 Handle<JSFunction> constructor, 12677 Handle<JSReceiver> new_target) { 12678 EnsureHasInitialMap(constructor); 12679 12680 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate); 12681 if (*new_target == *constructor) return constructor_initial_map; 12682 12683 // Fast case, new.target is a subclass of constructor. The map is cacheable 12684 // (and may already have been cached). new.target.prototype is guaranteed to 12685 // be a JSReceiver. 12686 if (new_target->IsJSFunction()) { 12687 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); 12688 12689 // Check that |function|'s initial map still in sync with the |constructor|, 12690 // otherwise we must create a new initial map for |function|. 12691 if (function->has_initial_map() && 12692 function->initial_map()->GetConstructor() == *constructor) { 12693 return handle(function->initial_map(), isolate); 12694 } 12695 12696 // Create a new map with the size and number of in-object properties 12697 // suggested by |function|. 12698 12699 // Link initial map and constructor function if the new.target is actually a 12700 // subclass constructor. 12701 if (IsDerivedConstructor(function->shared()->kind())) { 12702 Handle<Object> prototype(function->instance_prototype(), isolate); 12703 InstanceType instance_type = constructor_initial_map->instance_type(); 12704 DCHECK(CanSubclassHaveInobjectProperties(instance_type)); 12705 int internal_fields = 12706 JSObject::GetInternalFieldCount(*constructor_initial_map); 12707 int pre_allocated = constructor_initial_map->GetInObjectProperties() - 12708 constructor_initial_map->unused_property_fields(); 12709 int instance_size; 12710 int in_object_properties; 12711 function->CalculateInstanceSizeForDerivedClass( 12712 instance_type, internal_fields, &instance_size, 12713 &in_object_properties); 12714 12715 int unused_property_fields = in_object_properties - pre_allocated; 12716 Handle<Map> map = 12717 Map::CopyInitialMap(constructor_initial_map, instance_size, 12718 in_object_properties, unused_property_fields); 12719 map->set_new_target_is_base(false); 12720 12721 JSFunction::SetInitialMap(function, map, prototype); 12722 map->SetConstructor(*constructor); 12723 map->set_construction_counter(Map::kNoSlackTracking); 12724 map->StartInobjectSlackTracking(); 12725 return map; 12726 } 12727 } 12728 12729 // Slow path, new.target is either a proxy or can't cache the map. 12730 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to 12731 // fall back to the intrinsicDefaultProto. 12732 Handle<Object> prototype; 12733 if (new_target->IsJSFunction()) { 12734 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); 12735 // Make sure the new.target.prototype is cached. 12736 EnsureHasInitialMap(function); 12737 prototype = handle(function->prototype(), isolate); 12738 } else { 12739 Handle<String> prototype_string = isolate->factory()->prototype_string(); 12740 ASSIGN_RETURN_ON_EXCEPTION( 12741 isolate, prototype, 12742 JSReceiver::GetProperty(new_target, prototype_string), Map); 12743 // The above prototype lookup might change the constructor and its 12744 // prototype, hence we have to reload the initial map. 12745 EnsureHasInitialMap(constructor); 12746 constructor_initial_map = handle(constructor->initial_map(), isolate); 12747 } 12748 12749 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the 12750 // correct realm. Rather than directly fetching the .prototype, we fetch the 12751 // constructor that points to the .prototype. This relies on 12752 // constructor.prototype being FROZEN for those constructors. 12753 if (!prototype->IsJSReceiver()) { 12754 Handle<Context> context; 12755 ASSIGN_RETURN_ON_EXCEPTION(isolate, context, 12756 JSReceiver::GetFunctionRealm(new_target), Map); 12757 DCHECK(context->IsNativeContext()); 12758 Handle<Object> maybe_index = JSReceiver::GetDataProperty( 12759 constructor, isolate->factory()->native_context_index_symbol()); 12760 int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value() 12761 : Context::OBJECT_FUNCTION_INDEX; 12762 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index))); 12763 prototype = handle(realm_constructor->prototype(), isolate); 12764 } 12765 12766 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); 12767 map->set_new_target_is_base(false); 12768 DCHECK(prototype->IsJSReceiver()); 12769 if (map->prototype() != *prototype) { 12770 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 12771 } 12772 map->SetConstructor(*constructor); 12773 return map; 12774 } 12775 12776 12777 void JSFunction::PrintName(FILE* out) { 12778 std::unique_ptr<char[]> name = shared()->DebugName()->ToCString(); 12779 PrintF(out, "%s", name.get()); 12780 } 12781 12782 12783 Handle<String> JSFunction::GetName(Handle<JSFunction> function) { 12784 Isolate* isolate = function->GetIsolate(); 12785 Handle<Object> name = 12786 JSReceiver::GetDataProperty(function, isolate->factory()->name_string()); 12787 if (name->IsString()) return Handle<String>::cast(name); 12788 return handle(function->shared()->DebugName(), isolate); 12789 } 12790 12791 12792 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) { 12793 Isolate* isolate = function->GetIsolate(); 12794 Handle<Object> name = JSReceiver::GetDataProperty( 12795 function, isolate->factory()->display_name_string()); 12796 if (name->IsString()) return Handle<String>::cast(name); 12797 return JSFunction::GetName(function); 12798 } 12799 12800 void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name, 12801 Handle<String> prefix) { 12802 Isolate* isolate = function->GetIsolate(); 12803 Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked(); 12804 if (prefix->length() > 0) { 12805 IncrementalStringBuilder builder(isolate); 12806 builder.AppendString(prefix); 12807 builder.AppendCharacter(' '); 12808 builder.AppendString(function_name); 12809 function_name = builder.Finish().ToHandleChecked(); 12810 } 12811 JSObject::DefinePropertyOrElementIgnoreAttributes( 12812 function, isolate->factory()->name_string(), function_name, 12813 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)) 12814 .ToHandleChecked(); 12815 } 12816 12817 namespace { 12818 12819 char const kNativeCodeSource[] = "function () { [native code] }"; 12820 12821 12822 Handle<String> NativeCodeFunctionSourceString( 12823 Handle<SharedFunctionInfo> shared_info) { 12824 Isolate* const isolate = shared_info->GetIsolate(); 12825 if (shared_info->name()->IsString()) { 12826 IncrementalStringBuilder builder(isolate); 12827 builder.AppendCString("function "); 12828 builder.AppendString(handle(String::cast(shared_info->name()), isolate)); 12829 builder.AppendCString("() { [native code] }"); 12830 return builder.Finish().ToHandleChecked(); 12831 } 12832 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource); 12833 } 12834 12835 } // namespace 12836 12837 12838 // static 12839 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) { 12840 Isolate* const isolate = function->GetIsolate(); 12841 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource); 12842 } 12843 12844 12845 // static 12846 Handle<String> JSFunction::ToString(Handle<JSFunction> function) { 12847 Isolate* const isolate = function->GetIsolate(); 12848 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate); 12849 12850 // Check if {function} should hide its source code. 12851 if (!shared_info->IsUserJavaScript()) { 12852 return NativeCodeFunctionSourceString(shared_info); 12853 } 12854 12855 // Check if we should print {function} as a class. 12856 Handle<Object> class_start_position = JSReceiver::GetDataProperty( 12857 function, isolate->factory()->class_start_position_symbol()); 12858 if (class_start_position->IsSmi()) { 12859 Handle<Object> class_end_position = JSReceiver::GetDataProperty( 12860 function, isolate->factory()->class_end_position_symbol()); 12861 Handle<String> script_source( 12862 String::cast(Script::cast(shared_info->script())->source()), isolate); 12863 return isolate->factory()->NewSubString( 12864 script_source, Handle<Smi>::cast(class_start_position)->value(), 12865 Handle<Smi>::cast(class_end_position)->value()); 12866 } 12867 12868 // Check if we have source code for the {function}. 12869 if (!shared_info->HasSourceCode()) { 12870 return NativeCodeFunctionSourceString(shared_info); 12871 } 12872 12873 if (FLAG_harmony_function_tostring) { 12874 return Handle<String>::cast(shared_info->GetSourceCodeHarmony()); 12875 } 12876 12877 IncrementalStringBuilder builder(isolate); 12878 FunctionKind kind = shared_info->kind(); 12879 if (!IsArrowFunction(kind)) { 12880 if (IsConciseMethod(kind)) { 12881 if (IsGeneratorFunction(kind)) { 12882 builder.AppendCharacter('*'); 12883 } else if (IsAsyncFunction(kind)) { 12884 builder.AppendCString("async "); 12885 } 12886 } else { 12887 if (IsGeneratorFunction(kind)) { 12888 builder.AppendCString("function* "); 12889 } else if (IsAsyncFunction(kind)) { 12890 builder.AppendCString("async function "); 12891 } else { 12892 builder.AppendCString("function "); 12893 } 12894 } 12895 if (shared_info->name_should_print_as_anonymous()) { 12896 builder.AppendCString("anonymous"); 12897 } else if (!shared_info->is_anonymous_expression()) { 12898 builder.AppendString(handle(String::cast(shared_info->name()), isolate)); 12899 } 12900 } 12901 builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode())); 12902 return builder.Finish().ToHandleChecked(); 12903 } 12904 12905 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball, 12906 const char* to_string, Handle<Object> to_number, 12907 const char* type_of, byte kind) { 12908 Handle<String> internalized_to_string = 12909 isolate->factory()->InternalizeUtf8String(to_string); 12910 Handle<String> internalized_type_of = 12911 isolate->factory()->InternalizeUtf8String(type_of); 12912 oddball->set_to_number_raw(to_number->Number()); 12913 oddball->set_to_number(*to_number); 12914 oddball->set_to_string(*internalized_to_string); 12915 oddball->set_type_of(*internalized_type_of); 12916 oddball->set_kind(kind); 12917 } 12918 12919 void Script::SetEvalOrigin(Handle<Script> script, 12920 Handle<SharedFunctionInfo> outer_info, 12921 int eval_position) { 12922 if (eval_position == kNoSourcePosition) { 12923 // If the position is missing, attempt to get the code offset from the 12924 // current activation. Do not translate the code offset into source 12925 // position, but store it as negative value for lazy translation. 12926 StackTraceFrameIterator it(script->GetIsolate()); 12927 if (!it.done() && it.is_javascript()) { 12928 FrameSummary summary = FrameSummary::GetTop(it.javascript_frame()); 12929 script->set_eval_from_shared(summary.AsJavaScript().function()->shared()); 12930 script->set_eval_from_position(-summary.code_offset()); 12931 return; 12932 } 12933 eval_position = 0; 12934 } 12935 script->set_eval_from_shared(*outer_info); 12936 script->set_eval_from_position(eval_position); 12937 } 12938 12939 int Script::GetEvalPosition() { 12940 DisallowHeapAllocation no_gc; 12941 DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL); 12942 int position = eval_from_position(); 12943 if (position < 0) { 12944 // Due to laziness, the position may not have been translated from code 12945 // offset yet, which would be encoded as negative integer. In that case, 12946 // translate and set the position. 12947 if (eval_from_shared()->IsUndefined(GetIsolate())) { 12948 position = 0; 12949 } else { 12950 SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared()); 12951 position = shared->abstract_code()->SourcePosition(-position); 12952 } 12953 DCHECK(position >= 0); 12954 set_eval_from_position(position); 12955 } 12956 return position; 12957 } 12958 12959 void Script::InitLineEnds(Handle<Script> script) { 12960 Isolate* isolate = script->GetIsolate(); 12961 if (!script->line_ends()->IsUndefined(isolate)) return; 12962 DCHECK_NE(Script::TYPE_WASM, script->type()); 12963 12964 Object* src_obj = script->source(); 12965 if (!src_obj->IsString()) { 12966 DCHECK(src_obj->IsUndefined(isolate)); 12967 script->set_line_ends(isolate->heap()->empty_fixed_array()); 12968 } else { 12969 DCHECK(src_obj->IsString()); 12970 Handle<String> src(String::cast(src_obj), isolate); 12971 Handle<FixedArray> array = String::CalculateLineEnds(src, true); 12972 script->set_line_ends(*array); 12973 } 12974 12975 DCHECK(script->line_ends()->IsFixedArray()); 12976 } 12977 12978 bool Script::GetPositionInfo(Handle<Script> script, int position, 12979 PositionInfo* info, OffsetFlag offset_flag) { 12980 // For wasm, we do not create an artificial line_ends array, but do the 12981 // translation directly. 12982 if (script->type() != Script::TYPE_WASM) InitLineEnds(script); 12983 return script->GetPositionInfo(position, info, offset_flag); 12984 } 12985 12986 namespace { 12987 bool GetPositionInfoSlow(const Script* script, int position, 12988 Script::PositionInfo* info) { 12989 if (!script->source()->IsString()) return false; 12990 if (position < 0) position = 0; 12991 12992 String* source_string = String::cast(script->source()); 12993 int line = 0; 12994 int line_start = 0; 12995 int len = source_string->length(); 12996 for (int pos = 0; pos <= len; ++pos) { 12997 if (pos == len || source_string->Get(pos) == '\n') { 12998 if (position <= pos) { 12999 info->line = line; 13000 info->column = position - line_start; 13001 info->line_start = line_start; 13002 info->line_end = pos; 13003 return true; 13004 } 13005 line++; 13006 line_start = pos + 1; 13007 } 13008 } 13009 return false; 13010 } 13011 } // namespace 13012 13013 #define SMI_VALUE(x) (Smi::cast(x)->value()) 13014 bool Script::GetPositionInfo(int position, PositionInfo* info, 13015 OffsetFlag offset_flag) const { 13016 DisallowHeapAllocation no_allocation; 13017 13018 // For wasm, we do not rely on the line_ends array, but do the translation 13019 // directly. 13020 if (type() == Script::TYPE_WASM) { 13021 Handle<WasmCompiledModule> compiled_module( 13022 WasmCompiledModule::cast(wasm_compiled_module())); 13023 DCHECK_LE(0, position); 13024 return compiled_module->GetPositionInfo(static_cast<uint32_t>(position), 13025 info); 13026 } 13027 13028 if (line_ends()->IsUndefined(GetIsolate())) { 13029 // Slow mode: we do not have line_ends. We have to iterate through source. 13030 if (!GetPositionInfoSlow(this, position, info)) return false; 13031 } else { 13032 DCHECK(line_ends()->IsFixedArray()); 13033 FixedArray* ends = FixedArray::cast(line_ends()); 13034 13035 const int ends_len = ends->length(); 13036 if (ends_len == 0) return false; 13037 13038 // Return early on invalid positions. Negative positions behave as if 0 was 13039 // passed, and positions beyond the end of the script return as failure. 13040 if (position < 0) { 13041 position = 0; 13042 } else if (position > SMI_VALUE(ends->get(ends_len - 1))) { 13043 return false; 13044 } 13045 13046 // Determine line number by doing a binary search on the line ends array. 13047 if (SMI_VALUE(ends->get(0)) >= position) { 13048 info->line = 0; 13049 info->line_start = 0; 13050 info->column = position; 13051 } else { 13052 int left = 0; 13053 int right = ends_len - 1; 13054 13055 while (right > 0) { 13056 DCHECK_LE(left, right); 13057 const int mid = (left + right) / 2; 13058 if (position > SMI_VALUE(ends->get(mid))) { 13059 left = mid + 1; 13060 } else if (position <= SMI_VALUE(ends->get(mid - 1))) { 13061 right = mid - 1; 13062 } else { 13063 info->line = mid; 13064 break; 13065 } 13066 } 13067 DCHECK(SMI_VALUE(ends->get(info->line)) >= position && 13068 SMI_VALUE(ends->get(info->line - 1)) < position); 13069 info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1; 13070 info->column = position - info->line_start; 13071 } 13072 13073 // Line end is position of the linebreak character. 13074 info->line_end = SMI_VALUE(ends->get(info->line)); 13075 if (info->line_end > 0) { 13076 DCHECK(source()->IsString()); 13077 String* src = String::cast(source()); 13078 if (src->length() >= info->line_end && 13079 src->Get(info->line_end - 1) == '\r') { 13080 info->line_end--; 13081 } 13082 } 13083 } 13084 13085 // Add offsets if requested. 13086 if (offset_flag == WITH_OFFSET) { 13087 if (info->line == 0) { 13088 info->column += column_offset(); 13089 } 13090 info->line += line_offset(); 13091 } 13092 13093 return true; 13094 } 13095 #undef SMI_VALUE 13096 13097 int Script::GetColumnNumber(Handle<Script> script, int code_pos) { 13098 PositionInfo info; 13099 GetPositionInfo(script, code_pos, &info, WITH_OFFSET); 13100 return info.column; 13101 } 13102 13103 int Script::GetColumnNumber(int code_pos) const { 13104 PositionInfo info; 13105 GetPositionInfo(code_pos, &info, WITH_OFFSET); 13106 return info.column; 13107 } 13108 13109 int Script::GetLineNumber(Handle<Script> script, int code_pos) { 13110 PositionInfo info; 13111 GetPositionInfo(script, code_pos, &info, WITH_OFFSET); 13112 return info.line; 13113 } 13114 13115 int Script::GetLineNumber(int code_pos) const { 13116 PositionInfo info; 13117 GetPositionInfo(code_pos, &info, WITH_OFFSET); 13118 return info.line; 13119 } 13120 13121 Object* Script::GetNameOrSourceURL() { 13122 Isolate* isolate = GetIsolate(); 13123 // Keep in sync with ScriptNameOrSourceURL in messages.js. 13124 if (!source_url()->IsUndefined(isolate)) return source_url(); 13125 return name(); 13126 } 13127 13128 13129 Handle<JSObject> Script::GetWrapper(Handle<Script> script) { 13130 Isolate* isolate = script->GetIsolate(); 13131 if (!script->wrapper()->IsUndefined(isolate)) { 13132 DCHECK(script->wrapper()->IsWeakCell()); 13133 Handle<WeakCell> cell(WeakCell::cast(script->wrapper())); 13134 if (!cell->cleared()) { 13135 // Return a handle for the existing script wrapper from the cache. 13136 return handle(JSObject::cast(cell->value())); 13137 } 13138 // If we found an empty WeakCell, that means the script wrapper was 13139 // GCed. We are not notified directly of that, so we decrement here 13140 // so that we at least don't count double for any given script. 13141 isolate->counters()->script_wrappers()->Decrement(); 13142 } 13143 // Construct a new script wrapper. 13144 isolate->counters()->script_wrappers()->Increment(); 13145 Handle<JSFunction> constructor = isolate->script_function(); 13146 Handle<JSValue> result = 13147 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor)); 13148 result->set_value(*script); 13149 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result); 13150 script->set_wrapper(*cell); 13151 return result; 13152 } 13153 13154 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( 13155 Isolate* isolate, const FunctionLiteral* fun) { 13156 DCHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid); 13157 DCHECK_LT(fun->function_literal_id(), shared_function_infos()->length()); 13158 Object* shared = shared_function_infos()->get(fun->function_literal_id()); 13159 if (shared->IsUndefined(isolate) || WeakCell::cast(shared)->cleared()) { 13160 return MaybeHandle<SharedFunctionInfo>(); 13161 } 13162 return handle(SharedFunctionInfo::cast(WeakCell::cast(shared)->value())); 13163 } 13164 13165 Script::Iterator::Iterator(Isolate* isolate) 13166 : iterator_(isolate->heap()->script_list()) {} 13167 13168 13169 Script* Script::Iterator::Next() { return iterator_.Next<Script>(); } 13170 13171 SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script) 13172 : ScriptIterator(script->GetIsolate(), 13173 handle(script->shared_function_infos())) {} 13174 13175 SharedFunctionInfo::ScriptIterator::ScriptIterator( 13176 Isolate* isolate, Handle<FixedArray> shared_function_infos) 13177 : isolate_(isolate), 13178 shared_function_infos_(shared_function_infos), 13179 index_(0) {} 13180 13181 SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() { 13182 while (index_ < shared_function_infos_->length()) { 13183 Object* raw = shared_function_infos_->get(index_++); 13184 if (raw->IsUndefined(isolate_) || WeakCell::cast(raw)->cleared()) continue; 13185 return SharedFunctionInfo::cast(WeakCell::cast(raw)->value()); 13186 } 13187 return nullptr; 13188 } 13189 13190 void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) { 13191 shared_function_infos_ = handle(script->shared_function_infos()); 13192 index_ = 0; 13193 } 13194 13195 SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate) 13196 : script_iterator_(isolate), 13197 noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()), 13198 sfi_iterator_(handle(script_iterator_.Next(), isolate)) {} 13199 13200 SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() { 13201 SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>(); 13202 if (next != nullptr) return next; 13203 for (;;) { 13204 next = sfi_iterator_.Next(); 13205 if (next != nullptr) return next; 13206 Script* next_script = script_iterator_.Next(); 13207 if (next_script == nullptr) return nullptr; 13208 sfi_iterator_.Reset(handle(next_script)); 13209 } 13210 } 13211 13212 13213 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared, 13214 Handle<Object> script_object) { 13215 DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid); 13216 if (shared->script() == *script_object) return; 13217 Isolate* isolate = shared->GetIsolate(); 13218 13219 // Add shared function info to new script's list. If a collection occurs, 13220 // the shared function info may be temporarily in two lists. 13221 // This is okay because the gc-time processing of these lists can tolerate 13222 // duplicates. 13223 if (script_object->IsScript()) { 13224 Handle<Script> script = Handle<Script>::cast(script_object); 13225 Handle<FixedArray> list = handle(script->shared_function_infos(), isolate); 13226 #ifdef DEBUG 13227 DCHECK_LT(shared->function_literal_id(), list->length()); 13228 if (list->get(shared->function_literal_id())->IsWeakCell() && 13229 !WeakCell::cast(list->get(shared->function_literal_id()))->cleared()) { 13230 DCHECK( 13231 WeakCell::cast(list->get(shared->function_literal_id()))->value() == 13232 *shared); 13233 } 13234 #endif 13235 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(shared); 13236 list->set(shared->function_literal_id(), *cell); 13237 } else { 13238 Handle<Object> list = isolate->factory()->noscript_shared_function_infos(); 13239 13240 #ifdef DEBUG 13241 if (FLAG_enable_slow_asserts) { 13242 WeakFixedArray::Iterator iterator(*list); 13243 SharedFunctionInfo* next; 13244 while ((next = iterator.Next<SharedFunctionInfo>())) { 13245 DCHECK_NE(next, *shared); 13246 } 13247 } 13248 #endif // DEBUG 13249 13250 list = WeakFixedArray::Add(list, shared); 13251 13252 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list); 13253 } 13254 13255 if (shared->script()->IsScript()) { 13256 // Remove shared function info from old script's list. 13257 Script* old_script = Script::cast(shared->script()); 13258 13259 // Due to liveedit, it might happen that the old_script doesn't know 13260 // about the SharedFunctionInfo, so we have to guard against that. 13261 Handle<FixedArray> infos(old_script->shared_function_infos(), isolate); 13262 if (shared->function_literal_id() < infos->length()) { 13263 Object* raw = old_script->shared_function_infos()->get( 13264 shared->function_literal_id()); 13265 if (!raw->IsWeakCell() || WeakCell::cast(raw)->value() == *shared) { 13266 old_script->shared_function_infos()->set( 13267 shared->function_literal_id(), isolate->heap()->undefined_value()); 13268 } 13269 } 13270 } else { 13271 // Remove shared function info from root array. 13272 Object* list = isolate->heap()->noscript_shared_function_infos(); 13273 CHECK(WeakFixedArray::cast(list)->Remove(shared)); 13274 } 13275 13276 // Finally set new script. 13277 shared->set_script(*script_object); 13278 } 13279 13280 13281 String* SharedFunctionInfo::DebugName() { 13282 Object* n = name(); 13283 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name(); 13284 return String::cast(n); 13285 } 13286 13287 bool SharedFunctionInfo::HasNoSideEffect() { 13288 if (!computed_has_no_side_effect()) { 13289 DisallowHeapAllocation not_handlified; 13290 Handle<SharedFunctionInfo> info(this); 13291 set_has_no_side_effect(DebugEvaluate::FunctionHasNoSideEffect(info)); 13292 set_computed_has_no_side_effect(true); 13293 } 13294 return has_no_side_effect(); 13295 } 13296 13297 // The filter is a pattern that matches function names in this way: 13298 // "*" all; the default 13299 // "-" all but the top-level function 13300 // "-name" all but the function "name" 13301 // "" only the top-level function 13302 // "name" only the function "name" 13303 // "name*" only functions starting with "name" 13304 // "~" none; the tilde is not an identifier 13305 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) { 13306 if (*raw_filter == '*') return true; 13307 String* name = DebugName(); 13308 Vector<const char> filter = CStrVector(raw_filter); 13309 if (filter.length() == 0) return name->length() == 0; 13310 if (filter[0] == '-') { 13311 // Negative filter. 13312 if (filter.length() == 1) { 13313 return (name->length() != 0); 13314 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) { 13315 return false; 13316 } 13317 if (filter[filter.length() - 1] == '*' && 13318 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) { 13319 return false; 13320 } 13321 return true; 13322 13323 } else if (name->IsUtf8EqualTo(filter)) { 13324 return true; 13325 } 13326 if (filter[filter.length() - 1] == '*' && 13327 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) { 13328 return true; 13329 } 13330 return false; 13331 } 13332 13333 bool SharedFunctionInfo::HasSourceCode() const { 13334 Isolate* isolate = GetIsolate(); 13335 return !script()->IsUndefined(isolate) && 13336 !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate); 13337 } 13338 13339 13340 Handle<Object> SharedFunctionInfo::GetSourceCode() { 13341 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value(); 13342 Handle<String> source(String::cast(Script::cast(script())->source())); 13343 return GetIsolate()->factory()->NewSubString( 13344 source, start_position(), end_position()); 13345 } 13346 13347 Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() { 13348 Isolate* isolate = GetIsolate(); 13349 if (!HasSourceCode()) return isolate->factory()->undefined_value(); 13350 Handle<String> script_source(String::cast(Script::cast(script())->source())); 13351 int start_pos = function_token_position(); 13352 if (start_pos == kNoSourcePosition) start_pos = start_position(); 13353 return isolate->factory()->NewSubString(script_source, start_pos, 13354 end_position()); 13355 } 13356 13357 bool SharedFunctionInfo::IsInlineable() { 13358 // Check that the function has a script associated with it. 13359 if (!script()->IsScript()) return false; 13360 return !optimization_disabled(); 13361 } 13362 13363 13364 int SharedFunctionInfo::SourceSize() { 13365 return end_position() - start_position(); 13366 } 13367 13368 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type, 13369 int requested_internal_fields, 13370 int requested_in_object_properties, 13371 int* instance_size, 13372 int* in_object_properties) { 13373 int header_size = JSObject::GetHeaderSize(instance_type); 13374 DCHECK_LE(requested_internal_fields, 13375 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2); 13376 *instance_size = 13377 Min(header_size + 13378 ((requested_internal_fields + requested_in_object_properties) 13379 << kPointerSizeLog2), 13380 JSObject::kMaxInstanceSize); 13381 *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) - 13382 requested_internal_fields; 13383 } 13384 13385 13386 void JSFunction::CalculateInstanceSize(InstanceType instance_type, 13387 int requested_internal_fields, 13388 int* instance_size, 13389 int* in_object_properties) { 13390 CalculateInstanceSizeHelper(instance_type, requested_internal_fields, 13391 shared()->expected_nof_properties(), 13392 instance_size, in_object_properties); 13393 } 13394 13395 13396 void JSFunction::CalculateInstanceSizeForDerivedClass( 13397 InstanceType instance_type, int requested_internal_fields, 13398 int* instance_size, int* in_object_properties) { 13399 Isolate* isolate = GetIsolate(); 13400 int expected_nof_properties = 0; 13401 for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd(); 13402 iter.Advance()) { 13403 JSReceiver* current = iter.GetCurrent<JSReceiver>(); 13404 if (!current->IsJSFunction()) break; 13405 JSFunction* func = JSFunction::cast(current); 13406 SharedFunctionInfo* shared = func->shared(); 13407 expected_nof_properties += shared->expected_nof_properties(); 13408 if (!IsDerivedConstructor(shared->kind())) { 13409 break; 13410 } 13411 } 13412 CalculateInstanceSizeHelper(instance_type, requested_internal_fields, 13413 expected_nof_properties, instance_size, 13414 in_object_properties); 13415 } 13416 13417 13418 // Output the source code without any allocation in the heap. 13419 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) { 13420 const SharedFunctionInfo* s = v.value; 13421 // For some native functions there is no source. 13422 if (!s->HasSourceCode()) return os << "<No Source>"; 13423 13424 // Get the source for the script which this function came from. 13425 // Don't use String::cast because we don't want more assertion errors while 13426 // we are already creating a stack dump. 13427 String* script_source = 13428 reinterpret_cast<String*>(Script::cast(s->script())->source()); 13429 13430 if (!script_source->LooksValid()) return os << "<Invalid Source>"; 13431 13432 if (!s->is_toplevel()) { 13433 os << "function "; 13434 Object* name = s->name(); 13435 if (name->IsString() && String::cast(name)->length() > 0) { 13436 String::cast(name)->PrintUC16(os); 13437 } 13438 } 13439 13440 int len = s->end_position() - s->start_position(); 13441 if (len <= v.max_length || v.max_length < 0) { 13442 script_source->PrintUC16(os, s->start_position(), s->end_position()); 13443 return os; 13444 } else { 13445 script_source->PrintUC16(os, s->start_position(), 13446 s->start_position() + v.max_length); 13447 return os << "...\n"; 13448 } 13449 } 13450 13451 13452 static bool IsCodeEquivalent(Code* code, Code* recompiled) { 13453 if (code->instruction_size() != recompiled->instruction_size()) return false; 13454 ByteArray* code_relocation = code->relocation_info(); 13455 ByteArray* recompiled_relocation = recompiled->relocation_info(); 13456 int length = code_relocation->length(); 13457 if (length != recompiled_relocation->length()) return false; 13458 int compare = memcmp(code_relocation->GetDataStartAddress(), 13459 recompiled_relocation->GetDataStartAddress(), 13460 length); 13461 return compare == 0; 13462 } 13463 13464 13465 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) { 13466 DCHECK(!has_deoptimization_support()); 13467 DisallowHeapAllocation no_allocation; 13468 Code* code = this->code(); 13469 if (IsCodeEquivalent(code, recompiled)) { 13470 // Copy the deoptimization data from the recompiled code. 13471 code->set_deoptimization_data(recompiled->deoptimization_data()); 13472 code->set_has_deoptimization_support(true); 13473 } else { 13474 // TODO(3025757): In case the recompiled isn't equivalent to the 13475 // old code, we have to replace it. We should try to avoid this 13476 // altogether because it flushes valuable type feedback by 13477 // effectively resetting all IC state. 13478 ReplaceCode(recompiled); 13479 } 13480 DCHECK(has_deoptimization_support()); 13481 } 13482 13483 13484 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) { 13485 // Disable optimization for the shared function info and mark the 13486 // code as non-optimizable. The marker on the shared function info 13487 // is there because we flush non-optimized code thereby loosing the 13488 // non-optimizable information for the code. When the code is 13489 // regenerated and set on the shared function info it is marked as 13490 // non-optimizable if optimization is disabled for the shared 13491 // function info. 13492 DCHECK(reason != kNoReason); 13493 set_optimization_disabled(true); 13494 set_disable_optimization_reason(reason); 13495 // Code should be the lazy compilation stub or else unoptimized. 13496 DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION || 13497 abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION || 13498 abstract_code()->kind() == AbstractCode::BUILTIN); 13499 PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this)); 13500 if (FLAG_trace_opt) { 13501 PrintF("[disabled optimization for "); 13502 ShortPrint(); 13503 PrintF(", reason: %s]\n", GetBailoutReason(reason)); 13504 } 13505 } 13506 13507 namespace { 13508 13509 // Sets the expected number of properties based on estimate from parser. 13510 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, 13511 FunctionLiteral* literal) { 13512 int estimate = literal->expected_property_count(); 13513 13514 // If no properties are added in the constructor, they are more likely 13515 // to be added later. 13516 if (estimate == 0) estimate = 2; 13517 13518 // TODO(yangguo): check whether those heuristics are still up-to-date. 13519 // We do not shrink objects that go into a snapshot (yet), so we adjust 13520 // the estimate conservatively. 13521 if (shared->GetIsolate()->serializer_enabled()) { 13522 estimate += 2; 13523 } else { 13524 // Inobject slack tracking will reclaim redundant inobject space later, 13525 // so we can afford to adjust the estimate generously. 13526 estimate += 8; 13527 } 13528 13529 shared->set_expected_nof_properties(estimate); 13530 } 13531 13532 } // namespace 13533 13534 void SharedFunctionInfo::InitFromFunctionLiteral( 13535 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) { 13536 // When adding fields here, make sure DeclarationScope::AnalyzePartially is 13537 // updated accordingly. 13538 shared_info->set_length(lit->function_length()); 13539 shared_info->set_internal_formal_parameter_count(lit->parameter_count()); 13540 shared_info->set_function_token_position(lit->function_token_position()); 13541 shared_info->set_start_position(lit->start_position()); 13542 shared_info->set_end_position(lit->end_position()); 13543 shared_info->set_is_declaration(lit->is_declaration()); 13544 shared_info->set_is_named_expression(lit->is_named_expression()); 13545 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression()); 13546 shared_info->set_inferred_name(*lit->inferred_name()); 13547 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); 13548 shared_info->set_language_mode(lit->language_mode()); 13549 shared_info->set_uses_arguments(lit->scope()->arguments() != NULL); 13550 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); 13551 shared_info->set_kind(lit->kind()); 13552 if (!IsConstructable(lit->kind(), lit->language_mode())) { 13553 shared_info->SetConstructStub( 13554 *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable()); 13555 } 13556 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject()); 13557 shared_info->set_asm_function(lit->scope()->asm_function()); 13558 shared_info->set_function_literal_id(lit->function_literal_id()); 13559 SetExpectedNofPropertiesFromEstimate(shared_info, lit); 13560 } 13561 13562 13563 bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) { 13564 DCHECK(!id.IsNone()); 13565 Code* unoptimized = code(); 13566 DeoptimizationOutputData* data = 13567 DeoptimizationOutputData::cast(unoptimized->deoptimization_data()); 13568 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this); 13569 USE(ignore); 13570 return true; // Return true if there was no DCHECK. 13571 } 13572 13573 void SharedFunctionInfo::SetConstructStub(Code* code) { 13574 if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true); 13575 set_construct_stub(code); 13576 } 13577 13578 void Map::StartInobjectSlackTracking() { 13579 DCHECK(!IsInobjectSlackTrackingInProgress()); 13580 13581 // No tracking during the snapshot construction phase. 13582 Isolate* isolate = GetIsolate(); 13583 if (isolate->serializer_enabled()) return; 13584 13585 if (unused_property_fields() == 0) return; 13586 13587 set_construction_counter(Map::kSlackTrackingCounterStart); 13588 } 13589 13590 13591 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) { 13592 code()->ClearInlineCaches(); 13593 set_ic_age(new_ic_age); 13594 if (code()->kind() == Code::FUNCTION) { 13595 code()->set_profiler_ticks(0); 13596 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) { 13597 // Re-enable optimizations if they were disabled due to opt_count limit. 13598 set_optimization_disabled(false); 13599 } 13600 set_opt_count(0); 13601 set_deopt_count(0); 13602 } else if (IsInterpreted()) { 13603 set_profiler_ticks(0); 13604 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) { 13605 // Re-enable optimizations if they were disabled due to opt_count limit. 13606 set_optimization_disabled(false); 13607 } 13608 set_opt_count(0); 13609 set_deopt_count(0); 13610 } 13611 } 13612 13613 int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context) { 13614 DisallowHeapAllocation no_gc; 13615 DCHECK(native_context->IsNativeContext()); 13616 if (!OptimizedCodeMapIsCleared()) { 13617 FixedArray* optimized_code_map = this->optimized_code_map(); 13618 int length = optimized_code_map->length(); 13619 for (int i = kEntriesStart; i < length; i += kEntryLength) { 13620 if (WeakCell::cast(optimized_code_map->get(i + kContextOffset)) 13621 ->value() == native_context) { 13622 return i; 13623 } 13624 } 13625 } 13626 return -1; 13627 } 13628 13629 void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() { 13630 if (!OptimizedCodeMapIsCleared()) { 13631 FixedArray* optimized_code_map = this->optimized_code_map(); 13632 int length = optimized_code_map->length(); 13633 WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell(); 13634 for (int i = kEntriesStart; i < length; i += kEntryLength) { 13635 optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell, 13636 SKIP_WRITE_BARRIER); 13637 } 13638 } 13639 } 13640 13641 Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context, 13642 BailoutId osr_ast_id) { 13643 Code* result = nullptr; 13644 if (!osr_ast_id.IsNone()) { 13645 return native_context->SearchOptimizedCodeMap(this, osr_ast_id); 13646 } 13647 13648 DCHECK(osr_ast_id.IsNone()); 13649 int entry = SearchOptimizedCodeMapEntry(native_context); 13650 if (entry != kNotFound) { 13651 FixedArray* code_map = optimized_code_map(); 13652 DCHECK_LE(entry + kEntryLength, code_map->length()); 13653 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset)); 13654 result = cell->cleared() ? nullptr : Code::cast(cell->value()); 13655 } 13656 return result; 13657 } 13658 13659 13660 #define DECLARE_TAG(ignore1, name, ignore2) name, 13661 const char* const VisitorSynchronization::kTags[ 13662 VisitorSynchronization::kNumberOfSyncTags] = { 13663 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG) 13664 }; 13665 #undef DECLARE_TAG 13666 13667 13668 #define DECLARE_TAG(ignore1, ignore2, name) name, 13669 const char* const VisitorSynchronization::kTagNames[ 13670 VisitorSynchronization::kNumberOfSyncTags] = { 13671 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG) 13672 }; 13673 #undef DECLARE_TAG 13674 13675 13676 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { 13677 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); 13678 Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address()); 13679 Object* new_pointer = old_pointer; 13680 VisitPointer(&new_pointer); 13681 DCHECK_EQ(old_pointer, new_pointer); 13682 } 13683 13684 13685 void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) { 13686 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); 13687 Object* old_pointer = rinfo->code_age_stub(); 13688 Object* new_pointer = old_pointer; 13689 if (old_pointer != nullptr) { 13690 VisitPointer(&new_pointer); 13691 DCHECK_EQ(old_pointer, new_pointer); 13692 } 13693 } 13694 13695 13696 void ObjectVisitor::VisitCodeEntry(Address entry_address) { 13697 Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address); 13698 Object* new_pointer = old_pointer; 13699 VisitPointer(&new_pointer); 13700 DCHECK_EQ(old_pointer, new_pointer); 13701 } 13702 13703 13704 void ObjectVisitor::VisitCell(RelocInfo* rinfo) { 13705 DCHECK(rinfo->rmode() == RelocInfo::CELL); 13706 Object* old_pointer = rinfo->target_cell(); 13707 Object* new_pointer = old_pointer; 13708 VisitPointer(&new_pointer); 13709 DCHECK_EQ(old_pointer, new_pointer); 13710 } 13711 13712 13713 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) { 13714 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 13715 rinfo->IsPatchedDebugBreakSlotSequence()); 13716 Object* old_pointer = 13717 Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); 13718 Object* new_pointer = old_pointer; 13719 VisitPointer(&new_pointer); 13720 DCHECK_EQ(old_pointer, new_pointer); 13721 } 13722 13723 13724 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) { 13725 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); 13726 Object* old_pointer = rinfo->target_object(); 13727 Object* new_pointer = old_pointer; 13728 VisitPointer(&new_pointer); 13729 DCHECK_EQ(old_pointer, new_pointer); 13730 } 13731 13732 13733 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) { 13734 Address old_reference = rinfo->target_external_reference(); 13735 Address new_reference = old_reference; 13736 VisitExternalReference(&new_reference); 13737 DCHECK_EQ(old_reference, new_reference); 13738 } 13739 13740 13741 void Code::InvalidateRelocation() { 13742 InvalidateEmbeddedObjects(); 13743 set_relocation_info(GetHeap()->empty_byte_array()); 13744 } 13745 13746 13747 void Code::InvalidateEmbeddedObjects() { 13748 Object* undefined = GetHeap()->undefined_value(); 13749 Cell* undefined_cell = GetHeap()->undefined_cell(); 13750 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 13751 RelocInfo::ModeMask(RelocInfo::CELL); 13752 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 13753 RelocInfo::Mode mode = it.rinfo()->rmode(); 13754 if (mode == RelocInfo::EMBEDDED_OBJECT) { 13755 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER); 13756 } else if (mode == RelocInfo::CELL) { 13757 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER); 13758 } 13759 } 13760 } 13761 13762 13763 void Code::Relocate(intptr_t delta) { 13764 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { 13765 it.rinfo()->apply(delta); 13766 } 13767 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size()); 13768 } 13769 13770 13771 void Code::CopyFrom(const CodeDesc& desc) { 13772 // copy code 13773 CopyBytes(instruction_start(), desc.buffer, 13774 static_cast<size_t>(desc.instr_size)); 13775 13776 // copy unwinding info, if any 13777 if (desc.unwinding_info) { 13778 DCHECK_GT(desc.unwinding_info_size, 0); 13779 set_unwinding_info_size(desc.unwinding_info_size); 13780 CopyBytes(unwinding_info_start(), desc.unwinding_info, 13781 static_cast<size_t>(desc.unwinding_info_size)); 13782 } 13783 13784 // copy reloc info 13785 CopyBytes(relocation_start(), 13786 desc.buffer + desc.buffer_size - desc.reloc_size, 13787 static_cast<size_t>(desc.reloc_size)); 13788 13789 // unbox handles and relocate 13790 intptr_t delta = instruction_start() - desc.buffer; 13791 int mode_mask = RelocInfo::kCodeTargetMask | 13792 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 13793 RelocInfo::ModeMask(RelocInfo::CELL) | 13794 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | 13795 RelocInfo::kApplyMask; 13796 // Needed to find target_object and runtime_entry on X64 13797 Assembler* origin = desc.origin; 13798 AllowDeferredHandleDereference embedding_raw_address; 13799 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 13800 RelocInfo::Mode mode = it.rinfo()->rmode(); 13801 if (mode == RelocInfo::EMBEDDED_OBJECT) { 13802 Handle<Object> p = it.rinfo()->target_object_handle(origin); 13803 it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER, 13804 SKIP_ICACHE_FLUSH); 13805 } else if (mode == RelocInfo::CELL) { 13806 Handle<Cell> cell = it.rinfo()->target_cell_handle(); 13807 it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER, 13808 SKIP_ICACHE_FLUSH); 13809 } else if (RelocInfo::IsCodeTarget(mode)) { 13810 // rewrite code handles in inline cache targets to direct 13811 // pointers to the first instruction in the code object 13812 Handle<Object> p = it.rinfo()->target_object_handle(origin); 13813 Code* code = Code::cast(*p); 13814 it.rinfo()->set_target_address(code->instruction_start(), 13815 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); 13816 } else if (RelocInfo::IsRuntimeEntry(mode)) { 13817 Address p = it.rinfo()->target_runtime_entry(origin); 13818 it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER, 13819 SKIP_ICACHE_FLUSH); 13820 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) { 13821 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin); 13822 Code* code = Code::cast(*p); 13823 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH); 13824 } else { 13825 it.rinfo()->apply(delta); 13826 } 13827 } 13828 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size()); 13829 } 13830 13831 13832 SafepointEntry Code::GetSafepointEntry(Address pc) { 13833 SafepointTable table(this); 13834 return table.FindEntry(pc); 13835 } 13836 13837 13838 Object* Code::FindNthObject(int n, Map* match_map) { 13839 DCHECK(is_inline_cache_stub()); 13840 DisallowHeapAllocation no_allocation; 13841 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 13842 for (RelocIterator it(this, mask); !it.done(); it.next()) { 13843 RelocInfo* info = it.rinfo(); 13844 Object* object = info->target_object(); 13845 if (object->IsWeakCell()) object = WeakCell::cast(object)->value(); 13846 if (object->IsHeapObject()) { 13847 if (HeapObject::cast(object)->map() == match_map) { 13848 if (--n == 0) return object; 13849 } 13850 } 13851 } 13852 return NULL; 13853 } 13854 13855 13856 AllocationSite* Code::FindFirstAllocationSite() { 13857 Object* result = FindNthObject(1, GetHeap()->allocation_site_map()); 13858 return (result != NULL) ? AllocationSite::cast(result) : NULL; 13859 } 13860 13861 13862 Map* Code::FindFirstMap() { 13863 Object* result = FindNthObject(1, GetHeap()->meta_map()); 13864 return (result != NULL) ? Map::cast(result) : NULL; 13865 } 13866 13867 13868 void Code::FindAndReplace(const FindAndReplacePattern& pattern) { 13869 DCHECK(is_inline_cache_stub() || is_handler()); 13870 DisallowHeapAllocation no_allocation; 13871 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 13872 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32); 13873 int current_pattern = 0; 13874 for (RelocIterator it(this, mask); !it.done(); it.next()) { 13875 RelocInfo* info = it.rinfo(); 13876 Object* object = info->target_object(); 13877 if (object->IsHeapObject()) { 13878 if (object->IsWeakCell()) { 13879 object = HeapObject::cast(WeakCell::cast(object)->value()); 13880 } 13881 Map* map = HeapObject::cast(object)->map(); 13882 if (map == *pattern.find_[current_pattern]) { 13883 info->set_target_object(*pattern.replace_[current_pattern]); 13884 if (++current_pattern == pattern.count_) return; 13885 } 13886 } 13887 } 13888 UNREACHABLE(); 13889 } 13890 13891 13892 void Code::ClearInlineCaches() { 13893 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | 13894 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); 13895 for (RelocIterator it(this, mask); !it.done(); it.next()) { 13896 RelocInfo* info = it.rinfo(); 13897 Code* target(Code::GetCodeFromTargetAddress(info->target_address())); 13898 if (target->is_inline_cache_stub()) { 13899 ICUtility::Clear(this->GetIsolate(), info->pc(), 13900 info->host()->constant_pool()); 13901 } 13902 } 13903 } 13904 13905 int AbstractCode::SourcePosition(int offset) { 13906 int position = 0; 13907 // Subtract one because the current PC is one instruction after the call site. 13908 if (IsCode()) offset--; 13909 for (SourcePositionTableIterator iterator(source_position_table()); 13910 !iterator.done() && iterator.code_offset() <= offset; 13911 iterator.Advance()) { 13912 position = iterator.source_position().ScriptOffset(); 13913 } 13914 return position; 13915 } 13916 13917 int AbstractCode::SourceStatementPosition(int offset) { 13918 // First find the closest position. 13919 int position = SourcePosition(offset); 13920 // Now find the closest statement position before the position. 13921 int statement_position = 0; 13922 for (SourcePositionTableIterator it(source_position_table()); !it.done(); 13923 it.Advance()) { 13924 if (it.is_statement()) { 13925 int p = it.source_position().ScriptOffset(); 13926 if (statement_position < p && p <= position) { 13927 statement_position = p; 13928 } 13929 } 13930 } 13931 return statement_position; 13932 } 13933 13934 void JSFunction::ClearTypeFeedbackInfo() { 13935 if (feedback_vector_cell()->value()->IsFeedbackVector()) { 13936 FeedbackVector* vector = feedback_vector(); 13937 vector->ClearSlots(this); 13938 } 13939 } 13940 13941 BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) { 13942 DisallowHeapAllocation no_gc; 13943 DCHECK(kind() == FUNCTION); 13944 BackEdgeTable back_edges(this, &no_gc); 13945 for (uint32_t i = 0; i < back_edges.length(); i++) { 13946 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i); 13947 } 13948 return BailoutId::None(); 13949 } 13950 13951 13952 uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) { 13953 DisallowHeapAllocation no_gc; 13954 DCHECK(kind() == FUNCTION); 13955 BackEdgeTable back_edges(this, &no_gc); 13956 for (uint32_t i = 0; i < back_edges.length(); i++) { 13957 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i); 13958 } 13959 UNREACHABLE(); // We expect to find the back edge. 13960 return 0; 13961 } 13962 13963 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) { 13964 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge); 13965 } 13966 13967 13968 void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) { 13969 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge); 13970 } 13971 13972 13973 // NextAge defines the Code::Age state transitions during a GC cycle. 13974 static Code::Age NextAge(Code::Age age) { 13975 switch (age) { 13976 case Code::kNotExecutedCodeAge: // Keep, until we've been executed. 13977 case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed. 13978 case Code::kLastCodeAge: // Clamp at last Code::Age value. 13979 return age; 13980 case Code::kExecutedOnceCodeAge: 13981 // Pre-age code that has only been executed once. 13982 return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1); 13983 default: 13984 return static_cast<Code::Age>(age + 1); // Default case: Increase age. 13985 } 13986 } 13987 13988 13989 // IsOldAge defines the collection criteria for a Code object. 13990 static bool IsOldAge(Code::Age age) { 13991 return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge; 13992 } 13993 13994 13995 void Code::MakeYoung(Isolate* isolate) { 13996 byte* sequence = FindCodeAgeSequence(); 13997 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate); 13998 } 13999 14000 void Code::PreAge(Isolate* isolate) { 14001 byte* sequence = FindCodeAgeSequence(); 14002 if (sequence != NULL) { 14003 PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge); 14004 } 14005 } 14006 14007 void Code::MarkToBeExecutedOnce(Isolate* isolate) { 14008 byte* sequence = FindCodeAgeSequence(); 14009 if (sequence != NULL) { 14010 PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge); 14011 } 14012 } 14013 14014 void Code::MakeOlder() { 14015 byte* sequence = FindCodeAgeSequence(); 14016 if (sequence != NULL) { 14017 Isolate* isolate = GetIsolate(); 14018 Age age = GetCodeAge(isolate, sequence); 14019 Age next_age = NextAge(age); 14020 if (age != next_age) { 14021 PatchPlatformCodeAge(isolate, sequence, next_age); 14022 } 14023 } 14024 } 14025 14026 14027 bool Code::IsOld() { 14028 return IsOldAge(GetAge()); 14029 } 14030 14031 14032 byte* Code::FindCodeAgeSequence() { 14033 return FLAG_age_code && 14034 prologue_offset() != Code::kPrologueOffsetNotSet && 14035 (kind() == OPTIMIZED_FUNCTION || 14036 (kind() == FUNCTION && !has_debug_break_slots())) 14037 ? instruction_start() + prologue_offset() 14038 : NULL; 14039 } 14040 14041 14042 Code::Age Code::GetAge() { 14043 byte* sequence = FindCodeAgeSequence(); 14044 if (sequence == NULL) { 14045 return kNoAgeCodeAge; 14046 } 14047 return GetCodeAge(GetIsolate(), sequence); 14048 } 14049 14050 Code::Age Code::GetAgeOfCodeAgeStub(Code* code) { 14051 Isolate* isolate = code->GetIsolate(); 14052 Builtins* builtins = isolate->builtins(); 14053 #define HANDLE_CODE_AGE(AGE) \ 14054 if (code == *builtins->Make##AGE##CodeYoungAgain()) { \ 14055 return k##AGE##CodeAge; \ 14056 } 14057 CODE_AGE_LIST(HANDLE_CODE_AGE) 14058 #undef HANDLE_CODE_AGE 14059 if (code == *builtins->MarkCodeAsExecutedOnce()) { 14060 return kNotExecutedCodeAge; 14061 } 14062 if (code == *builtins->MarkCodeAsExecutedTwice()) { 14063 return kExecutedOnceCodeAge; 14064 } 14065 if (code == *builtins->MarkCodeAsToBeExecutedOnce()) { 14066 return kToBeExecutedOnceCodeAge; 14067 } 14068 UNREACHABLE(); 14069 return kNoAgeCodeAge; 14070 } 14071 14072 Code* Code::GetCodeAgeStub(Isolate* isolate, Age age) { 14073 Builtins* builtins = isolate->builtins(); 14074 switch (age) { 14075 #define HANDLE_CODE_AGE(AGE) \ 14076 case k##AGE##CodeAge: { \ 14077 return *builtins->Make##AGE##CodeYoungAgain(); \ 14078 } 14079 CODE_AGE_LIST(HANDLE_CODE_AGE) 14080 #undef HANDLE_CODE_AGE 14081 case kNotExecutedCodeAge: { 14082 return *builtins->MarkCodeAsExecutedOnce(); 14083 } 14084 case kExecutedOnceCodeAge: { 14085 return *builtins->MarkCodeAsExecutedTwice(); 14086 } 14087 case kToBeExecutedOnceCodeAge: { 14088 return *builtins->MarkCodeAsToBeExecutedOnce(); 14089 } 14090 default: 14091 UNREACHABLE(); 14092 break; 14093 } 14094 return NULL; 14095 } 14096 14097 14098 void Code::PrintDeoptLocation(FILE* out, Address pc) { 14099 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc); 14100 class SourcePosition pos = info.position; 14101 if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) { 14102 if (FLAG_hydrogen_track_positions) { 14103 PrintF(out, " ;;; deoptimize at %d_%d: %s\n", pos.InliningId(), 14104 pos.ScriptOffset(), DeoptimizeReasonToString(info.deopt_reason)); 14105 } else { 14106 PrintF(out, " ;;; deoptimize at "); 14107 OFStream outstr(out); 14108 pos.Print(outstr, this); 14109 PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason)); 14110 } 14111 } 14112 } 14113 14114 14115 bool Code::CanDeoptAt(Address pc) { 14116 DeoptimizationInputData* deopt_data = 14117 DeoptimizationInputData::cast(deoptimization_data()); 14118 Address code_start_address = instruction_start(); 14119 for (int i = 0; i < deopt_data->DeoptCount(); i++) { 14120 if (deopt_data->Pc(i)->value() == -1) continue; 14121 Address address = code_start_address + deopt_data->Pc(i)->value(); 14122 if (address == pc && deopt_data->AstId(i) != BailoutId::None()) { 14123 return true; 14124 } 14125 } 14126 return false; 14127 } 14128 14129 14130 // Identify kind of code. 14131 const char* Code::Kind2String(Kind kind) { 14132 switch (kind) { 14133 #define CASE(name) case name: return #name; 14134 CODE_KIND_LIST(CASE) 14135 #undef CASE 14136 case NUMBER_OF_KINDS: break; 14137 } 14138 UNREACHABLE(); 14139 return NULL; 14140 } 14141 14142 // Identify kind of code. 14143 const char* AbstractCode::Kind2String(Kind kind) { 14144 if (kind < AbstractCode::INTERPRETED_FUNCTION) 14145 return Code::Kind2String((Code::Kind)kind); 14146 if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION"; 14147 UNREACHABLE(); 14148 return NULL; 14149 } 14150 14151 Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) { 14152 DCHECK(code->kind() == OPTIMIZED_FUNCTION); 14153 WeakCell* raw_cell = code->CachedWeakCell(); 14154 if (raw_cell != NULL) return Handle<WeakCell>(raw_cell); 14155 Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code); 14156 DeoptimizationInputData::cast(code->deoptimization_data()) 14157 ->SetWeakCellCache(*cell); 14158 return cell; 14159 } 14160 14161 14162 WeakCell* Code::CachedWeakCell() { 14163 DCHECK(kind() == OPTIMIZED_FUNCTION); 14164 Object* weak_cell_cache = 14165 DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache(); 14166 if (weak_cell_cache->IsWeakCell()) { 14167 DCHECK(this == WeakCell::cast(weak_cell_cache)->value()); 14168 return WeakCell::cast(weak_cell_cache); 14169 } 14170 return NULL; 14171 } 14172 14173 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) 14174 14175 const char* Code::ICState2String(InlineCacheState state) { 14176 switch (state) { 14177 case UNINITIALIZED: 14178 return "UNINITIALIZED"; 14179 case PREMONOMORPHIC: 14180 return "PREMONOMORPHIC"; 14181 case MONOMORPHIC: 14182 return "MONOMORPHIC"; 14183 case RECOMPUTE_HANDLER: 14184 return "RECOMPUTE_HANDLER"; 14185 case POLYMORPHIC: 14186 return "POLYMORPHIC"; 14187 case MEGAMORPHIC: 14188 return "MEGAMORPHIC"; 14189 case GENERIC: 14190 return "GENERIC"; 14191 } 14192 UNREACHABLE(); 14193 return NULL; 14194 } 14195 14196 void Code::PrintExtraICState(std::ostream& os, // NOLINT 14197 Kind kind, ExtraICState extra) { 14198 os << "extra_ic_state = "; 14199 if ((kind == STORE_IC || kind == KEYED_STORE_IC) && 14200 is_strict(static_cast<LanguageMode>(extra))) { 14201 os << "STRICT\n"; 14202 } else { 14203 os << extra << "\n"; 14204 } 14205 } 14206 14207 #endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) 14208 14209 #ifdef ENABLE_DISASSEMBLER 14210 14211 void DeoptimizationInputData::DeoptimizationInputDataPrint( 14212 std::ostream& os) { // NOLINT 14213 disasm::NameConverter converter; 14214 int const inlined_function_count = InlinedFunctionCount()->value(); 14215 os << "Inlined functions (count = " << inlined_function_count << ")\n"; 14216 for (int id = 0; id < inlined_function_count; ++id) { 14217 Object* info = LiteralArray()->get(id); 14218 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n"; 14219 } 14220 os << "\n"; 14221 int deopt_count = DeoptCount(); 14222 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n"; 14223 if (0 != deopt_count) { 14224 os << " index ast id argc pc"; 14225 if (FLAG_print_code_verbose) os << " commands"; 14226 os << "\n"; 14227 } 14228 for (int i = 0; i < deopt_count; i++) { 14229 os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " " 14230 << std::setw(6) << ArgumentsStackHeight(i)->value() << " " 14231 << std::setw(6) << Pc(i)->value(); 14232 14233 if (!FLAG_print_code_verbose) { 14234 os << "\n"; 14235 continue; 14236 } 14237 // Print details of the frame translation. 14238 int translation_index = TranslationIndex(i)->value(); 14239 TranslationIterator iterator(TranslationByteArray(), translation_index); 14240 Translation::Opcode opcode = 14241 static_cast<Translation::Opcode>(iterator.Next()); 14242 DCHECK(Translation::BEGIN == opcode); 14243 int frame_count = iterator.Next(); 14244 int jsframe_count = iterator.Next(); 14245 os << " " << Translation::StringFor(opcode) 14246 << " {frame count=" << frame_count 14247 << ", js frame count=" << jsframe_count << "}\n"; 14248 14249 while (iterator.HasNext() && 14250 Translation::BEGIN != 14251 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) { 14252 os << std::setw(31) << " " << Translation::StringFor(opcode) << " "; 14253 14254 switch (opcode) { 14255 case Translation::BEGIN: 14256 UNREACHABLE(); 14257 break; 14258 14259 case Translation::JS_FRAME: { 14260 int ast_id = iterator.Next(); 14261 int shared_info_id = iterator.Next(); 14262 unsigned height = iterator.Next(); 14263 Object* shared_info = LiteralArray()->get(shared_info_id); 14264 os << "{ast_id=" << ast_id << ", function=" 14265 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14266 << ", height=" << height << "}"; 14267 break; 14268 } 14269 14270 case Translation::INTERPRETED_FRAME: { 14271 int bytecode_offset = iterator.Next(); 14272 int shared_info_id = iterator.Next(); 14273 unsigned height = iterator.Next(); 14274 Object* shared_info = LiteralArray()->get(shared_info_id); 14275 os << "{bytecode_offset=" << bytecode_offset << ", function=" 14276 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14277 << ", height=" << height << "}"; 14278 break; 14279 } 14280 14281 case Translation::CONSTRUCT_STUB_FRAME: { 14282 int bailout_id = iterator.Next(); 14283 int shared_info_id = iterator.Next(); 14284 Object* shared_info = LiteralArray()->get(shared_info_id); 14285 unsigned height = iterator.Next(); 14286 os << "{bailout_id=" << bailout_id << ", function=" 14287 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14288 << ", height=" << height << "}"; 14289 break; 14290 } 14291 14292 case Translation::COMPILED_STUB_FRAME: { 14293 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next()); 14294 os << "{kind=" << stub_kind << "}"; 14295 break; 14296 } 14297 14298 case Translation::ARGUMENTS_ADAPTOR_FRAME: { 14299 int shared_info_id = iterator.Next(); 14300 Object* shared_info = LiteralArray()->get(shared_info_id); 14301 unsigned height = iterator.Next(); 14302 os << "{function=" 14303 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14304 << ", height=" << height << "}"; 14305 break; 14306 } 14307 14308 case Translation::TAIL_CALLER_FRAME: { 14309 int shared_info_id = iterator.Next(); 14310 Object* shared_info = LiteralArray()->get(shared_info_id); 14311 os << "{function=" 14312 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14313 << "}"; 14314 break; 14315 } 14316 14317 case Translation::GETTER_STUB_FRAME: 14318 case Translation::SETTER_STUB_FRAME: { 14319 int shared_info_id = iterator.Next(); 14320 Object* shared_info = LiteralArray()->get(shared_info_id); 14321 os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info) 14322 ->DebugName()) << "}"; 14323 break; 14324 } 14325 14326 case Translation::REGISTER: { 14327 int reg_code = iterator.Next(); 14328 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}"; 14329 break; 14330 } 14331 14332 case Translation::INT32_REGISTER: { 14333 int reg_code = iterator.Next(); 14334 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}"; 14335 break; 14336 } 14337 14338 case Translation::UINT32_REGISTER: { 14339 int reg_code = iterator.Next(); 14340 os << "{input=" << converter.NameOfCPURegister(reg_code) 14341 << " (unsigned)}"; 14342 break; 14343 } 14344 14345 case Translation::BOOL_REGISTER: { 14346 int reg_code = iterator.Next(); 14347 os << "{input=" << converter.NameOfCPURegister(reg_code) 14348 << " (bool)}"; 14349 break; 14350 } 14351 14352 case Translation::FLOAT_REGISTER: { 14353 int reg_code = iterator.Next(); 14354 os << "{input=" 14355 << RegisterConfiguration::Crankshaft()->GetFloatRegisterName( 14356 reg_code) 14357 << "}"; 14358 break; 14359 } 14360 14361 case Translation::DOUBLE_REGISTER: { 14362 int reg_code = iterator.Next(); 14363 os << "{input=" 14364 << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName( 14365 reg_code) 14366 << "}"; 14367 break; 14368 } 14369 14370 case Translation::STACK_SLOT: { 14371 int input_slot_index = iterator.Next(); 14372 os << "{input=" << input_slot_index << "}"; 14373 break; 14374 } 14375 14376 case Translation::INT32_STACK_SLOT: { 14377 int input_slot_index = iterator.Next(); 14378 os << "{input=" << input_slot_index << "}"; 14379 break; 14380 } 14381 14382 case Translation::UINT32_STACK_SLOT: { 14383 int input_slot_index = iterator.Next(); 14384 os << "{input=" << input_slot_index << " (unsigned)}"; 14385 break; 14386 } 14387 14388 case Translation::BOOL_STACK_SLOT: { 14389 int input_slot_index = iterator.Next(); 14390 os << "{input=" << input_slot_index << " (bool)}"; 14391 break; 14392 } 14393 14394 case Translation::FLOAT_STACK_SLOT: 14395 case Translation::DOUBLE_STACK_SLOT: { 14396 int input_slot_index = iterator.Next(); 14397 os << "{input=" << input_slot_index << "}"; 14398 break; 14399 } 14400 14401 case Translation::LITERAL: { 14402 int literal_index = iterator.Next(); 14403 Object* literal_value = LiteralArray()->get(literal_index); 14404 os << "{literal_id=" << literal_index << " (" << Brief(literal_value) 14405 << ")}"; 14406 break; 14407 } 14408 14409 case Translation::DUPLICATED_OBJECT: { 14410 int object_index = iterator.Next(); 14411 os << "{object_index=" << object_index << "}"; 14412 break; 14413 } 14414 14415 case Translation::ARGUMENTS_OBJECT: 14416 case Translation::CAPTURED_OBJECT: { 14417 int args_length = iterator.Next(); 14418 os << "{length=" << args_length << "}"; 14419 break; 14420 } 14421 } 14422 os << "\n"; 14423 } 14424 } 14425 } 14426 14427 14428 void DeoptimizationOutputData::DeoptimizationOutputDataPrint( 14429 std::ostream& os) { // NOLINT 14430 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints() 14431 << ")\n"; 14432 if (this->DeoptPoints() == 0) return; 14433 14434 os << "ast id pc state\n"; 14435 for (int i = 0; i < this->DeoptPoints(); i++) { 14436 int pc_and_state = this->PcAndState(i)->value(); 14437 os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8) 14438 << FullCodeGenerator::PcField::decode(pc_and_state) << " " 14439 << Deoptimizer::BailoutStateToString( 14440 FullCodeGenerator::BailoutStateField::decode(pc_and_state)) 14441 << "\n"; 14442 } 14443 } 14444 14445 14446 void HandlerTable::HandlerTableRangePrint(std::ostream& os) { 14447 os << " from to hdlr\n"; 14448 for (int i = 0; i < length(); i += kRangeEntrySize) { 14449 int pc_start = Smi::cast(get(i + kRangeStartIndex))->value(); 14450 int pc_end = Smi::cast(get(i + kRangeEndIndex))->value(); 14451 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value(); 14452 int handler_offset = HandlerOffsetField::decode(handler_field); 14453 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 14454 int data = Smi::cast(get(i + kRangeDataIndex))->value(); 14455 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end 14456 << ") -> " << std::setw(4) << handler_offset 14457 << " (prediction=" << prediction << ", data=" << data << ")\n"; 14458 } 14459 } 14460 14461 14462 void HandlerTable::HandlerTableReturnPrint(std::ostream& os) { 14463 os << " off hdlr (c)\n"; 14464 for (int i = 0; i < length(); i += kReturnEntrySize) { 14465 int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value(); 14466 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value(); 14467 int handler_offset = HandlerOffsetField::decode(handler_field); 14468 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 14469 os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4) 14470 << handler_offset << " (prediction=" << prediction << ")\n"; 14471 } 14472 } 14473 14474 14475 void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT 14476 os << "kind = " << Kind2String(kind()) << "\n"; 14477 if (IsCodeStubOrIC()) { 14478 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this)); 14479 os << "major_key = " << (n == NULL ? "null" : n) << "\n"; 14480 } 14481 if (is_inline_cache_stub()) { 14482 if (!IC::ICUseVector(kind())) { 14483 InlineCacheState ic_state = IC::StateFromCode(this); 14484 os << "ic_state = " << ICState2String(ic_state) << "\n"; 14485 PrintExtraICState(os, kind(), extra_ic_state()); 14486 } 14487 if (is_compare_ic_stub()) { 14488 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC); 14489 CompareICStub stub(stub_key(), GetIsolate()); 14490 os << "compare_state = " << CompareICState::GetStateName(stub.left()) 14491 << "*" << CompareICState::GetStateName(stub.right()) << " -> " 14492 << CompareICState::GetStateName(stub.state()) << "\n"; 14493 os << "compare_operation = " << Token::Name(stub.op()) << "\n"; 14494 } 14495 } 14496 if ((name != nullptr) && (name[0] != '\0')) { 14497 os << "name = " << name << "\n"; 14498 } else if (kind() == BUILTIN) { 14499 name = GetIsolate()->builtins()->Lookup(instruction_start()); 14500 if (name != nullptr) { 14501 os << "name = " << name << "\n"; 14502 } 14503 } else if (kind() == BYTECODE_HANDLER) { 14504 name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this); 14505 if (name != nullptr) { 14506 os << "name = " << name << "\n"; 14507 } 14508 } 14509 if (kind() == OPTIMIZED_FUNCTION) { 14510 os << "stack_slots = " << stack_slots() << "\n"; 14511 } 14512 os << "compiler = " << (is_turbofanned() 14513 ? "turbofan" 14514 : is_crankshafted() ? "crankshaft" 14515 : kind() == Code::FUNCTION 14516 ? "full-codegen" 14517 : "unknown") << "\n"; 14518 14519 os << "Instructions (size = " << instruction_size() << ")\n"; 14520 { 14521 Isolate* isolate = GetIsolate(); 14522 int size = instruction_size(); 14523 int safepoint_offset = 14524 is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size; 14525 int back_edge_offset = (kind() == Code::FUNCTION) 14526 ? static_cast<int>(back_edge_table_offset()) 14527 : size; 14528 int constant_pool_offset = FLAG_enable_embedded_constant_pool 14529 ? this->constant_pool_offset() 14530 : size; 14531 14532 // Stop before reaching any embedded tables 14533 int code_size = Min(safepoint_offset, back_edge_offset); 14534 code_size = Min(code_size, constant_pool_offset); 14535 byte* begin = instruction_start(); 14536 byte* end = begin + code_size; 14537 Disassembler::Decode(isolate, &os, begin, end, this); 14538 14539 if (constant_pool_offset < size) { 14540 int constant_pool_size = size - constant_pool_offset; 14541 DCHECK((constant_pool_size & kPointerAlignmentMask) == 0); 14542 os << "\nConstant Pool (size = " << constant_pool_size << ")\n"; 14543 Vector<char> buf = Vector<char>::New(50); 14544 intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset); 14545 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) { 14546 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr); 14547 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n"; 14548 } 14549 } 14550 } 14551 os << "\n"; 14552 14553 SourcePositionTableIterator it(source_position_table()); 14554 if (!it.done()) { 14555 os << "Source positions:\n pc offset position\n"; 14556 for (; !it.done(); it.Advance()) { 14557 os << std::setw(10) << it.code_offset() << std::setw(10) 14558 << it.source_position().ScriptOffset() 14559 << (it.is_statement() ? " statement" : "") << "\n"; 14560 } 14561 os << "\n"; 14562 } 14563 14564 if (kind() == FUNCTION) { 14565 DeoptimizationOutputData* data = 14566 DeoptimizationOutputData::cast(this->deoptimization_data()); 14567 data->DeoptimizationOutputDataPrint(os); 14568 } else if (kind() == OPTIMIZED_FUNCTION) { 14569 DeoptimizationInputData* data = 14570 DeoptimizationInputData::cast(this->deoptimization_data()); 14571 data->DeoptimizationInputDataPrint(os); 14572 } 14573 os << "\n"; 14574 14575 if (is_crankshafted()) { 14576 SafepointTable table(this); 14577 os << "Safepoints (size = " << table.size() << ")\n"; 14578 for (unsigned i = 0; i < table.length(); i++) { 14579 unsigned pc_offset = table.GetPcOffset(i); 14580 os << static_cast<const void*>(instruction_start() + pc_offset) << " "; 14581 os << std::setw(4) << pc_offset << " "; 14582 table.PrintEntry(i, os); 14583 os << " (sp -> fp) "; 14584 SafepointEntry entry = table.GetEntry(i); 14585 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) { 14586 os << std::setw(6) << entry.deoptimization_index(); 14587 } else { 14588 os << "<none>"; 14589 } 14590 if (entry.argument_count() > 0) { 14591 os << " argc: " << entry.argument_count(); 14592 } 14593 os << "\n"; 14594 } 14595 os << "\n"; 14596 } else if (kind() == FUNCTION) { 14597 unsigned offset = back_edge_table_offset(); 14598 // If there is no back edge table, the "table start" will be at or after 14599 // (due to alignment) the end of the instruction stream. 14600 if (static_cast<int>(offset) < instruction_size()) { 14601 DisallowHeapAllocation no_gc; 14602 BackEdgeTable back_edges(this, &no_gc); 14603 14604 os << "Back edges (size = " << back_edges.length() << ")\n"; 14605 os << "ast_id pc_offset loop_depth\n"; 14606 14607 for (uint32_t i = 0; i < back_edges.length(); i++) { 14608 os << std::setw(6) << back_edges.ast_id(i).ToInt() << " " 14609 << std::setw(9) << back_edges.pc_offset(i) << " " << std::setw(10) 14610 << back_edges.loop_depth(i) << "\n"; 14611 } 14612 14613 os << "\n"; 14614 } 14615 #ifdef OBJECT_PRINT 14616 if (!type_feedback_info()->IsUndefined(GetIsolate())) { 14617 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os); 14618 os << "\n"; 14619 } 14620 #endif 14621 } 14622 14623 if (handler_table()->length() > 0) { 14624 os << "Handler Table (size = " << handler_table()->Size() << ")\n"; 14625 if (kind() == FUNCTION) { 14626 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os); 14627 } else if (kind() == OPTIMIZED_FUNCTION) { 14628 HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os); 14629 } 14630 os << "\n"; 14631 } 14632 14633 os << "RelocInfo (size = " << relocation_size() << ")\n"; 14634 for (RelocIterator it(this); !it.done(); it.next()) { 14635 it.rinfo()->Print(GetIsolate(), os); 14636 } 14637 os << "\n"; 14638 14639 if (has_unwinding_info()) { 14640 os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n"; 14641 EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(), 14642 unwinding_info_end()); 14643 eh_frame_disassembler.DisassembleToStream(os); 14644 os << "\n"; 14645 } 14646 } 14647 #endif // ENABLE_DISASSEMBLER 14648 14649 14650 void BytecodeArray::Disassemble(std::ostream& os) { 14651 os << "Parameter count " << parameter_count() << "\n"; 14652 os << "Frame size " << frame_size() << "\n"; 14653 14654 const uint8_t* base_address = GetFirstBytecodeAddress(); 14655 SourcePositionTableIterator source_positions(source_position_table()); 14656 14657 interpreter::BytecodeArrayIterator iterator(handle(this)); 14658 while (!iterator.done()) { 14659 if (!source_positions.done() && 14660 iterator.current_offset() == source_positions.code_offset()) { 14661 os << std::setw(5) << source_positions.source_position().ScriptOffset(); 14662 os << (source_positions.is_statement() ? " S> " : " E> "); 14663 source_positions.Advance(); 14664 } else { 14665 os << " "; 14666 } 14667 const uint8_t* current_address = base_address + iterator.current_offset(); 14668 os << reinterpret_cast<const void*>(current_address) << " @ " 14669 << std::setw(4) << iterator.current_offset() << " : "; 14670 interpreter::BytecodeDecoder::Decode(os, current_address, 14671 parameter_count()); 14672 if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) { 14673 const void* jump_target = base_address + iterator.GetJumpTargetOffset(); 14674 os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset() 14675 << ")"; 14676 } 14677 os << std::endl; 14678 iterator.Advance(); 14679 } 14680 14681 if (constant_pool()->length() > 0) { 14682 os << "Constant pool (size = " << constant_pool()->length() << ")\n"; 14683 constant_pool()->Print(); 14684 } 14685 14686 #ifdef ENABLE_DISASSEMBLER 14687 if (handler_table()->length() > 0) { 14688 os << "Handler Table (size = " << handler_table()->Size() << ")\n"; 14689 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os); 14690 } 14691 #endif 14692 } 14693 14694 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) { 14695 BytecodeArray* from = this; 14696 DCHECK_EQ(from->length(), to->length()); 14697 CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(), 14698 from->length()); 14699 } 14700 14701 void BytecodeArray::MakeOlder() { 14702 Age age = bytecode_age(); 14703 if (age < kLastBytecodeAge) { 14704 set_bytecode_age(static_cast<Age>(age + 1)); 14705 } 14706 DCHECK_GE(bytecode_age(), kFirstBytecodeAge); 14707 DCHECK_LE(bytecode_age(), kLastBytecodeAge); 14708 } 14709 14710 bool BytecodeArray::IsOld() const { 14711 return bytecode_age() >= kIsOldBytecodeAge; 14712 } 14713 14714 // static 14715 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { 14716 DCHECK(capacity >= 0); 14717 array->GetIsolate()->factory()->NewJSArrayStorage( 14718 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 14719 } 14720 14721 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) { 14722 // We should never end in here with a pixel or external array. 14723 DCHECK(array->AllowsSetLength()); 14724 if (array->SetLengthWouldNormalize(new_length)) { 14725 JSObject::NormalizeElements(array); 14726 } 14727 array->GetElementsAccessor()->SetLength(array, new_length); 14728 } 14729 14730 14731 // static 14732 void Map::AddDependentCode(Handle<Map> map, 14733 DependentCode::DependencyGroup group, 14734 Handle<Code> code) { 14735 Handle<WeakCell> cell = Code::WeakCellFor(code); 14736 Handle<DependentCode> codes = DependentCode::InsertWeakCode( 14737 Handle<DependentCode>(map->dependent_code()), group, cell); 14738 if (*codes != map->dependent_code()) map->set_dependent_code(*codes); 14739 } 14740 14741 14742 Handle<DependentCode> DependentCode::InsertCompilationDependencies( 14743 Handle<DependentCode> entries, DependencyGroup group, 14744 Handle<Foreign> info) { 14745 return Insert(entries, group, info); 14746 } 14747 14748 14749 Handle<DependentCode> DependentCode::InsertWeakCode( 14750 Handle<DependentCode> entries, DependencyGroup group, 14751 Handle<WeakCell> code_cell) { 14752 return Insert(entries, group, code_cell); 14753 } 14754 14755 14756 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries, 14757 DependencyGroup group, 14758 Handle<Object> object) { 14759 if (entries->length() == 0 || entries->group() > group) { 14760 // There is no such group. 14761 return DependentCode::New(group, object, entries); 14762 } 14763 if (entries->group() < group) { 14764 // The group comes later in the list. 14765 Handle<DependentCode> old_next(entries->next_link()); 14766 Handle<DependentCode> new_next = Insert(old_next, group, object); 14767 if (!old_next.is_identical_to(new_next)) { 14768 entries->set_next_link(*new_next); 14769 } 14770 return entries; 14771 } 14772 DCHECK_EQ(group, entries->group()); 14773 int count = entries->count(); 14774 // Check for existing entry to avoid duplicates. 14775 for (int i = 0; i < count; i++) { 14776 if (entries->object_at(i) == *object) return entries; 14777 } 14778 if (entries->length() < kCodesStartIndex + count + 1) { 14779 entries = EnsureSpace(entries); 14780 // Count could have changed, reload it. 14781 count = entries->count(); 14782 } 14783 entries->set_object_at(count, *object); 14784 entries->set_count(count + 1); 14785 return entries; 14786 } 14787 14788 14789 Handle<DependentCode> DependentCode::New(DependencyGroup group, 14790 Handle<Object> object, 14791 Handle<DependentCode> next) { 14792 Isolate* isolate = next->GetIsolate(); 14793 Handle<DependentCode> result = Handle<DependentCode>::cast( 14794 isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED)); 14795 result->set_next_link(*next); 14796 result->set_flags(GroupField::encode(group) | CountField::encode(1)); 14797 result->set_object_at(0, *object); 14798 return result; 14799 } 14800 14801 14802 Handle<DependentCode> DependentCode::EnsureSpace( 14803 Handle<DependentCode> entries) { 14804 if (entries->Compact()) return entries; 14805 Isolate* isolate = entries->GetIsolate(); 14806 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count()); 14807 int grow_by = capacity - entries->length(); 14808 return Handle<DependentCode>::cast( 14809 isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED)); 14810 } 14811 14812 14813 bool DependentCode::Compact() { 14814 int old_count = count(); 14815 int new_count = 0; 14816 for (int i = 0; i < old_count; i++) { 14817 Object* obj = object_at(i); 14818 if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) { 14819 if (i != new_count) { 14820 copy(i, new_count); 14821 } 14822 new_count++; 14823 } 14824 } 14825 set_count(new_count); 14826 for (int i = new_count; i < old_count; i++) { 14827 clear_at(i); 14828 } 14829 return new_count < old_count; 14830 } 14831 14832 14833 void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info, 14834 WeakCell* code_cell) { 14835 if (this->length() == 0 || this->group() > group) { 14836 // There is no such group. 14837 return; 14838 } 14839 if (this->group() < group) { 14840 // The group comes later in the list. 14841 next_link()->UpdateToFinishedCode(group, info, code_cell); 14842 return; 14843 } 14844 DCHECK_EQ(group, this->group()); 14845 DisallowHeapAllocation no_gc; 14846 int count = this->count(); 14847 for (int i = 0; i < count; i++) { 14848 if (object_at(i) == info) { 14849 set_object_at(i, code_cell); 14850 break; 14851 } 14852 } 14853 #ifdef DEBUG 14854 for (int i = 0; i < count; i++) { 14855 DCHECK(object_at(i) != info); 14856 } 14857 #endif 14858 } 14859 14860 14861 void DependentCode::RemoveCompilationDependencies( 14862 DependentCode::DependencyGroup group, Foreign* info) { 14863 if (this->length() == 0 || this->group() > group) { 14864 // There is no such group. 14865 return; 14866 } 14867 if (this->group() < group) { 14868 // The group comes later in the list. 14869 next_link()->RemoveCompilationDependencies(group, info); 14870 return; 14871 } 14872 DCHECK_EQ(group, this->group()); 14873 DisallowHeapAllocation no_allocation; 14874 int old_count = count(); 14875 // Find compilation info wrapper. 14876 int info_pos = -1; 14877 for (int i = 0; i < old_count; i++) { 14878 if (object_at(i) == info) { 14879 info_pos = i; 14880 break; 14881 } 14882 } 14883 if (info_pos == -1) return; // Not found. 14884 // Use the last code to fill the gap. 14885 if (info_pos < old_count - 1) { 14886 copy(old_count - 1, info_pos); 14887 } 14888 clear_at(old_count - 1); 14889 set_count(old_count - 1); 14890 14891 #ifdef DEBUG 14892 for (int i = 0; i < old_count - 1; i++) { 14893 DCHECK(object_at(i) != info); 14894 } 14895 #endif 14896 } 14897 14898 14899 bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) { 14900 if (this->length() == 0 || this->group() > group) { 14901 // There is no such group. 14902 return false; 14903 } 14904 if (this->group() < group) { 14905 // The group comes later in the list. 14906 return next_link()->Contains(group, code_cell); 14907 } 14908 DCHECK_EQ(group, this->group()); 14909 int count = this->count(); 14910 for (int i = 0; i < count; i++) { 14911 if (object_at(i) == code_cell) return true; 14912 } 14913 return false; 14914 } 14915 14916 14917 bool DependentCode::IsEmpty(DependencyGroup group) { 14918 if (this->length() == 0 || this->group() > group) { 14919 // There is no such group. 14920 return true; 14921 } 14922 if (this->group() < group) { 14923 // The group comes later in the list. 14924 return next_link()->IsEmpty(group); 14925 } 14926 DCHECK_EQ(group, this->group()); 14927 return count() == 0; 14928 } 14929 14930 14931 bool DependentCode::MarkCodeForDeoptimization( 14932 Isolate* isolate, 14933 DependentCode::DependencyGroup group) { 14934 if (this->length() == 0 || this->group() > group) { 14935 // There is no such group. 14936 return false; 14937 } 14938 if (this->group() < group) { 14939 // The group comes later in the list. 14940 return next_link()->MarkCodeForDeoptimization(isolate, group); 14941 } 14942 DCHECK_EQ(group, this->group()); 14943 DisallowHeapAllocation no_allocation_scope; 14944 // Mark all the code that needs to be deoptimized. 14945 bool marked = false; 14946 bool invalidate_embedded_objects = group == kWeakCodeGroup; 14947 int count = this->count(); 14948 for (int i = 0; i < count; i++) { 14949 Object* obj = object_at(i); 14950 if (obj->IsWeakCell()) { 14951 WeakCell* cell = WeakCell::cast(obj); 14952 if (cell->cleared()) continue; 14953 Code* code = Code::cast(cell->value()); 14954 if (!code->marked_for_deoptimization()) { 14955 SetMarkedForDeoptimization(code, group); 14956 if (invalidate_embedded_objects) { 14957 code->InvalidateEmbeddedObjects(); 14958 } 14959 marked = true; 14960 } 14961 } else { 14962 DCHECK(obj->IsForeign()); 14963 CompilationDependencies* info = 14964 reinterpret_cast<CompilationDependencies*>( 14965 Foreign::cast(obj)->foreign_address()); 14966 info->Abort(); 14967 } 14968 } 14969 for (int i = 0; i < count; i++) { 14970 clear_at(i); 14971 } 14972 set_count(0); 14973 return marked; 14974 } 14975 14976 14977 void DependentCode::DeoptimizeDependentCodeGroup( 14978 Isolate* isolate, 14979 DependentCode::DependencyGroup group) { 14980 DCHECK(AllowCodeDependencyChange::IsAllowed()); 14981 DisallowHeapAllocation no_allocation_scope; 14982 bool marked = MarkCodeForDeoptimization(isolate, group); 14983 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate); 14984 } 14985 14986 14987 void DependentCode::SetMarkedForDeoptimization(Code* code, 14988 DependencyGroup group) { 14989 code->set_marked_for_deoptimization(true); 14990 if (FLAG_trace_deopt && 14991 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) { 14992 DeoptimizationInputData* deopt_data = 14993 DeoptimizationInputData::cast(code->deoptimization_data()); 14994 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer()); 14995 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR 14996 " (opt #%d) for deoptimization, reason: %s]\n", 14997 reinterpret_cast<intptr_t>(code), 14998 deopt_data->OptimizationId()->value(), DependencyGroupName(group)); 14999 } 15000 } 15001 15002 15003 const char* DependentCode::DependencyGroupName(DependencyGroup group) { 15004 switch (group) { 15005 case kWeakCodeGroup: 15006 return "weak-code"; 15007 case kTransitionGroup: 15008 return "transition"; 15009 case kPrototypeCheckGroup: 15010 return "prototype-check"; 15011 case kPropertyCellChangedGroup: 15012 return "property-cell-changed"; 15013 case kFieldOwnerGroup: 15014 return "field-owner"; 15015 case kInitialMapChangedGroup: 15016 return "initial-map-changed"; 15017 case kAllocationSiteTenuringChangedGroup: 15018 return "allocation-site-tenuring-changed"; 15019 case kAllocationSiteTransitionChangedGroup: 15020 return "allocation-site-transition-changed"; 15021 } 15022 UNREACHABLE(); 15023 return "?"; 15024 } 15025 15026 15027 Handle<Map> Map::TransitionToPrototype(Handle<Map> map, 15028 Handle<Object> prototype, 15029 PrototypeOptimizationMode mode) { 15030 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype); 15031 if (new_map.is_null()) { 15032 new_map = Copy(map, "TransitionToPrototype"); 15033 TransitionArray::PutPrototypeTransition(map, prototype, new_map); 15034 Map::SetPrototype(new_map, prototype, mode); 15035 } 15036 return new_map; 15037 } 15038 15039 15040 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object, 15041 Handle<Object> value, bool from_javascript, 15042 ShouldThrow should_throw) { 15043 if (object->IsJSProxy()) { 15044 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value, 15045 from_javascript, should_throw); 15046 } 15047 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value, 15048 from_javascript, should_throw); 15049 } 15050 15051 15052 // ES6: 9.5.2 [[SetPrototypeOf]] (V) 15053 // static 15054 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value, 15055 bool from_javascript, 15056 ShouldThrow should_throw) { 15057 Isolate* isolate = proxy->GetIsolate(); 15058 STACK_CHECK(isolate, Nothing<bool>()); 15059 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string(); 15060 // 1. Assert: Either Type(V) is Object or Type(V) is Null. 15061 DCHECK(value->IsJSReceiver() || value->IsNull(isolate)); 15062 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 15063 Handle<Object> handler(proxy->handler(), isolate); 15064 // 3. If handler is null, throw a TypeError exception. 15065 // 4. Assert: Type(handler) is Object. 15066 if (proxy->IsRevoked()) { 15067 isolate->Throw(*isolate->factory()->NewTypeError( 15068 MessageTemplate::kProxyRevoked, trap_name)); 15069 return Nothing<bool>(); 15070 } 15071 // 5. Let target be the value of the [[ProxyTarget]] internal slot. 15072 Handle<JSReceiver> target(proxy->target(), isolate); 15073 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf"). 15074 Handle<Object> trap; 15075 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 15076 isolate, trap, 15077 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 15078 Nothing<bool>()); 15079 // 7. If trap is undefined, then return target.[[SetPrototypeOf]](). 15080 if (trap->IsUndefined(isolate)) { 15081 return JSReceiver::SetPrototype(target, value, from_javascript, 15082 should_throw); 15083 } 15084 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, target, V)). 15085 Handle<Object> argv[] = {target, value}; 15086 Handle<Object> trap_result; 15087 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 15088 isolate, trap_result, 15089 Execution::Call(isolate, trap, handler, arraysize(argv), argv), 15090 Nothing<bool>()); 15091 bool bool_trap_result = trap_result->BooleanValue(); 15092 // 9. If booleanTrapResult is false, return false. 15093 if (!bool_trap_result) { 15094 RETURN_FAILURE( 15095 isolate, should_throw, 15096 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 15097 } 15098 // 10. Let extensibleTarget be ? IsExtensible(target). 15099 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 15100 if (is_extensible.IsNothing()) return Nothing<bool>(); 15101 // 11. If extensibleTarget is true, return true. 15102 if (is_extensible.FromJust()) { 15103 if (bool_trap_result) return Just(true); 15104 RETURN_FAILURE( 15105 isolate, should_throw, 15106 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 15107 } 15108 // 12. Let targetProto be ? target.[[GetPrototypeOf]](). 15109 Handle<Object> target_proto; 15110 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto, 15111 JSReceiver::GetPrototype(isolate, target), 15112 Nothing<bool>()); 15113 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception. 15114 if (bool_trap_result && !value->SameValue(*target_proto)) { 15115 isolate->Throw(*isolate->factory()->NewTypeError( 15116 MessageTemplate::kProxySetPrototypeOfNonExtensible)); 15117 return Nothing<bool>(); 15118 } 15119 // 14. Return true. 15120 return Just(true); 15121 } 15122 15123 15124 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, 15125 Handle<Object> value, bool from_javascript, 15126 ShouldThrow should_throw) { 15127 Isolate* isolate = object->GetIsolate(); 15128 15129 #ifdef DEBUG 15130 int size = object->Size(); 15131 #endif 15132 15133 if (from_javascript) { 15134 if (object->IsAccessCheckNeeded() && 15135 !isolate->MayAccess(handle(isolate->context()), object)) { 15136 isolate->ReportFailedAccessCheck(object); 15137 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 15138 RETURN_FAILURE(isolate, should_throw, 15139 NewTypeError(MessageTemplate::kNoAccess)); 15140 } 15141 } else { 15142 DCHECK(!object->IsAccessCheckNeeded()); 15143 } 15144 15145 Heap* heap = isolate->heap(); 15146 // Silently ignore the change if value is not a JSObject or null. 15147 // SpiderMonkey behaves this way. 15148 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true); 15149 15150 bool all_extensible = object->map()->is_extensible(); 15151 Handle<JSObject> real_receiver = object; 15152 if (from_javascript) { 15153 // Find the first object in the chain whose prototype object is not 15154 // hidden. 15155 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, 15156 PrototypeIterator::END_AT_NON_HIDDEN); 15157 while (!iter.IsAtEnd()) { 15158 // Casting to JSObject is fine because hidden prototypes are never 15159 // JSProxies. 15160 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); 15161 iter.Advance(); 15162 all_extensible = all_extensible && real_receiver->map()->is_extensible(); 15163 } 15164 } 15165 Handle<Map> map(real_receiver->map()); 15166 15167 // Nothing to do if prototype is already set. 15168 if (map->prototype() == *value) return Just(true); 15169 15170 bool immutable_proto = map->is_immutable_proto(); 15171 if (immutable_proto) { 15172 RETURN_FAILURE( 15173 isolate, should_throw, 15174 NewTypeError(MessageTemplate::kImmutablePrototypeSet, object)); 15175 } 15176 15177 // From 8.6.2 Object Internal Methods 15178 // ... 15179 // In addition, if [[Extensible]] is false the value of the [[Class]] and 15180 // [[Prototype]] internal properties of the object may not be modified. 15181 // ... 15182 // Implementation specific extensions that modify [[Class]], [[Prototype]] 15183 // or [[Extensible]] must not violate the invariants defined in the preceding 15184 // paragraph. 15185 if (!all_extensible) { 15186 RETURN_FAILURE(isolate, should_throw, 15187 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); 15188 } 15189 15190 // Before we can set the prototype we need to be sure prototype cycles are 15191 // prevented. It is sufficient to validate that the receiver is not in the 15192 // new prototype chain. 15193 if (value->IsJSReceiver()) { 15194 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value), 15195 kStartAtReceiver); 15196 !iter.IsAtEnd(); iter.Advance()) { 15197 if (iter.GetCurrent<JSReceiver>() == *object) { 15198 // Cycle detected. 15199 RETURN_FAILURE(isolate, should_throw, 15200 NewTypeError(MessageTemplate::kCyclicProto)); 15201 } 15202 } 15203 } 15204 15205 // Set the new prototype of the object. 15206 15207 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); 15208 15209 PrototypeOptimizationMode mode = 15210 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; 15211 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); 15212 DCHECK(new_map->prototype() == *value); 15213 JSObject::MigrateToMap(real_receiver, new_map); 15214 15215 heap->ClearInstanceofCache(); 15216 DCHECK(size == object->Size()); 15217 return Just(true); 15218 } 15219 15220 // static 15221 void JSObject::SetImmutableProto(Handle<JSObject> object) { 15222 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS 15223 Handle<Map> map(object->map()); 15224 15225 // Nothing to do if prototype is already set. 15226 if (map->is_immutable_proto()) return; 15227 15228 Handle<Map> new_map = Map::TransitionToImmutableProto(map); 15229 object->set_map(*new_map); 15230 } 15231 15232 void JSObject::EnsureCanContainElements(Handle<JSObject> object, 15233 Arguments* args, 15234 uint32_t first_arg, 15235 uint32_t arg_count, 15236 EnsureElementsMode mode) { 15237 // Elements in |Arguments| are ordered backwards (because they're on the 15238 // stack), but the method that's called here iterates over them in forward 15239 // direction. 15240 return EnsureCanContainElements( 15241 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode); 15242 } 15243 15244 15245 ElementsAccessor* JSObject::GetElementsAccessor() { 15246 return ElementsAccessor::ForKind(GetElementsKind()); 15247 } 15248 15249 15250 void JSObject::ValidateElements(Handle<JSObject> object) { 15251 #ifdef ENABLE_SLOW_DCHECKS 15252 if (FLAG_enable_slow_asserts) { 15253 ElementsAccessor* accessor = object->GetElementsAccessor(); 15254 accessor->Validate(object); 15255 } 15256 #endif 15257 } 15258 15259 15260 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity, 15261 uint32_t index, 15262 uint32_t* new_capacity) { 15263 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <= 15264 JSObject::kMaxUncheckedFastElementsLength); 15265 if (index < capacity) { 15266 *new_capacity = capacity; 15267 return false; 15268 } 15269 if (index - capacity >= JSObject::kMaxGap) return true; 15270 *new_capacity = JSObject::NewElementsCapacity(index + 1); 15271 DCHECK_LT(index, *new_capacity); 15272 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength || 15273 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength && 15274 object->GetHeap()->InNewSpace(object))) { 15275 return false; 15276 } 15277 // If the fast-case backing storage takes up roughly three times as 15278 // much space (in machine words) as a dictionary backing storage 15279 // would, the object should have slow elements. 15280 int used_elements = object->GetFastElementsUsage(); 15281 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * 15282 SeededNumberDictionary::kEntrySize; 15283 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; 15284 } 15285 15286 15287 bool JSObject::WouldConvertToSlowElements(uint32_t index) { 15288 if (HasFastElements()) { 15289 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); 15290 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); 15291 uint32_t new_capacity; 15292 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity); 15293 } 15294 return false; 15295 } 15296 15297 15298 static ElementsKind BestFittingFastElementsKind(JSObject* object) { 15299 if (object->HasSloppyArgumentsElements()) { 15300 return FAST_SLOPPY_ARGUMENTS_ELEMENTS; 15301 } 15302 if (object->HasStringWrapperElements()) { 15303 return FAST_STRING_WRAPPER_ELEMENTS; 15304 } 15305 DCHECK(object->HasDictionaryElements()); 15306 SeededNumberDictionary* dictionary = object->element_dictionary(); 15307 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; 15308 for (int i = 0; i < dictionary->Capacity(); i++) { 15309 Object* key = dictionary->KeyAt(i); 15310 if (key->IsNumber()) { 15311 Object* value = dictionary->ValueAt(i); 15312 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; 15313 if (!value->IsSmi()) { 15314 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; 15315 kind = FAST_HOLEY_DOUBLE_ELEMENTS; 15316 } 15317 } 15318 } 15319 return kind; 15320 } 15321 15322 15323 static bool ShouldConvertToFastElements(JSObject* object, 15324 SeededNumberDictionary* dictionary, 15325 uint32_t index, 15326 uint32_t* new_capacity) { 15327 // If properties with non-standard attributes or accessors were added, we 15328 // cannot go back to fast elements. 15329 if (dictionary->requires_slow_elements()) return false; 15330 15331 // Adding a property with this index will require slow elements. 15332 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false; 15333 15334 if (object->IsJSArray()) { 15335 Object* length = JSArray::cast(object)->length(); 15336 if (!length->IsSmi()) return false; 15337 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value()); 15338 } else { 15339 *new_capacity = dictionary->max_number_key() + 1; 15340 } 15341 *new_capacity = Max(index + 1, *new_capacity); 15342 15343 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * 15344 SeededNumberDictionary::kEntrySize; 15345 15346 // Turn fast if the dictionary only saves 50% space. 15347 return 2 * dictionary_size >= *new_capacity; 15348 } 15349 15350 15351 // static 15352 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object, 15353 uint32_t index, 15354 Handle<Object> value, 15355 PropertyAttributes attributes) { 15356 MAYBE_RETURN_NULL( 15357 AddDataElement(object, index, value, attributes, THROW_ON_ERROR)); 15358 return value; 15359 } 15360 15361 15362 // static 15363 Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index, 15364 Handle<Object> value, 15365 PropertyAttributes attributes, 15366 ShouldThrow should_throw) { 15367 DCHECK(object->map()->is_extensible()); 15368 15369 Isolate* isolate = object->GetIsolate(); 15370 15371 uint32_t old_length = 0; 15372 uint32_t new_capacity = 0; 15373 15374 if (object->IsJSArray()) { 15375 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); 15376 } 15377 15378 ElementsKind kind = object->GetElementsKind(); 15379 FixedArrayBase* elements = object->elements(); 15380 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; 15381 if (IsSloppyArgumentsElements(kind)) { 15382 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); 15383 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; 15384 } else if (IsStringWrapperElementsKind(kind)) { 15385 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS; 15386 } 15387 15388 if (attributes != NONE) { 15389 kind = dictionary_kind; 15390 } else if (elements->IsSeededNumberDictionary()) { 15391 kind = ShouldConvertToFastElements(*object, 15392 SeededNumberDictionary::cast(elements), 15393 index, &new_capacity) 15394 ? BestFittingFastElementsKind(*object) 15395 : dictionary_kind; // Overwrite in case of arguments. 15396 } else if (ShouldConvertToSlowElements( 15397 *object, static_cast<uint32_t>(elements->length()), index, 15398 &new_capacity)) { 15399 kind = dictionary_kind; 15400 } 15401 15402 ElementsKind to = value->OptimalElementsKind(); 15403 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) { 15404 to = GetHoleyElementsKind(to); 15405 kind = GetHoleyElementsKind(kind); 15406 } 15407 to = GetMoreGeneralElementsKind(kind, to); 15408 ElementsAccessor* accessor = ElementsAccessor::ForKind(to); 15409 accessor->Add(object, index, value, attributes, new_capacity); 15410 15411 if (object->IsJSArray() && index >= old_length) { 15412 Handle<Object> new_length = 15413 isolate->factory()->NewNumberFromUint(index + 1); 15414 JSArray::cast(*object)->set_length(*new_length); 15415 } 15416 15417 return Just(true); 15418 } 15419 15420 15421 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) { 15422 if (!HasFastElements()) return false; 15423 uint32_t capacity = static_cast<uint32_t>(elements()->length()); 15424 uint32_t new_capacity; 15425 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) && 15426 ShouldConvertToSlowElements(this, capacity, new_length - 1, 15427 &new_capacity); 15428 } 15429 15430 15431 const double AllocationSite::kPretenureRatio = 0.85; 15432 15433 15434 void AllocationSite::ResetPretenureDecision() { 15435 set_pretenure_decision(kUndecided); 15436 set_memento_found_count(0); 15437 set_memento_create_count(0); 15438 } 15439 15440 15441 PretenureFlag AllocationSite::GetPretenureMode() { 15442 PretenureDecision mode = pretenure_decision(); 15443 // Zombie objects "decide" to be untenured. 15444 return mode == kTenure ? TENURED : NOT_TENURED; 15445 } 15446 15447 15448 bool AllocationSite::IsNestedSite() { 15449 DCHECK(FLAG_trace_track_allocation_sites); 15450 Object* current = GetHeap()->allocation_sites_list(); 15451 while (current->IsAllocationSite()) { 15452 AllocationSite* current_site = AllocationSite::cast(current); 15453 if (current_site->nested_site() == this) { 15454 return true; 15455 } 15456 current = current_site->weak_next(); 15457 } 15458 return false; 15459 } 15460 15461 template <AllocationSiteUpdateMode update_or_check> 15462 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site, 15463 ElementsKind to_kind) { 15464 Isolate* isolate = site->GetIsolate(); 15465 bool result = false; 15466 15467 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) { 15468 Handle<JSArray> transition_info = 15469 handle(JSArray::cast(site->transition_info())); 15470 ElementsKind kind = transition_info->GetElementsKind(); 15471 // if kind is holey ensure that to_kind is as well. 15472 if (IsHoleyElementsKind(kind)) { 15473 to_kind = GetHoleyElementsKind(to_kind); 15474 } 15475 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { 15476 // If the array is huge, it's not likely to be defined in a local 15477 // function, so we shouldn't make new instances of it very often. 15478 uint32_t length = 0; 15479 CHECK(transition_info->length()->ToArrayLength(&length)); 15480 if (length <= kMaximumArrayBytesToPretransition) { 15481 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) { 15482 return true; 15483 } 15484 if (FLAG_trace_track_allocation_sites) { 15485 bool is_nested = site->IsNestedSite(); 15486 PrintF( 15487 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", 15488 reinterpret_cast<void*>(*site), 15489 is_nested ? "(nested)" : "", 15490 ElementsKindToString(kind), 15491 ElementsKindToString(to_kind)); 15492 } 15493 JSObject::TransitionElementsKind(transition_info, to_kind); 15494 site->dependent_code()->DeoptimizeDependentCodeGroup( 15495 isolate, DependentCode::kAllocationSiteTransitionChangedGroup); 15496 result = true; 15497 } 15498 } 15499 } else { 15500 ElementsKind kind = site->GetElementsKind(); 15501 // if kind is holey ensure that to_kind is as well. 15502 if (IsHoleyElementsKind(kind)) { 15503 to_kind = GetHoleyElementsKind(to_kind); 15504 } 15505 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { 15506 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true; 15507 if (FLAG_trace_track_allocation_sites) { 15508 PrintF("AllocationSite: JSArray %p site updated %s->%s\n", 15509 reinterpret_cast<void*>(*site), 15510 ElementsKindToString(kind), 15511 ElementsKindToString(to_kind)); 15512 } 15513 site->SetElementsKind(to_kind); 15514 site->dependent_code()->DeoptimizeDependentCodeGroup( 15515 isolate, DependentCode::kAllocationSiteTransitionChangedGroup); 15516 result = true; 15517 } 15518 } 15519 return result; 15520 } 15521 15522 AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) { 15523 if (IsFastSmiElementsKind(from) && 15524 IsMoreGeneralElementsKindTransition(from, to)) { 15525 return TRACK_ALLOCATION_SITE; 15526 } 15527 15528 return DONT_TRACK_ALLOCATION_SITE; 15529 } 15530 15531 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) { 15532 switch (decision) { 15533 case kUndecided: return "undecided"; 15534 case kDontTenure: return "don't tenure"; 15535 case kMaybeTenure: return "maybe tenure"; 15536 case kTenure: return "tenure"; 15537 case kZombie: return "zombie"; 15538 default: UNREACHABLE(); 15539 } 15540 return NULL; 15541 } 15542 15543 template <AllocationSiteUpdateMode update_or_check> 15544 bool JSObject::UpdateAllocationSite(Handle<JSObject> object, 15545 ElementsKind to_kind) { 15546 if (!object->IsJSArray()) return false; 15547 15548 Heap* heap = object->GetHeap(); 15549 if (!heap->InNewSpace(*object)) return false; 15550 15551 Handle<AllocationSite> site; 15552 { 15553 DisallowHeapAllocation no_allocation; 15554 15555 AllocationMemento* memento = 15556 heap->FindAllocationMemento<Heap::kForRuntime>(*object); 15557 if (memento == NULL) return false; 15558 15559 // Walk through to the Allocation Site 15560 site = handle(memento->GetAllocationSite()); 15561 } 15562 return AllocationSite::DigestTransitionFeedback<update_or_check>(site, 15563 to_kind); 15564 } 15565 15566 template bool 15567 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>( 15568 Handle<JSObject> object, ElementsKind to_kind); 15569 15570 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>( 15571 Handle<JSObject> object, ElementsKind to_kind); 15572 15573 void JSObject::TransitionElementsKind(Handle<JSObject> object, 15574 ElementsKind to_kind) { 15575 ElementsKind from_kind = object->GetElementsKind(); 15576 15577 if (IsFastHoleyElementsKind(from_kind)) { 15578 to_kind = GetHoleyElementsKind(to_kind); 15579 } 15580 15581 if (from_kind == to_kind) return; 15582 15583 // This method should never be called for any other case. 15584 DCHECK(IsFastElementsKind(from_kind)); 15585 DCHECK(IsFastElementsKind(to_kind)); 15586 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); 15587 15588 UpdateAllocationSite(object, to_kind); 15589 if (object->elements() == object->GetHeap()->empty_fixed_array() || 15590 IsFastDoubleElementsKind(from_kind) == 15591 IsFastDoubleElementsKind(to_kind)) { 15592 // No change is needed to the elements() buffer, the transition 15593 // only requires a map change. 15594 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); 15595 MigrateToMap(object, new_map); 15596 if (FLAG_trace_elements_transitions) { 15597 Handle<FixedArrayBase> elms(object->elements()); 15598 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); 15599 } 15600 } else { 15601 DCHECK((IsFastSmiElementsKind(from_kind) && 15602 IsFastDoubleElementsKind(to_kind)) || 15603 (IsFastDoubleElementsKind(from_kind) && 15604 IsFastObjectElementsKind(to_kind))); 15605 uint32_t c = static_cast<uint32_t>(object->elements()->length()); 15606 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c); 15607 } 15608 } 15609 15610 15611 // static 15612 bool Map::IsValidElementsTransition(ElementsKind from_kind, 15613 ElementsKind to_kind) { 15614 // Transitions can't go backwards. 15615 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { 15616 return false; 15617 } 15618 15619 // Transitions from HOLEY -> PACKED are not allowed. 15620 return !IsFastHoleyElementsKind(from_kind) || 15621 IsFastHoleyElementsKind(to_kind); 15622 } 15623 15624 15625 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { 15626 Map* map = array->map(); 15627 // Fast path: "length" is the first fast property of arrays. Since it's not 15628 // configurable, it's guaranteed to be the first in the descriptor array. 15629 if (!map->is_dictionary_map()) { 15630 DCHECK(map->instance_descriptors()->GetKey(0) == 15631 array->GetHeap()->length_string()); 15632 return map->instance_descriptors()->GetDetails(0).IsReadOnly(); 15633 } 15634 15635 Isolate* isolate = array->GetIsolate(); 15636 LookupIterator it(array, isolate->factory()->length_string(), array, 15637 LookupIterator::OWN_SKIP_INTERCEPTOR); 15638 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); 15639 return it.IsReadOnly(); 15640 } 15641 15642 15643 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, 15644 uint32_t index) { 15645 uint32_t length = 0; 15646 CHECK(array->length()->ToArrayLength(&length)); 15647 if (length <= index) return HasReadOnlyLength(array); 15648 return false; 15649 } 15650 15651 15652 template <typename BackingStore> 15653 static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) { 15654 Isolate* isolate = store->GetIsolate(); 15655 int limit = object->IsJSArray() 15656 ? Smi::cast(JSArray::cast(object)->length())->value() 15657 : store->length(); 15658 int used = 0; 15659 for (int i = 0; i < limit; ++i) { 15660 if (!store->is_the_hole(isolate, i)) ++used; 15661 } 15662 return used; 15663 } 15664 15665 15666 int JSObject::GetFastElementsUsage() { 15667 FixedArrayBase* store = elements(); 15668 switch (GetElementsKind()) { 15669 case FAST_SMI_ELEMENTS: 15670 case FAST_DOUBLE_ELEMENTS: 15671 case FAST_ELEMENTS: 15672 return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value() 15673 : store->length(); 15674 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 15675 store = FixedArray::cast(FixedArray::cast(store)->get(1)); 15676 // Fall through. 15677 case FAST_HOLEY_SMI_ELEMENTS: 15678 case FAST_HOLEY_ELEMENTS: 15679 case FAST_STRING_WRAPPER_ELEMENTS: 15680 return FastHoleyElementsUsage(this, FixedArray::cast(store)); 15681 case FAST_HOLEY_DOUBLE_ELEMENTS: 15682 if (elements()->length() == 0) return 0; 15683 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store)); 15684 15685 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 15686 case SLOW_STRING_WRAPPER_ELEMENTS: 15687 case DICTIONARY_ELEMENTS: 15688 case NO_ELEMENTS: 15689 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 15690 case TYPE##_ELEMENTS: \ 15691 15692 TYPED_ARRAYS(TYPED_ARRAY_CASE) 15693 #undef TYPED_ARRAY_CASE 15694 UNREACHABLE(); 15695 } 15696 return 0; 15697 } 15698 15699 15700 // Certain compilers request function template instantiation when they 15701 // see the definition of the other template functions in the 15702 // class. This requires us to have the template functions put 15703 // together, so even though this function belongs in objects-debug.cc, 15704 // we keep it here instead to satisfy certain compilers. 15705 #ifdef OBJECT_PRINT 15706 template <typename Derived, typename Shape, typename Key> 15707 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT 15708 Isolate* isolate = this->GetIsolate(); 15709 int capacity = this->Capacity(); 15710 for (int i = 0; i < capacity; i++) { 15711 Object* k = this->KeyAt(i); 15712 if (this->IsKey(isolate, k)) { 15713 os << "\n "; 15714 if (k->IsString()) { 15715 String::cast(k)->StringPrint(os); 15716 } else { 15717 os << Brief(k); 15718 } 15719 os << ": " << Brief(this->ValueAt(i)) << " "; 15720 this->DetailsAt(i).PrintAsSlowTo(os); 15721 } 15722 } 15723 } 15724 template <typename Derived, typename Shape, typename Key> 15725 void Dictionary<Derived, Shape, Key>::Print() { 15726 OFStream os(stdout); 15727 Print(os); 15728 } 15729 #endif 15730 15731 15732 template<typename Derived, typename Shape, typename Key> 15733 void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) { 15734 Isolate* isolate = this->GetIsolate(); 15735 int pos = 0; 15736 int capacity = this->Capacity(); 15737 DisallowHeapAllocation no_gc; 15738 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 15739 for (int i = 0; i < capacity; i++) { 15740 Object* k = this->KeyAt(i); 15741 if (this->IsKey(isolate, k)) { 15742 elements->set(pos++, this->ValueAt(i), mode); 15743 } 15744 } 15745 DCHECK(pos == elements->length()); 15746 } 15747 15748 15749 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it, 15750 bool* done) { 15751 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 15752 return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done); 15753 } 15754 15755 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object, 15756 Handle<Name> name) { 15757 LookupIterator it = LookupIterator::PropertyOrElement( 15758 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 15759 return HasProperty(&it); 15760 } 15761 15762 15763 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object, 15764 uint32_t index) { 15765 Isolate* isolate = object->GetIsolate(); 15766 LookupIterator it(isolate, object, index, object, 15767 LookupIterator::OWN_SKIP_INTERCEPTOR); 15768 return HasProperty(&it); 15769 } 15770 15771 15772 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object, 15773 Handle<Name> name) { 15774 LookupIterator it = LookupIterator::PropertyOrElement( 15775 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 15776 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it); 15777 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR) 15778 : Nothing<bool>(); 15779 } 15780 15781 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) { 15782 return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >> 15783 ElementsKindToShiftSize(kind)); 15784 } 15785 15786 bool JSObject::WasConstructedFromApiFunction() { 15787 auto instance_type = map()->instance_type(); 15788 bool is_api_object = instance_type == JS_API_OBJECT_TYPE || 15789 instance_type == JS_SPECIAL_API_OBJECT_TYPE; 15790 #ifdef ENABLE_SLOW_DCHECKS 15791 if (FLAG_enable_slow_asserts) { 15792 Object* maybe_constructor = map()->GetConstructor(); 15793 if (!maybe_constructor->IsJSFunction()) return false; 15794 JSFunction* constructor = JSFunction::cast(maybe_constructor); 15795 if (constructor->shared()->IsApiFunction()) { 15796 DCHECK(is_api_object); 15797 } else { 15798 DCHECK(!is_api_object); 15799 } 15800 } 15801 #endif 15802 return is_api_object; 15803 } 15804 15805 const char* Symbol::PrivateSymbolToName() const { 15806 Heap* heap = GetIsolate()->heap(); 15807 #define SYMBOL_CHECK_AND_PRINT(name) \ 15808 if (this == heap->name()) return #name; 15809 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT) 15810 #undef SYMBOL_CHECK_AND_PRINT 15811 return "UNKNOWN"; 15812 } 15813 15814 15815 void Symbol::SymbolShortPrint(std::ostream& os) { 15816 os << "<Symbol:"; 15817 if (!name()->IsUndefined(GetIsolate())) { 15818 os << " "; 15819 HeapStringAllocator allocator; 15820 StringStream accumulator(&allocator); 15821 String::cast(name())->StringShortPrint(&accumulator, false); 15822 os << accumulator.ToCString().get(); 15823 } else { 15824 os << " (" << PrivateSymbolToName() << ")"; 15825 } 15826 os << ">"; 15827 } 15828 15829 15830 // StringSharedKeys are used as keys in the eval cache. 15831 class StringSharedKey : public HashTableKey { 15832 public: 15833 // This tuple unambiguously identifies calls to eval() or 15834 // CreateDynamicFunction() (such as through the Function() constructor). 15835 // * source is the string passed into eval(). For dynamic functions, this is 15836 // the effective source for the function, some of which is implicitly 15837 // generated. 15838 // * shared is the shared function info for the function containing the call 15839 // to eval(). for dynamic functions, shared is the native context closure. 15840 // * When positive, position is the position in the source where eval is 15841 // called. When negative, position is the negation of the position in the 15842 // dynamic function's effective source where the ')' ends the parameters. 15843 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared, 15844 LanguageMode language_mode, int position) 15845 : source_(source), 15846 shared_(shared), 15847 language_mode_(language_mode), 15848 position_(position) {} 15849 15850 bool IsMatch(Object* other) override { 15851 DisallowHeapAllocation no_allocation; 15852 if (!other->IsFixedArray()) { 15853 if (!other->IsNumber()) return false; 15854 uint32_t other_hash = static_cast<uint32_t>(other->Number()); 15855 return Hash() == other_hash; 15856 } 15857 FixedArray* other_array = FixedArray::cast(other); 15858 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0)); 15859 if (shared != *shared_) return false; 15860 int language_unchecked = Smi::cast(other_array->get(2))->value(); 15861 DCHECK(is_valid_language_mode(language_unchecked)); 15862 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked); 15863 if (language_mode != language_mode_) return false; 15864 int position = Smi::cast(other_array->get(3))->value(); 15865 if (position != position_) return false; 15866 String* source = String::cast(other_array->get(1)); 15867 return source->Equals(*source_); 15868 } 15869 15870 static uint32_t StringSharedHashHelper(String* source, 15871 SharedFunctionInfo* shared, 15872 LanguageMode language_mode, 15873 int position) { 15874 uint32_t hash = source->Hash(); 15875 if (shared->HasSourceCode()) { 15876 // Instead of using the SharedFunctionInfo pointer in the hash 15877 // code computation, we use a combination of the hash of the 15878 // script source code and the start position of the calling scope. 15879 // We do this to ensure that the cache entries can survive garbage 15880 // collection. 15881 Script* script(Script::cast(shared->script())); 15882 hash ^= String::cast(script->source())->Hash(); 15883 STATIC_ASSERT(LANGUAGE_END == 2); 15884 if (is_strict(language_mode)) hash ^= 0x8000; 15885 hash += position; 15886 } 15887 return hash; 15888 } 15889 15890 uint32_t Hash() override { 15891 return StringSharedHashHelper(*source_, *shared_, language_mode_, 15892 position_); 15893 } 15894 15895 uint32_t HashForObject(Object* obj) override { 15896 DisallowHeapAllocation no_allocation; 15897 if (obj->IsNumber()) { 15898 return static_cast<uint32_t>(obj->Number()); 15899 } 15900 FixedArray* other_array = FixedArray::cast(obj); 15901 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0)); 15902 String* source = String::cast(other_array->get(1)); 15903 int language_unchecked = Smi::cast(other_array->get(2))->value(); 15904 DCHECK(is_valid_language_mode(language_unchecked)); 15905 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked); 15906 int position = Smi::cast(other_array->get(3))->value(); 15907 return StringSharedHashHelper(source, shared, language_mode, position); 15908 } 15909 15910 15911 Handle<Object> AsHandle(Isolate* isolate) override { 15912 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4); 15913 array->set(0, *shared_); 15914 array->set(1, *source_); 15915 array->set(2, Smi::FromInt(language_mode_)); 15916 array->set(3, Smi::FromInt(position_)); 15917 return array; 15918 } 15919 15920 private: 15921 Handle<String> source_; 15922 Handle<SharedFunctionInfo> shared_; 15923 LanguageMode language_mode_; 15924 int position_; 15925 }; 15926 15927 // static 15928 const char* JSPromise::Status(int status) { 15929 switch (status) { 15930 case v8::Promise::kFulfilled: 15931 return "resolved"; 15932 case v8::Promise::kPending: 15933 return "pending"; 15934 case v8::Promise::kRejected: 15935 return "rejected"; 15936 } 15937 UNREACHABLE(); 15938 return NULL; 15939 } 15940 15941 namespace { 15942 15943 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) { 15944 JSRegExp::Flags value = JSRegExp::kNone; 15945 int length = flags->length(); 15946 // A longer flags string cannot be valid. 15947 if (length > 5) return JSRegExp::Flags(0); 15948 for (int i = 0; i < length; i++) { 15949 JSRegExp::Flag flag = JSRegExp::kNone; 15950 switch (flags->Get(i)) { 15951 case 'g': 15952 flag = JSRegExp::kGlobal; 15953 break; 15954 case 'i': 15955 flag = JSRegExp::kIgnoreCase; 15956 break; 15957 case 'm': 15958 flag = JSRegExp::kMultiline; 15959 break; 15960 case 'u': 15961 flag = JSRegExp::kUnicode; 15962 break; 15963 case 'y': 15964 flag = JSRegExp::kSticky; 15965 break; 15966 default: 15967 return JSRegExp::Flags(0); 15968 } 15969 // Duplicate flag. 15970 if (value & flag) return JSRegExp::Flags(0); 15971 value |= flag; 15972 } 15973 *success = true; 15974 return value; 15975 } 15976 15977 } // namespace 15978 15979 15980 // static 15981 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) { 15982 Isolate* isolate = pattern->GetIsolate(); 15983 Handle<JSFunction> constructor = isolate->regexp_function(); 15984 Handle<JSRegExp> regexp = 15985 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor)); 15986 15987 return JSRegExp::Initialize(regexp, pattern, flags); 15988 } 15989 15990 15991 // static 15992 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) { 15993 Isolate* const isolate = regexp->GetIsolate(); 15994 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp)); 15995 } 15996 15997 15998 template <typename Char> 15999 inline int CountRequiredEscapes(Handle<String> source) { 16000 DisallowHeapAllocation no_gc; 16001 int escapes = 0; 16002 Vector<const Char> src = source->GetCharVector<Char>(); 16003 for (int i = 0; i < src.length(); i++) { 16004 if (src[i] == '\\') { 16005 // Escape. Skip next character; 16006 i++; 16007 } else if (src[i] == '/') { 16008 // Not escaped forward-slash needs escape. 16009 escapes++; 16010 } 16011 } 16012 return escapes; 16013 } 16014 16015 16016 template <typename Char, typename StringType> 16017 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, 16018 Handle<StringType> result) { 16019 DisallowHeapAllocation no_gc; 16020 Vector<const Char> src = source->GetCharVector<Char>(); 16021 Vector<Char> dst(result->GetChars(), result->length()); 16022 int s = 0; 16023 int d = 0; 16024 while (s < src.length()) { 16025 if (src[s] == '\\') { 16026 // Escape. Copy this and next character. 16027 dst[d++] = src[s++]; 16028 if (s == src.length()) break; 16029 } else if (src[s] == '/') { 16030 // Not escaped forward-slash needs escape. 16031 dst[d++] = '\\'; 16032 } 16033 dst[d++] = src[s++]; 16034 } 16035 DCHECK_EQ(result->length(), d); 16036 return result; 16037 } 16038 16039 16040 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate, 16041 Handle<String> source) { 16042 String::Flatten(source); 16043 if (source->length() == 0) return isolate->factory()->query_colon_string(); 16044 bool one_byte = source->IsOneByteRepresentationUnderneath(); 16045 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source) 16046 : CountRequiredEscapes<uc16>(source); 16047 if (escapes == 0) return source; 16048 int length = source->length() + escapes; 16049 if (one_byte) { 16050 Handle<SeqOneByteString> result; 16051 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 16052 isolate->factory()->NewRawOneByteString(length), 16053 String); 16054 return WriteEscapedRegExpSource<uint8_t>(source, result); 16055 } else { 16056 Handle<SeqTwoByteString> result; 16057 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 16058 isolate->factory()->NewRawTwoByteString(length), 16059 String); 16060 return WriteEscapedRegExpSource<uc16>(source, result); 16061 } 16062 } 16063 16064 16065 // static 16066 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, 16067 Handle<String> source, 16068 Handle<String> flags_string) { 16069 Isolate* isolate = source->GetIsolate(); 16070 bool success = false; 16071 Flags flags = RegExpFlagsFromString(flags_string, &success); 16072 if (!success) { 16073 THROW_NEW_ERROR( 16074 isolate, 16075 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string), 16076 JSRegExp); 16077 } 16078 return Initialize(regexp, source, flags); 16079 } 16080 16081 16082 // static 16083 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, 16084 Handle<String> source, Flags flags) { 16085 Isolate* isolate = regexp->GetIsolate(); 16086 Factory* factory = isolate->factory(); 16087 // If source is the empty string we set it to "(?:)" instead as 16088 // suggested by ECMA-262, 5th, section 15.10.4.1. 16089 if (source->length() == 0) source = factory->query_colon_string(); 16090 16091 Handle<String> escaped_source; 16092 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source, 16093 EscapeRegExpSource(isolate, source), JSRegExp); 16094 16095 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags), 16096 JSRegExp); 16097 16098 regexp->set_source(*escaped_source); 16099 regexp->set_flags(Smi::FromInt(flags)); 16100 16101 Map* map = regexp->map(); 16102 Object* constructor = map->GetConstructor(); 16103 if (constructor->IsJSFunction() && 16104 JSFunction::cast(constructor)->initial_map() == map) { 16105 // If we still have the original map, set in-object properties directly. 16106 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero, 16107 SKIP_WRITE_BARRIER); 16108 } else { 16109 // Map has changed, so use generic, but slower, method. 16110 RETURN_ON_EXCEPTION(isolate, JSReceiver::SetProperty( 16111 regexp, factory->lastIndex_string(), 16112 Handle<Smi>(Smi::kZero, isolate), STRICT), 16113 JSRegExp); 16114 } 16115 16116 return regexp; 16117 } 16118 16119 16120 // RegExpKey carries the source and flags of a regular expression as key. 16121 class RegExpKey : public HashTableKey { 16122 public: 16123 RegExpKey(Handle<String> string, JSRegExp::Flags flags) 16124 : string_(string), flags_(Smi::FromInt(flags)) {} 16125 16126 // Rather than storing the key in the hash table, a pointer to the 16127 // stored value is stored where the key should be. IsMatch then 16128 // compares the search key to the found object, rather than comparing 16129 // a key to a key. 16130 bool IsMatch(Object* obj) override { 16131 FixedArray* val = FixedArray::cast(obj); 16132 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex))) 16133 && (flags_ == val->get(JSRegExp::kFlagsIndex)); 16134 } 16135 16136 uint32_t Hash() override { return RegExpHash(*string_, flags_); } 16137 16138 Handle<Object> AsHandle(Isolate* isolate) override { 16139 // Plain hash maps, which is where regexp keys are used, don't 16140 // use this function. 16141 UNREACHABLE(); 16142 return MaybeHandle<Object>().ToHandleChecked(); 16143 } 16144 16145 uint32_t HashForObject(Object* obj) override { 16146 FixedArray* val = FixedArray::cast(obj); 16147 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)), 16148 Smi::cast(val->get(JSRegExp::kFlagsIndex))); 16149 } 16150 16151 static uint32_t RegExpHash(String* string, Smi* flags) { 16152 return string->Hash() + flags->value(); 16153 } 16154 16155 Handle<String> string_; 16156 Smi* flags_; 16157 }; 16158 16159 16160 Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) { 16161 if (hash_field_ == 0) Hash(); 16162 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_); 16163 } 16164 16165 16166 Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) { 16167 if (hash_field_ == 0) Hash(); 16168 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_); 16169 } 16170 16171 16172 Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) { 16173 if (hash_field_ == 0) Hash(); 16174 return isolate->factory()->NewOneByteInternalizedSubString( 16175 string_, from_, length_, hash_field_); 16176 } 16177 16178 16179 bool SeqOneByteSubStringKey::IsMatch(Object* string) { 16180 Vector<const uint8_t> chars(string_->GetChars() + from_, length_); 16181 return String::cast(string)->IsOneByteEqualTo(chars); 16182 } 16183 16184 16185 // InternalizedStringKey carries a string/internalized-string object as key. 16186 class InternalizedStringKey : public HashTableKey { 16187 public: 16188 explicit InternalizedStringKey(Handle<String> string) 16189 : string_(String::Flatten(string)) {} 16190 16191 bool IsMatch(Object* string) override { 16192 return String::cast(string)->Equals(*string_); 16193 } 16194 16195 uint32_t Hash() override { return string_->Hash(); } 16196 16197 uint32_t HashForObject(Object* other) override { 16198 return String::cast(other)->Hash(); 16199 } 16200 16201 Handle<Object> AsHandle(Isolate* isolate) override { 16202 // Internalize the string if possible. 16203 MaybeHandle<Map> maybe_map = 16204 isolate->factory()->InternalizedStringMapForString(string_); 16205 Handle<Map> map; 16206 if (maybe_map.ToHandle(&map)) { 16207 string_->set_map_no_write_barrier(*map); 16208 DCHECK(string_->IsInternalizedString()); 16209 return string_; 16210 } 16211 if (FLAG_thin_strings) { 16212 // External strings get special treatment, to avoid copying their 16213 // contents. 16214 if (string_->IsExternalOneByteString()) { 16215 return isolate->factory() 16216 ->InternalizeExternalString<ExternalOneByteString>(string_); 16217 } else if (string_->IsExternalTwoByteString()) { 16218 return isolate->factory() 16219 ->InternalizeExternalString<ExternalTwoByteString>(string_); 16220 } 16221 } 16222 // Otherwise allocate a new internalized string. 16223 return isolate->factory()->NewInternalizedStringImpl( 16224 string_, string_->length(), string_->hash_field()); 16225 } 16226 16227 static uint32_t StringHash(Object* obj) { 16228 return String::cast(obj)->Hash(); 16229 } 16230 16231 private: 16232 Handle<String> string_; 16233 }; 16234 16235 16236 template<typename Derived, typename Shape, typename Key> 16237 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { 16238 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); 16239 } 16240 16241 16242 template<typename Derived, typename Shape, typename Key> 16243 void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) { 16244 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset, 16245 kHeaderSize + length() * kPointerSize, v); 16246 } 16247 16248 16249 template<typename Derived, typename Shape, typename Key> 16250 Handle<Derived> HashTable<Derived, Shape, Key>::New( 16251 Isolate* isolate, 16252 int at_least_space_for, 16253 MinimumCapacity capacity_option, 16254 PretenureFlag pretenure) { 16255 DCHECK(0 <= at_least_space_for); 16256 DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY, 16257 base::bits::IsPowerOfTwo32(at_least_space_for)); 16258 16259 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY) 16260 ? at_least_space_for 16261 : ComputeCapacity(at_least_space_for); 16262 if (capacity > HashTable::kMaxCapacity) { 16263 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true); 16264 } 16265 return New(isolate, capacity, pretenure); 16266 } 16267 16268 template <typename Derived, typename Shape, typename Key> 16269 Handle<Derived> HashTable<Derived, Shape, Key>::New(Isolate* isolate, 16270 int capacity, 16271 PretenureFlag pretenure) { 16272 Factory* factory = isolate->factory(); 16273 int length = EntryToIndex(capacity); 16274 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure); 16275 array->set_map_no_write_barrier(Shape::GetMap(isolate)); 16276 Handle<Derived> table = Handle<Derived>::cast(array); 16277 16278 table->SetNumberOfElements(0); 16279 table->SetNumberOfDeletedElements(0); 16280 table->SetCapacity(capacity); 16281 return table; 16282 } 16283 16284 // Find entry for key otherwise return kNotFound. 16285 template <typename Derived, typename Shape> 16286 int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) { 16287 if (!key->IsUniqueName()) { 16288 return DerivedDictionary::FindEntry(key); 16289 } 16290 16291 // Optimized for unique names. Knowledge of the key type allows: 16292 // 1. Move the check if the key is unique out of the loop. 16293 // 2. Avoid comparing hash codes in unique-to-unique comparison. 16294 // 3. Detect a case when a dictionary key is not unique but the key is. 16295 // In case of positive result the dictionary key may be replaced by the 16296 // internalized string with minimal performance penalty. It gives a chance 16297 // to perform further lookups in code stubs (and significant performance 16298 // boost a certain style of code). 16299 16300 // EnsureCapacity will guarantee the hash table is never full. 16301 uint32_t capacity = this->Capacity(); 16302 uint32_t entry = Derived::FirstProbe(key->Hash(), capacity); 16303 uint32_t count = 1; 16304 Isolate* isolate = this->GetIsolate(); 16305 while (true) { 16306 Object* element = this->KeyAt(entry); 16307 if (element->IsUndefined(isolate)) break; // Empty entry. 16308 if (*key == element) return entry; 16309 DCHECK(element->IsTheHole(isolate) || element->IsUniqueName()); 16310 entry = Derived::NextProbe(entry, count++, capacity); 16311 } 16312 return Derived::kNotFound; 16313 } 16314 16315 16316 template<typename Derived, typename Shape, typename Key> 16317 void HashTable<Derived, Shape, Key>::Rehash( 16318 Handle<Derived> new_table, 16319 Key key) { 16320 DCHECK(NumberOfElements() < new_table->Capacity()); 16321 16322 DisallowHeapAllocation no_gc; 16323 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc); 16324 16325 // Copy prefix to new array. 16326 for (int i = kPrefixStartIndex; 16327 i < kPrefixStartIndex + Shape::kPrefixSize; 16328 i++) { 16329 new_table->set(i, get(i), mode); 16330 } 16331 16332 // Rehash the elements. 16333 int capacity = this->Capacity(); 16334 Heap* heap = new_table->GetHeap(); 16335 Object* the_hole = heap->the_hole_value(); 16336 Object* undefined = heap->undefined_value(); 16337 for (int i = 0; i < capacity; i++) { 16338 uint32_t from_index = EntryToIndex(i); 16339 Object* k = this->get(from_index); 16340 if (k != the_hole && k != undefined) { 16341 uint32_t hash = this->HashForObject(key, k); 16342 uint32_t insertion_index = 16343 EntryToIndex(new_table->FindInsertionEntry(hash)); 16344 for (int j = 0; j < Shape::kEntrySize; j++) { 16345 new_table->set(insertion_index + j, get(from_index + j), mode); 16346 } 16347 } 16348 } 16349 new_table->SetNumberOfElements(NumberOfElements()); 16350 new_table->SetNumberOfDeletedElements(0); 16351 } 16352 16353 16354 template<typename Derived, typename Shape, typename Key> 16355 uint32_t HashTable<Derived, Shape, Key>::EntryForProbe( 16356 Key key, 16357 Object* k, 16358 int probe, 16359 uint32_t expected) { 16360 uint32_t hash = this->HashForObject(key, k); 16361 uint32_t capacity = this->Capacity(); 16362 uint32_t entry = FirstProbe(hash, capacity); 16363 for (int i = 1; i < probe; i++) { 16364 if (entry == expected) return expected; 16365 entry = NextProbe(entry, i, capacity); 16366 } 16367 return entry; 16368 } 16369 16370 16371 template<typename Derived, typename Shape, typename Key> 16372 void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1, 16373 uint32_t entry2, 16374 WriteBarrierMode mode) { 16375 int index1 = EntryToIndex(entry1); 16376 int index2 = EntryToIndex(entry2); 16377 Object* temp[Shape::kEntrySize]; 16378 for (int j = 0; j < Shape::kEntrySize; j++) { 16379 temp[j] = get(index1 + j); 16380 } 16381 for (int j = 0; j < Shape::kEntrySize; j++) { 16382 set(index1 + j, get(index2 + j), mode); 16383 } 16384 for (int j = 0; j < Shape::kEntrySize; j++) { 16385 set(index2 + j, temp[j], mode); 16386 } 16387 } 16388 16389 16390 template<typename Derived, typename Shape, typename Key> 16391 void HashTable<Derived, Shape, Key>::Rehash(Key key) { 16392 DisallowHeapAllocation no_gc; 16393 WriteBarrierMode mode = GetWriteBarrierMode(no_gc); 16394 Isolate* isolate = GetIsolate(); 16395 uint32_t capacity = Capacity(); 16396 bool done = false; 16397 for (int probe = 1; !done; probe++) { 16398 // All elements at entries given by one of the first _probe_ probes 16399 // are placed correctly. Other elements might need to be moved. 16400 done = true; 16401 for (uint32_t current = 0; current < capacity; current++) { 16402 Object* current_key = KeyAt(current); 16403 if (IsKey(isolate, current_key)) { 16404 uint32_t target = EntryForProbe(key, current_key, probe, current); 16405 if (current == target) continue; 16406 Object* target_key = KeyAt(target); 16407 if (!IsKey(target_key) || 16408 EntryForProbe(key, target_key, probe, target) != target) { 16409 // Put the current element into the correct position. 16410 Swap(current, target, mode); 16411 // The other element will be processed on the next iteration. 16412 current--; 16413 } else { 16414 // The place for the current element is occupied. Leave the element 16415 // for the next probe. 16416 done = false; 16417 } 16418 } 16419 } 16420 } 16421 // Wipe deleted entries. 16422 Object* the_hole = isolate->heap()->the_hole_value(); 16423 Object* undefined = isolate->heap()->undefined_value(); 16424 for (uint32_t current = 0; current < capacity; current++) { 16425 if (KeyAt(current) == the_hole) { 16426 set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined); 16427 } 16428 } 16429 SetNumberOfDeletedElements(0); 16430 } 16431 16432 16433 template<typename Derived, typename Shape, typename Key> 16434 Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity( 16435 Handle<Derived> table, 16436 int n, 16437 Key key, 16438 PretenureFlag pretenure) { 16439 Isolate* isolate = table->GetIsolate(); 16440 int capacity = table->Capacity(); 16441 int nof = table->NumberOfElements() + n; 16442 16443 if (table->HasSufficientCapacityToAdd(n)) return table; 16444 16445 const int kMinCapacityForPretenure = 256; 16446 bool should_pretenure = pretenure == TENURED || 16447 ((capacity > kMinCapacityForPretenure) && 16448 !isolate->heap()->InNewSpace(*table)); 16449 Handle<Derived> new_table = HashTable::New( 16450 isolate, 16451 nof * 2, 16452 USE_DEFAULT_MINIMUM_CAPACITY, 16453 should_pretenure ? TENURED : NOT_TENURED); 16454 16455 table->Rehash(new_table, key); 16456 return new_table; 16457 } 16458 16459 template <typename Derived, typename Shape, typename Key> 16460 bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd( 16461 int number_of_additional_elements) { 16462 int capacity = Capacity(); 16463 int nof = NumberOfElements() + number_of_additional_elements; 16464 int nod = NumberOfDeletedElements(); 16465 // Return true if: 16466 // 50% is still free after adding number_of_additional_elements elements and 16467 // at most 50% of the free elements are deleted elements. 16468 if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) { 16469 int needed_free = nof >> 1; 16470 if (nof + needed_free <= capacity) return true; 16471 } 16472 return false; 16473 } 16474 16475 16476 template<typename Derived, typename Shape, typename Key> 16477 Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table, 16478 Key key) { 16479 int capacity = table->Capacity(); 16480 int nof = table->NumberOfElements(); 16481 16482 // Shrink to fit the number of elements if only a quarter of the 16483 // capacity is filled with elements. 16484 if (nof > (capacity >> 2)) return table; 16485 // Allocate a new dictionary with room for at least the current 16486 // number of elements. The allocation method will make sure that 16487 // there is extra room in the dictionary for additions. Don't go 16488 // lower than room for 16 elements. 16489 int at_least_room_for = nof; 16490 if (at_least_room_for < 16) return table; 16491 16492 Isolate* isolate = table->GetIsolate(); 16493 const int kMinCapacityForPretenure = 256; 16494 bool pretenure = 16495 (at_least_room_for > kMinCapacityForPretenure) && 16496 !isolate->heap()->InNewSpace(*table); 16497 Handle<Derived> new_table = HashTable::New( 16498 isolate, 16499 at_least_room_for, 16500 USE_DEFAULT_MINIMUM_CAPACITY, 16501 pretenure ? TENURED : NOT_TENURED); 16502 16503 table->Rehash(new_table, key); 16504 return new_table; 16505 } 16506 16507 16508 template<typename Derived, typename Shape, typename Key> 16509 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) { 16510 uint32_t capacity = Capacity(); 16511 uint32_t entry = FirstProbe(hash, capacity); 16512 uint32_t count = 1; 16513 // EnsureCapacity will guarantee the hash table is never full. 16514 Isolate* isolate = GetIsolate(); 16515 while (true) { 16516 Object* element = KeyAt(entry); 16517 if (!IsKey(isolate, element)) break; 16518 entry = NextProbe(entry, count++, capacity); 16519 } 16520 return entry; 16521 } 16522 16523 16524 // Force instantiation of template instances class. 16525 // Please note this list is compiler dependent. 16526 16527 template class HashTable<StringTable, StringTableShape, HashTableKey*>; 16528 16529 template class HashTable<CompilationCacheTable, 16530 CompilationCacheShape, 16531 HashTableKey*>; 16532 16533 template class HashTable<ObjectHashTable, 16534 ObjectHashTableShape, 16535 Handle<Object> >; 16536 16537 template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >; 16538 16539 template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >; 16540 16541 template class Dictionary<GlobalDictionary, GlobalDictionaryShape, 16542 Handle<Name> >; 16543 16544 template class Dictionary<SeededNumberDictionary, 16545 SeededNumberDictionaryShape, 16546 uint32_t>; 16547 16548 template class Dictionary<UnseededNumberDictionary, 16549 UnseededNumberDictionaryShape, 16550 uint32_t>; 16551 16552 template Handle<SeededNumberDictionary> 16553 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New( 16554 Isolate*, int at_least_space_for, PretenureFlag pretenure, 16555 MinimumCapacity capacity_option); 16556 16557 template Handle<SeededNumberDictionary> 16558 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, 16559 uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure); 16560 16561 template Handle<UnseededNumberDictionary> 16562 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, 16563 uint32_t>::New(Isolate*, int at_least_space_for, 16564 PretenureFlag pretenure, 16565 MinimumCapacity capacity_option); 16566 16567 template Handle<NameDictionary> 16568 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New( 16569 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option); 16570 16571 template Handle<NameDictionary> 16572 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::NewEmpty( 16573 Isolate*, PretenureFlag pretenure); 16574 16575 template Handle<GlobalDictionary> 16576 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New( 16577 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option); 16578 16579 template Handle<SeededNumberDictionary> 16580 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16581 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>); 16582 16583 template Handle<UnseededNumberDictionary> 16584 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>:: 16585 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>); 16586 16587 template Object* 16588 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16589 SlowReverseLookup(Object* value); 16590 16591 template Object* 16592 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16593 SlowReverseLookup(Object* value); 16594 16595 template Handle<Object> 16596 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty( 16597 Handle<NameDictionary>, int); 16598 16599 template Handle<Object> 16600 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, 16601 uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int); 16602 16603 template Handle<Object> 16604 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, 16605 uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int); 16606 16607 template Handle<NameDictionary> 16608 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16609 New(Isolate*, int, MinimumCapacity, PretenureFlag); 16610 16611 template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape, 16612 Handle<Object>>::New(Isolate*, int n, 16613 MinimumCapacity, 16614 PretenureFlag); 16615 16616 template Handle<NameDictionary> 16617 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16618 Shrink(Handle<NameDictionary>, Handle<Name>); 16619 16620 template Handle<SeededNumberDictionary> 16621 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16622 Shrink(Handle<SeededNumberDictionary>, uint32_t); 16623 16624 template Handle<UnseededNumberDictionary> 16625 HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape, 16626 uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t); 16627 16628 template Handle<NameDictionary> 16629 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add( 16630 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails, 16631 int*); 16632 16633 template Handle<GlobalDictionary> 16634 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add( 16635 Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails, 16636 int*); 16637 16638 template Handle<FixedArray> Dictionary< 16639 NameDictionary, NameDictionaryShape, 16640 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>); 16641 16642 template Handle<SeededNumberDictionary> 16643 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add( 16644 Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails, 16645 int*); 16646 16647 template Handle<UnseededNumberDictionary> 16648 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, 16649 uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t, 16650 Handle<Object>, PropertyDetails, int*); 16651 16652 template Handle<SeededNumberDictionary> 16653 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16654 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t); 16655 16656 template Handle<UnseededNumberDictionary> 16657 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>:: 16658 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t); 16659 16660 template void Dictionary<NameDictionary, NameDictionaryShape, 16661 Handle<Name> >::SetRequiresCopyOnCapacityChange(); 16662 16663 template Handle<NameDictionary> 16664 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16665 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>); 16666 16667 template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, 16668 uint32_t>::FindEntry(uint32_t); 16669 16670 template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry( 16671 Handle<Name>); 16672 16673 template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 16674 NumberOfElementsFilterAttributes(PropertyFilter filter); 16675 16676 template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>:: 16677 NumberOfElementsFilterAttributes(PropertyFilter filter); 16678 16679 template void 16680 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 16681 CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape, 16682 Handle<Name>>> 16683 dictionary, 16684 Handle<FixedArray> storage, KeyCollectionMode mode, 16685 KeyAccumulator* accumulator); 16686 16687 template void 16688 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo( 16689 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>> 16690 dictionary, 16691 Handle<FixedArray> storage, KeyCollectionMode mode, 16692 KeyAccumulator* accumulator); 16693 16694 template Handle<FixedArray> 16695 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 16696 IterationIndices( 16697 Handle< 16698 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>> 16699 dictionary); 16700 template void 16701 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 16702 CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape, 16703 Handle<Name>>> 16704 dictionary, 16705 KeyAccumulator* keys); 16706 16707 template Handle<FixedArray> 16708 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::IterationIndices( 16709 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>> 16710 dictionary); 16711 template void 16712 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo( 16713 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>> 16714 dictionary, 16715 KeyAccumulator* keys); 16716 16717 Handle<Object> JSObject::PrepareSlowElementsForSort( 16718 Handle<JSObject> object, uint32_t limit) { 16719 DCHECK(object->HasDictionaryElements()); 16720 Isolate* isolate = object->GetIsolate(); 16721 // Must stay in dictionary mode, either because of requires_slow_elements, 16722 // or because we are not going to sort (and therefore compact) all of the 16723 // elements. 16724 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate); 16725 Handle<SeededNumberDictionary> new_dict = 16726 SeededNumberDictionary::New(isolate, dict->NumberOfElements()); 16727 16728 uint32_t pos = 0; 16729 uint32_t undefs = 0; 16730 int capacity = dict->Capacity(); 16731 Handle<Smi> bailout(Smi::FromInt(-1), isolate); 16732 // Entry to the new dictionary does not cause it to grow, as we have 16733 // allocated one that is large enough for all entries. 16734 DisallowHeapAllocation no_gc; 16735 for (int i = 0; i < capacity; i++) { 16736 Object* k = dict->KeyAt(i); 16737 if (!dict->IsKey(isolate, k)) continue; 16738 16739 DCHECK(k->IsNumber()); 16740 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0); 16741 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0); 16742 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32); 16743 16744 HandleScope scope(isolate); 16745 Handle<Object> value(dict->ValueAt(i), isolate); 16746 PropertyDetails details = dict->DetailsAt(i); 16747 if (details.kind() == kAccessor || details.IsReadOnly()) { 16748 // Bail out and do the sorting of undefineds and array holes in JS. 16749 // Also bail out if the element is not supposed to be moved. 16750 return bailout; 16751 } 16752 16753 uint32_t key = NumberToUint32(k); 16754 if (key < limit) { 16755 if (value->IsUndefined(isolate)) { 16756 undefs++; 16757 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { 16758 // Adding an entry with the key beyond smi-range requires 16759 // allocation. Bailout. 16760 return bailout; 16761 } else { 16762 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 16763 new_dict, pos, value, details, object); 16764 DCHECK(result.is_identical_to(new_dict)); 16765 USE(result); 16766 pos++; 16767 } 16768 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) { 16769 // Adding an entry with the key beyond smi-range requires 16770 // allocation. Bailout. 16771 return bailout; 16772 } else { 16773 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 16774 new_dict, key, value, details, object); 16775 DCHECK(result.is_identical_to(new_dict)); 16776 USE(result); 16777 } 16778 } 16779 16780 uint32_t result = pos; 16781 PropertyDetails no_details = PropertyDetails::Empty(); 16782 while (undefs > 0) { 16783 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { 16784 // Adding an entry with the key beyond smi-range requires 16785 // allocation. Bailout. 16786 return bailout; 16787 } 16788 HandleScope scope(isolate); 16789 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 16790 new_dict, pos, isolate->factory()->undefined_value(), no_details, 16791 object); 16792 DCHECK(result.is_identical_to(new_dict)); 16793 USE(result); 16794 pos++; 16795 undefs--; 16796 } 16797 16798 object->set_elements(*new_dict); 16799 16800 AllowHeapAllocation allocate_return_value; 16801 return isolate->factory()->NewNumberFromUint(result); 16802 } 16803 16804 16805 // Collects all defined (non-hole) and non-undefined (array) elements at 16806 // the start of the elements array. 16807 // If the object is in dictionary mode, it is converted to fast elements 16808 // mode. 16809 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object, 16810 uint32_t limit) { 16811 Isolate* isolate = object->GetIsolate(); 16812 if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) { 16813 return handle(Smi::FromInt(-1), isolate); 16814 } 16815 16816 if (object->HasStringWrapperElements()) { 16817 int len = String::cast(Handle<JSValue>::cast(object)->value())->length(); 16818 return handle(Smi::FromInt(len), isolate); 16819 } 16820 16821 if (object->HasDictionaryElements()) { 16822 // Convert to fast elements containing only the existing properties. 16823 // Ordering is irrelevant, since we are going to sort anyway. 16824 Handle<SeededNumberDictionary> dict(object->element_dictionary()); 16825 if (object->IsJSArray() || dict->requires_slow_elements() || 16826 dict->max_number_key() >= limit) { 16827 return JSObject::PrepareSlowElementsForSort(object, limit); 16828 } 16829 // Convert to fast elements. 16830 16831 Handle<Map> new_map = 16832 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS); 16833 16834 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ? 16835 NOT_TENURED: TENURED; 16836 Handle<FixedArray> fast_elements = 16837 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure); 16838 dict->CopyValuesTo(*fast_elements); 16839 JSObject::ValidateElements(object); 16840 16841 JSObject::SetMapAndElements(object, new_map, fast_elements); 16842 } else if (object->HasFixedTypedArrayElements()) { 16843 // Typed arrays cannot have holes or undefined elements. 16844 return handle(Smi::FromInt( 16845 FixedArrayBase::cast(object->elements())->length()), isolate); 16846 } else if (!object->HasFastDoubleElements()) { 16847 EnsureWritableFastElements(object); 16848 } 16849 DCHECK(object->HasFastSmiOrObjectElements() || 16850 object->HasFastDoubleElements()); 16851 16852 // Collect holes at the end, undefined before that and the rest at the 16853 // start, and return the number of non-hole, non-undefined values. 16854 16855 Handle<FixedArrayBase> elements_base(object->elements()); 16856 uint32_t elements_length = static_cast<uint32_t>(elements_base->length()); 16857 if (limit > elements_length) { 16858 limit = elements_length; 16859 } 16860 if (limit == 0) { 16861 return handle(Smi::kZero, isolate); 16862 } 16863 16864 uint32_t result = 0; 16865 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) { 16866 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base); 16867 // Split elements into defined and the_hole, in that order. 16868 unsigned int holes = limit; 16869 // Assume most arrays contain no holes and undefined values, so minimize the 16870 // number of stores of non-undefined, non-the-hole values. 16871 for (unsigned int i = 0; i < holes; i++) { 16872 if (elements->is_the_hole(i)) { 16873 holes--; 16874 } else { 16875 continue; 16876 } 16877 // Position i needs to be filled. 16878 while (holes > i) { 16879 if (elements->is_the_hole(holes)) { 16880 holes--; 16881 } else { 16882 elements->set(i, elements->get_scalar(holes)); 16883 break; 16884 } 16885 } 16886 } 16887 result = holes; 16888 while (holes < limit) { 16889 elements->set_the_hole(holes); 16890 holes++; 16891 } 16892 } else { 16893 FixedArray* elements = FixedArray::cast(*elements_base); 16894 DisallowHeapAllocation no_gc; 16895 16896 // Split elements into defined, undefined and the_hole, in that order. Only 16897 // count locations for undefined and the hole, and fill them afterwards. 16898 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc); 16899 unsigned int undefs = limit; 16900 unsigned int holes = limit; 16901 // Assume most arrays contain no holes and undefined values, so minimize the 16902 // number of stores of non-undefined, non-the-hole values. 16903 for (unsigned int i = 0; i < undefs; i++) { 16904 Object* current = elements->get(i); 16905 if (current->IsTheHole(isolate)) { 16906 holes--; 16907 undefs--; 16908 } else if (current->IsUndefined(isolate)) { 16909 undefs--; 16910 } else { 16911 continue; 16912 } 16913 // Position i needs to be filled. 16914 while (undefs > i) { 16915 current = elements->get(undefs); 16916 if (current->IsTheHole(isolate)) { 16917 holes--; 16918 undefs--; 16919 } else if (current->IsUndefined(isolate)) { 16920 undefs--; 16921 } else { 16922 elements->set(i, current, write_barrier); 16923 break; 16924 } 16925 } 16926 } 16927 result = undefs; 16928 while (undefs < holes) { 16929 elements->set_undefined(isolate, undefs); 16930 undefs++; 16931 } 16932 while (holes < limit) { 16933 elements->set_the_hole(isolate, holes); 16934 holes++; 16935 } 16936 } 16937 16938 return isolate->factory()->NewNumberFromUint(result); 16939 } 16940 16941 namespace { 16942 16943 bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s, 16944 Handle<Object>* index) { 16945 DCHECK(s->IsString() || s->IsSmi()); 16946 16947 Handle<Object> result; 16948 if (s->IsSmi()) { 16949 result = s; 16950 } else { 16951 result = String::ToNumber(Handle<String>::cast(s)); 16952 if (!result->IsMinusZero()) { 16953 Handle<String> str = Object::ToString(isolate, result).ToHandleChecked(); 16954 // Avoid treating strings like "2E1" and "20" as the same key. 16955 if (!str->SameValue(*s)) return false; 16956 } 16957 } 16958 *index = result; 16959 return true; 16960 } 16961 16962 } // anonymous namespace 16963 16964 // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc 16965 // static 16966 Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate, 16967 Handle<JSTypedArray> o, 16968 Handle<Object> key, 16969 PropertyDescriptor* desc, 16970 ShouldThrow should_throw) { 16971 // 1. Assert: IsPropertyKey(P) is true. 16972 DCHECK(key->IsName() || key->IsNumber()); 16973 // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot. 16974 // 3. If Type(P) is String, then 16975 if (key->IsString() || key->IsSmi()) { 16976 // 3a. Let numericIndex be ! CanonicalNumericIndexString(P) 16977 // 3b. If numericIndex is not undefined, then 16978 Handle<Object> numeric_index; 16979 if (CanonicalNumericIndexString(isolate, key, &numeric_index)) { 16980 // 3b i. If IsInteger(numericIndex) is false, return false. 16981 // 3b ii. If numericIndex = -0, return false. 16982 // 3b iii. If numericIndex < 0, return false. 16983 // FIXME: the standard allows up to 2^53 elements. 16984 uint32_t index; 16985 if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) { 16986 RETURN_FAILURE(isolate, should_throw, 16987 NewTypeError(MessageTemplate::kInvalidTypedArrayIndex)); 16988 } 16989 // 3b iv. Let length be O.[[ArrayLength]]. 16990 uint32_t length = o->length()->Number(); 16991 // 3b v. If numericIndex length, return false. 16992 if (index >= length) { 16993 RETURN_FAILURE(isolate, should_throw, 16994 NewTypeError(MessageTemplate::kInvalidTypedArrayIndex)); 16995 } 16996 // 3b vi. If IsAccessorDescriptor(Desc) is true, return false. 16997 if (PropertyDescriptor::IsAccessorDescriptor(desc)) { 16998 RETURN_FAILURE(isolate, should_throw, 16999 NewTypeError(MessageTemplate::kRedefineDisallowed, key)); 17000 } 17001 // 3b vii. If Desc has a [[Configurable]] field and if 17002 // Desc.[[Configurable]] is true, return false. 17003 // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] 17004 // is false, return false. 17005 // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is 17006 // false, return false. 17007 if ((desc->has_configurable() && desc->configurable()) || 17008 (desc->has_enumerable() && !desc->enumerable()) || 17009 (desc->has_writable() && !desc->writable())) { 17010 RETURN_FAILURE(isolate, should_throw, 17011 NewTypeError(MessageTemplate::kRedefineDisallowed, key)); 17012 } 17013 // 3b x. If Desc has a [[Value]] field, then 17014 // 3b x 1. Let value be Desc.[[Value]]. 17015 // 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value). 17016 if (desc->has_value()) { 17017 if (!desc->has_configurable()) desc->set_configurable(false); 17018 if (!desc->has_enumerable()) desc->set_enumerable(true); 17019 if (!desc->has_writable()) desc->set_writable(true); 17020 Handle<Object> value = desc->value(); 17021 RETURN_ON_EXCEPTION_VALUE(isolate, 17022 SetOwnElementIgnoreAttributes( 17023 o, index, value, desc->ToAttributes()), 17024 Nothing<bool>()); 17025 } 17026 // 3b xi. Return true. 17027 return Just(true); 17028 } 17029 } 17030 // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc). 17031 return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw); 17032 } 17033 17034 ExternalArrayType JSTypedArray::type() { 17035 switch (elements()->map()->instance_type()) { 17036 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \ 17037 case FIXED_##TYPE##_ARRAY_TYPE: \ 17038 return kExternal##Type##Array; 17039 17040 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE) 17041 #undef INSTANCE_TYPE_TO_ARRAY_TYPE 17042 17043 default: 17044 UNREACHABLE(); 17045 return static_cast<ExternalArrayType>(-1); 17046 } 17047 } 17048 17049 17050 size_t JSTypedArray::element_size() { 17051 switch (elements()->map()->instance_type()) { 17052 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \ 17053 case FIXED_##TYPE##_ARRAY_TYPE: \ 17054 return size; 17055 17056 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE) 17057 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE 17058 17059 default: 17060 UNREACHABLE(); 17061 return 0; 17062 } 17063 } 17064 17065 17066 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global, 17067 Handle<Name> name) { 17068 DCHECK(!global->HasFastProperties()); 17069 auto dictionary = handle(global->global_dictionary()); 17070 int entry = dictionary->FindEntry(name); 17071 if (entry == GlobalDictionary::kNotFound) return; 17072 PropertyCell::InvalidateEntry(dictionary, entry); 17073 } 17074 17075 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell( 17076 Handle<JSGlobalObject> global, Handle<Name> name, 17077 PropertyCellType cell_type, int* entry_out) { 17078 Isolate* isolate = global->GetIsolate(); 17079 DCHECK(!global->HasFastProperties()); 17080 Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate); 17081 int entry = dictionary->FindEntry(name); 17082 Handle<PropertyCell> cell; 17083 if (entry != GlobalDictionary::kNotFound) { 17084 if (entry_out) *entry_out = entry; 17085 // This call should be idempotent. 17086 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 17087 cell = handle(PropertyCell::cast(dictionary->ValueAt(entry))); 17088 PropertyCellType original_cell_type = cell->property_details().cell_type(); 17089 DCHECK(original_cell_type == PropertyCellType::kInvalidated || 17090 original_cell_type == PropertyCellType::kUninitialized); 17091 DCHECK(cell->value()->IsTheHole(isolate)); 17092 if (original_cell_type == PropertyCellType::kInvalidated) { 17093 cell = PropertyCell::InvalidateEntry(dictionary, entry); 17094 } 17095 PropertyDetails details(kData, NONE, 0, cell_type); 17096 cell->set_property_details(details); 17097 return cell; 17098 } 17099 cell = isolate->factory()->NewPropertyCell(); 17100 PropertyDetails details(kData, NONE, 0, cell_type); 17101 dictionary = 17102 GlobalDictionary::Add(dictionary, name, cell, details, entry_out); 17103 // {*entry_out} is initialized inside GlobalDictionary::Add(). 17104 global->set_properties(*dictionary); 17105 return cell; 17106 } 17107 17108 17109 // This class is used for looking up two character strings in the string table. 17110 // If we don't have a hit we don't want to waste much time so we unroll the 17111 // string hash calculation loop here for speed. Doesn't work if the two 17112 // characters form a decimal integer, since such strings have a different hash 17113 // algorithm. 17114 class TwoCharHashTableKey : public HashTableKey { 17115 public: 17116 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed) 17117 : c1_(c1), c2_(c2) { 17118 // Char 1. 17119 uint32_t hash = seed; 17120 hash += c1; 17121 hash += hash << 10; 17122 hash ^= hash >> 6; 17123 // Char 2. 17124 hash += c2; 17125 hash += hash << 10; 17126 hash ^= hash >> 6; 17127 // GetHash. 17128 hash += hash << 3; 17129 hash ^= hash >> 11; 17130 hash += hash << 15; 17131 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash; 17132 hash_ = hash; 17133 #ifdef DEBUG 17134 // If this assert fails then we failed to reproduce the two-character 17135 // version of the string hashing algorithm above. One reason could be 17136 // that we were passed two digits as characters, since the hash 17137 // algorithm is different in that case. 17138 uint16_t chars[2] = {c1, c2}; 17139 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed); 17140 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask; 17141 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash)); 17142 #endif 17143 } 17144 17145 bool IsMatch(Object* o) override { 17146 if (!o->IsString()) return false; 17147 String* other = String::cast(o); 17148 if (other->length() != 2) return false; 17149 if (other->Get(0) != c1_) return false; 17150 return other->Get(1) == c2_; 17151 } 17152 17153 uint32_t Hash() override { return hash_; } 17154 uint32_t HashForObject(Object* key) override { 17155 if (!key->IsString()) return 0; 17156 return String::cast(key)->Hash(); 17157 } 17158 17159 Handle<Object> AsHandle(Isolate* isolate) override { 17160 // The TwoCharHashTableKey is only used for looking in the string 17161 // table, not for adding to it. 17162 UNREACHABLE(); 17163 return MaybeHandle<Object>().ToHandleChecked(); 17164 } 17165 17166 private: 17167 uint16_t c1_; 17168 uint16_t c2_; 17169 uint32_t hash_; 17170 }; 17171 17172 17173 MaybeHandle<String> StringTable::InternalizeStringIfExists( 17174 Isolate* isolate, 17175 Handle<String> string) { 17176 if (string->IsInternalizedString()) { 17177 return string; 17178 } 17179 if (string->IsThinString()) { 17180 return handle(Handle<ThinString>::cast(string)->actual(), isolate); 17181 } 17182 return LookupStringIfExists(isolate, string); 17183 } 17184 17185 17186 MaybeHandle<String> StringTable::LookupStringIfExists( 17187 Isolate* isolate, 17188 Handle<String> string) { 17189 Handle<StringTable> string_table = isolate->factory()->string_table(); 17190 InternalizedStringKey key(string); 17191 int entry = string_table->FindEntry(&key); 17192 if (entry == kNotFound) { 17193 return MaybeHandle<String>(); 17194 } else { 17195 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate); 17196 DCHECK(StringShape(*result).IsInternalized()); 17197 return result; 17198 } 17199 } 17200 17201 17202 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists( 17203 Isolate* isolate, 17204 uint16_t c1, 17205 uint16_t c2) { 17206 Handle<StringTable> string_table = isolate->factory()->string_table(); 17207 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed()); 17208 int entry = string_table->FindEntry(&key); 17209 if (entry == kNotFound) { 17210 return MaybeHandle<String>(); 17211 } else { 17212 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate); 17213 DCHECK(StringShape(*result).IsInternalized()); 17214 return result; 17215 } 17216 } 17217 17218 17219 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, 17220 int expected) { 17221 Handle<StringTable> table = isolate->factory()->string_table(); 17222 // We need a key instance for the virtual hash function. 17223 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); 17224 table = StringTable::EnsureCapacity(table, expected, &dummy_key); 17225 isolate->heap()->SetRootStringTable(*table); 17226 } 17227 17228 namespace { 17229 17230 template <class StringClass> 17231 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from, 17232 Handle<String> to) { 17233 Handle<StringClass> cast_from = Handle<StringClass>::cast(from); 17234 Handle<StringClass> cast_to = Handle<StringClass>::cast(to); 17235 const typename StringClass::Resource* to_resource = cast_to->resource(); 17236 if (to_resource == nullptr) { 17237 // |to| is a just-created internalized copy of |from|. Migrate the resource. 17238 cast_to->set_resource(cast_from->resource()); 17239 // Zap |from|'s resource pointer to reflect the fact that |from| has 17240 // relinquished ownership of its resource. 17241 cast_from->set_resource(nullptr); 17242 } else if (to_resource != cast_from->resource()) { 17243 // |to| already existed and has its own resource. Finalize |from|. 17244 isolate->heap()->FinalizeExternalString(*from); 17245 } 17246 } 17247 17248 } // namespace 17249 17250 Handle<String> StringTable::LookupString(Isolate* isolate, 17251 Handle<String> string) { 17252 if (string->IsThinString()) { 17253 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); 17254 return handle(Handle<ThinString>::cast(string)->actual(), isolate); 17255 } 17256 if (string->IsConsString() && string->IsFlat()) { 17257 string = handle(Handle<ConsString>::cast(string)->first(), isolate); 17258 if (string->IsInternalizedString()) return string; 17259 } 17260 17261 InternalizedStringKey key(string); 17262 Handle<String> result = LookupKey(isolate, &key); 17263 17264 if (FLAG_thin_strings) { 17265 if (string->IsExternalString()) { 17266 if (result->IsExternalOneByteString()) { 17267 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, 17268 result); 17269 } else if (result->IsExternalTwoByteString()) { 17270 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, 17271 result); 17272 } else { 17273 // If the external string is duped into an existing non-external 17274 // internalized string, free its resource (it's about to be rewritten 17275 // into a ThinString below). 17276 isolate->heap()->FinalizeExternalString(*string); 17277 } 17278 } 17279 17280 // The LookupKey() call above tries to internalize the string in-place. 17281 // In cases where that wasn't possible (e.g. new-space strings), turn them 17282 // into ThinStrings referring to their internalized versions now. 17283 if (!string->IsInternalizedString()) { 17284 DisallowHeapAllocation no_gc; 17285 bool one_byte = result->IsOneByteRepresentation(); 17286 Handle<Map> map = one_byte 17287 ? isolate->factory()->thin_one_byte_string_map() 17288 : isolate->factory()->thin_string_map(); 17289 int old_size = string->Size(); 17290 DCHECK(old_size >= ThinString::kSize); 17291 string->synchronized_set_map(*map); 17292 Handle<ThinString> thin = Handle<ThinString>::cast(string); 17293 thin->set_actual(*result); 17294 Address thin_end = thin->address() + ThinString::kSize; 17295 int size_delta = old_size - ThinString::kSize; 17296 if (size_delta != 0) { 17297 Heap* heap = isolate->heap(); 17298 heap->CreateFillerObjectAt(thin_end, size_delta, 17299 ClearRecordedSlots::kNo); 17300 heap->AdjustLiveBytes(*thin, -size_delta); 17301 } 17302 } 17303 } else { // !FLAG_thin_strings 17304 if (string->IsConsString()) { 17305 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17306 cons->set_first(*result); 17307 cons->set_second(isolate->heap()->empty_string()); 17308 } else if (string->IsSlicedString()) { 17309 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); 17310 DisallowHeapAllocation no_gc; 17311 bool one_byte = result->IsOneByteRepresentation(); 17312 Handle<Map> map = one_byte 17313 ? isolate->factory()->cons_one_byte_string_map() 17314 : isolate->factory()->cons_string_map(); 17315 string->set_map(*map); 17316 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17317 cons->set_first(*result); 17318 cons->set_second(isolate->heap()->empty_string()); 17319 } 17320 } 17321 return result; 17322 } 17323 17324 17325 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { 17326 Handle<StringTable> table = isolate->factory()->string_table(); 17327 int entry = table->FindEntry(key); 17328 17329 // String already in table. 17330 if (entry != kNotFound) { 17331 return handle(String::cast(table->KeyAt(entry)), isolate); 17332 } 17333 17334 // Adding new string. Grow table if needed. 17335 table = StringTable::EnsureCapacity(table, 1, key); 17336 17337 // Create string object. 17338 Handle<Object> string = key->AsHandle(isolate); 17339 // There must be no attempts to internalize strings that could throw 17340 // InvalidStringLength error. 17341 CHECK(!string.is_null()); 17342 17343 // Add the new string and return it along with the string table. 17344 entry = table->FindInsertionEntry(key->Hash()); 17345 table->set(EntryToIndex(entry), *string); 17346 table->ElementAdded(); 17347 17348 isolate->heap()->SetRootStringTable(*table); 17349 return Handle<String>::cast(string); 17350 } 17351 17352 17353 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) { 17354 Handle<StringTable> table = isolate->factory()->string_table(); 17355 int entry = table->FindEntry(key); 17356 if (entry != kNotFound) return String::cast(table->KeyAt(entry)); 17357 return NULL; 17358 } 17359 17360 Handle<StringSet> StringSet::New(Isolate* isolate) { 17361 return HashTable::New(isolate, 0); 17362 } 17363 17364 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset, 17365 Handle<String> name) { 17366 if (!stringset->Has(name)) { 17367 stringset = EnsureCapacity(stringset, 1, *name); 17368 uint32_t hash = StringSetShape::Hash(*name); 17369 int entry = stringset->FindInsertionEntry(hash); 17370 stringset->set(EntryToIndex(entry), *name); 17371 stringset->ElementAdded(); 17372 } 17373 return stringset; 17374 } 17375 17376 bool StringSet::Has(Handle<String> name) { 17377 return FindEntry(*name) != kNotFound; 17378 } 17379 17380 Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set, 17381 Handle<Object> key) { 17382 Isolate* isolate = set->GetIsolate(); 17383 int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); 17384 17385 if (!set->Has(isolate, key, hash)) { 17386 set = EnsureCapacity(set, 1, key); 17387 int entry = set->FindInsertionEntry(hash); 17388 set->set(EntryToIndex(entry), *key); 17389 set->ElementAdded(); 17390 } 17391 return set; 17392 } 17393 17394 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src, 17395 Handle<Context> context, 17396 LanguageMode language_mode) { 17397 Isolate* isolate = GetIsolate(); 17398 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 17399 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17400 int entry = FindEntry(&key); 17401 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17402 int index = EntryToIndex(entry); 17403 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value(); 17404 return Handle<Object>(get(index + 1), isolate); 17405 } 17406 17407 namespace { 17408 17409 const int kLiteralEntryLength = 2; 17410 const int kLiteralInitialLength = 2; 17411 const int kLiteralContextOffset = 0; 17412 const int kLiteralLiteralsOffset = 1; 17413 17414 int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry, 17415 Context* native_context) { 17416 DisallowHeapAllocation no_gc; 17417 DCHECK(native_context->IsNativeContext()); 17418 Object* obj = cache->get(cache_entry); 17419 17420 if (obj->IsFixedArray()) { 17421 FixedArray* literals_map = FixedArray::cast(obj); 17422 int length = literals_map->length(); 17423 for (int i = 0; i < length; i += kLiteralEntryLength) { 17424 if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset)) 17425 ->value() == native_context) { 17426 return i; 17427 } 17428 } 17429 } 17430 return -1; 17431 } 17432 17433 void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry, 17434 Handle<Context> native_context, Handle<Cell> literals) { 17435 Isolate* isolate = native_context->GetIsolate(); 17436 DCHECK(native_context->IsNativeContext()); 17437 STATIC_ASSERT(kLiteralEntryLength == 2); 17438 Handle<FixedArray> new_literals_map; 17439 int entry; 17440 17441 Object* obj = cache->get(cache_entry); 17442 17443 if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) { 17444 new_literals_map = 17445 isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED); 17446 entry = 0; 17447 } else { 17448 Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate); 17449 entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context); 17450 if (entry >= 0) { 17451 // Just set the code of the entry. 17452 Handle<WeakCell> literals_cell = 17453 isolate->factory()->NewWeakCell(literals); 17454 old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell); 17455 return; 17456 } 17457 17458 // Can we reuse an entry? 17459 DCHECK(entry < 0); 17460 int length = old_literals_map->length(); 17461 for (int i = 0; i < length; i += kLiteralEntryLength) { 17462 if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset)) 17463 ->cleared()) { 17464 new_literals_map = old_literals_map; 17465 entry = i; 17466 break; 17467 } 17468 } 17469 17470 if (entry < 0) { 17471 // Copy old optimized code map and append one new entry. 17472 new_literals_map = isolate->factory()->CopyFixedArrayAndGrow( 17473 old_literals_map, kLiteralEntryLength, TENURED); 17474 entry = old_literals_map->length(); 17475 } 17476 } 17477 17478 Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals); 17479 WeakCell* context_cell = native_context->self_weak_cell(); 17480 17481 new_literals_map->set(entry + kLiteralContextOffset, context_cell); 17482 new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell); 17483 17484 #ifdef DEBUG 17485 for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) { 17486 WeakCell* cell = 17487 WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset)); 17488 DCHECK(cell->cleared() || cell->value()->IsNativeContext()); 17489 cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset)); 17490 DCHECK(cell->cleared() || (cell->value()->IsCell())); 17491 } 17492 #endif 17493 17494 Object* old_literals_map = cache->get(cache_entry); 17495 if (old_literals_map != *new_literals_map) { 17496 cache->set(cache_entry, *new_literals_map); 17497 } 17498 } 17499 17500 Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry, 17501 Context* native_context) { 17502 Cell* result = nullptr; 17503 int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context); 17504 if (entry >= 0) { 17505 FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry)); 17506 DCHECK_LE(entry + kLiteralEntryLength, literals_map->length()); 17507 WeakCell* cell = 17508 WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset)); 17509 17510 result = cell->cleared() ? nullptr : Cell::cast(cell->value()); 17511 } 17512 DCHECK(result == nullptr || result->IsCell()); 17513 return result; 17514 } 17515 17516 } // namespace 17517 17518 InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src, 17519 Handle<Context> context, 17520 LanguageMode language_mode) { 17521 InfoVectorPair empty_result; 17522 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 17523 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17524 int entry = FindEntry(&key); 17525 if (entry == kNotFound) return empty_result; 17526 int index = EntryToIndex(entry); 17527 if (!get(index)->IsFixedArray()) return empty_result; 17528 Object* obj = get(index + 1); 17529 if (obj->IsSharedFunctionInfo()) { 17530 Cell* literals = 17531 SearchLiteralsMap(this, index + 2, context->native_context()); 17532 return InfoVectorPair(SharedFunctionInfo::cast(obj), literals); 17533 } 17534 return empty_result; 17535 } 17536 17537 InfoVectorPair CompilationCacheTable::LookupEval( 17538 Handle<String> src, Handle<SharedFunctionInfo> outer_info, 17539 Handle<Context> native_context, LanguageMode language_mode, int position) { 17540 InfoVectorPair empty_result; 17541 StringSharedKey key(src, outer_info, language_mode, position); 17542 int entry = FindEntry(&key); 17543 if (entry == kNotFound) return empty_result; 17544 int index = EntryToIndex(entry); 17545 if (!get(index)->IsFixedArray()) return empty_result; 17546 Object* obj = get(EntryToIndex(entry) + 1); 17547 if (obj->IsSharedFunctionInfo()) { 17548 Cell* literals = 17549 SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context); 17550 return InfoVectorPair(SharedFunctionInfo::cast(obj), literals); 17551 } 17552 return empty_result; 17553 } 17554 17555 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src, 17556 JSRegExp::Flags flags) { 17557 Isolate* isolate = GetIsolate(); 17558 DisallowHeapAllocation no_allocation; 17559 RegExpKey key(src, flags); 17560 int entry = FindEntry(&key); 17561 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17562 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate); 17563 } 17564 17565 17566 Handle<CompilationCacheTable> CompilationCacheTable::Put( 17567 Handle<CompilationCacheTable> cache, Handle<String> src, 17568 Handle<Context> context, LanguageMode language_mode, Handle<Object> value) { 17569 Isolate* isolate = cache->GetIsolate(); 17570 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 17571 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17572 Handle<Object> k = key.AsHandle(isolate); 17573 cache = EnsureCapacity(cache, 1, &key); 17574 int entry = cache->FindInsertionEntry(key.Hash()); 17575 cache->set(EntryToIndex(entry), *k); 17576 cache->set(EntryToIndex(entry) + 1, *value); 17577 cache->ElementAdded(); 17578 return cache; 17579 } 17580 17581 Handle<CompilationCacheTable> CompilationCacheTable::PutScript( 17582 Handle<CompilationCacheTable> cache, Handle<String> src, 17583 Handle<Context> context, LanguageMode language_mode, 17584 Handle<SharedFunctionInfo> value, Handle<Cell> literals) { 17585 Isolate* isolate = cache->GetIsolate(); 17586 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 17587 Handle<Context> native_context(context->native_context()); 17588 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17589 Handle<Object> k = key.AsHandle(isolate); 17590 cache = EnsureCapacity(cache, 1, &key); 17591 int entry = cache->FindInsertionEntry(key.Hash()); 17592 cache->set(EntryToIndex(entry), *k); 17593 cache->set(EntryToIndex(entry) + 1, *value); 17594 AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals); 17595 cache->ElementAdded(); 17596 return cache; 17597 } 17598 17599 Handle<CompilationCacheTable> CompilationCacheTable::PutEval( 17600 Handle<CompilationCacheTable> cache, Handle<String> src, 17601 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value, 17602 Handle<Context> native_context, Handle<Cell> literals, int position) { 17603 Isolate* isolate = cache->GetIsolate(); 17604 StringSharedKey key(src, outer_info, value->language_mode(), position); 17605 { 17606 Handle<Object> k = key.AsHandle(isolate); 17607 int entry = cache->FindEntry(&key); 17608 if (entry != kNotFound) { 17609 cache->set(EntryToIndex(entry), *k); 17610 cache->set(EntryToIndex(entry) + 1, *value); 17611 // AddToLiteralsMap may allocate a new sub-array to live in the entry, 17612 // but it won't change the cache array. Therefore EntryToIndex and 17613 // entry remains correct. 17614 AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, 17615 literals); 17616 return cache; 17617 } 17618 } 17619 17620 cache = EnsureCapacity(cache, 1, &key); 17621 int entry = cache->FindInsertionEntry(key.Hash()); 17622 Handle<Object> k = 17623 isolate->factory()->NewNumber(static_cast<double>(key.Hash())); 17624 cache->set(EntryToIndex(entry), *k); 17625 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations)); 17626 cache->ElementAdded(); 17627 return cache; 17628 } 17629 17630 17631 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp( 17632 Handle<CompilationCacheTable> cache, Handle<String> src, 17633 JSRegExp::Flags flags, Handle<FixedArray> value) { 17634 RegExpKey key(src, flags); 17635 cache = EnsureCapacity(cache, 1, &key); 17636 int entry = cache->FindInsertionEntry(key.Hash()); 17637 // We store the value in the key slot, and compare the search key 17638 // to the stored value with a custon IsMatch function during lookups. 17639 cache->set(EntryToIndex(entry), *value); 17640 cache->set(EntryToIndex(entry) + 1, *value); 17641 cache->ElementAdded(); 17642 return cache; 17643 } 17644 17645 17646 void CompilationCacheTable::Age() { 17647 DisallowHeapAllocation no_allocation; 17648 Object* the_hole_value = GetHeap()->the_hole_value(); 17649 for (int entry = 0, size = Capacity(); entry < size; entry++) { 17650 int entry_index = EntryToIndex(entry); 17651 int value_index = entry_index + 1; 17652 17653 if (get(entry_index)->IsNumber()) { 17654 Smi* count = Smi::cast(get(value_index)); 17655 count = Smi::FromInt(count->value() - 1); 17656 if (count->value() == 0) { 17657 NoWriteBarrierSet(this, entry_index, the_hole_value); 17658 NoWriteBarrierSet(this, value_index, the_hole_value); 17659 ElementRemoved(); 17660 } else { 17661 NoWriteBarrierSet(this, value_index, count); 17662 } 17663 } else if (get(entry_index)->IsFixedArray()) { 17664 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index)); 17665 bool is_old = 17666 info->IsInterpreted() 17667 ? info->bytecode_array()->IsOld() 17668 : info->code()->kind() != Code::FUNCTION || info->code()->IsOld(); 17669 if (is_old) { 17670 for (int i = 0; i < kEntrySize; i++) { 17671 NoWriteBarrierSet(this, entry_index + i, the_hole_value); 17672 } 17673 ElementRemoved(); 17674 } 17675 } 17676 } 17677 } 17678 17679 17680 void CompilationCacheTable::Remove(Object* value) { 17681 DisallowHeapAllocation no_allocation; 17682 Object* the_hole_value = GetHeap()->the_hole_value(); 17683 for (int entry = 0, size = Capacity(); entry < size; entry++) { 17684 int entry_index = EntryToIndex(entry); 17685 int value_index = entry_index + 1; 17686 if (get(value_index) == value) { 17687 for (int i = 0; i < kEntrySize; i++) { 17688 NoWriteBarrierSet(this, entry_index + i, the_hole_value); 17689 } 17690 ElementRemoved(); 17691 } 17692 } 17693 return; 17694 } 17695 17696 template <typename Derived, typename Shape, typename Key> 17697 Handle<Derived> Dictionary<Derived, Shape, Key>::New( 17698 Isolate* isolate, int at_least_space_for, PretenureFlag pretenure, 17699 MinimumCapacity capacity_option) { 17700 DCHECK(0 <= at_least_space_for); 17701 Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for, 17702 capacity_option, pretenure); 17703 17704 // Initialize the next enumeration index. 17705 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex); 17706 return dict; 17707 } 17708 17709 template <typename Derived, typename Shape, typename Key> 17710 Handle<Derived> Dictionary<Derived, Shape, Key>::NewEmpty( 17711 Isolate* isolate, PretenureFlag pretenure) { 17712 Handle<Derived> dict = DerivedHashTable::New(isolate, 1, pretenure); 17713 // Attempt to add one element to the empty dictionary must cause reallocation. 17714 DCHECK(!dict->HasSufficientCapacityToAdd(1)); 17715 // Initialize the next enumeration index. 17716 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex); 17717 return dict; 17718 } 17719 17720 template <typename Derived, typename Shape, typename Key> 17721 Handle<FixedArray> 17722 Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices( 17723 Handle<Derived> dictionary) { 17724 int length = dictionary->NumberOfElements(); 17725 17726 Handle<FixedArray> iteration_order = IterationIndices(dictionary); 17727 DCHECK(iteration_order->length() == length); 17728 17729 // Iterate over the dictionary using the enumeration order and update 17730 // the dictionary with new enumeration indices. 17731 for (int i = 0; i < length; i++) { 17732 int index = Smi::cast(iteration_order->get(i))->value(); 17733 DCHECK(dictionary->IsKey(dictionary->KeyAt(index))); 17734 17735 int enum_index = PropertyDetails::kInitialIndex + i; 17736 17737 PropertyDetails details = dictionary->DetailsAt(index); 17738 PropertyDetails new_details = details.set_index(enum_index); 17739 dictionary->DetailsAtPut(index, new_details); 17740 } 17741 17742 // Set the next enumeration index. 17743 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length); 17744 return iteration_order; 17745 } 17746 17747 17748 template <typename Derived, typename Shape, typename Key> 17749 void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() { 17750 DCHECK_EQ(0, DerivedHashTable::NumberOfElements()); 17751 DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements()); 17752 // Make sure that HashTable::EnsureCapacity will create a copy. 17753 DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity()); 17754 DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1)); 17755 } 17756 17757 17758 template <typename Derived, typename Shape, typename Key> 17759 Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity( 17760 Handle<Derived> dictionary, int n, Key key) { 17761 // Check whether there are enough enumeration indices to add n elements. 17762 if (Shape::kIsEnumerable && 17763 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) { 17764 // If not, we generate new indices for the properties. 17765 GenerateNewEnumerationIndices(dictionary); 17766 } 17767 return DerivedHashTable::EnsureCapacity(dictionary, n, key); 17768 } 17769 17770 17771 template <typename Derived, typename Shape, typename Key> 17772 Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty( 17773 Handle<Derived> dictionary, int entry) { 17774 Factory* factory = dictionary->GetIsolate()->factory(); 17775 PropertyDetails details = dictionary->DetailsAt(entry); 17776 if (!details.IsConfigurable()) return factory->false_value(); 17777 17778 dictionary->SetEntry( 17779 entry, factory->the_hole_value(), factory->the_hole_value()); 17780 dictionary->ElementRemoved(); 17781 return factory->true_value(); 17782 } 17783 17784 17785 template<typename Derived, typename Shape, typename Key> 17786 Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut( 17787 Handle<Derived> dictionary, Key key, Handle<Object> value) { 17788 int entry = dictionary->FindEntry(key); 17789 17790 // If the entry is present set the value; 17791 if (entry != Dictionary::kNotFound) { 17792 dictionary->ValueAtPut(entry, *value); 17793 return dictionary; 17794 } 17795 17796 // Check whether the dictionary should be extended. 17797 dictionary = EnsureCapacity(dictionary, 1, key); 17798 #ifdef DEBUG 17799 USE(Shape::AsHandle(dictionary->GetIsolate(), key)); 17800 #endif 17801 PropertyDetails details = PropertyDetails::Empty(); 17802 17803 AddEntry(dictionary, key, value, details, dictionary->Hash(key)); 17804 return dictionary; 17805 } 17806 17807 template <typename Derived, typename Shape, typename Key> 17808 Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary, 17809 Key key, 17810 Handle<Object> value, 17811 PropertyDetails details, 17812 int* entry_out) { 17813 // Valdate key is absent. 17814 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound)); 17815 // Check whether the dictionary should be extended. 17816 dictionary = EnsureCapacity(dictionary, 1, key); 17817 17818 int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key)); 17819 if (entry_out) *entry_out = entry; 17820 return dictionary; 17821 } 17822 17823 // Add a key, value pair to the dictionary. Returns entry value. 17824 template <typename Derived, typename Shape, typename Key> 17825 int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary, 17826 Key key, Handle<Object> value, 17827 PropertyDetails details, 17828 uint32_t hash) { 17829 // Compute the key object. 17830 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key); 17831 17832 uint32_t entry = dictionary->FindInsertionEntry(hash); 17833 // Insert element at empty or deleted entry 17834 if (details.dictionary_index() == 0 && Shape::kIsEnumerable) { 17835 // Assign an enumeration index to the property and update 17836 // SetNextEnumerationIndex. 17837 int index = dictionary->NextEnumerationIndex(); 17838 details = details.set_index(index); 17839 dictionary->SetNextEnumerationIndex(index + 1); 17840 } 17841 dictionary->SetEntry(entry, k, value, details); 17842 DCHECK((dictionary->KeyAt(entry)->IsNumber() || 17843 dictionary->KeyAt(entry)->IsName())); 17844 dictionary->ElementAdded(); 17845 return entry; 17846 } 17847 17848 bool SeededNumberDictionary::HasComplexElements() { 17849 if (!requires_slow_elements()) return false; 17850 Isolate* isolate = this->GetIsolate(); 17851 int capacity = this->Capacity(); 17852 for (int i = 0; i < capacity; i++) { 17853 Object* k = this->KeyAt(i); 17854 if (!this->IsKey(isolate, k)) continue; 17855 DCHECK(!IsDeleted(i)); 17856 PropertyDetails details = this->DetailsAt(i); 17857 if (details.kind() == kAccessor) return true; 17858 PropertyAttributes attr = details.attributes(); 17859 if (attr & ALL_ATTRIBUTES_MASK) return true; 17860 } 17861 return false; 17862 } 17863 17864 void SeededNumberDictionary::UpdateMaxNumberKey( 17865 uint32_t key, Handle<JSObject> dictionary_holder) { 17866 DisallowHeapAllocation no_allocation; 17867 // If the dictionary requires slow elements an element has already 17868 // been added at a high index. 17869 if (requires_slow_elements()) return; 17870 // Check if this index is high enough that we should require slow 17871 // elements. 17872 if (key > kRequiresSlowElementsLimit) { 17873 if (!dictionary_holder.is_null()) { 17874 dictionary_holder->RequireSlowElements(this); 17875 } 17876 set_requires_slow_elements(); 17877 return; 17878 } 17879 // Update max key value. 17880 Object* max_index_object = get(kMaxNumberKeyIndex); 17881 if (!max_index_object->IsSmi() || max_number_key() < key) { 17882 FixedArray::set(kMaxNumberKeyIndex, 17883 Smi::FromInt(key << kRequiresSlowElementsTagSize)); 17884 } 17885 } 17886 17887 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry( 17888 Handle<SeededNumberDictionary> dictionary, uint32_t key, 17889 Handle<Object> value, PropertyDetails details, 17890 Handle<JSObject> dictionary_holder) { 17891 dictionary->UpdateMaxNumberKey(key, dictionary_holder); 17892 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); 17893 return Add(dictionary, key, value, details); 17894 } 17895 17896 17897 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry( 17898 Handle<UnseededNumberDictionary> dictionary, 17899 uint32_t key, 17900 Handle<Object> value) { 17901 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); 17902 return Add(dictionary, key, value, PropertyDetails::Empty()); 17903 } 17904 17905 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey( 17906 Handle<UnseededNumberDictionary> dictionary, uint32_t key) { 17907 int entry = dictionary->FindEntry(key); 17908 if (entry == kNotFound) return dictionary; 17909 17910 Factory* factory = dictionary->GetIsolate()->factory(); 17911 dictionary->SetEntry(entry, factory->the_hole_value(), 17912 factory->the_hole_value()); 17913 dictionary->ElementRemoved(); 17914 return dictionary->Shrink(dictionary, key); 17915 } 17916 17917 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut( 17918 Handle<SeededNumberDictionary> dictionary, uint32_t key, 17919 Handle<Object> value, Handle<JSObject> dictionary_holder) { 17920 dictionary->UpdateMaxNumberKey(key, dictionary_holder); 17921 return AtPut(dictionary, key, value); 17922 } 17923 17924 17925 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut( 17926 Handle<UnseededNumberDictionary> dictionary, 17927 uint32_t key, 17928 Handle<Object> value) { 17929 return AtPut(dictionary, key, value); 17930 } 17931 17932 Handle<SeededNumberDictionary> SeededNumberDictionary::Set( 17933 Handle<SeededNumberDictionary> dictionary, uint32_t key, 17934 Handle<Object> value, PropertyDetails details, 17935 Handle<JSObject> dictionary_holder) { 17936 int entry = dictionary->FindEntry(key); 17937 if (entry == kNotFound) { 17938 return AddNumberEntry(dictionary, key, value, details, dictionary_holder); 17939 } 17940 // Preserve enumeration index. 17941 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index()); 17942 Handle<Object> object_key = 17943 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); 17944 dictionary->SetEntry(entry, object_key, value, details); 17945 return dictionary; 17946 } 17947 17948 17949 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set( 17950 Handle<UnseededNumberDictionary> dictionary, 17951 uint32_t key, 17952 Handle<Object> value) { 17953 int entry = dictionary->FindEntry(key); 17954 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value); 17955 Handle<Object> object_key = 17956 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); 17957 dictionary->SetEntry(entry, object_key, value); 17958 return dictionary; 17959 } 17960 17961 17962 template <typename Derived, typename Shape, typename Key> 17963 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes( 17964 PropertyFilter filter) { 17965 Isolate* isolate = this->GetIsolate(); 17966 int capacity = this->Capacity(); 17967 int result = 0; 17968 for (int i = 0; i < capacity; i++) { 17969 Object* k = this->KeyAt(i); 17970 if (this->IsKey(isolate, k) && !k->FilterKey(filter)) { 17971 if (this->IsDeleted(i)) continue; 17972 PropertyDetails details = this->DetailsAt(i); 17973 PropertyAttributes attr = details.attributes(); 17974 if ((attr & filter) == 0) result++; 17975 } 17976 } 17977 return result; 17978 } 17979 17980 17981 template <typename Dictionary> 17982 struct EnumIndexComparator { 17983 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {} 17984 bool operator() (Smi* a, Smi* b) { 17985 PropertyDetails da(dict->DetailsAt(a->value())); 17986 PropertyDetails db(dict->DetailsAt(b->value())); 17987 return da.dictionary_index() < db.dictionary_index(); 17988 } 17989 Dictionary* dict; 17990 }; 17991 17992 template <typename Derived, typename Shape, typename Key> 17993 void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo( 17994 Handle<Dictionary<Derived, Shape, Key>> dictionary, 17995 Handle<FixedArray> storage, KeyCollectionMode mode, 17996 KeyAccumulator* accumulator) { 17997 DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr); 17998 Isolate* isolate = dictionary->GetIsolate(); 17999 int length = storage->length(); 18000 int capacity = dictionary->Capacity(); 18001 int properties = 0; 18002 for (int i = 0; i < capacity; i++) { 18003 Object* key = dictionary->KeyAt(i); 18004 bool is_shadowing_key = false; 18005 if (!dictionary->IsKey(isolate, key)) continue; 18006 if (key->IsSymbol()) continue; 18007 PropertyDetails details = dictionary->DetailsAt(i); 18008 if (details.IsDontEnum()) { 18009 if (mode == KeyCollectionMode::kIncludePrototypes) { 18010 is_shadowing_key = true; 18011 } else { 18012 continue; 18013 } 18014 } 18015 if (dictionary->IsDeleted(i)) continue; 18016 if (is_shadowing_key) { 18017 accumulator->AddShadowingKey(key); 18018 continue; 18019 } else { 18020 storage->set(properties, Smi::FromInt(i)); 18021 } 18022 properties++; 18023 if (mode == KeyCollectionMode::kOwnOnly && properties == length) break; 18024 } 18025 18026 CHECK_EQ(length, properties); 18027 DisallowHeapAllocation no_gc; 18028 Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary; 18029 FixedArray* raw_storage = *storage; 18030 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary)); 18031 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress()); 18032 std::sort(start, start + length, cmp); 18033 for (int i = 0; i < length; i++) { 18034 int index = Smi::cast(raw_storage->get(i))->value(); 18035 raw_storage->set(i, raw_dictionary->KeyAt(index)); 18036 } 18037 } 18038 18039 template <typename Derived, typename Shape, typename Key> 18040 Handle<FixedArray> Dictionary<Derived, Shape, Key>::IterationIndices( 18041 Handle<Dictionary<Derived, Shape, Key>> dictionary) { 18042 Isolate* isolate = dictionary->GetIsolate(); 18043 int capacity = dictionary->Capacity(); 18044 int length = dictionary->NumberOfElements(); 18045 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 18046 int array_size = 0; 18047 { 18048 DisallowHeapAllocation no_gc; 18049 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary; 18050 for (int i = 0; i < capacity; i++) { 18051 Object* k = raw_dict->KeyAt(i); 18052 if (!raw_dict->IsKey(isolate, k)) continue; 18053 if (raw_dict->IsDeleted(i)) continue; 18054 array->set(array_size++, Smi::FromInt(i)); 18055 } 18056 18057 DCHECK_EQ(array_size, length); 18058 18059 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict)); 18060 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress()); 18061 std::sort(start, start + array_size, cmp); 18062 } 18063 array->Shrink(array_size); 18064 return array; 18065 } 18066 18067 template <typename Derived, typename Shape, typename Key> 18068 void Dictionary<Derived, Shape, Key>::CollectKeysTo( 18069 Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) { 18070 Isolate* isolate = keys->isolate(); 18071 int capacity = dictionary->Capacity(); 18072 Handle<FixedArray> array = 18073 isolate->factory()->NewFixedArray(dictionary->NumberOfElements()); 18074 int array_size = 0; 18075 PropertyFilter filter = keys->filter(); 18076 { 18077 DisallowHeapAllocation no_gc; 18078 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary; 18079 for (int i = 0; i < capacity; i++) { 18080 Object* k = raw_dict->KeyAt(i); 18081 if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue; 18082 if (raw_dict->IsDeleted(i)) continue; 18083 PropertyDetails details = raw_dict->DetailsAt(i); 18084 if ((details.attributes() & filter) != 0) { 18085 keys->AddShadowingKey(k); 18086 continue; 18087 } 18088 if (filter & ONLY_ALL_CAN_READ) { 18089 if (details.kind() != kAccessor) continue; 18090 Object* accessors = raw_dict->ValueAt(i); 18091 if (accessors->IsPropertyCell()) { 18092 accessors = PropertyCell::cast(accessors)->value(); 18093 } 18094 if (!accessors->IsAccessorInfo()) continue; 18095 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; 18096 } 18097 array->set(array_size++, Smi::FromInt(i)); 18098 } 18099 18100 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict)); 18101 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress()); 18102 std::sort(start, start + array_size, cmp); 18103 } 18104 18105 bool has_seen_symbol = false; 18106 for (int i = 0; i < array_size; i++) { 18107 int index = Smi::cast(array->get(i))->value(); 18108 Object* key = dictionary->KeyAt(index); 18109 if (key->IsSymbol()) { 18110 has_seen_symbol = true; 18111 continue; 18112 } 18113 keys->AddKey(key, DO_NOT_CONVERT); 18114 } 18115 if (has_seen_symbol) { 18116 for (int i = 0; i < array_size; i++) { 18117 int index = Smi::cast(array->get(i))->value(); 18118 Object* key = dictionary->KeyAt(index); 18119 if (!key->IsSymbol()) continue; 18120 keys->AddKey(key, DO_NOT_CONVERT); 18121 } 18122 } 18123 } 18124 18125 18126 // Backwards lookup (slow). 18127 template<typename Derived, typename Shape, typename Key> 18128 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { 18129 Isolate* isolate = this->GetIsolate(); 18130 int capacity = this->Capacity(); 18131 for (int i = 0; i < capacity; i++) { 18132 Object* k = this->KeyAt(i); 18133 if (!this->IsKey(isolate, k)) continue; 18134 Object* e = this->ValueAt(i); 18135 // TODO(dcarney): this should be templatized. 18136 if (e->IsPropertyCell()) { 18137 e = PropertyCell::cast(e)->value(); 18138 } 18139 if (e == value) return k; 18140 } 18141 return isolate->heap()->undefined_value(); 18142 } 18143 18144 18145 Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key, 18146 int32_t hash) { 18147 DisallowHeapAllocation no_gc; 18148 DCHECK(IsKey(isolate, *key)); 18149 18150 int entry = FindEntry(isolate, key, hash); 18151 if (entry == kNotFound) return isolate->heap()->the_hole_value(); 18152 return get(EntryToIndex(entry) + 1); 18153 } 18154 18155 18156 Object* ObjectHashTable::Lookup(Handle<Object> key) { 18157 DisallowHeapAllocation no_gc; 18158 18159 Isolate* isolate = GetIsolate(); 18160 DCHECK(IsKey(isolate, *key)); 18161 18162 // If the object does not have an identity hash, it was never used as a key. 18163 Object* hash = key->GetHash(); 18164 if (hash->IsUndefined(isolate)) { 18165 return isolate->heap()->the_hole_value(); 18166 } 18167 return Lookup(isolate, key, Smi::cast(hash)->value()); 18168 } 18169 18170 Object* ObjectHashTable::ValueAt(int entry) { 18171 return get(EntryToValueIndex(entry)); 18172 } 18173 18174 Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) { 18175 return Lookup(GetIsolate(), key, hash); 18176 } 18177 18178 18179 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table, 18180 Handle<Object> key, 18181 Handle<Object> value) { 18182 Isolate* isolate = table->GetIsolate(); 18183 DCHECK(table->IsKey(isolate, *key)); 18184 DCHECK(!value->IsTheHole(isolate)); 18185 18186 // Make sure the key object has an identity hash code. 18187 int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); 18188 18189 return Put(table, key, value, hash); 18190 } 18191 18192 18193 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table, 18194 Handle<Object> key, 18195 Handle<Object> value, 18196 int32_t hash) { 18197 Isolate* isolate = table->GetIsolate(); 18198 DCHECK(table->IsKey(isolate, *key)); 18199 DCHECK(!value->IsTheHole(isolate)); 18200 18201 int entry = table->FindEntry(isolate, key, hash); 18202 18203 // Key is already in table, just overwrite value. 18204 if (entry != kNotFound) { 18205 table->set(EntryToIndex(entry) + 1, *value); 18206 return table; 18207 } 18208 18209 // Rehash if more than 33% of the entries are deleted entries. 18210 // TODO(jochen): Consider to shrink the fixed array in place. 18211 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) { 18212 table->Rehash(isolate->factory()->undefined_value()); 18213 } 18214 // If we're out of luck, we didn't get a GC recently, and so rehashing 18215 // isn't enough to avoid a crash. 18216 if (!table->HasSufficientCapacityToAdd(1)) { 18217 int nof = table->NumberOfElements() + 1; 18218 int capacity = ObjectHashTable::ComputeCapacity(nof * 2); 18219 if (capacity > ObjectHashTable::kMaxCapacity) { 18220 for (size_t i = 0; i < 2; ++i) { 18221 isolate->heap()->CollectAllGarbage( 18222 Heap::kFinalizeIncrementalMarkingMask, 18223 GarbageCollectionReason::kFullHashtable); 18224 } 18225 table->Rehash(isolate->factory()->undefined_value()); 18226 } 18227 } 18228 18229 // Check whether the hash table should be extended. 18230 table = EnsureCapacity(table, 1, key); 18231 table->AddEntry(table->FindInsertionEntry(hash), *key, *value); 18232 return table; 18233 } 18234 18235 18236 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table, 18237 Handle<Object> key, 18238 bool* was_present) { 18239 DCHECK(table->IsKey(table->GetIsolate(), *key)); 18240 18241 Object* hash = key->GetHash(); 18242 if (hash->IsUndefined(table->GetIsolate())) { 18243 *was_present = false; 18244 return table; 18245 } 18246 18247 return Remove(table, key, was_present, Smi::cast(hash)->value()); 18248 } 18249 18250 18251 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table, 18252 Handle<Object> key, 18253 bool* was_present, 18254 int32_t hash) { 18255 Isolate* isolate = table->GetIsolate(); 18256 DCHECK(table->IsKey(isolate, *key)); 18257 18258 int entry = table->FindEntry(isolate, 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 Shrink(table, key); 18267 } 18268 18269 18270 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) { 18271 set(EntryToIndex(entry), key); 18272 set(EntryToIndex(entry) + 1, value); 18273 ElementAdded(); 18274 } 18275 18276 18277 void ObjectHashTable::RemoveEntry(int entry) { 18278 set_the_hole(EntryToIndex(entry)); 18279 set_the_hole(EntryToIndex(entry) + 1); 18280 ElementRemoved(); 18281 } 18282 18283 18284 Object* WeakHashTable::Lookup(Handle<HeapObject> key) { 18285 DisallowHeapAllocation no_gc; 18286 Isolate* isolate = GetIsolate(); 18287 DCHECK(IsKey(isolate, *key)); 18288 int entry = FindEntry(key); 18289 if (entry == kNotFound) return isolate->heap()->the_hole_value(); 18290 return get(EntryToValueIndex(entry)); 18291 } 18292 18293 18294 Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table, 18295 Handle<HeapObject> key, 18296 Handle<HeapObject> value) { 18297 Isolate* isolate = key->GetIsolate(); 18298 DCHECK(table->IsKey(isolate, *key)); 18299 int entry = table->FindEntry(key); 18300 // Key is already in table, just overwrite value. 18301 if (entry != kNotFound) { 18302 table->set(EntryToValueIndex(entry), *value); 18303 return table; 18304 } 18305 18306 Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key); 18307 18308 // Check whether the hash table should be extended. 18309 table = EnsureCapacity(table, 1, key, TENURED); 18310 18311 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value); 18312 return table; 18313 } 18314 18315 18316 void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell, 18317 Handle<HeapObject> value) { 18318 DisallowHeapAllocation no_allocation; 18319 set(EntryToIndex(entry), *key_cell); 18320 set(EntryToValueIndex(entry), *value); 18321 ElementAdded(); 18322 } 18323 18324 18325 template<class Derived, class Iterator, int entrysize> 18326 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate( 18327 Isolate* isolate, int capacity, PretenureFlag pretenure) { 18328 // Capacity must be a power of two, since we depend on being able 18329 // to divide and multiple by 2 (kLoadFactor) to derive capacity 18330 // from number of buckets. If we decide to change kLoadFactor 18331 // to something other than 2, capacity should be stored as another 18332 // field of this object. 18333 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity)); 18334 if (capacity > kMaxCapacity) { 18335 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true); 18336 } 18337 int num_buckets = capacity / kLoadFactor; 18338 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray( 18339 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure); 18340 backing_store->set_map_no_write_barrier( 18341 isolate->heap()->ordered_hash_table_map()); 18342 Handle<Derived> table = Handle<Derived>::cast(backing_store); 18343 for (int i = 0; i < num_buckets; ++i) { 18344 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound)); 18345 } 18346 table->SetNumberOfBuckets(num_buckets); 18347 table->SetNumberOfElements(0); 18348 table->SetNumberOfDeletedElements(0); 18349 return table; 18350 } 18351 18352 18353 template<class Derived, class Iterator, int entrysize> 18354 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable( 18355 Handle<Derived> table) { 18356 DCHECK(!table->IsObsolete()); 18357 18358 int nof = table->NumberOfElements(); 18359 int nod = table->NumberOfDeletedElements(); 18360 int capacity = table->Capacity(); 18361 if ((nof + nod) < capacity) return table; 18362 // Don't need to grow if we can simply clear out deleted entries instead. 18363 // Note that we can't compact in place, though, so we always allocate 18364 // a new table. 18365 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity); 18366 } 18367 18368 18369 template<class Derived, class Iterator, int entrysize> 18370 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink( 18371 Handle<Derived> table) { 18372 DCHECK(!table->IsObsolete()); 18373 18374 int nof = table->NumberOfElements(); 18375 int capacity = table->Capacity(); 18376 if (nof >= (capacity >> 2)) return table; 18377 return Rehash(table, capacity / 2); 18378 } 18379 18380 18381 template<class Derived, class Iterator, int entrysize> 18382 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear( 18383 Handle<Derived> table) { 18384 DCHECK(!table->IsObsolete()); 18385 18386 Handle<Derived> new_table = 18387 Allocate(table->GetIsolate(), 18388 kMinCapacity, 18389 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED); 18390 18391 table->SetNextTable(*new_table); 18392 table->SetNumberOfDeletedElements(kClearedTableSentinel); 18393 18394 return new_table; 18395 } 18396 18397 template <class Derived, class Iterator, int entrysize> 18398 bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey( 18399 Handle<Derived> table, Handle<Object> key) { 18400 DisallowHeapAllocation no_gc; 18401 Isolate* isolate = table->GetIsolate(); 18402 Object* raw_key = *key; 18403 int entry = table->KeyToFirstEntry(isolate, raw_key); 18404 // Walk the chain in the bucket to find the key. 18405 while (entry != kNotFound) { 18406 Object* candidate_key = table->KeyAt(entry); 18407 if (candidate_key->SameValueZero(raw_key)) return true; 18408 entry = table->NextChainEntry(entry); 18409 } 18410 return false; 18411 } 18412 18413 18414 Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table, 18415 Handle<Object> key) { 18416 int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value(); 18417 int entry = table->HashToEntry(hash); 18418 // Walk the chain of the bucket and try finding the key. 18419 while (entry != kNotFound) { 18420 Object* candidate_key = table->KeyAt(entry); 18421 // Do not add if we have the key already 18422 if (candidate_key->SameValueZero(*key)) return table; 18423 entry = table->NextChainEntry(entry); 18424 } 18425 18426 table = OrderedHashSet::EnsureGrowable(table); 18427 // Read the existing bucket values. 18428 int bucket = table->HashToBucket(hash); 18429 int previous_entry = table->HashToEntry(hash); 18430 int nof = table->NumberOfElements(); 18431 // Insert a new entry at the end, 18432 int new_entry = nof + table->NumberOfDeletedElements(); 18433 int new_index = table->EntryToIndex(new_entry); 18434 table->set(new_index, *key); 18435 table->set(new_index + kChainOffset, Smi::FromInt(previous_entry)); 18436 // and point the bucket to the new entry. 18437 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); 18438 table->SetNumberOfElements(nof + 1); 18439 return table; 18440 } 18441 18442 Handle<FixedArray> OrderedHashSet::ConvertToKeysArray( 18443 Handle<OrderedHashSet> table, GetKeysConversion convert) { 18444 Isolate* isolate = table->GetIsolate(); 18445 int length = table->NumberOfElements(); 18446 int nof_buckets = table->NumberOfBuckets(); 18447 // Convert the dictionary to a linear list. 18448 Handle<FixedArray> result = Handle<FixedArray>::cast(table); 18449 // From this point on table is no longer a valid OrderedHashSet. 18450 result->set_map(isolate->heap()->fixed_array_map()); 18451 for (int i = 0; i < length; i++) { 18452 int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize); 18453 Object* key = table->get(index); 18454 if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) { 18455 key = *isolate->factory()->NumberToString(handle(key, isolate)); 18456 } 18457 result->set(i, key); 18458 } 18459 result->Shrink(length); 18460 return result; 18461 } 18462 18463 template<class Derived, class Iterator, int entrysize> 18464 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash( 18465 Handle<Derived> table, int new_capacity) { 18466 Isolate* isolate = table->GetIsolate(); 18467 DCHECK(!table->IsObsolete()); 18468 18469 Handle<Derived> new_table = 18470 Allocate(isolate, new_capacity, 18471 isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED); 18472 int nof = table->NumberOfElements(); 18473 int nod = table->NumberOfDeletedElements(); 18474 int new_buckets = new_table->NumberOfBuckets(); 18475 int new_entry = 0; 18476 int removed_holes_index = 0; 18477 18478 DisallowHeapAllocation no_gc; 18479 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) { 18480 Object* key = table->KeyAt(old_entry); 18481 if (key->IsTheHole(isolate)) { 18482 table->SetRemovedIndexAt(removed_holes_index++, old_entry); 18483 continue; 18484 } 18485 18486 Object* hash = key->GetHash(); 18487 int bucket = Smi::cast(hash)->value() & (new_buckets - 1); 18488 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket); 18489 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); 18490 int new_index = new_table->EntryToIndex(new_entry); 18491 int old_index = table->EntryToIndex(old_entry); 18492 for (int i = 0; i < entrysize; ++i) { 18493 Object* value = table->get(old_index + i); 18494 new_table->set(new_index + i, value); 18495 } 18496 new_table->set(new_index + kChainOffset, chain_entry); 18497 ++new_entry; 18498 } 18499 18500 DCHECK_EQ(nod, removed_holes_index); 18501 18502 new_table->SetNumberOfElements(nof); 18503 table->SetNextTable(*new_table); 18504 18505 return new_table; 18506 } 18507 18508 18509 template Handle<OrderedHashSet> 18510 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate( 18511 Isolate* isolate, int capacity, PretenureFlag pretenure); 18512 18513 template Handle<OrderedHashSet> 18514 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable( 18515 Handle<OrderedHashSet> table); 18516 18517 template Handle<OrderedHashSet> 18518 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink( 18519 Handle<OrderedHashSet> table); 18520 18521 template Handle<OrderedHashSet> 18522 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear( 18523 Handle<OrderedHashSet> table); 18524 18525 template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey( 18526 Handle<OrderedHashSet> table, Handle<Object> key); 18527 18528 18529 template Handle<OrderedHashMap> 18530 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate( 18531 Isolate* isolate, int capacity, PretenureFlag pretenure); 18532 18533 template Handle<OrderedHashMap> 18534 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable( 18535 Handle<OrderedHashMap> table); 18536 18537 template Handle<OrderedHashMap> 18538 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink( 18539 Handle<OrderedHashMap> table); 18540 18541 template Handle<OrderedHashMap> 18542 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear( 18543 Handle<OrderedHashMap> table); 18544 18545 template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey( 18546 Handle<OrderedHashMap> table, Handle<Object> key); 18547 18548 18549 template<class Derived, class TableType> 18550 void OrderedHashTableIterator<Derived, TableType>::Transition() { 18551 DisallowHeapAllocation no_allocation; 18552 TableType* table = TableType::cast(this->table()); 18553 if (!table->IsObsolete()) return; 18554 18555 int index = Smi::cast(this->index())->value(); 18556 while (table->IsObsolete()) { 18557 TableType* next_table = table->NextTable(); 18558 18559 if (index > 0) { 18560 int nod = table->NumberOfDeletedElements(); 18561 18562 if (nod == TableType::kClearedTableSentinel) { 18563 index = 0; 18564 } else { 18565 int old_index = index; 18566 for (int i = 0; i < nod; ++i) { 18567 int removed_index = table->RemovedIndexAt(i); 18568 if (removed_index >= old_index) break; 18569 --index; 18570 } 18571 } 18572 } 18573 18574 table = next_table; 18575 } 18576 18577 set_table(table); 18578 set_index(Smi::FromInt(index)); 18579 } 18580 18581 18582 template<class Derived, class TableType> 18583 bool OrderedHashTableIterator<Derived, TableType>::HasMore() { 18584 DisallowHeapAllocation no_allocation; 18585 Isolate* isolate = this->GetIsolate(); 18586 if (this->table()->IsUndefined(isolate)) return false; 18587 18588 Transition(); 18589 18590 TableType* table = TableType::cast(this->table()); 18591 int index = Smi::cast(this->index())->value(); 18592 int used_capacity = table->UsedCapacity(); 18593 18594 while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) { 18595 index++; 18596 } 18597 18598 set_index(Smi::FromInt(index)); 18599 18600 if (index < used_capacity) return true; 18601 18602 set_table(isolate->heap()->undefined_value()); 18603 return false; 18604 } 18605 18606 18607 template<class Derived, class TableType> 18608 Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) { 18609 DisallowHeapAllocation no_allocation; 18610 if (HasMore()) { 18611 FixedArray* array = FixedArray::cast(value_array->elements()); 18612 static_cast<Derived*>(this)->PopulateValueArray(array); 18613 MoveNext(); 18614 return Smi::cast(kind()); 18615 } 18616 return Smi::kZero; 18617 } 18618 18619 18620 template Smi* 18621 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next( 18622 JSArray* value_array); 18623 18624 template bool 18625 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore(); 18626 18627 template void 18628 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext(); 18629 18630 template Object* 18631 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey(); 18632 18633 template void 18634 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition(); 18635 18636 18637 template Smi* 18638 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next( 18639 JSArray* value_array); 18640 18641 template bool 18642 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore(); 18643 18644 template void 18645 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext(); 18646 18647 template Object* 18648 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey(); 18649 18650 template void 18651 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition(); 18652 18653 18654 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) { 18655 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet(); 18656 set->set_table(*table); 18657 } 18658 18659 18660 void JSSet::Clear(Handle<JSSet> set) { 18661 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); 18662 table = OrderedHashSet::Clear(table); 18663 set->set_table(*table); 18664 } 18665 18666 18667 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) { 18668 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap(); 18669 map->set_table(*table); 18670 } 18671 18672 18673 void JSMap::Clear(Handle<JSMap> map) { 18674 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); 18675 table = OrderedHashMap::Clear(table); 18676 map->set_table(*table); 18677 } 18678 18679 18680 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection, 18681 Isolate* isolate) { 18682 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0); 18683 weak_collection->set_table(*table); 18684 } 18685 18686 18687 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection, 18688 Handle<Object> key, Handle<Object> value, 18689 int32_t hash) { 18690 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 18691 Handle<ObjectHashTable> table( 18692 ObjectHashTable::cast(weak_collection->table())); 18693 DCHECK(table->IsKey(*key)); 18694 Handle<ObjectHashTable> new_table = 18695 ObjectHashTable::Put(table, key, value, hash); 18696 weak_collection->set_table(*new_table); 18697 if (*table != *new_table) { 18698 // Zap the old table since we didn't record slots for its elements. 18699 table->FillWithHoles(0, table->length()); 18700 } 18701 } 18702 18703 18704 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection, 18705 Handle<Object> key, int32_t hash) { 18706 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 18707 Handle<ObjectHashTable> table( 18708 ObjectHashTable::cast(weak_collection->table())); 18709 DCHECK(table->IsKey(*key)); 18710 bool was_present = false; 18711 Handle<ObjectHashTable> new_table = 18712 ObjectHashTable::Remove(table, key, &was_present, hash); 18713 weak_collection->set_table(*new_table); 18714 if (*table != *new_table) { 18715 // Zap the old table since we didn't record slots for its elements. 18716 table->FillWithHoles(0, table->length()); 18717 } 18718 return was_present; 18719 } 18720 18721 Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder, 18722 int max_entries) { 18723 Isolate* isolate = holder->GetIsolate(); 18724 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 18725 if (max_entries == 0 || max_entries > table->NumberOfElements()) { 18726 max_entries = table->NumberOfElements(); 18727 } 18728 int values_per_entry = holder->IsJSWeakMap() ? 2 : 1; 18729 Handle<FixedArray> entries = 18730 isolate->factory()->NewFixedArray(max_entries * values_per_entry); 18731 // Recompute max_values because GC could have removed elements from the table. 18732 if (max_entries > table->NumberOfElements()) { 18733 max_entries = table->NumberOfElements(); 18734 } 18735 18736 { 18737 DisallowHeapAllocation no_gc; 18738 int count = 0; 18739 for (int i = 0; 18740 count / values_per_entry < max_entries && i < table->Capacity(); i++) { 18741 Handle<Object> key(table->KeyAt(i), isolate); 18742 if (table->IsKey(isolate, *key)) { 18743 entries->set(count++, *key); 18744 if (values_per_entry > 1) { 18745 Object* value = table->Lookup(key); 18746 entries->set(count++, value); 18747 } 18748 } 18749 } 18750 DCHECK_EQ(max_entries * values_per_entry, count); 18751 } 18752 return isolate->factory()->NewJSArrayWithElements(entries); 18753 } 18754 18755 // Check if there is a break point at this source position. 18756 bool DebugInfo::HasBreakPoint(int source_position) { 18757 // Get the break point info object for this code offset. 18758 Object* break_point_info = GetBreakPointInfo(source_position); 18759 18760 // If there is no break point info object or no break points in the break 18761 // point info object there is no break point at this code offset. 18762 if (break_point_info->IsUndefined(GetIsolate())) return false; 18763 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0; 18764 } 18765 18766 // Get the break point info object for this source position. 18767 Object* DebugInfo::GetBreakPointInfo(int source_position) { 18768 Isolate* isolate = GetIsolate(); 18769 if (!break_points()->IsUndefined(isolate)) { 18770 for (int i = 0; i < break_points()->length(); i++) { 18771 if (!break_points()->get(i)->IsUndefined(isolate)) { 18772 BreakPointInfo* break_point_info = 18773 BreakPointInfo::cast(break_points()->get(i)); 18774 if (break_point_info->source_position() == source_position) { 18775 return break_point_info; 18776 } 18777 } 18778 } 18779 } 18780 return isolate->heap()->undefined_value(); 18781 } 18782 18783 bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, 18784 Handle<Object> break_point_object) { 18785 Isolate* isolate = debug_info->GetIsolate(); 18786 if (debug_info->break_points()->IsUndefined(isolate)) return false; 18787 18788 for (int i = 0; i < debug_info->break_points()->length(); i++) { 18789 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue; 18790 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>( 18791 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate); 18792 if (BreakPointInfo::HasBreakPointObject(break_point_info, 18793 break_point_object)) { 18794 BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object); 18795 return true; 18796 } 18797 } 18798 return false; 18799 } 18800 18801 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position, 18802 Handle<Object> break_point_object) { 18803 Isolate* isolate = debug_info->GetIsolate(); 18804 Handle<Object> break_point_info( 18805 debug_info->GetBreakPointInfo(source_position), isolate); 18806 if (!break_point_info->IsUndefined(isolate)) { 18807 BreakPointInfo::SetBreakPoint( 18808 Handle<BreakPointInfo>::cast(break_point_info), 18809 break_point_object); 18810 return; 18811 } 18812 18813 // Adding a new break point for a code offset which did not have any 18814 // break points before. Try to find a free slot. 18815 static const int kNoBreakPointInfo = -1; 18816 int index = kNoBreakPointInfo; 18817 for (int i = 0; i < debug_info->break_points()->length(); i++) { 18818 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) { 18819 index = i; 18820 break; 18821 } 18822 } 18823 if (index == kNoBreakPointInfo) { 18824 // No free slot - extend break point info array. 18825 Handle<FixedArray> old_break_points = Handle<FixedArray>( 18826 FixedArray::cast(debug_info->break_points()), isolate); 18827 Handle<FixedArray> new_break_points = 18828 isolate->factory()->NewFixedArray( 18829 old_break_points->length() + 18830 DebugInfo::kEstimatedNofBreakPointsInFunction); 18831 18832 debug_info->set_break_points(*new_break_points); 18833 for (int i = 0; i < old_break_points->length(); i++) { 18834 new_break_points->set(i, old_break_points->get(i)); 18835 } 18836 index = old_break_points->length(); 18837 } 18838 DCHECK(index != kNoBreakPointInfo); 18839 18840 // Allocate new BreakPointInfo object and set the break point. 18841 Handle<BreakPointInfo> new_break_point_info = 18842 isolate->factory()->NewBreakPointInfo(source_position); 18843 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object); 18844 debug_info->break_points()->set(index, *new_break_point_info); 18845 } 18846 18847 // Get the break point objects for a source position. 18848 Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) { 18849 Object* break_point_info = GetBreakPointInfo(source_position); 18850 Isolate* isolate = GetIsolate(); 18851 if (break_point_info->IsUndefined(isolate)) { 18852 return isolate->factory()->undefined_value(); 18853 } 18854 return Handle<Object>( 18855 BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate); 18856 } 18857 18858 18859 // Get the total number of break points. 18860 int DebugInfo::GetBreakPointCount() { 18861 Isolate* isolate = GetIsolate(); 18862 if (break_points()->IsUndefined(isolate)) return 0; 18863 int count = 0; 18864 for (int i = 0; i < break_points()->length(); i++) { 18865 if (!break_points()->get(i)->IsUndefined(isolate)) { 18866 BreakPointInfo* break_point_info = 18867 BreakPointInfo::cast(break_points()->get(i)); 18868 count += break_point_info->GetBreakPointCount(); 18869 } 18870 } 18871 return count; 18872 } 18873 18874 18875 Handle<Object> DebugInfo::FindBreakPointInfo( 18876 Handle<DebugInfo> debug_info, Handle<Object> break_point_object) { 18877 Isolate* isolate = debug_info->GetIsolate(); 18878 if (!debug_info->break_points()->IsUndefined(isolate)) { 18879 for (int i = 0; i < debug_info->break_points()->length(); i++) { 18880 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { 18881 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>( 18882 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate); 18883 if (BreakPointInfo::HasBreakPointObject(break_point_info, 18884 break_point_object)) { 18885 return break_point_info; 18886 } 18887 } 18888 } 18889 } 18890 return isolate->factory()->undefined_value(); 18891 } 18892 18893 // Remove the specified break point object. 18894 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, 18895 Handle<Object> break_point_object) { 18896 Isolate* isolate = break_point_info->GetIsolate(); 18897 // If there are no break points just ignore. 18898 if (break_point_info->break_point_objects()->IsUndefined(isolate)) return; 18899 // If there is a single break point clear it if it is the same. 18900 if (!break_point_info->break_point_objects()->IsFixedArray()) { 18901 if (break_point_info->break_point_objects() == *break_point_object) { 18902 break_point_info->set_break_point_objects( 18903 isolate->heap()->undefined_value()); 18904 } 18905 return; 18906 } 18907 // If there are multiple break points shrink the array 18908 DCHECK(break_point_info->break_point_objects()->IsFixedArray()); 18909 Handle<FixedArray> old_array = 18910 Handle<FixedArray>( 18911 FixedArray::cast(break_point_info->break_point_objects())); 18912 Handle<FixedArray> new_array = 18913 isolate->factory()->NewFixedArray(old_array->length() - 1); 18914 int found_count = 0; 18915 for (int i = 0; i < old_array->length(); i++) { 18916 if (old_array->get(i) == *break_point_object) { 18917 DCHECK(found_count == 0); 18918 found_count++; 18919 } else { 18920 new_array->set(i - found_count, old_array->get(i)); 18921 } 18922 } 18923 // If the break point was found in the list change it. 18924 if (found_count > 0) break_point_info->set_break_point_objects(*new_array); 18925 } 18926 18927 18928 // Add the specified break point object. 18929 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info, 18930 Handle<Object> break_point_object) { 18931 Isolate* isolate = break_point_info->GetIsolate(); 18932 18933 // If there was no break point objects before just set it. 18934 if (break_point_info->break_point_objects()->IsUndefined(isolate)) { 18935 break_point_info->set_break_point_objects(*break_point_object); 18936 return; 18937 } 18938 // If the break point object is the same as before just ignore. 18939 if (break_point_info->break_point_objects() == *break_point_object) return; 18940 // If there was one break point object before replace with array. 18941 if (!break_point_info->break_point_objects()->IsFixedArray()) { 18942 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2); 18943 array->set(0, break_point_info->break_point_objects()); 18944 array->set(1, *break_point_object); 18945 break_point_info->set_break_point_objects(*array); 18946 return; 18947 } 18948 // If there was more than one break point before extend array. 18949 Handle<FixedArray> old_array = 18950 Handle<FixedArray>( 18951 FixedArray::cast(break_point_info->break_point_objects())); 18952 Handle<FixedArray> new_array = 18953 isolate->factory()->NewFixedArray(old_array->length() + 1); 18954 for (int i = 0; i < old_array->length(); i++) { 18955 // If the break point was there before just ignore. 18956 if (old_array->get(i) == *break_point_object) return; 18957 new_array->set(i, old_array->get(i)); 18958 } 18959 // Add the new break point. 18960 new_array->set(old_array->length(), *break_point_object); 18961 break_point_info->set_break_point_objects(*new_array); 18962 } 18963 18964 18965 bool BreakPointInfo::HasBreakPointObject( 18966 Handle<BreakPointInfo> break_point_info, 18967 Handle<Object> break_point_object) { 18968 // No break point. 18969 Isolate* isolate = break_point_info->GetIsolate(); 18970 if (break_point_info->break_point_objects()->IsUndefined(isolate)) { 18971 return false; 18972 } 18973 // Single break point. 18974 if (!break_point_info->break_point_objects()->IsFixedArray()) { 18975 return break_point_info->break_point_objects() == *break_point_object; 18976 } 18977 // Multiple break points. 18978 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects()); 18979 for (int i = 0; i < array->length(); i++) { 18980 if (array->get(i) == *break_point_object) { 18981 return true; 18982 } 18983 } 18984 return false; 18985 } 18986 18987 18988 // Get the number of break points. 18989 int BreakPointInfo::GetBreakPointCount() { 18990 // No break point. 18991 if (break_point_objects()->IsUndefined(GetIsolate())) return 0; 18992 // Single break point. 18993 if (!break_point_objects()->IsFixedArray()) return 1; 18994 // Multiple break points. 18995 return FixedArray::cast(break_point_objects())->length(); 18996 } 18997 18998 18999 // static 19000 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor, 19001 Handle<JSReceiver> new_target, double tv) { 19002 Isolate* const isolate = constructor->GetIsolate(); 19003 Handle<JSObject> result; 19004 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 19005 JSObject::New(constructor, new_target), JSDate); 19006 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) { 19007 tv = DoubleToInteger(tv) + 0.0; 19008 } else { 19009 tv = std::numeric_limits<double>::quiet_NaN(); 19010 } 19011 Handle<Object> value = isolate->factory()->NewNumber(tv); 19012 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv)); 19013 return Handle<JSDate>::cast(result); 19014 } 19015 19016 19017 // static 19018 double JSDate::CurrentTimeValue(Isolate* isolate) { 19019 if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent()); 19020 19021 // According to ECMA-262, section 15.9.1, page 117, the precision of 19022 // the number in a Date object representing a particular instant in 19023 // time is milliseconds. Therefore, we floor the result of getting 19024 // the OS time. 19025 return Floor(FLAG_verify_predictable 19026 ? isolate->heap()->MonotonicallyIncreasingTimeInMs() 19027 : base::OS::TimeCurrentMillis()); 19028 } 19029 19030 19031 // static 19032 Object* JSDate::GetField(Object* object, Smi* index) { 19033 return JSDate::cast(object)->DoGetField( 19034 static_cast<FieldIndex>(index->value())); 19035 } 19036 19037 19038 Object* JSDate::DoGetField(FieldIndex index) { 19039 DCHECK(index != kDateValue); 19040 19041 DateCache* date_cache = GetIsolate()->date_cache(); 19042 19043 if (index < kFirstUncachedField) { 19044 Object* stamp = cache_stamp(); 19045 if (stamp != date_cache->stamp() && stamp->IsSmi()) { 19046 // Since the stamp is not NaN, the value is also not NaN. 19047 int64_t local_time_ms = 19048 date_cache->ToLocal(static_cast<int64_t>(value()->Number())); 19049 SetCachedFields(local_time_ms, date_cache); 19050 } 19051 switch (index) { 19052 case kYear: return year(); 19053 case kMonth: return month(); 19054 case kDay: return day(); 19055 case kWeekday: return weekday(); 19056 case kHour: return hour(); 19057 case kMinute: return min(); 19058 case kSecond: return sec(); 19059 default: UNREACHABLE(); 19060 } 19061 } 19062 19063 if (index >= kFirstUTCField) { 19064 return GetUTCField(index, value()->Number(), date_cache); 19065 } 19066 19067 double time = value()->Number(); 19068 if (std::isnan(time)) return GetIsolate()->heap()->nan_value(); 19069 19070 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time)); 19071 int days = DateCache::DaysFromTime(local_time_ms); 19072 19073 if (index == kDays) return Smi::FromInt(days); 19074 19075 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days); 19076 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000); 19077 DCHECK(index == kTimeInDay); 19078 return Smi::FromInt(time_in_day_ms); 19079 } 19080 19081 19082 Object* JSDate::GetUTCField(FieldIndex index, 19083 double value, 19084 DateCache* date_cache) { 19085 DCHECK(index >= kFirstUTCField); 19086 19087 if (std::isnan(value)) return GetIsolate()->heap()->nan_value(); 19088 19089 int64_t time_ms = static_cast<int64_t>(value); 19090 19091 if (index == kTimezoneOffset) { 19092 return Smi::FromInt(date_cache->TimezoneOffset(time_ms)); 19093 } 19094 19095 int days = DateCache::DaysFromTime(time_ms); 19096 19097 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days)); 19098 19099 if (index <= kDayUTC) { 19100 int year, month, day; 19101 date_cache->YearMonthDayFromDays(days, &year, &month, &day); 19102 if (index == kYearUTC) return Smi::FromInt(year); 19103 if (index == kMonthUTC) return Smi::FromInt(month); 19104 DCHECK(index == kDayUTC); 19105 return Smi::FromInt(day); 19106 } 19107 19108 int time_in_day_ms = DateCache::TimeInDay(time_ms, days); 19109 switch (index) { 19110 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000)); 19111 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60); 19112 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60); 19113 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000); 19114 case kDaysUTC: return Smi::FromInt(days); 19115 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms); 19116 default: UNREACHABLE(); 19117 } 19118 19119 UNREACHABLE(); 19120 return NULL; 19121 } 19122 19123 19124 // static 19125 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) { 19126 Isolate* const isolate = date->GetIsolate(); 19127 Handle<Object> value = isolate->factory()->NewNumber(v); 19128 bool value_is_nan = std::isnan(v); 19129 date->SetValue(*value, value_is_nan); 19130 return value; 19131 } 19132 19133 19134 void JSDate::SetValue(Object* value, bool is_value_nan) { 19135 set_value(value); 19136 if (is_value_nan) { 19137 HeapNumber* nan = GetIsolate()->heap()->nan_value(); 19138 set_cache_stamp(nan, SKIP_WRITE_BARRIER); 19139 set_year(nan, SKIP_WRITE_BARRIER); 19140 set_month(nan, SKIP_WRITE_BARRIER); 19141 set_day(nan, SKIP_WRITE_BARRIER); 19142 set_hour(nan, SKIP_WRITE_BARRIER); 19143 set_min(nan, SKIP_WRITE_BARRIER); 19144 set_sec(nan, SKIP_WRITE_BARRIER); 19145 set_weekday(nan, SKIP_WRITE_BARRIER); 19146 } else { 19147 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER); 19148 } 19149 } 19150 19151 19152 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) { 19153 int days = DateCache::DaysFromTime(local_time_ms); 19154 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days); 19155 int year, month, day; 19156 date_cache->YearMonthDayFromDays(days, &year, &month, &day); 19157 int weekday = date_cache->Weekday(days); 19158 int hour = time_in_day_ms / (60 * 60 * 1000); 19159 int min = (time_in_day_ms / (60 * 1000)) % 60; 19160 int sec = (time_in_day_ms / 1000) % 60; 19161 set_cache_stamp(date_cache->stamp()); 19162 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 19163 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 19164 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 19165 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 19166 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 19167 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 19168 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 19169 } 19170 19171 namespace { 19172 19173 Script* ScriptFromJSValue(Object* in) { 19174 DCHECK(in->IsJSValue()); 19175 JSValue* jsvalue = JSValue::cast(in); 19176 DCHECK(jsvalue->value()->IsScript()); 19177 return Script::cast(jsvalue->value()); 19178 } 19179 19180 } // namespace 19181 19182 int JSMessageObject::GetLineNumber() const { 19183 if (start_position() == -1) return Message::kNoLineNumberInfo; 19184 19185 Handle<Script> the_script = handle(ScriptFromJSValue(script())); 19186 19187 Script::PositionInfo info; 19188 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 19189 if (!Script::GetPositionInfo(the_script, start_position(), &info, 19190 offset_flag)) { 19191 return Message::kNoLineNumberInfo; 19192 } 19193 19194 return info.line + 1; 19195 } 19196 19197 int JSMessageObject::GetColumnNumber() const { 19198 if (start_position() == -1) return -1; 19199 19200 Handle<Script> the_script = handle(ScriptFromJSValue(script())); 19201 19202 Script::PositionInfo info; 19203 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 19204 if (!Script::GetPositionInfo(the_script, start_position(), &info, 19205 offset_flag)) { 19206 return -1; 19207 } 19208 19209 return info.column; // Note: No '+1' in contrast to GetLineNumber. 19210 } 19211 19212 Handle<String> JSMessageObject::GetSourceLine() const { 19213 Handle<Script> the_script = handle(ScriptFromJSValue(script())); 19214 19215 Isolate* isolate = the_script->GetIsolate(); 19216 if (the_script->type() == Script::TYPE_WASM) { 19217 return isolate->factory()->empty_string(); 19218 } 19219 19220 Script::PositionInfo info; 19221 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 19222 if (!Script::GetPositionInfo(the_script, start_position(), &info, 19223 offset_flag)) { 19224 return isolate->factory()->empty_string(); 19225 } 19226 19227 Handle<String> src = handle(String::cast(the_script->source()), isolate); 19228 return isolate->factory()->NewSubString(src, info.line_start, info.line_end); 19229 } 19230 19231 void JSArrayBuffer::Neuter() { 19232 CHECK(is_neuterable()); 19233 CHECK(is_external()); 19234 set_backing_store(NULL); 19235 set_byte_length(Smi::kZero); 19236 set_was_neutered(true); 19237 // Invalidate the neutering protector. 19238 Isolate* const isolate = GetIsolate(); 19239 if (isolate->IsArrayBufferNeuteringIntact()) { 19240 isolate->InvalidateArrayBufferNeuteringProtector(); 19241 } 19242 } 19243 19244 19245 void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate, 19246 bool is_external, void* data, size_t allocated_length, 19247 SharedFlag shared) { 19248 DCHECK(array_buffer->GetInternalFieldCount() == 19249 v8::ArrayBuffer::kInternalFieldCount); 19250 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { 19251 array_buffer->SetInternalField(i, Smi::kZero); 19252 } 19253 array_buffer->set_bit_field(0); 19254 array_buffer->set_is_external(is_external); 19255 array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared); 19256 array_buffer->set_is_shared(shared == SharedFlag::kShared); 19257 19258 Handle<Object> byte_length = 19259 isolate->factory()->NewNumberFromSize(allocated_length); 19260 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); 19261 array_buffer->set_byte_length(*byte_length); 19262 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that 19263 // are currently being constructed in the |ArrayBufferTracker|. The 19264 // registration method below handles the case of registering a buffer that has 19265 // already been promoted. 19266 array_buffer->set_backing_store(data); 19267 19268 if (data && !is_external) { 19269 isolate->heap()->RegisterNewArrayBuffer(*array_buffer); 19270 } 19271 } 19272 19273 19274 bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer, 19275 Isolate* isolate, 19276 size_t allocated_length, 19277 bool initialize, SharedFlag shared) { 19278 void* data; 19279 CHECK(isolate->array_buffer_allocator() != NULL); 19280 // Prevent creating array buffers when serializing. 19281 DCHECK(!isolate->serializer_enabled()); 19282 if (allocated_length != 0) { 19283 if (initialize) { 19284 data = isolate->array_buffer_allocator()->Allocate(allocated_length); 19285 } else { 19286 data = isolate->array_buffer_allocator()->AllocateUninitialized( 19287 allocated_length); 19288 } 19289 if (data == NULL) return false; 19290 } else { 19291 data = NULL; 19292 } 19293 19294 JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length, 19295 shared); 19296 return true; 19297 } 19298 19299 19300 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer( 19301 Handle<JSTypedArray> typed_array) { 19302 19303 Handle<Map> map(typed_array->map()); 19304 Isolate* isolate = typed_array->GetIsolate(); 19305 19306 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind())); 19307 19308 Handle<FixedTypedArrayBase> fixed_typed_array( 19309 FixedTypedArrayBase::cast(typed_array->elements())); 19310 19311 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()), 19312 isolate); 19313 void* backing_store = 19314 isolate->array_buffer_allocator()->AllocateUninitialized( 19315 fixed_typed_array->DataSize()); 19316 buffer->set_is_external(false); 19317 DCHECK(buffer->byte_length()->IsSmi() || 19318 buffer->byte_length()->IsHeapNumber()); 19319 DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize()); 19320 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that 19321 // are currently being constructed in the |ArrayBufferTracker|. The 19322 // registration method below handles the case of registering a buffer that has 19323 // already been promoted. 19324 buffer->set_backing_store(backing_store); 19325 isolate->heap()->RegisterNewArrayBuffer(*buffer); 19326 memcpy(buffer->backing_store(), 19327 fixed_typed_array->DataPtr(), 19328 fixed_typed_array->DataSize()); 19329 Handle<FixedTypedArrayBase> new_elements = 19330 isolate->factory()->NewFixedTypedArrayWithExternalPointer( 19331 fixed_typed_array->length(), typed_array->type(), 19332 static_cast<uint8_t*>(buffer->backing_store())); 19333 19334 typed_array->set_elements(*new_elements); 19335 19336 return buffer; 19337 } 19338 19339 19340 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() { 19341 Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()), 19342 GetIsolate()); 19343 if (array_buffer->was_neutered() || 19344 array_buffer->backing_store() != nullptr) { 19345 return array_buffer; 19346 } 19347 Handle<JSTypedArray> self(this); 19348 return MaterializeArrayBuffer(self); 19349 } 19350 19351 Handle<PropertyCell> PropertyCell::InvalidateEntry( 19352 Handle<GlobalDictionary> dictionary, int entry) { 19353 Isolate* isolate = dictionary->GetIsolate(); 19354 // Swap with a copy. 19355 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 19356 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry))); 19357 Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(); 19358 new_cell->set_value(cell->value()); 19359 dictionary->ValueAtPut(entry, *new_cell); 19360 bool is_the_hole = cell->value()->IsTheHole(isolate); 19361 // Cell is officially mutable henceforth. 19362 PropertyDetails details = cell->property_details(); 19363 details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized 19364 : PropertyCellType::kMutable); 19365 new_cell->set_property_details(details); 19366 // Old cell is ready for invalidation. 19367 if (is_the_hole) { 19368 cell->set_value(isolate->heap()->undefined_value()); 19369 } else { 19370 cell->set_value(isolate->heap()->the_hole_value()); 19371 } 19372 details = details.set_cell_type(PropertyCellType::kInvalidated); 19373 cell->set_property_details(details); 19374 cell->dependent_code()->DeoptimizeDependentCodeGroup( 19375 isolate, DependentCode::kPropertyCellChangedGroup); 19376 return new_cell; 19377 } 19378 19379 19380 PropertyCellConstantType PropertyCell::GetConstantType() { 19381 if (value()->IsSmi()) return PropertyCellConstantType::kSmi; 19382 return PropertyCellConstantType::kStableMap; 19383 } 19384 19385 19386 static bool RemainsConstantType(Handle<PropertyCell> cell, 19387 Handle<Object> value) { 19388 // TODO(dcarney): double->smi and smi->double transition from kConstant 19389 if (cell->value()->IsSmi() && value->IsSmi()) { 19390 return true; 19391 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) { 19392 return HeapObject::cast(cell->value())->map() == 19393 HeapObject::cast(*value)->map() && 19394 HeapObject::cast(*value)->map()->is_stable(); 19395 } 19396 return false; 19397 } 19398 19399 19400 PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell, 19401 Handle<Object> value, 19402 PropertyDetails details) { 19403 PropertyCellType type = details.cell_type(); 19404 Isolate* isolate = cell->GetIsolate(); 19405 DCHECK(!value->IsTheHole(isolate)); 19406 if (cell->value()->IsTheHole(isolate)) { 19407 switch (type) { 19408 // Only allow a cell to transition once into constant state. 19409 case PropertyCellType::kUninitialized: 19410 if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined; 19411 return PropertyCellType::kConstant; 19412 case PropertyCellType::kInvalidated: 19413 return PropertyCellType::kMutable; 19414 default: 19415 UNREACHABLE(); 19416 return PropertyCellType::kMutable; 19417 } 19418 } 19419 switch (type) { 19420 case PropertyCellType::kUndefined: 19421 return PropertyCellType::kConstant; 19422 case PropertyCellType::kConstant: 19423 if (*value == cell->value()) return PropertyCellType::kConstant; 19424 // Fall through. 19425 case PropertyCellType::kConstantType: 19426 if (RemainsConstantType(cell, value)) { 19427 return PropertyCellType::kConstantType; 19428 } 19429 // Fall through. 19430 case PropertyCellType::kMutable: 19431 return PropertyCellType::kMutable; 19432 } 19433 UNREACHABLE(); 19434 return PropertyCellType::kMutable; 19435 } 19436 19437 Handle<PropertyCell> PropertyCell::PrepareForValue( 19438 Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value, 19439 PropertyDetails details) { 19440 Isolate* isolate = dictionary->GetIsolate(); 19441 DCHECK(!value->IsTheHole(isolate)); 19442 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 19443 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry))); 19444 const PropertyDetails original_details = cell->property_details(); 19445 // Data accesses could be cached in ics or optimized code. 19446 bool invalidate = 19447 original_details.kind() == kData && details.kind() == kAccessor; 19448 int index = original_details.dictionary_index(); 19449 PropertyCellType old_type = original_details.cell_type(); 19450 // Preserve the enumeration index unless the property was deleted or never 19451 // initialized. 19452 if (cell->value()->IsTheHole(isolate)) { 19453 index = dictionary->NextEnumerationIndex(); 19454 dictionary->SetNextEnumerationIndex(index + 1); 19455 } 19456 DCHECK(index > 0); 19457 details = details.set_index(index); 19458 19459 PropertyCellType new_type = UpdatedType(cell, value, original_details); 19460 if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry); 19461 19462 // Install new property details. 19463 details = details.set_cell_type(new_type); 19464 cell->set_property_details(details); 19465 19466 // Deopt when transitioning from a constant type. 19467 if (!invalidate && (old_type != new_type || 19468 original_details.IsReadOnly() != details.IsReadOnly())) { 19469 cell->dependent_code()->DeoptimizeDependentCodeGroup( 19470 isolate, DependentCode::kPropertyCellChangedGroup); 19471 } 19472 return cell; 19473 } 19474 19475 19476 // static 19477 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, 19478 Handle<Object> new_value) { 19479 if (cell->value() != *new_value) { 19480 cell->set_value(*new_value); 19481 Isolate* isolate = cell->GetIsolate(); 19482 cell->dependent_code()->DeoptimizeDependentCodeGroup( 19483 isolate, DependentCode::kPropertyCellChangedGroup); 19484 } 19485 } 19486 19487 int JSGeneratorObject::source_position() const { 19488 CHECK(is_suspended()); 19489 DCHECK(function()->shared()->HasBytecodeArray()); 19490 DCHECK(!function()->shared()->HasBaselineCode()); 19491 int code_offset = Smi::cast(input_or_debug_pos())->value(); 19492 // The stored bytecode offset is relative to a different base than what 19493 // is used in the source position table, hence the subtraction. 19494 code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag; 19495 AbstractCode* code = 19496 AbstractCode::cast(function()->shared()->bytecode_array()); 19497 return code->SourcePosition(code_offset); 19498 } 19499 19500 // static 19501 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate, 19502 Handle<JSObject> receiver) { 19503 DisallowHeapAllocation no_gc; 19504 DCHECK(receiver->map()->is_access_check_needed()); 19505 Object* maybe_constructor = receiver->map()->GetConstructor(); 19506 // Might happen for a detached context. 19507 if (!maybe_constructor->IsJSFunction()) return nullptr; 19508 JSFunction* constructor = JSFunction::cast(maybe_constructor); 19509 // Might happen for the debug context. 19510 if (!constructor->shared()->IsApiFunction()) return nullptr; 19511 19512 Object* data_obj = 19513 constructor->shared()->get_api_func_data()->access_check_info(); 19514 if (data_obj->IsUndefined(isolate)) return nullptr; 19515 19516 return AccessCheckInfo::cast(data_obj); 19517 } 19518 19519 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) { 19520 for (PrototypeIterator iter(isolate, this, kStartAtReceiver, 19521 PrototypeIterator::END_AT_NULL); 19522 !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) { 19523 if (iter.GetCurrent<Object>()->IsJSProxy()) return true; 19524 } 19525 return false; 19526 } 19527 19528 MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) { 19529 Isolate* isolate = name->GetIsolate(); 19530 19531 Handle<Object> object(module()->exports()->Lookup(name), isolate); 19532 if (object->IsTheHole(isolate)) { 19533 return isolate->factory()->undefined_value(); 19534 } 19535 19536 Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate); 19537 if (value->IsTheHole(isolate)) { 19538 THROW_NEW_ERROR( 19539 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object); 19540 } 19541 19542 return value; 19543 } 19544 19545 namespace { 19546 19547 struct ModuleHandleHash { 19548 V8_INLINE size_t operator()(Handle<Module> module) const { 19549 return module->hash(); 19550 } 19551 }; 19552 19553 struct ModuleHandleEqual { 19554 V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const { 19555 return *lhs == *rhs; 19556 } 19557 }; 19558 19559 struct StringHandleHash { 19560 V8_INLINE size_t operator()(Handle<String> string) const { 19561 return string->Hash(); 19562 } 19563 }; 19564 19565 struct StringHandleEqual { 19566 V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const { 19567 return lhs->Equals(*rhs); 19568 } 19569 }; 19570 19571 class UnorderedStringSet 19572 : public std::unordered_set<Handle<String>, StringHandleHash, 19573 StringHandleEqual, 19574 zone_allocator<Handle<String>>> { 19575 public: 19576 explicit UnorderedStringSet(Zone* zone) 19577 : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual, 19578 zone_allocator<Handle<String>>>( 19579 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), 19580 zone_allocator<Handle<String>>(zone)) {} 19581 }; 19582 19583 class UnorderedModuleSet 19584 : public std::unordered_set<Handle<Module>, ModuleHandleHash, 19585 ModuleHandleEqual, 19586 zone_allocator<Handle<Module>>> { 19587 public: 19588 explicit UnorderedModuleSet(Zone* zone) 19589 : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual, 19590 zone_allocator<Handle<Module>>>( 19591 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), 19592 zone_allocator<Handle<Module>>(zone)) {} 19593 }; 19594 19595 class UnorderedStringMap 19596 : public std::unordered_map< 19597 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, 19598 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>> { 19599 public: 19600 explicit UnorderedStringMap(Zone* zone) 19601 : std::unordered_map< 19602 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, 19603 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>>( 19604 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), 19605 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>( 19606 zone)) {} 19607 }; 19608 19609 } // anonymous namespace 19610 19611 class Module::ResolveSet 19612 : public std::unordered_map< 19613 Handle<Module>, UnorderedStringSet*, ModuleHandleHash, 19614 ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>, 19615 UnorderedStringSet*>>> { 19616 public: 19617 explicit ResolveSet(Zone* zone) 19618 : std::unordered_map<Handle<Module>, UnorderedStringSet*, 19619 ModuleHandleHash, ModuleHandleEqual, 19620 zone_allocator<std::pair<const Handle<Module>, 19621 UnorderedStringSet*>>>( 19622 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), 19623 zone_allocator< 19624 std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)), 19625 zone_(zone) {} 19626 19627 Zone* zone() const { return zone_; } 19628 19629 private: 19630 Zone* zone_; 19631 }; 19632 19633 namespace { 19634 19635 int ExportIndex(int cell_index) { 19636 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 19637 ModuleDescriptor::kExport); 19638 return cell_index - 1; 19639 } 19640 19641 int ImportIndex(int cell_index) { 19642 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 19643 ModuleDescriptor::kImport); 19644 return -cell_index - 1; 19645 } 19646 19647 } // anonymous namespace 19648 19649 void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name, 19650 Handle<ModuleInfoEntry> entry) { 19651 Isolate* isolate = module->GetIsolate(); 19652 Handle<ObjectHashTable> exports(module->exports(), isolate); 19653 DCHECK(exports->Lookup(name)->IsTheHole(isolate)); 19654 exports = ObjectHashTable::Put(exports, name, entry); 19655 module->set_exports(*exports); 19656 } 19657 19658 void Module::CreateExport(Handle<Module> module, int cell_index, 19659 Handle<FixedArray> names) { 19660 DCHECK_LT(0, names->length()); 19661 Isolate* isolate = module->GetIsolate(); 19662 19663 Handle<Cell> cell = 19664 isolate->factory()->NewCell(isolate->factory()->undefined_value()); 19665 module->regular_exports()->set(ExportIndex(cell_index), *cell); 19666 19667 Handle<ObjectHashTable> exports(module->exports(), isolate); 19668 for (int i = 0, n = names->length(); i < n; ++i) { 19669 Handle<String> name(String::cast(names->get(i)), isolate); 19670 DCHECK(exports->Lookup(name)->IsTheHole(isolate)); 19671 exports = ObjectHashTable::Put(exports, name, cell); 19672 } 19673 module->set_exports(*exports); 19674 } 19675 19676 Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) { 19677 Isolate* isolate = module->GetIsolate(); 19678 Handle<Object> object; 19679 switch (ModuleDescriptor::GetCellIndexKind(cell_index)) { 19680 case ModuleDescriptor::kImport: 19681 object = handle(module->regular_imports()->get(ImportIndex(cell_index)), 19682 isolate); 19683 break; 19684 case ModuleDescriptor::kExport: 19685 object = handle(module->regular_exports()->get(ExportIndex(cell_index)), 19686 isolate); 19687 break; 19688 case ModuleDescriptor::kInvalid: 19689 UNREACHABLE(); 19690 break; 19691 } 19692 return handle(Handle<Cell>::cast(object)->value(), isolate); 19693 } 19694 19695 void Module::StoreVariable(Handle<Module> module, int cell_index, 19696 Handle<Object> value) { 19697 Isolate* isolate = module->GetIsolate(); 19698 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 19699 ModuleDescriptor::kExport); 19700 Handle<Object> object(module->regular_exports()->get(ExportIndex(cell_index)), 19701 isolate); 19702 Handle<Cell>::cast(object)->set_value(*value); 19703 } 19704 19705 MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module, 19706 Handle<String> name, int module_request, 19707 MessageLocation loc, bool must_resolve, 19708 Module::ResolveSet* resolve_set) { 19709 Isolate* isolate = module->GetIsolate(); 19710 Handle<Module> requested_module( 19711 Module::cast(module->requested_modules()->get(module_request)), isolate); 19712 return Module::ResolveExport(requested_module, name, loc, must_resolve, 19713 resolve_set); 19714 } 19715 19716 MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module, 19717 Handle<String> name, 19718 MessageLocation loc, bool must_resolve, 19719 Module::ResolveSet* resolve_set) { 19720 Isolate* isolate = module->GetIsolate(); 19721 Handle<Object> object(module->exports()->Lookup(name), isolate); 19722 if (object->IsCell()) { 19723 // Already resolved (e.g. because it's a local export). 19724 return Handle<Cell>::cast(object); 19725 } 19726 19727 // Check for cycle before recursing. 19728 { 19729 // Attempt insertion with a null string set. 19730 auto result = resolve_set->insert({module, nullptr}); 19731 UnorderedStringSet*& name_set = result.first->second; 19732 if (result.second) { 19733 // |module| wasn't in the map previously, so allocate a new name set. 19734 Zone* zone = resolve_set->zone(); 19735 name_set = 19736 new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone); 19737 } else if (name_set->count(name)) { 19738 // Cycle detected. 19739 if (must_resolve) { 19740 return isolate->Throw<Cell>( 19741 isolate->factory()->NewSyntaxError( 19742 MessageTemplate::kCyclicModuleDependency, name), 19743 &loc); 19744 } 19745 return MaybeHandle<Cell>(); 19746 } 19747 name_set->insert(name); 19748 } 19749 19750 if (object->IsModuleInfoEntry()) { 19751 // Not yet resolved indirect export. 19752 Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object); 19753 Handle<String> import_name(String::cast(entry->import_name()), isolate); 19754 Handle<Script> script( 19755 Script::cast(JSFunction::cast(module->code())->shared()->script()), 19756 isolate); 19757 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); 19758 19759 Handle<Cell> cell; 19760 if (!ResolveImport(module, import_name, entry->module_request(), new_loc, 19761 true, resolve_set) 19762 .ToHandle(&cell)) { 19763 DCHECK(isolate->has_pending_exception()); 19764 return MaybeHandle<Cell>(); 19765 } 19766 19767 // The export table may have changed but the entry in question should be 19768 // unchanged. 19769 Handle<ObjectHashTable> exports(module->exports(), isolate); 19770 DCHECK(exports->Lookup(name)->IsModuleInfoEntry()); 19771 19772 exports = ObjectHashTable::Put(exports, name, cell); 19773 module->set_exports(*exports); 19774 return cell; 19775 } 19776 19777 DCHECK(object->IsTheHole(isolate)); 19778 return Module::ResolveExportUsingStarExports(module, name, loc, must_resolve, 19779 resolve_set); 19780 } 19781 19782 MaybeHandle<Cell> Module::ResolveExportUsingStarExports( 19783 Handle<Module> module, Handle<String> name, MessageLocation loc, 19784 bool must_resolve, Module::ResolveSet* resolve_set) { 19785 Isolate* isolate = module->GetIsolate(); 19786 if (!name->Equals(isolate->heap()->default_string())) { 19787 // Go through all star exports looking for the given name. If multiple star 19788 // exports provide the name, make sure they all map it to the same cell. 19789 Handle<Cell> unique_cell; 19790 Handle<FixedArray> special_exports(module->info()->special_exports(), 19791 isolate); 19792 for (int i = 0, n = special_exports->length(); i < n; ++i) { 19793 i::Handle<i::ModuleInfoEntry> entry( 19794 i::ModuleInfoEntry::cast(special_exports->get(i)), isolate); 19795 if (!entry->export_name()->IsUndefined(isolate)) { 19796 continue; // Indirect export. 19797 } 19798 19799 Handle<Script> script( 19800 Script::cast(JSFunction::cast(module->code())->shared()->script()), 19801 isolate); 19802 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); 19803 19804 Handle<Cell> cell; 19805 if (ResolveImport(module, name, entry->module_request(), new_loc, false, 19806 resolve_set) 19807 .ToHandle(&cell)) { 19808 if (unique_cell.is_null()) unique_cell = cell; 19809 if (*unique_cell != *cell) { 19810 return isolate->Throw<Cell>( 19811 isolate->factory()->NewSyntaxError( 19812 MessageTemplate::kAmbiguousExport, name), 19813 &loc); 19814 } 19815 } else if (isolate->has_pending_exception()) { 19816 return MaybeHandle<Cell>(); 19817 } 19818 } 19819 19820 if (!unique_cell.is_null()) { 19821 // Found a unique star export for this name. 19822 Handle<ObjectHashTable> exports(module->exports(), isolate); 19823 DCHECK(exports->Lookup(name)->IsTheHole(isolate)); 19824 exports = ObjectHashTable::Put(exports, name, unique_cell); 19825 module->set_exports(*exports); 19826 return unique_cell; 19827 } 19828 } 19829 19830 // Unresolvable. 19831 if (must_resolve) { 19832 return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError( 19833 MessageTemplate::kUnresolvableExport, name), 19834 &loc); 19835 } 19836 return MaybeHandle<Cell>(); 19837 } 19838 19839 bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context, 19840 v8::Module::ResolveCallback callback) { 19841 if (module->instantiated()) return true; 19842 19843 Isolate* isolate = module->GetIsolate(); 19844 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()), 19845 isolate); 19846 Handle<JSFunction> function = 19847 isolate->factory()->NewFunctionFromSharedFunctionInfo( 19848 shared, 19849 handle(Utils::OpenHandle(*context)->native_context(), isolate)); 19850 module->set_code(*function); 19851 DCHECK(module->instantiated()); 19852 19853 Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(), 19854 isolate); 19855 19856 // Set up local exports. 19857 // TODO(neis): Create regular_exports array here instead of in factory method? 19858 for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) { 19859 int cell_index = module_info->RegularExportCellIndex(i); 19860 Handle<FixedArray> export_names(module_info->RegularExportExportNames(i), 19861 isolate); 19862 CreateExport(module, cell_index, export_names); 19863 } 19864 19865 // Partially set up indirect exports. 19866 // For each indirect export, we create the appropriate slot in the export 19867 // table and store its ModuleInfoEntry there. When we later find the correct 19868 // Cell in the module that actually provides the value, we replace the 19869 // ModuleInfoEntry by that Cell (see ResolveExport). 19870 Handle<FixedArray> special_exports(module_info->special_exports(), isolate); 19871 for (int i = 0, n = special_exports->length(); i < n; ++i) { 19872 Handle<ModuleInfoEntry> entry( 19873 ModuleInfoEntry::cast(special_exports->get(i)), isolate); 19874 Handle<Object> export_name(entry->export_name(), isolate); 19875 if (export_name->IsUndefined(isolate)) continue; // Star export. 19876 CreateIndirectExport(module, Handle<String>::cast(export_name), entry); 19877 } 19878 19879 Handle<FixedArray> module_requests(module_info->module_requests(), isolate); 19880 for (int i = 0, length = module_requests->length(); i < length; ++i) { 19881 Handle<String> specifier(String::cast(module_requests->get(i)), isolate); 19882 v8::Local<v8::Module> api_requested_module; 19883 // TODO(adamk): Revisit these failure cases once d8 knows how to 19884 // persist a module_map across multiple top-level module loads, as 19885 // the current module is left in a "half-instantiated" state. 19886 if (!callback(context, v8::Utils::ToLocal(specifier), 19887 v8::Utils::ToLocal(module)) 19888 .ToLocal(&api_requested_module)) { 19889 // TODO(adamk): Give this a better error message. But this is a 19890 // misuse of the API anyway. 19891 isolate->ThrowIllegalOperation(); 19892 return false; 19893 } 19894 Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module); 19895 module->requested_modules()->set(i, *requested_module); 19896 if (!Instantiate(requested_module, context, callback)) { 19897 return false; 19898 } 19899 } 19900 19901 Zone zone(isolate->allocator(), ZONE_NAME); 19902 19903 // Resolve imports. 19904 Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate); 19905 for (int i = 0, n = regular_imports->length(); i < n; ++i) { 19906 Handle<ModuleInfoEntry> entry( 19907 ModuleInfoEntry::cast(regular_imports->get(i)), isolate); 19908 Handle<String> name(String::cast(entry->import_name()), isolate); 19909 Handle<Script> script( 19910 Script::cast(JSFunction::cast(module->code())->shared()->script()), 19911 isolate); 19912 MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); 19913 ResolveSet resolve_set(&zone); 19914 Handle<Cell> cell; 19915 if (!ResolveImport(module, name, entry->module_request(), loc, true, 19916 &resolve_set) 19917 .ToHandle(&cell)) { 19918 return false; 19919 } 19920 module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell); 19921 } 19922 19923 // Resolve indirect exports. 19924 for (int i = 0, n = special_exports->length(); i < n; ++i) { 19925 Handle<ModuleInfoEntry> entry( 19926 ModuleInfoEntry::cast(special_exports->get(i)), isolate); 19927 Handle<Object> name(entry->export_name(), isolate); 19928 if (name->IsUndefined(isolate)) continue; // Star export. 19929 Handle<Script> script( 19930 Script::cast(JSFunction::cast(module->code())->shared()->script()), 19931 isolate); 19932 MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); 19933 ResolveSet resolve_set(&zone); 19934 if (ResolveExport(module, Handle<String>::cast(name), loc, true, 19935 &resolve_set) 19936 .is_null()) { 19937 return false; 19938 } 19939 } 19940 19941 return true; 19942 } 19943 19944 MaybeHandle<Object> Module::Evaluate(Handle<Module> module) { 19945 DCHECK(module->instantiated()); 19946 19947 // Each module can only be evaluated once. 19948 Isolate* isolate = module->GetIsolate(); 19949 if (module->evaluated()) return isolate->factory()->undefined_value(); 19950 Handle<JSFunction> function(JSFunction::cast(module->code()), isolate); 19951 module->set_evaluated(); 19952 19953 // Initialization. 19954 DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type()); 19955 Handle<Object> receiver = isolate->factory()->undefined_value(); 19956 Handle<Object> argv[] = {module}; 19957 Handle<Object> generator; 19958 ASSIGN_RETURN_ON_EXCEPTION( 19959 isolate, generator, 19960 Execution::Call(isolate, function, receiver, arraysize(argv), argv), 19961 Object); 19962 19963 // Recursion. 19964 Handle<FixedArray> requested_modules(module->requested_modules(), isolate); 19965 for (int i = 0, length = requested_modules->length(); i < length; ++i) { 19966 Handle<Module> import(Module::cast(requested_modules->get(i)), isolate); 19967 RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object); 19968 } 19969 19970 // Evaluation of module body. 19971 Handle<JSFunction> resume( 19972 isolate->native_context()->generator_next_internal(), isolate); 19973 return Execution::Call(isolate, resume, generator, 0, nullptr); 19974 } 19975 19976 namespace { 19977 19978 void FetchStarExports(Handle<Module> module, Zone* zone, 19979 UnorderedModuleSet* visited) { 19980 DCHECK(module->instantiated()); 19981 19982 bool cycle = !visited->insert(module).second; 19983 if (cycle) return; 19984 19985 Isolate* isolate = module->GetIsolate(); 19986 Handle<ObjectHashTable> exports(module->exports(), isolate); 19987 UnorderedStringMap more_exports(zone); 19988 19989 // TODO(neis): Only allocate more_exports if there are star exports. 19990 // Maybe split special_exports into indirect_exports and star_exports. 19991 19992 Handle<FixedArray> special_exports(module->info()->special_exports(), 19993 isolate); 19994 for (int i = 0, n = special_exports->length(); i < n; ++i) { 19995 Handle<ModuleInfoEntry> entry( 19996 ModuleInfoEntry::cast(special_exports->get(i)), isolate); 19997 if (!entry->export_name()->IsUndefined(isolate)) { 19998 continue; // Indirect export. 19999 } 20000 20001 Handle<Module> requested_module( 20002 Module::cast(module->requested_modules()->get(entry->module_request())), 20003 isolate); 20004 20005 // Recurse. 20006 FetchStarExports(requested_module, zone, visited); 20007 20008 // Collect all of [requested_module]'s exports that must be added to 20009 // [module]'s exports (i.e. to [exports]). We record these in 20010 // [more_exports]. Ambiguities (conflicting exports) are marked by mapping 20011 // the name to undefined instead of a Cell. 20012 Handle<ObjectHashTable> requested_exports(requested_module->exports(), 20013 isolate); 20014 for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) { 20015 Handle<Object> key(requested_exports->KeyAt(i), isolate); 20016 if (!requested_exports->IsKey(isolate, *key)) continue; 20017 Handle<String> name = Handle<String>::cast(key); 20018 20019 if (name->Equals(isolate->heap()->default_string())) continue; 20020 if (!exports->Lookup(name)->IsTheHole(isolate)) continue; 20021 20022 Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate); 20023 auto insert_result = more_exports.insert(std::make_pair(name, cell)); 20024 if (!insert_result.second) { 20025 auto it = insert_result.first; 20026 if (*it->second == *cell || it->second->IsUndefined(isolate)) { 20027 // We already recorded this mapping before, or the name is already 20028 // known to be ambiguous. In either case, there's nothing to do. 20029 } else { 20030 DCHECK(it->second->IsCell()); 20031 // Different star exports provide different cells for this name, hence 20032 // mark the name as ambiguous. 20033 it->second = isolate->factory()->undefined_value(); 20034 } 20035 } 20036 } 20037 } 20038 20039 // Copy [more_exports] into [exports]. 20040 for (const auto& elem : more_exports) { 20041 if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export. 20042 DCHECK(!elem.first->Equals(isolate->heap()->default_string())); 20043 DCHECK(elem.second->IsCell()); 20044 exports = ObjectHashTable::Put(exports, elem.first, elem.second); 20045 } 20046 module->set_exports(*exports); 20047 } 20048 20049 } // anonymous namespace 20050 20051 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module, 20052 int module_request) { 20053 Isolate* isolate = module->GetIsolate(); 20054 Handle<Module> requested_module( 20055 Module::cast(module->requested_modules()->get(module_request)), isolate); 20056 return Module::GetModuleNamespace(requested_module); 20057 } 20058 20059 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) { 20060 Isolate* isolate = module->GetIsolate(); 20061 20062 Handle<HeapObject> object(module->module_namespace(), isolate); 20063 if (!object->IsUndefined(isolate)) { 20064 // Namespace object already exists. 20065 return Handle<JSModuleNamespace>::cast(object); 20066 } 20067 20068 // Create the namespace object (initially empty). 20069 Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace(); 20070 ns->set_module(*module); 20071 module->set_module_namespace(*ns); 20072 20073 // Collect the export names. 20074 Zone zone(isolate->allocator(), ZONE_NAME); 20075 UnorderedModuleSet visited(&zone); 20076 FetchStarExports(module, &zone, &visited); 20077 Handle<ObjectHashTable> exports(module->exports(), isolate); 20078 ZoneVector<Handle<String>> names(&zone); 20079 names.reserve(exports->NumberOfElements()); 20080 for (int i = 0, n = exports->Capacity(); i < n; ++i) { 20081 Handle<Object> key(exports->KeyAt(i), isolate); 20082 if (!exports->IsKey(isolate, *key)) continue; 20083 DCHECK(exports->ValueAt(i)->IsCell()); 20084 names.push_back(Handle<String>::cast(key)); 20085 } 20086 DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements()); 20087 20088 // Sort them alphabetically. 20089 struct { 20090 bool operator()(Handle<String> a, Handle<String> b) { 20091 return String::Compare(a, b) == ComparisonResult::kLessThan; 20092 } 20093 } StringLess; 20094 std::sort(names.begin(), names.end(), StringLess); 20095 20096 // Create the corresponding properties in the namespace object. 20097 PropertyAttributes attr = DONT_DELETE; 20098 for (const auto& name : names) { 20099 JSObject::SetAccessor( 20100 ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr)) 20101 .Check(); 20102 } 20103 JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked(); 20104 20105 return ns; 20106 } 20107 20108 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName( 20109 Isolate* isolate, Handle<Object> getter) { 20110 if (getter->IsFunctionTemplateInfo()) { 20111 Handle<FunctionTemplateInfo> fti = 20112 Handle<FunctionTemplateInfo>::cast(getter); 20113 // Check if the accessor uses a cached property. 20114 if (!fti->cached_property_name()->IsTheHole(isolate)) { 20115 return handle(Name::cast(fti->cached_property_name())); 20116 } 20117 } 20118 return MaybeHandle<Name>(); 20119 } 20120 20121 // static 20122 ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) { 20123 DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE); 20124 DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE); 20125 20126 if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) { 20127 // Should be ignored for key iterators. 20128 return FAST_ELEMENTS; 20129 } else { 20130 ElementsKind kind; 20131 if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) { 20132 // Convert `type` to a value iterator from an entries iterator 20133 type = static_cast<InstanceType>(type + 20134 (FIRST_ARRAY_VALUE_ITERATOR_TYPE - 20135 FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE)); 20136 DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE); 20137 DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE); 20138 } 20139 20140 if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) { 20141 kind = 20142 static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 20143 (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE)); 20144 DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); 20145 } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) { 20146 kind = static_cast<ElementsKind>( 20147 FIRST_FAST_ELEMENTS_KIND + 20148 (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE)); 20149 DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND); 20150 } else { 20151 // For any slow element cases, the actual elements kind is not known. 20152 // Simply 20153 // return a slow elements kind in this case. Users of this function must 20154 // not 20155 // depend on this. 20156 return DICTIONARY_ELEMENTS; 20157 } 20158 DCHECK_LE(kind, LAST_ELEMENTS_KIND); 20159 return kind; 20160 } 20161 } 20162 20163 } // namespace internal 20164 } // namespace v8 20165