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/base/bits.h" 22 #include "src/base/utils/random-number-generator.h" 23 #include "src/bootstrapper.h" 24 #include "src/code-stubs.h" 25 #include "src/codegen.h" 26 #include "src/compilation-dependencies.h" 27 #include "src/compiler.h" 28 #include "src/counters-inl.h" 29 #include "src/counters.h" 30 #include "src/date.h" 31 #include "src/debug/debug.h" 32 #include "src/deoptimizer.h" 33 #include "src/elements.h" 34 #include "src/execution.h" 35 #include "src/field-index-inl.h" 36 #include "src/field-index.h" 37 #include "src/field-type.h" 38 #include "src/frames-inl.h" 39 #include "src/full-codegen/full-codegen.h" 40 #include "src/globals.h" 41 #include "src/ic/ic.h" 42 #include "src/identity-map.h" 43 #include "src/interpreter/bytecode-array-iterator.h" 44 #include "src/interpreter/bytecode-decoder.h" 45 #include "src/interpreter/interpreter.h" 46 #include "src/isolate-inl.h" 47 #include "src/keys.h" 48 #include "src/list.h" 49 #include "src/log.h" 50 #include "src/lookup.h" 51 #include "src/macro-assembler.h" 52 #include "src/messages.h" 53 #include "src/objects-body-descriptors-inl.h" 54 #include "src/property-descriptor.h" 55 #include "src/prototype.h" 56 #include "src/regexp/jsregexp.h" 57 #include "src/safepoint-table.h" 58 #include "src/snapshot/code-serializer.h" 59 #include "src/source-position-table.h" 60 #include "src/string-builder.h" 61 #include "src/string-search.h" 62 #include "src/string-stream.h" 63 #include "src/utils.h" 64 #include "src/wasm/wasm-module.h" 65 #include "src/wasm/wasm-objects.h" 66 #include "src/zone/zone.h" 67 68 #ifdef ENABLE_DISASSEMBLER 69 #include "src/disasm.h" 70 #include "src/disassembler.h" 71 #include "src/eh-frame.h" 72 #endif 73 74 namespace v8 { 75 namespace internal { 76 77 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) { 78 switch (instance_type) { 79 #define WRITE_TYPE(TYPE) \ 80 case TYPE: \ 81 return os << #TYPE; 82 INSTANCE_TYPE_LIST(WRITE_TYPE) 83 #undef WRITE_TYPE 84 } 85 UNREACHABLE(); 86 return os << "UNKNOWN"; // Keep the compiler happy. 87 } 88 89 Handle<FieldType> Object::OptimalType(Isolate* isolate, 90 Representation representation) { 91 if (representation.IsNone()) return FieldType::None(isolate); 92 if (FLAG_track_field_types) { 93 if (representation.IsHeapObject() && IsHeapObject()) { 94 // We can track only JavaScript objects with stable maps. 95 Handle<Map> map(HeapObject::cast(this)->map(), isolate); 96 if (map->is_stable() && map->IsJSReceiverMap()) { 97 return FieldType::Class(map, isolate); 98 } 99 } 100 } 101 return FieldType::Any(isolate); 102 } 103 104 105 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate, 106 Handle<Object> object, 107 Handle<Context> native_context) { 108 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 109 Handle<JSFunction> constructor; 110 if (object->IsSmi()) { 111 constructor = handle(native_context->number_function(), isolate); 112 } else { 113 int constructor_function_index = 114 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex(); 115 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 116 THROW_NEW_ERROR(isolate, 117 NewTypeError(MessageTemplate::kUndefinedOrNullToObject), 118 JSReceiver); 119 } 120 constructor = handle( 121 JSFunction::cast(native_context->get(constructor_function_index)), 122 isolate); 123 } 124 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); 125 Handle<JSValue>::cast(result)->set_value(*object); 126 return result; 127 } 128 129 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. 130 // static 131 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate, 132 Handle<Object> object) { 133 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 134 if (*object == isolate->heap()->null_value() || 135 object->IsUndefined(isolate)) { 136 return isolate->global_proxy(); 137 } 138 return Object::ToObject(isolate, object); 139 } 140 141 // static 142 MaybeHandle<Object> Object::ToNumber(Handle<Object> input) { 143 while (true) { 144 if (input->IsNumber()) { 145 return input; 146 } 147 if (input->IsString()) { 148 return String::ToNumber(Handle<String>::cast(input)); 149 } 150 if (input->IsOddball()) { 151 return Oddball::ToNumber(Handle<Oddball>::cast(input)); 152 } 153 Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate(); 154 if (input->IsSymbol()) { 155 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), 156 Object); 157 } 158 if (input->IsSimd128Value()) { 159 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber), 160 Object); 161 } 162 ASSIGN_RETURN_ON_EXCEPTION( 163 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), 164 ToPrimitiveHint::kNumber), 165 Object); 166 } 167 } 168 169 170 // static 171 MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) { 172 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 173 return isolate->factory()->NewNumber(DoubleToInteger(input->Number())); 174 } 175 176 177 // static 178 MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) { 179 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 180 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number())); 181 } 182 183 184 // static 185 MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) { 186 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 187 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number())); 188 } 189 190 191 // static 192 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate, 193 Handle<Object> input) { 194 ASSIGN_RETURN_ON_EXCEPTION( 195 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString), 196 Name); 197 if (input->IsName()) return Handle<Name>::cast(input); 198 return ToString(isolate, input); 199 } 200 201 // static 202 MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) { 203 while (true) { 204 if (input->IsString()) { 205 return Handle<String>::cast(input); 206 } 207 if (input->IsOddball()) { 208 return handle(Handle<Oddball>::cast(input)->to_string(), isolate); 209 } 210 if (input->IsNumber()) { 211 return isolate->factory()->NumberToString(input); 212 } 213 if (input->IsSymbol()) { 214 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString), 215 String); 216 } 217 if (input->IsSimd128Value()) { 218 return Simd128Value::ToString(Handle<Simd128Value>::cast(input)); 219 } 220 ASSIGN_RETURN_ON_EXCEPTION( 221 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), 222 ToPrimitiveHint::kString), 223 String); 224 } 225 } 226 227 namespace { 228 229 bool IsErrorObject(Isolate* isolate, Handle<Object> object) { 230 if (!object->IsJSReceiver()) return false; 231 Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol(); 232 return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol) 233 .FromMaybe(false); 234 } 235 236 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) { 237 return object->IsString() ? Handle<String>::cast(object) 238 : isolate->factory()->empty_string(); 239 } 240 241 Handle<String> NoSideEffectsErrorToString(Isolate* isolate, 242 Handle<Object> input) { 243 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); 244 245 Handle<Name> name_key = isolate->factory()->name_string(); 246 Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key); 247 Handle<String> name_str = AsStringOrEmpty(isolate, name); 248 249 Handle<Name> msg_key = isolate->factory()->message_string(); 250 Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key); 251 Handle<String> msg_str = AsStringOrEmpty(isolate, msg); 252 253 if (name_str->length() == 0) return msg_str; 254 if (msg_str->length() == 0) return name_str; 255 256 IncrementalStringBuilder builder(isolate); 257 builder.AppendString(name_str); 258 builder.AppendCString(": "); 259 builder.AppendString(msg_str); 260 261 return builder.Finish().ToHandleChecked(); 262 } 263 264 } // namespace 265 266 // static 267 Handle<String> Object::NoSideEffectsToString(Isolate* isolate, 268 Handle<Object> input) { 269 DisallowJavascriptExecution no_js(isolate); 270 271 if (input->IsString() || input->IsNumber() || input->IsOddball() || 272 input->IsSimd128Value()) { 273 return Object::ToString(isolate, input).ToHandleChecked(); 274 } else if (input->IsFunction()) { 275 // -- F u n c t i o n 276 Handle<String> fun_str; 277 if (input->IsJSBoundFunction()) { 278 fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input)); 279 } else { 280 DCHECK(input->IsJSFunction()); 281 fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input)); 282 } 283 284 if (fun_str->length() > 128) { 285 IncrementalStringBuilder builder(isolate); 286 builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111)); 287 builder.AppendCString("...<omitted>..."); 288 builder.AppendString(isolate->factory()->NewSubString( 289 fun_str, fun_str->length() - 2, fun_str->length())); 290 291 return builder.Finish().ToHandleChecked(); 292 } 293 return fun_str; 294 } else if (input->IsSymbol()) { 295 // -- S y m b o l 296 Handle<Symbol> symbol = Handle<Symbol>::cast(input); 297 298 IncrementalStringBuilder builder(isolate); 299 builder.AppendCString("Symbol("); 300 if (symbol->name()->IsString()) { 301 builder.AppendString(handle(String::cast(symbol->name()), isolate)); 302 } 303 builder.AppendCharacter(')'); 304 305 return builder.Finish().ToHandleChecked(); 306 } else if (input->IsJSReceiver()) { 307 // -- J S R e c e i v e r 308 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); 309 Handle<Object> to_string = JSReceiver::GetDataProperty( 310 receiver, isolate->factory()->toString_string()); 311 312 if (IsErrorObject(isolate, input) || 313 *to_string == *isolate->error_to_string()) { 314 // When internally formatting error objects, use a side-effects-free 315 // version of Error.prototype.toString independent of the actually 316 // installed toString method. 317 return NoSideEffectsErrorToString(isolate, input); 318 } else if (*to_string == *isolate->object_to_string()) { 319 Handle<Object> ctor = JSReceiver::GetDataProperty( 320 receiver, isolate->factory()->constructor_string()); 321 if (ctor->IsFunction()) { 322 Handle<String> ctor_name; 323 if (ctor->IsJSBoundFunction()) { 324 ctor_name = JSBoundFunction::GetName( 325 isolate, Handle<JSBoundFunction>::cast(ctor)) 326 .ToHandleChecked(); 327 } else if (ctor->IsJSFunction()) { 328 Handle<Object> ctor_name_obj = 329 JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor)); 330 ctor_name = AsStringOrEmpty(isolate, ctor_name_obj); 331 } 332 333 if (ctor_name->length() != 0) { 334 IncrementalStringBuilder builder(isolate); 335 builder.AppendCString("#<"); 336 builder.AppendString(ctor_name); 337 builder.AppendCString(">"); 338 339 return builder.Finish().ToHandleChecked(); 340 } 341 } 342 } 343 } 344 345 // At this point, input is either none of the above or a JSReceiver. 346 347 Handle<JSReceiver> receiver; 348 if (input->IsJSReceiver()) { 349 receiver = Handle<JSReceiver>::cast(input); 350 } else { 351 // This is the only case where Object::ToObject throws. 352 DCHECK(!input->IsSmi()); 353 int constructor_function_index = 354 Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex(); 355 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 356 return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]"); 357 } 358 359 receiver = Object::ToObject(isolate, input, isolate->native_context()) 360 .ToHandleChecked(); 361 } 362 363 Handle<String> builtin_tag = handle(receiver->class_name(), isolate); 364 Handle<Object> tag_obj = JSReceiver::GetDataProperty( 365 receiver, isolate->factory()->to_string_tag_symbol()); 366 Handle<String> tag = 367 tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag; 368 369 IncrementalStringBuilder builder(isolate); 370 builder.AppendCString("[object "); 371 builder.AppendString(tag); 372 builder.AppendCString("]"); 373 374 return builder.Finish().ToHandleChecked(); 375 } 376 377 // static 378 MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) { 379 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 380 double len = DoubleToInteger(input->Number()); 381 if (len <= 0.0) { 382 len = 0.0; 383 } else if (len >= kMaxSafeInteger) { 384 len = kMaxSafeInteger; 385 } 386 return isolate->factory()->NewNumber(len); 387 } 388 389 // static 390 MaybeHandle<Object> Object::ToIndex(Isolate* isolate, Handle<Object> input, 391 MessageTemplate::Template error_index) { 392 if (input->IsUndefined(isolate)) return isolate->factory()->NewNumber(0.0); 393 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 394 double len = DoubleToInteger(input->Number()) + 0.0; 395 auto js_len = isolate->factory()->NewNumber(len); 396 if (len < 0.0 || len > kMaxSafeInteger) { 397 THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object); 398 } 399 return js_len; 400 } 401 402 bool Object::BooleanValue() { 403 if (IsSmi()) return Smi::cast(this)->value() != 0; 404 DCHECK(IsHeapObject()); 405 Isolate* isolate = HeapObject::cast(this)->GetIsolate(); 406 if (IsBoolean()) return IsTrue(isolate); 407 if (IsUndefined(isolate) || IsNull(isolate)) return false; 408 if (IsUndetectable()) return false; // Undetectable object is false. 409 if (IsString()) return String::cast(this)->length() != 0; 410 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue(); 411 return true; 412 } 413 414 415 namespace { 416 417 // TODO(bmeurer): Maybe we should introduce a marker interface Number, 418 // where we put all these methods at some point? 419 ComparisonResult NumberCompare(double x, double y) { 420 if (std::isnan(x) || std::isnan(y)) { 421 return ComparisonResult::kUndefined; 422 } else if (x < y) { 423 return ComparisonResult::kLessThan; 424 } else if (x > y) { 425 return ComparisonResult::kGreaterThan; 426 } else { 427 return ComparisonResult::kEqual; 428 } 429 } 430 431 432 bool NumberEquals(double x, double y) { 433 // Must check explicitly for NaN's on Windows, but -0 works fine. 434 if (std::isnan(x)) return false; 435 if (std::isnan(y)) return false; 436 return x == y; 437 } 438 439 440 bool NumberEquals(const Object* x, const Object* y) { 441 return NumberEquals(x->Number(), y->Number()); 442 } 443 444 445 bool NumberEquals(Handle<Object> x, Handle<Object> y) { 446 return NumberEquals(*x, *y); 447 } 448 449 } // namespace 450 451 452 // static 453 Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) { 454 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4. 455 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) || 456 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) { 457 return Nothing<ComparisonResult>(); 458 } 459 if (x->IsString() && y->IsString()) { 460 // ES6 section 7.2.11 Abstract Relational Comparison step 5. 461 return Just( 462 String::Compare(Handle<String>::cast(x), Handle<String>::cast(y))); 463 } 464 // ES6 section 7.2.11 Abstract Relational Comparison step 6. 465 if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) { 466 return Nothing<ComparisonResult>(); 467 } 468 return Just(NumberCompare(x->Number(), y->Number())); 469 } 470 471 472 // static 473 Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) { 474 // This is the generic version of Abstract Equality Comparison; a version in 475 // JavaScript land is available in the EqualStub and NotEqualStub. Whenever 476 // you change something functionality wise in here, remember to update the 477 // TurboFan code stubs as well. 478 while (true) { 479 if (x->IsNumber()) { 480 if (y->IsNumber()) { 481 return Just(NumberEquals(x, y)); 482 } else if (y->IsBoolean()) { 483 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 484 } else if (y->IsString()) { 485 return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y)))); 486 } else if (y->IsJSReceiver()) { 487 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 488 .ToHandle(&y)) { 489 return Nothing<bool>(); 490 } 491 } else { 492 return Just(false); 493 } 494 } else if (x->IsString()) { 495 if (y->IsString()) { 496 return Just( 497 String::Equals(Handle<String>::cast(x), Handle<String>::cast(y))); 498 } else if (y->IsNumber()) { 499 x = String::ToNumber(Handle<String>::cast(x)); 500 return Just(NumberEquals(x, y)); 501 } else if (y->IsBoolean()) { 502 x = String::ToNumber(Handle<String>::cast(x)); 503 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 504 } else if (y->IsJSReceiver()) { 505 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 506 .ToHandle(&y)) { 507 return Nothing<bool>(); 508 } 509 } else { 510 return Just(false); 511 } 512 } else if (x->IsBoolean()) { 513 if (y->IsOddball()) { 514 return Just(x.is_identical_to(y)); 515 } else if (y->IsNumber()) { 516 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 517 } else if (y->IsString()) { 518 y = String::ToNumber(Handle<String>::cast(y)); 519 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 520 } else if (y->IsJSReceiver()) { 521 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 522 .ToHandle(&y)) { 523 return Nothing<bool>(); 524 } 525 x = Oddball::ToNumber(Handle<Oddball>::cast(x)); 526 } else { 527 return Just(false); 528 } 529 } else if (x->IsSymbol()) { 530 if (y->IsSymbol()) { 531 return Just(x.is_identical_to(y)); 532 } else if (y->IsJSReceiver()) { 533 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 534 .ToHandle(&y)) { 535 return Nothing<bool>(); 536 } 537 } else { 538 return Just(false); 539 } 540 } else if (x->IsSimd128Value()) { 541 if (y->IsSimd128Value()) { 542 return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x), 543 Handle<Simd128Value>::cast(y))); 544 } else if (y->IsJSReceiver()) { 545 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 546 .ToHandle(&y)) { 547 return Nothing<bool>(); 548 } 549 } else { 550 return Just(false); 551 } 552 } else if (x->IsJSReceiver()) { 553 if (y->IsJSReceiver()) { 554 return Just(x.is_identical_to(y)); 555 } else if (y->IsUndetectable()) { 556 return Just(x->IsUndetectable()); 557 } else if (y->IsBoolean()) { 558 y = Oddball::ToNumber(Handle<Oddball>::cast(y)); 559 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x)) 560 .ToHandle(&x)) { 561 return Nothing<bool>(); 562 } 563 } else { 564 return Just(x->IsUndetectable() && y->IsUndetectable()); 565 } 566 } 567 } 568 569 570 bool Object::StrictEquals(Object* that) { 571 if (this->IsNumber()) { 572 if (!that->IsNumber()) return false; 573 return NumberEquals(this, that); 574 } else if (this->IsString()) { 575 if (!that->IsString()) return false; 576 return String::cast(this)->Equals(String::cast(that)); 577 } else if (this->IsSimd128Value()) { 578 if (!that->IsSimd128Value()) return false; 579 return Simd128Value::cast(this)->Equals(Simd128Value::cast(that)); 580 } 581 return this == that; 582 } 583 584 585 // static 586 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) { 587 if (object->IsNumber()) return isolate->factory()->number_string(); 588 if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of()); 589 if (object->IsUndetectable()) { 590 return isolate->factory()->undefined_string(); 591 } 592 if (object->IsString()) return isolate->factory()->string_string(); 593 if (object->IsSymbol()) return isolate->factory()->symbol_string(); 594 if (object->IsString()) return isolate->factory()->string_string(); 595 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 596 if (object->Is##Type()) return isolate->factory()->type##_string(); 597 SIMD128_TYPES(SIMD128_TYPE) 598 #undef SIMD128_TYPE 599 if (object->IsCallable()) return isolate->factory()->function_string(); 600 return isolate->factory()->object_string(); 601 } 602 603 604 // static 605 MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs, 606 Handle<Object> rhs) { 607 if (!lhs->IsNumber() || !rhs->IsNumber()) { 608 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 609 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 610 } 611 return isolate->factory()->NewNumber(lhs->Number() * rhs->Number()); 612 } 613 614 615 // static 616 MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs, 617 Handle<Object> rhs) { 618 if (!lhs->IsNumber() || !rhs->IsNumber()) { 619 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 620 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 621 } 622 return isolate->factory()->NewNumber(lhs->Number() / rhs->Number()); 623 } 624 625 626 // static 627 MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs, 628 Handle<Object> rhs) { 629 if (!lhs->IsNumber() || !rhs->IsNumber()) { 630 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 631 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 632 } 633 return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number())); 634 } 635 636 637 // static 638 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs, 639 Handle<Object> rhs) { 640 if (lhs->IsNumber() && rhs->IsNumber()) { 641 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 642 } else if (lhs->IsString() && rhs->IsString()) { 643 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 644 Handle<String>::cast(rhs)); 645 } 646 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object); 647 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object); 648 if (lhs->IsString() || rhs->IsString()) { 649 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs), 650 Object); 651 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs), 652 Object); 653 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 654 Handle<String>::cast(rhs)); 655 } 656 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 657 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 658 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 659 } 660 661 662 // static 663 MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs, 664 Handle<Object> rhs) { 665 if (!lhs->IsNumber() || !rhs->IsNumber()) { 666 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 667 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 668 } 669 return isolate->factory()->NewNumber(lhs->Number() - rhs->Number()); 670 } 671 672 673 // static 674 MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs, 675 Handle<Object> rhs) { 676 if (!lhs->IsNumber() || !rhs->IsNumber()) { 677 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 678 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 679 } 680 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) 681 << (NumberToUint32(*rhs) & 0x1F)); 682 } 683 684 685 // static 686 MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs, 687 Handle<Object> rhs) { 688 if (!lhs->IsNumber() || !rhs->IsNumber()) { 689 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 690 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 691 } 692 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >> 693 (NumberToUint32(*rhs) & 0x1F)); 694 } 695 696 697 // static 698 MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate, 699 Handle<Object> lhs, 700 Handle<Object> rhs) { 701 if (!lhs->IsNumber() || !rhs->IsNumber()) { 702 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 703 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 704 } 705 return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >> 706 (NumberToUint32(*rhs) & 0x1F)); 707 } 708 709 710 // static 711 MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs, 712 Handle<Object> rhs) { 713 if (!lhs->IsNumber() || !rhs->IsNumber()) { 714 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 715 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 716 } 717 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) & 718 NumberToInt32(*rhs)); 719 } 720 721 722 // static 723 MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs, 724 Handle<Object> rhs) { 725 if (!lhs->IsNumber() || !rhs->IsNumber()) { 726 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 727 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 728 } 729 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) | 730 NumberToInt32(*rhs)); 731 } 732 733 734 // static 735 MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs, 736 Handle<Object> rhs) { 737 if (!lhs->IsNumber() || !rhs->IsNumber()) { 738 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 739 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 740 } 741 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^ 742 NumberToInt32(*rhs)); 743 } 744 745 // static 746 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate, 747 Handle<Object> callable, 748 Handle<Object> object) { 749 // The {callable} must have a [[Call]] internal method. 750 if (!callable->IsCallable()) return isolate->factory()->false_value(); 751 752 // Check if {callable} is a bound function, and if so retrieve its 753 // [[BoundTargetFunction]] and use that instead of {callable}. 754 if (callable->IsJSBoundFunction()) { 755 Handle<Object> bound_callable( 756 Handle<JSBoundFunction>::cast(callable)->bound_target_function(), 757 isolate); 758 return Object::InstanceOf(isolate, object, bound_callable); 759 } 760 761 // If {object} is not a receiver, return false. 762 if (!object->IsJSReceiver()) return isolate->factory()->false_value(); 763 764 // Get the "prototype" of {callable}; raise an error if it's not a receiver. 765 Handle<Object> prototype; 766 ASSIGN_RETURN_ON_EXCEPTION( 767 isolate, prototype, 768 Object::GetProperty(callable, isolate->factory()->prototype_string()), 769 Object); 770 if (!prototype->IsJSReceiver()) { 771 THROW_NEW_ERROR( 772 isolate, 773 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype), 774 Object); 775 } 776 777 // Return whether or not {prototype} is in the prototype chain of {object}. 778 Maybe<bool> result = JSReceiver::HasInPrototypeChain( 779 isolate, Handle<JSReceiver>::cast(object), prototype); 780 if (result.IsNothing()) return MaybeHandle<Object>(); 781 return isolate->factory()->ToBoolean(result.FromJust()); 782 } 783 784 // static 785 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object, 786 Handle<Object> callable) { 787 // The {callable} must be a receiver. 788 if (!callable->IsJSReceiver()) { 789 THROW_NEW_ERROR(isolate, 790 NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck), 791 Object); 792 } 793 794 // Lookup the @@hasInstance method on {callable}. 795 Handle<Object> inst_of_handler; 796 ASSIGN_RETURN_ON_EXCEPTION( 797 isolate, inst_of_handler, 798 JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable), 799 isolate->factory()->has_instance_symbol()), 800 Object); 801 if (!inst_of_handler->IsUndefined(isolate)) { 802 // Call the {inst_of_handler} on the {callable}. 803 Handle<Object> result; 804 ASSIGN_RETURN_ON_EXCEPTION( 805 isolate, result, 806 Execution::Call(isolate, inst_of_handler, callable, 1, &object), 807 Object); 808 return isolate->factory()->ToBoolean(result->BooleanValue()); 809 } 810 811 // The {callable} must have a [[Call]] internal method. 812 if (!callable->IsCallable()) { 813 THROW_NEW_ERROR( 814 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck), 815 Object); 816 } 817 818 // Fall back to OrdinaryHasInstance with {callable} and {object}. 819 Handle<Object> result; 820 ASSIGN_RETURN_ON_EXCEPTION( 821 isolate, result, 822 JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object); 823 return result; 824 } 825 826 Maybe<bool> Object::IsArray(Handle<Object> object) { 827 if (object->IsJSArray()) return Just(true); 828 if (object->IsJSProxy()) { 829 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object); 830 Isolate* isolate = proxy->GetIsolate(); 831 if (proxy->IsRevoked()) { 832 isolate->Throw(*isolate->factory()->NewTypeError( 833 MessageTemplate::kProxyRevoked, 834 isolate->factory()->NewStringFromAsciiChecked("IsArray"))); 835 return Nothing<bool>(); 836 } 837 return Object::IsArray(handle(proxy->target(), isolate)); 838 } 839 return Just(false); 840 } 841 842 843 // static 844 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver, 845 Handle<Name> name) { 846 Handle<Object> func; 847 Isolate* isolate = receiver->GetIsolate(); 848 ASSIGN_RETURN_ON_EXCEPTION(isolate, func, 849 JSReceiver::GetProperty(receiver, name), Object); 850 if (func->IsNull(isolate) || func->IsUndefined(isolate)) { 851 return isolate->factory()->undefined_value(); 852 } 853 if (!func->IsCallable()) { 854 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction, 855 func, name, receiver), 856 Object); 857 } 858 return func; 859 } 860 861 862 // static 863 MaybeHandle<FixedArray> Object::CreateListFromArrayLike( 864 Isolate* isolate, Handle<Object> object, ElementTypes element_types) { 865 // 1. ReturnIfAbrupt(object). 866 // 2. (default elementTypes -- not applicable.) 867 // 3. If Type(obj) is not Object, throw a TypeError exception. 868 if (!object->IsJSReceiver()) { 869 THROW_NEW_ERROR(isolate, 870 NewTypeError(MessageTemplate::kCalledOnNonObject, 871 isolate->factory()->NewStringFromAsciiChecked( 872 "CreateListFromArrayLike")), 873 FixedArray); 874 } 875 // 4. Let len be ? ToLength(? Get(obj, "length")). 876 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); 877 Handle<Object> raw_length_number; 878 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number, 879 Object::GetLengthFromArrayLike(isolate, receiver), 880 FixedArray); 881 uint32_t len; 882 if (!raw_length_number->ToUint32(&len) || 883 len > static_cast<uint32_t>(FixedArray::kMaxLength)) { 884 THROW_NEW_ERROR(isolate, 885 NewRangeError(MessageTemplate::kInvalidArrayLength), 886 FixedArray); 887 } 888 // 5. Let list be an empty List. 889 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len); 890 // 6. Let index be 0. 891 // 7. Repeat while index < len: 892 for (uint32_t index = 0; index < len; ++index) { 893 // 7a. Let indexName be ToString(index). 894 // 7b. Let next be ? Get(obj, indexName). 895 Handle<Object> next; 896 ASSIGN_RETURN_ON_EXCEPTION(isolate, next, 897 JSReceiver::GetElement(isolate, receiver, index), 898 FixedArray); 899 switch (element_types) { 900 case ElementTypes::kAll: 901 // Nothing to do. 902 break; 903 case ElementTypes::kStringAndSymbol: { 904 // 7c. If Type(next) is not an element of elementTypes, throw a 905 // TypeError exception. 906 if (!next->IsName()) { 907 THROW_NEW_ERROR(isolate, 908 NewTypeError(MessageTemplate::kNotPropertyName, next), 909 FixedArray); 910 } 911 // 7d. Append next as the last element of list. 912 // Internalize on the fly so we can use pointer identity later. 913 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next)); 914 break; 915 } 916 } 917 list->set(index, *next); 918 // 7e. Set index to index + 1. (See loop header.) 919 } 920 // 8. Return list. 921 return list; 922 } 923 924 925 // static 926 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate, 927 Handle<Object> object) { 928 Handle<Object> val; 929 Handle<Object> key = isolate->factory()->length_string(); 930 ASSIGN_RETURN_ON_EXCEPTION( 931 isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object); 932 return Object::ToLength(isolate, val); 933 } 934 935 // static 936 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) { 937 for (; it->IsFound(); it->Next()) { 938 switch (it->state()) { 939 case LookupIterator::NOT_FOUND: 940 case LookupIterator::TRANSITION: 941 UNREACHABLE(); 942 case LookupIterator::JSPROXY: 943 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(), 944 it->GetName()); 945 case LookupIterator::INTERCEPTOR: { 946 Maybe<PropertyAttributes> result = 947 JSObject::GetPropertyAttributesWithInterceptor(it); 948 if (result.IsNothing()) return Nothing<bool>(); 949 if (result.FromJust() != ABSENT) return Just(true); 950 break; 951 } 952 case LookupIterator::ACCESS_CHECK: { 953 if (it->HasAccess()) break; 954 Maybe<PropertyAttributes> result = 955 JSObject::GetPropertyAttributesWithFailedAccessCheck(it); 956 if (result.IsNothing()) return Nothing<bool>(); 957 return Just(result.FromJust() != ABSENT); 958 } 959 case LookupIterator::INTEGER_INDEXED_EXOTIC: 960 // TypedArray out-of-bounds access. 961 return Just(false); 962 case LookupIterator::ACCESSOR: 963 case LookupIterator::DATA: 964 return Just(true); 965 } 966 } 967 return Just(false); 968 } 969 970 971 // static 972 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) { 973 for (; it->IsFound(); it->Next()) { 974 switch (it->state()) { 975 case LookupIterator::NOT_FOUND: 976 case LookupIterator::TRANSITION: 977 UNREACHABLE(); 978 case LookupIterator::JSPROXY: { 979 bool was_found; 980 MaybeHandle<Object> result = 981 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(), 982 it->GetName(), it->GetReceiver(), &was_found); 983 if (!was_found) it->NotFound(); 984 return result; 985 } 986 case LookupIterator::INTERCEPTOR: { 987 bool done; 988 Handle<Object> result; 989 ASSIGN_RETURN_ON_EXCEPTION( 990 it->isolate(), result, 991 JSObject::GetPropertyWithInterceptor(it, &done), Object); 992 if (done) return result; 993 break; 994 } 995 case LookupIterator::ACCESS_CHECK: 996 if (it->HasAccess()) break; 997 return JSObject::GetPropertyWithFailedAccessCheck(it); 998 case LookupIterator::ACCESSOR: 999 return GetPropertyWithAccessor(it); 1000 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1001 return it->isolate()->factory()->undefined_value(); 1002 case LookupIterator::DATA: 1003 return it->GetDataValue(); 1004 } 1005 } 1006 return it->isolate()->factory()->undefined_value(); 1007 } 1008 1009 1010 // static 1011 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate, 1012 Handle<JSProxy> proxy, 1013 Handle<Name> name, 1014 Handle<Object> receiver, 1015 bool* was_found) { 1016 *was_found = true; 1017 if (receiver->IsJSGlobalObject()) { 1018 THROW_NEW_ERROR( 1019 isolate, 1020 NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name), 1021 Object); 1022 } 1023 1024 DCHECK(!name->IsPrivate()); 1025 STACK_CHECK(isolate, MaybeHandle<Object>()); 1026 Handle<Name> trap_name = isolate->factory()->get_string(); 1027 // 1. Assert: IsPropertyKey(P) is true. 1028 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 1029 Handle<Object> handler(proxy->handler(), isolate); 1030 // 3. If handler is null, throw a TypeError exception. 1031 // 4. Assert: Type(handler) is Object. 1032 if (proxy->IsRevoked()) { 1033 THROW_NEW_ERROR(isolate, 1034 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1035 Object); 1036 } 1037 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 1038 Handle<JSReceiver> target(proxy->target(), isolate); 1039 // 6. Let trap be ? GetMethod(handler, "get"). 1040 Handle<Object> trap; 1041 ASSIGN_RETURN_ON_EXCEPTION( 1042 isolate, trap, 1043 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object); 1044 // 7. If trap is undefined, then 1045 if (trap->IsUndefined(isolate)) { 1046 // 7.a Return target.[[Get]](P, Receiver). 1047 LookupIterator it = 1048 LookupIterator::PropertyOrElement(isolate, receiver, name, target); 1049 MaybeHandle<Object> result = Object::GetProperty(&it); 1050 *was_found = it.IsFound(); 1051 return result; 1052 } 1053 // 8. Let trapResult be ? Call(trap, handler, target, P, Receiver). 1054 Handle<Object> trap_result; 1055 Handle<Object> args[] = {target, name, receiver}; 1056 ASSIGN_RETURN_ON_EXCEPTION( 1057 isolate, trap_result, 1058 Execution::Call(isolate, trap, handler, arraysize(args), args), Object); 1059 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). 1060 PropertyDescriptor target_desc; 1061 Maybe<bool> target_found = 1062 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 1063 MAYBE_RETURN_NULL(target_found); 1064 // 10. If targetDesc is not undefined, then 1065 if (target_found.FromJust()) { 1066 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is 1067 // false and targetDesc.[[Writable]] is false, then 1068 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false, 1069 // throw a TypeError exception. 1070 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && 1071 !target_desc.configurable() && 1072 !target_desc.writable() && 1073 !trap_result->SameValue(*target_desc.value()); 1074 if (inconsistent) { 1075 THROW_NEW_ERROR( 1076 isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, 1077 name, target_desc.value(), trap_result), 1078 Object); 1079 } 1080 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] 1081 // is false and targetDesc.[[Get]] is undefined, then 1082 // 10.b.i. If trapResult is not undefined, throw a TypeError exception. 1083 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 1084 !target_desc.configurable() && 1085 target_desc.get()->IsUndefined(isolate) && 1086 !trap_result->IsUndefined(isolate); 1087 if (inconsistent) { 1088 THROW_NEW_ERROR( 1089 isolate, 1090 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name, 1091 trap_result), 1092 Object); 1093 } 1094 } 1095 // 11. Return trap_result 1096 return trap_result; 1097 } 1098 1099 1100 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) { 1101 for (; it->IsFound(); it->Next()) { 1102 switch (it->state()) { 1103 case LookupIterator::INTERCEPTOR: 1104 case LookupIterator::NOT_FOUND: 1105 case LookupIterator::TRANSITION: 1106 UNREACHABLE(); 1107 case LookupIterator::ACCESS_CHECK: 1108 // Support calling this method without an active context, but refuse 1109 // access to access-checked objects in that case. 1110 if (it->isolate()->context() != nullptr && it->HasAccess()) continue; 1111 // Fall through. 1112 case LookupIterator::JSPROXY: 1113 it->NotFound(); 1114 return it->isolate()->factory()->undefined_value(); 1115 case LookupIterator::ACCESSOR: 1116 // TODO(verwaest): For now this doesn't call into AccessorInfo, since 1117 // clients don't need it. Update once relevant. 1118 it->NotFound(); 1119 return it->isolate()->factory()->undefined_value(); 1120 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1121 return it->isolate()->factory()->undefined_value(); 1122 case LookupIterator::DATA: 1123 return it->GetDataValue(); 1124 } 1125 } 1126 return it->isolate()->factory()->undefined_value(); 1127 } 1128 1129 1130 bool Object::ToInt32(int32_t* value) { 1131 if (IsSmi()) { 1132 *value = Smi::cast(this)->value(); 1133 return true; 1134 } 1135 if (IsHeapNumber()) { 1136 double num = HeapNumber::cast(this)->value(); 1137 if (FastI2D(FastD2I(num)) == num) { 1138 *value = FastD2I(num); 1139 return true; 1140 } 1141 } 1142 return false; 1143 } 1144 1145 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( 1146 Isolate* isolate, Handle<FunctionTemplateInfo> info) { 1147 Object* current_info = info->shared_function_info(); 1148 if (current_info->IsSharedFunctionInfo()) { 1149 return handle(SharedFunctionInfo::cast(current_info), isolate); 1150 } 1151 1152 Handle<Object> class_name(info->class_name(), isolate); 1153 Handle<String> name = class_name->IsString() 1154 ? Handle<String>::cast(class_name) 1155 : isolate->factory()->empty_string(); 1156 Handle<Code> code; 1157 if (info->call_code()->IsCallHandlerInfo() && 1158 CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) { 1159 code = isolate->builtins()->HandleFastApiCall(); 1160 } else { 1161 code = isolate->builtins()->HandleApiCall(); 1162 } 1163 bool is_constructor = !info->remove_prototype(); 1164 Handle<SharedFunctionInfo> result = 1165 isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor); 1166 if (is_constructor) { 1167 result->SetConstructStub(*isolate->builtins()->JSConstructStubApi()); 1168 } 1169 1170 result->set_length(info->length()); 1171 if (class_name->IsString()) result->set_instance_class_name(*class_name); 1172 result->set_api_func_data(*info); 1173 result->DontAdaptArguments(); 1174 DCHECK(result->IsApiFunction()); 1175 1176 info->set_shared_function_info(*result); 1177 return result; 1178 } 1179 1180 bool FunctionTemplateInfo::IsTemplateFor(Map* map) { 1181 // There is a constraint on the object; check. 1182 if (!map->IsJSObjectMap()) return false; 1183 // Fetch the constructor function of the object. 1184 Object* cons_obj = map->GetConstructor(); 1185 if (!cons_obj->IsJSFunction()) return false; 1186 JSFunction* fun = JSFunction::cast(cons_obj); 1187 // Iterate through the chain of inheriting function templates to 1188 // see if the required one occurs. 1189 for (Object* type = fun->shared()->function_data(); 1190 type->IsFunctionTemplateInfo(); 1191 type = FunctionTemplateInfo::cast(type)->parent_template()) { 1192 if (type == this) return true; 1193 } 1194 // Didn't find the required type in the inheritance chain. 1195 return false; 1196 } 1197 1198 1199 // static 1200 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) { 1201 Handle<FixedArray> list = 1202 isolate->factory()->NewFixedArray(kLengthIndex + size); 1203 list->set(kLengthIndex, Smi::kZero); 1204 return Handle<TemplateList>::cast(list); 1205 } 1206 1207 // static 1208 Handle<TemplateList> TemplateList::Add(Isolate* isolate, 1209 Handle<TemplateList> list, 1210 Handle<i::Object> value) { 1211 STATIC_ASSERT(kFirstElementIndex == 1); 1212 int index = list->length() + 1; 1213 Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list); 1214 fixed_array = FixedArray::SetAndGrow(fixed_array, index, value); 1215 fixed_array->set(kLengthIndex, Smi::FromInt(index)); 1216 return Handle<TemplateList>::cast(fixed_array); 1217 } 1218 1219 // static 1220 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor, 1221 Handle<JSReceiver> new_target, 1222 Handle<AllocationSite> site) { 1223 // If called through new, new.target can be: 1224 // - a subclass of constructor, 1225 // - a proxy wrapper around constructor, or 1226 // - the constructor itself. 1227 // If called through Reflect.construct, it's guaranteed to be a constructor. 1228 Isolate* const isolate = constructor->GetIsolate(); 1229 DCHECK(constructor->IsConstructor()); 1230 DCHECK(new_target->IsConstructor()); 1231 DCHECK(!constructor->has_initial_map() || 1232 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE); 1233 1234 Handle<Map> initial_map; 1235 ASSIGN_RETURN_ON_EXCEPTION( 1236 isolate, initial_map, 1237 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject); 1238 Handle<JSObject> result = 1239 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site); 1240 isolate->counters()->constructed_objects()->Increment(); 1241 isolate->counters()->constructed_objects_runtime()->Increment(); 1242 return result; 1243 } 1244 1245 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) { 1246 DCHECK(object->HasFastSmiOrObjectElements() || 1247 object->HasFastStringWrapperElements()); 1248 FixedArray* raw_elems = FixedArray::cast(object->elements()); 1249 Heap* heap = object->GetHeap(); 1250 if (raw_elems->map() != heap->fixed_cow_array_map()) return; 1251 Isolate* isolate = heap->isolate(); 1252 Handle<FixedArray> elems(raw_elems, isolate); 1253 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap( 1254 elems, isolate->factory()->fixed_array_map()); 1255 object->set_elements(*writable_elems); 1256 isolate->counters()->cow_arrays_converted()->Increment(); 1257 } 1258 1259 1260 // ES6 9.5.1 1261 // static 1262 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) { 1263 Isolate* isolate = proxy->GetIsolate(); 1264 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string(); 1265 1266 STACK_CHECK(isolate, MaybeHandle<Object>()); 1267 1268 // 1. Let handler be the value of the [[ProxyHandler]] internal slot. 1269 // 2. If handler is null, throw a TypeError exception. 1270 // 3. Assert: Type(handler) is Object. 1271 // 4. Let target be the value of the [[ProxyTarget]] internal slot. 1272 if (proxy->IsRevoked()) { 1273 THROW_NEW_ERROR(isolate, 1274 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1275 Object); 1276 } 1277 Handle<JSReceiver> target(proxy->target(), isolate); 1278 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 1279 1280 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). 1281 Handle<Object> trap; 1282 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name), 1283 Object); 1284 // 6. If trap is undefined, then return target.[[GetPrototypeOf]](). 1285 if (trap->IsUndefined(isolate)) { 1286 return JSReceiver::GetPrototype(isolate, target); 1287 } 1288 // 7. Let handlerProto be ? Call(trap, handler, target). 1289 Handle<Object> argv[] = {target}; 1290 Handle<Object> handler_proto; 1291 ASSIGN_RETURN_ON_EXCEPTION( 1292 isolate, handler_proto, 1293 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object); 1294 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError. 1295 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) { 1296 THROW_NEW_ERROR(isolate, 1297 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid), 1298 Object); 1299 } 1300 // 9. Let extensibleTarget be ? IsExtensible(target). 1301 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 1302 MAYBE_RETURN_NULL(is_extensible); 1303 // 10. If extensibleTarget is true, return handlerProto. 1304 if (is_extensible.FromJust()) return handler_proto; 1305 // 11. Let targetProto be ? target.[[GetPrototypeOf]](). 1306 Handle<Object> target_proto; 1307 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto, 1308 JSReceiver::GetPrototype(isolate, target), Object); 1309 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError. 1310 if (!handler_proto->SameValue(*target_proto)) { 1311 THROW_NEW_ERROR( 1312 isolate, 1313 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible), 1314 Object); 1315 } 1316 // 13. Return handlerProto. 1317 return handler_proto; 1318 } 1319 1320 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) { 1321 Isolate* isolate = it->isolate(); 1322 Handle<Object> structure = it->GetAccessors(); 1323 Handle<Object> receiver = it->GetReceiver(); 1324 1325 // We should never get here to initialize a const with the hole value since a 1326 // const declaration would conflict with the getter. 1327 DCHECK(!structure->IsForeign()); 1328 1329 // API style callbacks. 1330 if (structure->IsAccessorInfo()) { 1331 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1332 Handle<Name> name = it->GetName(); 1333 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1334 if (!info->IsCompatibleReceiver(*receiver)) { 1335 THROW_NEW_ERROR(isolate, 1336 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, 1337 name, receiver), 1338 Object); 1339 } 1340 1341 v8::AccessorNameGetterCallback call_fun = 1342 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter()); 1343 if (call_fun == nullptr) return isolate->factory()->undefined_value(); 1344 1345 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1346 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver, 1347 Object::ConvertReceiver(isolate, receiver), 1348 Object); 1349 } 1350 1351 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1352 Object::DONT_THROW); 1353 Handle<Object> result = args.Call(call_fun, name); 1354 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1355 if (result.is_null()) return isolate->factory()->undefined_value(); 1356 Handle<Object> reboxed_result = handle(*result, isolate); 1357 if (info->replace_on_access() && receiver->IsJSReceiver()) { 1358 args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>( 1359 &Accessors::ReconfigureToDataProperty), 1360 name, result); 1361 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1362 } 1363 return reboxed_result; 1364 } 1365 1366 // AccessorPair with 'cached' private property. 1367 if (it->TryLookupCachedProperty()) { 1368 return Object::GetProperty(it); 1369 } 1370 1371 // Regular accessor. 1372 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate); 1373 if (getter->IsFunctionTemplateInfo()) { 1374 return Builtins::InvokeApiFunction( 1375 isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, 1376 nullptr, isolate->factory()->undefined_value()); 1377 } else if (getter->IsCallable()) { 1378 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1379 return Object::GetPropertyWithDefinedGetter( 1380 receiver, Handle<JSReceiver>::cast(getter)); 1381 } 1382 // Getter is not a function. 1383 return isolate->factory()->undefined_value(); 1384 } 1385 1386 // static 1387 Address AccessorInfo::redirect(Isolate* isolate, Address address, 1388 AccessorComponent component) { 1389 ApiFunction fun(address); 1390 DCHECK_EQ(ACCESSOR_GETTER, component); 1391 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; 1392 return ExternalReference(&fun, type, isolate).address(); 1393 } 1394 1395 Address AccessorInfo::redirected_getter() const { 1396 Address accessor = v8::ToCData<Address>(getter()); 1397 if (accessor == nullptr) return nullptr; 1398 return redirect(GetIsolate(), accessor, ACCESSOR_GETTER); 1399 } 1400 1401 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate, 1402 Handle<AccessorInfo> info, 1403 Handle<Map> map) { 1404 if (!info->HasExpectedReceiverType()) return true; 1405 if (!map->IsJSObjectMap()) return false; 1406 return FunctionTemplateInfo::cast(info->expected_receiver_type()) 1407 ->IsTemplateFor(*map); 1408 } 1409 1410 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it, 1411 Handle<Object> value, 1412 ShouldThrow should_throw) { 1413 Isolate* isolate = it->isolate(); 1414 Handle<Object> structure = it->GetAccessors(); 1415 Handle<Object> receiver = it->GetReceiver(); 1416 1417 // We should never get here to initialize a const with the hole value since a 1418 // const declaration would conflict with the setter. 1419 DCHECK(!structure->IsForeign()); 1420 1421 // API style callbacks. 1422 if (structure->IsAccessorInfo()) { 1423 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1424 Handle<Name> name = it->GetName(); 1425 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1426 if (!info->IsCompatibleReceiver(*receiver)) { 1427 isolate->Throw(*isolate->factory()->NewTypeError( 1428 MessageTemplate::kIncompatibleMethodReceiver, name, receiver)); 1429 return Nothing<bool>(); 1430 } 1431 1432 // The actual type of call_fun is either v8::AccessorNameSetterCallback or 1433 // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the 1434 // AccessorInfo was created by the API or internally (see accessors.cc). 1435 // Here we handle both cases using GenericNamedPropertySetterCallback and 1436 // its Call method. 1437 GenericNamedPropertySetterCallback call_fun = 1438 v8::ToCData<GenericNamedPropertySetterCallback>(info->setter()); 1439 1440 if (call_fun == nullptr) { 1441 // TODO(verwaest): We should not get here anymore once all AccessorInfos 1442 // are marked as special_data_property. They cannot both be writable and 1443 // not have a setter. 1444 return Just(true); 1445 } 1446 1447 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1448 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1449 isolate, receiver, Object::ConvertReceiver(isolate, receiver), 1450 Nothing<bool>()); 1451 } 1452 1453 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1454 should_throw); 1455 Handle<Object> result = args.Call(call_fun, name, value); 1456 // In the case of AccessorNameSetterCallback, we know that the result value 1457 // cannot have been set, so the result of Call will be null. In the case of 1458 // AccessorNameBooleanSetterCallback, the result will either be null 1459 // (signalling an exception) or a boolean Oddball. 1460 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1461 if (result.is_null()) return Just(true); 1462 DCHECK(result->BooleanValue() || should_throw == DONT_THROW); 1463 return Just(result->BooleanValue()); 1464 } 1465 1466 // Regular accessor. 1467 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); 1468 if (setter->IsFunctionTemplateInfo()) { 1469 Handle<Object> argv[] = {value}; 1470 RETURN_ON_EXCEPTION_VALUE( 1471 isolate, Builtins::InvokeApiFunction( 1472 isolate, false, Handle<FunctionTemplateInfo>::cast(setter), 1473 receiver, arraysize(argv), argv, 1474 isolate->factory()->undefined_value()), 1475 Nothing<bool>()); 1476 return Just(true); 1477 } else if (setter->IsCallable()) { 1478 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1479 return SetPropertyWithDefinedSetter( 1480 receiver, Handle<JSReceiver>::cast(setter), value, should_throw); 1481 } 1482 1483 RETURN_FAILURE(isolate, should_throw, 1484 NewTypeError(MessageTemplate::kNoSetterInCallback, 1485 it->GetName(), it->GetHolder<JSObject>())); 1486 } 1487 1488 1489 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter( 1490 Handle<Object> receiver, 1491 Handle<JSReceiver> getter) { 1492 Isolate* isolate = getter->GetIsolate(); 1493 1494 // Platforms with simulators like arm/arm64 expose a funny issue. If the 1495 // simulator has a separate JS stack pointer from the C++ stack pointer, it 1496 // can miss C++ stack overflows in the stack guard at the start of JavaScript 1497 // functions. It would be very expensive to check the C++ stack pointer at 1498 // that location. The best solution seems to be to break the impasse by 1499 // adding checks at possible recursion points. What's more, we don't put 1500 // this stack check behind the USE_SIMULATOR define in order to keep 1501 // behavior the same between hardware and simulators. 1502 StackLimitCheck check(isolate); 1503 if (check.JsHasOverflowed()) { 1504 isolate->StackOverflow(); 1505 return MaybeHandle<Object>(); 1506 } 1507 1508 return Execution::Call(isolate, getter, receiver, 0, NULL); 1509 } 1510 1511 1512 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver, 1513 Handle<JSReceiver> setter, 1514 Handle<Object> value, 1515 ShouldThrow should_throw) { 1516 Isolate* isolate = setter->GetIsolate(); 1517 1518 Handle<Object> argv[] = { value }; 1519 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver, 1520 arraysize(argv), argv), 1521 Nothing<bool>()); 1522 return Just(true); 1523 } 1524 1525 1526 // static 1527 bool JSObject::AllCanRead(LookupIterator* it) { 1528 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of 1529 // which have already been checked. 1530 DCHECK(it->state() == LookupIterator::ACCESS_CHECK || 1531 it->state() == LookupIterator::INTERCEPTOR); 1532 for (it->Next(); it->IsFound(); it->Next()) { 1533 if (it->state() == LookupIterator::ACCESSOR) { 1534 auto accessors = it->GetAccessors(); 1535 if (accessors->IsAccessorInfo()) { 1536 if (AccessorInfo::cast(*accessors)->all_can_read()) return true; 1537 } 1538 } else if (it->state() == LookupIterator::INTERCEPTOR) { 1539 if (it->GetInterceptor()->all_can_read()) return true; 1540 } else if (it->state() == LookupIterator::JSPROXY) { 1541 // Stop lookupiterating. And no, AllCanNotRead. 1542 return false; 1543 } 1544 } 1545 return false; 1546 } 1547 1548 namespace { 1549 1550 MaybeHandle<Object> GetPropertyWithInterceptorInternal( 1551 LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) { 1552 *done = false; 1553 Isolate* isolate = it->isolate(); 1554 // Make sure that the top context does not change when doing callbacks or 1555 // interceptor calls. 1556 AssertNoContextChange ncc(isolate); 1557 1558 if (interceptor->getter()->IsUndefined(isolate)) { 1559 return isolate->factory()->undefined_value(); 1560 } 1561 1562 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1563 Handle<Object> result; 1564 Handle<Object> receiver = it->GetReceiver(); 1565 if (!receiver->IsJSReceiver()) { 1566 ASSIGN_RETURN_ON_EXCEPTION( 1567 isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object); 1568 } 1569 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1570 *holder, Object::DONT_THROW); 1571 1572 if (it->IsElement()) { 1573 uint32_t index = it->index(); 1574 v8::IndexedPropertyGetterCallback getter = 1575 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); 1576 result = args.Call(getter, index); 1577 } else { 1578 Handle<Name> name = it->name(); 1579 DCHECK(!name->IsPrivate()); 1580 1581 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { 1582 return isolate->factory()->undefined_value(); 1583 } 1584 1585 v8::GenericNamedPropertyGetterCallback getter = 1586 v8::ToCData<v8::GenericNamedPropertyGetterCallback>( 1587 interceptor->getter()); 1588 result = args.Call(getter, name); 1589 } 1590 1591 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1592 if (result.is_null()) return isolate->factory()->undefined_value(); 1593 *done = true; 1594 // Rebox handle before return 1595 return handle(*result, isolate); 1596 } 1597 1598 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal( 1599 LookupIterator* it, Handle<InterceptorInfo> interceptor) { 1600 Isolate* isolate = it->isolate(); 1601 // Make sure that the top context does not change when doing 1602 // callbacks or interceptor calls. 1603 AssertNoContextChange ncc(isolate); 1604 HandleScope scope(isolate); 1605 1606 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1607 if (!it->IsElement() && it->name()->IsSymbol() && 1608 !interceptor->can_intercept_symbols()) { 1609 return Just(ABSENT); 1610 } 1611 Handle<Object> receiver = it->GetReceiver(); 1612 if (!receiver->IsJSReceiver()) { 1613 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1614 Object::ConvertReceiver(isolate, receiver), 1615 Nothing<PropertyAttributes>()); 1616 } 1617 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1618 *holder, Object::DONT_THROW); 1619 if (!interceptor->query()->IsUndefined(isolate)) { 1620 Handle<Object> result; 1621 if (it->IsElement()) { 1622 uint32_t index = it->index(); 1623 v8::IndexedPropertyQueryCallback query = 1624 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query()); 1625 result = args.Call(query, index); 1626 } else { 1627 Handle<Name> name = it->name(); 1628 DCHECK(!name->IsPrivate()); 1629 v8::GenericNamedPropertyQueryCallback query = 1630 v8::ToCData<v8::GenericNamedPropertyQueryCallback>( 1631 interceptor->query()); 1632 result = args.Call(query, name); 1633 } 1634 if (!result.is_null()) { 1635 int32_t value; 1636 CHECK(result->ToInt32(&value)); 1637 return Just(static_cast<PropertyAttributes>(value)); 1638 } 1639 } else if (!interceptor->getter()->IsUndefined(isolate)) { 1640 // TODO(verwaest): Use GetPropertyWithInterceptor? 1641 Handle<Object> result; 1642 if (it->IsElement()) { 1643 uint32_t index = it->index(); 1644 v8::IndexedPropertyGetterCallback getter = 1645 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); 1646 result = args.Call(getter, index); 1647 } else { 1648 Handle<Name> name = it->name(); 1649 DCHECK(!name->IsPrivate()); 1650 v8::GenericNamedPropertyGetterCallback getter = 1651 v8::ToCData<v8::GenericNamedPropertyGetterCallback>( 1652 interceptor->getter()); 1653 result = args.Call(getter, name); 1654 } 1655 if (!result.is_null()) return Just(DONT_ENUM); 1656 } 1657 1658 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1659 return Just(ABSENT); 1660 } 1661 1662 Maybe<bool> SetPropertyWithInterceptorInternal( 1663 LookupIterator* it, Handle<InterceptorInfo> interceptor, 1664 Object::ShouldThrow should_throw, Handle<Object> value) { 1665 Isolate* isolate = it->isolate(); 1666 // Make sure that the top context does not change when doing callbacks or 1667 // interceptor calls. 1668 AssertNoContextChange ncc(isolate); 1669 1670 if (interceptor->setter()->IsUndefined(isolate)) return Just(false); 1671 1672 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1673 bool result; 1674 Handle<Object> receiver = it->GetReceiver(); 1675 if (!receiver->IsJSReceiver()) { 1676 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1677 Object::ConvertReceiver(isolate, receiver), 1678 Nothing<bool>()); 1679 } 1680 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1681 *holder, should_throw); 1682 1683 if (it->IsElement()) { 1684 uint32_t index = it->index(); 1685 v8::IndexedPropertySetterCallback setter = 1686 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter()); 1687 // TODO(neis): In the future, we may want to actually return the 1688 // interceptor's result, which then should be a boolean. 1689 result = !args.Call(setter, index, value).is_null(); 1690 } else { 1691 Handle<Name> name = it->name(); 1692 DCHECK(!name->IsPrivate()); 1693 1694 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { 1695 return Just(false); 1696 } 1697 1698 v8::GenericNamedPropertySetterCallback setter = 1699 v8::ToCData<v8::GenericNamedPropertySetterCallback>( 1700 interceptor->setter()); 1701 result = !args.Call(setter, name, value).is_null(); 1702 } 1703 1704 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 1705 return Just(result); 1706 } 1707 1708 Maybe<bool> DefinePropertyWithInterceptorInternal( 1709 LookupIterator* it, Handle<InterceptorInfo> interceptor, 1710 Object::ShouldThrow should_throw, PropertyDescriptor& desc) { 1711 Isolate* isolate = it->isolate(); 1712 // Make sure that the top context does not change when doing callbacks or 1713 // interceptor calls. 1714 AssertNoContextChange ncc(isolate); 1715 1716 if (interceptor->definer()->IsUndefined(isolate)) return Just(false); 1717 1718 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1719 bool result; 1720 Handle<Object> receiver = it->GetReceiver(); 1721 if (!receiver->IsJSReceiver()) { 1722 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1723 Object::ConvertReceiver(isolate, receiver), 1724 Nothing<bool>()); 1725 } 1726 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1727 *holder, should_throw); 1728 1729 std::unique_ptr<v8::PropertyDescriptor> descriptor( 1730 new v8::PropertyDescriptor()); 1731 if (PropertyDescriptor::IsAccessorDescriptor(&desc)) { 1732 descriptor.reset(new v8::PropertyDescriptor( 1733 v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set()))); 1734 } else if (PropertyDescriptor::IsDataDescriptor(&desc)) { 1735 if (desc.has_writable()) { 1736 descriptor.reset(new v8::PropertyDescriptor( 1737 v8::Utils::ToLocal(desc.value()), desc.writable())); 1738 } else { 1739 descriptor.reset( 1740 new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value()))); 1741 } 1742 } 1743 if (desc.has_enumerable()) { 1744 descriptor->set_enumerable(desc.enumerable()); 1745 } 1746 if (desc.has_configurable()) { 1747 descriptor->set_configurable(desc.configurable()); 1748 } 1749 1750 if (it->IsElement()) { 1751 uint32_t index = it->index(); 1752 v8::IndexedPropertyDefinerCallback definer = 1753 v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer()); 1754 result = !args.Call(definer, index, *descriptor).is_null(); 1755 } else { 1756 Handle<Name> name = it->name(); 1757 DCHECK(!name->IsPrivate()); 1758 1759 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { 1760 return Just(false); 1761 } 1762 1763 v8::GenericNamedPropertyDefinerCallback definer = 1764 v8::ToCData<v8::GenericNamedPropertyDefinerCallback>( 1765 interceptor->definer()); 1766 result = !args.Call(definer, name, *descriptor).is_null(); 1767 } 1768 1769 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 1770 return Just(result); 1771 } 1772 1773 } // namespace 1774 1775 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( 1776 LookupIterator* it) { 1777 Isolate* isolate = it->isolate(); 1778 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1779 Handle<InterceptorInfo> interceptor = 1780 it->GetInterceptorForFailedAccessCheck(); 1781 if (interceptor.is_null()) { 1782 while (AllCanRead(it)) { 1783 if (it->state() == LookupIterator::ACCESSOR) { 1784 return GetPropertyWithAccessor(it); 1785 } 1786 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 1787 bool done; 1788 Handle<Object> result; 1789 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 1790 GetPropertyWithInterceptor(it, &done), Object); 1791 if (done) return result; 1792 } 1793 } else { 1794 MaybeHandle<Object> result; 1795 bool done; 1796 result = GetPropertyWithInterceptorInternal(it, interceptor, &done); 1797 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1798 if (done) return result; 1799 } 1800 1801 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns 1802 // undefined. 1803 Handle<Name> name = it->GetName(); 1804 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) { 1805 return it->factory()->undefined_value(); 1806 } 1807 1808 isolate->ReportFailedAccessCheck(checked); 1809 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1810 return it->factory()->undefined_value(); 1811 } 1812 1813 1814 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck( 1815 LookupIterator* it) { 1816 Isolate* isolate = it->isolate(); 1817 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1818 Handle<InterceptorInfo> interceptor = 1819 it->GetInterceptorForFailedAccessCheck(); 1820 if (interceptor.is_null()) { 1821 while (AllCanRead(it)) { 1822 if (it->state() == LookupIterator::ACCESSOR) { 1823 return Just(it->property_attributes()); 1824 } 1825 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 1826 auto result = GetPropertyAttributesWithInterceptor(it); 1827 if (isolate->has_scheduled_exception()) break; 1828 if (result.IsJust() && result.FromJust() != ABSENT) return result; 1829 } 1830 } else { 1831 Maybe<PropertyAttributes> result = 1832 GetPropertyAttributesWithInterceptorInternal(it, interceptor); 1833 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1834 if (result.FromMaybe(ABSENT) != ABSENT) return result; 1835 } 1836 isolate->ReportFailedAccessCheck(checked); 1837 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1838 return Just(ABSENT); 1839 } 1840 1841 1842 // static 1843 bool JSObject::AllCanWrite(LookupIterator* it) { 1844 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) { 1845 if (it->state() == LookupIterator::ACCESSOR) { 1846 Handle<Object> accessors = it->GetAccessors(); 1847 if (accessors->IsAccessorInfo()) { 1848 if (AccessorInfo::cast(*accessors)->all_can_write()) return true; 1849 } 1850 } 1851 } 1852 return false; 1853 } 1854 1855 1856 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck( 1857 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) { 1858 Isolate* isolate = it->isolate(); 1859 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1860 Handle<InterceptorInfo> interceptor = 1861 it->GetInterceptorForFailedAccessCheck(); 1862 if (interceptor.is_null()) { 1863 if (AllCanWrite(it)) { 1864 return SetPropertyWithAccessor(it, value, should_throw); 1865 } 1866 } else { 1867 Maybe<bool> result = SetPropertyWithInterceptorInternal( 1868 it, interceptor, should_throw, value); 1869 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1870 if (result.IsJust()) return result; 1871 } 1872 1873 isolate->ReportFailedAccessCheck(checked); 1874 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1875 return Just(true); 1876 } 1877 1878 1879 void JSObject::SetNormalizedProperty(Handle<JSObject> object, 1880 Handle<Name> name, 1881 Handle<Object> value, 1882 PropertyDetails details) { 1883 DCHECK(!object->HasFastProperties()); 1884 if (!name->IsUniqueName()) { 1885 name = object->GetIsolate()->factory()->InternalizeString( 1886 Handle<String>::cast(name)); 1887 } 1888 1889 if (object->IsJSGlobalObject()) { 1890 Handle<GlobalDictionary> dictionary(object->global_dictionary()); 1891 1892 int entry = dictionary->FindEntry(name); 1893 if (entry == GlobalDictionary::kNotFound) { 1894 Isolate* isolate = object->GetIsolate(); 1895 auto cell = isolate->factory()->NewPropertyCell(); 1896 cell->set_value(*value); 1897 auto cell_type = value->IsUndefined(isolate) 1898 ? PropertyCellType::kUndefined 1899 : PropertyCellType::kConstant; 1900 details = details.set_cell_type(cell_type); 1901 value = cell; 1902 dictionary = GlobalDictionary::Add(dictionary, name, value, details); 1903 object->set_properties(*dictionary); 1904 } else { 1905 Handle<PropertyCell> cell = 1906 PropertyCell::PrepareForValue(dictionary, entry, value, details); 1907 cell->set_value(*value); 1908 } 1909 } else { 1910 Handle<NameDictionary> dictionary(object->property_dictionary()); 1911 1912 int entry = dictionary->FindEntry(name); 1913 if (entry == NameDictionary::kNotFound) { 1914 dictionary = NameDictionary::Add(dictionary, name, value, details); 1915 object->set_properties(*dictionary); 1916 } else { 1917 PropertyDetails original_details = dictionary->DetailsAt(entry); 1918 int enumeration_index = original_details.dictionary_index(); 1919 DCHECK(enumeration_index > 0); 1920 details = details.set_index(enumeration_index); 1921 dictionary->SetEntry(entry, name, value, details); 1922 } 1923 } 1924 } 1925 1926 // static 1927 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate, 1928 Handle<JSReceiver> object, 1929 Handle<Object> proto) { 1930 PrototypeIterator iter(isolate, object, kStartAtReceiver); 1931 while (true) { 1932 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); 1933 if (iter.IsAtEnd()) return Just(false); 1934 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { 1935 return Just(true); 1936 } 1937 } 1938 } 1939 1940 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) { 1941 DisallowHeapAllocation no_alloc; 1942 if (IsSmi()) { 1943 Context* native_context = isolate->context()->native_context(); 1944 return native_context->number_function()->initial_map(); 1945 } 1946 1947 // The object is either a number, a string, a symbol, a boolean, a SIMD value, 1948 // a real JS object, or a Harmony proxy. 1949 HeapObject* heap_object = HeapObject::cast(this); 1950 return heap_object->map()->GetPrototypeChainRootMap(isolate); 1951 } 1952 1953 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) { 1954 DisallowHeapAllocation no_alloc; 1955 if (IsJSReceiverMap()) { 1956 return this; 1957 } 1958 int constructor_function_index = GetConstructorFunctionIndex(); 1959 if (constructor_function_index != Map::kNoConstructorFunctionIndex) { 1960 Context* native_context = isolate->context()->native_context(); 1961 JSFunction* constructor_function = 1962 JSFunction::cast(native_context->get(constructor_function_index)); 1963 return constructor_function->initial_map(); 1964 } 1965 return isolate->heap()->null_value()->map(); 1966 } 1967 1968 namespace { 1969 1970 // Returns a non-SMI for JSObjects, but returns the hash code for simple 1971 // objects. This avoids a double lookup in the cases where we know we will 1972 // add the hash to the JSObject if it does not already exist. 1973 Object* GetSimpleHash(Object* object) { 1974 // The object is either a Smi, a HeapNumber, a name, an odd-ball, 1975 // a SIMD value type, a real JS object, or a Harmony proxy. 1976 if (object->IsSmi()) { 1977 uint32_t hash = 1978 ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed); 1979 return Smi::FromInt(hash & Smi::kMaxValue); 1980 } 1981 if (object->IsHeapNumber()) { 1982 double num = HeapNumber::cast(object)->value(); 1983 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue); 1984 if (i::IsMinusZero(num)) num = 0; 1985 if (IsSmiDouble(num)) { 1986 return Smi::FromInt(FastD2I(num))->GetHash(); 1987 } 1988 uint32_t hash = ComputeLongHash(double_to_uint64(num)); 1989 return Smi::FromInt(hash & Smi::kMaxValue); 1990 } 1991 if (object->IsName()) { 1992 uint32_t hash = Name::cast(object)->Hash(); 1993 return Smi::FromInt(hash); 1994 } 1995 if (object->IsOddball()) { 1996 uint32_t hash = Oddball::cast(object)->to_string()->Hash(); 1997 return Smi::FromInt(hash); 1998 } 1999 if (object->IsSimd128Value()) { 2000 uint32_t hash = Simd128Value::cast(object)->Hash(); 2001 return Smi::FromInt(hash & Smi::kMaxValue); 2002 } 2003 DCHECK(object->IsJSReceiver()); 2004 // Simply return the receiver as it is guaranteed to not be a SMI. 2005 return object; 2006 } 2007 2008 } // namespace 2009 2010 Object* Object::GetHash() { 2011 Object* hash = GetSimpleHash(this); 2012 if (hash->IsSmi()) return hash; 2013 2014 DisallowHeapAllocation no_gc; 2015 DCHECK(IsJSReceiver()); 2016 JSReceiver* receiver = JSReceiver::cast(this); 2017 Isolate* isolate = receiver->GetIsolate(); 2018 return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate)); 2019 } 2020 2021 Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) { 2022 Object* hash = GetSimpleHash(*object); 2023 if (hash->IsSmi()) return Smi::cast(hash); 2024 2025 DCHECK(object->IsJSReceiver()); 2026 return JSReceiver::GetOrCreateIdentityHash(isolate, 2027 Handle<JSReceiver>::cast(object)); 2028 } 2029 2030 2031 bool Object::SameValue(Object* other) { 2032 if (other == this) return true; 2033 2034 // The object is either a number, a name, an odd-ball, 2035 // a real JS object, or a Harmony proxy. 2036 if (IsNumber() && other->IsNumber()) { 2037 double this_value = Number(); 2038 double other_value = other->Number(); 2039 // SameValue(NaN, NaN) is true. 2040 if (this_value != other_value) { 2041 return std::isnan(this_value) && std::isnan(other_value); 2042 } 2043 // SameValue(0.0, -0.0) is false. 2044 return (std::signbit(this_value) == std::signbit(other_value)); 2045 } 2046 if (IsString() && other->IsString()) { 2047 return String::cast(this)->Equals(String::cast(other)); 2048 } 2049 if (IsFloat32x4() && other->IsFloat32x4()) { 2050 Float32x4* a = Float32x4::cast(this); 2051 Float32x4* b = Float32x4::cast(other); 2052 for (int i = 0; i < 4; i++) { 2053 float x = a->get_lane(i); 2054 float y = b->get_lane(i); 2055 // Implements the ES5 SameValue operation for floating point types. 2056 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue 2057 if (x != y && !(std::isnan(x) && std::isnan(y))) return false; 2058 if (std::signbit(x) != std::signbit(y)) return false; 2059 } 2060 return true; 2061 } else if (IsSimd128Value() && other->IsSimd128Value()) { 2062 Simd128Value* a = Simd128Value::cast(this); 2063 Simd128Value* b = Simd128Value::cast(other); 2064 return a->map() == b->map() && a->BitwiseEquals(b); 2065 } 2066 return false; 2067 } 2068 2069 2070 bool Object::SameValueZero(Object* other) { 2071 if (other == this) return true; 2072 2073 // The object is either a number, a name, an odd-ball, 2074 // a real JS object, or a Harmony proxy. 2075 if (IsNumber() && other->IsNumber()) { 2076 double this_value = Number(); 2077 double other_value = other->Number(); 2078 // +0 == -0 is true 2079 return this_value == other_value || 2080 (std::isnan(this_value) && std::isnan(other_value)); 2081 } 2082 if (IsString() && other->IsString()) { 2083 return String::cast(this)->Equals(String::cast(other)); 2084 } 2085 if (IsFloat32x4() && other->IsFloat32x4()) { 2086 Float32x4* a = Float32x4::cast(this); 2087 Float32x4* b = Float32x4::cast(other); 2088 for (int i = 0; i < 4; i++) { 2089 float x = a->get_lane(i); 2090 float y = b->get_lane(i); 2091 // Implements the ES6 SameValueZero operation for floating point types. 2092 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero 2093 if (x != y && !(std::isnan(x) && std::isnan(y))) return false; 2094 // SameValueZero doesn't distinguish between 0 and -0. 2095 } 2096 return true; 2097 } else if (IsSimd128Value() && other->IsSimd128Value()) { 2098 Simd128Value* a = Simd128Value::cast(this); 2099 Simd128Value* b = Simd128Value::cast(other); 2100 return a->map() == b->map() && a->BitwiseEquals(b); 2101 } 2102 return false; 2103 } 2104 2105 2106 MaybeHandle<Object> Object::ArraySpeciesConstructor( 2107 Isolate* isolate, Handle<Object> original_array) { 2108 Handle<Object> default_species = isolate->array_function(); 2109 if (original_array->IsJSArray() && 2110 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) && 2111 isolate->IsArraySpeciesLookupChainIntact()) { 2112 return default_species; 2113 } 2114 Handle<Object> constructor = isolate->factory()->undefined_value(); 2115 Maybe<bool> is_array = Object::IsArray(original_array); 2116 MAYBE_RETURN_NULL(is_array); 2117 if (is_array.FromJust()) { 2118 ASSIGN_RETURN_ON_EXCEPTION( 2119 isolate, constructor, 2120 Object::GetProperty(original_array, 2121 isolate->factory()->constructor_string()), 2122 Object); 2123 if (constructor->IsConstructor()) { 2124 Handle<Context> constructor_context; 2125 ASSIGN_RETURN_ON_EXCEPTION( 2126 isolate, constructor_context, 2127 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)), 2128 Object); 2129 if (*constructor_context != *isolate->native_context() && 2130 *constructor == constructor_context->array_function()) { 2131 constructor = isolate->factory()->undefined_value(); 2132 } 2133 } 2134 if (constructor->IsJSReceiver()) { 2135 ASSIGN_RETURN_ON_EXCEPTION( 2136 isolate, constructor, 2137 JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor), 2138 isolate->factory()->species_symbol()), 2139 Object); 2140 if (constructor->IsNull(isolate)) { 2141 constructor = isolate->factory()->undefined_value(); 2142 } 2143 } 2144 } 2145 if (constructor->IsUndefined(isolate)) { 2146 return default_species; 2147 } else { 2148 if (!constructor->IsConstructor()) { 2149 THROW_NEW_ERROR(isolate, 2150 NewTypeError(MessageTemplate::kSpeciesNotConstructor), 2151 Object); 2152 } 2153 return constructor; 2154 } 2155 } 2156 2157 2158 void Object::ShortPrint(FILE* out) { 2159 OFStream os(out); 2160 os << Brief(this); 2161 } 2162 2163 2164 void Object::ShortPrint(StringStream* accumulator) { 2165 std::ostringstream os; 2166 os << Brief(this); 2167 accumulator->Add(os.str().c_str()); 2168 } 2169 2170 2171 void Object::ShortPrint(std::ostream& os) { os << Brief(this); } 2172 2173 2174 std::ostream& operator<<(std::ostream& os, const Brief& v) { 2175 if (v.value->IsSmi()) { 2176 Smi::cast(v.value)->SmiPrint(os); 2177 } else { 2178 // TODO(svenpanne) Const-correct HeapObjectShortPrint! 2179 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value)); 2180 obj->HeapObjectShortPrint(os); 2181 } 2182 return os; 2183 } 2184 2185 // Declaration of the static Smi::kZero constant. 2186 Smi* const Smi::kZero(nullptr); 2187 2188 void Smi::SmiPrint(std::ostream& os) const { // NOLINT 2189 os << value(); 2190 } 2191 2192 2193 // Should a word be prefixed by 'a' or 'an' in order to read naturally in 2194 // English? Returns false for non-ASCII or words that don't start with 2195 // a capital letter. The a/an rule follows pronunciation in English. 2196 // We don't use the BBC's overcorrect "an historic occasion" though if 2197 // you speak a dialect you may well say "an 'istoric occasion". 2198 static bool AnWord(String* str) { 2199 if (str->length() == 0) return false; // A nothing. 2200 int c0 = str->Get(0); 2201 int c1 = str->length() > 1 ? str->Get(1) : 0; 2202 if (c0 == 'U') { 2203 if (c1 > 'Z') { 2204 return true; // An Umpire, but a UTF8String, a U. 2205 } 2206 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { 2207 return true; // An Ape, an ABCBook. 2208 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && 2209 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || 2210 c0 == 'S' || c0 == 'X')) { 2211 return true; // An MP3File, an M. 2212 } 2213 return false; 2214 } 2215 2216 2217 Handle<String> String::SlowFlatten(Handle<ConsString> cons, 2218 PretenureFlag pretenure) { 2219 DCHECK(cons->second()->length() != 0); 2220 2221 // TurboFan can create cons strings with empty first parts. 2222 if (cons->first()->length() == 0) return handle(cons->second()); 2223 2224 DCHECK(AllowHeapAllocation::IsAllowed()); 2225 Isolate* isolate = cons->GetIsolate(); 2226 int length = cons->length(); 2227 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure 2228 : TENURED; 2229 Handle<SeqString> result; 2230 if (cons->IsOneByteRepresentation()) { 2231 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString( 2232 length, tenure).ToHandleChecked(); 2233 DisallowHeapAllocation no_gc; 2234 WriteToFlat(*cons, flat->GetChars(), 0, length); 2235 result = flat; 2236 } else { 2237 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString( 2238 length, tenure).ToHandleChecked(); 2239 DisallowHeapAllocation no_gc; 2240 WriteToFlat(*cons, flat->GetChars(), 0, length); 2241 result = flat; 2242 } 2243 cons->set_first(*result); 2244 cons->set_second(isolate->heap()->empty_string()); 2245 DCHECK(result->IsFlat()); 2246 return result; 2247 } 2248 2249 2250 2251 bool String::MakeExternal(v8::String::ExternalStringResource* resource) { 2252 // Externalizing twice leaks the external resource, so it's 2253 // prohibited by the API. 2254 DCHECK(!this->IsExternalString()); 2255 DCHECK(!resource->IsCompressible()); 2256 #ifdef ENABLE_SLOW_DCHECKS 2257 if (FLAG_enable_slow_asserts) { 2258 // Assert that the resource and the string are equivalent. 2259 DCHECK(static_cast<size_t>(this->length()) == resource->length()); 2260 ScopedVector<uc16> smart_chars(this->length()); 2261 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2262 DCHECK(memcmp(smart_chars.start(), 2263 resource->data(), 2264 resource->length() * sizeof(smart_chars[0])) == 0); 2265 } 2266 #endif // DEBUG 2267 int size = this->Size(); // Byte size of the original string. 2268 // Abort if size does not allow in-place conversion. 2269 if (size < ExternalString::kShortSize) return false; 2270 Heap* heap = GetHeap(); 2271 bool is_one_byte = this->IsOneByteRepresentation(); 2272 bool is_internalized = this->IsInternalizedString(); 2273 bool has_pointers = this->IsConsString() || this->IsSlicedString(); 2274 2275 // Morph the string to an external string by replacing the map and 2276 // reinitializing the fields. This won't work if the space the existing 2277 // string occupies is too small for a regular external string. 2278 // Instead, we resort to a short external string instead, omitting 2279 // the field caching the address of the backing store. When we encounter 2280 // short external strings in generated code, we need to bailout to runtime. 2281 Map* new_map; 2282 if (size < ExternalString::kSize) { 2283 new_map = is_internalized 2284 ? (is_one_byte 2285 ? heap->short_external_internalized_string_with_one_byte_data_map() 2286 : heap->short_external_internalized_string_map()) 2287 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map() 2288 : heap->short_external_string_map()); 2289 } else { 2290 new_map = is_internalized 2291 ? (is_one_byte 2292 ? heap->external_internalized_string_with_one_byte_data_map() 2293 : heap->external_internalized_string_map()) 2294 : (is_one_byte ? heap->external_string_with_one_byte_data_map() 2295 : heap->external_string_map()); 2296 } 2297 2298 // Byte size of the external String object. 2299 int new_size = this->SizeFromMap(new_map); 2300 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, 2301 ClearRecordedSlots::kNo); 2302 if (has_pointers) { 2303 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size); 2304 } 2305 2306 // We are storing the new map using release store after creating a filler for 2307 // the left-over space to avoid races with the sweeper thread. 2308 this->synchronized_set_map(new_map); 2309 2310 ExternalTwoByteString* self = ExternalTwoByteString::cast(this); 2311 self->set_resource(resource); 2312 if (is_internalized) self->Hash(); // Force regeneration of the hash value. 2313 2314 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER); 2315 return true; 2316 } 2317 2318 2319 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) { 2320 // Externalizing twice leaks the external resource, so it's 2321 // prohibited by the API. 2322 DCHECK(!this->IsExternalString()); 2323 DCHECK(!resource->IsCompressible()); 2324 #ifdef ENABLE_SLOW_DCHECKS 2325 if (FLAG_enable_slow_asserts) { 2326 // Assert that the resource and the string are equivalent. 2327 DCHECK(static_cast<size_t>(this->length()) == resource->length()); 2328 if (this->IsTwoByteRepresentation()) { 2329 ScopedVector<uint16_t> smart_chars(this->length()); 2330 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2331 DCHECK(String::IsOneByte(smart_chars.start(), this->length())); 2332 } 2333 ScopedVector<char> smart_chars(this->length()); 2334 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2335 DCHECK(memcmp(smart_chars.start(), 2336 resource->data(), 2337 resource->length() * sizeof(smart_chars[0])) == 0); 2338 } 2339 #endif // DEBUG 2340 int size = this->Size(); // Byte size of the original string. 2341 // Abort if size does not allow in-place conversion. 2342 if (size < ExternalString::kShortSize) return false; 2343 Heap* heap = GetHeap(); 2344 bool is_internalized = this->IsInternalizedString(); 2345 bool has_pointers = this->IsConsString() || this->IsSlicedString(); 2346 2347 // Morph the string to an external string by replacing the map and 2348 // reinitializing the fields. This won't work if the space the existing 2349 // string occupies is too small for a regular external string. 2350 // Instead, we resort to a short external string instead, omitting 2351 // the field caching the address of the backing store. When we encounter 2352 // short external strings in generated code, we need to bailout to runtime. 2353 Map* new_map; 2354 if (size < ExternalString::kSize) { 2355 new_map = is_internalized 2356 ? heap->short_external_one_byte_internalized_string_map() 2357 : heap->short_external_one_byte_string_map(); 2358 } else { 2359 new_map = is_internalized 2360 ? heap->external_one_byte_internalized_string_map() 2361 : heap->external_one_byte_string_map(); 2362 } 2363 2364 // Byte size of the external String object. 2365 int new_size = this->SizeFromMap(new_map); 2366 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, 2367 ClearRecordedSlots::kNo); 2368 if (has_pointers) { 2369 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size); 2370 } 2371 2372 // We are storing the new map using release store after creating a filler for 2373 // the left-over space to avoid races with the sweeper thread. 2374 this->synchronized_set_map(new_map); 2375 2376 ExternalOneByteString* self = ExternalOneByteString::cast(this); 2377 self->set_resource(resource); 2378 if (is_internalized) self->Hash(); // Force regeneration of the hash value. 2379 2380 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER); 2381 return true; 2382 } 2383 2384 void String::StringShortPrint(StringStream* accumulator, bool show_details) { 2385 int len = length(); 2386 if (len > kMaxShortPrintLength) { 2387 accumulator->Add("<Very long string[%u]>", len); 2388 return; 2389 } 2390 2391 if (!LooksValid()) { 2392 accumulator->Add("<Invalid String>"); 2393 return; 2394 } 2395 2396 StringCharacterStream stream(this); 2397 2398 bool truncated = false; 2399 if (len > kMaxShortPrintLength) { 2400 len = kMaxShortPrintLength; 2401 truncated = true; 2402 } 2403 bool one_byte = true; 2404 for (int i = 0; i < len; i++) { 2405 uint16_t c = stream.GetNext(); 2406 2407 if (c < 32 || c >= 127) { 2408 one_byte = false; 2409 } 2410 } 2411 stream.Reset(this); 2412 if (one_byte) { 2413 if (show_details) accumulator->Add("<String[%u]: ", length()); 2414 for (int i = 0; i < len; i++) { 2415 accumulator->Put(static_cast<char>(stream.GetNext())); 2416 } 2417 if (show_details) accumulator->Put('>'); 2418 } else { 2419 // Backslash indicates that the string contains control 2420 // characters and that backslashes are therefore escaped. 2421 if (show_details) accumulator->Add("<String[%u]\\: ", length()); 2422 for (int i = 0; i < len; i++) { 2423 uint16_t c = stream.GetNext(); 2424 if (c == '\n') { 2425 accumulator->Add("\\n"); 2426 } else if (c == '\r') { 2427 accumulator->Add("\\r"); 2428 } else if (c == '\\') { 2429 accumulator->Add("\\\\"); 2430 } else if (c < 32 || c > 126) { 2431 accumulator->Add("\\x%02x", c); 2432 } else { 2433 accumulator->Put(static_cast<char>(c)); 2434 } 2435 } 2436 if (truncated) { 2437 accumulator->Put('.'); 2438 accumulator->Put('.'); 2439 accumulator->Put('.'); 2440 } 2441 if (show_details) accumulator->Put('>'); 2442 } 2443 return; 2444 } 2445 2446 2447 void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT 2448 if (end < 0) end = length(); 2449 StringCharacterStream stream(this, start); 2450 for (int i = start; i < end && stream.HasMore(); i++) { 2451 os << AsUC16(stream.GetNext()); 2452 } 2453 } 2454 2455 2456 void JSObject::JSObjectShortPrint(StringStream* accumulator) { 2457 switch (map()->instance_type()) { 2458 case JS_ARRAY_TYPE: { 2459 double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate()) 2460 ? 0 2461 : JSArray::cast(this)->length()->Number(); 2462 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length)); 2463 break; 2464 } 2465 case JS_BOUND_FUNCTION_TYPE: { 2466 JSBoundFunction* bound_function = JSBoundFunction::cast(this); 2467 accumulator->Add("<JS BoundFunction"); 2468 accumulator->Add( 2469 " (BoundTargetFunction %p)>", 2470 reinterpret_cast<void*>(bound_function->bound_target_function())); 2471 break; 2472 } 2473 case JS_WEAK_MAP_TYPE: { 2474 accumulator->Add("<JS WeakMap>"); 2475 break; 2476 } 2477 case JS_WEAK_SET_TYPE: { 2478 accumulator->Add("<JS WeakSet>"); 2479 break; 2480 } 2481 case JS_REGEXP_TYPE: { 2482 accumulator->Add("<JS RegExp>"); 2483 break; 2484 } 2485 case JS_FUNCTION_TYPE: { 2486 JSFunction* function = JSFunction::cast(this); 2487 Object* fun_name = function->shared()->DebugName(); 2488 bool printed = false; 2489 if (fun_name->IsString()) { 2490 String* str = String::cast(fun_name); 2491 if (str->length() > 0) { 2492 accumulator->Add("<JS Function "); 2493 accumulator->Put(str); 2494 printed = true; 2495 } 2496 } 2497 if (!printed) { 2498 accumulator->Add("<JS Function"); 2499 } 2500 if (FLAG_trace_file_names) { 2501 Object* source_name = 2502 Script::cast(function->shared()->script())->name(); 2503 if (source_name->IsString()) { 2504 String* str = String::cast(source_name); 2505 if (str->length() > 0) { 2506 accumulator->Add(" <"); 2507 accumulator->Put(str); 2508 accumulator->Add(">"); 2509 } 2510 } 2511 } 2512 accumulator->Add(" (SharedFunctionInfo %p)", 2513 reinterpret_cast<void*>(function->shared())); 2514 accumulator->Put('>'); 2515 break; 2516 } 2517 case JS_GENERATOR_OBJECT_TYPE: { 2518 accumulator->Add("<JS Generator>"); 2519 break; 2520 } 2521 // All other JSObjects are rather similar to each other (JSObject, 2522 // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue). 2523 default: { 2524 Map* map_of_this = map(); 2525 Heap* heap = GetHeap(); 2526 Object* constructor = map_of_this->GetConstructor(); 2527 bool printed = false; 2528 if (constructor->IsHeapObject() && 2529 !heap->Contains(HeapObject::cast(constructor))) { 2530 accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); 2531 } else { 2532 bool global_object = IsJSGlobalProxy(); 2533 if (constructor->IsJSFunction()) { 2534 if (!heap->Contains(JSFunction::cast(constructor)->shared())) { 2535 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); 2536 } else { 2537 Object* constructor_name = 2538 JSFunction::cast(constructor)->shared()->name(); 2539 if (constructor_name->IsString()) { 2540 String* str = String::cast(constructor_name); 2541 if (str->length() > 0) { 2542 bool vowel = AnWord(str); 2543 accumulator->Add("<%sa%s ", 2544 global_object ? "Global Object: " : "", 2545 vowel ? "n" : ""); 2546 accumulator->Put(str); 2547 accumulator->Add(" with %smap %p", 2548 map_of_this->is_deprecated() ? "deprecated " : "", 2549 map_of_this); 2550 printed = true; 2551 } 2552 } 2553 } 2554 } 2555 if (!printed) { 2556 accumulator->Add("<JS %sObject", global_object ? "Global " : ""); 2557 } 2558 } 2559 if (IsJSValue()) { 2560 accumulator->Add(" value = "); 2561 JSValue::cast(this)->value()->ShortPrint(accumulator); 2562 } 2563 accumulator->Put('>'); 2564 break; 2565 } 2566 } 2567 } 2568 2569 2570 void JSObject::PrintElementsTransition( 2571 FILE* file, Handle<JSObject> object, 2572 ElementsKind from_kind, Handle<FixedArrayBase> from_elements, 2573 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) { 2574 if (from_kind != to_kind) { 2575 OFStream os(file); 2576 os << "elements transition [" << ElementsKindToString(from_kind) << " -> " 2577 << ElementsKindToString(to_kind) << "] in "; 2578 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true); 2579 PrintF(file, " for "); 2580 object->ShortPrint(file); 2581 PrintF(file, " from "); 2582 from_elements->ShortPrint(file); 2583 PrintF(file, " to "); 2584 to_elements->ShortPrint(file); 2585 PrintF(file, "\n"); 2586 } 2587 } 2588 2589 2590 // static 2591 MaybeHandle<JSFunction> Map::GetConstructorFunction( 2592 Handle<Map> map, Handle<Context> native_context) { 2593 if (map->IsPrimitiveMap()) { 2594 int const constructor_function_index = map->GetConstructorFunctionIndex(); 2595 if (constructor_function_index != kNoConstructorFunctionIndex) { 2596 return handle( 2597 JSFunction::cast(native_context->get(constructor_function_index))); 2598 } 2599 } 2600 return MaybeHandle<JSFunction>(); 2601 } 2602 2603 2604 void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind, 2605 PropertyAttributes attributes) { 2606 OFStream os(file); 2607 os << "[reconfiguring]"; 2608 Name* name = instance_descriptors()->GetKey(modify_index); 2609 if (name->IsString()) { 2610 String::cast(name)->PrintOn(file); 2611 } else { 2612 os << "{symbol " << static_cast<void*>(name) << "}"; 2613 } 2614 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: "; 2615 os << attributes << " ["; 2616 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true); 2617 os << "]\n"; 2618 } 2619 2620 void Map::PrintGeneralization( 2621 FILE* file, const char* reason, int modify_index, int split, 2622 int descriptors, bool constant_to_field, Representation old_representation, 2623 Representation new_representation, MaybeHandle<FieldType> old_field_type, 2624 MaybeHandle<Object> old_value, MaybeHandle<FieldType> new_field_type, 2625 MaybeHandle<Object> new_value) { 2626 OFStream os(file); 2627 os << "[generalizing]"; 2628 Name* name = instance_descriptors()->GetKey(modify_index); 2629 if (name->IsString()) { 2630 String::cast(name)->PrintOn(file); 2631 } else { 2632 os << "{symbol " << static_cast<void*>(name) << "}"; 2633 } 2634 os << ":"; 2635 if (constant_to_field) { 2636 os << "c"; 2637 } else { 2638 os << old_representation.Mnemonic() << "{"; 2639 if (old_field_type.is_null()) { 2640 os << Brief(*(old_value.ToHandleChecked())); 2641 } else { 2642 old_field_type.ToHandleChecked()->PrintTo(os); 2643 } 2644 os << "}"; 2645 } 2646 os << "->" << new_representation.Mnemonic() << "{"; 2647 if (new_field_type.is_null()) { 2648 os << Brief(*(new_value.ToHandleChecked())); 2649 } else { 2650 new_field_type.ToHandleChecked()->PrintTo(os); 2651 } 2652 os << "} ("; 2653 if (strlen(reason) > 0) { 2654 os << reason; 2655 } else { 2656 os << "+" << (descriptors - split) << " maps"; 2657 } 2658 os << ") ["; 2659 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true); 2660 os << "]\n"; 2661 } 2662 2663 2664 void JSObject::PrintInstanceMigration(FILE* file, 2665 Map* original_map, 2666 Map* new_map) { 2667 PrintF(file, "[migrating]"); 2668 DescriptorArray* o = original_map->instance_descriptors(); 2669 DescriptorArray* n = new_map->instance_descriptors(); 2670 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) { 2671 Representation o_r = o->GetDetails(i).representation(); 2672 Representation n_r = n->GetDetails(i).representation(); 2673 if (!o_r.Equals(n_r)) { 2674 String::cast(o->GetKey(i))->PrintOn(file); 2675 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic()); 2676 } else if (o->GetDetails(i).type() == DATA_CONSTANT && 2677 n->GetDetails(i).type() == DATA) { 2678 Name* name = o->GetKey(i); 2679 if (name->IsString()) { 2680 String::cast(name)->PrintOn(file); 2681 } else { 2682 PrintF(file, "{symbol %p}", static_cast<void*>(name)); 2683 } 2684 PrintF(file, " "); 2685 } 2686 } 2687 PrintF(file, "\n"); 2688 } 2689 2690 2691 void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT 2692 Heap* heap = GetHeap(); 2693 Isolate* isolate = heap->isolate(); 2694 if (!heap->Contains(this)) { 2695 os << "!!!INVALID POINTER!!!"; 2696 return; 2697 } 2698 if (!heap->Contains(map())) { 2699 os << "!!!INVALID MAP!!!"; 2700 return; 2701 } 2702 2703 os << this << " "; 2704 2705 if (IsString()) { 2706 HeapStringAllocator allocator; 2707 StringStream accumulator(&allocator); 2708 String::cast(this)->StringShortPrint(&accumulator); 2709 os << accumulator.ToCString().get(); 2710 return; 2711 } 2712 if (IsJSObject()) { 2713 HeapStringAllocator allocator; 2714 StringStream accumulator(&allocator); 2715 JSObject::cast(this)->JSObjectShortPrint(&accumulator); 2716 os << accumulator.ToCString().get(); 2717 return; 2718 } 2719 switch (map()->instance_type()) { 2720 case MAP_TYPE: 2721 os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind()) 2722 << ")>"; 2723 break; 2724 case FIXED_ARRAY_TYPE: 2725 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>"; 2726 break; 2727 case FIXED_DOUBLE_ARRAY_TYPE: 2728 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length() 2729 << "]>"; 2730 break; 2731 case BYTE_ARRAY_TYPE: 2732 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>"; 2733 break; 2734 case BYTECODE_ARRAY_TYPE: 2735 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>"; 2736 break; 2737 case TRANSITION_ARRAY_TYPE: 2738 os << "<TransitionArray[" << TransitionArray::cast(this)->length() 2739 << "]>"; 2740 break; 2741 case FREE_SPACE_TYPE: 2742 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>"; 2743 break; 2744 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \ 2745 case FIXED_##TYPE##_ARRAY_TYPE: \ 2746 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \ 2747 << "]>"; \ 2748 break; 2749 2750 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT) 2751 #undef TYPED_ARRAY_SHORT_PRINT 2752 2753 case SHARED_FUNCTION_INFO_TYPE: { 2754 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this); 2755 std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString(); 2756 if (debug_name[0] != 0) { 2757 os << "<SharedFunctionInfo " << debug_name.get() << ">"; 2758 } else { 2759 os << "<SharedFunctionInfo>"; 2760 } 2761 break; 2762 } 2763 case JS_MESSAGE_OBJECT_TYPE: 2764 os << "<JSMessageObject>"; 2765 break; 2766 #define MAKE_STRUCT_CASE(NAME, Name, name) \ 2767 case NAME##_TYPE: \ 2768 os << "<" #Name ">"; \ 2769 break; 2770 STRUCT_LIST(MAKE_STRUCT_CASE) 2771 #undef MAKE_STRUCT_CASE 2772 case CODE_TYPE: { 2773 Code* code = Code::cast(this); 2774 os << "<Code: " << Code::Kind2String(code->kind()) << ">"; 2775 break; 2776 } 2777 case ODDBALL_TYPE: { 2778 if (IsUndefined(isolate)) { 2779 os << "<undefined>"; 2780 } else if (IsTheHole(isolate)) { 2781 os << "<the hole>"; 2782 } else if (IsNull(isolate)) { 2783 os << "<null>"; 2784 } else if (IsTrue(isolate)) { 2785 os << "<true>"; 2786 } else if (IsFalse(isolate)) { 2787 os << "<false>"; 2788 } else { 2789 os << "<Odd Oddball: "; 2790 os << Oddball::cast(this)->to_string()->ToCString().get(); 2791 os << ">"; 2792 } 2793 break; 2794 } 2795 case SYMBOL_TYPE: { 2796 Symbol* symbol = Symbol::cast(this); 2797 symbol->SymbolShortPrint(os); 2798 break; 2799 } 2800 case HEAP_NUMBER_TYPE: { 2801 os << "<Number: "; 2802 HeapNumber::cast(this)->HeapNumberPrint(os); 2803 os << ">"; 2804 break; 2805 } 2806 case MUTABLE_HEAP_NUMBER_TYPE: { 2807 os << "<MutableNumber: "; 2808 HeapNumber::cast(this)->HeapNumberPrint(os); 2809 os << '>'; 2810 break; 2811 } 2812 case SIMD128_VALUE_TYPE: { 2813 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 2814 if (Is##Type()) { \ 2815 os << "<" #Type ">"; \ 2816 break; \ 2817 } 2818 SIMD128_TYPES(SIMD128_TYPE) 2819 #undef SIMD128_TYPE 2820 UNREACHABLE(); 2821 break; 2822 } 2823 case JS_PROXY_TYPE: 2824 os << "<JSProxy>"; 2825 break; 2826 case FOREIGN_TYPE: 2827 os << "<Foreign>"; 2828 break; 2829 case CELL_TYPE: { 2830 os << "Cell for "; 2831 HeapStringAllocator allocator; 2832 StringStream accumulator(&allocator); 2833 Cell::cast(this)->value()->ShortPrint(&accumulator); 2834 os << accumulator.ToCString().get(); 2835 break; 2836 } 2837 case PROPERTY_CELL_TYPE: { 2838 os << "PropertyCell for "; 2839 HeapStringAllocator allocator; 2840 StringStream accumulator(&allocator); 2841 PropertyCell* cell = PropertyCell::cast(this); 2842 cell->value()->ShortPrint(&accumulator); 2843 os << accumulator.ToCString().get(); 2844 break; 2845 } 2846 case WEAK_CELL_TYPE: { 2847 os << "WeakCell for "; 2848 HeapStringAllocator allocator; 2849 StringStream accumulator(&allocator); 2850 WeakCell::cast(this)->value()->ShortPrint(&accumulator); 2851 os << accumulator.ToCString().get(); 2852 break; 2853 } 2854 default: 2855 os << "<Other heap object (" << map()->instance_type() << ")>"; 2856 break; 2857 } 2858 } 2859 2860 2861 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); } 2862 2863 2864 void HeapObject::IterateBody(ObjectVisitor* v) { 2865 Map* m = map(); 2866 IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v); 2867 } 2868 2869 2870 void HeapObject::IterateBody(InstanceType type, int object_size, 2871 ObjectVisitor* v) { 2872 IterateBodyFast<ObjectVisitor>(type, object_size, v); 2873 } 2874 2875 2876 struct CallIsValidSlot { 2877 template <typename BodyDescriptor> 2878 static bool apply(HeapObject* obj, int offset, int) { 2879 return BodyDescriptor::IsValidSlot(obj, offset); 2880 } 2881 }; 2882 2883 2884 bool HeapObject::IsValidSlot(int offset) { 2885 DCHECK_NE(0, offset); 2886 return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(), 2887 this, offset, 0); 2888 } 2889 2890 2891 bool HeapNumber::HeapNumberBooleanValue() { 2892 return DoubleToBoolean(value()); 2893 } 2894 2895 2896 void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT 2897 os << value(); 2898 } 2899 2900 2901 #define FIELD_ADDR_CONST(p, offset) \ 2902 (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag) 2903 2904 #define READ_INT32_FIELD(p, offset) \ 2905 (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset))) 2906 2907 #define READ_INT64_FIELD(p, offset) \ 2908 (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset))) 2909 2910 #define READ_BYTE_FIELD(p, offset) \ 2911 (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset))) 2912 2913 2914 // static 2915 Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) { 2916 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 2917 if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input)); 2918 SIMD128_TYPES(SIMD128_TYPE) 2919 #undef SIMD128_TYPE 2920 UNREACHABLE(); 2921 return Handle<String>::null(); 2922 } 2923 2924 2925 // static 2926 Handle<String> Float32x4::ToString(Handle<Float32x4> input) { 2927 Isolate* const isolate = input->GetIsolate(); 2928 char arr[100]; 2929 Vector<char> buffer(arr, arraysize(arr)); 2930 std::ostringstream os; 2931 os << "SIMD.Float32x4(" 2932 << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", " 2933 << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", " 2934 << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", " 2935 << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")"; 2936 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); 2937 } 2938 2939 2940 #define SIMD128_BOOL_TO_STRING(Type, lane_count) \ 2941 Handle<String> Type::ToString(Handle<Type> input) { \ 2942 Isolate* const isolate = input->GetIsolate(); \ 2943 std::ostringstream os; \ 2944 os << "SIMD." #Type "("; \ 2945 os << (input->get_lane(0) ? "true" : "false"); \ 2946 for (int i = 1; i < lane_count; i++) { \ 2947 os << ", " << (input->get_lane(i) ? "true" : "false"); \ 2948 } \ 2949 os << ")"; \ 2950 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \ 2951 } 2952 SIMD128_BOOL_TO_STRING(Bool32x4, 4) 2953 SIMD128_BOOL_TO_STRING(Bool16x8, 8) 2954 SIMD128_BOOL_TO_STRING(Bool8x16, 16) 2955 #undef SIMD128_BOOL_TO_STRING 2956 2957 2958 #define SIMD128_INT_TO_STRING(Type, lane_count) \ 2959 Handle<String> Type::ToString(Handle<Type> input) { \ 2960 Isolate* const isolate = input->GetIsolate(); \ 2961 char arr[100]; \ 2962 Vector<char> buffer(arr, arraysize(arr)); \ 2963 std::ostringstream os; \ 2964 os << "SIMD." #Type "("; \ 2965 os << IntToCString(input->get_lane(0), buffer); \ 2966 for (int i = 1; i < lane_count; i++) { \ 2967 os << ", " << IntToCString(input->get_lane(i), buffer); \ 2968 } \ 2969 os << ")"; \ 2970 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \ 2971 } 2972 SIMD128_INT_TO_STRING(Int32x4, 4) 2973 SIMD128_INT_TO_STRING(Uint32x4, 4) 2974 SIMD128_INT_TO_STRING(Int16x8, 8) 2975 SIMD128_INT_TO_STRING(Uint16x8, 8) 2976 SIMD128_INT_TO_STRING(Int8x16, 16) 2977 SIMD128_INT_TO_STRING(Uint8x16, 16) 2978 #undef SIMD128_INT_TO_STRING 2979 2980 2981 bool Simd128Value::BitwiseEquals(const Simd128Value* other) const { 2982 return READ_INT64_FIELD(this, kValueOffset) == 2983 READ_INT64_FIELD(other, kValueOffset) && 2984 READ_INT64_FIELD(this, kValueOffset + kInt64Size) == 2985 READ_INT64_FIELD(other, kValueOffset + kInt64Size); 2986 } 2987 2988 2989 uint32_t Simd128Value::Hash() const { 2990 uint32_t seed = v8::internal::kZeroHashSeed; 2991 uint32_t hash; 2992 hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed); 2993 hash = ComputeIntegerHash( 2994 READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31); 2995 hash = ComputeIntegerHash( 2996 READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31); 2997 hash = ComputeIntegerHash( 2998 READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31); 2999 return hash; 3000 } 3001 3002 3003 void Simd128Value::CopyBits(void* destination) const { 3004 memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size); 3005 } 3006 3007 3008 String* JSReceiver::class_name() { 3009 if (IsFunction()) { 3010 return GetHeap()->Function_string(); 3011 } 3012 Object* maybe_constructor = map()->GetConstructor(); 3013 if (maybe_constructor->IsJSFunction()) { 3014 JSFunction* constructor = JSFunction::cast(maybe_constructor); 3015 return String::cast(constructor->shared()->instance_class_name()); 3016 } 3017 // If the constructor is not present, return "Object". 3018 return GetHeap()->Object_string(); 3019 } 3020 3021 3022 // static 3023 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) { 3024 Isolate* isolate = receiver->GetIsolate(); 3025 3026 // If the object was instantiated simply with base == new.target, the 3027 // constructor on the map provides the most accurate name. 3028 // Don't provide the info for prototypes, since their constructors are 3029 // reclaimed and replaced by Object in OptimizeAsPrototype. 3030 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() && 3031 !receiver->map()->is_prototype_map()) { 3032 Object* maybe_constructor = receiver->map()->GetConstructor(); 3033 if (maybe_constructor->IsJSFunction()) { 3034 JSFunction* constructor = JSFunction::cast(maybe_constructor); 3035 String* name = String::cast(constructor->shared()->name()); 3036 if (name->length() == 0) name = constructor->shared()->inferred_name(); 3037 if (name->length() != 0 && 3038 !name->Equals(isolate->heap()->Object_string())) { 3039 return handle(name, isolate); 3040 } 3041 } 3042 } 3043 3044 Handle<Object> maybe_tag = JSReceiver::GetDataProperty( 3045 receiver, isolate->factory()->to_string_tag_symbol()); 3046 if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag); 3047 3048 PrototypeIterator iter(isolate, receiver); 3049 if (iter.IsAtEnd()) return handle(receiver->class_name()); 3050 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter); 3051 LookupIterator it(receiver, isolate->factory()->constructor_string(), start, 3052 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); 3053 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it); 3054 Handle<String> result = isolate->factory()->Object_string(); 3055 if (maybe_constructor->IsJSFunction()) { 3056 JSFunction* constructor = JSFunction::cast(*maybe_constructor); 3057 String* name = String::cast(constructor->shared()->name()); 3058 if (name->length() == 0) name = constructor->shared()->inferred_name(); 3059 if (name->length() > 0) result = handle(name, isolate); 3060 } 3061 3062 return result.is_identical_to(isolate->factory()->Object_string()) 3063 ? handle(receiver->class_name()) 3064 : result; 3065 } 3066 3067 3068 Context* JSReceiver::GetCreationContext() { 3069 JSReceiver* receiver = this; 3070 while (receiver->IsJSBoundFunction()) { 3071 receiver = JSBoundFunction::cast(receiver)->bound_target_function(); 3072 } 3073 Object* constructor = receiver->map()->GetConstructor(); 3074 JSFunction* function; 3075 if (constructor->IsJSFunction()) { 3076 function = JSFunction::cast(constructor); 3077 } else { 3078 // Functions have null as a constructor, 3079 // but any JSFunction knows its context immediately. 3080 CHECK(receiver->IsJSFunction()); 3081 function = JSFunction::cast(receiver); 3082 } 3083 3084 return function->context()->native_context(); 3085 } 3086 3087 static Handle<Object> WrapType(Handle<FieldType> type) { 3088 if (type->IsClass()) return Map::WeakCellForMap(type->AsClass()); 3089 return type; 3090 } 3091 3092 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name, 3093 Handle<FieldType> type, 3094 PropertyAttributes attributes, 3095 Representation representation, 3096 TransitionFlag flag) { 3097 DCHECK(DescriptorArray::kNotFound == 3098 map->instance_descriptors()->Search( 3099 *name, map->NumberOfOwnDescriptors())); 3100 3101 // Ensure the descriptor array does not get too big. 3102 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { 3103 return MaybeHandle<Map>(); 3104 } 3105 3106 Isolate* isolate = map->GetIsolate(); 3107 3108 // Compute the new index for new field. 3109 int index = map->NextFreePropertyIndex(); 3110 3111 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) { 3112 representation = Representation::Tagged(); 3113 type = FieldType::Any(isolate); 3114 } 3115 3116 Handle<Object> wrapped_type(WrapType(type)); 3117 3118 DataDescriptor new_field_desc(name, index, wrapped_type, attributes, 3119 representation); 3120 Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag); 3121 int unused_property_fields = new_map->unused_property_fields() - 1; 3122 if (unused_property_fields < 0) { 3123 unused_property_fields += JSObject::kFieldsAdded; 3124 } 3125 new_map->set_unused_property_fields(unused_property_fields); 3126 return new_map; 3127 } 3128 3129 3130 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map, 3131 Handle<Name> name, 3132 Handle<Object> constant, 3133 PropertyAttributes attributes, 3134 TransitionFlag flag) { 3135 // Ensure the descriptor array does not get too big. 3136 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { 3137 return MaybeHandle<Map>(); 3138 } 3139 3140 // Allocate new instance descriptors with (name, constant) added. 3141 DataConstantDescriptor new_constant_desc(name, constant, attributes); 3142 return Map::CopyAddDescriptor(map, &new_constant_desc, flag); 3143 } 3144 3145 const char* Representation::Mnemonic() const { 3146 switch (kind_) { 3147 case kNone: return "v"; 3148 case kTagged: return "t"; 3149 case kSmi: return "s"; 3150 case kDouble: return "d"; 3151 case kInteger32: return "i"; 3152 case kHeapObject: return "h"; 3153 case kExternal: return "x"; 3154 default: 3155 UNREACHABLE(); 3156 return NULL; 3157 } 3158 } 3159 3160 bool Map::InstancesNeedRewriting(Map* target) { 3161 int target_number_of_fields = target->NumberOfFields(); 3162 int target_inobject = target->GetInObjectProperties(); 3163 int target_unused = target->unused_property_fields(); 3164 int old_number_of_fields; 3165 3166 return InstancesNeedRewriting(target, target_number_of_fields, 3167 target_inobject, target_unused, 3168 &old_number_of_fields); 3169 } 3170 3171 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields, 3172 int target_inobject, int target_unused, 3173 int* old_number_of_fields) { 3174 // If fields were added (or removed), rewrite the instance. 3175 *old_number_of_fields = NumberOfFields(); 3176 DCHECK(target_number_of_fields >= *old_number_of_fields); 3177 if (target_number_of_fields != *old_number_of_fields) return true; 3178 3179 // If smi descriptors were replaced by double descriptors, rewrite. 3180 DescriptorArray* old_desc = instance_descriptors(); 3181 DescriptorArray* new_desc = target->instance_descriptors(); 3182 int limit = NumberOfOwnDescriptors(); 3183 for (int i = 0; i < limit; i++) { 3184 if (new_desc->GetDetails(i).representation().IsDouble() != 3185 old_desc->GetDetails(i).representation().IsDouble()) { 3186 return true; 3187 } 3188 } 3189 3190 // If no fields were added, and no inobject properties were removed, setting 3191 // the map is sufficient. 3192 if (target_inobject == GetInObjectProperties()) return false; 3193 // In-object slack tracking may have reduced the object size of the new map. 3194 // In that case, succeed if all existing fields were inobject, and they still 3195 // fit within the new inobject size. 3196 DCHECK(target_inobject < GetInObjectProperties()); 3197 if (target_number_of_fields <= target_inobject) { 3198 DCHECK(target_number_of_fields + target_unused == target_inobject); 3199 return false; 3200 } 3201 // Otherwise, properties will need to be moved to the backing store. 3202 return true; 3203 } 3204 3205 3206 // static 3207 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map, 3208 Handle<Map> new_map, 3209 Isolate* isolate) { 3210 DCHECK(old_map->is_prototype_map()); 3211 DCHECK(new_map->is_prototype_map()); 3212 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate); 3213 new_map->set_prototype_info(old_map->prototype_info()); 3214 old_map->set_prototype_info(Smi::kZero); 3215 if (FLAG_trace_prototype_users) { 3216 PrintF("Moving prototype_info %p from map %p to map %p.\n", 3217 reinterpret_cast<void*>(new_map->prototype_info()), 3218 reinterpret_cast<void*>(*old_map), 3219 reinterpret_cast<void*>(*new_map)); 3220 } 3221 if (was_registered) { 3222 if (new_map->prototype_info()->IsPrototypeInfo()) { 3223 // The new map isn't registered with its prototype yet; reflect this fact 3224 // in the PrototypeInfo it just inherited from the old map. 3225 PrototypeInfo::cast(new_map->prototype_info()) 3226 ->set_registry_slot(PrototypeInfo::UNREGISTERED); 3227 } 3228 JSObject::LazyRegisterPrototypeUser(new_map, isolate); 3229 } 3230 } 3231 3232 namespace { 3233 // To migrate a fast instance to a fast map: 3234 // - First check whether the instance needs to be rewritten. If not, simply 3235 // change the map. 3236 // - Otherwise, allocate a fixed array large enough to hold all fields, in 3237 // addition to unused space. 3238 // - Copy all existing properties in, in the following order: backing store 3239 // properties, unused fields, inobject properties. 3240 // - If all allocation succeeded, commit the state atomically: 3241 // * Copy inobject properties from the backing store back into the object. 3242 // * Trim the difference in instance size of the object. This also cleanly 3243 // frees inobject properties that moved to the backing store. 3244 // * If there are properties left in the backing store, trim of the space used 3245 // to temporarily store the inobject properties. 3246 // * If there are properties left in the backing store, install the backing 3247 // store. 3248 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { 3249 Isolate* isolate = object->GetIsolate(); 3250 Handle<Map> old_map(object->map()); 3251 // In case of a regular transition. 3252 if (new_map->GetBackPointer() == *old_map) { 3253 // If the map does not add named properties, simply set the map. 3254 if (old_map->NumberOfOwnDescriptors() == 3255 new_map->NumberOfOwnDescriptors()) { 3256 object->synchronized_set_map(*new_map); 3257 return; 3258 } 3259 3260 PropertyDetails details = new_map->GetLastDescriptorDetails(); 3261 // Either new_map adds an kDescriptor property, or a kField property for 3262 // which there is still space, and which does not require a mutable double 3263 // box (an out-of-object double). 3264 if (details.location() == kDescriptor || 3265 (old_map->unused_property_fields() > 0 && 3266 ((FLAG_unbox_double_fields && object->properties()->length() == 0) || 3267 !details.representation().IsDouble()))) { 3268 object->synchronized_set_map(*new_map); 3269 return; 3270 } 3271 3272 // If there is still space in the object, we need to allocate a mutable 3273 // double box. 3274 if (old_map->unused_property_fields() > 0) { 3275 FieldIndex index = 3276 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded()); 3277 DCHECK(details.representation().IsDouble()); 3278 DCHECK(!new_map->IsUnboxedDoubleField(index)); 3279 Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE); 3280 object->RawFastPropertyAtPut(index, *value); 3281 object->synchronized_set_map(*new_map); 3282 return; 3283 } 3284 3285 // This migration is a transition from a map that has run out of property 3286 // space. Extend the backing store. 3287 int grow_by = new_map->unused_property_fields() + 1; 3288 Handle<FixedArray> old_storage = handle(object->properties(), isolate); 3289 Handle<FixedArray> new_storage = 3290 isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by); 3291 3292 // Properly initialize newly added property. 3293 Handle<Object> value; 3294 if (details.representation().IsDouble()) { 3295 value = isolate->factory()->NewHeapNumber(0, MUTABLE); 3296 } else { 3297 value = isolate->factory()->uninitialized_value(); 3298 } 3299 DCHECK_EQ(DATA, details.type()); 3300 int target_index = details.field_index() - new_map->GetInObjectProperties(); 3301 DCHECK(target_index >= 0); // Must be a backing store index. 3302 new_storage->set(target_index, *value); 3303 3304 // From here on we cannot fail and we shouldn't GC anymore. 3305 DisallowHeapAllocation no_allocation; 3306 3307 // Set the new property value and do the map transition. 3308 object->set_properties(*new_storage); 3309 object->synchronized_set_map(*new_map); 3310 return; 3311 } 3312 3313 int old_number_of_fields; 3314 int number_of_fields = new_map->NumberOfFields(); 3315 int inobject = new_map->GetInObjectProperties(); 3316 int unused = new_map->unused_property_fields(); 3317 3318 // Nothing to do if no functions were converted to fields and no smis were 3319 // converted to doubles. 3320 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject, 3321 unused, &old_number_of_fields)) { 3322 object->synchronized_set_map(*new_map); 3323 return; 3324 } 3325 3326 int total_size = number_of_fields + unused; 3327 int external = total_size - inobject; 3328 3329 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size); 3330 3331 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); 3332 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors()); 3333 int old_nof = old_map->NumberOfOwnDescriptors(); 3334 int new_nof = new_map->NumberOfOwnDescriptors(); 3335 3336 // This method only supports generalizing instances to at least the same 3337 // number of properties. 3338 DCHECK(old_nof <= new_nof); 3339 3340 for (int i = 0; i < old_nof; i++) { 3341 PropertyDetails details = new_descriptors->GetDetails(i); 3342 if (details.type() != DATA) continue; 3343 PropertyDetails old_details = old_descriptors->GetDetails(i); 3344 Representation old_representation = old_details.representation(); 3345 Representation representation = details.representation(); 3346 Handle<Object> value; 3347 if (old_details.type() == ACCESSOR_CONSTANT) { 3348 // In case of kAccessor -> kData property reconfiguration, the property 3349 // must already be prepared for data or certain type. 3350 DCHECK(!details.representation().IsNone()); 3351 if (details.representation().IsDouble()) { 3352 value = isolate->factory()->NewHeapNumber(0, MUTABLE); 3353 } else { 3354 value = isolate->factory()->uninitialized_value(); 3355 } 3356 } else if (old_details.type() == DATA_CONSTANT) { 3357 value = handle(old_descriptors->GetValue(i), isolate); 3358 DCHECK(!old_representation.IsDouble() && !representation.IsDouble()); 3359 } else { 3360 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i); 3361 if (object->IsUnboxedDoubleField(index)) { 3362 double old = object->RawFastDoublePropertyAt(index); 3363 value = isolate->factory()->NewHeapNumber( 3364 old, representation.IsDouble() ? MUTABLE : IMMUTABLE); 3365 3366 } else { 3367 value = handle(object->RawFastPropertyAt(index), isolate); 3368 if (!old_representation.IsDouble() && representation.IsDouble()) { 3369 if (old_representation.IsNone()) { 3370 value = handle(Smi::kZero, isolate); 3371 } 3372 value = Object::NewStorageFor(isolate, value, representation); 3373 } else if (old_representation.IsDouble() && 3374 !representation.IsDouble()) { 3375 value = Object::WrapForRead(isolate, value, old_representation); 3376 } 3377 } 3378 } 3379 DCHECK(!(representation.IsDouble() && value->IsSmi())); 3380 int target_index = new_descriptors->GetFieldIndex(i) - inobject; 3381 if (target_index < 0) target_index += total_size; 3382 array->set(target_index, *value); 3383 } 3384 3385 for (int i = old_nof; i < new_nof; i++) { 3386 PropertyDetails details = new_descriptors->GetDetails(i); 3387 if (details.type() != DATA) continue; 3388 Handle<Object> value; 3389 if (details.representation().IsDouble()) { 3390 value = isolate->factory()->NewHeapNumber(0, MUTABLE); 3391 } else { 3392 value = isolate->factory()->uninitialized_value(); 3393 } 3394 int target_index = new_descriptors->GetFieldIndex(i) - inobject; 3395 if (target_index < 0) target_index += total_size; 3396 array->set(target_index, *value); 3397 } 3398 3399 // From here on we cannot fail and we shouldn't GC anymore. 3400 DisallowHeapAllocation no_allocation; 3401 3402 Heap* heap = isolate->heap(); 3403 3404 // Copy (real) inobject properties. If necessary, stop at number_of_fields to 3405 // avoid overwriting |one_pointer_filler_map|. 3406 int limit = Min(inobject, number_of_fields); 3407 for (int i = 0; i < limit; i++) { 3408 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); 3409 Object* value = array->get(external + i); 3410 // Can't use JSObject::FastPropertyAtPut() because proper map was not set 3411 // yet. 3412 if (new_map->IsUnboxedDoubleField(index)) { 3413 DCHECK(value->IsMutableHeapNumber()); 3414 object->RawFastDoublePropertyAtPut(index, 3415 HeapNumber::cast(value)->value()); 3416 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) { 3417 // Transition from tagged to untagged slot. 3418 heap->ClearRecordedSlot(*object, 3419 HeapObject::RawField(*object, index.offset())); 3420 } 3421 } else { 3422 object->RawFastPropertyAtPut(index, value); 3423 } 3424 } 3425 3426 3427 // If there are properties in the new backing store, trim it to the correct 3428 // size and install the backing store into the object. 3429 if (external > 0) { 3430 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, inobject); 3431 object->set_properties(*array); 3432 } 3433 3434 // Create filler object past the new instance size. 3435 int new_instance_size = new_map->instance_size(); 3436 int instance_size_delta = old_map->instance_size() - new_instance_size; 3437 DCHECK(instance_size_delta >= 0); 3438 3439 if (instance_size_delta > 0) { 3440 Address address = object->address(); 3441 heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta, 3442 ClearRecordedSlots::kYes); 3443 heap->AdjustLiveBytes(*object, -instance_size_delta, 3444 Heap::CONCURRENT_TO_SWEEPER); 3445 } 3446 3447 // We are storing the new map using release store after creating a filler for 3448 // the left-over space to avoid races with the sweeper thread. 3449 object->synchronized_set_map(*new_map); 3450 } 3451 3452 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map, 3453 int expected_additional_properties) { 3454 // The global object is always normalized. 3455 DCHECK(!object->IsJSGlobalObject()); 3456 // JSGlobalProxy must never be normalized 3457 DCHECK(!object->IsJSGlobalProxy()); 3458 3459 Isolate* isolate = object->GetIsolate(); 3460 HandleScope scope(isolate); 3461 Handle<Map> map(object->map()); 3462 3463 // Allocate new content. 3464 int real_size = map->NumberOfOwnDescriptors(); 3465 int property_count = real_size; 3466 if (expected_additional_properties > 0) { 3467 property_count += expected_additional_properties; 3468 } else { 3469 // Make space for two more properties. 3470 property_count += NameDictionary::kInitialCapacity; 3471 } 3472 Handle<NameDictionary> dictionary = 3473 NameDictionary::New(isolate, property_count); 3474 3475 Handle<DescriptorArray> descs(map->instance_descriptors()); 3476 for (int i = 0; i < real_size; i++) { 3477 PropertyDetails details = descs->GetDetails(i); 3478 Handle<Name> key(descs->GetKey(i)); 3479 switch (details.type()) { 3480 case DATA_CONSTANT: { 3481 Handle<Object> value(descs->GetConstant(i), isolate); 3482 PropertyDetails d(details.attributes(), DATA, i + 1, 3483 PropertyCellType::kNoCell); 3484 dictionary = NameDictionary::Add(dictionary, key, value, d); 3485 break; 3486 } 3487 case DATA: { 3488 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 3489 Handle<Object> value; 3490 if (object->IsUnboxedDoubleField(index)) { 3491 double old_value = object->RawFastDoublePropertyAt(index); 3492 value = isolate->factory()->NewHeapNumber(old_value); 3493 } else { 3494 value = handle(object->RawFastPropertyAt(index), isolate); 3495 if (details.representation().IsDouble()) { 3496 DCHECK(value->IsMutableHeapNumber()); 3497 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value); 3498 value = isolate->factory()->NewHeapNumber(old->value()); 3499 } 3500 } 3501 PropertyDetails d(details.attributes(), DATA, i + 1, 3502 PropertyCellType::kNoCell); 3503 dictionary = NameDictionary::Add(dictionary, key, value, d); 3504 break; 3505 } 3506 case ACCESSOR: { 3507 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 3508 Handle<Object> value(object->RawFastPropertyAt(index), isolate); 3509 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1, 3510 PropertyCellType::kNoCell); 3511 dictionary = NameDictionary::Add(dictionary, key, value, d); 3512 break; 3513 } 3514 case ACCESSOR_CONSTANT: { 3515 Handle<Object> value(descs->GetCallbacksObject(i), isolate); 3516 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1, 3517 PropertyCellType::kNoCell); 3518 dictionary = NameDictionary::Add(dictionary, key, value, d); 3519 break; 3520 } 3521 } 3522 } 3523 3524 // Copy the next enumeration index from instance descriptor. 3525 dictionary->SetNextEnumerationIndex(real_size + 1); 3526 3527 // From here on we cannot fail and we shouldn't GC anymore. 3528 DisallowHeapAllocation no_allocation; 3529 3530 // Resize the object in the heap if necessary. 3531 int new_instance_size = new_map->instance_size(); 3532 int instance_size_delta = map->instance_size() - new_instance_size; 3533 DCHECK(instance_size_delta >= 0); 3534 3535 if (instance_size_delta > 0) { 3536 Heap* heap = isolate->heap(); 3537 heap->CreateFillerObjectAt(object->address() + new_instance_size, 3538 instance_size_delta, ClearRecordedSlots::kYes); 3539 heap->AdjustLiveBytes(*object, -instance_size_delta, 3540 Heap::CONCURRENT_TO_SWEEPER); 3541 } 3542 3543 // We are storing the new map using release store after creating a filler for 3544 // the left-over space to avoid races with the sweeper thread. 3545 object->synchronized_set_map(*new_map); 3546 3547 object->set_properties(*dictionary); 3548 3549 // Ensure that in-object space of slow-mode object does not contain random 3550 // garbage. 3551 int inobject_properties = new_map->GetInObjectProperties(); 3552 if (inobject_properties) { 3553 Heap* heap = isolate->heap(); 3554 heap->ClearRecordedSlotRange( 3555 object->address() + map->GetInObjectPropertyOffset(0), 3556 object->address() + new_instance_size); 3557 3558 for (int i = 0; i < inobject_properties; i++) { 3559 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); 3560 object->RawFastPropertyAtPut(index, Smi::kZero); 3561 } 3562 } 3563 3564 isolate->counters()->props_to_dictionary()->Increment(); 3565 3566 #ifdef DEBUG 3567 if (FLAG_trace_normalization) { 3568 OFStream os(stdout); 3569 os << "Object properties have been normalized:\n"; 3570 object->Print(os); 3571 } 3572 #endif 3573 } 3574 3575 } // namespace 3576 3577 // static 3578 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map, 3579 Isolate* isolate) { 3580 if (!old_map->is_prototype_map()) return; 3581 3582 InvalidatePrototypeChains(*old_map); 3583 3584 // If the map was registered with its prototype before, ensure that it 3585 // registers with its new prototype now. This preserves the invariant that 3586 // when a map on a prototype chain is registered with its prototype, then 3587 // all prototypes further up the chain are also registered with their 3588 // respective prototypes. 3589 UpdatePrototypeUserRegistration(old_map, new_map, isolate); 3590 } 3591 3592 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, 3593 int expected_additional_properties) { 3594 if (object->map() == *new_map) return; 3595 Handle<Map> old_map(object->map()); 3596 NotifyMapChange(old_map, new_map, new_map->GetIsolate()); 3597 3598 if (old_map->is_dictionary_map()) { 3599 // For slow-to-fast migrations JSObject::MigrateSlowToFast() 3600 // must be used instead. 3601 CHECK(new_map->is_dictionary_map()); 3602 3603 // Slow-to-slow migration is trivial. 3604 object->set_map(*new_map); 3605 } else if (!new_map->is_dictionary_map()) { 3606 MigrateFastToFast(object, new_map); 3607 if (old_map->is_prototype_map()) { 3608 DCHECK(!old_map->is_stable()); 3609 DCHECK(new_map->is_stable()); 3610 // Clear out the old descriptor array to avoid problems to sharing 3611 // the descriptor array without using an explicit. 3612 old_map->InitializeDescriptors( 3613 old_map->GetHeap()->empty_descriptor_array(), 3614 LayoutDescriptor::FastPointerLayout()); 3615 // Ensure that no transition was inserted for prototype migrations. 3616 DCHECK_EQ( 3617 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions())); 3618 DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate())); 3619 } 3620 } else { 3621 MigrateFastToSlow(object, new_map, expected_additional_properties); 3622 } 3623 3624 // Careful: Don't allocate here! 3625 // For some callers of this method, |object| might be in an inconsistent 3626 // state now: the new map might have a new elements_kind, but the object's 3627 // elements pointer hasn't been updated yet. Callers will fix this, but in 3628 // the meantime, (indirectly) calling JSObjectVerify() must be avoided. 3629 // When adding code here, add a DisallowHeapAllocation too. 3630 } 3631 3632 void JSObject::ForceSetPrototype(Handle<JSObject> object, 3633 Handle<Object> proto) { 3634 // object.__proto__ = proto; 3635 Handle<Map> old_map = Handle<Map>(object->map()); 3636 Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype"); 3637 Map::SetPrototype(new_map, proto, FAST_PROTOTYPE); 3638 JSObject::MigrateToMap(object, new_map); 3639 } 3640 3641 int Map::NumberOfFields() { 3642 DescriptorArray* descriptors = instance_descriptors(); 3643 int result = 0; 3644 for (int i = 0; i < NumberOfOwnDescriptors(); i++) { 3645 if (descriptors->GetDetails(i).location() == kField) result++; 3646 } 3647 return result; 3648 } 3649 3650 Handle<Map> Map::CopyGeneralizeAllRepresentations( 3651 Handle<Map> map, ElementsKind elements_kind, int modify_index, 3652 StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes, 3653 const char* reason) { 3654 Isolate* isolate = map->GetIsolate(); 3655 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 3656 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 3657 Handle<DescriptorArray> descriptors = 3658 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors); 3659 3660 for (int i = 0; i < number_of_own_descriptors; i++) { 3661 descriptors->SetRepresentation(i, Representation::Tagged()); 3662 if (descriptors->GetDetails(i).type() == DATA) { 3663 descriptors->SetValue(i, FieldType::Any()); 3664 } 3665 } 3666 3667 Handle<LayoutDescriptor> new_layout_descriptor( 3668 LayoutDescriptor::FastPointerLayout(), isolate); 3669 Handle<Map> new_map = CopyReplaceDescriptors( 3670 map, descriptors, new_layout_descriptor, OMIT_TRANSITION, 3671 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION); 3672 3673 // Unless the instance is being migrated, ensure that modify_index is a field. 3674 if (modify_index >= 0) { 3675 PropertyDetails details = descriptors->GetDetails(modify_index); 3676 if (store_mode == FORCE_FIELD && 3677 (details.type() != DATA || details.attributes() != attributes)) { 3678 int field_index = details.type() == DATA ? details.field_index() 3679 : new_map->NumberOfFields(); 3680 DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate), 3681 field_index, attributes, Representation::Tagged()); 3682 descriptors->Replace(modify_index, &d); 3683 if (details.type() != DATA) { 3684 int unused_property_fields = new_map->unused_property_fields() - 1; 3685 if (unused_property_fields < 0) { 3686 unused_property_fields += JSObject::kFieldsAdded; 3687 } 3688 new_map->set_unused_property_fields(unused_property_fields); 3689 } 3690 } else { 3691 DCHECK(details.attributes() == attributes); 3692 } 3693 3694 if (FLAG_trace_generalization) { 3695 MaybeHandle<FieldType> field_type = FieldType::None(isolate); 3696 if (details.type() == DATA) { 3697 field_type = handle( 3698 map->instance_descriptors()->GetFieldType(modify_index), isolate); 3699 } 3700 map->PrintGeneralization( 3701 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(), 3702 new_map->NumberOfOwnDescriptors(), 3703 details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD, 3704 details.representation(), Representation::Tagged(), field_type, 3705 MaybeHandle<Object>(), FieldType::Any(isolate), 3706 MaybeHandle<Object>()); 3707 } 3708 } 3709 new_map->set_elements_kind(elements_kind); 3710 return new_map; 3711 } 3712 3713 3714 void Map::DeprecateTransitionTree() { 3715 if (is_deprecated()) return; 3716 Object* transitions = raw_transitions(); 3717 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 3718 for (int i = 0; i < num_transitions; ++i) { 3719 TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree(); 3720 } 3721 deprecate(); 3722 dependent_code()->DeoptimizeDependentCodeGroup( 3723 GetIsolate(), DependentCode::kTransitionGroup); 3724 NotifyLeafMapLayoutChange(); 3725 } 3726 3727 3728 static inline bool EqualImmutableValues(Object* obj1, Object* obj2) { 3729 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds. 3730 // TODO(ishell): compare AccessorPairs. 3731 return false; 3732 } 3733 3734 3735 // Installs |new_descriptors| over the current instance_descriptors to ensure 3736 // proper sharing of descriptor arrays. 3737 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors, 3738 LayoutDescriptor* new_layout_descriptor) { 3739 Isolate* isolate = GetIsolate(); 3740 // Don't overwrite the empty descriptor array or initial map's descriptors. 3741 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) { 3742 return; 3743 } 3744 3745 DescriptorArray* to_replace = instance_descriptors(); 3746 isolate->heap()->incremental_marking()->IterateBlackObject(to_replace); 3747 Map* current = this; 3748 while (current->instance_descriptors() == to_replace) { 3749 Object* next = current->GetBackPointer(); 3750 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map. 3751 current->SetEnumLength(kInvalidEnumCacheSentinel); 3752 current->UpdateDescriptors(new_descriptors, new_layout_descriptor); 3753 current = Map::cast(next); 3754 } 3755 set_owns_descriptors(false); 3756 } 3757 3758 3759 Map* Map::FindRootMap() { 3760 Map* result = this; 3761 Isolate* isolate = GetIsolate(); 3762 while (true) { 3763 Object* back = result->GetBackPointer(); 3764 if (back->IsUndefined(isolate)) { 3765 // Initial map always owns descriptors and doesn't have unused entries 3766 // in the descriptor array. 3767 DCHECK(result->owns_descriptors()); 3768 DCHECK_EQ(result->NumberOfOwnDescriptors(), 3769 result->instance_descriptors()->number_of_descriptors()); 3770 return result; 3771 } 3772 result = Map::cast(back); 3773 } 3774 } 3775 3776 3777 Map* Map::FindLastMatchMap(int verbatim, 3778 int length, 3779 DescriptorArray* descriptors) { 3780 DisallowHeapAllocation no_allocation; 3781 3782 // This can only be called on roots of transition trees. 3783 DCHECK_EQ(verbatim, NumberOfOwnDescriptors()); 3784 3785 Map* current = this; 3786 3787 for (int i = verbatim; i < length; i++) { 3788 Name* name = descriptors->GetKey(i); 3789 PropertyDetails details = descriptors->GetDetails(i); 3790 Map* next = TransitionArray::SearchTransition(current, details.kind(), name, 3791 details.attributes()); 3792 if (next == NULL) break; 3793 DescriptorArray* next_descriptors = next->instance_descriptors(); 3794 3795 PropertyDetails next_details = next_descriptors->GetDetails(i); 3796 DCHECK_EQ(details.kind(), next_details.kind()); 3797 DCHECK_EQ(details.attributes(), next_details.attributes()); 3798 if (details.location() != next_details.location()) break; 3799 if (!details.representation().Equals(next_details.representation())) break; 3800 3801 if (next_details.location() == kField) { 3802 FieldType* next_field_type = next_descriptors->GetFieldType(i); 3803 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) { 3804 break; 3805 } 3806 } else { 3807 if (!EqualImmutableValues(descriptors->GetValue(i), 3808 next_descriptors->GetValue(i))) { 3809 break; 3810 } 3811 } 3812 current = next; 3813 } 3814 return current; 3815 } 3816 3817 3818 Map* Map::FindFieldOwner(int descriptor) { 3819 DisallowHeapAllocation no_allocation; 3820 DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type()); 3821 Map* result = this; 3822 Isolate* isolate = GetIsolate(); 3823 while (true) { 3824 Object* back = result->GetBackPointer(); 3825 if (back->IsUndefined(isolate)) break; 3826 Map* parent = Map::cast(back); 3827 if (parent->NumberOfOwnDescriptors() <= descriptor) break; 3828 result = parent; 3829 } 3830 return result; 3831 } 3832 3833 3834 void Map::UpdateFieldType(int descriptor, Handle<Name> name, 3835 Representation new_representation, 3836 Handle<Object> new_wrapped_type) { 3837 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell()); 3838 // We store raw pointers in the queue, so no allocations are allowed. 3839 DisallowHeapAllocation no_allocation; 3840 PropertyDetails details = instance_descriptors()->GetDetails(descriptor); 3841 if (details.type() != DATA) return; 3842 3843 Zone zone(GetIsolate()->allocator(), ZONE_NAME); 3844 ZoneQueue<Map*> backlog(&zone); 3845 backlog.push(this); 3846 3847 while (!backlog.empty()) { 3848 Map* current = backlog.front(); 3849 backlog.pop(); 3850 3851 Object* transitions = current->raw_transitions(); 3852 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 3853 for (int i = 0; i < num_transitions; ++i) { 3854 Map* target = TransitionArray::GetTarget(transitions, i); 3855 backlog.push(target); 3856 } 3857 DescriptorArray* descriptors = current->instance_descriptors(); 3858 PropertyDetails details = descriptors->GetDetails(descriptor); 3859 3860 // It is allowed to change representation here only from None to something. 3861 DCHECK(details.representation().Equals(new_representation) || 3862 details.representation().IsNone()); 3863 3864 // Skip if already updated the shared descriptor. 3865 if (descriptors->GetValue(descriptor) != *new_wrapped_type) { 3866 DataDescriptor d(name, descriptors->GetFieldIndex(descriptor), 3867 new_wrapped_type, details.attributes(), 3868 new_representation); 3869 descriptors->Replace(descriptor, &d); 3870 } 3871 } 3872 } 3873 3874 bool FieldTypeIsCleared(Representation rep, FieldType* type) { 3875 return type->IsNone() && rep.IsHeapObject(); 3876 } 3877 3878 3879 // static 3880 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1, 3881 Handle<FieldType> type1, 3882 Representation rep2, 3883 Handle<FieldType> type2, 3884 Isolate* isolate) { 3885 // Cleared field types need special treatment. They represent lost knowledge, 3886 // so we must be conservative, so their generalization with any other type 3887 // is "Any". 3888 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) { 3889 return FieldType::Any(isolate); 3890 } 3891 if (type1->NowIs(type2)) return type2; 3892 if (type2->NowIs(type1)) return type1; 3893 return FieldType::Any(isolate); 3894 } 3895 3896 3897 // static 3898 void Map::GeneralizeFieldType(Handle<Map> map, int modify_index, 3899 Representation new_representation, 3900 Handle<FieldType> new_field_type) { 3901 Isolate* isolate = map->GetIsolate(); 3902 3903 // Check if we actually need to generalize the field type at all. 3904 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 3905 Representation old_representation = 3906 old_descriptors->GetDetails(modify_index).representation(); 3907 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index), 3908 isolate); 3909 3910 if (old_representation.Equals(new_representation) && 3911 !FieldTypeIsCleared(new_representation, *new_field_type) && 3912 // Checking old_field_type for being cleared is not necessary because 3913 // the NowIs check below would fail anyway in that case. 3914 new_field_type->NowIs(old_field_type)) { 3915 DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type, 3916 new_representation, new_field_type, isolate) 3917 ->NowIs(old_field_type)); 3918 return; 3919 } 3920 3921 // Determine the field owner. 3922 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate); 3923 Handle<DescriptorArray> descriptors( 3924 field_owner->instance_descriptors(), isolate); 3925 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index)); 3926 3927 new_field_type = 3928 Map::GeneralizeFieldType(old_representation, old_field_type, 3929 new_representation, new_field_type, isolate); 3930 3931 PropertyDetails details = descriptors->GetDetails(modify_index); 3932 Handle<Name> name(descriptors->GetKey(modify_index)); 3933 3934 Handle<Object> wrapped_type(WrapType(new_field_type)); 3935 field_owner->UpdateFieldType(modify_index, name, new_representation, 3936 wrapped_type); 3937 field_owner->dependent_code()->DeoptimizeDependentCodeGroup( 3938 isolate, DependentCode::kFieldOwnerGroup); 3939 3940 if (FLAG_trace_generalization) { 3941 map->PrintGeneralization( 3942 stdout, "field type generalization", modify_index, 3943 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false, 3944 details.representation(), details.representation(), old_field_type, 3945 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>()); 3946 } 3947 } 3948 3949 static inline Handle<FieldType> GetFieldType( 3950 Isolate* isolate, Handle<DescriptorArray> descriptors, int descriptor, 3951 PropertyLocation location, Representation representation) { 3952 #ifdef DEBUG 3953 PropertyDetails details = descriptors->GetDetails(descriptor); 3954 DCHECK_EQ(kData, details.kind()); 3955 DCHECK_EQ(details.location(), location); 3956 #endif 3957 if (location == kField) { 3958 return handle(descriptors->GetFieldType(descriptor), isolate); 3959 } else { 3960 return descriptors->GetValue(descriptor) 3961 ->OptimalType(isolate, representation); 3962 } 3963 } 3964 3965 // Reconfigures elements kind to |new_elements_kind| and/or property at 3966 // |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or 3967 // |new_representation|/|new_field_type|. 3968 // If |modify_index| is negative then no properties are reconfigured but the 3969 // map is migrated to the up-to-date non-deprecated state. 3970 // 3971 // This method rewrites or completes the transition tree to reflect the new 3972 // change. To avoid high degrees over polymorphism, and to stabilize quickly, 3973 // on every rewrite the new type is deduced by merging the current type with 3974 // any potential new (partial) version of the type in the transition tree. 3975 // To do this, on each rewrite: 3976 // - Search the root of the transition tree using FindRootMap. 3977 // - Find/create a |root_map| with requested |new_elements_kind|. 3978 // - Find |target_map|, the newest matching version of this map using the 3979 // virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at 3980 // |modify_index| is considered to be of |new_kind| and having 3981 // |new_attributes|) to walk the transition tree. 3982 // - Merge/generalize the "enhanced" descriptor array of the |old_map| and 3983 // descriptor array of the |target_map|. 3984 // - Generalize the |modify_index| descriptor using |new_representation| and 3985 // |new_field_type|. 3986 // - Walk the tree again starting from the root towards |target_map|. Stop at 3987 // |split_map|, the first map who's descriptor array does not match the merged 3988 // descriptor array. 3989 // - If |target_map| == |split_map|, |target_map| is in the expected state. 3990 // Return it. 3991 // - Otherwise, invalidate the outdated transition target from |target_map|, and 3992 // replace its transition tree with a new branch for the updated descriptors. 3993 Handle<Map> Map::Reconfigure(Handle<Map> old_map, 3994 ElementsKind new_elements_kind, int modify_index, 3995 PropertyKind new_kind, 3996 PropertyAttributes new_attributes, 3997 Representation new_representation, 3998 Handle<FieldType> new_field_type, 3999 StoreMode store_mode) { 4000 DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet. 4001 DCHECK(store_mode != FORCE_FIELD || modify_index >= 0); 4002 Isolate* isolate = old_map->GetIsolate(); 4003 4004 Handle<DescriptorArray> old_descriptors( 4005 old_map->instance_descriptors(), isolate); 4006 int old_nof = old_map->NumberOfOwnDescriptors(); 4007 4008 // If it's just a representation generalization case (i.e. property kind and 4009 // attributes stays unchanged) it's fine to transition from None to anything 4010 // but double without any modification to the object, because the default 4011 // uninitialized value for representation None can be overwritten by both 4012 // smi and tagged values. Doubles, however, would require a box allocation. 4013 if (modify_index >= 0 && !new_representation.IsNone() && 4014 !new_representation.IsDouble() && 4015 old_map->elements_kind() == new_elements_kind) { 4016 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); 4017 Representation old_representation = old_details.representation(); 4018 4019 if (old_representation.IsNone()) { 4020 DCHECK_EQ(new_kind, old_details.kind()); 4021 DCHECK_EQ(new_attributes, old_details.attributes()); 4022 DCHECK_EQ(DATA, old_details.type()); 4023 if (FLAG_trace_generalization) { 4024 old_map->PrintGeneralization( 4025 stdout, "uninitialized field", modify_index, 4026 old_map->NumberOfOwnDescriptors(), 4027 old_map->NumberOfOwnDescriptors(), false, old_representation, 4028 new_representation, 4029 handle(old_descriptors->GetFieldType(modify_index), isolate), 4030 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>()); 4031 } 4032 Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate); 4033 4034 GeneralizeFieldType(field_owner, modify_index, new_representation, 4035 new_field_type); 4036 DCHECK(old_descriptors->GetDetails(modify_index) 4037 .representation() 4038 .Equals(new_representation)); 4039 DCHECK( 4040 old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type)); 4041 return old_map; 4042 } 4043 } 4044 4045 // Check the state of the root map. 4046 Handle<Map> root_map(old_map->FindRootMap(), isolate); 4047 if (!old_map->EquivalentToForTransition(*root_map)) { 4048 return CopyGeneralizeAllRepresentations( 4049 old_map, new_elements_kind, modify_index, store_mode, new_kind, 4050 new_attributes, "GenAll_NotEquivalent"); 4051 } 4052 4053 ElementsKind from_kind = root_map->elements_kind(); 4054 ElementsKind to_kind = new_elements_kind; 4055 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS. 4056 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS && 4057 to_kind != SLOW_STRING_WRAPPER_ELEMENTS && 4058 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS && 4059 !(IsTransitionableFastElementsKind(from_kind) && 4060 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) { 4061 return CopyGeneralizeAllRepresentations( 4062 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 4063 "GenAll_InvalidElementsTransition"); 4064 } 4065 int root_nof = root_map->NumberOfOwnDescriptors(); 4066 if (modify_index >= 0 && modify_index < root_nof) { 4067 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); 4068 if (old_details.kind() != new_kind || 4069 old_details.attributes() != new_attributes) { 4070 return CopyGeneralizeAllRepresentations( 4071 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 4072 "GenAll_RootModification1"); 4073 } 4074 if ((old_details.type() != DATA && store_mode == FORCE_FIELD) || 4075 (old_details.type() == DATA && 4076 (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) || 4077 !new_representation.fits_into(old_details.representation())))) { 4078 return CopyGeneralizeAllRepresentations( 4079 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 4080 "GenAll_RootModification2"); 4081 } 4082 } 4083 4084 // From here on, use the map with correct elements kind as root map. 4085 if (from_kind != to_kind) { 4086 root_map = Map::AsElementsKind(root_map, to_kind); 4087 } 4088 4089 Handle<Map> target_map = root_map; 4090 for (int i = root_nof; i < old_nof; ++i) { 4091 PropertyDetails old_details = old_descriptors->GetDetails(i); 4092 PropertyKind next_kind; 4093 PropertyLocation next_location; 4094 PropertyAttributes next_attributes; 4095 Representation next_representation; 4096 bool property_kind_reconfiguration = false; 4097 4098 if (modify_index == i) { 4099 DCHECK_EQ(FORCE_FIELD, store_mode); 4100 property_kind_reconfiguration = old_details.kind() != new_kind; 4101 4102 next_kind = new_kind; 4103 next_location = kField; 4104 next_attributes = new_attributes; 4105 // If property kind is not reconfigured merge the result with 4106 // representation/field type from the old descriptor. 4107 next_representation = new_representation; 4108 if (!property_kind_reconfiguration) { 4109 next_representation = 4110 next_representation.generalize(old_details.representation()); 4111 } 4112 4113 } else { 4114 next_kind = old_details.kind(); 4115 next_location = old_details.location(); 4116 next_attributes = old_details.attributes(); 4117 next_representation = old_details.representation(); 4118 } 4119 Map* transition = TransitionArray::SearchTransition( 4120 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes); 4121 if (transition == NULL) break; 4122 Handle<Map> tmp_map(transition, isolate); 4123 4124 Handle<DescriptorArray> tmp_descriptors = handle( 4125 tmp_map->instance_descriptors(), isolate); 4126 4127 // Check if target map is incompatible. 4128 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); 4129 DCHECK_EQ(next_kind, tmp_details.kind()); 4130 DCHECK_EQ(next_attributes, tmp_details.attributes()); 4131 if (next_kind == kAccessor && 4132 !EqualImmutableValues(old_descriptors->GetValue(i), 4133 tmp_descriptors->GetValue(i))) { 4134 return CopyGeneralizeAllRepresentations( 4135 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 4136 "GenAll_Incompatible"); 4137 } 4138 if (next_location == kField && tmp_details.location() == kDescriptor) break; 4139 4140 Representation tmp_representation = tmp_details.representation(); 4141 if (!next_representation.fits_into(tmp_representation)) break; 4142 4143 PropertyLocation old_location = old_details.location(); 4144 PropertyLocation tmp_location = tmp_details.location(); 4145 if (tmp_location == kField) { 4146 if (next_kind == kData) { 4147 Handle<FieldType> next_field_type; 4148 if (modify_index == i) { 4149 next_field_type = new_field_type; 4150 if (!property_kind_reconfiguration) { 4151 Handle<FieldType> old_field_type = 4152 GetFieldType(isolate, old_descriptors, i, 4153 old_details.location(), tmp_representation); 4154 Representation old_representation = old_details.representation(); 4155 next_field_type = GeneralizeFieldType( 4156 old_representation, old_field_type, new_representation, 4157 next_field_type, isolate); 4158 } 4159 } else { 4160 Handle<FieldType> old_field_type = 4161 GetFieldType(isolate, old_descriptors, i, old_details.location(), 4162 tmp_representation); 4163 next_field_type = old_field_type; 4164 } 4165 GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type); 4166 } 4167 } else if (old_location == kField || 4168 !EqualImmutableValues(old_descriptors->GetValue(i), 4169 tmp_descriptors->GetValue(i))) { 4170 break; 4171 } 4172 DCHECK(!tmp_map->is_deprecated()); 4173 target_map = tmp_map; 4174 } 4175 4176 // Directly change the map if the target map is more general. 4177 Handle<DescriptorArray> target_descriptors( 4178 target_map->instance_descriptors(), isolate); 4179 int target_nof = target_map->NumberOfOwnDescriptors(); 4180 if (target_nof == old_nof && 4181 (store_mode != FORCE_FIELD || 4182 (modify_index >= 0 && 4183 target_descriptors->GetDetails(modify_index).location() == kField))) { 4184 #ifdef DEBUG 4185 if (modify_index >= 0) { 4186 PropertyDetails details = target_descriptors->GetDetails(modify_index); 4187 DCHECK_EQ(new_kind, details.kind()); 4188 DCHECK_EQ(new_attributes, details.attributes()); 4189 DCHECK(new_representation.fits_into(details.representation())); 4190 DCHECK(details.location() != kField || 4191 new_field_type->NowIs( 4192 target_descriptors->GetFieldType(modify_index))); 4193 } 4194 #endif 4195 if (*target_map != *old_map) { 4196 old_map->NotifyLeafMapLayoutChange(); 4197 } 4198 return target_map; 4199 } 4200 4201 // Find the last compatible target map in the transition tree. 4202 for (int i = target_nof; i < old_nof; ++i) { 4203 PropertyDetails old_details = old_descriptors->GetDetails(i); 4204 PropertyKind next_kind; 4205 PropertyAttributes next_attributes; 4206 if (modify_index == i) { 4207 next_kind = new_kind; 4208 next_attributes = new_attributes; 4209 } else { 4210 next_kind = old_details.kind(); 4211 next_attributes = old_details.attributes(); 4212 } 4213 Map* transition = TransitionArray::SearchTransition( 4214 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes); 4215 if (transition == NULL) break; 4216 Handle<Map> tmp_map(transition, isolate); 4217 Handle<DescriptorArray> tmp_descriptors( 4218 tmp_map->instance_descriptors(), isolate); 4219 4220 // Check if target map is compatible. 4221 #ifdef DEBUG 4222 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); 4223 DCHECK_EQ(next_kind, tmp_details.kind()); 4224 DCHECK_EQ(next_attributes, tmp_details.attributes()); 4225 #endif 4226 if (next_kind == kAccessor && 4227 !EqualImmutableValues(old_descriptors->GetValue(i), 4228 tmp_descriptors->GetValue(i))) { 4229 return CopyGeneralizeAllRepresentations( 4230 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 4231 "GenAll_Incompatible"); 4232 } 4233 DCHECK(!tmp_map->is_deprecated()); 4234 target_map = tmp_map; 4235 } 4236 target_nof = target_map->NumberOfOwnDescriptors(); 4237 target_descriptors = handle(target_map->instance_descriptors(), isolate); 4238 4239 // Allocate a new descriptor array large enough to hold the required 4240 // descriptors, with minimally the exact same size as the old descriptor 4241 // array. 4242 int new_slack = Max( 4243 old_nof, old_descriptors->number_of_descriptors()) - old_nof; 4244 Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate( 4245 isolate, old_nof, new_slack); 4246 DCHECK(new_descriptors->length() > target_descriptors->length() || 4247 new_descriptors->NumberOfSlackDescriptors() > 0 || 4248 new_descriptors->number_of_descriptors() == 4249 old_descriptors->number_of_descriptors()); 4250 DCHECK(new_descriptors->number_of_descriptors() == old_nof); 4251 4252 // 0 -> |root_nof| 4253 int current_offset = 0; 4254 for (int i = 0; i < root_nof; ++i) { 4255 PropertyDetails old_details = old_descriptors->GetDetails(i); 4256 if (old_details.location() == kField) { 4257 current_offset += old_details.field_width_in_words(); 4258 } 4259 Descriptor d(handle(old_descriptors->GetKey(i), isolate), 4260 handle(old_descriptors->GetValue(i), isolate), 4261 old_details); 4262 new_descriptors->Set(i, &d); 4263 } 4264 4265 // |root_nof| -> |target_nof| 4266 for (int i = root_nof; i < target_nof; ++i) { 4267 Handle<Name> target_key(target_descriptors->GetKey(i), isolate); 4268 PropertyDetails old_details = old_descriptors->GetDetails(i); 4269 PropertyDetails target_details = target_descriptors->GetDetails(i); 4270 4271 PropertyKind next_kind; 4272 PropertyAttributes next_attributes; 4273 PropertyLocation next_location; 4274 Representation next_representation; 4275 bool property_kind_reconfiguration = false; 4276 4277 if (modify_index == i) { 4278 DCHECK_EQ(FORCE_FIELD, store_mode); 4279 property_kind_reconfiguration = old_details.kind() != new_kind; 4280 4281 next_kind = new_kind; 4282 next_attributes = new_attributes; 4283 next_location = kField; 4284 4285 // Merge new representation/field type with ones from the target 4286 // descriptor. If property kind is not reconfigured merge the result with 4287 // representation/field type from the old descriptor. 4288 next_representation = 4289 new_representation.generalize(target_details.representation()); 4290 if (!property_kind_reconfiguration) { 4291 next_representation = 4292 next_representation.generalize(old_details.representation()); 4293 } 4294 } else { 4295 // Merge old_descriptor and target_descriptor entries. 4296 DCHECK_EQ(target_details.kind(), old_details.kind()); 4297 next_kind = target_details.kind(); 4298 next_attributes = target_details.attributes(); 4299 next_location = 4300 old_details.location() == kField || 4301 target_details.location() == kField || 4302 !EqualImmutableValues(target_descriptors->GetValue(i), 4303 old_descriptors->GetValue(i)) 4304 ? kField 4305 : kDescriptor; 4306 4307 next_representation = old_details.representation().generalize( 4308 target_details.representation()); 4309 } 4310 DCHECK_EQ(next_kind, target_details.kind()); 4311 DCHECK_EQ(next_attributes, target_details.attributes()); 4312 4313 if (next_location == kField) { 4314 if (next_kind == kData) { 4315 Handle<FieldType> target_field_type = 4316 GetFieldType(isolate, target_descriptors, i, 4317 target_details.location(), next_representation); 4318 4319 Handle<FieldType> next_field_type; 4320 if (modify_index == i) { 4321 next_field_type = GeneralizeFieldType( 4322 target_details.representation(), target_field_type, 4323 new_representation, new_field_type, isolate); 4324 if (!property_kind_reconfiguration) { 4325 Handle<FieldType> old_field_type = 4326 GetFieldType(isolate, old_descriptors, i, 4327 old_details.location(), next_representation); 4328 next_field_type = GeneralizeFieldType( 4329 old_details.representation(), old_field_type, 4330 next_representation, next_field_type, isolate); 4331 } 4332 } else { 4333 Handle<FieldType> old_field_type = 4334 GetFieldType(isolate, old_descriptors, i, old_details.location(), 4335 next_representation); 4336 next_field_type = GeneralizeFieldType( 4337 old_details.representation(), old_field_type, next_representation, 4338 target_field_type, isolate); 4339 } 4340 Handle<Object> wrapped_type(WrapType(next_field_type)); 4341 DataDescriptor d(target_key, current_offset, wrapped_type, 4342 next_attributes, next_representation); 4343 current_offset += d.GetDetails().field_width_in_words(); 4344 new_descriptors->Set(i, &d); 4345 } else { 4346 UNIMPLEMENTED(); // TODO(ishell): implement. 4347 } 4348 } else { 4349 PropertyDetails details(next_attributes, next_kind, next_location, 4350 next_representation); 4351 Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate), 4352 details); 4353 new_descriptors->Set(i, &d); 4354 } 4355 } 4356 4357 // |target_nof| -> |old_nof| 4358 for (int i = target_nof; i < old_nof; ++i) { 4359 PropertyDetails old_details = old_descriptors->GetDetails(i); 4360 Handle<Name> old_key(old_descriptors->GetKey(i), isolate); 4361 4362 // Merge old_descriptor entry and modified details together. 4363 PropertyKind next_kind; 4364 PropertyAttributes next_attributes; 4365 PropertyLocation next_location; 4366 Representation next_representation; 4367 bool property_kind_reconfiguration = false; 4368 4369 if (modify_index == i) { 4370 DCHECK_EQ(FORCE_FIELD, store_mode); 4371 // In case of property kind reconfiguration it is not necessary to 4372 // take into account representation/field type of the old descriptor. 4373 property_kind_reconfiguration = old_details.kind() != new_kind; 4374 4375 next_kind = new_kind; 4376 next_attributes = new_attributes; 4377 next_location = kField; 4378 next_representation = new_representation; 4379 if (!property_kind_reconfiguration) { 4380 next_representation = 4381 next_representation.generalize(old_details.representation()); 4382 } 4383 } else { 4384 next_kind = old_details.kind(); 4385 next_attributes = old_details.attributes(); 4386 next_location = old_details.location(); 4387 next_representation = old_details.representation(); 4388 } 4389 4390 if (next_location == kField) { 4391 if (next_kind == kData) { 4392 Handle<FieldType> next_field_type; 4393 if (modify_index == i) { 4394 next_field_type = new_field_type; 4395 if (!property_kind_reconfiguration) { 4396 Handle<FieldType> old_field_type = 4397 GetFieldType(isolate, old_descriptors, i, 4398 old_details.location(), next_representation); 4399 next_field_type = GeneralizeFieldType( 4400 old_details.representation(), old_field_type, 4401 next_representation, next_field_type, isolate); 4402 } 4403 } else { 4404 Handle<FieldType> old_field_type = 4405 GetFieldType(isolate, old_descriptors, i, old_details.location(), 4406 next_representation); 4407 next_field_type = old_field_type; 4408 } 4409 4410 Handle<Object> wrapped_type(WrapType(next_field_type)); 4411 4412 DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes, 4413 next_representation); 4414 current_offset += d.GetDetails().field_width_in_words(); 4415 new_descriptors->Set(i, &d); 4416 } else { 4417 UNIMPLEMENTED(); // TODO(ishell): implement. 4418 } 4419 } else { 4420 PropertyDetails details(next_attributes, next_kind, next_location, 4421 next_representation); 4422 Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate), 4423 details); 4424 new_descriptors->Set(i, &d); 4425 } 4426 } 4427 4428 new_descriptors->Sort(); 4429 4430 DCHECK(store_mode != FORCE_FIELD || 4431 new_descriptors->GetDetails(modify_index).location() == kField); 4432 4433 Handle<Map> split_map(root_map->FindLastMatchMap( 4434 root_nof, old_nof, *new_descriptors), isolate); 4435 int split_nof = split_map->NumberOfOwnDescriptors(); 4436 DCHECK_NE(old_nof, split_nof); 4437 4438 PropertyKind split_kind; 4439 PropertyAttributes split_attributes; 4440 if (modify_index == split_nof) { 4441 split_kind = new_kind; 4442 split_attributes = new_attributes; 4443 } else { 4444 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof); 4445 split_kind = split_prop_details.kind(); 4446 split_attributes = split_prop_details.attributes(); 4447 } 4448 4449 // Invalidate a transition target at |key|. 4450 Map* maybe_transition = TransitionArray::SearchTransition( 4451 *split_map, split_kind, old_descriptors->GetKey(split_nof), 4452 split_attributes); 4453 if (maybe_transition != NULL) { 4454 maybe_transition->DeprecateTransitionTree(); 4455 } 4456 4457 // If |maybe_transition| is not NULL then the transition array already 4458 // contains entry for given descriptor. This means that the transition 4459 // could be inserted regardless of whether transitions array is full or not. 4460 if (maybe_transition == NULL && 4461 !TransitionArray::CanHaveMoreTransitions(split_map)) { 4462 return CopyGeneralizeAllRepresentations( 4463 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 4464 "GenAll_CantHaveMoreTransitions"); 4465 } 4466 4467 old_map->NotifyLeafMapLayoutChange(); 4468 4469 if (FLAG_trace_generalization && modify_index >= 0) { 4470 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); 4471 PropertyDetails new_details = new_descriptors->GetDetails(modify_index); 4472 MaybeHandle<FieldType> old_field_type; 4473 MaybeHandle<FieldType> new_field_type; 4474 MaybeHandle<Object> old_value; 4475 MaybeHandle<Object> new_value; 4476 if (old_details.type() == DATA) { 4477 old_field_type = 4478 handle(old_descriptors->GetFieldType(modify_index), isolate); 4479 } else { 4480 old_value = handle(old_descriptors->GetValue(modify_index), isolate); 4481 } 4482 if (new_details.type() == DATA) { 4483 new_field_type = 4484 handle(new_descriptors->GetFieldType(modify_index), isolate); 4485 } else { 4486 new_value = handle(new_descriptors->GetValue(modify_index), isolate); 4487 } 4488 4489 old_map->PrintGeneralization( 4490 stdout, "", modify_index, split_nof, old_nof, 4491 old_details.location() == kDescriptor && store_mode == FORCE_FIELD, 4492 old_details.representation(), new_details.representation(), 4493 old_field_type, old_value, new_field_type, new_value); 4494 } 4495 4496 Handle<LayoutDescriptor> new_layout_descriptor = 4497 LayoutDescriptor::New(split_map, new_descriptors, old_nof); 4498 4499 Handle<Map> new_map = 4500 AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor); 4501 4502 // Deprecated part of the transition tree is no longer reachable, so replace 4503 // current instance descriptors in the "survived" part of the tree with 4504 // the new descriptors to maintain descriptors sharing invariant. 4505 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor); 4506 return new_map; 4507 } 4508 4509 4510 // Generalize the representation of all DATA descriptors. 4511 Handle<Map> Map::GeneralizeAllFieldRepresentations( 4512 Handle<Map> map) { 4513 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 4514 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) { 4515 PropertyDetails details = descriptors->GetDetails(i); 4516 if (details.type() == DATA) { 4517 map = ReconfigureProperty(map, i, kData, details.attributes(), 4518 Representation::Tagged(), 4519 FieldType::Any(map->GetIsolate()), FORCE_FIELD); 4520 } 4521 } 4522 return map; 4523 } 4524 4525 4526 // static 4527 MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) { 4528 DisallowHeapAllocation no_allocation; 4529 DisallowDeoptimization no_deoptimization(old_map->GetIsolate()); 4530 4531 if (!old_map->is_deprecated()) return old_map; 4532 4533 // Check the state of the root map. 4534 Map* root_map = old_map->FindRootMap(); 4535 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>(); 4536 4537 ElementsKind from_kind = root_map->elements_kind(); 4538 ElementsKind to_kind = old_map->elements_kind(); 4539 if (from_kind != to_kind) { 4540 // Try to follow existing elements kind transitions. 4541 root_map = root_map->LookupElementsTransitionMap(to_kind); 4542 if (root_map == NULL) return MaybeHandle<Map>(); 4543 // From here on, use the map with correct elements kind as root map. 4544 } 4545 Map* new_map = root_map->TryReplayPropertyTransitions(*old_map); 4546 if (new_map == nullptr) return MaybeHandle<Map>(); 4547 return handle(new_map); 4548 } 4549 4550 Map* Map::TryReplayPropertyTransitions(Map* old_map) { 4551 DisallowHeapAllocation no_allocation; 4552 DisallowDeoptimization no_deoptimization(GetIsolate()); 4553 4554 int root_nof = NumberOfOwnDescriptors(); 4555 4556 int old_nof = old_map->NumberOfOwnDescriptors(); 4557 DescriptorArray* old_descriptors = old_map->instance_descriptors(); 4558 4559 Map* new_map = this; 4560 for (int i = root_nof; i < old_nof; ++i) { 4561 PropertyDetails old_details = old_descriptors->GetDetails(i); 4562 Map* transition = TransitionArray::SearchTransition( 4563 new_map, old_details.kind(), old_descriptors->GetKey(i), 4564 old_details.attributes()); 4565 if (transition == NULL) return nullptr; 4566 new_map = transition; 4567 DescriptorArray* new_descriptors = new_map->instance_descriptors(); 4568 4569 PropertyDetails new_details = new_descriptors->GetDetails(i); 4570 DCHECK_EQ(old_details.kind(), new_details.kind()); 4571 DCHECK_EQ(old_details.attributes(), new_details.attributes()); 4572 if (!old_details.representation().fits_into(new_details.representation())) { 4573 return nullptr; 4574 } 4575 switch (new_details.type()) { 4576 case DATA: { 4577 FieldType* new_type = new_descriptors->GetFieldType(i); 4578 // Cleared field types need special treatment. They represent lost 4579 // knowledge, so we must first generalize the new_type to "Any". 4580 if (FieldTypeIsCleared(new_details.representation(), new_type)) { 4581 return nullptr; 4582 } 4583 PropertyType old_property_type = old_details.type(); 4584 if (old_property_type == DATA) { 4585 FieldType* old_type = old_descriptors->GetFieldType(i); 4586 if (FieldTypeIsCleared(old_details.representation(), old_type) || 4587 !old_type->NowIs(new_type)) { 4588 return nullptr; 4589 } 4590 } else { 4591 DCHECK(old_property_type == DATA_CONSTANT); 4592 Object* old_value = old_descriptors->GetValue(i); 4593 if (!new_type->NowContains(old_value)) { 4594 return nullptr; 4595 } 4596 } 4597 break; 4598 } 4599 case ACCESSOR: { 4600 #ifdef DEBUG 4601 FieldType* new_type = new_descriptors->GetFieldType(i); 4602 DCHECK(new_type->IsAny()); 4603 #endif 4604 break; 4605 } 4606 4607 case DATA_CONSTANT: 4608 case ACCESSOR_CONSTANT: { 4609 Object* old_value = old_descriptors->GetValue(i); 4610 Object* new_value = new_descriptors->GetValue(i); 4611 if (old_details.location() == kField || old_value != new_value) { 4612 return nullptr; 4613 } 4614 break; 4615 } 4616 } 4617 } 4618 if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr; 4619 return new_map; 4620 } 4621 4622 4623 // static 4624 Handle<Map> Map::Update(Handle<Map> map) { 4625 if (!map->is_deprecated()) return map; 4626 return ReconfigureProperty(map, -1, kData, NONE, Representation::None(), 4627 FieldType::None(map->GetIsolate()), 4628 ALLOW_IN_DESCRIPTOR); 4629 } 4630 4631 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it, 4632 ShouldThrow should_throw, 4633 Handle<Object> value) { 4634 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 4635 return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(), 4636 should_throw, value); 4637 } 4638 4639 MaybeHandle<Object> Object::SetProperty(Handle<Object> object, 4640 Handle<Name> name, Handle<Object> value, 4641 LanguageMode language_mode, 4642 StoreFromKeyed store_mode) { 4643 LookupIterator it(object, name); 4644 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode)); 4645 return value; 4646 } 4647 4648 4649 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it, 4650 Handle<Object> value, 4651 LanguageMode language_mode, 4652 StoreFromKeyed store_mode, 4653 bool* found) { 4654 it->UpdateProtector(); 4655 DCHECK(it->IsFound()); 4656 ShouldThrow should_throw = 4657 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4658 4659 // Make sure that the top context does not change when doing callbacks or 4660 // interceptor calls. 4661 AssertNoContextChange ncc(it->isolate()); 4662 4663 do { 4664 switch (it->state()) { 4665 case LookupIterator::NOT_FOUND: 4666 UNREACHABLE(); 4667 4668 case LookupIterator::ACCESS_CHECK: 4669 if (it->HasAccess()) break; 4670 // Check whether it makes sense to reuse the lookup iterator. Here it 4671 // might still call into setters up the prototype chain. 4672 return JSObject::SetPropertyWithFailedAccessCheck(it, value, 4673 should_throw); 4674 4675 case LookupIterator::JSPROXY: 4676 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(), 4677 value, it->GetReceiver(), language_mode); 4678 4679 case LookupIterator::INTERCEPTOR: { 4680 if (it->HolderIsReceiverOrHiddenPrototype()) { 4681 Maybe<bool> result = 4682 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 4683 if (result.IsNothing() || result.FromJust()) return result; 4684 } else { 4685 Maybe<PropertyAttributes> maybe_attributes = 4686 JSObject::GetPropertyAttributesWithInterceptor(it); 4687 if (!maybe_attributes.IsJust()) return Nothing<bool>(); 4688 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) { 4689 return WriteToReadOnlyProperty(it, value, should_throw); 4690 } 4691 if (maybe_attributes.FromJust() == ABSENT) break; 4692 *found = false; 4693 return Nothing<bool>(); 4694 } 4695 break; 4696 } 4697 4698 case LookupIterator::ACCESSOR: { 4699 if (it->IsReadOnly()) { 4700 return WriteToReadOnlyProperty(it, value, should_throw); 4701 } 4702 Handle<Object> accessors = it->GetAccessors(); 4703 if (accessors->IsAccessorInfo() && 4704 !it->HolderIsReceiverOrHiddenPrototype() && 4705 AccessorInfo::cast(*accessors)->is_special_data_property()) { 4706 *found = false; 4707 return Nothing<bool>(); 4708 } 4709 return SetPropertyWithAccessor(it, value, should_throw); 4710 } 4711 case LookupIterator::INTEGER_INDEXED_EXOTIC: 4712 // TODO(verwaest): We should throw an exception if holder is receiver. 4713 return Just(true); 4714 4715 case LookupIterator::DATA: 4716 if (it->IsReadOnly()) { 4717 return WriteToReadOnlyProperty(it, value, should_throw); 4718 } 4719 if (it->HolderIsReceiverOrHiddenPrototype()) { 4720 return SetDataProperty(it, value); 4721 } 4722 // Fall through. 4723 case LookupIterator::TRANSITION: 4724 *found = false; 4725 return Nothing<bool>(); 4726 } 4727 it->Next(); 4728 } while (it->IsFound()); 4729 4730 *found = false; 4731 return Nothing<bool>(); 4732 } 4733 4734 4735 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value, 4736 LanguageMode language_mode, 4737 StoreFromKeyed store_mode) { 4738 if (it->IsFound()) { 4739 bool found = true; 4740 Maybe<bool> result = 4741 SetPropertyInternal(it, value, language_mode, store_mode, &found); 4742 if (found) return result; 4743 } 4744 4745 // If the receiver is the JSGlobalObject, the store was contextual. In case 4746 // the property did not exist yet on the global object itself, we have to 4747 // throw a reference error in strict mode. In sloppy mode, we continue. 4748 if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) { 4749 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError( 4750 MessageTemplate::kNotDefined, it->name())); 4751 return Nothing<bool>(); 4752 } 4753 4754 ShouldThrow should_throw = 4755 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4756 return AddDataProperty(it, value, NONE, should_throw, store_mode); 4757 } 4758 4759 4760 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, 4761 LanguageMode language_mode, 4762 StoreFromKeyed store_mode) { 4763 Isolate* isolate = it->isolate(); 4764 4765 if (it->IsFound()) { 4766 bool found = true; 4767 Maybe<bool> result = 4768 SetPropertyInternal(it, value, language_mode, store_mode, &found); 4769 if (found) return result; 4770 } 4771 4772 it->UpdateProtector(); 4773 4774 // The property either doesn't exist on the holder or exists there as a data 4775 // property. 4776 4777 ShouldThrow should_throw = 4778 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4779 4780 if (!it->GetReceiver()->IsJSReceiver()) { 4781 return WriteToReadOnlyProperty(it, value, should_throw); 4782 } 4783 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 4784 4785 LookupIterator::Configuration c = LookupIterator::OWN; 4786 LookupIterator own_lookup = 4787 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c) 4788 : LookupIterator(receiver, it->name(), c); 4789 4790 for (; own_lookup.IsFound(); own_lookup.Next()) { 4791 switch (own_lookup.state()) { 4792 case LookupIterator::ACCESS_CHECK: 4793 if (!own_lookup.HasAccess()) { 4794 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value, 4795 should_throw); 4796 } 4797 break; 4798 4799 case LookupIterator::ACCESSOR: 4800 if (own_lookup.GetAccessors()->IsAccessorInfo()) { 4801 if (own_lookup.IsReadOnly()) { 4802 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 4803 } 4804 return JSObject::SetPropertyWithAccessor(&own_lookup, value, 4805 should_throw); 4806 } 4807 // Fall through. 4808 case LookupIterator::INTEGER_INDEXED_EXOTIC: 4809 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 4810 should_throw); 4811 4812 case LookupIterator::DATA: { 4813 if (own_lookup.IsReadOnly()) { 4814 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 4815 } 4816 return SetDataProperty(&own_lookup, value); 4817 } 4818 4819 case LookupIterator::INTERCEPTOR: 4820 case LookupIterator::JSPROXY: { 4821 PropertyDescriptor desc; 4822 Maybe<bool> owned = 4823 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc); 4824 MAYBE_RETURN(owned, Nothing<bool>()); 4825 if (!owned.FromJust()) { 4826 return JSReceiver::CreateDataProperty(&own_lookup, value, 4827 should_throw); 4828 } 4829 if (PropertyDescriptor::IsAccessorDescriptor(&desc) || 4830 !desc.writable()) { 4831 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 4832 should_throw); 4833 } 4834 4835 PropertyDescriptor value_desc; 4836 value_desc.set_value(value); 4837 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 4838 &value_desc, should_throw); 4839 } 4840 4841 case LookupIterator::NOT_FOUND: 4842 case LookupIterator::TRANSITION: 4843 UNREACHABLE(); 4844 } 4845 } 4846 4847 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode); 4848 } 4849 4850 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate, 4851 Handle<Object> receiver, 4852 Handle<Object> name, 4853 Handle<Object> value, 4854 ShouldThrow should_throw) { 4855 RETURN_FAILURE( 4856 isolate, should_throw, 4857 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name, 4858 Object::TypeOf(isolate, receiver), receiver)); 4859 } 4860 4861 4862 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it, 4863 Handle<Object> value, 4864 ShouldThrow should_throw) { 4865 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), 4866 it->GetName(), value, should_throw); 4867 } 4868 4869 4870 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate, 4871 Handle<Object> receiver, 4872 Handle<Object> name, 4873 Handle<Object> value, 4874 ShouldThrow should_throw) { 4875 RETURN_FAILURE(isolate, should_throw, 4876 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name, 4877 Object::TypeOf(isolate, receiver), receiver)); 4878 } 4879 4880 4881 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate, 4882 Handle<Object> name, 4883 Handle<Object> value, 4884 ShouldThrow should_throw) { 4885 RETURN_FAILURE(isolate, should_throw, 4886 NewTypeError(MessageTemplate::kRedefineDisallowed, name)); 4887 } 4888 4889 4890 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { 4891 // Proxies are handled elsewhere. Other non-JSObjects cannot have own 4892 // properties. 4893 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); 4894 4895 // Store on the holder which may be hidden behind the receiver. 4896 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); 4897 4898 Handle<Object> to_assign = value; 4899 // Convert the incoming value to a number for storing into typed arrays. 4900 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) { 4901 if (!value->IsNumber() && !value->IsUndefined(it->isolate())) { 4902 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 4903 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>()); 4904 // We have to recheck the length. However, it can only change if the 4905 // underlying buffer was neutered, so just check that. 4906 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) { 4907 return Just(true); 4908 // TODO(neis): According to the spec, this should throw a TypeError. 4909 } 4910 } 4911 } 4912 4913 // Possibly migrate to the most up-to-date map that will be able to store 4914 // |value| under it->name(). 4915 it->PrepareForDataProperty(to_assign); 4916 4917 // Write the property value. 4918 it->WriteDataValue(to_assign); 4919 4920 #if VERIFY_HEAP 4921 if (FLAG_verify_heap) { 4922 receiver->JSObjectVerify(); 4923 } 4924 #endif 4925 return Just(true); 4926 } 4927 4928 4929 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, 4930 PropertyAttributes attributes, 4931 ShouldThrow should_throw, 4932 StoreFromKeyed store_mode) { 4933 if (!it->GetReceiver()->IsJSObject()) { 4934 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) { 4935 RETURN_FAILURE(it->isolate(), should_throw, 4936 NewTypeError(MessageTemplate::kProxyPrivate)); 4937 } 4938 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(), 4939 value, should_throw); 4940 } 4941 4942 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state()); 4943 4944 Handle<JSObject> receiver = it->GetStoreTarget(); 4945 4946 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) 4947 // instead. If the prototype is Null, the proxy is detached. 4948 if (receiver->IsJSGlobalProxy()) return Just(true); 4949 4950 Isolate* isolate = it->isolate(); 4951 4952 if (it->ExtendingNonExtensible(receiver)) { 4953 RETURN_FAILURE( 4954 isolate, should_throw, 4955 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName())); 4956 } 4957 4958 if (it->IsElement()) { 4959 if (receiver->IsJSArray()) { 4960 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 4961 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) { 4962 RETURN_FAILURE(array->GetIsolate(), should_throw, 4963 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, 4964 isolate->factory()->length_string(), 4965 Object::TypeOf(isolate, array), array)); 4966 } 4967 4968 if (FLAG_trace_external_array_abuse && 4969 array->HasFixedTypedArrayElements()) { 4970 CheckArrayAbuse(array, "typed elements write", it->index(), true); 4971 } 4972 4973 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) { 4974 CheckArrayAbuse(array, "elements write", it->index(), false); 4975 } 4976 } 4977 4978 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value, 4979 attributes, should_throw); 4980 JSObject::ValidateElements(receiver); 4981 return result; 4982 } else { 4983 it->UpdateProtector(); 4984 // Migrate to the most up-to-date map that will be able to store |value| 4985 // under it->name() with |attributes|. 4986 it->PrepareTransitionToDataProperty(receiver, value, attributes, 4987 store_mode); 4988 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); 4989 it->ApplyTransitionToDataProperty(receiver); 4990 4991 // Write the property value. 4992 it->WriteDataValue(value); 4993 4994 #if VERIFY_HEAP 4995 if (FLAG_verify_heap) { 4996 receiver->JSObjectVerify(); 4997 } 4998 #endif 4999 } 5000 5001 return Just(true); 5002 } 5003 5004 5005 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { 5006 // Only supports adding slack to owned descriptors. 5007 DCHECK(map->owns_descriptors()); 5008 5009 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 5010 int old_size = map->NumberOfOwnDescriptors(); 5011 if (slack <= descriptors->NumberOfSlackDescriptors()) return; 5012 5013 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 5014 descriptors, old_size, slack); 5015 5016 DisallowHeapAllocation no_allocation; 5017 // The descriptors are still the same, so keep the layout descriptor. 5018 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor(); 5019 5020 if (old_size == 0) { 5021 map->UpdateDescriptors(*new_descriptors, layout_descriptor); 5022 return; 5023 } 5024 5025 // If the source descriptors had an enum cache we copy it. This ensures 5026 // that the maps to which we push the new descriptor array back can rely 5027 // on a cache always being available once it is set. If the map has more 5028 // enumerated descriptors than available in the original cache, the cache 5029 // will be lazily replaced by the extended cache when needed. 5030 if (descriptors->HasEnumCache()) { 5031 new_descriptors->CopyEnumCacheFrom(*descriptors); 5032 } 5033 5034 Isolate* isolate = map->GetIsolate(); 5035 // Replace descriptors by new_descriptors in all maps that share it. 5036 isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors); 5037 5038 Map* current = *map; 5039 while (current->instance_descriptors() == *descriptors) { 5040 Object* next = current->GetBackPointer(); 5041 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map. 5042 current->UpdateDescriptors(*new_descriptors, layout_descriptor); 5043 current = Map::cast(next); 5044 } 5045 map->UpdateDescriptors(*new_descriptors, layout_descriptor); 5046 } 5047 5048 template <class T> 5049 static int AppendUniqueCallbacks(Handle<TemplateList> callbacks, 5050 Handle<typename T::Array> array, 5051 int valid_descriptors) { 5052 int nof_callbacks = callbacks->length(); 5053 5054 Isolate* isolate = array->GetIsolate(); 5055 // Ensure the keys are unique names before writing them into the 5056 // instance descriptor. Since it may cause a GC, it has to be done before we 5057 // temporarily put the heap in an invalid state while appending descriptors. 5058 for (int i = 0; i < nof_callbacks; ++i) { 5059 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i))); 5060 if (entry->name()->IsUniqueName()) continue; 5061 Handle<String> key = 5062 isolate->factory()->InternalizeString( 5063 Handle<String>(String::cast(entry->name()))); 5064 entry->set_name(*key); 5065 } 5066 5067 // Fill in new callback descriptors. Process the callbacks from 5068 // back to front so that the last callback with a given name takes 5069 // precedence over previously added callbacks with that name. 5070 for (int i = nof_callbacks - 1; i >= 0; i--) { 5071 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i))); 5072 Handle<Name> key(Name::cast(entry->name())); 5073 // Check if a descriptor with this name already exists before writing. 5074 if (!T::Contains(key, entry, valid_descriptors, array)) { 5075 T::Insert(key, entry, valid_descriptors, array); 5076 valid_descriptors++; 5077 } 5078 } 5079 5080 return valid_descriptors; 5081 } 5082 5083 struct DescriptorArrayAppender { 5084 typedef DescriptorArray Array; 5085 static bool Contains(Handle<Name> key, 5086 Handle<AccessorInfo> entry, 5087 int valid_descriptors, 5088 Handle<DescriptorArray> array) { 5089 DisallowHeapAllocation no_gc; 5090 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound; 5091 } 5092 static void Insert(Handle<Name> key, 5093 Handle<AccessorInfo> entry, 5094 int valid_descriptors, 5095 Handle<DescriptorArray> array) { 5096 DisallowHeapAllocation no_gc; 5097 AccessorConstantDescriptor desc(key, entry, entry->property_attributes()); 5098 array->Append(&desc); 5099 } 5100 }; 5101 5102 5103 struct FixedArrayAppender { 5104 typedef FixedArray Array; 5105 static bool Contains(Handle<Name> key, 5106 Handle<AccessorInfo> entry, 5107 int valid_descriptors, 5108 Handle<FixedArray> array) { 5109 for (int i = 0; i < valid_descriptors; i++) { 5110 if (*key == AccessorInfo::cast(array->get(i))->name()) return true; 5111 } 5112 return false; 5113 } 5114 static void Insert(Handle<Name> key, 5115 Handle<AccessorInfo> entry, 5116 int valid_descriptors, 5117 Handle<FixedArray> array) { 5118 DisallowHeapAllocation no_gc; 5119 array->set(valid_descriptors, *entry); 5120 } 5121 }; 5122 5123 5124 void Map::AppendCallbackDescriptors(Handle<Map> map, 5125 Handle<Object> descriptors) { 5126 int nof = map->NumberOfOwnDescriptors(); 5127 Handle<DescriptorArray> array(map->instance_descriptors()); 5128 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors); 5129 DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length()); 5130 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof); 5131 map->SetNumberOfOwnDescriptors(nof); 5132 } 5133 5134 5135 int AccessorInfo::AppendUnique(Handle<Object> descriptors, 5136 Handle<FixedArray> array, 5137 int valid_descriptors) { 5138 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors); 5139 DCHECK_GE(array->length(), callbacks->length() + valid_descriptors); 5140 return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array, 5141 valid_descriptors); 5142 } 5143 5144 5145 static bool ContainsMap(MapHandleList* maps, Map* map) { 5146 DCHECK_NOT_NULL(map); 5147 for (int i = 0; i < maps->length(); ++i) { 5148 if (!maps->at(i).is_null() && *maps->at(i) == map) return true; 5149 } 5150 return false; 5151 } 5152 5153 Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) { 5154 DisallowHeapAllocation no_allocation; 5155 DisallowDeoptimization no_deoptimization(GetIsolate()); 5156 5157 ElementsKind kind = elements_kind(); 5158 bool packed = IsFastPackedElementsKind(kind); 5159 5160 Map* transition = nullptr; 5161 if (IsTransitionableFastElementsKind(kind)) { 5162 // Check the state of the root map. 5163 Map* root_map = FindRootMap(); 5164 if (!EquivalentToForTransition(root_map)) return nullptr; 5165 root_map = root_map->LookupElementsTransitionMap(kind); 5166 DCHECK_NOT_NULL(root_map); 5167 // Starting from the next existing elements kind transition try to 5168 // replay the property transitions that does not involve instance rewriting 5169 // (ElementsTransitionAndStoreStub does not support that). 5170 for (root_map = root_map->ElementsTransitionMap(); 5171 root_map != nullptr && root_map->has_fast_elements(); 5172 root_map = root_map->ElementsTransitionMap()) { 5173 Map* current = root_map->TryReplayPropertyTransitions(this); 5174 if (current == nullptr) continue; 5175 if (InstancesNeedRewriting(current)) continue; 5176 5177 if (ContainsMap(candidates, current) && 5178 (packed || !IsFastPackedElementsKind(current->elements_kind()))) { 5179 transition = current; 5180 packed = packed && IsFastPackedElementsKind(current->elements_kind()); 5181 } 5182 } 5183 } 5184 return transition; 5185 } 5186 5187 5188 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { 5189 // Ensure we are requested to search elements kind transition "near the root". 5190 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(), 5191 map->NumberOfOwnDescriptors()); 5192 Map* current_map = map; 5193 5194 ElementsKind kind = map->elements_kind(); 5195 while (kind != to_kind) { 5196 Map* next_map = current_map->ElementsTransitionMap(); 5197 if (next_map == nullptr) return current_map; 5198 kind = next_map->elements_kind(); 5199 current_map = next_map; 5200 } 5201 5202 DCHECK_EQ(to_kind, current_map->elements_kind()); 5203 return current_map; 5204 } 5205 5206 5207 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { 5208 Map* to_map = FindClosestElementsTransition(this, to_kind); 5209 if (to_map->elements_kind() == to_kind) return to_map; 5210 return nullptr; 5211 } 5212 5213 5214 bool Map::IsMapInArrayPrototypeChain() { 5215 Isolate* isolate = GetIsolate(); 5216 if (isolate->initial_array_prototype()->map() == this) { 5217 return true; 5218 } 5219 5220 if (isolate->initial_object_prototype()->map() == this) { 5221 return true; 5222 } 5223 5224 return false; 5225 } 5226 5227 5228 Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) { 5229 Isolate* isolate = map->GetIsolate(); 5230 if (map->weak_cell_cache()->IsWeakCell()) { 5231 return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache())); 5232 } 5233 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map); 5234 map->set_weak_cell_cache(*weak_cell); 5235 return weak_cell; 5236 } 5237 5238 5239 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map, 5240 ElementsKind to_kind) { 5241 DCHECK(IsTransitionElementsKind(map->elements_kind())); 5242 5243 Handle<Map> current_map = map; 5244 5245 ElementsKind kind = map->elements_kind(); 5246 TransitionFlag flag; 5247 if (map->is_prototype_map()) { 5248 flag = OMIT_TRANSITION; 5249 } else { 5250 flag = INSERT_TRANSITION; 5251 if (IsFastElementsKind(kind)) { 5252 while (kind != to_kind && !IsTerminalElementsKind(kind)) { 5253 kind = GetNextTransitionElementsKind(kind); 5254 current_map = Map::CopyAsElementsKind(current_map, kind, flag); 5255 } 5256 } 5257 } 5258 5259 // In case we are exiting the fast elements kind system, just add the map in 5260 // the end. 5261 if (kind != to_kind) { 5262 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag); 5263 } 5264 5265 DCHECK(current_map->elements_kind() == to_kind); 5266 return current_map; 5267 } 5268 5269 5270 Handle<Map> Map::TransitionElementsTo(Handle<Map> map, 5271 ElementsKind to_kind) { 5272 ElementsKind from_kind = map->elements_kind(); 5273 if (from_kind == to_kind) return map; 5274 5275 Isolate* isolate = map->GetIsolate(); 5276 Context* native_context = isolate->context()->native_context(); 5277 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) { 5278 if (*map == native_context->fast_aliased_arguments_map()) { 5279 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); 5280 return handle(native_context->slow_aliased_arguments_map()); 5281 } 5282 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) { 5283 if (*map == native_context->slow_aliased_arguments_map()) { 5284 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); 5285 return handle(native_context->fast_aliased_arguments_map()); 5286 } 5287 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { 5288 // Reuse map transitions for JSArrays. 5289 DisallowHeapAllocation no_gc; 5290 if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) { 5291 Object* maybe_transitioned_map = 5292 native_context->get(Context::ArrayMapIndex(to_kind)); 5293 if (maybe_transitioned_map->IsMap()) { 5294 return handle(Map::cast(maybe_transitioned_map), isolate); 5295 } 5296 } 5297 } 5298 5299 DCHECK(!map->IsUndefined(isolate)); 5300 // Check if we can go back in the elements kind transition chain. 5301 if (IsHoleyElementsKind(from_kind) && 5302 to_kind == GetPackedElementsKind(from_kind) && 5303 map->GetBackPointer()->IsMap() && 5304 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) { 5305 return handle(Map::cast(map->GetBackPointer())); 5306 } 5307 5308 bool allow_store_transition = IsTransitionElementsKind(from_kind); 5309 // Only store fast element maps in ascending generality. 5310 if (IsFastElementsKind(to_kind)) { 5311 allow_store_transition = 5312 allow_store_transition && IsTransitionableFastElementsKind(from_kind) && 5313 IsMoreGeneralElementsKindTransition(from_kind, to_kind); 5314 } 5315 5316 if (!allow_store_transition) { 5317 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION); 5318 } 5319 5320 return Map::ReconfigureElementsKind(map, to_kind); 5321 } 5322 5323 5324 // static 5325 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) { 5326 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind)); 5327 5328 if (closest_map->elements_kind() == kind) { 5329 return closest_map; 5330 } 5331 5332 return AddMissingElementsTransitions(closest_map, kind); 5333 } 5334 5335 5336 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, 5337 ElementsKind to_kind) { 5338 Handle<Map> map(object->map()); 5339 return Map::TransitionElementsTo(map, to_kind); 5340 } 5341 5342 5343 void JSProxy::Revoke(Handle<JSProxy> proxy) { 5344 Isolate* isolate = proxy->GetIsolate(); 5345 if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value()); 5346 DCHECK(proxy->IsRevoked()); 5347 } 5348 5349 5350 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy, 5351 Handle<Name> name) { 5352 DCHECK(!name->IsPrivate()); 5353 STACK_CHECK(isolate, Nothing<bool>()); 5354 // 1. (Assert) 5355 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 5356 Handle<Object> handler(proxy->handler(), isolate); 5357 // 3. If handler is null, throw a TypeError exception. 5358 // 4. Assert: Type(handler) is Object. 5359 if (proxy->IsRevoked()) { 5360 isolate->Throw(*isolate->factory()->NewTypeError( 5361 MessageTemplate::kProxyRevoked, isolate->factory()->has_string())); 5362 return Nothing<bool>(); 5363 } 5364 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 5365 Handle<JSReceiver> target(proxy->target(), isolate); 5366 // 6. Let trap be ? GetMethod(handler, "has"). 5367 Handle<Object> trap; 5368 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5369 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), 5370 isolate->factory()->has_string()), 5371 Nothing<bool>()); 5372 // 7. If trap is undefined, then 5373 if (trap->IsUndefined(isolate)) { 5374 // 7a. Return target.[[HasProperty]](P). 5375 return JSReceiver::HasProperty(target, name); 5376 } 5377 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, target, P)). 5378 Handle<Object> trap_result_obj; 5379 Handle<Object> args[] = {target, name}; 5380 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5381 isolate, trap_result_obj, 5382 Execution::Call(isolate, trap, handler, arraysize(args), args), 5383 Nothing<bool>()); 5384 bool boolean_trap_result = trap_result_obj->BooleanValue(); 5385 // 9. If booleanTrapResult is false, then: 5386 if (!boolean_trap_result) { 5387 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P). 5388 PropertyDescriptor target_desc; 5389 Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor( 5390 isolate, target, name, &target_desc); 5391 MAYBE_RETURN(target_found, Nothing<bool>()); 5392 // 9b. If targetDesc is not undefined, then: 5393 if (target_found.FromJust()) { 5394 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError 5395 // exception. 5396 if (!target_desc.configurable()) { 5397 isolate->Throw(*isolate->factory()->NewTypeError( 5398 MessageTemplate::kProxyHasNonConfigurable, name)); 5399 return Nothing<bool>(); 5400 } 5401 // 9b ii. Let extensibleTarget be ? IsExtensible(target). 5402 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 5403 MAYBE_RETURN(extensible_target, Nothing<bool>()); 5404 // 9b iii. If extensibleTarget is false, throw a TypeError exception. 5405 if (!extensible_target.FromJust()) { 5406 isolate->Throw(*isolate->factory()->NewTypeError( 5407 MessageTemplate::kProxyHasNonExtensible, name)); 5408 return Nothing<bool>(); 5409 } 5410 } 5411 } 5412 // 10. Return booleanTrapResult. 5413 return Just(boolean_trap_result); 5414 } 5415 5416 5417 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name, 5418 Handle<Object> value, Handle<Object> receiver, 5419 LanguageMode language_mode) { 5420 DCHECK(!name->IsPrivate()); 5421 Isolate* isolate = proxy->GetIsolate(); 5422 STACK_CHECK(isolate, Nothing<bool>()); 5423 Factory* factory = isolate->factory(); 5424 Handle<String> trap_name = factory->set_string(); 5425 ShouldThrow should_throw = 5426 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 5427 5428 if (proxy->IsRevoked()) { 5429 isolate->Throw( 5430 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 5431 return Nothing<bool>(); 5432 } 5433 Handle<JSReceiver> target(proxy->target(), isolate); 5434 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 5435 5436 Handle<Object> trap; 5437 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5438 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 5439 if (trap->IsUndefined(isolate)) { 5440 LookupIterator it = 5441 LookupIterator::PropertyOrElement(isolate, receiver, name, target); 5442 return Object::SetSuperProperty(&it, value, language_mode, 5443 Object::MAY_BE_STORE_FROM_KEYED); 5444 } 5445 5446 Handle<Object> trap_result; 5447 Handle<Object> args[] = {target, name, value, receiver}; 5448 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5449 isolate, trap_result, 5450 Execution::Call(isolate, trap, handler, arraysize(args), args), 5451 Nothing<bool>()); 5452 if (!trap_result->BooleanValue()) { 5453 RETURN_FAILURE(isolate, should_throw, 5454 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 5455 trap_name, name)); 5456 } 5457 5458 // Enforce the invariant. 5459 PropertyDescriptor target_desc; 5460 Maybe<bool> owned = 5461 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 5462 MAYBE_RETURN(owned, Nothing<bool>()); 5463 if (owned.FromJust()) { 5464 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && 5465 !target_desc.configurable() && 5466 !target_desc.writable() && 5467 !value->SameValue(*target_desc.value()); 5468 if (inconsistent) { 5469 isolate->Throw(*isolate->factory()->NewTypeError( 5470 MessageTemplate::kProxySetFrozenData, name)); 5471 return Nothing<bool>(); 5472 } 5473 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 5474 !target_desc.configurable() && 5475 target_desc.set()->IsUndefined(isolate); 5476 if (inconsistent) { 5477 isolate->Throw(*isolate->factory()->NewTypeError( 5478 MessageTemplate::kProxySetFrozenAccessor, name)); 5479 return Nothing<bool>(); 5480 } 5481 } 5482 return Just(true); 5483 } 5484 5485 5486 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy, 5487 Handle<Name> name, 5488 LanguageMode language_mode) { 5489 DCHECK(!name->IsPrivate()); 5490 ShouldThrow should_throw = 5491 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 5492 Isolate* isolate = proxy->GetIsolate(); 5493 STACK_CHECK(isolate, Nothing<bool>()); 5494 Factory* factory = isolate->factory(); 5495 Handle<String> trap_name = factory->deleteProperty_string(); 5496 5497 if (proxy->IsRevoked()) { 5498 isolate->Throw( 5499 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 5500 return Nothing<bool>(); 5501 } 5502 Handle<JSReceiver> target(proxy->target(), isolate); 5503 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 5504 5505 Handle<Object> trap; 5506 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5507 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 5508 if (trap->IsUndefined(isolate)) { 5509 return JSReceiver::DeletePropertyOrElement(target, name, language_mode); 5510 } 5511 5512 Handle<Object> trap_result; 5513 Handle<Object> args[] = {target, name}; 5514 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5515 isolate, trap_result, 5516 Execution::Call(isolate, trap, handler, arraysize(args), args), 5517 Nothing<bool>()); 5518 if (!trap_result->BooleanValue()) { 5519 RETURN_FAILURE(isolate, should_throw, 5520 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 5521 trap_name, name)); 5522 } 5523 5524 // Enforce the invariant. 5525 PropertyDescriptor target_desc; 5526 Maybe<bool> owned = 5527 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 5528 MAYBE_RETURN(owned, Nothing<bool>()); 5529 if (owned.FromJust() && !target_desc.configurable()) { 5530 isolate->Throw(*factory->NewTypeError( 5531 MessageTemplate::kProxyDeletePropertyNonConfigurable, name)); 5532 return Nothing<bool>(); 5533 } 5534 return Just(true); 5535 } 5536 5537 5538 // static 5539 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target, 5540 Handle<Object> handler) { 5541 if (!target->IsJSReceiver()) { 5542 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 5543 JSProxy); 5544 } 5545 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) { 5546 THROW_NEW_ERROR(isolate, 5547 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked), 5548 JSProxy); 5549 } 5550 if (!handler->IsJSReceiver()) { 5551 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 5552 JSProxy); 5553 } 5554 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) { 5555 THROW_NEW_ERROR(isolate, 5556 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked), 5557 JSProxy); 5558 } 5559 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target), 5560 Handle<JSReceiver>::cast(handler)); 5561 } 5562 5563 5564 // static 5565 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) { 5566 DCHECK(proxy->map()->is_constructor()); 5567 if (proxy->IsRevoked()) { 5568 THROW_NEW_ERROR(proxy->GetIsolate(), 5569 NewTypeError(MessageTemplate::kProxyRevoked), Context); 5570 } 5571 Handle<JSReceiver> target(JSReceiver::cast(proxy->target())); 5572 return JSReceiver::GetFunctionRealm(target); 5573 } 5574 5575 5576 // static 5577 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm( 5578 Handle<JSBoundFunction> function) { 5579 DCHECK(function->map()->is_constructor()); 5580 return JSReceiver::GetFunctionRealm( 5581 handle(function->bound_target_function())); 5582 } 5583 5584 // static 5585 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate, 5586 Handle<JSBoundFunction> function) { 5587 Handle<String> prefix = isolate->factory()->bound__string(); 5588 if (!function->bound_target_function()->IsJSFunction()) return prefix; 5589 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()), 5590 isolate); 5591 Handle<Object> target_name = JSFunction::GetName(isolate, target); 5592 if (!target_name->IsString()) return prefix; 5593 Factory* factory = isolate->factory(); 5594 return factory->NewConsString(prefix, Handle<String>::cast(target_name)); 5595 } 5596 5597 // static 5598 Handle<Object> JSFunction::GetName(Isolate* isolate, 5599 Handle<JSFunction> function) { 5600 if (function->shared()->name_should_print_as_anonymous()) { 5601 return isolate->factory()->anonymous_string(); 5602 } 5603 return handle(function->shared()->name(), isolate); 5604 } 5605 5606 // static 5607 MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate, 5608 Handle<JSFunction> function) { 5609 int length = 0; 5610 if (function->shared()->is_compiled()) { 5611 length = function->shared()->length(); 5612 } else { 5613 // If the function isn't compiled yet, the length is not computed 5614 // correctly yet. Compile it now and return the right length. 5615 if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) { 5616 length = function->shared()->length(); 5617 } 5618 if (isolate->has_pending_exception()) return MaybeHandle<Smi>(); 5619 } 5620 return handle(Smi::FromInt(length), isolate); 5621 } 5622 5623 // static 5624 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) { 5625 DCHECK(function->map()->is_constructor()); 5626 return handle(function->context()->native_context()); 5627 } 5628 5629 5630 // static 5631 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) { 5632 DCHECK(object->map()->is_constructor()); 5633 DCHECK(!object->IsJSFunction()); 5634 return handle(object->GetCreationContext()); 5635 } 5636 5637 5638 // static 5639 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) { 5640 if (receiver->IsJSProxy()) { 5641 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver)); 5642 } 5643 5644 if (receiver->IsJSFunction()) { 5645 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver)); 5646 } 5647 5648 if (receiver->IsJSBoundFunction()) { 5649 return JSBoundFunction::GetFunctionRealm( 5650 Handle<JSBoundFunction>::cast(receiver)); 5651 } 5652 5653 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver)); 5654 } 5655 5656 5657 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) { 5658 PropertyDescriptor desc; 5659 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor( 5660 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc); 5661 MAYBE_RETURN(found, Nothing<PropertyAttributes>()); 5662 if (!found.FromJust()) return Just(ABSENT); 5663 return Just(desc.ToAttributes()); 5664 } 5665 5666 5667 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { 5668 DCHECK(object->map()->GetInObjectProperties() == 5669 map->GetInObjectProperties()); 5670 ElementsKind obj_kind = object->map()->elements_kind(); 5671 ElementsKind map_kind = map->elements_kind(); 5672 if (map_kind != obj_kind) { 5673 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind); 5674 if (IsDictionaryElementsKind(obj_kind)) { 5675 to_kind = obj_kind; 5676 } 5677 if (IsDictionaryElementsKind(to_kind)) { 5678 NormalizeElements(object); 5679 } else { 5680 TransitionElementsKind(object, to_kind); 5681 } 5682 map = Map::ReconfigureElementsKind(map, to_kind); 5683 } 5684 JSObject::MigrateToMap(object, map); 5685 } 5686 5687 5688 void JSObject::MigrateInstance(Handle<JSObject> object) { 5689 Handle<Map> original_map(object->map()); 5690 Handle<Map> map = Map::Update(original_map); 5691 map->set_migration_target(true); 5692 MigrateToMap(object, map); 5693 if (FLAG_trace_migration) { 5694 object->PrintInstanceMigration(stdout, *original_map, *map); 5695 } 5696 #if VERIFY_HEAP 5697 if (FLAG_verify_heap) { 5698 object->JSObjectVerify(); 5699 } 5700 #endif 5701 } 5702 5703 5704 // static 5705 bool JSObject::TryMigrateInstance(Handle<JSObject> object) { 5706 Isolate* isolate = object->GetIsolate(); 5707 DisallowDeoptimization no_deoptimization(isolate); 5708 Handle<Map> original_map(object->map(), isolate); 5709 Handle<Map> new_map; 5710 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) { 5711 return false; 5712 } 5713 JSObject::MigrateToMap(object, new_map); 5714 if (FLAG_trace_migration) { 5715 object->PrintInstanceMigration(stdout, *original_map, object->map()); 5716 } 5717 #if VERIFY_HEAP 5718 if (FLAG_verify_heap) { 5719 object->JSObjectVerify(); 5720 } 5721 #endif 5722 return true; 5723 } 5724 5725 5726 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name, 5727 Handle<Object> value, 5728 PropertyAttributes attributes) { 5729 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR); 5730 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); 5731 #ifdef DEBUG 5732 uint32_t index; 5733 DCHECK(!object->IsJSProxy()); 5734 DCHECK(!name->AsArrayIndex(&index)); 5735 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); 5736 DCHECK(maybe.IsJust()); 5737 DCHECK(!it.IsFound()); 5738 DCHECK(object->map()->is_extensible() || name->IsPrivate()); 5739 #endif 5740 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR, 5741 CERTAINLY_NOT_STORE_FROM_KEYED) 5742 .IsJust()); 5743 } 5744 5745 5746 // Reconfigures a property to a data property with attributes, even if it is not 5747 // reconfigurable. 5748 // Requires a LookupIterator that does not look at the prototype chain beyond 5749 // hidden prototypes. 5750 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes( 5751 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 5752 AccessorInfoHandling handling) { 5753 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes( 5754 it, value, attributes, THROW_ON_ERROR, handling)); 5755 return value; 5756 } 5757 5758 5759 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( 5760 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 5761 ShouldThrow should_throw, AccessorInfoHandling handling) { 5762 it->UpdateProtector(); 5763 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 5764 5765 for (; it->IsFound(); it->Next()) { 5766 switch (it->state()) { 5767 case LookupIterator::JSPROXY: 5768 case LookupIterator::NOT_FOUND: 5769 case LookupIterator::TRANSITION: 5770 UNREACHABLE(); 5771 5772 case LookupIterator::ACCESS_CHECK: 5773 if (!it->HasAccess()) { 5774 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 5775 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 5776 return Just(true); 5777 } 5778 break; 5779 5780 // If there's an interceptor, try to store the property with the 5781 // interceptor. 5782 // In case of success, the attributes will have been reset to the default 5783 // attributes of the interceptor, rather than the incoming attributes. 5784 // 5785 // TODO(verwaest): JSProxy afterwards verify the attributes that the 5786 // JSProxy claims it has, and verifies that they are compatible. If not, 5787 // they throw. Here we should do the same. 5788 case LookupIterator::INTERCEPTOR: 5789 if (handling == DONT_FORCE_FIELD) { 5790 Maybe<bool> result = 5791 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 5792 if (result.IsNothing() || result.FromJust()) return result; 5793 } 5794 break; 5795 5796 case LookupIterator::ACCESSOR: { 5797 Handle<Object> accessors = it->GetAccessors(); 5798 5799 // Special handling for AccessorInfo, which behaves like a data 5800 // property. 5801 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) { 5802 PropertyAttributes current_attributes = it->property_attributes(); 5803 // Ensure the context isn't changed after calling into accessors. 5804 AssertNoContextChange ncc(it->isolate()); 5805 5806 // Update the attributes before calling the setter. The setter may 5807 // later change the shape of the property. 5808 if (current_attributes != attributes) { 5809 it->TransitionToAccessorPair(accessors, attributes); 5810 } 5811 5812 return JSObject::SetPropertyWithAccessor(it, value, should_throw); 5813 } 5814 5815 it->ReconfigureDataProperty(value, attributes); 5816 return Just(true); 5817 } 5818 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5819 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value, 5820 should_throw); 5821 5822 case LookupIterator::DATA: { 5823 // Regular property update if the attributes match. 5824 if (it->property_attributes() == attributes) { 5825 return SetDataProperty(it, value); 5826 } 5827 5828 // Special case: properties of typed arrays cannot be reconfigured to 5829 // non-writable nor to non-enumerable. 5830 if (it->IsElement() && object->HasFixedTypedArrayElements()) { 5831 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), 5832 value, should_throw); 5833 } 5834 5835 // Reconfigure the data property if the attributes mismatch. 5836 it->ReconfigureDataProperty(value, attributes); 5837 5838 return Just(true); 5839 } 5840 } 5841 } 5842 5843 return AddDataProperty(it, value, attributes, should_throw, 5844 CERTAINLY_NOT_STORE_FROM_KEYED); 5845 } 5846 5847 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( 5848 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, 5849 PropertyAttributes attributes) { 5850 DCHECK(!value->IsTheHole(object->GetIsolate())); 5851 LookupIterator it(object, name, object, LookupIterator::OWN); 5852 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5853 } 5854 5855 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes( 5856 Handle<JSObject> object, uint32_t index, Handle<Object> value, 5857 PropertyAttributes attributes) { 5858 Isolate* isolate = object->GetIsolate(); 5859 LookupIterator it(isolate, object, index, object, LookupIterator::OWN); 5860 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5861 } 5862 5863 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes( 5864 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, 5865 PropertyAttributes attributes) { 5866 Isolate* isolate = object->GetIsolate(); 5867 LookupIterator it = LookupIterator::PropertyOrElement( 5868 isolate, object, name, object, LookupIterator::OWN); 5869 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5870 } 5871 5872 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( 5873 LookupIterator* it) { 5874 return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor()); 5875 } 5876 5877 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes( 5878 LookupIterator* it) { 5879 for (; it->IsFound(); it->Next()) { 5880 switch (it->state()) { 5881 case LookupIterator::NOT_FOUND: 5882 case LookupIterator::TRANSITION: 5883 UNREACHABLE(); 5884 case LookupIterator::JSPROXY: 5885 return JSProxy::GetPropertyAttributes(it); 5886 case LookupIterator::INTERCEPTOR: { 5887 Maybe<PropertyAttributes> result = 5888 JSObject::GetPropertyAttributesWithInterceptor(it); 5889 if (!result.IsJust()) return result; 5890 if (result.FromJust() != ABSENT) return result; 5891 break; 5892 } 5893 case LookupIterator::ACCESS_CHECK: 5894 if (it->HasAccess()) break; 5895 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it); 5896 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5897 return Just(ABSENT); 5898 case LookupIterator::ACCESSOR: 5899 case LookupIterator::DATA: 5900 return Just(it->property_attributes()); 5901 } 5902 } 5903 return Just(ABSENT); 5904 } 5905 5906 5907 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) { 5908 Handle<FixedArray> array( 5909 isolate->factory()->NewFixedArray(kEntries, TENURED)); 5910 return Handle<NormalizedMapCache>::cast(array); 5911 } 5912 5913 5914 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map, 5915 PropertyNormalizationMode mode) { 5916 DisallowHeapAllocation no_gc; 5917 Object* value = FixedArray::get(GetIndex(fast_map)); 5918 if (!value->IsMap() || 5919 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) { 5920 return MaybeHandle<Map>(); 5921 } 5922 return handle(Map::cast(value)); 5923 } 5924 5925 5926 void NormalizedMapCache::Set(Handle<Map> fast_map, 5927 Handle<Map> normalized_map) { 5928 DisallowHeapAllocation no_gc; 5929 DCHECK(normalized_map->is_dictionary_map()); 5930 FixedArray::set(GetIndex(fast_map), *normalized_map); 5931 } 5932 5933 5934 void NormalizedMapCache::Clear() { 5935 int entries = length(); 5936 for (int i = 0; i != entries; i++) { 5937 set_undefined(i); 5938 } 5939 } 5940 5941 5942 void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object, 5943 Handle<Name> name, 5944 Handle<Code> code) { 5945 Handle<Map> map(object->map()); 5946 Map::UpdateCodeCache(map, name, code); 5947 } 5948 5949 5950 void JSObject::NormalizeProperties(Handle<JSObject> object, 5951 PropertyNormalizationMode mode, 5952 int expected_additional_properties, 5953 const char* reason) { 5954 if (!object->HasFastProperties()) return; 5955 5956 Handle<Map> map(object->map()); 5957 Handle<Map> new_map = Map::Normalize(map, mode, reason); 5958 5959 MigrateToMap(object, new_map, expected_additional_properties); 5960 } 5961 5962 5963 void JSObject::MigrateSlowToFast(Handle<JSObject> object, 5964 int unused_property_fields, 5965 const char* reason) { 5966 if (object->HasFastProperties()) return; 5967 DCHECK(!object->IsJSGlobalObject()); 5968 Isolate* isolate = object->GetIsolate(); 5969 Factory* factory = isolate->factory(); 5970 Handle<NameDictionary> dictionary(object->property_dictionary()); 5971 5972 // Make sure we preserve dictionary representation if there are too many 5973 // descriptors. 5974 int number_of_elements = dictionary->NumberOfElements(); 5975 if (number_of_elements > kMaxNumberOfDescriptors) return; 5976 5977 Handle<FixedArray> iteration_order; 5978 if (number_of_elements != dictionary->NextEnumerationIndex()) { 5979 iteration_order = 5980 NameDictionary::DoGenerateNewEnumerationIndices(dictionary); 5981 } else { 5982 iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary); 5983 } 5984 5985 int instance_descriptor_length = iteration_order->length(); 5986 int number_of_fields = 0; 5987 5988 // Compute the length of the instance descriptor. 5989 for (int i = 0; i < instance_descriptor_length; i++) { 5990 int index = Smi::cast(iteration_order->get(i))->value(); 5991 DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index))); 5992 5993 Object* value = dictionary->ValueAt(index); 5994 PropertyType type = dictionary->DetailsAt(index).type(); 5995 if (type == DATA && !value->IsJSFunction()) { 5996 number_of_fields += 1; 5997 } 5998 } 5999 6000 Handle<Map> old_map(object->map(), isolate); 6001 6002 int inobject_props = old_map->GetInObjectProperties(); 6003 6004 // Allocate new map. 6005 Handle<Map> new_map = Map::CopyDropDescriptors(old_map); 6006 new_map->set_dictionary_map(false); 6007 6008 NotifyMapChange(old_map, new_map, isolate); 6009 6010 #if TRACE_MAPS 6011 if (FLAG_trace_maps) { 6012 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n", 6013 reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map), 6014 reason); 6015 } 6016 #endif 6017 6018 if (instance_descriptor_length == 0) { 6019 DisallowHeapAllocation no_gc; 6020 DCHECK_LE(unused_property_fields, inobject_props); 6021 // Transform the object. 6022 new_map->set_unused_property_fields(inobject_props); 6023 object->synchronized_set_map(*new_map); 6024 object->set_properties(isolate->heap()->empty_fixed_array()); 6025 // Check that it really works. 6026 DCHECK(object->HasFastProperties()); 6027 return; 6028 } 6029 6030 // Allocate the instance descriptor. 6031 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate( 6032 isolate, instance_descriptor_length, 0, TENURED); 6033 6034 int number_of_allocated_fields = 6035 number_of_fields + unused_property_fields - inobject_props; 6036 if (number_of_allocated_fields < 0) { 6037 // There is enough inobject space for all fields (including unused). 6038 number_of_allocated_fields = 0; 6039 unused_property_fields = inobject_props - number_of_fields; 6040 } 6041 6042 // Allocate the fixed array for the fields. 6043 Handle<FixedArray> fields = factory->NewFixedArray( 6044 number_of_allocated_fields); 6045 6046 // Fill in the instance descriptor and the fields. 6047 int current_offset = 0; 6048 for (int i = 0; i < instance_descriptor_length; i++) { 6049 int index = Smi::cast(iteration_order->get(i))->value(); 6050 Object* k = dictionary->KeyAt(index); 6051 DCHECK(dictionary->IsKey(k)); 6052 // Dictionary keys are internalized upon insertion. 6053 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild. 6054 CHECK(k->IsUniqueName()); 6055 Handle<Name> key(Name::cast(k), isolate); 6056 6057 Object* value = dictionary->ValueAt(index); 6058 6059 PropertyDetails details = dictionary->DetailsAt(index); 6060 int enumeration_index = details.dictionary_index(); 6061 PropertyType type = details.type(); 6062 6063 if (value->IsJSFunction()) { 6064 DataConstantDescriptor d(key, handle(value, isolate), 6065 details.attributes()); 6066 descriptors->Set(enumeration_index - 1, &d); 6067 } else if (type == DATA) { 6068 if (current_offset < inobject_props) { 6069 object->InObjectPropertyAtPut(current_offset, value, 6070 UPDATE_WRITE_BARRIER); 6071 } else { 6072 int offset = current_offset - inobject_props; 6073 fields->set(offset, value); 6074 } 6075 DataDescriptor d(key, current_offset, details.attributes(), 6076 // TODO(verwaest): value->OptimalRepresentation(); 6077 Representation::Tagged()); 6078 current_offset += d.GetDetails().field_width_in_words(); 6079 descriptors->Set(enumeration_index - 1, &d); 6080 } else if (type == ACCESSOR_CONSTANT) { 6081 AccessorConstantDescriptor d(key, handle(value, isolate), 6082 details.attributes()); 6083 descriptors->Set(enumeration_index - 1, &d); 6084 } else { 6085 UNREACHABLE(); 6086 } 6087 } 6088 DCHECK(current_offset == number_of_fields); 6089 6090 descriptors->Sort(); 6091 6092 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New( 6093 new_map, descriptors, descriptors->number_of_descriptors()); 6094 6095 DisallowHeapAllocation no_gc; 6096 new_map->InitializeDescriptors(*descriptors, *layout_descriptor); 6097 new_map->set_unused_property_fields(unused_property_fields); 6098 6099 // Transform the object. 6100 object->synchronized_set_map(*new_map); 6101 6102 object->set_properties(*fields); 6103 DCHECK(object->IsJSObject()); 6104 6105 // Check that it really works. 6106 DCHECK(object->HasFastProperties()); 6107 } 6108 6109 6110 void JSObject::ResetElements(Handle<JSObject> object) { 6111 Isolate* isolate = object->GetIsolate(); 6112 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map()); 6113 if (object->map()->has_dictionary_elements()) { 6114 Handle<SeededNumberDictionary> new_elements = 6115 SeededNumberDictionary::New(isolate, 0); 6116 object->set_elements(*new_elements); 6117 } else { 6118 object->set_elements(object->map()->GetInitialElements()); 6119 } 6120 } 6121 6122 6123 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) { 6124 if (dictionary->requires_slow_elements()) return; 6125 dictionary->set_requires_slow_elements(); 6126 // TODO(verwaest): Remove this hack. 6127 if (map()->is_prototype_map()) { 6128 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate()); 6129 } 6130 } 6131 6132 6133 Handle<SeededNumberDictionary> JSObject::NormalizeElements( 6134 Handle<JSObject> object) { 6135 DCHECK(!object->HasFixedTypedArrayElements()); 6136 Isolate* isolate = object->GetIsolate(); 6137 bool is_arguments = object->HasSloppyArgumentsElements(); 6138 { 6139 DisallowHeapAllocation no_gc; 6140 FixedArrayBase* elements = object->elements(); 6141 6142 if (is_arguments) { 6143 FixedArray* parameter_map = FixedArray::cast(elements); 6144 elements = FixedArrayBase::cast(parameter_map->get(1)); 6145 } 6146 6147 if (elements->IsDictionary()) { 6148 return handle(SeededNumberDictionary::cast(elements), isolate); 6149 } 6150 } 6151 6152 DCHECK(object->HasFastSmiOrObjectElements() || 6153 object->HasFastDoubleElements() || 6154 object->HasFastArgumentsElements() || 6155 object->HasFastStringWrapperElements()); 6156 6157 Handle<SeededNumberDictionary> dictionary = 6158 object->GetElementsAccessor()->Normalize(object); 6159 6160 // Switch to using the dictionary as the backing storage for elements. 6161 ElementsKind target_kind = is_arguments 6162 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS 6163 : object->HasFastStringWrapperElements() 6164 ? SLOW_STRING_WRAPPER_ELEMENTS 6165 : DICTIONARY_ELEMENTS; 6166 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); 6167 // Set the new map first to satify the elements type assert in set_elements(). 6168 JSObject::MigrateToMap(object, new_map); 6169 6170 if (is_arguments) { 6171 FixedArray::cast(object->elements())->set(1, *dictionary); 6172 } else { 6173 object->set_elements(*dictionary); 6174 } 6175 6176 isolate->counters()->elements_to_dictionary()->Increment(); 6177 6178 #ifdef DEBUG 6179 if (FLAG_trace_normalization) { 6180 OFStream os(stdout); 6181 os << "Object elements have been normalized:\n"; 6182 object->Print(os); 6183 } 6184 #endif 6185 6186 DCHECK(object->HasDictionaryElements() || 6187 object->HasSlowArgumentsElements() || 6188 object->HasSlowStringWrapperElements()); 6189 return dictionary; 6190 } 6191 6192 6193 template <typename ProxyType> 6194 static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate, 6195 Handle<ProxyType> proxy) { 6196 Object* maybe_hash = proxy->hash(); 6197 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash); 6198 6199 Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue)); 6200 proxy->set_hash(hash); 6201 return hash; 6202 } 6203 6204 // static 6205 Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) { 6206 if (object->IsJSGlobalProxy()) { 6207 return JSGlobalProxy::cast(*object)->hash(); 6208 } 6209 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol(); 6210 return *JSReceiver::GetDataProperty(object, hash_code_symbol); 6211 } 6212 6213 // static 6214 Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate, 6215 Handle<JSObject> object) { 6216 if (object->IsJSGlobalProxy()) { 6217 return GetOrCreateIdentityHashHelper(isolate, 6218 Handle<JSGlobalProxy>::cast(object)); 6219 } 6220 6221 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol(); 6222 LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN); 6223 if (it.IsFound()) { 6224 DCHECK_EQ(LookupIterator::DATA, it.state()); 6225 Object* maybe_hash = *it.GetDataValue(); 6226 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash); 6227 } 6228 6229 Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue)); 6230 CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR, 6231 CERTAINLY_NOT_STORE_FROM_KEYED) 6232 .IsJust()); 6233 return hash; 6234 } 6235 6236 // static 6237 Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) { 6238 return proxy->hash(); 6239 } 6240 6241 Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) { 6242 return GetOrCreateIdentityHashHelper(isolate, proxy); 6243 } 6244 6245 6246 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it, 6247 ShouldThrow should_throw) { 6248 Isolate* isolate = it->isolate(); 6249 // Make sure that the top context does not change when doing callbacks or 6250 // interceptor calls. 6251 AssertNoContextChange ncc(isolate); 6252 6253 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 6254 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); 6255 if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>(); 6256 6257 Handle<JSObject> holder = it->GetHolder<JSObject>(); 6258 Handle<Object> receiver = it->GetReceiver(); 6259 if (!receiver->IsJSReceiver()) { 6260 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 6261 Object::ConvertReceiver(isolate, receiver), 6262 Nothing<bool>()); 6263 } 6264 6265 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 6266 *holder, should_throw); 6267 Handle<Object> result; 6268 if (it->IsElement()) { 6269 uint32_t index = it->index(); 6270 v8::IndexedPropertyDeleterCallback deleter = 6271 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter()); 6272 result = args.Call(deleter, index); 6273 } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) { 6274 return Nothing<bool>(); 6275 } else { 6276 Handle<Name> name = it->name(); 6277 DCHECK(!name->IsPrivate()); 6278 v8::GenericNamedPropertyDeleterCallback deleter = 6279 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>( 6280 interceptor->deleter()); 6281 result = args.Call(deleter, name); 6282 } 6283 6284 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6285 if (result.is_null()) return Nothing<bool>(); 6286 6287 DCHECK(result->IsBoolean()); 6288 // Rebox CustomArguments::kReturnValueOffset before returning. 6289 return Just(result->IsTrue(isolate)); 6290 } 6291 6292 6293 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object, 6294 Handle<Name> name, int entry) { 6295 DCHECK(!object->HasFastProperties()); 6296 Isolate* isolate = object->GetIsolate(); 6297 6298 if (object->IsJSGlobalObject()) { 6299 // If we have a global object, invalidate the cell and swap in a new one. 6300 Handle<GlobalDictionary> dictionary( 6301 JSObject::cast(*object)->global_dictionary()); 6302 DCHECK_NE(GlobalDictionary::kNotFound, entry); 6303 6304 auto cell = PropertyCell::InvalidateEntry(dictionary, entry); 6305 cell->set_value(isolate->heap()->the_hole_value()); 6306 cell->set_property_details( 6307 PropertyDetails::Empty(PropertyCellType::kUninitialized)); 6308 } else { 6309 Handle<NameDictionary> dictionary(object->property_dictionary()); 6310 DCHECK_NE(NameDictionary::kNotFound, entry); 6311 6312 NameDictionary::DeleteProperty(dictionary, entry); 6313 Handle<NameDictionary> new_properties = 6314 NameDictionary::Shrink(dictionary, name); 6315 object->set_properties(*new_properties); 6316 } 6317 } 6318 6319 6320 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it, 6321 LanguageMode language_mode) { 6322 it->UpdateProtector(); 6323 6324 Isolate* isolate = it->isolate(); 6325 6326 if (it->state() == LookupIterator::JSPROXY) { 6327 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(), 6328 it->GetName(), language_mode); 6329 } 6330 6331 if (it->GetReceiver()->IsJSProxy()) { 6332 if (it->state() != LookupIterator::NOT_FOUND) { 6333 DCHECK_EQ(LookupIterator::DATA, it->state()); 6334 DCHECK(it->name()->IsPrivate()); 6335 it->Delete(); 6336 } 6337 return Just(true); 6338 } 6339 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); 6340 6341 for (; it->IsFound(); it->Next()) { 6342 switch (it->state()) { 6343 case LookupIterator::JSPROXY: 6344 case LookupIterator::NOT_FOUND: 6345 case LookupIterator::TRANSITION: 6346 UNREACHABLE(); 6347 case LookupIterator::ACCESS_CHECK: 6348 if (it->HasAccess()) break; 6349 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 6350 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6351 return Just(false); 6352 case LookupIterator::INTERCEPTOR: { 6353 ShouldThrow should_throw = 6354 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 6355 Maybe<bool> result = 6356 JSObject::DeletePropertyWithInterceptor(it, should_throw); 6357 // An exception was thrown in the interceptor. Propagate. 6358 if (isolate->has_pending_exception()) return Nothing<bool>(); 6359 // Delete with interceptor succeeded. Return result. 6360 // TODO(neis): In strict mode, we should probably throw if the 6361 // interceptor returns false. 6362 if (result.IsJust()) return result; 6363 break; 6364 } 6365 case LookupIterator::INTEGER_INDEXED_EXOTIC: 6366 return Just(true); 6367 case LookupIterator::DATA: 6368 case LookupIterator::ACCESSOR: { 6369 if (!it->IsConfigurable()) { 6370 // Fail if the property is not configurable. 6371 if (is_strict(language_mode)) { 6372 isolate->Throw(*isolate->factory()->NewTypeError( 6373 MessageTemplate::kStrictDeleteProperty, it->GetName(), 6374 receiver)); 6375 return Nothing<bool>(); 6376 } 6377 return Just(false); 6378 } 6379 6380 it->Delete(); 6381 6382 return Just(true); 6383 } 6384 } 6385 } 6386 6387 return Just(true); 6388 } 6389 6390 6391 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index, 6392 LanguageMode language_mode) { 6393 LookupIterator it(object->GetIsolate(), object, index, object, 6394 LookupIterator::OWN); 6395 return DeleteProperty(&it, language_mode); 6396 } 6397 6398 6399 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object, 6400 Handle<Name> name, 6401 LanguageMode language_mode) { 6402 LookupIterator it(object, name, object, LookupIterator::OWN); 6403 return DeleteProperty(&it, language_mode); 6404 } 6405 6406 6407 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object, 6408 Handle<Name> name, 6409 LanguageMode language_mode) { 6410 LookupIterator it = LookupIterator::PropertyOrElement( 6411 name->GetIsolate(), object, name, object, LookupIterator::OWN); 6412 return DeleteProperty(&it, language_mode); 6413 } 6414 6415 6416 // ES6 7.1.14 6417 // static 6418 MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate, 6419 Handle<Object> value) { 6420 // 1. Let key be ToPrimitive(argument, hint String). 6421 MaybeHandle<Object> maybe_key = 6422 Object::ToPrimitive(value, ToPrimitiveHint::kString); 6423 // 2. ReturnIfAbrupt(key). 6424 Handle<Object> key; 6425 if (!maybe_key.ToHandle(&key)) return key; 6426 // 3. If Type(key) is Symbol, then return key. 6427 if (key->IsSymbol()) return key; 6428 // 4. Return ToString(key). 6429 // Extending spec'ed behavior, we'd be happy to return an element index. 6430 if (key->IsSmi()) return key; 6431 if (key->IsHeapNumber()) { 6432 uint32_t uint_value; 6433 if (value->ToArrayLength(&uint_value) && 6434 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) { 6435 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate); 6436 } 6437 } 6438 return Object::ToString(isolate, key); 6439 } 6440 6441 6442 // ES6 19.1.2.4 6443 // static 6444 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object, 6445 Handle<Object> key, 6446 Handle<Object> attributes) { 6447 // 1. If Type(O) is not Object, throw a TypeError exception. 6448 if (!object->IsJSReceiver()) { 6449 Handle<String> fun_name = 6450 isolate->factory()->InternalizeUtf8String("Object.defineProperty"); 6451 THROW_NEW_ERROR_RETURN_FAILURE( 6452 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name)); 6453 } 6454 // 2. Let key be ToPropertyKey(P). 6455 // 3. ReturnIfAbrupt(key). 6456 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key)); 6457 // 4. Let desc be ToPropertyDescriptor(Attributes). 6458 // 5. ReturnIfAbrupt(desc). 6459 PropertyDescriptor desc; 6460 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) { 6461 return isolate->heap()->exception(); 6462 } 6463 // 6. Let success be DefinePropertyOrThrow(O,key, desc). 6464 Maybe<bool> success = DefineOwnProperty( 6465 isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR); 6466 // 7. ReturnIfAbrupt(success). 6467 MAYBE_RETURN(success, isolate->heap()->exception()); 6468 CHECK(success.FromJust()); 6469 // 8. Return O. 6470 return *object; 6471 } 6472 6473 6474 // ES6 19.1.2.3.1 6475 // static 6476 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate, 6477 Handle<Object> object, 6478 Handle<Object> properties) { 6479 // 1. If Type(O) is not Object, throw a TypeError exception. 6480 if (!object->IsJSReceiver()) { 6481 Handle<String> fun_name = 6482 isolate->factory()->InternalizeUtf8String("Object.defineProperties"); 6483 THROW_NEW_ERROR(isolate, 6484 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name), 6485 Object); 6486 } 6487 // 2. Let props be ToObject(Properties). 6488 // 3. ReturnIfAbrupt(props). 6489 Handle<JSReceiver> props; 6490 ASSIGN_RETURN_ON_EXCEPTION(isolate, props, 6491 Object::ToObject(isolate, properties), Object); 6492 6493 // 4. Let keys be props.[[OwnPropertyKeys]](). 6494 // 5. ReturnIfAbrupt(keys). 6495 Handle<FixedArray> keys; 6496 ASSIGN_RETURN_ON_EXCEPTION( 6497 isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly, 6498 ALL_PROPERTIES), 6499 Object); 6500 // 6. Let descriptors be an empty List. 6501 int capacity = keys->length(); 6502 std::vector<PropertyDescriptor> descriptors(capacity); 6503 size_t descriptors_index = 0; 6504 // 7. Repeat for each element nextKey of keys in List order, 6505 for (int i = 0; i < keys->length(); ++i) { 6506 Handle<Object> next_key(keys->get(i), isolate); 6507 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey). 6508 // 7b. ReturnIfAbrupt(propDesc). 6509 bool success = false; 6510 LookupIterator it = LookupIterator::PropertyOrElement( 6511 isolate, props, next_key, &success, LookupIterator::OWN); 6512 DCHECK(success); 6513 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 6514 if (!maybe.IsJust()) return MaybeHandle<Object>(); 6515 PropertyAttributes attrs = maybe.FromJust(); 6516 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true: 6517 if (attrs == ABSENT) continue; 6518 if (attrs & DONT_ENUM) continue; 6519 // 7c i. Let descObj be Get(props, nextKey). 6520 // 7c ii. ReturnIfAbrupt(descObj). 6521 Handle<Object> desc_obj; 6522 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it), 6523 Object); 6524 // 7c iii. Let desc be ToPropertyDescriptor(descObj). 6525 success = PropertyDescriptor::ToPropertyDescriptor( 6526 isolate, desc_obj, &descriptors[descriptors_index]); 6527 // 7c iv. ReturnIfAbrupt(desc). 6528 if (!success) return MaybeHandle<Object>(); 6529 // 7c v. Append the pair (a two element List) consisting of nextKey and 6530 // desc to the end of descriptors. 6531 descriptors[descriptors_index].set_name(next_key); 6532 descriptors_index++; 6533 } 6534 // 8. For each pair from descriptors in list order, 6535 for (size_t i = 0; i < descriptors_index; ++i) { 6536 PropertyDescriptor* desc = &descriptors[i]; 6537 // 8a. Let P be the first element of pair. 6538 // 8b. Let desc be the second element of pair. 6539 // 8c. Let status be DefinePropertyOrThrow(O, P, desc). 6540 Maybe<bool> status = 6541 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object), 6542 desc->name(), desc, THROW_ON_ERROR); 6543 // 8d. ReturnIfAbrupt(status). 6544 if (!status.IsJust()) return MaybeHandle<Object>(); 6545 CHECK(status.FromJust()); 6546 } 6547 // 9. Return o. 6548 return object; 6549 } 6550 6551 6552 // static 6553 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate, 6554 Handle<JSReceiver> object, 6555 Handle<Object> key, 6556 PropertyDescriptor* desc, 6557 ShouldThrow should_throw) { 6558 if (object->IsJSArray()) { 6559 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object), 6560 key, desc, should_throw); 6561 } 6562 if (object->IsJSProxy()) { 6563 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object), 6564 key, desc, should_throw); 6565 } 6566 // TODO(neis): Special case for JSModuleNamespace? 6567 6568 // OrdinaryDefineOwnProperty, by virtue of calling 6569 // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2) 6570 // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception: 6571 // TODO(jkummerow): Setting an indexed accessor on a typed array should throw. 6572 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key, 6573 desc, should_throw); 6574 } 6575 6576 6577 // static 6578 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, 6579 Handle<JSObject> object, 6580 Handle<Object> key, 6581 PropertyDescriptor* desc, 6582 ShouldThrow should_throw) { 6583 bool success = false; 6584 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... 6585 LookupIterator it = LookupIterator::PropertyOrElement( 6586 isolate, object, key, &success, LookupIterator::OWN); 6587 DCHECK(success); // ...so creating a LookupIterator can't fail. 6588 6589 // Deal with access checks first. 6590 if (it.state() == LookupIterator::ACCESS_CHECK) { 6591 if (!it.HasAccess()) { 6592 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); 6593 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6594 return Just(true); 6595 } 6596 it.Next(); 6597 } 6598 6599 // Handle interceptor 6600 if (it.state() == LookupIterator::INTERCEPTOR) { 6601 if (it.HolderIsReceiverOrHiddenPrototype()) { 6602 Maybe<bool> result = DefinePropertyWithInterceptorInternal( 6603 &it, it.GetInterceptor(), should_throw, *desc); 6604 if (result.IsNothing() || result.FromJust()) { 6605 return result; 6606 } 6607 } 6608 } 6609 6610 return OrdinaryDefineOwnProperty(&it, desc, should_throw); 6611 } 6612 6613 6614 // ES6 9.1.6.1 6615 // static 6616 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it, 6617 PropertyDescriptor* desc, 6618 ShouldThrow should_throw) { 6619 Isolate* isolate = it->isolate(); 6620 // 1. Let current be O.[[GetOwnProperty]](P). 6621 // 2. ReturnIfAbrupt(current). 6622 PropertyDescriptor current; 6623 MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>()); 6624 6625 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset 6626 // the iterator every time. Currently, the reasons why we need it are: 6627 // - handle interceptors correctly 6628 // - handle accessors correctly (which might change the holder's map) 6629 it->Restart(); 6630 // 3. Let extensible be the value of the [[Extensible]] internal slot of O. 6631 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 6632 bool extensible = JSObject::IsExtensible(object); 6633 6634 return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc, 6635 ¤t, should_throw); 6636 } 6637 6638 6639 // ES6 9.1.6.2 6640 // static 6641 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor( 6642 Isolate* isolate, bool extensible, PropertyDescriptor* desc, 6643 PropertyDescriptor* current, Handle<Name> property_name, 6644 ShouldThrow should_throw) { 6645 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, 6646 // Extensible, Desc, Current). 6647 return ValidateAndApplyPropertyDescriptor( 6648 isolate, NULL, extensible, desc, current, should_throw, property_name); 6649 } 6650 6651 6652 // ES6 9.1.6.3 6653 // static 6654 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor( 6655 Isolate* isolate, LookupIterator* it, bool extensible, 6656 PropertyDescriptor* desc, PropertyDescriptor* current, 6657 ShouldThrow should_throw, Handle<Name> property_name) { 6658 // We either need a LookupIterator, or a property name. 6659 DCHECK((it == NULL) != property_name.is_null()); 6660 Handle<JSObject> object; 6661 if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver()); 6662 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc); 6663 bool desc_is_accessor_descriptor = 6664 PropertyDescriptor::IsAccessorDescriptor(desc); 6665 bool desc_is_generic_descriptor = 6666 PropertyDescriptor::IsGenericDescriptor(desc); 6667 // 1. (Assert) 6668 // 2. If current is undefined, then 6669 if (current->is_empty()) { 6670 // 2a. If extensible is false, return false. 6671 if (!extensible) { 6672 RETURN_FAILURE(isolate, should_throw, 6673 NewTypeError(MessageTemplate::kDefineDisallowed, 6674 it != NULL ? it->GetName() : property_name)); 6675 } 6676 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then: 6677 // (This is equivalent to !IsAccessorDescriptor(desc).) 6678 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) == 6679 !desc_is_accessor_descriptor); 6680 if (!desc_is_accessor_descriptor) { 6681 // 2c i. If O is not undefined, create an own data property named P of 6682 // object O whose [[Value]], [[Writable]], [[Enumerable]] and 6683 // [[Configurable]] attribute values are described by Desc. If the value 6684 // of an attribute field of Desc is absent, the attribute of the newly 6685 // created property is set to its default value. 6686 if (it != NULL) { 6687 if (!desc->has_writable()) desc->set_writable(false); 6688 if (!desc->has_enumerable()) desc->set_enumerable(false); 6689 if (!desc->has_configurable()) desc->set_configurable(false); 6690 Handle<Object> value( 6691 desc->has_value() 6692 ? desc->value() 6693 : Handle<Object>::cast(isolate->factory()->undefined_value())); 6694 MaybeHandle<Object> result = 6695 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, 6696 desc->ToAttributes()); 6697 if (result.is_null()) return Nothing<bool>(); 6698 } 6699 } else { 6700 // 2d. Else Desc must be an accessor Property Descriptor, 6701 DCHECK(desc_is_accessor_descriptor); 6702 // 2d i. If O is not undefined, create an own accessor property named P 6703 // of object O whose [[Get]], [[Set]], [[Enumerable]] and 6704 // [[Configurable]] attribute values are described by Desc. If the value 6705 // of an attribute field of Desc is absent, the attribute of the newly 6706 // created property is set to its default value. 6707 if (it != NULL) { 6708 if (!desc->has_enumerable()) desc->set_enumerable(false); 6709 if (!desc->has_configurable()) desc->set_configurable(false); 6710 Handle<Object> getter( 6711 desc->has_get() 6712 ? desc->get() 6713 : Handle<Object>::cast(isolate->factory()->null_value())); 6714 Handle<Object> setter( 6715 desc->has_set() 6716 ? desc->set() 6717 : Handle<Object>::cast(isolate->factory()->null_value())); 6718 MaybeHandle<Object> result = 6719 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes()); 6720 if (result.is_null()) return Nothing<bool>(); 6721 } 6722 } 6723 // 2e. Return true. 6724 return Just(true); 6725 } 6726 // 3. Return true, if every field in Desc is absent. 6727 // 4. Return true, if every field in Desc also occurs in current and the 6728 // value of every field in Desc is the same value as the corresponding field 6729 // in current when compared using the SameValue algorithm. 6730 if ((!desc->has_enumerable() || 6731 desc->enumerable() == current->enumerable()) && 6732 (!desc->has_configurable() || 6733 desc->configurable() == current->configurable()) && 6734 (!desc->has_value() || 6735 (current->has_value() && current->value()->SameValue(*desc->value()))) && 6736 (!desc->has_writable() || 6737 (current->has_writable() && current->writable() == desc->writable())) && 6738 (!desc->has_get() || 6739 (current->has_get() && current->get()->SameValue(*desc->get()))) && 6740 (!desc->has_set() || 6741 (current->has_set() && current->set()->SameValue(*desc->set())))) { 6742 return Just(true); 6743 } 6744 // 5. If the [[Configurable]] field of current is false, then 6745 if (!current->configurable()) { 6746 // 5a. Return false, if the [[Configurable]] field of Desc is true. 6747 if (desc->has_configurable() && desc->configurable()) { 6748 RETURN_FAILURE(isolate, should_throw, 6749 NewTypeError(MessageTemplate::kRedefineDisallowed, 6750 it != NULL ? it->GetName() : property_name)); 6751 } 6752 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the 6753 // [[Enumerable]] fields of current and Desc are the Boolean negation of 6754 // each other. 6755 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) { 6756 RETURN_FAILURE(isolate, should_throw, 6757 NewTypeError(MessageTemplate::kRedefineDisallowed, 6758 it != NULL ? it->GetName() : property_name)); 6759 } 6760 } 6761 6762 bool current_is_data_descriptor = 6763 PropertyDescriptor::IsDataDescriptor(current); 6764 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required. 6765 if (desc_is_generic_descriptor) { 6766 // Nothing to see here. 6767 6768 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have 6769 // different results, then: 6770 } else if (current_is_data_descriptor != desc_is_data_descriptor) { 6771 // 7a. Return false, if the [[Configurable]] field of current is false. 6772 if (!current->configurable()) { 6773 RETURN_FAILURE(isolate, should_throw, 6774 NewTypeError(MessageTemplate::kRedefineDisallowed, 6775 it != NULL ? it->GetName() : property_name)); 6776 } 6777 // 7b. If IsDataDescriptor(current) is true, then: 6778 if (current_is_data_descriptor) { 6779 // 7b i. If O is not undefined, convert the property named P of object O 6780 // from a data property to an accessor property. Preserve the existing 6781 // values of the converted property's [[Configurable]] and [[Enumerable]] 6782 // attributes and set the rest of the property's attributes to their 6783 // default values. 6784 // --> Folded into step 10. 6785 } else { 6786 // 7c i. If O is not undefined, convert the property named P of object O 6787 // from an accessor property to a data property. Preserve the existing 6788 // values of the converted propertys [[Configurable]] and [[Enumerable]] 6789 // attributes and set the rest of the propertys attributes to their 6790 // default values. 6791 // --> Folded into step 10. 6792 } 6793 6794 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both 6795 // true, then: 6796 } else if (current_is_data_descriptor && desc_is_data_descriptor) { 6797 // 8a. If the [[Configurable]] field of current is false, then: 6798 if (!current->configurable()) { 6799 // 8a i. Return false, if the [[Writable]] field of current is false and 6800 // the [[Writable]] field of Desc is true. 6801 if (!current->writable() && desc->has_writable() && desc->writable()) { 6802 RETURN_FAILURE( 6803 isolate, should_throw, 6804 NewTypeError(MessageTemplate::kRedefineDisallowed, 6805 it != NULL ? it->GetName() : property_name)); 6806 } 6807 // 8a ii. If the [[Writable]] field of current is false, then: 6808 if (!current->writable()) { 6809 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and 6810 // SameValue(Desc.[[Value]], current.[[Value]]) is false. 6811 if (desc->has_value() && !desc->value()->SameValue(*current->value())) { 6812 RETURN_FAILURE( 6813 isolate, should_throw, 6814 NewTypeError(MessageTemplate::kRedefineDisallowed, 6815 it != NULL ? it->GetName() : property_name)); 6816 } 6817 } 6818 } 6819 } else { 6820 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) 6821 // are both true, 6822 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) && 6823 desc_is_accessor_descriptor); 6824 // 9a. If the [[Configurable]] field of current is false, then: 6825 if (!current->configurable()) { 6826 // 9a i. Return false, if the [[Set]] field of Desc is present and 6827 // SameValue(Desc.[[Set]], current.[[Set]]) is false. 6828 if (desc->has_set() && !desc->set()->SameValue(*current->set())) { 6829 RETURN_FAILURE( 6830 isolate, should_throw, 6831 NewTypeError(MessageTemplate::kRedefineDisallowed, 6832 it != NULL ? it->GetName() : property_name)); 6833 } 6834 // 9a ii. Return false, if the [[Get]] field of Desc is present and 6835 // SameValue(Desc.[[Get]], current.[[Get]]) is false. 6836 if (desc->has_get() && !desc->get()->SameValue(*current->get())) { 6837 RETURN_FAILURE( 6838 isolate, should_throw, 6839 NewTypeError(MessageTemplate::kRedefineDisallowed, 6840 it != NULL ? it->GetName() : property_name)); 6841 } 6842 } 6843 } 6844 6845 // 10. If O is not undefined, then: 6846 if (it != NULL) { 6847 // 10a. For each field of Desc that is present, set the corresponding 6848 // attribute of the property named P of object O to the value of the field. 6849 PropertyAttributes attrs = NONE; 6850 6851 if (desc->has_enumerable()) { 6852 attrs = static_cast<PropertyAttributes>( 6853 attrs | (desc->enumerable() ? NONE : DONT_ENUM)); 6854 } else { 6855 attrs = static_cast<PropertyAttributes>( 6856 attrs | (current->enumerable() ? NONE : DONT_ENUM)); 6857 } 6858 if (desc->has_configurable()) { 6859 attrs = static_cast<PropertyAttributes>( 6860 attrs | (desc->configurable() ? NONE : DONT_DELETE)); 6861 } else { 6862 attrs = static_cast<PropertyAttributes>( 6863 attrs | (current->configurable() ? NONE : DONT_DELETE)); 6864 } 6865 if (desc_is_data_descriptor || 6866 (desc_is_generic_descriptor && current_is_data_descriptor)) { 6867 if (desc->has_writable()) { 6868 attrs = static_cast<PropertyAttributes>( 6869 attrs | (desc->writable() ? NONE : READ_ONLY)); 6870 } else { 6871 attrs = static_cast<PropertyAttributes>( 6872 attrs | (current->writable() ? NONE : READ_ONLY)); 6873 } 6874 Handle<Object> value( 6875 desc->has_value() ? desc->value() 6876 : current->has_value() 6877 ? current->value() 6878 : Handle<Object>::cast( 6879 isolate->factory()->undefined_value())); 6880 MaybeHandle<Object> result = 6881 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs); 6882 if (result.is_null()) return Nothing<bool>(); 6883 } else { 6884 DCHECK(desc_is_accessor_descriptor || 6885 (desc_is_generic_descriptor && 6886 PropertyDescriptor::IsAccessorDescriptor(current))); 6887 Handle<Object> getter( 6888 desc->has_get() 6889 ? desc->get() 6890 : current->has_get() 6891 ? current->get() 6892 : Handle<Object>::cast(isolate->factory()->null_value())); 6893 Handle<Object> setter( 6894 desc->has_set() 6895 ? desc->set() 6896 : current->has_set() 6897 ? current->set() 6898 : Handle<Object>::cast(isolate->factory()->null_value())); 6899 MaybeHandle<Object> result = 6900 JSObject::DefineAccessor(it, getter, setter, attrs); 6901 if (result.is_null()) return Nothing<bool>(); 6902 } 6903 } 6904 6905 // 11. Return true. 6906 return Just(true); 6907 } 6908 6909 6910 // static 6911 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it, 6912 Handle<Object> value, 6913 ShouldThrow should_throw) { 6914 DCHECK(!it->check_prototype_chain()); 6915 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 6916 Isolate* isolate = receiver->GetIsolate(); 6917 6918 if (receiver->IsJSObject()) { 6919 return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut. 6920 } 6921 6922 PropertyDescriptor new_desc; 6923 new_desc.set_value(value); 6924 new_desc.set_writable(true); 6925 new_desc.set_enumerable(true); 6926 new_desc.set_configurable(true); 6927 6928 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 6929 &new_desc, should_throw); 6930 } 6931 6932 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it, 6933 Handle<Object> value, 6934 ShouldThrow should_throw) { 6935 DCHECK(it->GetReceiver()->IsJSObject()); 6936 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>()); 6937 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 6938 Isolate* isolate = receiver->GetIsolate(); 6939 6940 if (it->IsFound()) { 6941 Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it); 6942 MAYBE_RETURN(attributes, Nothing<bool>()); 6943 if ((attributes.FromJust() & DONT_DELETE) != 0) { 6944 RETURN_FAILURE( 6945 isolate, should_throw, 6946 NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName())); 6947 } 6948 } else { 6949 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) { 6950 RETURN_FAILURE( 6951 isolate, should_throw, 6952 NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName())); 6953 } 6954 } 6955 6956 RETURN_ON_EXCEPTION_VALUE(it->isolate(), 6957 DefineOwnPropertyIgnoreAttributes(it, value, NONE), 6958 Nothing<bool>()); 6959 6960 return Just(true); 6961 } 6962 6963 6964 // TODO(jkummerow): Consider unification with FastAsArrayLength() in 6965 // accessors.cc. 6966 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) { 6967 DCHECK(value->IsNumber() || value->IsName()); 6968 if (value->ToArrayLength(length)) return true; 6969 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length); 6970 return false; 6971 } 6972 6973 6974 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) { 6975 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32; 6976 } 6977 6978 6979 // ES6 9.4.2.1 6980 // static 6981 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o, 6982 Handle<Object> name, 6983 PropertyDescriptor* desc, 6984 ShouldThrow should_throw) { 6985 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.) 6986 // 2. If P is "length", then: 6987 // TODO(jkummerow): Check if we need slow string comparison. 6988 if (*name == isolate->heap()->length_string()) { 6989 // 2a. Return ArraySetLength(A, Desc). 6990 return ArraySetLength(isolate, o, desc, should_throw); 6991 } 6992 // 3. Else if P is an array index, then: 6993 uint32_t index = 0; 6994 if (PropertyKeyToArrayIndex(name, &index)) { 6995 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 6996 PropertyDescriptor old_len_desc; 6997 Maybe<bool> success = GetOwnPropertyDescriptor( 6998 isolate, o, isolate->factory()->length_string(), &old_len_desc); 6999 // 3b. (Assert) 7000 DCHECK(success.FromJust()); 7001 USE(success); 7002 // 3c. Let oldLen be oldLenDesc.[[Value]]. 7003 uint32_t old_len = 0; 7004 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 7005 // 3d. Let index be ToUint32(P). 7006 // (Already done above.) 7007 // 3e. (Assert) 7008 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false, 7009 // return false. 7010 if (index >= old_len && old_len_desc.has_writable() && 7011 !old_len_desc.writable()) { 7012 RETURN_FAILURE(isolate, should_throw, 7013 NewTypeError(MessageTemplate::kDefineDisallowed, name)); 7014 } 7015 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc). 7016 Maybe<bool> succeeded = 7017 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 7018 // 3h. Assert: succeeded is not an abrupt completion. 7019 // In our case, if should_throw == THROW_ON_ERROR, it can be! 7020 // 3i. If succeeded is false, return false. 7021 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded; 7022 // 3j. If index >= oldLen, then: 7023 if (index >= old_len) { 7024 // 3j i. Set oldLenDesc.[[Value]] to index + 1. 7025 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1)); 7026 // 3j ii. Let succeeded be 7027 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc). 7028 succeeded = OrdinaryDefineOwnProperty(isolate, o, 7029 isolate->factory()->length_string(), 7030 &old_len_desc, should_throw); 7031 // 3j iii. Assert: succeeded is true. 7032 DCHECK(succeeded.FromJust()); 7033 USE(succeeded); 7034 } 7035 // 3k. Return true. 7036 return Just(true); 7037 } 7038 7039 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc). 7040 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 7041 } 7042 7043 7044 // Part of ES6 9.4.2.4 ArraySetLength. 7045 // static 7046 bool JSArray::AnythingToArrayLength(Isolate* isolate, 7047 Handle<Object> length_object, 7048 uint32_t* output) { 7049 // Fast path: check numbers and strings that can be converted directly 7050 // and unobservably. 7051 if (length_object->ToArrayLength(output)) return true; 7052 if (length_object->IsString() && 7053 Handle<String>::cast(length_object)->AsArrayIndex(output)) { 7054 return true; 7055 } 7056 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength". 7057 // 3. Let newLen be ToUint32(Desc.[[Value]]). 7058 Handle<Object> uint32_v; 7059 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) { 7060 // 4. ReturnIfAbrupt(newLen). 7061 return false; 7062 } 7063 // 5. Let numberLen be ToNumber(Desc.[[Value]]). 7064 Handle<Object> number_v; 7065 if (!Object::ToNumber(length_object).ToHandle(&number_v)) { 7066 // 6. ReturnIfAbrupt(newLen). 7067 return false; 7068 } 7069 // 7. If newLen != numberLen, throw a RangeError exception. 7070 if (uint32_v->Number() != number_v->Number()) { 7071 Handle<Object> exception = 7072 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength); 7073 isolate->Throw(*exception); 7074 return false; 7075 } 7076 CHECK(uint32_v->ToArrayLength(output)); 7077 return true; 7078 } 7079 7080 7081 // ES6 9.4.2.4 7082 // static 7083 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a, 7084 PropertyDescriptor* desc, 7085 ShouldThrow should_throw) { 7086 // 1. If the [[Value]] field of Desc is absent, then 7087 if (!desc->has_value()) { 7088 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc). 7089 return OrdinaryDefineOwnProperty( 7090 isolate, a, isolate->factory()->length_string(), desc, should_throw); 7091 } 7092 // 2. Let newLenDesc be a copy of Desc. 7093 // (Actual copying is not necessary.) 7094 PropertyDescriptor* new_len_desc = desc; 7095 // 3. - 7. Convert Desc.[[Value]] to newLen. 7096 uint32_t new_len = 0; 7097 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) { 7098 DCHECK(isolate->has_pending_exception()); 7099 return Nothing<bool>(); 7100 } 7101 // 8. Set newLenDesc.[[Value]] to newLen. 7102 // (Done below, if needed.) 7103 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 7104 PropertyDescriptor old_len_desc; 7105 Maybe<bool> success = GetOwnPropertyDescriptor( 7106 isolate, a, isolate->factory()->length_string(), &old_len_desc); 7107 // 10. (Assert) 7108 DCHECK(success.FromJust()); 7109 USE(success); 7110 // 11. Let oldLen be oldLenDesc.[[Value]]. 7111 uint32_t old_len = 0; 7112 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 7113 // 12. If newLen >= oldLen, then 7114 if (new_len >= old_len) { 7115 // 8. Set newLenDesc.[[Value]] to newLen. 7116 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc). 7117 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len)); 7118 return OrdinaryDefineOwnProperty(isolate, a, 7119 isolate->factory()->length_string(), 7120 new_len_desc, should_throw); 7121 } 7122 // 13. If oldLenDesc.[[Writable]] is false, return false. 7123 if (!old_len_desc.writable()) { 7124 RETURN_FAILURE(isolate, should_throw, 7125 NewTypeError(MessageTemplate::kRedefineDisallowed, 7126 isolate->factory()->length_string())); 7127 } 7128 // 14. If newLenDesc.[[Writable]] is absent or has the value true, 7129 // let newWritable be true. 7130 bool new_writable = false; 7131 if (!new_len_desc->has_writable() || new_len_desc->writable()) { 7132 new_writable = true; 7133 } else { 7134 // 15. Else, 7135 // 15a. Need to defer setting the [[Writable]] attribute to false in case 7136 // any elements cannot be deleted. 7137 // 15b. Let newWritable be false. (It's initialized as "false" anyway.) 7138 // 15c. Set newLenDesc.[[Writable]] to true. 7139 // (Not needed.) 7140 } 7141 // Most of steps 16 through 19 is implemented by JSArray::SetLength. 7142 JSArray::SetLength(a, new_len); 7143 // Steps 19d-ii, 20. 7144 if (!new_writable) { 7145 PropertyDescriptor readonly; 7146 readonly.set_writable(false); 7147 Maybe<bool> success = OrdinaryDefineOwnProperty( 7148 isolate, a, isolate->factory()->length_string(), &readonly, 7149 should_throw); 7150 DCHECK(success.FromJust()); 7151 USE(success); 7152 } 7153 uint32_t actual_new_len = 0; 7154 CHECK(a->length()->ToArrayLength(&actual_new_len)); 7155 // Steps 19d-v, 21. Return false if there were non-deletable elements. 7156 bool result = actual_new_len == new_len; 7157 if (!result) { 7158 RETURN_FAILURE( 7159 isolate, should_throw, 7160 NewTypeError(MessageTemplate::kStrictDeleteProperty, 7161 isolate->factory()->NewNumberFromUint(actual_new_len - 1), 7162 a)); 7163 } 7164 return Just(result); 7165 } 7166 7167 7168 // ES6 9.5.6 7169 // static 7170 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy, 7171 Handle<Object> key, 7172 PropertyDescriptor* desc, 7173 ShouldThrow should_throw) { 7174 STACK_CHECK(isolate, Nothing<bool>()); 7175 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) { 7176 return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc, 7177 should_throw); 7178 } 7179 Handle<String> trap_name = isolate->factory()->defineProperty_string(); 7180 // 1. Assert: IsPropertyKey(P) is true. 7181 DCHECK(key->IsName() || key->IsNumber()); 7182 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 7183 Handle<Object> handler(proxy->handler(), isolate); 7184 // 3. If handler is null, throw a TypeError exception. 7185 // 4. Assert: Type(handler) is Object. 7186 if (proxy->IsRevoked()) { 7187 isolate->Throw(*isolate->factory()->NewTypeError( 7188 MessageTemplate::kProxyRevoked, trap_name)); 7189 return Nothing<bool>(); 7190 } 7191 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 7192 Handle<JSReceiver> target(proxy->target(), isolate); 7193 // 6. Let trap be ? GetMethod(handler, "defineProperty"). 7194 Handle<Object> trap; 7195 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7196 isolate, trap, 7197 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 7198 Nothing<bool>()); 7199 // 7. If trap is undefined, then: 7200 if (trap->IsUndefined(isolate)) { 7201 // 7a. Return target.[[DefineOwnProperty]](P, Desc). 7202 return JSReceiver::DefineOwnProperty(isolate, target, key, desc, 7203 should_throw); 7204 } 7205 // 8. Let descObj be FromPropertyDescriptor(Desc). 7206 Handle<Object> desc_obj = desc->ToObject(isolate); 7207 // 9. Let booleanTrapResult be 7208 // ToBoolean(? Call(trap, handler, target, P, descObj)). 7209 Handle<Name> property_name = 7210 key->IsName() 7211 ? Handle<Name>::cast(key) 7212 : Handle<Name>::cast(isolate->factory()->NumberToString(key)); 7213 // Do not leak private property names. 7214 DCHECK(!property_name->IsPrivate()); 7215 Handle<Object> trap_result_obj; 7216 Handle<Object> args[] = {target, property_name, desc_obj}; 7217 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7218 isolate, trap_result_obj, 7219 Execution::Call(isolate, trap, handler, arraysize(args), args), 7220 Nothing<bool>()); 7221 // 10. If booleanTrapResult is false, return false. 7222 if (!trap_result_obj->BooleanValue()) { 7223 RETURN_FAILURE(isolate, should_throw, 7224 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 7225 trap_name, property_name)); 7226 } 7227 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P). 7228 PropertyDescriptor target_desc; 7229 Maybe<bool> target_found = 7230 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc); 7231 MAYBE_RETURN(target_found, Nothing<bool>()); 7232 // 12. Let extensibleTarget be ? IsExtensible(target). 7233 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target); 7234 MAYBE_RETURN(maybe_extensible, Nothing<bool>()); 7235 bool extensible_target = maybe_extensible.FromJust(); 7236 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] 7237 // is false, then: 7238 // 13a. Let settingConfigFalse be true. 7239 // 14. Else let settingConfigFalse be false. 7240 bool setting_config_false = desc->has_configurable() && !desc->configurable(); 7241 // 15. If targetDesc is undefined, then 7242 if (!target_found.FromJust()) { 7243 // 15a. If extensibleTarget is false, throw a TypeError exception. 7244 if (!extensible_target) { 7245 isolate->Throw(*isolate->factory()->NewTypeError( 7246 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name)); 7247 return Nothing<bool>(); 7248 } 7249 // 15b. If settingConfigFalse is true, throw a TypeError exception. 7250 if (setting_config_false) { 7251 isolate->Throw(*isolate->factory()->NewTypeError( 7252 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 7253 return Nothing<bool>(); 7254 } 7255 } else { 7256 // 16. Else targetDesc is not undefined, 7257 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, 7258 // targetDesc) is false, throw a TypeError exception. 7259 Maybe<bool> valid = 7260 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc, 7261 &target_desc, property_name, DONT_THROW); 7262 MAYBE_RETURN(valid, Nothing<bool>()); 7263 if (!valid.FromJust()) { 7264 isolate->Throw(*isolate->factory()->NewTypeError( 7265 MessageTemplate::kProxyDefinePropertyIncompatible, property_name)); 7266 return Nothing<bool>(); 7267 } 7268 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is 7269 // true, throw a TypeError exception. 7270 if (setting_config_false && target_desc.configurable()) { 7271 isolate->Throw(*isolate->factory()->NewTypeError( 7272 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 7273 return Nothing<bool>(); 7274 } 7275 } 7276 // 17. Return true. 7277 return Just(true); 7278 } 7279 7280 7281 // static 7282 Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy, 7283 Handle<Symbol> private_name, 7284 PropertyDescriptor* desc, 7285 ShouldThrow should_throw) { 7286 // Despite the generic name, this can only add private data properties. 7287 if (!PropertyDescriptor::IsDataDescriptor(desc) || 7288 desc->ToAttributes() != DONT_ENUM) { 7289 RETURN_FAILURE(isolate, should_throw, 7290 NewTypeError(MessageTemplate::kProxyPrivate)); 7291 } 7292 DCHECK(proxy->map()->is_dictionary_map()); 7293 Handle<Object> value = 7294 desc->has_value() 7295 ? desc->value() 7296 : Handle<Object>::cast(isolate->factory()->undefined_value()); 7297 7298 LookupIterator it(proxy, private_name, proxy); 7299 7300 if (it.IsFound()) { 7301 DCHECK_EQ(LookupIterator::DATA, it.state()); 7302 DCHECK_EQ(DONT_ENUM, it.property_attributes()); 7303 it.WriteDataValue(value); 7304 return Just(true); 7305 } 7306 7307 Handle<NameDictionary> dict(proxy->property_dictionary()); 7308 PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell); 7309 Handle<NameDictionary> result = 7310 NameDictionary::Add(dict, private_name, value, details); 7311 if (!dict.is_identical_to(result)) proxy->set_properties(*result); 7312 return Just(true); 7313 } 7314 7315 7316 // static 7317 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate, 7318 Handle<JSReceiver> object, 7319 Handle<Object> key, 7320 PropertyDescriptor* desc) { 7321 bool success = false; 7322 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... 7323 LookupIterator it = LookupIterator::PropertyOrElement( 7324 isolate, object, key, &success, LookupIterator::OWN); 7325 DCHECK(success); // ...so creating a LookupIterator can't fail. 7326 return GetOwnPropertyDescriptor(&it, desc); 7327 } 7328 7329 namespace { 7330 7331 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it, 7332 PropertyDescriptor* desc) { 7333 if (it->state() == LookupIterator::INTERCEPTOR) { 7334 Isolate* isolate = it->isolate(); 7335 Handle<InterceptorInfo> interceptor = it->GetInterceptor(); 7336 if (!interceptor->descriptor()->IsUndefined(isolate)) { 7337 Handle<Object> result; 7338 Handle<JSObject> holder = it->GetHolder<JSObject>(); 7339 7340 Handle<Object> receiver = it->GetReceiver(); 7341 if (!receiver->IsJSReceiver()) { 7342 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7343 isolate, receiver, Object::ConvertReceiver(isolate, receiver), 7344 Nothing<bool>()); 7345 } 7346 7347 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 7348 *holder, Object::DONT_THROW); 7349 if (it->IsElement()) { 7350 uint32_t index = it->index(); 7351 v8::IndexedPropertyDescriptorCallback descriptorCallback = 7352 v8::ToCData<v8::IndexedPropertyDescriptorCallback>( 7353 interceptor->descriptor()); 7354 7355 result = args.Call(descriptorCallback, index); 7356 } else { 7357 Handle<Name> name = it->name(); 7358 DCHECK(!name->IsPrivate()); 7359 v8::GenericNamedPropertyDescriptorCallback descriptorCallback = 7360 v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>( 7361 interceptor->descriptor()); 7362 result = args.Call(descriptorCallback, name); 7363 } 7364 if (!result.is_null()) { 7365 // Request successfully intercepted, try to set the property 7366 // descriptor. 7367 Utils::ApiCheck( 7368 PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc), 7369 it->IsElement() ? "v8::IndexedPropertyDescriptorCallback" 7370 : "v8::NamedPropertyDescriptorCallback", 7371 "Invalid property descriptor."); 7372 7373 return Just(true); 7374 } 7375 } 7376 } 7377 return Just(false); 7378 } 7379 } // namespace 7380 7381 // ES6 9.1.5.1 7382 // Returns true on success, false if the property didn't exist, nothing if 7383 // an exception was thrown. 7384 // static 7385 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it, 7386 PropertyDescriptor* desc) { 7387 Isolate* isolate = it->isolate(); 7388 // "Virtual" dispatch. 7389 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) { 7390 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(), 7391 it->GetName(), desc); 7392 } 7393 7394 Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc); 7395 MAYBE_RETURN(intercepted, Nothing<bool>()); 7396 if (intercepted.FromJust()) { 7397 return Just(true); 7398 } 7399 7400 // Request was not intercepted, continue as normal. 7401 // 1. (Assert) 7402 // 2. If O does not have an own property with key P, return undefined. 7403 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it); 7404 MAYBE_RETURN(maybe, Nothing<bool>()); 7405 PropertyAttributes attrs = maybe.FromJust(); 7406 if (attrs == ABSENT) return Just(false); 7407 DCHECK(!isolate->has_pending_exception()); 7408 7409 // 3. Let D be a newly created Property Descriptor with no fields. 7410 DCHECK(desc->is_empty()); 7411 // 4. Let X be O's own property whose key is P. 7412 // 5. If X is a data property, then 7413 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR && 7414 it->GetAccessors()->IsAccessorPair(); 7415 if (!is_accessor_pair) { 7416 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute. 7417 Handle<Object> value; 7418 if (!Object::GetProperty(it).ToHandle(&value)) { 7419 DCHECK(isolate->has_pending_exception()); 7420 return Nothing<bool>(); 7421 } 7422 desc->set_value(value); 7423 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute 7424 desc->set_writable((attrs & READ_ONLY) == 0); 7425 } else { 7426 // 6. Else X is an accessor property, so 7427 Handle<AccessorPair> accessors = 7428 Handle<AccessorPair>::cast(it->GetAccessors()); 7429 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute. 7430 desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER)); 7431 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute. 7432 desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER)); 7433 } 7434 7435 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute. 7436 desc->set_enumerable((attrs & DONT_ENUM) == 0); 7437 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute. 7438 desc->set_configurable((attrs & DONT_DELETE) == 0); 7439 // 9. Return D. 7440 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) != 7441 PropertyDescriptor::IsDataDescriptor(desc)); 7442 return Just(true); 7443 } 7444 7445 7446 // ES6 9.5.5 7447 // static 7448 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate, 7449 Handle<JSProxy> proxy, 7450 Handle<Name> name, 7451 PropertyDescriptor* desc) { 7452 DCHECK(!name->IsPrivate()); 7453 STACK_CHECK(isolate, Nothing<bool>()); 7454 7455 Handle<String> trap_name = 7456 isolate->factory()->getOwnPropertyDescriptor_string(); 7457 // 1. (Assert) 7458 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 7459 Handle<Object> handler(proxy->handler(), isolate); 7460 // 3. If handler is null, throw a TypeError exception. 7461 // 4. Assert: Type(handler) is Object. 7462 if (proxy->IsRevoked()) { 7463 isolate->Throw(*isolate->factory()->NewTypeError( 7464 MessageTemplate::kProxyRevoked, trap_name)); 7465 return Nothing<bool>(); 7466 } 7467 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 7468 Handle<JSReceiver> target(proxy->target(), isolate); 7469 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor"). 7470 Handle<Object> trap; 7471 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7472 isolate, trap, 7473 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 7474 Nothing<bool>()); 7475 // 7. If trap is undefined, then 7476 if (trap->IsUndefined(isolate)) { 7477 // 7a. Return target.[[GetOwnProperty]](P). 7478 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc); 7479 } 7480 // 8. Let trapResultObj be ? Call(trap, handler, target, P). 7481 Handle<Object> trap_result_obj; 7482 Handle<Object> args[] = {target, name}; 7483 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7484 isolate, trap_result_obj, 7485 Execution::Call(isolate, trap, handler, arraysize(args), args), 7486 Nothing<bool>()); 7487 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a 7488 // TypeError exception. 7489 if (!trap_result_obj->IsJSReceiver() && 7490 !trap_result_obj->IsUndefined(isolate)) { 7491 isolate->Throw(*isolate->factory()->NewTypeError( 7492 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name)); 7493 return Nothing<bool>(); 7494 } 7495 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). 7496 PropertyDescriptor target_desc; 7497 Maybe<bool> found = 7498 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 7499 MAYBE_RETURN(found, Nothing<bool>()); 7500 // 11. If trapResultObj is undefined, then 7501 if (trap_result_obj->IsUndefined(isolate)) { 7502 // 11a. If targetDesc is undefined, return undefined. 7503 if (!found.FromJust()) return Just(false); 7504 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError 7505 // exception. 7506 if (!target_desc.configurable()) { 7507 isolate->Throw(*isolate->factory()->NewTypeError( 7508 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name)); 7509 return Nothing<bool>(); 7510 } 7511 // 11c. Let extensibleTarget be ? IsExtensible(target). 7512 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 7513 MAYBE_RETURN(extensible_target, Nothing<bool>()); 7514 // 11d. (Assert) 7515 // 11e. If extensibleTarget is false, throw a TypeError exception. 7516 if (!extensible_target.FromJust()) { 7517 isolate->Throw(*isolate->factory()->NewTypeError( 7518 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name)); 7519 return Nothing<bool>(); 7520 } 7521 // 11f. Return undefined. 7522 return Just(false); 7523 } 7524 // 12. Let extensibleTarget be ? IsExtensible(target). 7525 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 7526 MAYBE_RETURN(extensible_target, Nothing<bool>()); 7527 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj). 7528 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj, 7529 desc)) { 7530 DCHECK(isolate->has_pending_exception()); 7531 return Nothing<bool>(); 7532 } 7533 // 14. Call CompletePropertyDescriptor(resultDesc). 7534 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc); 7535 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget, 7536 // resultDesc, targetDesc). 7537 Maybe<bool> valid = 7538 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(), 7539 desc, &target_desc, name, DONT_THROW); 7540 MAYBE_RETURN(valid, Nothing<bool>()); 7541 // 16. If valid is false, throw a TypeError exception. 7542 if (!valid.FromJust()) { 7543 isolate->Throw(*isolate->factory()->NewTypeError( 7544 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name)); 7545 return Nothing<bool>(); 7546 } 7547 // 17. If resultDesc.[[Configurable]] is false, then 7548 if (!desc->configurable()) { 7549 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true: 7550 if (target_desc.is_empty() || target_desc.configurable()) { 7551 // 17a i. Throw a TypeError exception. 7552 isolate->Throw(*isolate->factory()->NewTypeError( 7553 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable, 7554 name)); 7555 return Nothing<bool>(); 7556 } 7557 } 7558 // 18. Return resultDesc. 7559 return Just(true); 7560 } 7561 7562 7563 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, 7564 ElementsKind kind, 7565 Object* object) { 7566 Isolate* isolate = elements->GetIsolate(); 7567 if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) { 7568 int length = IsJSArray() 7569 ? Smi::cast(JSArray::cast(this)->length())->value() 7570 : elements->length(); 7571 for (int i = 0; i < length; ++i) { 7572 Object* element = elements->get(i); 7573 if (!element->IsTheHole(isolate) && element == object) return true; 7574 } 7575 } else { 7576 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS); 7577 Object* key = 7578 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object); 7579 if (!key->IsUndefined(isolate)) return true; 7580 } 7581 return false; 7582 } 7583 7584 7585 // Check whether this object references another object. 7586 bool JSObject::ReferencesObject(Object* obj) { 7587 Map* map_of_this = map(); 7588 Heap* heap = GetHeap(); 7589 DisallowHeapAllocation no_allocation; 7590 7591 // Is the object the constructor for this object? 7592 if (map_of_this->GetConstructor() == obj) { 7593 return true; 7594 } 7595 7596 // Is the object the prototype for this object? 7597 if (map_of_this->prototype() == obj) { 7598 return true; 7599 } 7600 7601 // Check if the object is among the named properties. 7602 Object* key = SlowReverseLookup(obj); 7603 if (!key->IsUndefined(heap->isolate())) { 7604 return true; 7605 } 7606 7607 // Check if the object is among the indexed properties. 7608 ElementsKind kind = GetElementsKind(); 7609 switch (kind) { 7610 // Raw pixels and external arrays do not reference other 7611 // objects. 7612 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 7613 case TYPE##_ELEMENTS: \ 7614 break; 7615 7616 TYPED_ARRAYS(TYPED_ARRAY_CASE) 7617 #undef TYPED_ARRAY_CASE 7618 7619 case FAST_DOUBLE_ELEMENTS: 7620 case FAST_HOLEY_DOUBLE_ELEMENTS: 7621 break; 7622 case FAST_SMI_ELEMENTS: 7623 case FAST_HOLEY_SMI_ELEMENTS: 7624 break; 7625 case FAST_ELEMENTS: 7626 case FAST_HOLEY_ELEMENTS: 7627 case DICTIONARY_ELEMENTS: 7628 case FAST_STRING_WRAPPER_ELEMENTS: 7629 case SLOW_STRING_WRAPPER_ELEMENTS: { 7630 FixedArray* elements = FixedArray::cast(this->elements()); 7631 if (ReferencesObjectFromElements(elements, kind, obj)) return true; 7632 break; 7633 } 7634 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 7635 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 7636 FixedArray* parameter_map = FixedArray::cast(elements()); 7637 // Check the mapped parameters. 7638 int length = parameter_map->length(); 7639 for (int i = 2; i < length; ++i) { 7640 Object* value = parameter_map->get(i); 7641 if (!value->IsTheHole(heap->isolate()) && value == obj) return true; 7642 } 7643 // Check the arguments. 7644 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); 7645 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : 7646 FAST_HOLEY_ELEMENTS; 7647 if (ReferencesObjectFromElements(arguments, kind, obj)) return true; 7648 break; 7649 } 7650 case NO_ELEMENTS: 7651 break; 7652 } 7653 7654 // For functions check the context. 7655 if (IsJSFunction()) { 7656 // Get the constructor function for arguments array. 7657 Map* arguments_map = 7658 heap->isolate()->context()->native_context()->sloppy_arguments_map(); 7659 JSFunction* arguments_function = 7660 JSFunction::cast(arguments_map->GetConstructor()); 7661 7662 // Get the context and don't check if it is the native context. 7663 JSFunction* f = JSFunction::cast(this); 7664 Context* context = f->context(); 7665 if (context->IsNativeContext()) { 7666 return false; 7667 } 7668 7669 // Check the non-special context slots. 7670 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) { 7671 // Only check JS objects. 7672 if (context->get(i)->IsJSObject()) { 7673 JSObject* ctxobj = JSObject::cast(context->get(i)); 7674 // If it is an arguments array check the content. 7675 if (ctxobj->map()->GetConstructor() == arguments_function) { 7676 if (ctxobj->ReferencesObject(obj)) { 7677 return true; 7678 } 7679 } else if (ctxobj == obj) { 7680 return true; 7681 } 7682 } 7683 } 7684 7685 // Check the context extension (if any) if it can have references. 7686 if (context->has_extension() && !context->IsCatchContext()) { 7687 // With harmony scoping, a JSFunction may have a script context. 7688 // TODO(mvstanton): walk into the ScopeInfo. 7689 if (context->IsScriptContext()) { 7690 return false; 7691 } 7692 7693 return context->extension_object()->ReferencesObject(obj); 7694 } 7695 } 7696 7697 // No references to object. 7698 return false; 7699 } 7700 7701 7702 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver, 7703 IntegrityLevel level, 7704 ShouldThrow should_throw) { 7705 DCHECK(level == SEALED || level == FROZEN); 7706 7707 if (receiver->IsJSObject()) { 7708 Handle<JSObject> object = Handle<JSObject>::cast(receiver); 7709 if (!object->HasSloppyArgumentsElements()) { // Fast path. 7710 if (level == SEALED) { 7711 return JSObject::PreventExtensionsWithTransition<SEALED>(object, 7712 should_throw); 7713 } else { 7714 return JSObject::PreventExtensionsWithTransition<FROZEN>(object, 7715 should_throw); 7716 } 7717 } 7718 } 7719 7720 Isolate* isolate = receiver->GetIsolate(); 7721 7722 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw), 7723 Nothing<bool>()); 7724 7725 Handle<FixedArray> keys; 7726 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7727 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>()); 7728 7729 PropertyDescriptor no_conf; 7730 no_conf.set_configurable(false); 7731 7732 PropertyDescriptor no_conf_no_write; 7733 no_conf_no_write.set_configurable(false); 7734 no_conf_no_write.set_writable(false); 7735 7736 if (level == SEALED) { 7737 for (int i = 0; i < keys->length(); ++i) { 7738 Handle<Object> key(keys->get(i), isolate); 7739 MAYBE_RETURN( 7740 DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR), 7741 Nothing<bool>()); 7742 } 7743 return Just(true); 7744 } 7745 7746 for (int i = 0; i < keys->length(); ++i) { 7747 Handle<Object> key(keys->get(i), isolate); 7748 PropertyDescriptor current_desc; 7749 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( 7750 isolate, receiver, key, ¤t_desc); 7751 MAYBE_RETURN(owned, Nothing<bool>()); 7752 if (owned.FromJust()) { 7753 PropertyDescriptor desc = 7754 PropertyDescriptor::IsAccessorDescriptor(¤t_desc) 7755 ? no_conf 7756 : no_conf_no_write; 7757 MAYBE_RETURN( 7758 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR), 7759 Nothing<bool>()); 7760 } 7761 } 7762 return Just(true); 7763 } 7764 7765 7766 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object, 7767 IntegrityLevel level) { 7768 DCHECK(level == SEALED || level == FROZEN); 7769 Isolate* isolate = object->GetIsolate(); 7770 7771 Maybe<bool> extensible = JSReceiver::IsExtensible(object); 7772 MAYBE_RETURN(extensible, Nothing<bool>()); 7773 if (extensible.FromJust()) return Just(false); 7774 7775 Handle<FixedArray> keys; 7776 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7777 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>()); 7778 7779 for (int i = 0; i < keys->length(); ++i) { 7780 Handle<Object> key(keys->get(i), isolate); 7781 PropertyDescriptor current_desc; 7782 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( 7783 isolate, object, key, ¤t_desc); 7784 MAYBE_RETURN(owned, Nothing<bool>()); 7785 if (owned.FromJust()) { 7786 if (current_desc.configurable()) return Just(false); 7787 if (level == FROZEN && 7788 PropertyDescriptor::IsDataDescriptor(¤t_desc) && 7789 current_desc.writable()) { 7790 return Just(false); 7791 } 7792 } 7793 } 7794 return Just(true); 7795 } 7796 7797 7798 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, 7799 ShouldThrow should_throw) { 7800 if (object->IsJSProxy()) { 7801 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object), 7802 should_throw); 7803 } 7804 DCHECK(object->IsJSObject()); 7805 return JSObject::PreventExtensions(Handle<JSObject>::cast(object), 7806 should_throw); 7807 } 7808 7809 7810 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy, 7811 ShouldThrow should_throw) { 7812 Isolate* isolate = proxy->GetIsolate(); 7813 STACK_CHECK(isolate, Nothing<bool>()); 7814 Factory* factory = isolate->factory(); 7815 Handle<String> trap_name = factory->preventExtensions_string(); 7816 7817 if (proxy->IsRevoked()) { 7818 isolate->Throw( 7819 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 7820 return Nothing<bool>(); 7821 } 7822 Handle<JSReceiver> target(proxy->target(), isolate); 7823 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 7824 7825 Handle<Object> trap; 7826 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7827 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 7828 if (trap->IsUndefined(isolate)) { 7829 return JSReceiver::PreventExtensions(target, should_throw); 7830 } 7831 7832 Handle<Object> trap_result; 7833 Handle<Object> args[] = {target}; 7834 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7835 isolate, trap_result, 7836 Execution::Call(isolate, trap, handler, arraysize(args), args), 7837 Nothing<bool>()); 7838 if (!trap_result->BooleanValue()) { 7839 RETURN_FAILURE( 7840 isolate, should_throw, 7841 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 7842 } 7843 7844 // Enforce the invariant. 7845 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 7846 MAYBE_RETURN(target_result, Nothing<bool>()); 7847 if (target_result.FromJust()) { 7848 isolate->Throw(*factory->NewTypeError( 7849 MessageTemplate::kProxyPreventExtensionsExtensible)); 7850 return Nothing<bool>(); 7851 } 7852 return Just(true); 7853 } 7854 7855 7856 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, 7857 ShouldThrow should_throw) { 7858 Isolate* isolate = object->GetIsolate(); 7859 7860 if (!object->HasSloppyArgumentsElements()) { 7861 return PreventExtensionsWithTransition<NONE>(object, should_throw); 7862 } 7863 7864 if (object->IsAccessCheckNeeded() && 7865 !isolate->MayAccess(handle(isolate->context()), object)) { 7866 isolate->ReportFailedAccessCheck(object); 7867 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 7868 RETURN_FAILURE(isolate, should_throw, 7869 NewTypeError(MessageTemplate::kNoAccess)); 7870 } 7871 7872 if (!object->map()->is_extensible()) return Just(true); 7873 7874 if (object->IsJSGlobalProxy()) { 7875 PrototypeIterator iter(isolate, object); 7876 if (iter.IsAtEnd()) return Just(true); 7877 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); 7878 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter), 7879 should_throw); 7880 } 7881 7882 if (!object->HasFixedTypedArrayElements()) { 7883 // If there are fast elements we normalize. 7884 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); 7885 DCHECK(object->HasDictionaryElements() || 7886 object->HasSlowArgumentsElements()); 7887 7888 // Make sure that we never go back to fast case. 7889 object->RequireSlowElements(*dictionary); 7890 } 7891 7892 // Do a map transition, other objects with this map may still 7893 // be extensible. 7894 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. 7895 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions"); 7896 7897 new_map->set_is_extensible(false); 7898 JSObject::MigrateToMap(object, new_map); 7899 DCHECK(!object->map()->is_extensible()); 7900 7901 return Just(true); 7902 } 7903 7904 7905 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) { 7906 if (object->IsJSProxy()) { 7907 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object)); 7908 } 7909 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object))); 7910 } 7911 7912 7913 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) { 7914 Isolate* isolate = proxy->GetIsolate(); 7915 STACK_CHECK(isolate, Nothing<bool>()); 7916 Factory* factory = isolate->factory(); 7917 Handle<String> trap_name = factory->isExtensible_string(); 7918 7919 if (proxy->IsRevoked()) { 7920 isolate->Throw( 7921 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 7922 return Nothing<bool>(); 7923 } 7924 Handle<JSReceiver> target(proxy->target(), isolate); 7925 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 7926 7927 Handle<Object> trap; 7928 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7929 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 7930 if (trap->IsUndefined(isolate)) { 7931 return JSReceiver::IsExtensible(target); 7932 } 7933 7934 Handle<Object> trap_result; 7935 Handle<Object> args[] = {target}; 7936 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7937 isolate, trap_result, 7938 Execution::Call(isolate, trap, handler, arraysize(args), args), 7939 Nothing<bool>()); 7940 7941 // Enforce the invariant. 7942 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 7943 MAYBE_RETURN(target_result, Nothing<bool>()); 7944 if (target_result.FromJust() != trap_result->BooleanValue()) { 7945 isolate->Throw( 7946 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent, 7947 factory->ToBoolean(target_result.FromJust()))); 7948 return Nothing<bool>(); 7949 } 7950 return target_result; 7951 } 7952 7953 7954 bool JSObject::IsExtensible(Handle<JSObject> object) { 7955 Isolate* isolate = object->GetIsolate(); 7956 if (object->IsAccessCheckNeeded() && 7957 !isolate->MayAccess(handle(isolate->context()), object)) { 7958 return true; 7959 } 7960 if (object->IsJSGlobalProxy()) { 7961 PrototypeIterator iter(isolate, *object); 7962 if (iter.IsAtEnd()) return false; 7963 DCHECK(iter.GetCurrent()->IsJSGlobalObject()); 7964 return iter.GetCurrent<JSObject>()->map()->is_extensible(); 7965 } 7966 return object->map()->is_extensible(); 7967 } 7968 7969 namespace { 7970 7971 template <typename Dictionary> 7972 void DictionaryDetailsAtPut(Isolate* isolate, Handle<Dictionary> dictionary, 7973 int entry, PropertyDetails details) { 7974 dictionary->DetailsAtPut(entry, details); 7975 } 7976 7977 template <> 7978 void DictionaryDetailsAtPut<GlobalDictionary>( 7979 Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry, 7980 PropertyDetails details) { 7981 Object* value = dictionary->ValueAt(entry); 7982 DCHECK(value->IsPropertyCell()); 7983 value = PropertyCell::cast(value)->value(); 7984 if (value->IsTheHole(isolate)) return; 7985 PropertyCell::PrepareForValue(dictionary, entry, handle(value, isolate), 7986 details); 7987 } 7988 7989 template <typename Dictionary> 7990 void ApplyAttributesToDictionary(Isolate* isolate, 7991 Handle<Dictionary> dictionary, 7992 const PropertyAttributes attributes) { 7993 int capacity = dictionary->Capacity(); 7994 for (int i = 0; i < capacity; i++) { 7995 Object* k = dictionary->KeyAt(i); 7996 if (dictionary->IsKey(isolate, k) && 7997 !(k->IsSymbol() && Symbol::cast(k)->is_private())) { 7998 PropertyDetails details = dictionary->DetailsAt(i); 7999 int attrs = attributes; 8000 // READ_ONLY is an invalid attribute for JS setters/getters. 8001 if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) { 8002 Object* v = dictionary->ValueAt(i); 8003 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value(); 8004 if (v->IsAccessorPair()) attrs &= ~READ_ONLY; 8005 } 8006 details = details.CopyAddAttributes( 8007 static_cast<PropertyAttributes>(attrs)); 8008 DictionaryDetailsAtPut<Dictionary>(isolate, dictionary, i, details); 8009 } 8010 } 8011 } 8012 8013 } // namespace 8014 8015 template <PropertyAttributes attrs> 8016 Maybe<bool> JSObject::PreventExtensionsWithTransition( 8017 Handle<JSObject> object, ShouldThrow should_throw) { 8018 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN); 8019 8020 // Sealing/freezing sloppy arguments should be handled elsewhere. 8021 DCHECK(!object->HasSloppyArgumentsElements()); 8022 8023 Isolate* isolate = object->GetIsolate(); 8024 if (object->IsAccessCheckNeeded() && 8025 !isolate->MayAccess(handle(isolate->context()), object)) { 8026 isolate->ReportFailedAccessCheck(object); 8027 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 8028 RETURN_FAILURE(isolate, should_throw, 8029 NewTypeError(MessageTemplate::kNoAccess)); 8030 } 8031 8032 if (attrs == NONE && !object->map()->is_extensible()) return Just(true); 8033 8034 if (object->IsJSGlobalProxy()) { 8035 PrototypeIterator iter(isolate, object); 8036 if (iter.IsAtEnd()) return Just(true); 8037 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); 8038 return PreventExtensionsWithTransition<attrs>( 8039 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw); 8040 } 8041 8042 Handle<SeededNumberDictionary> new_element_dictionary; 8043 if (!object->HasFixedTypedArrayElements() && 8044 !object->HasDictionaryElements() && 8045 !object->HasSlowStringWrapperElements()) { 8046 int length = 8047 object->IsJSArray() 8048 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() 8049 : object->elements()->length(); 8050 new_element_dictionary = 8051 length == 0 ? isolate->factory()->empty_slow_element_dictionary() 8052 : object->GetElementsAccessor()->Normalize(object); 8053 } 8054 8055 Handle<Symbol> transition_marker; 8056 if (attrs == NONE) { 8057 transition_marker = isolate->factory()->nonextensible_symbol(); 8058 } else if (attrs == SEALED) { 8059 transition_marker = isolate->factory()->sealed_symbol(); 8060 } else { 8061 DCHECK(attrs == FROZEN); 8062 transition_marker = isolate->factory()->frozen_symbol(); 8063 } 8064 8065 Handle<Map> old_map(object->map(), isolate); 8066 Map* transition = 8067 TransitionArray::SearchSpecial(*old_map, *transition_marker); 8068 if (transition != NULL) { 8069 Handle<Map> transition_map(transition, isolate); 8070 DCHECK(transition_map->has_dictionary_elements() || 8071 transition_map->has_fixed_typed_array_elements() || 8072 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS); 8073 DCHECK(!transition_map->is_extensible()); 8074 JSObject::MigrateToMap(object, transition_map); 8075 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) { 8076 // Create a new descriptor array with the appropriate property attributes 8077 Handle<Map> new_map = Map::CopyForPreventExtensions( 8078 old_map, attrs, transition_marker, "CopyForPreventExtensions"); 8079 JSObject::MigrateToMap(object, new_map); 8080 } else { 8081 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map()); 8082 // Slow path: need to normalize properties for safety 8083 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, 8084 "SlowPreventExtensions"); 8085 8086 // Create a new map, since other objects with this map may be extensible. 8087 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. 8088 Handle<Map> new_map = 8089 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions"); 8090 new_map->set_is_extensible(false); 8091 if (!new_element_dictionary.is_null()) { 8092 ElementsKind new_kind = 8093 IsStringWrapperElementsKind(old_map->elements_kind()) 8094 ? SLOW_STRING_WRAPPER_ELEMENTS 8095 : DICTIONARY_ELEMENTS; 8096 new_map->set_elements_kind(new_kind); 8097 } 8098 JSObject::MigrateToMap(object, new_map); 8099 8100 if (attrs != NONE) { 8101 if (object->IsJSGlobalObject()) { 8102 Handle<GlobalDictionary> dictionary(object->global_dictionary(), 8103 isolate); 8104 ApplyAttributesToDictionary(isolate, dictionary, attrs); 8105 } else { 8106 Handle<NameDictionary> dictionary(object->property_dictionary(), 8107 isolate); 8108 ApplyAttributesToDictionary(isolate, dictionary, attrs); 8109 } 8110 } 8111 } 8112 8113 // Both seal and preventExtensions always go through without modifications to 8114 // typed array elements. Freeze works only if there are no actual elements. 8115 if (object->HasFixedTypedArrayElements()) { 8116 if (attrs == FROZEN && 8117 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) { 8118 isolate->Throw(*isolate->factory()->NewTypeError( 8119 MessageTemplate::kCannotFreezeArrayBufferView)); 8120 return Nothing<bool>(); 8121 } 8122 return Just(true); 8123 } 8124 8125 DCHECK(object->map()->has_dictionary_elements() || 8126 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS); 8127 if (!new_element_dictionary.is_null()) { 8128 object->set_elements(*new_element_dictionary); 8129 } 8130 8131 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) { 8132 Handle<SeededNumberDictionary> dictionary(object->element_dictionary(), 8133 isolate); 8134 // Make sure we never go back to the fast case 8135 object->RequireSlowElements(*dictionary); 8136 if (attrs != NONE) { 8137 ApplyAttributesToDictionary(isolate, dictionary, attrs); 8138 } 8139 } 8140 8141 return Just(true); 8142 } 8143 8144 8145 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object, 8146 Representation representation, 8147 FieldIndex index) { 8148 Isolate* isolate = object->GetIsolate(); 8149 if (object->IsUnboxedDoubleField(index)) { 8150 double value = object->RawFastDoublePropertyAt(index); 8151 return isolate->factory()->NewHeapNumber(value); 8152 } 8153 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate); 8154 return Object::WrapForRead(isolate, raw_value, representation); 8155 } 8156 8157 template <class ContextObject> 8158 class JSObjectWalkVisitor { 8159 public: 8160 JSObjectWalkVisitor(ContextObject* site_context, bool copying, 8161 JSObject::DeepCopyHints hints) 8162 : site_context_(site_context), 8163 copying_(copying), 8164 hints_(hints) {} 8165 8166 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object); 8167 8168 protected: 8169 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty( 8170 Handle<JSObject> object, 8171 Handle<JSObject> value) { 8172 Handle<AllocationSite> current_site = site_context()->EnterNewScope(); 8173 MaybeHandle<JSObject> copy_of_value = StructureWalk(value); 8174 site_context()->ExitScope(current_site, value); 8175 return copy_of_value; 8176 } 8177 8178 inline ContextObject* site_context() { return site_context_; } 8179 inline Isolate* isolate() { return site_context()->isolate(); } 8180 8181 inline bool copying() const { return copying_; } 8182 8183 private: 8184 ContextObject* site_context_; 8185 const bool copying_; 8186 const JSObject::DeepCopyHints hints_; 8187 }; 8188 8189 template <class ContextObject> 8190 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk( 8191 Handle<JSObject> object) { 8192 Isolate* isolate = this->isolate(); 8193 bool copying = this->copying(); 8194 bool shallow = hints_ == JSObject::kObjectIsShallow; 8195 8196 if (!shallow) { 8197 StackLimitCheck check(isolate); 8198 8199 if (check.HasOverflowed()) { 8200 isolate->StackOverflow(); 8201 return MaybeHandle<JSObject>(); 8202 } 8203 } 8204 8205 if (object->map()->is_deprecated()) { 8206 JSObject::MigrateInstance(object); 8207 } 8208 8209 Handle<JSObject> copy; 8210 if (copying) { 8211 // JSFunction objects are not allowed to be in normal boilerplates at all. 8212 DCHECK(!object->IsJSFunction()); 8213 Handle<AllocationSite> site_to_pass; 8214 if (site_context()->ShouldCreateMemento(object)) { 8215 site_to_pass = site_context()->current(); 8216 } 8217 copy = isolate->factory()->CopyJSObjectWithAllocationSite( 8218 object, site_to_pass); 8219 } else { 8220 copy = object; 8221 } 8222 8223 DCHECK(copying || copy.is_identical_to(object)); 8224 8225 ElementsKind kind = copy->GetElementsKind(); 8226 if (copying && IsFastSmiOrObjectElementsKind(kind) && 8227 FixedArray::cast(copy->elements())->map() == 8228 isolate->heap()->fixed_cow_array_map()) { 8229 isolate->counters()->cow_arrays_created_runtime()->Increment(); 8230 } 8231 8232 if (!shallow) { 8233 HandleScope scope(isolate); 8234 8235 // Deep copy own properties. 8236 if (copy->HasFastProperties()) { 8237 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors()); 8238 int limit = copy->map()->NumberOfOwnDescriptors(); 8239 for (int i = 0; i < limit; i++) { 8240 PropertyDetails details = descriptors->GetDetails(i); 8241 if (details.type() != DATA) continue; 8242 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i); 8243 if (object->IsUnboxedDoubleField(index)) { 8244 if (copying) { 8245 double value = object->RawFastDoublePropertyAt(index); 8246 copy->RawFastDoublePropertyAtPut(index, value); 8247 } 8248 } else { 8249 Handle<Object> value(object->RawFastPropertyAt(index), isolate); 8250 if (value->IsJSObject()) { 8251 ASSIGN_RETURN_ON_EXCEPTION( 8252 isolate, value, 8253 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 8254 JSObject); 8255 if (copying) { 8256 copy->FastPropertyAtPut(index, *value); 8257 } 8258 } else { 8259 if (copying) { 8260 Representation representation = details.representation(); 8261 value = Object::NewStorageFor(isolate, value, representation); 8262 copy->FastPropertyAtPut(index, *value); 8263 } 8264 } 8265 } 8266 } 8267 } else { 8268 // Only deep copy fields from the object literal expression. 8269 // In particular, don't try to copy the length attribute of 8270 // an array. 8271 PropertyFilter filter = static_cast<PropertyFilter>( 8272 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE); 8273 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter); 8274 accumulator.CollectOwnPropertyNames(copy, copy); 8275 Handle<FixedArray> names = accumulator.GetKeys(); 8276 for (int i = 0; i < names->length(); i++) { 8277 DCHECK(names->get(i)->IsName()); 8278 Handle<Name> name(Name::cast(names->get(i))); 8279 Handle<Object> value = 8280 JSObject::GetProperty(copy, name).ToHandleChecked(); 8281 if (value->IsJSObject()) { 8282 Handle<JSObject> result; 8283 ASSIGN_RETURN_ON_EXCEPTION( 8284 isolate, result, 8285 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 8286 JSObject); 8287 if (copying) { 8288 // Creating object copy for literals. No strict mode needed. 8289 JSObject::SetProperty(copy, name, result, SLOPPY).Assert(); 8290 } 8291 } 8292 } 8293 } 8294 8295 // Deep copy own elements. 8296 switch (kind) { 8297 case FAST_ELEMENTS: 8298 case FAST_HOLEY_ELEMENTS: { 8299 Handle<FixedArray> elements(FixedArray::cast(copy->elements())); 8300 if (elements->map() == isolate->heap()->fixed_cow_array_map()) { 8301 #ifdef DEBUG 8302 for (int i = 0; i < elements->length(); i++) { 8303 DCHECK(!elements->get(i)->IsJSObject()); 8304 } 8305 #endif 8306 } else { 8307 for (int i = 0; i < elements->length(); i++) { 8308 Handle<Object> value(elements->get(i), isolate); 8309 if (value->IsJSObject()) { 8310 Handle<JSObject> result; 8311 ASSIGN_RETURN_ON_EXCEPTION( 8312 isolate, result, 8313 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 8314 JSObject); 8315 if (copying) { 8316 elements->set(i, *result); 8317 } 8318 } 8319 } 8320 } 8321 break; 8322 } 8323 case DICTIONARY_ELEMENTS: { 8324 Handle<SeededNumberDictionary> element_dictionary( 8325 copy->element_dictionary()); 8326 int capacity = element_dictionary->Capacity(); 8327 for (int i = 0; i < capacity; i++) { 8328 Object* k = element_dictionary->KeyAt(i); 8329 if (element_dictionary->IsKey(isolate, k)) { 8330 Handle<Object> value(element_dictionary->ValueAt(i), isolate); 8331 if (value->IsJSObject()) { 8332 Handle<JSObject> result; 8333 ASSIGN_RETURN_ON_EXCEPTION( 8334 isolate, result, 8335 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 8336 JSObject); 8337 if (copying) { 8338 element_dictionary->ValueAtPut(i, *result); 8339 } 8340 } 8341 } 8342 } 8343 break; 8344 } 8345 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 8346 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 8347 UNIMPLEMENTED(); 8348 break; 8349 case FAST_STRING_WRAPPER_ELEMENTS: 8350 case SLOW_STRING_WRAPPER_ELEMENTS: 8351 UNREACHABLE(); 8352 break; 8353 8354 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 8355 case TYPE##_ELEMENTS: \ 8356 8357 TYPED_ARRAYS(TYPED_ARRAY_CASE) 8358 #undef TYPED_ARRAY_CASE 8359 // Typed elements cannot be created using an object literal. 8360 UNREACHABLE(); 8361 break; 8362 8363 case FAST_SMI_ELEMENTS: 8364 case FAST_HOLEY_SMI_ELEMENTS: 8365 case FAST_DOUBLE_ELEMENTS: 8366 case FAST_HOLEY_DOUBLE_ELEMENTS: 8367 case NO_ELEMENTS: 8368 // No contained objects, nothing to do. 8369 break; 8370 } 8371 } 8372 8373 return copy; 8374 } 8375 8376 8377 MaybeHandle<JSObject> JSObject::DeepWalk( 8378 Handle<JSObject> object, 8379 AllocationSiteCreationContext* site_context) { 8380 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false, 8381 kNoHints); 8382 MaybeHandle<JSObject> result = v.StructureWalk(object); 8383 Handle<JSObject> for_assert; 8384 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object)); 8385 return result; 8386 } 8387 8388 8389 MaybeHandle<JSObject> JSObject::DeepCopy( 8390 Handle<JSObject> object, 8391 AllocationSiteUsageContext* site_context, 8392 DeepCopyHints hints) { 8393 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints); 8394 MaybeHandle<JSObject> copy = v.StructureWalk(object); 8395 Handle<JSObject> for_assert; 8396 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object)); 8397 return copy; 8398 } 8399 8400 // static 8401 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver, 8402 ToPrimitiveHint hint) { 8403 Isolate* const isolate = receiver->GetIsolate(); 8404 Handle<Object> exotic_to_prim; 8405 ASSIGN_RETURN_ON_EXCEPTION( 8406 isolate, exotic_to_prim, 8407 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object); 8408 if (!exotic_to_prim->IsUndefined(isolate)) { 8409 Handle<Object> hint_string = 8410 isolate->factory()->ToPrimitiveHintString(hint); 8411 Handle<Object> result; 8412 ASSIGN_RETURN_ON_EXCEPTION( 8413 isolate, result, 8414 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string), 8415 Object); 8416 if (result->IsPrimitive()) return result; 8417 THROW_NEW_ERROR(isolate, 8418 NewTypeError(MessageTemplate::kCannotConvertToPrimitive), 8419 Object); 8420 } 8421 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString) 8422 ? OrdinaryToPrimitiveHint::kString 8423 : OrdinaryToPrimitiveHint::kNumber); 8424 } 8425 8426 8427 // static 8428 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive( 8429 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) { 8430 Isolate* const isolate = receiver->GetIsolate(); 8431 Handle<String> method_names[2]; 8432 switch (hint) { 8433 case OrdinaryToPrimitiveHint::kNumber: 8434 method_names[0] = isolate->factory()->valueOf_string(); 8435 method_names[1] = isolate->factory()->toString_string(); 8436 break; 8437 case OrdinaryToPrimitiveHint::kString: 8438 method_names[0] = isolate->factory()->toString_string(); 8439 method_names[1] = isolate->factory()->valueOf_string(); 8440 break; 8441 } 8442 for (Handle<String> name : method_names) { 8443 Handle<Object> method; 8444 ASSIGN_RETURN_ON_EXCEPTION(isolate, method, 8445 JSReceiver::GetProperty(receiver, name), Object); 8446 if (method->IsCallable()) { 8447 Handle<Object> result; 8448 ASSIGN_RETURN_ON_EXCEPTION( 8449 isolate, result, Execution::Call(isolate, method, receiver, 0, NULL), 8450 Object); 8451 if (result->IsPrimitive()) return result; 8452 } 8453 } 8454 THROW_NEW_ERROR(isolate, 8455 NewTypeError(MessageTemplate::kCannotConvertToPrimitive), 8456 Object); 8457 } 8458 8459 8460 // TODO(cbruni/jkummerow): Consider moving this into elements.cc. 8461 bool JSObject::HasEnumerableElements() { 8462 // TODO(cbruni): cleanup 8463 JSObject* object = this; 8464 switch (object->GetElementsKind()) { 8465 case FAST_SMI_ELEMENTS: 8466 case FAST_ELEMENTS: 8467 case FAST_DOUBLE_ELEMENTS: { 8468 int length = object->IsJSArray() 8469 ? Smi::cast(JSArray::cast(object)->length())->value() 8470 : object->elements()->length(); 8471 return length > 0; 8472 } 8473 case FAST_HOLEY_SMI_ELEMENTS: 8474 case FAST_HOLEY_ELEMENTS: { 8475 FixedArray* elements = FixedArray::cast(object->elements()); 8476 int length = object->IsJSArray() 8477 ? Smi::cast(JSArray::cast(object)->length())->value() 8478 : elements->length(); 8479 Isolate* isolate = GetIsolate(); 8480 for (int i = 0; i < length; i++) { 8481 if (!elements->is_the_hole(isolate, i)) return true; 8482 } 8483 return false; 8484 } 8485 case FAST_HOLEY_DOUBLE_ELEMENTS: { 8486 int length = object->IsJSArray() 8487 ? Smi::cast(JSArray::cast(object)->length())->value() 8488 : object->elements()->length(); 8489 // Zero-length arrays would use the empty FixedArray... 8490 if (length == 0) return false; 8491 // ...so only cast to FixedDoubleArray otherwise. 8492 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements()); 8493 for (int i = 0; i < length; i++) { 8494 if (!elements->is_the_hole(i)) return true; 8495 } 8496 return false; 8497 } 8498 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 8499 case TYPE##_ELEMENTS: 8500 8501 TYPED_ARRAYS(TYPED_ARRAY_CASE) 8502 #undef TYPED_ARRAY_CASE 8503 { 8504 int length = object->elements()->length(); 8505 return length > 0; 8506 } 8507 case DICTIONARY_ELEMENTS: { 8508 SeededNumberDictionary* elements = 8509 SeededNumberDictionary::cast(object->elements()); 8510 return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0; 8511 } 8512 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 8513 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 8514 // We're approximating non-empty arguments objects here. 8515 return true; 8516 case FAST_STRING_WRAPPER_ELEMENTS: 8517 case SLOW_STRING_WRAPPER_ELEMENTS: 8518 if (String::cast(JSValue::cast(object)->value())->length() > 0) { 8519 return true; 8520 } 8521 return object->elements()->length() > 0; 8522 case NO_ELEMENTS: 8523 return false; 8524 } 8525 UNREACHABLE(); 8526 return true; 8527 } 8528 8529 8530 int Map::NumberOfDescribedProperties(DescriptorFlag which, 8531 PropertyFilter filter) { 8532 int result = 0; 8533 DescriptorArray* descs = instance_descriptors(); 8534 int limit = which == ALL_DESCRIPTORS 8535 ? descs->number_of_descriptors() 8536 : NumberOfOwnDescriptors(); 8537 for (int i = 0; i < limit; i++) { 8538 if ((descs->GetDetails(i).attributes() & filter) == 0 && 8539 !descs->GetKey(i)->FilterKey(filter)) { 8540 result++; 8541 } 8542 } 8543 return result; 8544 } 8545 8546 8547 int Map::NextFreePropertyIndex() { 8548 int free_index = 0; 8549 int number_of_own_descriptors = NumberOfOwnDescriptors(); 8550 DescriptorArray* descs = instance_descriptors(); 8551 for (int i = 0; i < number_of_own_descriptors; i++) { 8552 PropertyDetails details = descs->GetDetails(i); 8553 if (details.location() == kField) { 8554 int candidate = details.field_index() + details.field_width_in_words(); 8555 if (candidate > free_index) free_index = candidate; 8556 } 8557 } 8558 return free_index; 8559 } 8560 8561 8562 bool Map::OnlyHasSimpleProperties() { 8563 // Wrapped string elements aren't explicitly stored in the elements backing 8564 // store, but are loaded indirectly from the underlying string. 8565 return !IsStringWrapperElementsKind(elements_kind()) && 8566 instance_type() > LAST_SPECIAL_RECEIVER_TYPE && 8567 !has_hidden_prototype() && !is_dictionary_map(); 8568 } 8569 8570 MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries( 8571 Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries, 8572 Handle<FixedArray>* result) { 8573 Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate); 8574 8575 if (!map->IsJSObjectMap()) return Just(false); 8576 if (!map->OnlyHasSimpleProperties()) return Just(false); 8577 8578 Handle<JSObject> object(JSObject::cast(*receiver)); 8579 8580 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 8581 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 8582 int number_of_own_elements = 8583 object->GetElementsAccessor()->GetCapacity(*object, object->elements()); 8584 Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray( 8585 number_of_own_descriptors + number_of_own_elements); 8586 int count = 0; 8587 8588 if (object->elements() != isolate->heap()->empty_fixed_array()) { 8589 MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries( 8590 isolate, object, values_or_entries, get_entries, &count, 8591 ENUMERABLE_STRINGS), 8592 Nothing<bool>()); 8593 } 8594 8595 bool stable = object->map() == *map; 8596 8597 for (int index = 0; index < number_of_own_descriptors; index++) { 8598 Handle<Name> next_key(descriptors->GetKey(index), isolate); 8599 if (!next_key->IsString()) continue; 8600 Handle<Object> prop_value; 8601 8602 // Directly decode from the descriptor array if |from| did not change shape. 8603 if (stable) { 8604 PropertyDetails details = descriptors->GetDetails(index); 8605 if (!details.IsEnumerable()) continue; 8606 if (details.kind() == kData) { 8607 if (details.location() == kDescriptor) { 8608 prop_value = handle(descriptors->GetValue(index), isolate); 8609 } else { 8610 Representation representation = details.representation(); 8611 FieldIndex field_index = FieldIndex::ForDescriptor(*map, index); 8612 prop_value = 8613 JSObject::FastPropertyAt(object, representation, field_index); 8614 } 8615 } else { 8616 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8617 isolate, prop_value, JSReceiver::GetProperty(object, next_key), 8618 Nothing<bool>()); 8619 stable = object->map() == *map; 8620 } 8621 } else { 8622 // If the map did change, do a slower lookup. We are still guaranteed that 8623 // the object has a simple shape, and that the key is a name. 8624 LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR); 8625 if (!it.IsFound()) continue; 8626 DCHECK(it.state() == LookupIterator::DATA || 8627 it.state() == LookupIterator::ACCESSOR); 8628 if (!it.IsEnumerable()) continue; 8629 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8630 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); 8631 } 8632 8633 if (get_entries) { 8634 prop_value = MakeEntryPair(isolate, next_key, prop_value); 8635 } 8636 8637 values_or_entries->set(count, *prop_value); 8638 count++; 8639 } 8640 8641 if (count < values_or_entries->length()) values_or_entries->Shrink(count); 8642 *result = values_or_entries; 8643 return Just(true); 8644 } 8645 8646 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, 8647 Handle<JSReceiver> object, 8648 PropertyFilter filter, 8649 bool get_entries) { 8650 Handle<FixedArray> values_or_entries; 8651 if (filter == ENUMERABLE_STRINGS) { 8652 Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries( 8653 isolate, object, get_entries, &values_or_entries); 8654 if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>(); 8655 if (fast_values_or_entries.FromJust()) return values_or_entries; 8656 } 8657 8658 PropertyFilter key_filter = 8659 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE); 8660 8661 Handle<FixedArray> keys; 8662 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8663 isolate, keys, 8664 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter, 8665 GetKeysConversion::kConvertToString), 8666 MaybeHandle<FixedArray>()); 8667 8668 values_or_entries = isolate->factory()->NewFixedArray(keys->length()); 8669 int length = 0; 8670 8671 for (int i = 0; i < keys->length(); ++i) { 8672 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate)); 8673 8674 if (filter & ONLY_ENUMERABLE) { 8675 PropertyDescriptor descriptor; 8676 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor( 8677 isolate, object, key, &descriptor); 8678 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>()); 8679 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue; 8680 } 8681 8682 Handle<Object> value; 8683 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8684 isolate, value, JSReceiver::GetPropertyOrElement(object, key), 8685 MaybeHandle<FixedArray>()); 8686 8687 if (get_entries) { 8688 Handle<FixedArray> entry_storage = 8689 isolate->factory()->NewUninitializedFixedArray(2); 8690 entry_storage->set(0, *key); 8691 entry_storage->set(1, *value); 8692 value = isolate->factory()->NewJSArrayWithElements(entry_storage, 8693 FAST_ELEMENTS, 2); 8694 } 8695 8696 values_or_entries->set(length, *value); 8697 length++; 8698 } 8699 if (length < values_or_entries->length()) values_or_entries->Shrink(length); 8700 return values_or_entries; 8701 } 8702 8703 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object, 8704 PropertyFilter filter) { 8705 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false); 8706 } 8707 8708 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object, 8709 PropertyFilter filter) { 8710 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true); 8711 } 8712 8713 bool Map::DictionaryElementsInPrototypeChainOnly() { 8714 if (IsDictionaryElementsKind(elements_kind())) { 8715 return false; 8716 } 8717 8718 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) { 8719 // Be conservative, don't walk into proxies. 8720 if (iter.GetCurrent()->IsJSProxy()) return true; 8721 // String wrappers have non-configurable, non-writable elements. 8722 if (iter.GetCurrent()->IsStringWrapper()) return true; 8723 JSObject* current = iter.GetCurrent<JSObject>(); 8724 8725 if (current->HasDictionaryElements() && 8726 current->element_dictionary()->requires_slow_elements()) { 8727 return true; 8728 } 8729 8730 if (current->HasSlowArgumentsElements()) { 8731 FixedArray* parameter_map = FixedArray::cast(current->elements()); 8732 Object* arguments = parameter_map->get(1); 8733 if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) { 8734 return true; 8735 } 8736 } 8737 } 8738 8739 return false; 8740 } 8741 8742 8743 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object, 8744 Handle<Name> name, 8745 Handle<Object> getter, 8746 Handle<Object> setter, 8747 PropertyAttributes attributes) { 8748 Isolate* isolate = object->GetIsolate(); 8749 8750 LookupIterator it = LookupIterator::PropertyOrElement( 8751 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 8752 return DefineAccessor(&it, getter, setter, attributes); 8753 } 8754 8755 8756 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it, 8757 Handle<Object> getter, 8758 Handle<Object> setter, 8759 PropertyAttributes attributes) { 8760 Isolate* isolate = it->isolate(); 8761 8762 it->UpdateProtector(); 8763 8764 if (it->state() == LookupIterator::ACCESS_CHECK) { 8765 if (!it->HasAccess()) { 8766 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 8767 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 8768 return isolate->factory()->undefined_value(); 8769 } 8770 it->Next(); 8771 } 8772 8773 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 8774 // Ignore accessors on typed arrays. 8775 if (it->IsElement() && object->HasFixedTypedArrayElements()) { 8776 return it->factory()->undefined_value(); 8777 } 8778 8779 DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) || 8780 getter->IsNull(isolate) || getter->IsFunctionTemplateInfo()); 8781 DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) || 8782 setter->IsNull(isolate) || setter->IsFunctionTemplateInfo()); 8783 it->TransitionToAccessorProperty(getter, setter, attributes); 8784 8785 return isolate->factory()->undefined_value(); 8786 } 8787 8788 8789 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object, 8790 Handle<AccessorInfo> info) { 8791 Isolate* isolate = object->GetIsolate(); 8792 Handle<Name> name(Name::cast(info->name()), isolate); 8793 8794 LookupIterator it = LookupIterator::PropertyOrElement( 8795 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 8796 8797 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that 8798 // the FailedAccessCheckCallbackFunction doesn't throw an exception. 8799 // 8800 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can 8801 // remove reliance on default return values. 8802 if (it.state() == LookupIterator::ACCESS_CHECK) { 8803 if (!it.HasAccess()) { 8804 isolate->ReportFailedAccessCheck(object); 8805 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 8806 return it.factory()->undefined_value(); 8807 } 8808 it.Next(); 8809 } 8810 8811 // Ignore accessors on typed arrays. 8812 if (it.IsElement() && object->HasFixedTypedArrayElements()) { 8813 return it.factory()->undefined_value(); 8814 } 8815 8816 CHECK(GetPropertyAttributes(&it).IsJust()); 8817 8818 // ES5 forbids turning a property into an accessor if it's not 8819 // configurable. See 8.6.1 (Table 5). 8820 if (it.IsFound() && !it.IsConfigurable()) { 8821 return it.factory()->undefined_value(); 8822 } 8823 8824 it.TransitionToAccessorPair(info, info->property_attributes()); 8825 8826 return object; 8827 } 8828 8829 Object* JSObject::SlowReverseLookup(Object* value) { 8830 if (HasFastProperties()) { 8831 int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); 8832 DescriptorArray* descs = map()->instance_descriptors(); 8833 bool value_is_number = value->IsNumber(); 8834 for (int i = 0; i < number_of_own_descriptors; i++) { 8835 if (descs->GetType(i) == DATA) { 8836 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i); 8837 if (IsUnboxedDoubleField(field_index)) { 8838 if (value_is_number) { 8839 double property = RawFastDoublePropertyAt(field_index); 8840 if (property == value->Number()) { 8841 return descs->GetKey(i); 8842 } 8843 } 8844 } else { 8845 Object* property = RawFastPropertyAt(field_index); 8846 if (field_index.is_double()) { 8847 DCHECK(property->IsMutableHeapNumber()); 8848 if (value_is_number && property->Number() == value->Number()) { 8849 return descs->GetKey(i); 8850 } 8851 } else if (property == value) { 8852 return descs->GetKey(i); 8853 } 8854 } 8855 } else if (descs->GetType(i) == DATA_CONSTANT) { 8856 if (descs->GetConstant(i) == value) { 8857 return descs->GetKey(i); 8858 } 8859 } 8860 } 8861 return GetHeap()->undefined_value(); 8862 } else if (IsJSGlobalObject()) { 8863 return global_dictionary()->SlowReverseLookup(value); 8864 } else { 8865 return property_dictionary()->SlowReverseLookup(value); 8866 } 8867 } 8868 8869 8870 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) { 8871 Isolate* isolate = map->GetIsolate(); 8872 Handle<Map> result = 8873 isolate->factory()->NewMap(map->instance_type(), instance_size); 8874 Handle<Object> prototype(map->prototype(), isolate); 8875 Map::SetPrototype(result, prototype); 8876 result->set_constructor_or_backpointer(map->GetConstructor()); 8877 result->set_bit_field(map->bit_field()); 8878 result->set_bit_field2(map->bit_field2()); 8879 int new_bit_field3 = map->bit_field3(); 8880 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); 8881 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); 8882 new_bit_field3 = EnumLengthBits::update(new_bit_field3, 8883 kInvalidEnumCacheSentinel); 8884 new_bit_field3 = Deprecated::update(new_bit_field3, false); 8885 if (!map->is_dictionary_map()) { 8886 new_bit_field3 = IsUnstable::update(new_bit_field3, false); 8887 } 8888 result->set_bit_field3(new_bit_field3); 8889 return result; 8890 } 8891 8892 8893 Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode, 8894 const char* reason) { 8895 DCHECK(!fast_map->is_dictionary_map()); 8896 8897 Isolate* isolate = fast_map->GetIsolate(); 8898 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(), 8899 isolate); 8900 bool use_cache = 8901 !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate); 8902 Handle<NormalizedMapCache> cache; 8903 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache); 8904 8905 Handle<Map> new_map; 8906 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) { 8907 #ifdef VERIFY_HEAP 8908 if (FLAG_verify_heap) new_map->DictionaryMapVerify(); 8909 #endif 8910 #ifdef ENABLE_SLOW_DCHECKS 8911 if (FLAG_enable_slow_asserts) { 8912 // The cached map should match newly created normalized map bit-by-bit, 8913 // except for the code cache, which can contain some ics which can be 8914 // applied to the shared map, dependent code and weak cell cache. 8915 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode); 8916 8917 if (new_map->is_prototype_map()) { 8918 // For prototype maps, the PrototypeInfo is not copied. 8919 DCHECK(memcmp(fresh->address(), new_map->address(), 8920 kTransitionsOrPrototypeInfoOffset) == 0); 8921 DCHECK(fresh->raw_transitions() == Smi::kZero); 8922 STATIC_ASSERT(kDescriptorsOffset == 8923 kTransitionsOrPrototypeInfoOffset + kPointerSize); 8924 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset), 8925 HeapObject::RawField(*new_map, kDescriptorsOffset), 8926 kCodeCacheOffset - kDescriptorsOffset) == 0); 8927 } else { 8928 DCHECK(memcmp(fresh->address(), new_map->address(), 8929 Map::kCodeCacheOffset) == 0); 8930 } 8931 STATIC_ASSERT(Map::kDependentCodeOffset == 8932 Map::kCodeCacheOffset + kPointerSize); 8933 STATIC_ASSERT(Map::kWeakCellCacheOffset == 8934 Map::kDependentCodeOffset + kPointerSize); 8935 int offset = Map::kWeakCellCacheOffset + kPointerSize; 8936 DCHECK(memcmp(fresh->address() + offset, 8937 new_map->address() + offset, 8938 Map::kSize - offset) == 0); 8939 } 8940 #endif 8941 } else { 8942 new_map = Map::CopyNormalized(fast_map, mode); 8943 if (use_cache) { 8944 cache->Set(fast_map, new_map); 8945 isolate->counters()->maps_normalized()->Increment(); 8946 } 8947 #if TRACE_MAPS 8948 if (FLAG_trace_maps) { 8949 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n", 8950 reinterpret_cast<void*>(*fast_map), 8951 reinterpret_cast<void*>(*new_map), reason); 8952 } 8953 #endif 8954 } 8955 fast_map->NotifyLeafMapLayoutChange(); 8956 return new_map; 8957 } 8958 8959 8960 Handle<Map> Map::CopyNormalized(Handle<Map> map, 8961 PropertyNormalizationMode mode) { 8962 int new_instance_size = map->instance_size(); 8963 if (mode == CLEAR_INOBJECT_PROPERTIES) { 8964 new_instance_size -= map->GetInObjectProperties() * kPointerSize; 8965 } 8966 8967 Handle<Map> result = RawCopy(map, new_instance_size); 8968 8969 if (mode != CLEAR_INOBJECT_PROPERTIES) { 8970 result->SetInObjectProperties(map->GetInObjectProperties()); 8971 } 8972 8973 result->set_dictionary_map(true); 8974 result->set_migration_target(false); 8975 result->set_construction_counter(kNoSlackTracking); 8976 8977 #ifdef VERIFY_HEAP 8978 if (FLAG_verify_heap) result->DictionaryMapVerify(); 8979 #endif 8980 8981 return result; 8982 } 8983 8984 // Return an immutable prototype exotic object version of the input map. 8985 // Never even try to cache it in the transition tree, as it is intended 8986 // for the global object and its prototype chain, and excluding it saves 8987 // memory on the map transition tree. 8988 8989 // static 8990 Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) { 8991 Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype"); 8992 new_map->set_immutable_proto(true); 8993 return new_map; 8994 } 8995 8996 Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size, 8997 int in_object_properties, 8998 int unused_property_fields) { 8999 #ifdef DEBUG 9000 Isolate* isolate = map->GetIsolate(); 9001 // Strict function maps have Function as a constructor but the 9002 // Function's initial map is a sloppy function map. Same holds for 9003 // GeneratorFunction and its initial map. 9004 Object* constructor = map->GetConstructor(); 9005 DCHECK(constructor->IsJSFunction()); 9006 DCHECK(*map == JSFunction::cast(constructor)->initial_map() || 9007 *map == *isolate->strict_function_map() || 9008 *map == *isolate->strict_generator_function_map()); 9009 #endif 9010 // Initial maps must always own their descriptors and it's descriptor array 9011 // does not contain descriptors that do not belong to the map. 9012 DCHECK(map->owns_descriptors()); 9013 DCHECK_EQ(map->NumberOfOwnDescriptors(), 9014 map->instance_descriptors()->number_of_descriptors()); 9015 9016 Handle<Map> result = RawCopy(map, instance_size); 9017 9018 // Please note instance_type and instance_size are set when allocated. 9019 result->SetInObjectProperties(in_object_properties); 9020 result->set_unused_property_fields(unused_property_fields); 9021 9022 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9023 if (number_of_own_descriptors > 0) { 9024 // The copy will use the same descriptors array. 9025 result->UpdateDescriptors(map->instance_descriptors(), 9026 map->GetLayoutDescriptor()); 9027 result->SetNumberOfOwnDescriptors(number_of_own_descriptors); 9028 9029 DCHECK_EQ(result->NumberOfFields(), 9030 in_object_properties - unused_property_fields); 9031 } 9032 9033 return result; 9034 } 9035 9036 9037 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) { 9038 Handle<Map> result = RawCopy(map, map->instance_size()); 9039 9040 // Please note instance_type and instance_size are set when allocated. 9041 if (map->IsJSObjectMap()) { 9042 result->SetInObjectProperties(map->GetInObjectProperties()); 9043 result->set_unused_property_fields(map->unused_property_fields()); 9044 } 9045 result->ClearCodeCache(map->GetHeap()); 9046 map->NotifyLeafMapLayoutChange(); 9047 return result; 9048 } 9049 9050 9051 Handle<Map> Map::ShareDescriptor(Handle<Map> map, 9052 Handle<DescriptorArray> descriptors, 9053 Descriptor* descriptor) { 9054 // Sanity check. This path is only to be taken if the map owns its descriptor 9055 // array, implying that its NumberOfOwnDescriptors equals the number of 9056 // descriptors in the descriptor array. 9057 DCHECK_EQ(map->NumberOfOwnDescriptors(), 9058 map->instance_descriptors()->number_of_descriptors()); 9059 9060 Handle<Map> result = CopyDropDescriptors(map); 9061 Handle<Name> name = descriptor->GetKey(); 9062 9063 // Ensure there's space for the new descriptor in the shared descriptor array. 9064 if (descriptors->NumberOfSlackDescriptors() == 0) { 9065 int old_size = descriptors->number_of_descriptors(); 9066 if (old_size == 0) { 9067 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1); 9068 } else { 9069 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors); 9070 EnsureDescriptorSlack(map, slack); 9071 descriptors = handle(map->instance_descriptors()); 9072 } 9073 } 9074 9075 Handle<LayoutDescriptor> layout_descriptor = 9076 FLAG_unbox_double_fields 9077 ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails()) 9078 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate()); 9079 9080 { 9081 DisallowHeapAllocation no_gc; 9082 descriptors->Append(descriptor); 9083 result->InitializeDescriptors(*descriptors, *layout_descriptor); 9084 } 9085 9086 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1); 9087 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION); 9088 9089 return result; 9090 } 9091 9092 9093 #if TRACE_MAPS 9094 9095 // static 9096 void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) { 9097 if (FLAG_trace_maps) { 9098 PrintF("[TraceMaps: %s from= %p to= %p name= ", what, 9099 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to)); 9100 name->NameShortPrint(); 9101 PrintF(" ]\n"); 9102 } 9103 } 9104 9105 9106 // static 9107 void Map::TraceAllTransitions(Map* map) { 9108 Object* transitions = map->raw_transitions(); 9109 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 9110 for (int i = -0; i < num_transitions; ++i) { 9111 Map* target = TransitionArray::GetTarget(transitions, i); 9112 Name* key = TransitionArray::GetKey(transitions, i); 9113 Map::TraceTransition("Transition", map, target, key); 9114 Map::TraceAllTransitions(target); 9115 } 9116 } 9117 9118 #endif // TRACE_MAPS 9119 9120 9121 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child, 9122 Handle<Name> name, SimpleTransitionFlag flag) { 9123 if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) { 9124 parent->set_owns_descriptors(false); 9125 } else { 9126 // |parent| is initial map and it must keep the ownership, there must be no 9127 // descriptors in the descriptors array that do not belong to the map. 9128 DCHECK(parent->owns_descriptors()); 9129 DCHECK_EQ(parent->NumberOfOwnDescriptors(), 9130 parent->instance_descriptors()->number_of_descriptors()); 9131 } 9132 if (parent->is_prototype_map()) { 9133 DCHECK(child->is_prototype_map()); 9134 #if TRACE_MAPS 9135 Map::TraceTransition("NoTransition", *parent, *child, *name); 9136 #endif 9137 } else { 9138 TransitionArray::Insert(parent, name, child, flag); 9139 #if TRACE_MAPS 9140 Map::TraceTransition("Transition", *parent, *child, *name); 9141 #endif 9142 } 9143 } 9144 9145 9146 Handle<Map> Map::CopyReplaceDescriptors( 9147 Handle<Map> map, Handle<DescriptorArray> descriptors, 9148 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag, 9149 MaybeHandle<Name> maybe_name, const char* reason, 9150 SimpleTransitionFlag simple_flag) { 9151 DCHECK(descriptors->IsSortedNoDuplicates()); 9152 9153 Handle<Map> result = CopyDropDescriptors(map); 9154 9155 if (!map->is_prototype_map()) { 9156 if (flag == INSERT_TRANSITION && 9157 TransitionArray::CanHaveMoreTransitions(map)) { 9158 result->InitializeDescriptors(*descriptors, *layout_descriptor); 9159 9160 Handle<Name> name; 9161 CHECK(maybe_name.ToHandle(&name)); 9162 ConnectTransition(map, result, name, simple_flag); 9163 } else { 9164 int length = descriptors->number_of_descriptors(); 9165 for (int i = 0; i < length; i++) { 9166 descriptors->SetRepresentation(i, Representation::Tagged()); 9167 if (descriptors->GetDetails(i).type() == DATA) { 9168 descriptors->SetValue(i, FieldType::Any()); 9169 } 9170 } 9171 result->InitializeDescriptors(*descriptors, 9172 LayoutDescriptor::FastPointerLayout()); 9173 } 9174 } else { 9175 result->InitializeDescriptors(*descriptors, *layout_descriptor); 9176 } 9177 #if TRACE_MAPS 9178 if (FLAG_trace_maps && 9179 // Mirror conditions above that did not call ConnectTransition(). 9180 (map->is_prototype_map() || 9181 !(flag == INSERT_TRANSITION && 9182 TransitionArray::CanHaveMoreTransitions(map)))) { 9183 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n", 9184 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result), 9185 reason); 9186 } 9187 #endif 9188 9189 return result; 9190 } 9191 9192 9193 // Creates transition tree starting from |split_map| and adding all descriptors 9194 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors(). 9195 // The way how it is done is tricky because of GC and special descriptors 9196 // marking logic. 9197 Handle<Map> Map::AddMissingTransitions( 9198 Handle<Map> split_map, Handle<DescriptorArray> descriptors, 9199 Handle<LayoutDescriptor> full_layout_descriptor) { 9200 DCHECK(descriptors->IsSortedNoDuplicates()); 9201 int split_nof = split_map->NumberOfOwnDescriptors(); 9202 int nof_descriptors = descriptors->number_of_descriptors(); 9203 DCHECK_LT(split_nof, nof_descriptors); 9204 9205 // Start with creating last map which will own full descriptors array. 9206 // This is necessary to guarantee that GC will mark the whole descriptor 9207 // array if any of the allocations happening below fail. 9208 // Number of unused properties is temporarily incorrect and the layout 9209 // descriptor could unnecessarily be in slow mode but we will fix after 9210 // all the other intermediate maps are created. 9211 Handle<Map> last_map = CopyDropDescriptors(split_map); 9212 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor); 9213 last_map->set_unused_property_fields(0); 9214 9215 // During creation of intermediate maps we violate descriptors sharing 9216 // invariant since the last map is not yet connected to the transition tree 9217 // we create here. But it is safe because GC never trims map's descriptors 9218 // if there are no dead transitions from that map and this is exactly the 9219 // case for all the intermediate maps we create here. 9220 Handle<Map> map = split_map; 9221 for (int i = split_nof; i < nof_descriptors - 1; ++i) { 9222 Handle<Map> new_map = CopyDropDescriptors(map); 9223 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor); 9224 map = new_map; 9225 } 9226 map->NotifyLeafMapLayoutChange(); 9227 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors, 9228 full_layout_descriptor); 9229 return last_map; 9230 } 9231 9232 9233 // Since this method is used to rewrite an existing transition tree, it can 9234 // always insert transitions without checking. 9235 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child, 9236 int new_descriptor, 9237 Handle<DescriptorArray> descriptors, 9238 Handle<LayoutDescriptor> full_layout_descriptor) { 9239 DCHECK(descriptors->IsSortedNoDuplicates()); 9240 9241 child->set_instance_descriptors(*descriptors); 9242 child->SetNumberOfOwnDescriptors(new_descriptor + 1); 9243 9244 int unused_property_fields = parent->unused_property_fields(); 9245 PropertyDetails details = descriptors->GetDetails(new_descriptor); 9246 if (details.location() == kField) { 9247 unused_property_fields = parent->unused_property_fields() - 1; 9248 if (unused_property_fields < 0) { 9249 unused_property_fields += JSObject::kFieldsAdded; 9250 } 9251 } 9252 child->set_unused_property_fields(unused_property_fields); 9253 9254 if (FLAG_unbox_double_fields) { 9255 Handle<LayoutDescriptor> layout_descriptor = 9256 LayoutDescriptor::AppendIfFastOrUseFull(parent, details, 9257 full_layout_descriptor); 9258 child->set_layout_descriptor(*layout_descriptor); 9259 #ifdef VERIFY_HEAP 9260 // TODO(ishell): remove these checks from VERIFY_HEAP mode. 9261 if (FLAG_verify_heap) { 9262 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); 9263 } 9264 #else 9265 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); 9266 #endif 9267 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child)); 9268 } 9269 9270 Handle<Name> name = handle(descriptors->GetKey(new_descriptor)); 9271 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION); 9272 } 9273 9274 9275 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind, 9276 TransitionFlag flag) { 9277 Map* maybe_elements_transition_map = NULL; 9278 if (flag == INSERT_TRANSITION) { 9279 // Ensure we are requested to add elements kind transition "near the root". 9280 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(), 9281 map->NumberOfOwnDescriptors()); 9282 9283 maybe_elements_transition_map = map->ElementsTransitionMap(); 9284 DCHECK(maybe_elements_transition_map == NULL || 9285 (maybe_elements_transition_map->elements_kind() == 9286 DICTIONARY_ELEMENTS && 9287 kind == DICTIONARY_ELEMENTS)); 9288 DCHECK(!IsFastElementsKind(kind) || 9289 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind)); 9290 DCHECK(kind != map->elements_kind()); 9291 } 9292 9293 bool insert_transition = flag == INSERT_TRANSITION && 9294 TransitionArray::CanHaveMoreTransitions(map) && 9295 maybe_elements_transition_map == NULL; 9296 9297 if (insert_transition) { 9298 Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind"); 9299 new_map->set_elements_kind(kind); 9300 9301 Isolate* isolate = map->GetIsolate(); 9302 Handle<Name> name = isolate->factory()->elements_transition_symbol(); 9303 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION); 9304 return new_map; 9305 } 9306 9307 // Create a new free-floating map only if we are not allowed to store it. 9308 Handle<Map> new_map = Copy(map, "CopyAsElementsKind"); 9309 new_map->set_elements_kind(kind); 9310 return new_map; 9311 } 9312 9313 9314 Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map, 9315 LanguageMode language_mode, FunctionKind kind) { 9316 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type()); 9317 // Initial map for sloppy mode function is stored in the function 9318 // constructor. Initial maps for strict mode are cached as special transitions 9319 // using |strict_function_transition_symbol| as a key. 9320 if (language_mode == SLOPPY) return initial_map; 9321 Isolate* isolate = initial_map->GetIsolate(); 9322 9323 int map_index = Context::FunctionMapIndex(language_mode, kind); 9324 Handle<Map> function_map( 9325 Map::cast(isolate->native_context()->get(map_index))); 9326 9327 STATIC_ASSERT(LANGUAGE_END == 2); 9328 DCHECK_EQ(STRICT, language_mode); 9329 Handle<Symbol> transition_symbol = 9330 isolate->factory()->strict_function_transition_symbol(); 9331 Map* maybe_transition = 9332 TransitionArray::SearchSpecial(*initial_map, *transition_symbol); 9333 if (maybe_transition != NULL) { 9334 return handle(maybe_transition, isolate); 9335 } 9336 initial_map->NotifyLeafMapLayoutChange(); 9337 9338 // Create new map taking descriptors from the |function_map| and all 9339 // the other details from the |initial_map|. 9340 Handle<Map> map = 9341 Map::CopyInitialMap(function_map, initial_map->instance_size(), 9342 initial_map->GetInObjectProperties(), 9343 initial_map->unused_property_fields()); 9344 map->SetConstructor(initial_map->GetConstructor()); 9345 map->set_prototype(initial_map->prototype()); 9346 9347 if (TransitionArray::CanHaveMoreTransitions(initial_map)) { 9348 Map::ConnectTransition(initial_map, map, transition_symbol, 9349 SPECIAL_TRANSITION); 9350 } 9351 return map; 9352 } 9353 9354 9355 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) { 9356 DCHECK(!map->is_prototype_map()); 9357 Handle<Map> new_map = CopyDropDescriptors(map); 9358 9359 if (map->owns_descriptors()) { 9360 // In case the map owned its own descriptors, share the descriptors and 9361 // transfer ownership to the new map. 9362 // The properties did not change, so reuse descriptors. 9363 new_map->InitializeDescriptors(map->instance_descriptors(), 9364 map->GetLayoutDescriptor()); 9365 } else { 9366 // In case the map did not own its own descriptors, a split is forced by 9367 // copying the map; creating a new descriptor array cell. 9368 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 9369 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9370 Handle<DescriptorArray> new_descriptors = 9371 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors); 9372 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9373 map->GetIsolate()); 9374 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); 9375 } 9376 9377 #if TRACE_MAPS 9378 if (FLAG_trace_maps) { 9379 PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n", 9380 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map), 9381 reason); 9382 } 9383 #endif 9384 9385 return new_map; 9386 } 9387 9388 9389 Handle<Map> Map::Copy(Handle<Map> map, const char* reason) { 9390 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 9391 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9392 Handle<DescriptorArray> new_descriptors = 9393 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors); 9394 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9395 map->GetIsolate()); 9396 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9397 OMIT_TRANSITION, MaybeHandle<Name>(), reason, 9398 SPECIAL_TRANSITION); 9399 } 9400 9401 9402 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) { 9403 Handle<Map> copy = 9404 Copy(handle(isolate->object_function()->initial_map()), "MapCreate"); 9405 9406 // Check that we do not overflow the instance size when adding the extra 9407 // inobject properties. If the instance size overflows, we allocate as many 9408 // properties as we can as inobject properties. 9409 int max_extra_properties = 9410 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2; 9411 9412 if (inobject_properties > max_extra_properties) { 9413 inobject_properties = max_extra_properties; 9414 } 9415 9416 int new_instance_size = 9417 JSObject::kHeaderSize + kPointerSize * inobject_properties; 9418 9419 // Adjust the map with the extra inobject properties. 9420 copy->SetInObjectProperties(inobject_properties); 9421 copy->set_unused_property_fields(inobject_properties); 9422 copy->set_instance_size(new_instance_size); 9423 copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy)); 9424 return copy; 9425 } 9426 9427 9428 Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map, 9429 PropertyAttributes attrs_to_add, 9430 Handle<Symbol> transition_marker, 9431 const char* reason) { 9432 int num_descriptors = map->NumberOfOwnDescriptors(); 9433 Isolate* isolate = map->GetIsolate(); 9434 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes( 9435 handle(map->instance_descriptors(), isolate), num_descriptors, 9436 attrs_to_add); 9437 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9438 isolate); 9439 Handle<Map> new_map = CopyReplaceDescriptors( 9440 map, new_desc, new_layout_descriptor, INSERT_TRANSITION, 9441 transition_marker, reason, SPECIAL_TRANSITION); 9442 new_map->set_is_extensible(false); 9443 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) { 9444 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind()) 9445 ? SLOW_STRING_WRAPPER_ELEMENTS 9446 : DICTIONARY_ELEMENTS; 9447 new_map->set_elements_kind(new_kind); 9448 } 9449 return new_map; 9450 } 9451 9452 FieldType* DescriptorArray::GetFieldType(int descriptor_number) { 9453 DCHECK(GetDetails(descriptor_number).location() == kField); 9454 Object* value = GetValue(descriptor_number); 9455 if (value->IsWeakCell()) { 9456 if (WeakCell::cast(value)->cleared()) return FieldType::None(); 9457 value = WeakCell::cast(value)->value(); 9458 } 9459 return FieldType::cast(value); 9460 } 9461 9462 namespace { 9463 9464 bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) { 9465 PropertyDetails details = descriptors->GetDetails(descriptor); 9466 switch (details.type()) { 9467 case DATA: 9468 return value->FitsRepresentation(details.representation()) && 9469 descriptors->GetFieldType(descriptor)->NowContains(value); 9470 9471 case DATA_CONSTANT: 9472 DCHECK(descriptors->GetConstant(descriptor) != value || 9473 value->FitsRepresentation(details.representation())); 9474 return descriptors->GetConstant(descriptor) == value; 9475 9476 case ACCESSOR: 9477 case ACCESSOR_CONSTANT: 9478 return false; 9479 } 9480 9481 UNREACHABLE(); 9482 return false; 9483 } 9484 9485 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor, 9486 Handle<Object> value) { 9487 if (CanHoldValue(map->instance_descriptors(), descriptor, *value)) return map; 9488 9489 Isolate* isolate = map->GetIsolate(); 9490 PropertyAttributes attributes = 9491 map->instance_descriptors()->GetDetails(descriptor).attributes(); 9492 Representation representation = value->OptimalRepresentation(); 9493 Handle<FieldType> type = value->OptimalType(isolate, representation); 9494 9495 return Map::ReconfigureProperty(map, descriptor, kData, attributes, 9496 representation, type, FORCE_FIELD); 9497 } 9498 9499 } // namespace 9500 9501 // static 9502 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, 9503 Handle<Object> value) { 9504 // Dictionaries can store any property value. 9505 DCHECK(!map->is_dictionary_map()); 9506 // Update to the newest map before storing the property. 9507 return UpdateDescriptorForValue(Update(map), descriptor, value); 9508 } 9509 9510 9511 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, 9512 Handle<Object> value, 9513 PropertyAttributes attributes, 9514 StoreFromKeyed store_mode) { 9515 RuntimeCallTimerScope stats_scope( 9516 *map, map->is_prototype_map() 9517 ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty 9518 : &RuntimeCallStats::Map_TransitionToDataProperty); 9519 9520 DCHECK(name->IsUniqueName()); 9521 DCHECK(!map->is_dictionary_map()); 9522 9523 // Migrate to the newest map before storing the property. 9524 map = Update(map); 9525 9526 Map* maybe_transition = 9527 TransitionArray::SearchTransition(*map, kData, *name, attributes); 9528 if (maybe_transition != NULL) { 9529 Handle<Map> transition(maybe_transition); 9530 int descriptor = transition->LastAdded(); 9531 9532 DCHECK_EQ(attributes, transition->instance_descriptors() 9533 ->GetDetails(descriptor) 9534 .attributes()); 9535 9536 return UpdateDescriptorForValue(transition, descriptor, value); 9537 } 9538 9539 TransitionFlag flag = INSERT_TRANSITION; 9540 MaybeHandle<Map> maybe_map; 9541 if (value->IsJSFunction()) { 9542 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag); 9543 } else if (!map->TooManyFastProperties(store_mode)) { 9544 Isolate* isolate = name->GetIsolate(); 9545 Representation representation = value->OptimalRepresentation(); 9546 Handle<FieldType> type = value->OptimalType(isolate, representation); 9547 maybe_map = 9548 Map::CopyWithField(map, name, type, attributes, representation, flag); 9549 } 9550 9551 Handle<Map> result; 9552 if (!maybe_map.ToHandle(&result)) { 9553 #if TRACE_MAPS 9554 if (FLAG_trace_maps) { 9555 Vector<char> name_buffer = Vector<char>::New(100); 9556 name->NameShortPrint(name_buffer); 9557 Vector<char> buffer = Vector<char>::New(128); 9558 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start()); 9559 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start()); 9560 } 9561 #endif 9562 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, 9563 "TooManyFastProperties"); 9564 } 9565 9566 return result; 9567 } 9568 9569 9570 Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor, 9571 PropertyKind kind, 9572 PropertyAttributes attributes) { 9573 // Dictionaries have to be reconfigured in-place. 9574 DCHECK(!map->is_dictionary_map()); 9575 9576 if (!map->GetBackPointer()->IsMap()) { 9577 // There is no benefit from reconstructing transition tree for maps without 9578 // back pointers. 9579 return CopyGeneralizeAllRepresentations( 9580 map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes, 9581 "GenAll_AttributesMismatchProtoMap"); 9582 } 9583 9584 if (FLAG_trace_generalization) { 9585 map->PrintReconfiguration(stdout, descriptor, kind, attributes); 9586 } 9587 9588 Isolate* isolate = map->GetIsolate(); 9589 Handle<Map> new_map = ReconfigureProperty( 9590 map, descriptor, kind, attributes, Representation::None(), 9591 FieldType::None(isolate), FORCE_FIELD); 9592 return new_map; 9593 } 9594 9595 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map, 9596 Handle<Name> name, int descriptor, 9597 Handle<Object> getter, 9598 Handle<Object> setter, 9599 PropertyAttributes attributes) { 9600 RuntimeCallTimerScope stats_scope( 9601 isolate, 9602 map->is_prototype_map() 9603 ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty 9604 : &RuntimeCallStats::Map_TransitionToAccessorProperty); 9605 9606 // At least one of the accessors needs to be a new value. 9607 DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate)); 9608 DCHECK(name->IsUniqueName()); 9609 9610 // Dictionary maps can always have additional data properties. 9611 if (map->is_dictionary_map()) return map; 9612 9613 // Migrate to the newest map before transitioning to the new property. 9614 map = Update(map); 9615 9616 PropertyNormalizationMode mode = map->is_prototype_map() 9617 ? KEEP_INOBJECT_PROPERTIES 9618 : CLEAR_INOBJECT_PROPERTIES; 9619 9620 Map* maybe_transition = 9621 TransitionArray::SearchTransition(*map, kAccessor, *name, attributes); 9622 if (maybe_transition != NULL) { 9623 Handle<Map> transition(maybe_transition, isolate); 9624 DescriptorArray* descriptors = transition->instance_descriptors(); 9625 int descriptor = transition->LastAdded(); 9626 DCHECK(descriptors->GetKey(descriptor)->Equals(*name)); 9627 9628 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind()); 9629 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes()); 9630 9631 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate); 9632 if (!maybe_pair->IsAccessorPair()) { 9633 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair"); 9634 } 9635 9636 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair); 9637 if (!pair->Equals(*getter, *setter)) { 9638 return Map::Normalize(map, mode, "TransitionToDifferentAccessor"); 9639 } 9640 9641 return transition; 9642 } 9643 9644 Handle<AccessorPair> pair; 9645 DescriptorArray* old_descriptors = map->instance_descriptors(); 9646 if (descriptor != DescriptorArray::kNotFound) { 9647 if (descriptor != map->LastAdded()) { 9648 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast"); 9649 } 9650 PropertyDetails old_details = old_descriptors->GetDetails(descriptor); 9651 if (old_details.type() != ACCESSOR_CONSTANT) { 9652 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors"); 9653 } 9654 9655 if (old_details.attributes() != attributes) { 9656 return Map::Normalize(map, mode, "AccessorsWithAttributes"); 9657 } 9658 9659 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate); 9660 if (!maybe_pair->IsAccessorPair()) { 9661 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair"); 9662 } 9663 9664 Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair); 9665 if (current_pair->Equals(*getter, *setter)) return map; 9666 9667 bool overwriting_accessor = false; 9668 if (!getter->IsNull(isolate) && 9669 !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) && 9670 current_pair->get(ACCESSOR_GETTER) != *getter) { 9671 overwriting_accessor = true; 9672 } 9673 if (!setter->IsNull(isolate) && 9674 !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) && 9675 current_pair->get(ACCESSOR_SETTER) != *setter) { 9676 overwriting_accessor = true; 9677 } 9678 if (overwriting_accessor) { 9679 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors"); 9680 } 9681 9682 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair)); 9683 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors || 9684 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) { 9685 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors"); 9686 } else { 9687 pair = isolate->factory()->NewAccessorPair(); 9688 } 9689 9690 pair->SetComponents(*getter, *setter); 9691 9692 TransitionFlag flag = INSERT_TRANSITION; 9693 AccessorConstantDescriptor new_desc(name, pair, attributes); 9694 return Map::CopyInsertDescriptor(map, &new_desc, flag); 9695 } 9696 9697 9698 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, 9699 Descriptor* descriptor, 9700 TransitionFlag flag) { 9701 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 9702 9703 // Share descriptors only if map owns descriptors and it not an initial map. 9704 if (flag == INSERT_TRANSITION && map->owns_descriptors() && 9705 !map->GetBackPointer()->IsUndefined(map->GetIsolate()) && 9706 TransitionArray::CanHaveMoreTransitions(map)) { 9707 return ShareDescriptor(map, descriptors, descriptor); 9708 } 9709 9710 int nof = map->NumberOfOwnDescriptors(); 9711 Handle<DescriptorArray> new_descriptors = 9712 DescriptorArray::CopyUpTo(descriptors, nof, 1); 9713 new_descriptors->Append(descriptor); 9714 9715 Handle<LayoutDescriptor> new_layout_descriptor = 9716 FLAG_unbox_double_fields 9717 ? LayoutDescriptor::New(map, new_descriptors, nof + 1) 9718 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate()); 9719 9720 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9721 flag, descriptor->GetKey(), "CopyAddDescriptor", 9722 SIMPLE_PROPERTY_TRANSITION); 9723 } 9724 9725 9726 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map, 9727 Descriptor* descriptor, 9728 TransitionFlag flag) { 9729 Handle<DescriptorArray> old_descriptors(map->instance_descriptors()); 9730 9731 // We replace the key if it is already present. 9732 int index = old_descriptors->SearchWithCache(map->GetIsolate(), 9733 *descriptor->GetKey(), *map); 9734 if (index != DescriptorArray::kNotFound) { 9735 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag); 9736 } 9737 return CopyAddDescriptor(map, descriptor, flag); 9738 } 9739 9740 9741 Handle<DescriptorArray> DescriptorArray::CopyUpTo( 9742 Handle<DescriptorArray> desc, 9743 int enumeration_index, 9744 int slack) { 9745 return DescriptorArray::CopyUpToAddAttributes( 9746 desc, enumeration_index, NONE, slack); 9747 } 9748 9749 9750 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes( 9751 Handle<DescriptorArray> desc, 9752 int enumeration_index, 9753 PropertyAttributes attributes, 9754 int slack) { 9755 if (enumeration_index + slack == 0) { 9756 return desc->GetIsolate()->factory()->empty_descriptor_array(); 9757 } 9758 9759 int size = enumeration_index; 9760 9761 Handle<DescriptorArray> descriptors = 9762 DescriptorArray::Allocate(desc->GetIsolate(), size, slack); 9763 9764 if (attributes != NONE) { 9765 for (int i = 0; i < size; ++i) { 9766 Object* value = desc->GetValue(i); 9767 Name* key = desc->GetKey(i); 9768 PropertyDetails details = desc->GetDetails(i); 9769 // Bulk attribute changes never affect private properties. 9770 if (!key->IsPrivate()) { 9771 int mask = DONT_DELETE | DONT_ENUM; 9772 // READ_ONLY is an invalid attribute for JS setters/getters. 9773 if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) { 9774 mask |= READ_ONLY; 9775 } 9776 details = details.CopyAddAttributes( 9777 static_cast<PropertyAttributes>(attributes & mask)); 9778 } 9779 Descriptor inner_desc( 9780 handle(key), handle(value, desc->GetIsolate()), details); 9781 descriptors->SetDescriptor(i, &inner_desc); 9782 } 9783 } else { 9784 for (int i = 0; i < size; ++i) { 9785 descriptors->CopyFrom(i, *desc); 9786 } 9787 } 9788 9789 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort(); 9790 9791 return descriptors; 9792 } 9793 9794 9795 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) { 9796 for (int i = 0; i < nof_descriptors; i++) { 9797 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) { 9798 return false; 9799 } 9800 PropertyDetails details = GetDetails(i); 9801 PropertyDetails other_details = desc->GetDetails(i); 9802 if (details.type() != other_details.type() || 9803 !details.representation().Equals(other_details.representation())) { 9804 return false; 9805 } 9806 } 9807 return true; 9808 } 9809 9810 9811 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map, 9812 Handle<DescriptorArray> descriptors, 9813 Descriptor* descriptor, 9814 int insertion_index, 9815 TransitionFlag flag) { 9816 Handle<Name> key = descriptor->GetKey(); 9817 DCHECK(*key == descriptors->GetKey(insertion_index)); 9818 9819 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 9820 descriptors, map->NumberOfOwnDescriptors()); 9821 9822 new_descriptors->Replace(insertion_index, descriptor); 9823 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New( 9824 map, new_descriptors, new_descriptors->number_of_descriptors()); 9825 9826 SimpleTransitionFlag simple_flag = 9827 (insertion_index == descriptors->number_of_descriptors() - 1) 9828 ? SIMPLE_PROPERTY_TRANSITION 9829 : PROPERTY_TRANSITION; 9830 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9831 flag, key, "CopyReplaceDescriptor", 9832 simple_flag); 9833 } 9834 9835 // Helper class to manage a Map's code cache. The layout depends on the number 9836 // of entries; this is worthwhile because most code caches are very small, 9837 // but some are huge (thousands of entries). 9838 // For zero entries, the EmptyFixedArray is used. 9839 // For one entry, we use a 2-element FixedArray containing [name, code]. 9840 // For 2..100 entries, we use a FixedArray with linear lookups, the layout is: 9841 // [0] - number of slots that are currently in use 9842 // [1] - first name 9843 // [2] - first code 9844 // [3] - second name 9845 // [4] - second code 9846 // etc. 9847 // For more than 128 entries, we use a CodeCacheHashTable. 9848 class CodeCache : public AllStatic { 9849 public: 9850 // Returns the new cache, to be stored on the map. 9851 static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache, 9852 Handle<Name> name, Handle<Code> code) { 9853 int length = cache->length(); 9854 if (length == 0) return PutFirstElement(isolate, name, code); 9855 if (length == kEntrySize) { 9856 return PutSecondElement(isolate, cache, name, code); 9857 } 9858 if (length <= kLinearMaxSize) { 9859 Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code); 9860 if (!result.is_null()) return result; 9861 // Fall through if linear storage is getting too large. 9862 } 9863 return PutHashTableElement(isolate, cache, name, code); 9864 } 9865 9866 static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) { 9867 int length = cache->length(); 9868 if (length == 0) return nullptr; 9869 if (length == kEntrySize) return OneElementLookup(cache, name, flags); 9870 if (!cache->IsCodeCacheHashTable()) { 9871 return LinearLookup(cache, name, flags); 9872 } else { 9873 return CodeCacheHashTable::cast(cache)->Lookup(name, flags); 9874 } 9875 } 9876 9877 private: 9878 static const int kNameIndex = 0; 9879 static const int kCodeIndex = 1; 9880 static const int kEntrySize = 2; 9881 9882 static const int kLinearUsageIndex = 0; 9883 static const int kLinearReservedSlots = 1; 9884 static const int kLinearInitialCapacity = 2; 9885 static const int kLinearMaxSize = 257; // == LinearSizeFor(128); 9886 9887 static const int kHashTableInitialCapacity = 200; // Number of entries. 9888 9889 static int LinearSizeFor(int entries) { 9890 return kLinearReservedSlots + kEntrySize * entries; 9891 } 9892 9893 static int LinearNewSize(int old_size) { 9894 int old_entries = (old_size - kLinearReservedSlots) / kEntrySize; 9895 return LinearSizeFor(old_entries * 2); 9896 } 9897 9898 static Code* OneElementLookup(FixedArray* cache, Name* name, 9899 Code::Flags flags) { 9900 DCHECK_EQ(cache->length(), kEntrySize); 9901 if (cache->get(kNameIndex) != name) return nullptr; 9902 Code* maybe_code = Code::cast(cache->get(kCodeIndex)); 9903 if (maybe_code->flags() != flags) return nullptr; 9904 return maybe_code; 9905 } 9906 9907 static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) { 9908 DCHECK_GE(cache->length(), kEntrySize); 9909 DCHECK(!cache->IsCodeCacheHashTable()); 9910 int usage = GetLinearUsage(cache); 9911 for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) { 9912 if (cache->get(i + kNameIndex) != name) continue; 9913 Code* code = Code::cast(cache->get(i + kCodeIndex)); 9914 if (code->flags() == flags) return code; 9915 } 9916 return nullptr; 9917 } 9918 9919 static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name, 9920 Handle<Code> code) { 9921 Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize); 9922 cache->set(kNameIndex, *name); 9923 cache->set(kCodeIndex, *code); 9924 return cache; 9925 } 9926 9927 static Handle<FixedArray> PutSecondElement(Isolate* isolate, 9928 Handle<FixedArray> cache, 9929 Handle<Name> name, 9930 Handle<Code> code) { 9931 DCHECK_EQ(cache->length(), kEntrySize); 9932 Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray( 9933 LinearSizeFor(kLinearInitialCapacity)); 9934 new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex)); 9935 new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex)); 9936 new_cache->set(LinearSizeFor(1) + kNameIndex, *name); 9937 new_cache->set(LinearSizeFor(1) + kCodeIndex, *code); 9938 new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2))); 9939 return new_cache; 9940 } 9941 9942 static Handle<FixedArray> PutLinearElement(Isolate* isolate, 9943 Handle<FixedArray> cache, 9944 Handle<Name> name, 9945 Handle<Code> code) { 9946 int length = cache->length(); 9947 int usage = GetLinearUsage(*cache); 9948 DCHECK_LE(usage, length); 9949 // Check if we need to grow. 9950 if (usage == length) { 9951 int new_length = LinearNewSize(length); 9952 if (new_length > kLinearMaxSize) return Handle<FixedArray>::null(); 9953 Handle<FixedArray> new_cache = 9954 isolate->factory()->NewFixedArray(new_length); 9955 for (int i = kLinearReservedSlots; i < length; i++) { 9956 new_cache->set(i, cache->get(i)); 9957 } 9958 cache = new_cache; 9959 } 9960 // Store new entry. 9961 DCHECK_GE(cache->length(), usage + kEntrySize); 9962 cache->set(usage + kNameIndex, *name); 9963 cache->set(usage + kCodeIndex, *code); 9964 cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize)); 9965 return cache; 9966 } 9967 9968 static Handle<FixedArray> PutHashTableElement(Isolate* isolate, 9969 Handle<FixedArray> cache, 9970 Handle<Name> name, 9971 Handle<Code> code) { 9972 // Check if we need to transition from linear to hash table storage. 9973 if (!cache->IsCodeCacheHashTable()) { 9974 // Check that the initial hash table capacity is large enough. 9975 DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128)); 9976 STATIC_ASSERT(kHashTableInitialCapacity > 128); 9977 9978 int length = cache->length(); 9979 // Only migrate from linear storage when it's full. 9980 DCHECK_EQ(length, GetLinearUsage(*cache)); 9981 DCHECK_EQ(length, kLinearMaxSize); 9982 Handle<CodeCacheHashTable> table = 9983 CodeCacheHashTable::New(isolate, kHashTableInitialCapacity); 9984 HandleScope scope(isolate); 9985 for (int i = kLinearReservedSlots; i < length; i += kEntrySize) { 9986 Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate); 9987 Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate); 9988 CodeCacheHashTable::Put(table, old_name, old_code); 9989 } 9990 cache = table; 9991 } 9992 // Store new entry. 9993 DCHECK(cache->IsCodeCacheHashTable()); 9994 return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache), 9995 name, code); 9996 } 9997 9998 static inline int GetLinearUsage(FixedArray* linear_cache) { 9999 DCHECK_GT(linear_cache->length(), kEntrySize); 10000 return Smi::cast(linear_cache->get(kLinearUsageIndex))->value(); 10001 } 10002 }; 10003 10004 void Map::UpdateCodeCache(Handle<Map> map, 10005 Handle<Name> name, 10006 Handle<Code> code) { 10007 Isolate* isolate = map->GetIsolate(); 10008 Handle<FixedArray> cache(map->code_cache(), isolate); 10009 Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code); 10010 map->set_code_cache(*new_cache); 10011 } 10012 10013 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) { 10014 return CodeCache::Lookup(code_cache(), name, flags); 10015 } 10016 10017 10018 // The key in the code cache hash table consists of the property name and the 10019 // code object. The actual match is on the name and the code flags. If a key 10020 // is created using the flags and not a code object it can only be used for 10021 // lookup not to create a new entry. 10022 class CodeCacheHashTableKey : public HashTableKey { 10023 public: 10024 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags) 10025 : name_(name), flags_(flags), code_() { 10026 DCHECK(name_->IsUniqueName()); 10027 } 10028 10029 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code) 10030 : name_(name), flags_(code->flags()), code_(code) { 10031 DCHECK(name_->IsUniqueName()); 10032 } 10033 10034 bool IsMatch(Object* other) override { 10035 DCHECK(other->IsFixedArray()); 10036 FixedArray* pair = FixedArray::cast(other); 10037 Name* name = Name::cast(pair->get(0)); 10038 Code::Flags flags = Code::cast(pair->get(1))->flags(); 10039 if (flags != flags_) return false; 10040 DCHECK(name->IsUniqueName()); 10041 return *name_ == name; 10042 } 10043 10044 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) { 10045 return name->Hash() ^ flags; 10046 } 10047 10048 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); } 10049 10050 uint32_t HashForObject(Object* obj) override { 10051 FixedArray* pair = FixedArray::cast(obj); 10052 Name* name = Name::cast(pair->get(0)); 10053 Code* code = Code::cast(pair->get(1)); 10054 return NameFlagsHashHelper(name, code->flags()); 10055 } 10056 10057 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override { 10058 Handle<Code> code = code_.ToHandleChecked(); 10059 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2); 10060 pair->set(0, *name_); 10061 pair->set(1, *code); 10062 return pair; 10063 } 10064 10065 private: 10066 Handle<Name> name_; 10067 Code::Flags flags_; 10068 // TODO(jkummerow): We should be able to get by without this. 10069 MaybeHandle<Code> code_; 10070 }; 10071 10072 10073 Handle<CodeCacheHashTable> CodeCacheHashTable::Put( 10074 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) { 10075 CodeCacheHashTableKey key(name, code); 10076 10077 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key); 10078 10079 int entry = new_cache->FindInsertionEntry(key.Hash()); 10080 Handle<Object> k = key.AsHandle(cache->GetIsolate()); 10081 10082 new_cache->set(EntryToIndex(entry), *k); 10083 new_cache->ElementAdded(); 10084 return new_cache; 10085 } 10086 10087 Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) { 10088 DisallowHeapAllocation no_alloc; 10089 CodeCacheHashTableKey key(handle(name), flags); 10090 int entry = FindEntry(&key); 10091 if (entry == kNotFound) return nullptr; 10092 return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1)); 10093 } 10094 10095 Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index, 10096 Handle<Object> value) { 10097 if (index < array->length()) { 10098 array->set(index, *value); 10099 return array; 10100 } 10101 int capacity = array->length(); 10102 do { 10103 capacity = JSObject::NewElementsCapacity(capacity); 10104 } while (capacity <= index); 10105 Handle<FixedArray> new_array = 10106 array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity); 10107 array->CopyTo(0, *new_array, 0, array->length()); 10108 new_array->FillWithHoles(array->length(), new_array->length()); 10109 new_array->set(index, *value); 10110 return new_array; 10111 } 10112 10113 void FixedArray::Shrink(int new_length) { 10114 DCHECK(0 <= new_length && new_length <= length()); 10115 if (new_length < length()) { 10116 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( 10117 this, length() - new_length); 10118 } 10119 } 10120 10121 10122 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) { 10123 DisallowHeapAllocation no_gc; 10124 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc); 10125 for (int index = 0; index < len; index++) { 10126 dest->set(dest_pos+index, get(pos+index), mode); 10127 } 10128 } 10129 10130 10131 #ifdef DEBUG 10132 bool FixedArray::IsEqualTo(FixedArray* other) { 10133 if (length() != other->length()) return false; 10134 for (int i = 0 ; i < length(); ++i) { 10135 if (get(i) != other->get(i)) return false; 10136 } 10137 return true; 10138 } 10139 #endif 10140 10141 10142 // static 10143 void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index, 10144 Handle<HeapObject> value) { 10145 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything. 10146 Handle<WeakCell> cell = 10147 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value)) 10148 : array->GetIsolate()->factory()->NewWeakCell(value); 10149 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell); 10150 if (FLAG_trace_weak_arrays) { 10151 PrintF("[WeakFixedArray: storing at index %d ]\n", index); 10152 } 10153 array->set_last_used_index(index); 10154 } 10155 10156 10157 // static 10158 Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array, 10159 Handle<HeapObject> value, 10160 int* assigned_index) { 10161 Handle<WeakFixedArray> array = 10162 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) 10163 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) 10164 : Handle<WeakFixedArray>::cast(maybe_array); 10165 // Try to store the new entry if there's room. Optimize for consecutive 10166 // accesses. 10167 int first_index = array->last_used_index(); 10168 int length = array->Length(); 10169 if (length > 0) { 10170 for (int i = first_index;;) { 10171 if (array->IsEmptySlot((i))) { 10172 WeakFixedArray::Set(array, i, value); 10173 if (assigned_index != NULL) *assigned_index = i; 10174 return array; 10175 } 10176 if (FLAG_trace_weak_arrays) { 10177 PrintF("[WeakFixedArray: searching for free slot]\n"); 10178 } 10179 i = (i + 1) % length; 10180 if (i == first_index) break; 10181 } 10182 } 10183 10184 // No usable slot found, grow the array. 10185 int new_length = length == 0 ? 1 : length + (length >> 1) + 4; 10186 Handle<WeakFixedArray> new_array = 10187 Allocate(array->GetIsolate(), new_length, array); 10188 if (FLAG_trace_weak_arrays) { 10189 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length); 10190 } 10191 WeakFixedArray::Set(new_array, length, value); 10192 if (assigned_index != NULL) *assigned_index = length; 10193 return new_array; 10194 } 10195 10196 10197 template <class CompactionCallback> 10198 void WeakFixedArray::Compact() { 10199 FixedArray* array = FixedArray::cast(this); 10200 int new_length = kFirstIndex; 10201 for (int i = kFirstIndex; i < array->length(); i++) { 10202 Object* element = array->get(i); 10203 if (element->IsSmi()) continue; 10204 if (WeakCell::cast(element)->cleared()) continue; 10205 Object* value = WeakCell::cast(element)->value(); 10206 CompactionCallback::Callback(value, i - kFirstIndex, 10207 new_length - kFirstIndex); 10208 array->set(new_length++, element); 10209 } 10210 array->Shrink(new_length); 10211 set_last_used_index(0); 10212 } 10213 10214 10215 void WeakFixedArray::Iterator::Reset(Object* maybe_array) { 10216 if (maybe_array->IsWeakFixedArray()) { 10217 list_ = WeakFixedArray::cast(maybe_array); 10218 index_ = 0; 10219 #ifdef DEBUG 10220 last_used_index_ = list_->last_used_index(); 10221 #endif // DEBUG 10222 } 10223 } 10224 10225 10226 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value, 10227 int old_index, 10228 int new_index) { 10229 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map()); 10230 Map* map = Map::cast(value); 10231 DCHECK(map->prototype_info()->IsPrototypeInfo()); 10232 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info()); 10233 DCHECK_EQ(old_index, proto_info->registry_slot()); 10234 proto_info->set_registry_slot(new_index); 10235 } 10236 10237 10238 template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>(); 10239 template void 10240 WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>(); 10241 10242 10243 bool WeakFixedArray::Remove(Handle<HeapObject> value) { 10244 if (Length() == 0) return false; 10245 // Optimize for the most recently added element to be removed again. 10246 int first_index = last_used_index(); 10247 for (int i = first_index;;) { 10248 if (Get(i) == *value) { 10249 Clear(i); 10250 // Users of WeakFixedArray should make sure that there are no duplicates. 10251 return true; 10252 } 10253 i = (i + 1) % Length(); 10254 if (i == first_index) return false; 10255 } 10256 UNREACHABLE(); 10257 } 10258 10259 10260 // static 10261 Handle<WeakFixedArray> WeakFixedArray::Allocate( 10262 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) { 10263 DCHECK(0 <= size); 10264 Handle<FixedArray> result = 10265 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex); 10266 int index = 0; 10267 if (!initialize_from.is_null()) { 10268 DCHECK(initialize_from->Length() <= size); 10269 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from); 10270 // Copy the entries without compacting, since the PrototypeInfo relies on 10271 // the index of the entries not to change. 10272 while (index < raw_source->length()) { 10273 result->set(index, raw_source->get(index)); 10274 index++; 10275 } 10276 } 10277 while (index < result->length()) { 10278 result->set(index, Smi::kZero); 10279 index++; 10280 } 10281 return Handle<WeakFixedArray>::cast(result); 10282 } 10283 10284 10285 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj, 10286 AddMode mode) { 10287 int length = array->Length(); 10288 array = EnsureSpace(array, length + 1); 10289 if (mode == kReloadLengthAfterAllocation) { 10290 DCHECK(array->Length() <= length); 10291 length = array->Length(); 10292 } 10293 array->Set(length, *obj); 10294 array->SetLength(length + 1); 10295 return array; 10296 } 10297 10298 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1, 10299 Handle<Object> obj2, AddMode mode) { 10300 int length = array->Length(); 10301 array = EnsureSpace(array, length + 2); 10302 if (mode == kReloadLengthAfterAllocation) { 10303 length = array->Length(); 10304 } 10305 array->Set(length, *obj1); 10306 array->Set(length + 1, *obj2); 10307 array->SetLength(length + 2); 10308 return array; 10309 } 10310 10311 10312 bool ArrayList::IsFull() { 10313 int capacity = length(); 10314 return kFirstIndex + Length() == capacity; 10315 } 10316 10317 namespace { 10318 10319 Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array, 10320 int length) { 10321 int capacity = array->length(); 10322 if (capacity < length) { 10323 Isolate* isolate = array->GetIsolate(); 10324 int new_capacity = length; 10325 new_capacity = new_capacity + Max(new_capacity / 2, 2); 10326 int grow_by = new_capacity - capacity; 10327 array = Handle<ArrayList>::cast( 10328 isolate->factory()->CopyFixedArrayAndGrow(array, grow_by)); 10329 } 10330 return array; 10331 } 10332 10333 } // namespace 10334 10335 Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) { 10336 const bool empty = (array->length() == 0); 10337 auto ret = Handle<ArrayList>::cast( 10338 EnsureSpaceInFixedArray(array, kFirstIndex + length)); 10339 if (empty) ret->SetLength(0); 10340 return ret; 10341 } 10342 10343 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures( 10344 Handle<RegExpMatchInfo> match_info, int capture_count) { 10345 DCHECK_GE(match_info->length(), kLastMatchOverhead); 10346 const int required_length = kFirstCaptureIndex + capture_count; 10347 Handle<FixedArray> result = 10348 EnsureSpaceInFixedArray(match_info, required_length); 10349 return Handle<RegExpMatchInfo>::cast(result); 10350 } 10351 10352 // static 10353 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in, 10354 Handle<Object> receiver, 10355 Handle<JSFunction> function, 10356 Handle<AbstractCode> code, 10357 int offset, int flags) { 10358 const int frame_count = in->FrameCount(); 10359 const int new_length = LengthFor(frame_count + 1); 10360 Handle<FrameArray> array = EnsureSpace(in, new_length); 10361 array->SetReceiver(frame_count, *receiver); 10362 array->SetFunction(frame_count, *function); 10363 array->SetCode(frame_count, *code); 10364 array->SetOffset(frame_count, Smi::FromInt(offset)); 10365 array->SetFlags(frame_count, Smi::FromInt(flags)); 10366 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1)); 10367 return array; 10368 } 10369 10370 // static 10371 Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in, 10372 Handle<Object> wasm_instance, 10373 int wasm_function_index, 10374 Handle<AbstractCode> code, 10375 int offset, int flags) { 10376 const int frame_count = in->FrameCount(); 10377 const int new_length = LengthFor(frame_count + 1); 10378 Handle<FrameArray> array = EnsureSpace(in, new_length); 10379 array->SetWasmInstance(frame_count, *wasm_instance); 10380 array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index)); 10381 array->SetCode(frame_count, *code); 10382 array->SetOffset(frame_count, Smi::FromInt(offset)); 10383 array->SetFlags(frame_count, Smi::FromInt(flags)); 10384 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1)); 10385 return array; 10386 } 10387 10388 void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); } 10389 10390 // static 10391 Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array, 10392 int length) { 10393 return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length)); 10394 } 10395 10396 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate, 10397 int number_of_descriptors, 10398 int slack, 10399 PretenureFlag pretenure) { 10400 DCHECK(0 <= number_of_descriptors); 10401 Factory* factory = isolate->factory(); 10402 // Do not use DescriptorArray::cast on incomplete object. 10403 int size = number_of_descriptors + slack; 10404 if (size == 0) return factory->empty_descriptor_array(); 10405 // Allocate the array of keys. 10406 Handle<FixedArray> result = 10407 factory->NewFixedArray(LengthFor(size), pretenure); 10408 10409 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); 10410 result->set(kEnumCacheIndex, Smi::kZero); 10411 return Handle<DescriptorArray>::cast(result); 10412 } 10413 10414 void DescriptorArray::ClearEnumCache() { set(kEnumCacheIndex, Smi::kZero); } 10415 10416 void DescriptorArray::Replace(int index, Descriptor* descriptor) { 10417 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index)); 10418 Set(index, descriptor); 10419 } 10420 10421 10422 // static 10423 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors, 10424 Isolate* isolate, 10425 Handle<FixedArray> new_cache, 10426 Handle<FixedArray> new_index_cache) { 10427 DCHECK(!descriptors->IsEmpty()); 10428 FixedArray* bridge_storage; 10429 bool needs_new_enum_cache = !descriptors->HasEnumCache(); 10430 if (needs_new_enum_cache) { 10431 bridge_storage = *isolate->factory()->NewFixedArray( 10432 DescriptorArray::kEnumCacheBridgeLength); 10433 } else { 10434 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex)); 10435 } 10436 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache); 10437 bridge_storage->set( 10438 kEnumCacheBridgeIndicesCacheIndex, 10439 new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache); 10440 if (needs_new_enum_cache) { 10441 descriptors->set(kEnumCacheIndex, bridge_storage); 10442 } 10443 } 10444 10445 10446 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) { 10447 Object* value = src->GetValue(index); 10448 PropertyDetails details = src->GetDetails(index); 10449 Descriptor desc(handle(src->GetKey(index)), 10450 handle(value, src->GetIsolate()), 10451 details); 10452 SetDescriptor(index, &desc); 10453 } 10454 10455 10456 void DescriptorArray::Sort() { 10457 // In-place heap sort. 10458 int len = number_of_descriptors(); 10459 // Reset sorting since the descriptor array might contain invalid pointers. 10460 for (int i = 0; i < len; ++i) SetSortedKey(i, i); 10461 // Bottom-up max-heap construction. 10462 // Index of the last node with children 10463 const int max_parent_index = (len / 2) - 1; 10464 for (int i = max_parent_index; i >= 0; --i) { 10465 int parent_index = i; 10466 const uint32_t parent_hash = GetSortedKey(i)->Hash(); 10467 while (parent_index <= max_parent_index) { 10468 int child_index = 2 * parent_index + 1; 10469 uint32_t child_hash = GetSortedKey(child_index)->Hash(); 10470 if (child_index + 1 < len) { 10471 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash(); 10472 if (right_child_hash > child_hash) { 10473 child_index++; 10474 child_hash = right_child_hash; 10475 } 10476 } 10477 if (child_hash <= parent_hash) break; 10478 SwapSortedKeys(parent_index, child_index); 10479 // Now element at child_index could be < its children. 10480 parent_index = child_index; // parent_hash remains correct. 10481 } 10482 } 10483 10484 // Extract elements and create sorted array. 10485 for (int i = len - 1; i > 0; --i) { 10486 // Put max element at the back of the array. 10487 SwapSortedKeys(0, i); 10488 // Shift down the new top element. 10489 int parent_index = 0; 10490 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash(); 10491 const int max_parent_index = (i / 2) - 1; 10492 while (parent_index <= max_parent_index) { 10493 int child_index = parent_index * 2 + 1; 10494 uint32_t child_hash = GetSortedKey(child_index)->Hash(); 10495 if (child_index + 1 < i) { 10496 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash(); 10497 if (right_child_hash > child_hash) { 10498 child_index++; 10499 child_hash = right_child_hash; 10500 } 10501 } 10502 if (child_hash <= parent_hash) break; 10503 SwapSortedKeys(parent_index, child_index); 10504 parent_index = child_index; 10505 } 10506 } 10507 DCHECK(IsSortedNoDuplicates()); 10508 } 10509 10510 10511 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) { 10512 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair(); 10513 copy->set_getter(pair->getter()); 10514 copy->set_setter(pair->setter()); 10515 return copy; 10516 } 10517 10518 Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair, 10519 AccessorComponent component) { 10520 Object* accessor = accessor_pair->get(component); 10521 if (accessor->IsFunctionTemplateInfo()) { 10522 return ApiNatives::InstantiateFunction( 10523 handle(FunctionTemplateInfo::cast(accessor))) 10524 .ToHandleChecked(); 10525 } 10526 Isolate* isolate = accessor_pair->GetIsolate(); 10527 if (accessor->IsNull(isolate)) { 10528 return isolate->factory()->undefined_value(); 10529 } 10530 return handle(accessor, isolate); 10531 } 10532 10533 Handle<DeoptimizationInputData> DeoptimizationInputData::New( 10534 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) { 10535 return Handle<DeoptimizationInputData>::cast( 10536 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count), 10537 pretenure)); 10538 } 10539 10540 10541 Handle<DeoptimizationOutputData> DeoptimizationOutputData::New( 10542 Isolate* isolate, 10543 int number_of_deopt_points, 10544 PretenureFlag pretenure) { 10545 Handle<FixedArray> result; 10546 if (number_of_deopt_points == 0) { 10547 result = isolate->factory()->empty_fixed_array(); 10548 } else { 10549 result = isolate->factory()->NewFixedArray( 10550 LengthOfFixedArray(number_of_deopt_points), pretenure); 10551 } 10552 return Handle<DeoptimizationOutputData>::cast(result); 10553 } 10554 10555 SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) { 10556 if (index == -1) { 10557 return SharedFunctionInfo::cast(this->SharedFunctionInfo()); 10558 } else { 10559 return SharedFunctionInfo::cast(LiteralArray()->get(index)); 10560 } 10561 } 10562 10563 const int LiteralsArray::kFeedbackVectorOffset = 10564 LiteralsArray::OffsetOfElementAt(LiteralsArray::kVectorIndex); 10565 10566 const int LiteralsArray::kOffsetToFirstLiteral = 10567 LiteralsArray::OffsetOfElementAt(LiteralsArray::kFirstLiteralIndex); 10568 10569 // static 10570 Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate, 10571 Handle<TypeFeedbackVector> vector, 10572 int number_of_literals, 10573 PretenureFlag pretenure) { 10574 if (vector->is_empty() && number_of_literals == 0) { 10575 return Handle<LiteralsArray>::cast( 10576 isolate->factory()->empty_literals_array()); 10577 } 10578 Handle<FixedArray> literals = isolate->factory()->NewFixedArray( 10579 number_of_literals + kFirstLiteralIndex, pretenure); 10580 Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals); 10581 casted_literals->set_feedback_vector(*vector); 10582 return casted_literals; 10583 } 10584 10585 int HandlerTable::LookupRange(int pc_offset, int* data_out, 10586 CatchPrediction* prediction_out) { 10587 int innermost_handler = -1; 10588 #ifdef DEBUG 10589 // Assuming that ranges are well nested, we don't need to track the innermost 10590 // offsets. This is just to verify that the table is actually well nested. 10591 int innermost_start = std::numeric_limits<int>::min(); 10592 int innermost_end = std::numeric_limits<int>::max(); 10593 #endif 10594 for (int i = 0; i < length(); i += kRangeEntrySize) { 10595 int start_offset = Smi::cast(get(i + kRangeStartIndex))->value(); 10596 int end_offset = Smi::cast(get(i + kRangeEndIndex))->value(); 10597 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value(); 10598 int handler_offset = HandlerOffsetField::decode(handler_field); 10599 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 10600 int handler_data = Smi::cast(get(i + kRangeDataIndex))->value(); 10601 if (pc_offset > start_offset && pc_offset <= end_offset) { 10602 DCHECK_GE(start_offset, innermost_start); 10603 DCHECK_LT(end_offset, innermost_end); 10604 innermost_handler = handler_offset; 10605 #ifdef DEBUG 10606 innermost_start = start_offset; 10607 innermost_end = end_offset; 10608 #endif 10609 if (data_out) *data_out = handler_data; 10610 if (prediction_out) *prediction_out = prediction; 10611 } 10612 } 10613 return innermost_handler; 10614 } 10615 10616 10617 // TODO(turbofan): Make sure table is sorted and use binary search. 10618 int HandlerTable::LookupReturn(int pc_offset) { 10619 for (int i = 0; i < length(); i += kReturnEntrySize) { 10620 int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value(); 10621 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value(); 10622 if (pc_offset == return_offset) { 10623 return HandlerOffsetField::decode(handler_field); 10624 } 10625 } 10626 return -1; 10627 } 10628 10629 10630 #ifdef DEBUG 10631 bool DescriptorArray::IsEqualTo(DescriptorArray* other) { 10632 if (IsEmpty()) return other->IsEmpty(); 10633 if (other->IsEmpty()) return false; 10634 if (length() != other->length()) return false; 10635 for (int i = 0; i < length(); ++i) { 10636 if (get(i) != other->get(i)) return false; 10637 } 10638 return true; 10639 } 10640 #endif 10641 10642 // static 10643 Handle<String> String::Trim(Handle<String> string, TrimMode mode) { 10644 Isolate* const isolate = string->GetIsolate(); 10645 string = String::Flatten(string); 10646 int const length = string->length(); 10647 10648 // Perform left trimming if requested. 10649 int left = 0; 10650 UnicodeCache* unicode_cache = isolate->unicode_cache(); 10651 if (mode == kTrim || mode == kTrimLeft) { 10652 while (left < length && 10653 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { 10654 left++; 10655 } 10656 } 10657 10658 // Perform right trimming if requested. 10659 int right = length; 10660 if (mode == kTrim || mode == kTrimRight) { 10661 while ( 10662 right > left && 10663 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { 10664 right--; 10665 } 10666 } 10667 10668 return isolate->factory()->NewSubString(string, left, right); 10669 } 10670 10671 bool String::LooksValid() { 10672 if (!GetIsolate()->heap()->Contains(this)) return false; 10673 return true; 10674 } 10675 10676 10677 // static 10678 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { 10679 if (name->IsString()) return Handle<String>::cast(name); 10680 // ES6 section 9.2.11 SetFunctionName, step 4. 10681 Isolate* const isolate = name->GetIsolate(); 10682 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); 10683 if (description->IsUndefined(isolate)) { 10684 return isolate->factory()->empty_string(); 10685 } 10686 IncrementalStringBuilder builder(isolate); 10687 builder.AppendCharacter('['); 10688 builder.AppendString(Handle<String>::cast(description)); 10689 builder.AppendCharacter(']'); 10690 return builder.Finish(); 10691 } 10692 10693 // static 10694 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name, 10695 Handle<String> prefix) { 10696 Handle<String> name_string; 10697 Isolate* const isolate = name->GetIsolate(); 10698 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name), 10699 String); 10700 IncrementalStringBuilder builder(isolate); 10701 builder.AppendString(prefix); 10702 builder.AppendCharacter(' '); 10703 builder.AppendString(name_string); 10704 return builder.Finish(); 10705 } 10706 10707 namespace { 10708 10709 bool AreDigits(const uint8_t* s, int from, int to) { 10710 for (int i = from; i < to; i++) { 10711 if (s[i] < '0' || s[i] > '9') return false; 10712 } 10713 10714 return true; 10715 } 10716 10717 10718 int ParseDecimalInteger(const uint8_t* s, int from, int to) { 10719 DCHECK(to - from < 10); // Overflow is not possible. 10720 DCHECK(from < to); 10721 int d = s[from] - '0'; 10722 10723 for (int i = from + 1; i < to; i++) { 10724 d = 10 * d + (s[i] - '0'); 10725 } 10726 10727 return d; 10728 } 10729 10730 } // namespace 10731 10732 10733 // static 10734 Handle<Object> String::ToNumber(Handle<String> subject) { 10735 Isolate* const isolate = subject->GetIsolate(); 10736 10737 // Flatten {subject} string first. 10738 subject = String::Flatten(subject); 10739 10740 // Fast array index case. 10741 uint32_t index; 10742 if (subject->AsArrayIndex(&index)) { 10743 return isolate->factory()->NewNumberFromUint(index); 10744 } 10745 10746 // Fast case: short integer or some sorts of junk values. 10747 if (subject->IsSeqOneByteString()) { 10748 int len = subject->length(); 10749 if (len == 0) return handle(Smi::kZero, isolate); 10750 10751 DisallowHeapAllocation no_gc; 10752 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars(); 10753 bool minus = (data[0] == '-'); 10754 int start_pos = (minus ? 1 : 0); 10755 10756 if (start_pos == len) { 10757 return isolate->factory()->nan_value(); 10758 } else if (data[start_pos] > '9') { 10759 // Fast check for a junk value. A valid string may start from a 10760 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit 10761 // or the 'I' character ('Infinity'). All of that have codes not greater 10762 // than '9' except 'I' and . 10763 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { 10764 return isolate->factory()->nan_value(); 10765 } 10766 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 10767 // The maximal/minimal smi has 10 digits. If the string has less digits 10768 // we know it will fit into the smi-data type. 10769 int d = ParseDecimalInteger(data, start_pos, len); 10770 if (minus) { 10771 if (d == 0) return isolate->factory()->minus_zero_value(); 10772 d = -d; 10773 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize && 10774 (len == 1 || data[0] != '0')) { 10775 // String hash is not calculated yet but all the data are present. 10776 // Update the hash field to speed up sequential convertions. 10777 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); 10778 #ifdef DEBUG 10779 subject->Hash(); // Force hash calculation. 10780 DCHECK_EQ(static_cast<int>(subject->hash_field()), 10781 static_cast<int>(hash)); 10782 #endif 10783 subject->set_hash_field(hash); 10784 } 10785 return handle(Smi::FromInt(d), isolate); 10786 } 10787 } 10788 10789 // Slower case. 10790 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY; 10791 return isolate->factory()->NewNumber( 10792 StringToDouble(isolate->unicode_cache(), subject, flags)); 10793 } 10794 10795 10796 String::FlatContent String::GetFlatContent() { 10797 DCHECK(!AllowHeapAllocation::IsAllowed()); 10798 int length = this->length(); 10799 StringShape shape(this); 10800 String* string = this; 10801 int offset = 0; 10802 if (shape.representation_tag() == kConsStringTag) { 10803 ConsString* cons = ConsString::cast(string); 10804 if (cons->second()->length() != 0) { 10805 return FlatContent(); 10806 } 10807 string = cons->first(); 10808 shape = StringShape(string); 10809 } 10810 if (shape.representation_tag() == kSlicedStringTag) { 10811 SlicedString* slice = SlicedString::cast(string); 10812 offset = slice->offset(); 10813 string = slice->parent(); 10814 shape = StringShape(string); 10815 DCHECK(shape.representation_tag() != kConsStringTag && 10816 shape.representation_tag() != kSlicedStringTag); 10817 } 10818 if (shape.encoding_tag() == kOneByteStringTag) { 10819 const uint8_t* start; 10820 if (shape.representation_tag() == kSeqStringTag) { 10821 start = SeqOneByteString::cast(string)->GetChars(); 10822 } else { 10823 start = ExternalOneByteString::cast(string)->GetChars(); 10824 } 10825 return FlatContent(start + offset, length); 10826 } else { 10827 DCHECK(shape.encoding_tag() == kTwoByteStringTag); 10828 const uc16* start; 10829 if (shape.representation_tag() == kSeqStringTag) { 10830 start = SeqTwoByteString::cast(string)->GetChars(); 10831 } else { 10832 start = ExternalTwoByteString::cast(string)->GetChars(); 10833 } 10834 return FlatContent(start + offset, length); 10835 } 10836 } 10837 10838 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls, 10839 RobustnessFlag robust_flag, 10840 int offset, int length, 10841 int* length_return) { 10842 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { 10843 return std::unique_ptr<char[]>(); 10844 } 10845 // Negative length means the to the end of the string. 10846 if (length < 0) length = kMaxInt - offset; 10847 10848 // Compute the size of the UTF-8 string. Start at the specified offset. 10849 StringCharacterStream stream(this, offset); 10850 int character_position = offset; 10851 int utf8_bytes = 0; 10852 int last = unibrow::Utf16::kNoPreviousCharacter; 10853 while (stream.HasMore() && character_position++ < offset + length) { 10854 uint16_t character = stream.GetNext(); 10855 utf8_bytes += unibrow::Utf8::Length(character, last); 10856 last = character; 10857 } 10858 10859 if (length_return) { 10860 *length_return = utf8_bytes; 10861 } 10862 10863 char* result = NewArray<char>(utf8_bytes + 1); 10864 10865 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset. 10866 stream.Reset(this, offset); 10867 character_position = offset; 10868 int utf8_byte_position = 0; 10869 last = unibrow::Utf16::kNoPreviousCharacter; 10870 while (stream.HasMore() && character_position++ < offset + length) { 10871 uint16_t character = stream.GetNext(); 10872 if (allow_nulls == DISALLOW_NULLS && character == 0) { 10873 character = ' '; 10874 } 10875 utf8_byte_position += 10876 unibrow::Utf8::Encode(result + utf8_byte_position, character, last); 10877 last = character; 10878 } 10879 result[utf8_byte_position] = 0; 10880 return std::unique_ptr<char[]>(result); 10881 } 10882 10883 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls, 10884 RobustnessFlag robust_flag, 10885 int* length_return) { 10886 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); 10887 } 10888 10889 10890 const uc16* String::GetTwoByteData(unsigned start) { 10891 DCHECK(!IsOneByteRepresentationUnderneath()); 10892 switch (StringShape(this).representation_tag()) { 10893 case kSeqStringTag: 10894 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); 10895 case kExternalStringTag: 10896 return ExternalTwoByteString::cast(this)-> 10897 ExternalTwoByteStringGetData(start); 10898 case kSlicedStringTag: { 10899 SlicedString* slice = SlicedString::cast(this); 10900 return slice->parent()->GetTwoByteData(start + slice->offset()); 10901 } 10902 case kConsStringTag: 10903 UNREACHABLE(); 10904 return NULL; 10905 } 10906 UNREACHABLE(); 10907 return NULL; 10908 } 10909 10910 10911 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { 10912 return reinterpret_cast<uc16*>( 10913 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start; 10914 } 10915 10916 10917 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) { 10918 Relocatable* current = isolate->relocatable_top(); 10919 while (current != NULL) { 10920 current->PostGarbageCollection(); 10921 current = current->prev_; 10922 } 10923 } 10924 10925 10926 // Reserve space for statics needing saving and restoring. 10927 int Relocatable::ArchiveSpacePerThread() { 10928 return sizeof(Relocatable*); // NOLINT 10929 } 10930 10931 10932 // Archive statics that are thread-local. 10933 char* Relocatable::ArchiveState(Isolate* isolate, char* to) { 10934 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top(); 10935 isolate->set_relocatable_top(NULL); 10936 return to + ArchiveSpacePerThread(); 10937 } 10938 10939 10940 // Restore statics that are thread-local. 10941 char* Relocatable::RestoreState(Isolate* isolate, char* from) { 10942 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from)); 10943 return from + ArchiveSpacePerThread(); 10944 } 10945 10946 10947 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) { 10948 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage); 10949 Iterate(v, top); 10950 return thread_storage + ArchiveSpacePerThread(); 10951 } 10952 10953 10954 void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) { 10955 Iterate(v, isolate->relocatable_top()); 10956 } 10957 10958 10959 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) { 10960 Relocatable* current = top; 10961 while (current != NULL) { 10962 current->IterateInstance(v); 10963 current = current->prev_; 10964 } 10965 } 10966 10967 10968 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str) 10969 : Relocatable(isolate), 10970 str_(str.location()), 10971 length_(str->length()) { 10972 PostGarbageCollection(); 10973 } 10974 10975 10976 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input) 10977 : Relocatable(isolate), 10978 str_(0), 10979 is_one_byte_(true), 10980 length_(input.length()), 10981 start_(input.start()) {} 10982 10983 10984 void FlatStringReader::PostGarbageCollection() { 10985 if (str_ == NULL) return; 10986 Handle<String> str(str_); 10987 DCHECK(str->IsFlat()); 10988 DisallowHeapAllocation no_gc; 10989 // This does not actually prevent the vector from being relocated later. 10990 String::FlatContent content = str->GetFlatContent(); 10991 DCHECK(content.IsFlat()); 10992 is_one_byte_ = content.IsOneByte(); 10993 if (is_one_byte_) { 10994 start_ = content.ToOneByteVector().start(); 10995 } else { 10996 start_ = content.ToUC16Vector().start(); 10997 } 10998 } 10999 11000 11001 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) { 11002 DCHECK(cons_string != NULL); 11003 root_ = cons_string; 11004 consumed_ = offset; 11005 // Force stack blown condition to trigger restart. 11006 depth_ = 1; 11007 maximum_depth_ = kStackSize + depth_; 11008 DCHECK(StackBlown()); 11009 } 11010 11011 11012 String* ConsStringIterator::Continue(int* offset_out) { 11013 DCHECK(depth_ != 0); 11014 DCHECK_EQ(0, *offset_out); 11015 bool blew_stack = StackBlown(); 11016 String* string = NULL; 11017 // Get the next leaf if there is one. 11018 if (!blew_stack) string = NextLeaf(&blew_stack); 11019 // Restart search from root. 11020 if (blew_stack) { 11021 DCHECK(string == NULL); 11022 string = Search(offset_out); 11023 } 11024 // Ensure future calls return null immediately. 11025 if (string == NULL) Reset(NULL); 11026 return string; 11027 } 11028 11029 11030 String* ConsStringIterator::Search(int* offset_out) { 11031 ConsString* cons_string = root_; 11032 // Reset the stack, pushing the root string. 11033 depth_ = 1; 11034 maximum_depth_ = 1; 11035 frames_[0] = cons_string; 11036 const int consumed = consumed_; 11037 int offset = 0; 11038 while (true) { 11039 // Loop until the string is found which contains the target offset. 11040 String* string = cons_string->first(); 11041 int length = string->length(); 11042 int32_t type; 11043 if (consumed < offset + length) { 11044 // Target offset is in the left branch. 11045 // Keep going if we're still in a ConString. 11046 type = string->map()->instance_type(); 11047 if ((type & kStringRepresentationMask) == kConsStringTag) { 11048 cons_string = ConsString::cast(string); 11049 PushLeft(cons_string); 11050 continue; 11051 } 11052 // Tell the stack we're done descending. 11053 AdjustMaximumDepth(); 11054 } else { 11055 // Descend right. 11056 // Update progress through the string. 11057 offset += length; 11058 // Keep going if we're still in a ConString. 11059 string = cons_string->second(); 11060 type = string->map()->instance_type(); 11061 if ((type & kStringRepresentationMask) == kConsStringTag) { 11062 cons_string = ConsString::cast(string); 11063 PushRight(cons_string); 11064 continue; 11065 } 11066 // Need this to be updated for the current string. 11067 length = string->length(); 11068 // Account for the possibility of an empty right leaf. 11069 // This happens only if we have asked for an offset outside the string. 11070 if (length == 0) { 11071 // Reset so future operations will return null immediately. 11072 Reset(NULL); 11073 return NULL; 11074 } 11075 // Tell the stack we're done descending. 11076 AdjustMaximumDepth(); 11077 // Pop stack so next iteration is in correct place. 11078 Pop(); 11079 } 11080 DCHECK(length != 0); 11081 // Adjust return values and exit. 11082 consumed_ = offset + length; 11083 *offset_out = consumed - offset; 11084 return string; 11085 } 11086 UNREACHABLE(); 11087 return NULL; 11088 } 11089 11090 11091 String* ConsStringIterator::NextLeaf(bool* blew_stack) { 11092 while (true) { 11093 // Tree traversal complete. 11094 if (depth_ == 0) { 11095 *blew_stack = false; 11096 return NULL; 11097 } 11098 // We've lost track of higher nodes. 11099 if (StackBlown()) { 11100 *blew_stack = true; 11101 return NULL; 11102 } 11103 // Go right. 11104 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)]; 11105 String* string = cons_string->second(); 11106 int32_t type = string->map()->instance_type(); 11107 if ((type & kStringRepresentationMask) != kConsStringTag) { 11108 // Pop stack so next iteration is in correct place. 11109 Pop(); 11110 int length = string->length(); 11111 // Could be a flattened ConsString. 11112 if (length == 0) continue; 11113 consumed_ += length; 11114 return string; 11115 } 11116 cons_string = ConsString::cast(string); 11117 PushRight(cons_string); 11118 // Need to traverse all the way left. 11119 while (true) { 11120 // Continue left. 11121 string = cons_string->first(); 11122 type = string->map()->instance_type(); 11123 if ((type & kStringRepresentationMask) != kConsStringTag) { 11124 AdjustMaximumDepth(); 11125 int length = string->length(); 11126 if (length == 0) break; // Skip empty left-hand sides of ConsStrings. 11127 consumed_ += length; 11128 return string; 11129 } 11130 cons_string = ConsString::cast(string); 11131 PushLeft(cons_string); 11132 } 11133 } 11134 UNREACHABLE(); 11135 return NULL; 11136 } 11137 11138 11139 uint16_t ConsString::ConsStringGet(int index) { 11140 DCHECK(index >= 0 && index < this->length()); 11141 11142 // Check for a flattened cons string 11143 if (second()->length() == 0) { 11144 String* left = first(); 11145 return left->Get(index); 11146 } 11147 11148 String* string = String::cast(this); 11149 11150 while (true) { 11151 if (StringShape(string).IsCons()) { 11152 ConsString* cons_string = ConsString::cast(string); 11153 String* left = cons_string->first(); 11154 if (left->length() > index) { 11155 string = left; 11156 } else { 11157 index -= left->length(); 11158 string = cons_string->second(); 11159 } 11160 } else { 11161 return string->Get(index); 11162 } 11163 } 11164 11165 UNREACHABLE(); 11166 return 0; 11167 } 11168 11169 11170 uint16_t SlicedString::SlicedStringGet(int index) { 11171 return parent()->Get(offset() + index); 11172 } 11173 11174 11175 template <typename sinkchar> 11176 void String::WriteToFlat(String* src, 11177 sinkchar* sink, 11178 int f, 11179 int t) { 11180 String* source = src; 11181 int from = f; 11182 int to = t; 11183 while (true) { 11184 DCHECK(0 <= from && from <= to && to <= source->length()); 11185 switch (StringShape(source).full_representation_tag()) { 11186 case kOneByteStringTag | kExternalStringTag: { 11187 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from, 11188 to - from); 11189 return; 11190 } 11191 case kTwoByteStringTag | kExternalStringTag: { 11192 const uc16* data = 11193 ExternalTwoByteString::cast(source)->GetChars(); 11194 CopyChars(sink, 11195 data + from, 11196 to - from); 11197 return; 11198 } 11199 case kOneByteStringTag | kSeqStringTag: { 11200 CopyChars(sink, 11201 SeqOneByteString::cast(source)->GetChars() + from, 11202 to - from); 11203 return; 11204 } 11205 case kTwoByteStringTag | kSeqStringTag: { 11206 CopyChars(sink, 11207 SeqTwoByteString::cast(source)->GetChars() + from, 11208 to - from); 11209 return; 11210 } 11211 case kOneByteStringTag | kConsStringTag: 11212 case kTwoByteStringTag | kConsStringTag: { 11213 ConsString* cons_string = ConsString::cast(source); 11214 String* first = cons_string->first(); 11215 int boundary = first->length(); 11216 if (to - boundary >= boundary - from) { 11217 // Right hand side is longer. Recurse over left. 11218 if (from < boundary) { 11219 WriteToFlat(first, sink, from, boundary); 11220 if (from == 0 && cons_string->second() == first) { 11221 CopyChars(sink + boundary, sink, boundary); 11222 return; 11223 } 11224 sink += boundary - from; 11225 from = 0; 11226 } else { 11227 from -= boundary; 11228 } 11229 to -= boundary; 11230 source = cons_string->second(); 11231 } else { 11232 // Left hand side is longer. Recurse over right. 11233 if (to > boundary) { 11234 String* second = cons_string->second(); 11235 // When repeatedly appending to a string, we get a cons string that 11236 // is unbalanced to the left, a list, essentially. We inline the 11237 // common case of sequential one-byte right child. 11238 if (to - boundary == 1) { 11239 sink[boundary - from] = static_cast<sinkchar>(second->Get(0)); 11240 } else if (second->IsSeqOneByteString()) { 11241 CopyChars(sink + boundary - from, 11242 SeqOneByteString::cast(second)->GetChars(), 11243 to - boundary); 11244 } else { 11245 WriteToFlat(second, 11246 sink + boundary - from, 11247 0, 11248 to - boundary); 11249 } 11250 to = boundary; 11251 } 11252 source = first; 11253 } 11254 break; 11255 } 11256 case kOneByteStringTag | kSlicedStringTag: 11257 case kTwoByteStringTag | kSlicedStringTag: { 11258 SlicedString* slice = SlicedString::cast(source); 11259 unsigned offset = slice->offset(); 11260 WriteToFlat(slice->parent(), sink, from + offset, to + offset); 11261 return; 11262 } 11263 } 11264 } 11265 } 11266 11267 11268 11269 template <typename SourceChar> 11270 static void CalculateLineEndsImpl(Isolate* isolate, 11271 List<int>* line_ends, 11272 Vector<const SourceChar> src, 11273 bool include_ending_line) { 11274 const int src_len = src.length(); 11275 UnicodeCache* cache = isolate->unicode_cache(); 11276 for (int i = 0; i < src_len - 1; i++) { 11277 SourceChar current = src[i]; 11278 SourceChar next = src[i + 1]; 11279 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i); 11280 } 11281 11282 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) { 11283 line_ends->Add(src_len - 1); 11284 } 11285 if (include_ending_line) { 11286 // Include one character beyond the end of script. The rewriter uses that 11287 // position for the implicit return statement. 11288 line_ends->Add(src_len); 11289 } 11290 } 11291 11292 11293 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src, 11294 bool include_ending_line) { 11295 src = Flatten(src); 11296 // Rough estimate of line count based on a roughly estimated average 11297 // length of (unpacked) code. 11298 int line_count_estimate = src->length() >> 4; 11299 List<int> line_ends(line_count_estimate); 11300 Isolate* isolate = src->GetIsolate(); 11301 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid. 11302 // Dispatch on type of strings. 11303 String::FlatContent content = src->GetFlatContent(); 11304 DCHECK(content.IsFlat()); 11305 if (content.IsOneByte()) { 11306 CalculateLineEndsImpl(isolate, 11307 &line_ends, 11308 content.ToOneByteVector(), 11309 include_ending_line); 11310 } else { 11311 CalculateLineEndsImpl(isolate, 11312 &line_ends, 11313 content.ToUC16Vector(), 11314 include_ending_line); 11315 } 11316 } 11317 int line_count = line_ends.length(); 11318 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count); 11319 for (int i = 0; i < line_count; i++) { 11320 array->set(i, Smi::FromInt(line_ends[i])); 11321 } 11322 return array; 11323 } 11324 11325 11326 // Compares the contents of two strings by reading and comparing 11327 // int-sized blocks of characters. 11328 template <typename Char> 11329 static inline bool CompareRawStringContents(const Char* const a, 11330 const Char* const b, 11331 int length) { 11332 return CompareChars(a, b, length) == 0; 11333 } 11334 11335 11336 template<typename Chars1, typename Chars2> 11337 class RawStringComparator : public AllStatic { 11338 public: 11339 static inline bool compare(const Chars1* a, const Chars2* b, int len) { 11340 DCHECK(sizeof(Chars1) != sizeof(Chars2)); 11341 for (int i = 0; i < len; i++) { 11342 if (a[i] != b[i]) { 11343 return false; 11344 } 11345 } 11346 return true; 11347 } 11348 }; 11349 11350 11351 template<> 11352 class RawStringComparator<uint16_t, uint16_t> { 11353 public: 11354 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) { 11355 return CompareRawStringContents(a, b, len); 11356 } 11357 }; 11358 11359 11360 template<> 11361 class RawStringComparator<uint8_t, uint8_t> { 11362 public: 11363 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) { 11364 return CompareRawStringContents(a, b, len); 11365 } 11366 }; 11367 11368 11369 class StringComparator { 11370 class State { 11371 public: 11372 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {} 11373 11374 void Init(String* string) { 11375 ConsString* cons_string = String::VisitFlat(this, string); 11376 iter_.Reset(cons_string); 11377 if (cons_string != NULL) { 11378 int offset; 11379 string = iter_.Next(&offset); 11380 String::VisitFlat(this, string, offset); 11381 } 11382 } 11383 11384 inline void VisitOneByteString(const uint8_t* chars, int length) { 11385 is_one_byte_ = true; 11386 buffer8_ = chars; 11387 length_ = length; 11388 } 11389 11390 inline void VisitTwoByteString(const uint16_t* chars, int length) { 11391 is_one_byte_ = false; 11392 buffer16_ = chars; 11393 length_ = length; 11394 } 11395 11396 void Advance(int consumed) { 11397 DCHECK(consumed <= length_); 11398 // Still in buffer. 11399 if (length_ != consumed) { 11400 if (is_one_byte_) { 11401 buffer8_ += consumed; 11402 } else { 11403 buffer16_ += consumed; 11404 } 11405 length_ -= consumed; 11406 return; 11407 } 11408 // Advance state. 11409 int offset; 11410 String* next = iter_.Next(&offset); 11411 DCHECK_EQ(0, offset); 11412 DCHECK(next != NULL); 11413 String::VisitFlat(this, next); 11414 } 11415 11416 ConsStringIterator iter_; 11417 bool is_one_byte_; 11418 int length_; 11419 union { 11420 const uint8_t* buffer8_; 11421 const uint16_t* buffer16_; 11422 }; 11423 11424 private: 11425 DISALLOW_COPY_AND_ASSIGN(State); 11426 }; 11427 11428 public: 11429 inline StringComparator() {} 11430 11431 template<typename Chars1, typename Chars2> 11432 static inline bool Equals(State* state_1, State* state_2, int to_check) { 11433 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_); 11434 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_); 11435 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check); 11436 } 11437 11438 bool Equals(String* string_1, String* string_2) { 11439 int length = string_1->length(); 11440 state_1_.Init(string_1); 11441 state_2_.Init(string_2); 11442 while (true) { 11443 int to_check = Min(state_1_.length_, state_2_.length_); 11444 DCHECK(to_check > 0 && to_check <= length); 11445 bool is_equal; 11446 if (state_1_.is_one_byte_) { 11447 if (state_2_.is_one_byte_) { 11448 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check); 11449 } else { 11450 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check); 11451 } 11452 } else { 11453 if (state_2_.is_one_byte_) { 11454 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check); 11455 } else { 11456 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check); 11457 } 11458 } 11459 // Looping done. 11460 if (!is_equal) return false; 11461 length -= to_check; 11462 // Exit condition. Strings are equal. 11463 if (length == 0) return true; 11464 state_1_.Advance(to_check); 11465 state_2_.Advance(to_check); 11466 } 11467 } 11468 11469 private: 11470 State state_1_; 11471 State state_2_; 11472 11473 DISALLOW_COPY_AND_ASSIGN(StringComparator); 11474 }; 11475 11476 11477 bool String::SlowEquals(String* other) { 11478 DisallowHeapAllocation no_gc; 11479 // Fast check: negative check with lengths. 11480 int len = length(); 11481 if (len != other->length()) return false; 11482 if (len == 0) return true; 11483 11484 // Fast check: if hash code is computed for both strings 11485 // a fast negative check can be performed. 11486 if (HasHashCode() && other->HasHashCode()) { 11487 #ifdef ENABLE_SLOW_DCHECKS 11488 if (FLAG_enable_slow_asserts) { 11489 if (Hash() != other->Hash()) { 11490 bool found_difference = false; 11491 for (int i = 0; i < len; i++) { 11492 if (Get(i) != other->Get(i)) { 11493 found_difference = true; 11494 break; 11495 } 11496 } 11497 DCHECK(found_difference); 11498 } 11499 } 11500 #endif 11501 if (Hash() != other->Hash()) return false; 11502 } 11503 11504 // We know the strings are both non-empty. Compare the first chars 11505 // before we try to flatten the strings. 11506 if (this->Get(0) != other->Get(0)) return false; 11507 11508 if (IsSeqOneByteString() && other->IsSeqOneByteString()) { 11509 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars(); 11510 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(); 11511 return CompareRawStringContents(str1, str2, len); 11512 } 11513 11514 StringComparator comparator; 11515 return comparator.Equals(this, other); 11516 } 11517 11518 11519 bool String::SlowEquals(Handle<String> one, Handle<String> two) { 11520 // Fast check: negative check with lengths. 11521 int one_length = one->length(); 11522 if (one_length != two->length()) return false; 11523 if (one_length == 0) return true; 11524 11525 // Fast check: if hash code is computed for both strings 11526 // a fast negative check can be performed. 11527 if (one->HasHashCode() && two->HasHashCode()) { 11528 #ifdef ENABLE_SLOW_DCHECKS 11529 if (FLAG_enable_slow_asserts) { 11530 if (one->Hash() != two->Hash()) { 11531 bool found_difference = false; 11532 for (int i = 0; i < one_length; i++) { 11533 if (one->Get(i) != two->Get(i)) { 11534 found_difference = true; 11535 break; 11536 } 11537 } 11538 DCHECK(found_difference); 11539 } 11540 } 11541 #endif 11542 if (one->Hash() != two->Hash()) return false; 11543 } 11544 11545 // We know the strings are both non-empty. Compare the first chars 11546 // before we try to flatten the strings. 11547 if (one->Get(0) != two->Get(0)) return false; 11548 11549 one = String::Flatten(one); 11550 two = String::Flatten(two); 11551 11552 DisallowHeapAllocation no_gc; 11553 String::FlatContent flat1 = one->GetFlatContent(); 11554 String::FlatContent flat2 = two->GetFlatContent(); 11555 11556 if (flat1.IsOneByte() && flat2.IsOneByte()) { 11557 return CompareRawStringContents(flat1.ToOneByteVector().start(), 11558 flat2.ToOneByteVector().start(), 11559 one_length); 11560 } else { 11561 for (int i = 0; i < one_length; i++) { 11562 if (flat1.Get(i) != flat2.Get(i)) return false; 11563 } 11564 return true; 11565 } 11566 } 11567 11568 11569 // static 11570 ComparisonResult String::Compare(Handle<String> x, Handle<String> y) { 11571 // A few fast case tests before we flatten. 11572 if (x.is_identical_to(y)) { 11573 return ComparisonResult::kEqual; 11574 } else if (y->length() == 0) { 11575 return x->length() == 0 ? ComparisonResult::kEqual 11576 : ComparisonResult::kGreaterThan; 11577 } else if (x->length() == 0) { 11578 return ComparisonResult::kLessThan; 11579 } 11580 11581 int const d = x->Get(0) - y->Get(0); 11582 if (d < 0) { 11583 return ComparisonResult::kLessThan; 11584 } else if (d > 0) { 11585 return ComparisonResult::kGreaterThan; 11586 } 11587 11588 // Slow case. 11589 x = String::Flatten(x); 11590 y = String::Flatten(y); 11591 11592 DisallowHeapAllocation no_gc; 11593 ComparisonResult result = ComparisonResult::kEqual; 11594 int prefix_length = x->length(); 11595 if (y->length() < prefix_length) { 11596 prefix_length = y->length(); 11597 result = ComparisonResult::kGreaterThan; 11598 } else if (y->length() > prefix_length) { 11599 result = ComparisonResult::kLessThan; 11600 } 11601 int r; 11602 String::FlatContent x_content = x->GetFlatContent(); 11603 String::FlatContent y_content = y->GetFlatContent(); 11604 if (x_content.IsOneByte()) { 11605 Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); 11606 if (y_content.IsOneByte()) { 11607 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 11608 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11609 } else { 11610 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 11611 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11612 } 11613 } else { 11614 Vector<const uc16> x_chars = x_content.ToUC16Vector(); 11615 if (y_content.IsOneByte()) { 11616 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 11617 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11618 } else { 11619 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 11620 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11621 } 11622 } 11623 if (r < 0) { 11624 result = ComparisonResult::kLessThan; 11625 } else if (r > 0) { 11626 result = ComparisonResult::kGreaterThan; 11627 } 11628 return result; 11629 } 11630 11631 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver, 11632 Handle<Object> search, Handle<Object> position) { 11633 if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) { 11634 THROW_NEW_ERROR_RETURN_FAILURE( 11635 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, 11636 isolate->factory()->NewStringFromAsciiChecked( 11637 "String.prototype.indexOf"))); 11638 } 11639 Handle<String> receiver_string; 11640 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string, 11641 Object::ToString(isolate, receiver)); 11642 11643 Handle<String> search_string; 11644 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string, 11645 Object::ToString(isolate, search)); 11646 11647 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 11648 Object::ToInteger(isolate, position)); 11649 11650 double index = std::max(position->Number(), 0.0); 11651 index = std::min(index, static_cast<double>(receiver_string->length())); 11652 11653 return Smi::FromInt(String::IndexOf(isolate, receiver_string, search_string, 11654 static_cast<uint32_t>(index))); 11655 } 11656 11657 namespace { 11658 11659 template <typename T> 11660 int SearchString(Isolate* isolate, String::FlatContent receiver_content, 11661 Vector<T> pat_vector, int start_index) { 11662 if (receiver_content.IsOneByte()) { 11663 return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector, 11664 start_index); 11665 } 11666 return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector, 11667 start_index); 11668 } 11669 11670 } // namespace 11671 11672 int String::IndexOf(Isolate* isolate, Handle<String> receiver, 11673 Handle<String> search, int start_index) { 11674 DCHECK(0 <= start_index); 11675 DCHECK(start_index <= receiver->length()); 11676 11677 uint32_t search_length = search->length(); 11678 if (search_length == 0) return start_index; 11679 11680 uint32_t receiver_length = receiver->length(); 11681 if (start_index + search_length > receiver_length) return -1; 11682 11683 receiver = String::Flatten(receiver); 11684 search = String::Flatten(search); 11685 11686 DisallowHeapAllocation no_gc; // ensure vectors stay valid 11687 // Extract flattened substrings of cons strings before getting encoding. 11688 String::FlatContent receiver_content = receiver->GetFlatContent(); 11689 String::FlatContent search_content = search->GetFlatContent(); 11690 11691 // dispatch on type of strings 11692 if (search_content.IsOneByte()) { 11693 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector(); 11694 return SearchString<const uint8_t>(isolate, receiver_content, pat_vector, 11695 start_index); 11696 } 11697 Vector<const uc16> pat_vector = search_content.ToUC16Vector(); 11698 return SearchString<const uc16>(isolate, receiver_content, pat_vector, 11699 start_index); 11700 } 11701 11702 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match, 11703 Handle<String> replacement) { 11704 Factory* factory = isolate->factory(); 11705 11706 const int replacement_length = replacement->length(); 11707 const int captures_length = match->CaptureCount(); 11708 11709 replacement = String::Flatten(replacement); 11710 11711 Handle<String> dollar_string = 11712 factory->LookupSingleCharacterStringFromCode('$'); 11713 int next = String::IndexOf(isolate, replacement, dollar_string, 0); 11714 if (next < 0) { 11715 return replacement; 11716 } 11717 11718 IncrementalStringBuilder builder(isolate); 11719 11720 if (next > 0) { 11721 builder.AppendString(factory->NewSubString(replacement, 0, next)); 11722 } 11723 11724 while (true) { 11725 int pos = next + 1; 11726 if (pos < replacement_length) { 11727 const uint16_t peek = replacement->Get(pos); 11728 if (peek == '$') { // $$ 11729 pos++; 11730 builder.AppendCharacter('$'); 11731 } else if (peek == '&') { // $& - match 11732 pos++; 11733 builder.AppendString(match->GetMatch()); 11734 } else if (peek == '`') { // $` - prefix 11735 pos++; 11736 builder.AppendString(match->GetPrefix()); 11737 } else if (peek == '\'') { // $' - suffix 11738 pos++; 11739 builder.AppendString(match->GetSuffix()); 11740 } else if (peek >= '0' && peek <= '9') { 11741 // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99 11742 int scaled_index = (peek - '0'); 11743 int advance = 1; 11744 11745 if (pos + 1 < replacement_length) { 11746 const uint16_t next_peek = replacement->Get(pos + 1); 11747 if (next_peek >= '0' && next_peek <= '9') { 11748 const int new_scaled_index = scaled_index * 10 + (next_peek - '0'); 11749 if (new_scaled_index < captures_length) { 11750 scaled_index = new_scaled_index; 11751 advance = 2; 11752 } 11753 } 11754 } 11755 11756 if (scaled_index != 0 && scaled_index < captures_length) { 11757 bool capture_exists; 11758 Handle<String> capture; 11759 ASSIGN_RETURN_ON_EXCEPTION( 11760 isolate, capture, 11761 match->GetCapture(scaled_index, &capture_exists), String); 11762 if (capture_exists) builder.AppendString(capture); 11763 pos += advance; 11764 } else { 11765 builder.AppendCharacter('$'); 11766 } 11767 } else { 11768 builder.AppendCharacter('$'); 11769 } 11770 } else { 11771 builder.AppendCharacter('$'); 11772 } 11773 11774 // Go the the next $ in the replacement. 11775 next = String::IndexOf(isolate, replacement, dollar_string, pos); 11776 11777 // Return if there are no more $ characters in the replacement. If we 11778 // haven't reached the end, we need to append the suffix. 11779 if (next < 0) { 11780 if (pos < replacement_length) { 11781 builder.AppendString( 11782 factory->NewSubString(replacement, pos, replacement_length)); 11783 } 11784 return builder.Finish(); 11785 } 11786 11787 // Append substring between the previous and the next $ character. 11788 if (next > pos) { 11789 builder.AppendString(factory->NewSubString(replacement, pos, next)); 11790 } 11791 } 11792 11793 UNREACHABLE(); 11794 return MaybeHandle<String>(); 11795 } 11796 11797 namespace { // for String.Prototype.lastIndexOf 11798 11799 template <typename schar, typename pchar> 11800 int StringMatchBackwards(Vector<const schar> subject, 11801 Vector<const pchar> pattern, int idx) { 11802 int pattern_length = pattern.length(); 11803 DCHECK(pattern_length >= 1); 11804 DCHECK(idx + pattern_length <= subject.length()); 11805 11806 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 11807 for (int i = 0; i < pattern_length; i++) { 11808 uc16 c = pattern[i]; 11809 if (c > String::kMaxOneByteCharCode) { 11810 return -1; 11811 } 11812 } 11813 } 11814 11815 pchar pattern_first_char = pattern[0]; 11816 for (int i = idx; i >= 0; i--) { 11817 if (subject[i] != pattern_first_char) continue; 11818 int j = 1; 11819 while (j < pattern_length) { 11820 if (pattern[j] != subject[i + j]) { 11821 break; 11822 } 11823 j++; 11824 } 11825 if (j == pattern_length) { 11826 return i; 11827 } 11828 } 11829 return -1; 11830 } 11831 11832 } // namespace 11833 11834 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver, 11835 Handle<Object> search, Handle<Object> position) { 11836 if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) { 11837 THROW_NEW_ERROR_RETURN_FAILURE( 11838 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, 11839 isolate->factory()->NewStringFromAsciiChecked( 11840 "String.prototype.lastIndexOf"))); 11841 } 11842 Handle<String> receiver_string; 11843 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string, 11844 Object::ToString(isolate, receiver)); 11845 11846 Handle<String> search_string; 11847 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string, 11848 Object::ToString(isolate, search)); 11849 11850 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 11851 Object::ToNumber(position)); 11852 11853 uint32_t start_index; 11854 11855 if (position->IsNaN()) { 11856 start_index = receiver_string->length(); 11857 } else { 11858 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 11859 Object::ToInteger(isolate, position)); 11860 11861 double position_number = std::max(position->Number(), 0.0); 11862 position_number = std::min(position_number, 11863 static_cast<double>(receiver_string->length())); 11864 start_index = static_cast<uint32_t>(position_number); 11865 } 11866 11867 uint32_t pattern_length = search_string->length(); 11868 uint32_t receiver_length = receiver_string->length(); 11869 11870 if (start_index + pattern_length > receiver_length) { 11871 start_index = receiver_length - pattern_length; 11872 } 11873 11874 if (pattern_length == 0) { 11875 return Smi::FromInt(start_index); 11876 } 11877 11878 receiver_string = String::Flatten(receiver_string); 11879 search_string = String::Flatten(search_string); 11880 11881 int last_index = -1; 11882 DisallowHeapAllocation no_gc; // ensure vectors stay valid 11883 11884 String::FlatContent receiver_content = receiver_string->GetFlatContent(); 11885 String::FlatContent search_content = search_string->GetFlatContent(); 11886 11887 if (search_content.IsOneByte()) { 11888 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector(); 11889 if (receiver_content.IsOneByte()) { 11890 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(), 11891 pat_vector, start_index); 11892 } else { 11893 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(), 11894 pat_vector, start_index); 11895 } 11896 } else { 11897 Vector<const uc16> pat_vector = search_content.ToUC16Vector(); 11898 if (receiver_content.IsOneByte()) { 11899 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(), 11900 pat_vector, start_index); 11901 } else { 11902 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(), 11903 pat_vector, start_index); 11904 } 11905 } 11906 return Smi::FromInt(last_index); 11907 } 11908 11909 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) { 11910 int slen = length(); 11911 // Can't check exact length equality, but we can check bounds. 11912 int str_len = str.length(); 11913 if (!allow_prefix_match && 11914 (str_len < slen || 11915 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) { 11916 return false; 11917 } 11918 int i; 11919 size_t remaining_in_str = static_cast<size_t>(str_len); 11920 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start()); 11921 for (i = 0; i < slen && remaining_in_str > 0; i++) { 11922 size_t cursor = 0; 11923 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor); 11924 DCHECK(cursor > 0 && cursor <= remaining_in_str); 11925 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) { 11926 if (i > slen - 1) return false; 11927 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false; 11928 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false; 11929 } else { 11930 if (Get(i) != r) return false; 11931 } 11932 utf8_data += cursor; 11933 remaining_in_str -= cursor; 11934 } 11935 return (allow_prefix_match || i == slen) && remaining_in_str == 0; 11936 } 11937 11938 11939 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) { 11940 int slen = length(); 11941 if (str.length() != slen) return false; 11942 DisallowHeapAllocation no_gc; 11943 FlatContent content = GetFlatContent(); 11944 if (content.IsOneByte()) { 11945 return CompareChars(content.ToOneByteVector().start(), 11946 str.start(), slen) == 0; 11947 } 11948 for (int i = 0; i < slen; i++) { 11949 if (Get(i) != static_cast<uint16_t>(str[i])) return false; 11950 } 11951 return true; 11952 } 11953 11954 11955 bool String::IsTwoByteEqualTo(Vector<const uc16> str) { 11956 int slen = length(); 11957 if (str.length() != slen) return false; 11958 DisallowHeapAllocation no_gc; 11959 FlatContent content = GetFlatContent(); 11960 if (content.IsTwoByte()) { 11961 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0; 11962 } 11963 for (int i = 0; i < slen; i++) { 11964 if (Get(i) != str[i]) return false; 11965 } 11966 return true; 11967 } 11968 11969 11970 uint32_t String::ComputeAndSetHash() { 11971 // Should only be called if hash code has not yet been computed. 11972 DCHECK(!HasHashCode()); 11973 11974 // Store the hash code in the object. 11975 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed()); 11976 set_hash_field(field); 11977 11978 // Check the hash code is there. 11979 DCHECK(HasHashCode()); 11980 uint32_t result = field >> kHashShift; 11981 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed. 11982 return result; 11983 } 11984 11985 11986 bool String::ComputeArrayIndex(uint32_t* index) { 11987 int length = this->length(); 11988 if (length == 0 || length > kMaxArrayIndexSize) return false; 11989 StringCharacterStream stream(this); 11990 return StringToArrayIndex(&stream, index); 11991 } 11992 11993 11994 bool String::SlowAsArrayIndex(uint32_t* index) { 11995 if (length() <= kMaxCachedArrayIndexLength) { 11996 Hash(); // force computation of hash code 11997 uint32_t field = hash_field(); 11998 if ((field & kIsNotArrayIndexMask) != 0) return false; 11999 // Isolate the array index form the full hash field. 12000 *index = ArrayIndexValueBits::decode(field); 12001 return true; 12002 } else { 12003 return ComputeArrayIndex(index); 12004 } 12005 } 12006 12007 12008 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) { 12009 int new_size, old_size; 12010 int old_length = string->length(); 12011 if (old_length <= new_length) return string; 12012 12013 if (string->IsSeqOneByteString()) { 12014 old_size = SeqOneByteString::SizeFor(old_length); 12015 new_size = SeqOneByteString::SizeFor(new_length); 12016 } else { 12017 DCHECK(string->IsSeqTwoByteString()); 12018 old_size = SeqTwoByteString::SizeFor(old_length); 12019 new_size = SeqTwoByteString::SizeFor(new_length); 12020 } 12021 12022 int delta = old_size - new_size; 12023 12024 Address start_of_string = string->address(); 12025 DCHECK_OBJECT_ALIGNED(start_of_string); 12026 DCHECK_OBJECT_ALIGNED(start_of_string + new_size); 12027 12028 Heap* heap = string->GetHeap(); 12029 // Sizes are pointer size aligned, so that we can use filler objects 12030 // that are a multiple of pointer size. 12031 heap->CreateFillerObjectAt(start_of_string + new_size, delta, 12032 ClearRecordedSlots::kNo); 12033 heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER); 12034 12035 // We are storing the new length using release store after creating a filler 12036 // for the left-over space to avoid races with the sweeper thread. 12037 string->synchronized_set_length(new_length); 12038 12039 if (new_length == 0) return heap->isolate()->factory()->empty_string(); 12040 return string; 12041 } 12042 12043 12044 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { 12045 // For array indexes mix the length into the hash as an array index could 12046 // be zero. 12047 DCHECK(length > 0); 12048 DCHECK(length <= String::kMaxArrayIndexSize); 12049 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 12050 (1 << String::kArrayIndexValueBits)); 12051 12052 value <<= String::ArrayIndexValueBits::kShift; 12053 value |= length << String::ArrayIndexLengthBits::kShift; 12054 12055 DCHECK((value & String::kIsNotArrayIndexMask) == 0); 12056 DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength, 12057 (value & String::kContainsCachedArrayIndexMask) == 0); 12058 return value; 12059 } 12060 12061 12062 uint32_t StringHasher::GetHashField() { 12063 if (length_ <= String::kMaxHashCalcLength) { 12064 if (is_array_index_) { 12065 return MakeArrayIndexHash(array_index_, length_); 12066 } 12067 return (GetHashCore(raw_running_hash_) << String::kHashShift) | 12068 String::kIsNotArrayIndexMask; 12069 } else { 12070 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask; 12071 } 12072 } 12073 12074 12075 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, 12076 uint32_t seed, 12077 int* utf16_length_out) { 12078 int vector_length = chars.length(); 12079 // Handle some edge cases 12080 if (vector_length <= 1) { 12081 DCHECK(vector_length == 0 || 12082 static_cast<uint8_t>(chars.start()[0]) <= 12083 unibrow::Utf8::kMaxOneByteChar); 12084 *utf16_length_out = vector_length; 12085 return HashSequentialString(chars.start(), vector_length, seed); 12086 } 12087 // Start with a fake length which won't affect computation. 12088 // It will be updated later. 12089 StringHasher hasher(String::kMaxArrayIndexSize, seed); 12090 size_t remaining = static_cast<size_t>(vector_length); 12091 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start()); 12092 int utf16_length = 0; 12093 bool is_index = true; 12094 DCHECK(hasher.is_array_index_); 12095 while (remaining > 0) { 12096 size_t consumed = 0; 12097 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed); 12098 DCHECK(consumed > 0 && consumed <= remaining); 12099 stream += consumed; 12100 remaining -= consumed; 12101 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode; 12102 utf16_length += is_two_characters ? 2 : 1; 12103 // No need to keep hashing. But we do need to calculate utf16_length. 12104 if (utf16_length > String::kMaxHashCalcLength) continue; 12105 if (is_two_characters) { 12106 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c); 12107 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c); 12108 hasher.AddCharacter(c1); 12109 hasher.AddCharacter(c2); 12110 if (is_index) is_index = hasher.UpdateIndex(c1); 12111 if (is_index) is_index = hasher.UpdateIndex(c2); 12112 } else { 12113 hasher.AddCharacter(c); 12114 if (is_index) is_index = hasher.UpdateIndex(c); 12115 } 12116 } 12117 *utf16_length_out = static_cast<int>(utf16_length); 12118 // Must set length here so that hash computation is correct. 12119 hasher.length_ = utf16_length; 12120 return hasher.GetHashField(); 12121 } 12122 12123 12124 void IteratingStringHasher::VisitConsString(ConsString* cons_string) { 12125 // Run small ConsStrings through ConsStringIterator. 12126 if (cons_string->length() < 64) { 12127 ConsStringIterator iter(cons_string); 12128 int offset; 12129 String* string; 12130 while (nullptr != (string = iter.Next(&offset))) { 12131 DCHECK_EQ(0, offset); 12132 String::VisitFlat(this, string, 0); 12133 } 12134 return; 12135 } 12136 // Slow case. 12137 const int max_length = String::kMaxHashCalcLength; 12138 int length = std::min(cons_string->length(), max_length); 12139 if (cons_string->HasOnlyOneByteChars()) { 12140 uint8_t* buffer = new uint8_t[length]; 12141 String::WriteToFlat(cons_string, buffer, 0, length); 12142 AddCharacters(buffer, length); 12143 delete[] buffer; 12144 } else { 12145 uint16_t* buffer = new uint16_t[length]; 12146 String::WriteToFlat(cons_string, buffer, 0, length); 12147 AddCharacters(buffer, length); 12148 delete[] buffer; 12149 } 12150 } 12151 12152 12153 void String::PrintOn(FILE* file) { 12154 int length = this->length(); 12155 for (int i = 0; i < length; i++) { 12156 PrintF(file, "%c", Get(i)); 12157 } 12158 } 12159 12160 12161 int Map::Hash() { 12162 // For performance reasons we only hash the 3 most variable fields of a map: 12163 // constructor, prototype and bit_field2. For predictability reasons we 12164 // use objects' offsets in respective pages for hashing instead of raw 12165 // addresses. 12166 12167 // Shift away the tag. 12168 int hash = ObjectAddressForHashing(GetConstructor()) >> 2; 12169 12170 // XOR-ing the prototype and constructor directly yields too many zero bits 12171 // when the two pointers are close (which is fairly common). 12172 // To avoid this we shift the prototype bits relatively to the constructor. 12173 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits); 12174 12175 return hash ^ (hash >> 16) ^ bit_field2(); 12176 } 12177 12178 12179 namespace { 12180 12181 bool CheckEquivalent(Map* first, Map* second) { 12182 return first->GetConstructor() == second->GetConstructor() && 12183 first->prototype() == second->prototype() && 12184 first->instance_type() == second->instance_type() && 12185 first->bit_field() == second->bit_field() && 12186 first->is_extensible() == second->is_extensible() && 12187 first->new_target_is_base() == second->new_target_is_base() && 12188 first->has_hidden_prototype() == second->has_hidden_prototype(); 12189 } 12190 12191 } // namespace 12192 12193 12194 bool Map::EquivalentToForTransition(Map* other) { 12195 if (!CheckEquivalent(this, other)) return false; 12196 if (instance_type() == JS_FUNCTION_TYPE) { 12197 // JSFunctions require more checks to ensure that sloppy function is 12198 // not equvalent to strict function. 12199 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors()); 12200 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(), 12201 nof); 12202 } 12203 return true; 12204 } 12205 12206 12207 bool Map::EquivalentToForNormalization(Map* other, 12208 PropertyNormalizationMode mode) { 12209 int properties = 12210 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties(); 12211 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() && 12212 GetInObjectProperties() == properties; 12213 } 12214 12215 12216 bool JSFunction::Inlines(SharedFunctionInfo* candidate) { 12217 DisallowHeapAllocation no_gc; 12218 if (shared() == candidate) return true; 12219 if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false; 12220 DeoptimizationInputData* const data = 12221 DeoptimizationInputData::cast(code()->deoptimization_data()); 12222 if (data->length() == 0) return false; 12223 FixedArray* const literals = data->LiteralArray(); 12224 int const inlined_count = data->InlinedFunctionCount()->value(); 12225 for (int i = 0; i < inlined_count; ++i) { 12226 if (SharedFunctionInfo::cast(literals->get(i)) == candidate) { 12227 return true; 12228 } 12229 } 12230 return false; 12231 } 12232 12233 void JSFunction::MarkForBaseline() { 12234 Isolate* isolate = GetIsolate(); 12235 set_code_no_write_barrier( 12236 isolate->builtins()->builtin(Builtins::kCompileBaseline)); 12237 // No write barrier required, since the builtin is part of the root set. 12238 if (FLAG_mark_shared_functions_for_tier_up) { 12239 shared()->set_marked_for_tier_up(true); 12240 } 12241 } 12242 12243 void JSFunction::MarkForOptimization() { 12244 Isolate* isolate = GetIsolate(); 12245 DCHECK(!IsOptimized()); 12246 DCHECK(shared()->allows_lazy_compilation() || 12247 !shared()->optimization_disabled()); 12248 set_code_no_write_barrier( 12249 isolate->builtins()->builtin(Builtins::kCompileOptimized)); 12250 // No write barrier required, since the builtin is part of the root set. 12251 if (FLAG_mark_shared_functions_for_tier_up) { 12252 shared()->set_marked_for_tier_up(true); 12253 } 12254 } 12255 12256 12257 void JSFunction::AttemptConcurrentOptimization() { 12258 Isolate* isolate = GetIsolate(); 12259 if (!isolate->concurrent_recompilation_enabled() || 12260 isolate->bootstrapper()->IsActive()) { 12261 MarkForOptimization(); 12262 return; 12263 } 12264 DCHECK(!IsInOptimizationQueue()); 12265 DCHECK(!IsOptimized()); 12266 DCHECK(shared()->allows_lazy_compilation() || 12267 !shared()->optimization_disabled()); 12268 DCHECK(isolate->concurrent_recompilation_enabled()); 12269 if (FLAG_trace_concurrent_recompilation) { 12270 PrintF(" ** Marking "); 12271 ShortPrint(); 12272 PrintF(" for concurrent recompilation.\n"); 12273 } 12274 12275 set_code_no_write_barrier( 12276 isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent)); 12277 // No write barrier required, since the builtin is part of the root set. 12278 if (FLAG_mark_shared_functions_for_tier_up) { 12279 // TODO(leszeks): The compilation isn't concurrent if we trigger it using 12280 // this bit. 12281 shared()->set_marked_for_tier_up(true); 12282 } 12283 } 12284 12285 // static 12286 Handle<LiteralsArray> SharedFunctionInfo::FindOrCreateLiterals( 12287 Handle<SharedFunctionInfo> shared, Handle<Context> native_context) { 12288 Isolate* isolate = shared->GetIsolate(); 12289 CodeAndLiterals result = 12290 shared->SearchOptimizedCodeMap(*native_context, BailoutId::None()); 12291 if (result.literals != nullptr) { 12292 DCHECK(shared->feedback_metadata()->is_empty() || 12293 !result.literals->feedback_vector()->is_empty()); 12294 return handle(result.literals, isolate); 12295 } 12296 12297 Handle<TypeFeedbackVector> feedback_vector = 12298 TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata())); 12299 Handle<LiteralsArray> literals = 12300 LiteralsArray::New(isolate, feedback_vector, shared->num_literals()); 12301 Handle<Code> code; 12302 if (result.code != nullptr) { 12303 code = Handle<Code>(result.code, isolate); 12304 } 12305 AddToOptimizedCodeMap(shared, native_context, code, literals, 12306 BailoutId::None()); 12307 return literals; 12308 } 12309 12310 // static 12311 void SharedFunctionInfo::AddToOptimizedCodeMap( 12312 Handle<SharedFunctionInfo> shared, Handle<Context> native_context, 12313 MaybeHandle<Code> code, Handle<LiteralsArray> literals, 12314 BailoutId osr_ast_id) { 12315 Isolate* isolate = shared->GetIsolate(); 12316 if (isolate->serializer_enabled()) return; 12317 DCHECK(code.is_null() || 12318 code.ToHandleChecked()->kind() == Code::OPTIMIZED_FUNCTION); 12319 DCHECK(native_context->IsNativeContext()); 12320 STATIC_ASSERT(kEntryLength == 4); 12321 Handle<FixedArray> new_code_map; 12322 int entry; 12323 12324 if (shared->OptimizedCodeMapIsCleared()) { 12325 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED); 12326 entry = kEntriesStart; 12327 } else { 12328 Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate); 12329 entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id); 12330 if (entry >= kEntriesStart) { 12331 // Just set the code and literals of the entry. 12332 if (!code.is_null()) { 12333 Handle<WeakCell> code_cell = 12334 isolate->factory()->NewWeakCell(code.ToHandleChecked()); 12335 old_code_map->set(entry + kCachedCodeOffset, *code_cell); 12336 } 12337 Handle<WeakCell> literals_cell = 12338 isolate->factory()->NewWeakCell(literals); 12339 old_code_map->set(entry + kLiteralsOffset, *literals_cell); 12340 return; 12341 } 12342 12343 // Can we reuse an entry? 12344 DCHECK(entry < kEntriesStart); 12345 int length = old_code_map->length(); 12346 for (int i = kEntriesStart; i < length; i += kEntryLength) { 12347 if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) { 12348 new_code_map = old_code_map; 12349 entry = i; 12350 break; 12351 } 12352 } 12353 12354 if (entry < kEntriesStart) { 12355 // Copy old optimized code map and append one new entry. 12356 new_code_map = isolate->factory()->CopyFixedArrayAndGrow( 12357 old_code_map, kEntryLength, TENURED); 12358 // TODO(mstarzinger): Temporary workaround. The allocation above might 12359 // have flushed the optimized code map and the copy we created is full of 12360 // holes. For now we just give up on adding the entry and pretend it got 12361 // flushed. 12362 if (shared->OptimizedCodeMapIsCleared()) return; 12363 entry = old_code_map->length(); 12364 } 12365 } 12366 12367 Handle<WeakCell> code_cell = 12368 code.is_null() ? isolate->factory()->empty_weak_cell() 12369 : isolate->factory()->NewWeakCell(code.ToHandleChecked()); 12370 Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals); 12371 WeakCell* context_cell = native_context->self_weak_cell(); 12372 12373 new_code_map->set(entry + kContextOffset, context_cell); 12374 new_code_map->set(entry + kCachedCodeOffset, *code_cell); 12375 new_code_map->set(entry + kLiteralsOffset, *literals_cell); 12376 new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt())); 12377 12378 #ifdef DEBUG 12379 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) { 12380 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset)); 12381 DCHECK(cell->cleared() || cell->value()->IsNativeContext()); 12382 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset)); 12383 DCHECK(cell->cleared() || 12384 (cell->value()->IsCode() && 12385 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION)); 12386 cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset)); 12387 DCHECK(cell->cleared() || cell->value()->IsFixedArray()); 12388 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi()); 12389 } 12390 #endif 12391 12392 FixedArray* old_code_map = shared->optimized_code_map(); 12393 if (old_code_map != *new_code_map) { 12394 shared->set_optimized_code_map(*new_code_map); 12395 } 12396 } 12397 12398 12399 void SharedFunctionInfo::ClearOptimizedCodeMap() { 12400 FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array(); 12401 set_optimized_code_map(empty_fixed_array, SKIP_WRITE_BARRIER); 12402 } 12403 12404 12405 void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code, 12406 const char* reason) { 12407 DisallowHeapAllocation no_gc; 12408 if (OptimizedCodeMapIsCleared()) return; 12409 12410 Heap* heap = GetHeap(); 12411 FixedArray* code_map = optimized_code_map(); 12412 int dst = kEntriesStart; 12413 int length = code_map->length(); 12414 for (int src = kEntriesStart; src < length; src += kEntryLength) { 12415 DCHECK(WeakCell::cast(code_map->get(src))->cleared() || 12416 WeakCell::cast(code_map->get(src))->value()->IsNativeContext()); 12417 if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() == 12418 optimized_code) { 12419 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value()); 12420 if (FLAG_trace_opt) { 12421 PrintF("[evicting entry from optimizing code map (%s) for ", reason); 12422 ShortPrint(); 12423 if (osr.IsNone()) { 12424 PrintF("]\n"); 12425 } else { 12426 PrintF(" (osr ast id %d)]\n", osr.ToInt()); 12427 } 12428 } 12429 if (!osr.IsNone()) { 12430 // Evict the src entry by not copying it to the dst entry. 12431 continue; 12432 } 12433 // In case of non-OSR entry just clear the code in order to proceed 12434 // sharing literals. 12435 code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(), 12436 SKIP_WRITE_BARRIER); 12437 } 12438 12439 // Keep the src entry by copying it to the dst entry. 12440 if (dst != src) { 12441 code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset)); 12442 code_map->set(dst + kCachedCodeOffset, 12443 code_map->get(src + kCachedCodeOffset)); 12444 code_map->set(dst + kLiteralsOffset, 12445 code_map->get(src + kLiteralsOffset)); 12446 code_map->set(dst + kOsrAstIdOffset, 12447 code_map->get(src + kOsrAstIdOffset)); 12448 } 12449 dst += kEntryLength; 12450 } 12451 if (dst != length) { 12452 // Always trim even when array is cleared because of heap verifier. 12453 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map, 12454 length - dst); 12455 if (code_map->length() == kEntriesStart) { 12456 ClearOptimizedCodeMap(); 12457 } 12458 } 12459 } 12460 12461 12462 void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) { 12463 FixedArray* code_map = optimized_code_map(); 12464 DCHECK(shrink_by % kEntryLength == 0); 12465 DCHECK(shrink_by <= code_map->length() - kEntriesStart); 12466 // Always trim even when array is cleared because of heap verifier. 12467 GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map, 12468 shrink_by); 12469 if (code_map->length() == kEntriesStart) { 12470 ClearOptimizedCodeMap(); 12471 } 12472 } 12473 12474 // static 12475 void JSFunction::EnsureLiterals(Handle<JSFunction> function) { 12476 Handle<SharedFunctionInfo> shared(function->shared()); 12477 Handle<Context> native_context(function->context()->native_context()); 12478 if (function->literals() == 12479 function->GetIsolate()->heap()->empty_literals_array()) { 12480 Handle<LiteralsArray> literals = 12481 SharedFunctionInfo::FindOrCreateLiterals(shared, native_context); 12482 function->set_literals(*literals); 12483 } 12484 } 12485 12486 static void GetMinInobjectSlack(Map* map, void* data) { 12487 int slack = map->unused_property_fields(); 12488 if (*reinterpret_cast<int*>(data) > slack) { 12489 *reinterpret_cast<int*>(data) = slack; 12490 } 12491 } 12492 12493 12494 static void ShrinkInstanceSize(Map* map, void* data) { 12495 int slack = *reinterpret_cast<int*>(data); 12496 map->SetInObjectProperties(map->GetInObjectProperties() - slack); 12497 map->set_unused_property_fields(map->unused_property_fields() - slack); 12498 map->set_instance_size(map->instance_size() - slack * kPointerSize); 12499 map->set_construction_counter(Map::kNoSlackTracking); 12500 12501 // Visitor id might depend on the instance size, recalculate it. 12502 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map)); 12503 } 12504 12505 static void StopSlackTracking(Map* map, void* data) { 12506 map->set_construction_counter(Map::kNoSlackTracking); 12507 } 12508 12509 void Map::CompleteInobjectSlackTracking() { 12510 // Has to be an initial map. 12511 DCHECK(GetBackPointer()->IsUndefined(GetIsolate())); 12512 12513 int slack = unused_property_fields(); 12514 TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack); 12515 if (slack != 0) { 12516 // Resize the initial map and all maps in its transition tree. 12517 TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack); 12518 } else { 12519 TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr); 12520 } 12521 } 12522 12523 12524 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) { 12525 DisallowHeapAllocation no_gc; 12526 if (!object->HasFastProperties()) return false; 12527 Map* map = object->map(); 12528 if (map->is_prototype_map()) return false; 12529 DescriptorArray* descriptors = map->instance_descriptors(); 12530 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { 12531 PropertyDetails details = descriptors->GetDetails(i); 12532 if (details.location() == kDescriptor) continue; 12533 if (details.representation().IsHeapObject() || 12534 details.representation().IsTagged()) { 12535 FieldIndex index = FieldIndex::ForDescriptor(map, i); 12536 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true; 12537 } 12538 } 12539 return false; 12540 } 12541 12542 // static 12543 void JSObject::MakePrototypesFast(Handle<Object> receiver, 12544 WhereToStart where_to_start, 12545 Isolate* isolate) { 12546 if (!receiver->IsJSReceiver()) return; 12547 for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver), 12548 where_to_start); 12549 !iter.IsAtEnd(); iter.Advance()) { 12550 Handle<Object> current = PrototypeIterator::GetCurrent(iter); 12551 if (!current->IsJSObject()) return; 12552 Handle<JSObject> current_obj = Handle<JSObject>::cast(current); 12553 Map* current_map = current_obj->map(); 12554 if (current_map->is_prototype_map() && 12555 !current_map->should_be_fast_prototype_map()) { 12556 Handle<Map> map(current_map); 12557 Map::SetShouldBeFastPrototypeMap(map, true, isolate); 12558 JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE); 12559 } 12560 } 12561 } 12562 12563 // static 12564 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, 12565 PrototypeOptimizationMode mode) { 12566 if (object->IsJSGlobalObject()) return; 12567 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { 12568 // First normalize to ensure all JSFunctions are DATA_CONSTANT. 12569 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, 12570 "NormalizeAsPrototype"); 12571 } 12572 Handle<Map> previous_map(object->map()); 12573 if (object->map()->is_prototype_map()) { 12574 if (object->map()->should_be_fast_prototype_map() && 12575 !object->HasFastProperties()) { 12576 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); 12577 } 12578 } else { 12579 if (object->map() == *previous_map) { 12580 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); 12581 JSObject::MigrateToMap(object, new_map); 12582 } 12583 object->map()->set_is_prototype_map(true); 12584 12585 // Replace the pointer to the exact constructor with the Object function 12586 // from the same context if undetectable from JS. This is to avoid keeping 12587 // memory alive unnecessarily. 12588 Object* maybe_constructor = object->map()->GetConstructor(); 12589 if (maybe_constructor->IsJSFunction()) { 12590 JSFunction* constructor = JSFunction::cast(maybe_constructor); 12591 Isolate* isolate = object->GetIsolate(); 12592 if (!constructor->shared()->IsApiFunction() && 12593 object->class_name() == isolate->heap()->Object_string()) { 12594 Context* context = constructor->context()->native_context(); 12595 JSFunction* object_function = context->object_function(); 12596 object->map()->SetConstructor(object_function); 12597 } 12598 } 12599 } 12600 } 12601 12602 12603 // static 12604 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { 12605 if (!object->map()->is_prototype_map()) return; 12606 if (!object->map()->should_be_fast_prototype_map()) return; 12607 OptimizeAsPrototype(object, FAST_PROTOTYPE); 12608 } 12609 12610 12611 // static 12612 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) { 12613 // Contract: In line with InvalidatePrototypeChains()'s requirements, 12614 // leaf maps don't need to register as users, only prototypes do. 12615 DCHECK(user->is_prototype_map()); 12616 12617 Handle<Map> current_user = user; 12618 Handle<PrototypeInfo> current_user_info = 12619 Map::GetOrCreatePrototypeInfo(user, isolate); 12620 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) { 12621 // Walk up the prototype chain as far as links haven't been registered yet. 12622 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) { 12623 break; 12624 } 12625 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter); 12626 // Proxies on the prototype chain are not supported. They make it 12627 // impossible to make any assumptions about the prototype chain anyway. 12628 if (maybe_proto->IsJSProxy()) return; 12629 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto); 12630 Handle<PrototypeInfo> proto_info = 12631 Map::GetOrCreatePrototypeInfo(proto, isolate); 12632 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); 12633 int slot = 0; 12634 Handle<WeakFixedArray> new_array = 12635 WeakFixedArray::Add(maybe_registry, current_user, &slot); 12636 current_user_info->set_registry_slot(slot); 12637 if (!maybe_registry.is_identical_to(new_array)) { 12638 proto_info->set_prototype_users(*new_array); 12639 } 12640 if (FLAG_trace_prototype_users) { 12641 PrintF("Registering %p as a user of prototype %p (map=%p).\n", 12642 reinterpret_cast<void*>(*current_user), 12643 reinterpret_cast<void*>(*proto), 12644 reinterpret_cast<void*>(proto->map())); 12645 } 12646 12647 current_user = handle(proto->map(), isolate); 12648 current_user_info = proto_info; 12649 } 12650 } 12651 12652 12653 // Can be called regardless of whether |user| was actually registered with 12654 // |prototype|. Returns true when there was a registration. 12655 // static 12656 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) { 12657 DCHECK(user->is_prototype_map()); 12658 // If it doesn't have a PrototypeInfo, it was never registered. 12659 if (!user->prototype_info()->IsPrototypeInfo()) return false; 12660 // If it had no prototype before, see if it had users that might expect 12661 // registration. 12662 if (!user->prototype()->IsJSObject()) { 12663 Object* users = 12664 PrototypeInfo::cast(user->prototype_info())->prototype_users(); 12665 return users->IsWeakFixedArray(); 12666 } 12667 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate); 12668 Handle<PrototypeInfo> user_info = 12669 Map::GetOrCreatePrototypeInfo(user, isolate); 12670 int slot = user_info->registry_slot(); 12671 if (slot == PrototypeInfo::UNREGISTERED) return false; 12672 DCHECK(prototype->map()->is_prototype_map()); 12673 Object* maybe_proto_info = prototype->map()->prototype_info(); 12674 // User knows its registry slot, prototype info and user registry must exist. 12675 DCHECK(maybe_proto_info->IsPrototypeInfo()); 12676 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), 12677 isolate); 12678 Object* maybe_registry = proto_info->prototype_users(); 12679 DCHECK(maybe_registry->IsWeakFixedArray()); 12680 DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user); 12681 WeakFixedArray::cast(maybe_registry)->Clear(slot); 12682 if (FLAG_trace_prototype_users) { 12683 PrintF("Unregistering %p as a user of prototype %p.\n", 12684 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); 12685 } 12686 return true; 12687 } 12688 12689 12690 static void InvalidatePrototypeChainsInternal(Map* map) { 12691 DCHECK(map->is_prototype_map()); 12692 if (FLAG_trace_prototype_users) { 12693 PrintF("Invalidating prototype map %p 's cell\n", 12694 reinterpret_cast<void*>(map)); 12695 } 12696 Object* maybe_proto_info = map->prototype_info(); 12697 if (!maybe_proto_info->IsPrototypeInfo()) return; 12698 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); 12699 Object* maybe_cell = proto_info->validity_cell(); 12700 if (maybe_cell->IsCell()) { 12701 // Just set the value; the cell will be replaced lazily. 12702 Cell* cell = Cell::cast(maybe_cell); 12703 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); 12704 } 12705 12706 WeakFixedArray::Iterator iterator(proto_info->prototype_users()); 12707 // For now, only maps register themselves as users. 12708 Map* user; 12709 while ((user = iterator.Next<Map>())) { 12710 // Walk the prototype chain (backwards, towards leaf objects) if necessary. 12711 InvalidatePrototypeChainsInternal(user); 12712 } 12713 } 12714 12715 12716 // static 12717 void JSObject::InvalidatePrototypeChains(Map* map) { 12718 DisallowHeapAllocation no_gc; 12719 InvalidatePrototypeChainsInternal(map); 12720 } 12721 12722 12723 // static 12724 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype, 12725 Isolate* isolate) { 12726 Object* maybe_proto_info = prototype->map()->prototype_info(); 12727 if (maybe_proto_info->IsPrototypeInfo()) { 12728 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); 12729 } 12730 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); 12731 prototype->map()->set_prototype_info(*proto_info); 12732 return proto_info; 12733 } 12734 12735 12736 // static 12737 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map, 12738 Isolate* isolate) { 12739 Object* maybe_proto_info = prototype_map->prototype_info(); 12740 if (maybe_proto_info->IsPrototypeInfo()) { 12741 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); 12742 } 12743 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); 12744 prototype_map->set_prototype_info(*proto_info); 12745 return proto_info; 12746 } 12747 12748 // static 12749 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value, 12750 Isolate* isolate) { 12751 if (value == false && !map->prototype_info()->IsPrototypeInfo()) { 12752 // "False" is the implicit default value, so there's nothing to do. 12753 return; 12754 } 12755 GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value); 12756 } 12757 12758 // static 12759 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, 12760 Isolate* isolate) { 12761 Handle<Object> maybe_prototype( 12762 map->GetPrototypeChainRootMap(isolate)->prototype(), isolate); 12763 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); 12764 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); 12765 // Ensure the prototype is registered with its own prototypes so its cell 12766 // will be invalidated when necessary. 12767 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), 12768 isolate); 12769 Handle<PrototypeInfo> proto_info = 12770 GetOrCreatePrototypeInfo(prototype, isolate); 12771 Object* maybe_cell = proto_info->validity_cell(); 12772 // Return existing cell if it's still valid. 12773 if (maybe_cell->IsCell()) { 12774 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); 12775 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { 12776 return cell; 12777 } 12778 } 12779 // Otherwise create a new cell. 12780 Handle<Cell> cell = isolate->factory()->NewCell( 12781 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); 12782 proto_info->set_validity_cell(*cell); 12783 return cell; 12784 } 12785 12786 // static 12787 Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype, 12788 Isolate* isolate) { 12789 DCHECK(!prototype.is_null()); 12790 Handle<PrototypeInfo> proto_info = 12791 GetOrCreatePrototypeInfo(prototype, isolate); 12792 Object* maybe_cell = proto_info->weak_cell(); 12793 // Return existing cell if it's already created. 12794 if (maybe_cell->IsWeakCell()) { 12795 Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate); 12796 DCHECK(!cell->cleared()); 12797 return cell; 12798 } 12799 // Otherwise create a new cell. 12800 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype); 12801 proto_info->set_weak_cell(*cell); 12802 return cell; 12803 } 12804 12805 // static 12806 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, 12807 PrototypeOptimizationMode proto_mode) { 12808 RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype); 12809 12810 bool is_hidden = false; 12811 if (prototype->IsJSObject()) { 12812 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); 12813 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); 12814 12815 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor(); 12816 if (maybe_constructor->IsJSFunction()) { 12817 JSFunction* constructor = JSFunction::cast(maybe_constructor); 12818 Object* data = constructor->shared()->function_data(); 12819 is_hidden = (data->IsFunctionTemplateInfo() && 12820 FunctionTemplateInfo::cast(data)->hidden_prototype()) || 12821 prototype->IsJSGlobalObject(); 12822 } 12823 } 12824 map->set_has_hidden_prototype(is_hidden); 12825 12826 WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate()) 12827 ? SKIP_WRITE_BARRIER 12828 : UPDATE_WRITE_BARRIER; 12829 map->set_prototype(*prototype, wb_mode); 12830 } 12831 12832 12833 Handle<Object> CacheInitialJSArrayMaps( 12834 Handle<Context> native_context, Handle<Map> initial_map) { 12835 // Replace all of the cached initial array maps in the native context with 12836 // the appropriate transitioned elements kind maps. 12837 Handle<Map> current_map = initial_map; 12838 ElementsKind kind = current_map->elements_kind(); 12839 DCHECK_EQ(GetInitialFastElementsKind(), kind); 12840 native_context->set(Context::ArrayMapIndex(kind), *current_map); 12841 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1; 12842 i < kFastElementsKindCount; ++i) { 12843 Handle<Map> new_map; 12844 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); 12845 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) { 12846 new_map = handle(maybe_elements_transition); 12847 } else { 12848 new_map = Map::CopyAsElementsKind( 12849 current_map, next_kind, INSERT_TRANSITION); 12850 } 12851 DCHECK_EQ(next_kind, new_map->elements_kind()); 12852 native_context->set(Context::ArrayMapIndex(next_kind), *new_map); 12853 current_map = new_map; 12854 } 12855 return initial_map; 12856 } 12857 12858 12859 void JSFunction::SetInstancePrototype(Handle<JSFunction> function, 12860 Handle<Object> value) { 12861 Isolate* isolate = function->GetIsolate(); 12862 12863 DCHECK(value->IsJSReceiver()); 12864 12865 // Now some logic for the maps of the objects that are created by using this 12866 // function as a constructor. 12867 if (function->has_initial_map()) { 12868 // If the function has allocated the initial map replace it with a 12869 // copy containing the new prototype. Also complete any in-object 12870 // slack tracking that is in progress at this point because it is 12871 // still tracking the old copy. 12872 function->CompleteInobjectSlackTrackingIfActive(); 12873 12874 Handle<Map> initial_map(function->initial_map(), isolate); 12875 12876 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() && 12877 initial_map->instance_type() == JS_OBJECT_TYPE) { 12878 // Put the value in the initial map field until an initial map is needed. 12879 // At that point, a new initial map is created and the prototype is put 12880 // into the initial map where it belongs. 12881 function->set_prototype_or_initial_map(*value); 12882 } else { 12883 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype"); 12884 JSFunction::SetInitialMap(function, new_map, value); 12885 12886 // If the function is used as the global Array function, cache the 12887 // updated initial maps (and transitioned versions) in the native context. 12888 Handle<Context> native_context(function->context()->native_context(), 12889 isolate); 12890 Handle<Object> array_function( 12891 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate); 12892 if (array_function->IsJSFunction() && 12893 *function == JSFunction::cast(*array_function)) { 12894 CacheInitialJSArrayMaps(native_context, new_map); 12895 } 12896 } 12897 12898 // Deoptimize all code that embeds the previous initial map. 12899 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( 12900 isolate, DependentCode::kInitialMapChangedGroup); 12901 } else { 12902 // Put the value in the initial map field until an initial map is 12903 // needed. At that point, a new initial map is created and the 12904 // prototype is put into the initial map where it belongs. 12905 function->set_prototype_or_initial_map(*value); 12906 if (value->IsJSObject()) { 12907 // Optimize as prototype to detach it from its transition tree. 12908 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), 12909 FAST_PROTOTYPE); 12910 } 12911 } 12912 isolate->heap()->ClearInstanceofCache(); 12913 } 12914 12915 12916 void JSFunction::SetPrototype(Handle<JSFunction> function, 12917 Handle<Object> value) { 12918 DCHECK(function->IsConstructor() || 12919 IsGeneratorFunction(function->shared()->kind())); 12920 Handle<Object> construct_prototype = value; 12921 12922 // If the value is not a JSReceiver, store the value in the map's 12923 // constructor field so it can be accessed. Also, set the prototype 12924 // used for constructing objects to the original object prototype. 12925 // See ECMA-262 13.2.2. 12926 if (!value->IsJSReceiver()) { 12927 // Copy the map so this does not affect unrelated functions. 12928 // Remove map transitions because they point to maps with a 12929 // different prototype. 12930 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype"); 12931 12932 JSObject::MigrateToMap(function, new_map); 12933 new_map->SetConstructor(*value); 12934 new_map->set_non_instance_prototype(true); 12935 Isolate* isolate = new_map->GetIsolate(); 12936 12937 construct_prototype = handle( 12938 IsGeneratorFunction(function->shared()->kind()) 12939 ? function->context() 12940 ->native_context() 12941 ->initial_generator_prototype() 12942 : function->context()->native_context()->initial_object_prototype(), 12943 isolate); 12944 } else { 12945 function->map()->set_non_instance_prototype(false); 12946 } 12947 12948 return SetInstancePrototype(function, construct_prototype); 12949 } 12950 12951 12952 bool JSFunction::RemovePrototype() { 12953 Context* native_context = context()->native_context(); 12954 Map* no_prototype_map = 12955 is_strict(shared()->language_mode()) 12956 ? native_context->strict_function_without_prototype_map() 12957 : native_context->sloppy_function_without_prototype_map(); 12958 12959 if (map() == no_prototype_map) return true; 12960 12961 #ifdef DEBUG 12962 if (map() != (is_strict(shared()->language_mode()) 12963 ? native_context->strict_function_map() 12964 : native_context->sloppy_function_map())) { 12965 return false; 12966 } 12967 #endif 12968 12969 set_map(no_prototype_map); 12970 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value()); 12971 return true; 12972 } 12973 12974 12975 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map, 12976 Handle<Object> prototype) { 12977 if (map->prototype() != *prototype) { 12978 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 12979 } 12980 function->set_prototype_or_initial_map(*map); 12981 map->SetConstructor(*function); 12982 #if TRACE_MAPS 12983 if (FLAG_trace_maps) { 12984 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n", 12985 reinterpret_cast<void*>(*map), function->shared()->unique_id(), 12986 function->shared()->DebugName()->ToCString().get()); 12987 } 12988 #endif 12989 } 12990 12991 12992 #ifdef DEBUG 12993 namespace { 12994 12995 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) { 12996 switch (instance_type) { 12997 case JS_API_OBJECT_TYPE: 12998 case JS_ARRAY_BUFFER_TYPE: 12999 case JS_ARRAY_TYPE: 13000 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 13001 case JS_DATA_VIEW_TYPE: 13002 case JS_DATE_TYPE: 13003 case JS_FUNCTION_TYPE: 13004 case JS_GENERATOR_OBJECT_TYPE: 13005 case JS_MAP_ITERATOR_TYPE: 13006 case JS_MAP_TYPE: 13007 case JS_MESSAGE_OBJECT_TYPE: 13008 case JS_OBJECT_TYPE: 13009 case JS_ERROR_TYPE: 13010 case JS_ARGUMENTS_TYPE: 13011 case JS_PROMISE_TYPE: 13012 case JS_REGEXP_TYPE: 13013 case JS_SET_ITERATOR_TYPE: 13014 case JS_SET_TYPE: 13015 case JS_SPECIAL_API_OBJECT_TYPE: 13016 case JS_TYPED_ARRAY_TYPE: 13017 case JS_VALUE_TYPE: 13018 case JS_WEAK_MAP_TYPE: 13019 case JS_WEAK_SET_TYPE: 13020 return true; 13021 13022 case BYTECODE_ARRAY_TYPE: 13023 case BYTE_ARRAY_TYPE: 13024 case CELL_TYPE: 13025 case CODE_TYPE: 13026 case FILLER_TYPE: 13027 case FIXED_ARRAY_TYPE: 13028 case FIXED_DOUBLE_ARRAY_TYPE: 13029 case FOREIGN_TYPE: 13030 case FREE_SPACE_TYPE: 13031 case HEAP_NUMBER_TYPE: 13032 case JS_BOUND_FUNCTION_TYPE: 13033 case JS_GLOBAL_OBJECT_TYPE: 13034 case JS_GLOBAL_PROXY_TYPE: 13035 case JS_PROXY_TYPE: 13036 case MAP_TYPE: 13037 case MUTABLE_HEAP_NUMBER_TYPE: 13038 case ODDBALL_TYPE: 13039 case PROPERTY_CELL_TYPE: 13040 case SHARED_FUNCTION_INFO_TYPE: 13041 case SIMD128_VALUE_TYPE: 13042 case SYMBOL_TYPE: 13043 case WEAK_CELL_TYPE: 13044 13045 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 13046 case FIXED_##TYPE##_ARRAY_TYPE: 13047 #undef TYPED_ARRAY_CASE 13048 13049 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: 13050 STRUCT_LIST(MAKE_STRUCT_CASE) 13051 #undef MAKE_STRUCT_CASE 13052 // We must not end up here for these instance types at all. 13053 UNREACHABLE(); 13054 // Fall through. 13055 default: 13056 return false; 13057 } 13058 } 13059 13060 } // namespace 13061 #endif 13062 13063 13064 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { 13065 DCHECK(function->IsConstructor() || 13066 IsResumableFunction(function->shared()->kind())); 13067 if (function->has_initial_map()) return; 13068 Isolate* isolate = function->GetIsolate(); 13069 13070 // The constructor should be compiled for the optimization hints to be 13071 // available. 13072 Compiler::Compile(function, Compiler::CLEAR_EXCEPTION); 13073 13074 // First create a new map with the size and number of in-object properties 13075 // suggested by the function. 13076 InstanceType instance_type; 13077 if (IsResumableFunction(function->shared()->kind())) { 13078 instance_type = JS_GENERATOR_OBJECT_TYPE; 13079 } else { 13080 instance_type = JS_OBJECT_TYPE; 13081 } 13082 int instance_size; 13083 int in_object_properties; 13084 function->CalculateInstanceSize(instance_type, 0, &instance_size, 13085 &in_object_properties); 13086 13087 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size); 13088 13089 // Fetch or allocate prototype. 13090 Handle<Object> prototype; 13091 if (function->has_instance_prototype()) { 13092 prototype = handle(function->instance_prototype(), isolate); 13093 } else { 13094 prototype = isolate->factory()->NewFunctionPrototype(function); 13095 } 13096 map->SetInObjectProperties(in_object_properties); 13097 map->set_unused_property_fields(in_object_properties); 13098 DCHECK(map->has_fast_object_elements()); 13099 13100 // Finally link initial map and constructor function. 13101 DCHECK(prototype->IsJSReceiver()); 13102 JSFunction::SetInitialMap(function, map, prototype); 13103 map->StartInobjectSlackTracking(); 13104 } 13105 13106 13107 // static 13108 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate, 13109 Handle<JSFunction> constructor, 13110 Handle<JSReceiver> new_target) { 13111 EnsureHasInitialMap(constructor); 13112 13113 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate); 13114 if (*new_target == *constructor) return constructor_initial_map; 13115 13116 // Fast case, new.target is a subclass of constructor. The map is cacheable 13117 // (and may already have been cached). new.target.prototype is guaranteed to 13118 // be a JSReceiver. 13119 if (new_target->IsJSFunction()) { 13120 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); 13121 13122 // Check that |function|'s initial map still in sync with the |constructor|, 13123 // otherwise we must create a new initial map for |function|. 13124 if (function->has_initial_map() && 13125 function->initial_map()->GetConstructor() == *constructor) { 13126 return handle(function->initial_map(), isolate); 13127 } 13128 13129 // Create a new map with the size and number of in-object properties 13130 // suggested by |function|. 13131 13132 // Link initial map and constructor function if the new.target is actually a 13133 // subclass constructor. 13134 if (IsSubclassConstructor(function->shared()->kind())) { 13135 Handle<Object> prototype(function->instance_prototype(), isolate); 13136 InstanceType instance_type = constructor_initial_map->instance_type(); 13137 DCHECK(CanSubclassHaveInobjectProperties(instance_type)); 13138 int internal_fields = 13139 JSObject::GetInternalFieldCount(*constructor_initial_map); 13140 int pre_allocated = constructor_initial_map->GetInObjectProperties() - 13141 constructor_initial_map->unused_property_fields(); 13142 int instance_size; 13143 int in_object_properties; 13144 function->CalculateInstanceSizeForDerivedClass( 13145 instance_type, internal_fields, &instance_size, 13146 &in_object_properties); 13147 13148 int unused_property_fields = in_object_properties - pre_allocated; 13149 Handle<Map> map = 13150 Map::CopyInitialMap(constructor_initial_map, instance_size, 13151 in_object_properties, unused_property_fields); 13152 map->set_new_target_is_base(false); 13153 13154 JSFunction::SetInitialMap(function, map, prototype); 13155 map->SetConstructor(*constructor); 13156 map->set_construction_counter(Map::kNoSlackTracking); 13157 map->StartInobjectSlackTracking(); 13158 return map; 13159 } 13160 } 13161 13162 // Slow path, new.target is either a proxy or can't cache the map. 13163 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to 13164 // fall back to the intrinsicDefaultProto. 13165 Handle<Object> prototype; 13166 if (new_target->IsJSFunction()) { 13167 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); 13168 // Make sure the new.target.prototype is cached. 13169 EnsureHasInitialMap(function); 13170 prototype = handle(function->prototype(), isolate); 13171 } else { 13172 Handle<String> prototype_string = isolate->factory()->prototype_string(); 13173 ASSIGN_RETURN_ON_EXCEPTION( 13174 isolate, prototype, 13175 JSReceiver::GetProperty(new_target, prototype_string), Map); 13176 // The above prototype lookup might change the constructor and its 13177 // prototype, hence we have to reload the initial map. 13178 EnsureHasInitialMap(constructor); 13179 constructor_initial_map = handle(constructor->initial_map(), isolate); 13180 } 13181 13182 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the 13183 // correct realm. Rather than directly fetching the .prototype, we fetch the 13184 // constructor that points to the .prototype. This relies on 13185 // constructor.prototype being FROZEN for those constructors. 13186 if (!prototype->IsJSReceiver()) { 13187 Handle<Context> context; 13188 ASSIGN_RETURN_ON_EXCEPTION(isolate, context, 13189 JSReceiver::GetFunctionRealm(new_target), Map); 13190 DCHECK(context->IsNativeContext()); 13191 Handle<Object> maybe_index = JSReceiver::GetDataProperty( 13192 constructor, isolate->factory()->native_context_index_symbol()); 13193 int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value() 13194 : Context::OBJECT_FUNCTION_INDEX; 13195 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index))); 13196 prototype = handle(realm_constructor->prototype(), isolate); 13197 } 13198 13199 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); 13200 map->set_new_target_is_base(false); 13201 DCHECK(prototype->IsJSReceiver()); 13202 if (map->prototype() != *prototype) { 13203 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 13204 } 13205 map->SetConstructor(*constructor); 13206 return map; 13207 } 13208 13209 13210 void JSFunction::PrintName(FILE* out) { 13211 std::unique_ptr<char[]> name = shared()->DebugName()->ToCString(); 13212 PrintF(out, "%s", name.get()); 13213 } 13214 13215 13216 Handle<String> JSFunction::GetName(Handle<JSFunction> function) { 13217 Isolate* isolate = function->GetIsolate(); 13218 Handle<Object> name = 13219 JSReceiver::GetDataProperty(function, isolate->factory()->name_string()); 13220 if (name->IsString()) return Handle<String>::cast(name); 13221 return handle(function->shared()->DebugName(), isolate); 13222 } 13223 13224 13225 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) { 13226 Isolate* isolate = function->GetIsolate(); 13227 Handle<Object> name = JSReceiver::GetDataProperty( 13228 function, isolate->factory()->display_name_string()); 13229 if (name->IsString()) return Handle<String>::cast(name); 13230 return JSFunction::GetName(function); 13231 } 13232 13233 void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name, 13234 Handle<String> prefix) { 13235 Isolate* isolate = function->GetIsolate(); 13236 Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked(); 13237 if (prefix->length() > 0) { 13238 IncrementalStringBuilder builder(isolate); 13239 builder.AppendString(prefix); 13240 builder.AppendCharacter(' '); 13241 builder.AppendString(function_name); 13242 function_name = builder.Finish().ToHandleChecked(); 13243 } 13244 JSObject::DefinePropertyOrElementIgnoreAttributes( 13245 function, isolate->factory()->name_string(), function_name, 13246 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)) 13247 .ToHandleChecked(); 13248 } 13249 13250 namespace { 13251 13252 char const kNativeCodeSource[] = "function () { [native code] }"; 13253 13254 13255 Handle<String> NativeCodeFunctionSourceString( 13256 Handle<SharedFunctionInfo> shared_info) { 13257 Isolate* const isolate = shared_info->GetIsolate(); 13258 if (shared_info->name()->IsString()) { 13259 IncrementalStringBuilder builder(isolate); 13260 builder.AppendCString("function "); 13261 builder.AppendString(handle(String::cast(shared_info->name()), isolate)); 13262 builder.AppendCString("() { [native code] }"); 13263 return builder.Finish().ToHandleChecked(); 13264 } 13265 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource); 13266 } 13267 13268 } // namespace 13269 13270 13271 // static 13272 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) { 13273 Isolate* const isolate = function->GetIsolate(); 13274 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource); 13275 } 13276 13277 13278 // static 13279 Handle<String> JSFunction::ToString(Handle<JSFunction> function) { 13280 Isolate* const isolate = function->GetIsolate(); 13281 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate); 13282 13283 // Check if {function} should hide its source code. 13284 if (!shared_info->script()->IsScript() || 13285 Script::cast(shared_info->script())->hide_source()) { 13286 return NativeCodeFunctionSourceString(shared_info); 13287 } 13288 13289 // Check if we should print {function} as a class. 13290 Handle<Object> class_start_position = JSReceiver::GetDataProperty( 13291 function, isolate->factory()->class_start_position_symbol()); 13292 if (class_start_position->IsSmi()) { 13293 Handle<Object> class_end_position = JSReceiver::GetDataProperty( 13294 function, isolate->factory()->class_end_position_symbol()); 13295 Handle<String> script_source( 13296 String::cast(Script::cast(shared_info->script())->source()), isolate); 13297 return isolate->factory()->NewSubString( 13298 script_source, Handle<Smi>::cast(class_start_position)->value(), 13299 Handle<Smi>::cast(class_end_position)->value()); 13300 } 13301 13302 // Check if we have source code for the {function}. 13303 if (!shared_info->HasSourceCode()) { 13304 return NativeCodeFunctionSourceString(shared_info); 13305 } 13306 13307 IncrementalStringBuilder builder(isolate); 13308 FunctionKind kind = shared_info->kind(); 13309 if (!IsArrowFunction(kind)) { 13310 if (IsConciseMethod(kind)) { 13311 if (IsGeneratorFunction(kind)) { 13312 builder.AppendCharacter('*'); 13313 } else if (IsAsyncFunction(kind)) { 13314 builder.AppendCString("async "); 13315 } 13316 } else { 13317 if (IsGeneratorFunction(kind)) { 13318 builder.AppendCString("function* "); 13319 } else if (IsAsyncFunction(kind)) { 13320 builder.AppendCString("async function "); 13321 } else { 13322 builder.AppendCString("function "); 13323 } 13324 } 13325 if (shared_info->name_should_print_as_anonymous()) { 13326 builder.AppendCString("anonymous"); 13327 } else if (!shared_info->is_anonymous_expression()) { 13328 builder.AppendString(handle(String::cast(shared_info->name()), isolate)); 13329 } 13330 } 13331 builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode())); 13332 return builder.Finish().ToHandleChecked(); 13333 } 13334 13335 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball, 13336 const char* to_string, Handle<Object> to_number, 13337 const char* type_of, byte kind) { 13338 Handle<String> internalized_to_string = 13339 isolate->factory()->InternalizeUtf8String(to_string); 13340 Handle<String> internalized_type_of = 13341 isolate->factory()->InternalizeUtf8String(type_of); 13342 oddball->set_to_number_raw(to_number->Number()); 13343 oddball->set_to_number(*to_number); 13344 oddball->set_to_string(*internalized_to_string); 13345 oddball->set_type_of(*internalized_type_of); 13346 oddball->set_kind(kind); 13347 } 13348 13349 void Script::SetEvalOrigin(Handle<Script> script, 13350 Handle<SharedFunctionInfo> outer_info, 13351 int eval_position) { 13352 if (eval_position == kNoSourcePosition) { 13353 // If the position is missing, attempt to get the code offset from the 13354 // current activation. Do not translate the code offset into source 13355 // position, but store it as negative value for lazy translation. 13356 StackTraceFrameIterator it(script->GetIsolate()); 13357 if (!it.done() && it.is_javascript()) { 13358 FrameSummary summary = FrameSummary::GetFirst(it.javascript_frame()); 13359 script->set_eval_from_shared(summary.function()->shared()); 13360 script->set_eval_from_position(-summary.code_offset()); 13361 return; 13362 } 13363 eval_position = 0; 13364 } 13365 script->set_eval_from_shared(*outer_info); 13366 script->set_eval_from_position(eval_position); 13367 } 13368 13369 int Script::GetEvalPosition() { 13370 DisallowHeapAllocation no_gc; 13371 DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL); 13372 int position = eval_from_position(); 13373 if (position < 0) { 13374 // Due to laziness, the position may not have been translated from code 13375 // offset yet, which would be encoded as negative integer. In that case, 13376 // translate and set the position. 13377 if (eval_from_shared()->IsUndefined(GetIsolate())) { 13378 position = 0; 13379 } else { 13380 SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared()); 13381 position = shared->abstract_code()->SourcePosition(-position); 13382 } 13383 DCHECK(position >= 0); 13384 set_eval_from_position(position); 13385 } 13386 return position; 13387 } 13388 13389 void Script::InitLineEnds(Handle<Script> script) { 13390 Isolate* isolate = script->GetIsolate(); 13391 if (!script->line_ends()->IsUndefined(isolate)) return; 13392 DCHECK_NE(Script::TYPE_WASM, script->type()); 13393 13394 Object* src_obj = script->source(); 13395 if (!src_obj->IsString()) { 13396 DCHECK(src_obj->IsUndefined(isolate)); 13397 script->set_line_ends(isolate->heap()->empty_fixed_array()); 13398 } else { 13399 DCHECK(src_obj->IsString()); 13400 Handle<String> src(String::cast(src_obj), isolate); 13401 Handle<FixedArray> array = String::CalculateLineEnds(src, true); 13402 script->set_line_ends(*array); 13403 } 13404 13405 DCHECK(script->line_ends()->IsFixedArray()); 13406 } 13407 13408 bool Script::GetPositionInfo(Handle<Script> script, int position, 13409 PositionInfo* info, OffsetFlag offset_flag) { 13410 // For wasm, we do not create an artificial line_ends array, but do the 13411 // translation directly. 13412 if (script->type() == Script::TYPE_WASM) { 13413 Handle<WasmCompiledModule> compiled_module( 13414 WasmCompiledModule::cast(script->wasm_compiled_module())); 13415 DCHECK_LE(0, position); 13416 return wasm::GetPositionInfo(compiled_module, 13417 static_cast<uint32_t>(position), info); 13418 } 13419 13420 InitLineEnds(script); 13421 return script->GetPositionInfo(position, info, offset_flag); 13422 } 13423 13424 namespace { 13425 bool GetPositionInfoSlow(const Script* script, int position, 13426 Script::PositionInfo* info) { 13427 if (!script->source()->IsString()) return false; 13428 if (position < 0) position = 0; 13429 13430 String* source_string = String::cast(script->source()); 13431 int line = 0; 13432 int line_start = 0; 13433 int len = source_string->length(); 13434 for (int pos = 0; pos <= len; ++pos) { 13435 if (pos == len || source_string->Get(pos) == '\n') { 13436 if (position <= pos) { 13437 info->line = line; 13438 info->column = position - line_start; 13439 info->line_start = line_start; 13440 info->line_end = pos; 13441 return true; 13442 } 13443 line++; 13444 line_start = pos + 1; 13445 } 13446 } 13447 return false; 13448 } 13449 } // namespace 13450 13451 #define SMI_VALUE(x) (Smi::cast(x)->value()) 13452 bool Script::GetPositionInfo(int position, PositionInfo* info, 13453 OffsetFlag offset_flag) const { 13454 DisallowHeapAllocation no_allocation; 13455 13456 if (line_ends()->IsUndefined(GetIsolate())) { 13457 // Slow mode: we do not have line_ends. We have to iterate through source. 13458 if (!GetPositionInfoSlow(this, position, info)) return false; 13459 } else { 13460 DCHECK(line_ends()->IsFixedArray()); 13461 FixedArray* ends = FixedArray::cast(line_ends()); 13462 13463 const int ends_len = ends->length(); 13464 if (ends_len == 0) return false; 13465 13466 // Return early on invalid positions. Negative positions behave as if 0 was 13467 // passed, and positions beyond the end of the script return as failure. 13468 if (position < 0) { 13469 position = 0; 13470 } else if (position > SMI_VALUE(ends->get(ends_len - 1))) { 13471 return false; 13472 } 13473 13474 // Determine line number by doing a binary search on the line ends array. 13475 if (SMI_VALUE(ends->get(0)) >= position) { 13476 info->line = 0; 13477 info->line_start = 0; 13478 info->column = position; 13479 } else { 13480 int left = 0; 13481 int right = ends_len - 1; 13482 13483 while (right > 0) { 13484 DCHECK_LE(left, right); 13485 const int mid = (left + right) / 2; 13486 if (position > SMI_VALUE(ends->get(mid))) { 13487 left = mid + 1; 13488 } else if (position <= SMI_VALUE(ends->get(mid - 1))) { 13489 right = mid - 1; 13490 } else { 13491 info->line = mid; 13492 break; 13493 } 13494 } 13495 DCHECK(SMI_VALUE(ends->get(info->line)) >= position && 13496 SMI_VALUE(ends->get(info->line - 1)) < position); 13497 info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1; 13498 info->column = position - info->line_start; 13499 } 13500 13501 // Line end is position of the linebreak character. 13502 info->line_end = SMI_VALUE(ends->get(info->line)); 13503 if (info->line_end > 0) { 13504 DCHECK(source()->IsString()); 13505 String* src = String::cast(source()); 13506 if (src->length() >= info->line_end && 13507 src->Get(info->line_end - 1) == '\r') { 13508 info->line_end--; 13509 } 13510 } 13511 } 13512 13513 // Add offsets if requested. 13514 if (offset_flag == WITH_OFFSET) { 13515 if (info->line == 0) { 13516 info->column += column_offset(); 13517 } 13518 info->line += line_offset(); 13519 } 13520 13521 return true; 13522 } 13523 #undef SMI_VALUE 13524 13525 int Script::GetColumnNumber(Handle<Script> script, int code_pos) { 13526 PositionInfo info; 13527 GetPositionInfo(script, code_pos, &info, WITH_OFFSET); 13528 return info.column; 13529 } 13530 13531 int Script::GetColumnNumber(int code_pos) const { 13532 PositionInfo info; 13533 GetPositionInfo(code_pos, &info, WITH_OFFSET); 13534 return info.column; 13535 } 13536 13537 int Script::GetLineNumber(Handle<Script> script, int code_pos) { 13538 PositionInfo info; 13539 GetPositionInfo(script, code_pos, &info, WITH_OFFSET); 13540 return info.line; 13541 } 13542 13543 int Script::GetLineNumber(int code_pos) const { 13544 PositionInfo info; 13545 GetPositionInfo(code_pos, &info, WITH_OFFSET); 13546 return info.line; 13547 } 13548 13549 Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) { 13550 Isolate* isolate = script->GetIsolate(); 13551 13552 // Keep in sync with ScriptNameOrSourceURL in messages.js. 13553 13554 if (!script->source_url()->IsUndefined(isolate)) { 13555 return handle(script->source_url(), isolate); 13556 } 13557 return handle(script->name(), isolate); 13558 } 13559 13560 13561 Handle<JSObject> Script::GetWrapper(Handle<Script> script) { 13562 Isolate* isolate = script->GetIsolate(); 13563 if (!script->wrapper()->IsUndefined(isolate)) { 13564 DCHECK(script->wrapper()->IsWeakCell()); 13565 Handle<WeakCell> cell(WeakCell::cast(script->wrapper())); 13566 if (!cell->cleared()) { 13567 // Return a handle for the existing script wrapper from the cache. 13568 return handle(JSObject::cast(cell->value())); 13569 } 13570 // If we found an empty WeakCell, that means the script wrapper was 13571 // GCed. We are not notified directly of that, so we decrement here 13572 // so that we at least don't count double for any given script. 13573 isolate->counters()->script_wrappers()->Decrement(); 13574 } 13575 // Construct a new script wrapper. 13576 isolate->counters()->script_wrappers()->Increment(); 13577 Handle<JSFunction> constructor = isolate->script_function(); 13578 Handle<JSValue> result = 13579 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor)); 13580 result->set_value(*script); 13581 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result); 13582 script->set_wrapper(*cell); 13583 return result; 13584 } 13585 13586 13587 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( 13588 FunctionLiteral* fun) { 13589 WeakFixedArray::Iterator iterator(shared_function_infos()); 13590 SharedFunctionInfo* shared; 13591 while ((shared = iterator.Next<SharedFunctionInfo>())) { 13592 if (fun->function_token_position() == shared->function_token_position() && 13593 fun->start_position() == shared->start_position() && 13594 fun->end_position() == shared->end_position()) { 13595 return Handle<SharedFunctionInfo>(shared); 13596 } 13597 } 13598 return MaybeHandle<SharedFunctionInfo>(); 13599 } 13600 13601 13602 Script::Iterator::Iterator(Isolate* isolate) 13603 : iterator_(isolate->heap()->script_list()) {} 13604 13605 13606 Script* Script::Iterator::Next() { return iterator_.Next<Script>(); } 13607 13608 13609 SharedFunctionInfo::Iterator::Iterator(Isolate* isolate) 13610 : script_iterator_(isolate), 13611 sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {} 13612 13613 13614 bool SharedFunctionInfo::Iterator::NextScript() { 13615 Script* script = script_iterator_.Next(); 13616 if (script == NULL) return false; 13617 sfi_iterator_.Reset(script->shared_function_infos()); 13618 return true; 13619 } 13620 13621 13622 SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() { 13623 do { 13624 SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>(); 13625 if (next != NULL) return next; 13626 } while (NextScript()); 13627 return NULL; 13628 } 13629 13630 13631 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared, 13632 Handle<Object> script_object) { 13633 if (shared->script() == *script_object) return; 13634 Isolate* isolate = shared->GetIsolate(); 13635 13636 // Add shared function info to new script's list. If a collection occurs, 13637 // the shared function info may be temporarily in two lists. 13638 // This is okay because the gc-time processing of these lists can tolerate 13639 // duplicates. 13640 Handle<Object> list; 13641 if (script_object->IsScript()) { 13642 Handle<Script> script = Handle<Script>::cast(script_object); 13643 list = handle(script->shared_function_infos(), isolate); 13644 } else { 13645 list = isolate->factory()->noscript_shared_function_infos(); 13646 } 13647 13648 #ifdef DEBUG 13649 if (FLAG_enable_slow_asserts) { 13650 WeakFixedArray::Iterator iterator(*list); 13651 SharedFunctionInfo* next; 13652 while ((next = iterator.Next<SharedFunctionInfo>())) { 13653 DCHECK_NE(next, *shared); 13654 } 13655 } 13656 #endif // DEBUG 13657 list = WeakFixedArray::Add(list, shared); 13658 13659 if (script_object->IsScript()) { 13660 Handle<Script> script = Handle<Script>::cast(script_object); 13661 script->set_shared_function_infos(*list); 13662 } else { 13663 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list); 13664 } 13665 13666 // Remove shared function info from old script's list. 13667 if (shared->script()->IsScript()) { 13668 Script* old_script = Script::cast(shared->script()); 13669 if (old_script->shared_function_infos()->IsWeakFixedArray()) { 13670 WeakFixedArray* list = 13671 WeakFixedArray::cast(old_script->shared_function_infos()); 13672 list->Remove(shared); 13673 } 13674 } else { 13675 // Remove shared function info from root array. 13676 Object* list = isolate->heap()->noscript_shared_function_infos(); 13677 CHECK(WeakFixedArray::cast(list)->Remove(shared)); 13678 } 13679 13680 // Finally set new script. 13681 shared->set_script(*script_object); 13682 } 13683 13684 13685 String* SharedFunctionInfo::DebugName() { 13686 Object* n = name(); 13687 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name(); 13688 return String::cast(n); 13689 } 13690 13691 // The filter is a pattern that matches function names in this way: 13692 // "*" all; the default 13693 // "-" all but the top-level function 13694 // "-name" all but the function "name" 13695 // "" only the top-level function 13696 // "name" only the function "name" 13697 // "name*" only functions starting with "name" 13698 // "~" none; the tilde is not an identifier 13699 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) { 13700 if (*raw_filter == '*') return true; 13701 String* name = DebugName(); 13702 Vector<const char> filter = CStrVector(raw_filter); 13703 if (filter.length() == 0) return name->length() == 0; 13704 if (filter[0] == '-') { 13705 // Negative filter. 13706 if (filter.length() == 1) { 13707 return (name->length() != 0); 13708 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) { 13709 return false; 13710 } 13711 if (filter[filter.length() - 1] == '*' && 13712 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) { 13713 return false; 13714 } 13715 return true; 13716 13717 } else if (name->IsUtf8EqualTo(filter)) { 13718 return true; 13719 } 13720 if (filter[filter.length() - 1] == '*' && 13721 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) { 13722 return true; 13723 } 13724 return false; 13725 } 13726 13727 bool SharedFunctionInfo::HasSourceCode() const { 13728 Isolate* isolate = GetIsolate(); 13729 return !script()->IsUndefined(isolate) && 13730 !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate); 13731 } 13732 13733 13734 Handle<Object> SharedFunctionInfo::GetSourceCode() { 13735 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value(); 13736 Handle<String> source(String::cast(Script::cast(script())->source())); 13737 return GetIsolate()->factory()->NewSubString( 13738 source, start_position(), end_position()); 13739 } 13740 13741 13742 bool SharedFunctionInfo::IsInlineable() { 13743 // Check that the function has a script associated with it. 13744 if (!script()->IsScript()) return false; 13745 return !optimization_disabled(); 13746 } 13747 13748 13749 int SharedFunctionInfo::SourceSize() { 13750 return end_position() - start_position(); 13751 } 13752 13753 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type, 13754 int requested_internal_fields, 13755 int requested_in_object_properties, 13756 int* instance_size, 13757 int* in_object_properties) { 13758 int header_size = JSObject::GetHeaderSize(instance_type); 13759 DCHECK_LE(requested_internal_fields, 13760 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2); 13761 *instance_size = 13762 Min(header_size + 13763 ((requested_internal_fields + requested_in_object_properties) 13764 << kPointerSizeLog2), 13765 JSObject::kMaxInstanceSize); 13766 *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) - 13767 requested_internal_fields; 13768 } 13769 13770 13771 void JSFunction::CalculateInstanceSize(InstanceType instance_type, 13772 int requested_internal_fields, 13773 int* instance_size, 13774 int* in_object_properties) { 13775 CalculateInstanceSizeHelper(instance_type, requested_internal_fields, 13776 shared()->expected_nof_properties(), 13777 instance_size, in_object_properties); 13778 } 13779 13780 13781 void JSFunction::CalculateInstanceSizeForDerivedClass( 13782 InstanceType instance_type, int requested_internal_fields, 13783 int* instance_size, int* in_object_properties) { 13784 Isolate* isolate = GetIsolate(); 13785 int expected_nof_properties = 0; 13786 for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd(); 13787 iter.Advance()) { 13788 JSReceiver* current = iter.GetCurrent<JSReceiver>(); 13789 if (!current->IsJSFunction()) break; 13790 JSFunction* func = JSFunction::cast(current); 13791 SharedFunctionInfo* shared = func->shared(); 13792 expected_nof_properties += shared->expected_nof_properties(); 13793 if (!IsSubclassConstructor(shared->kind())) { 13794 break; 13795 } 13796 } 13797 CalculateInstanceSizeHelper(instance_type, requested_internal_fields, 13798 expected_nof_properties, instance_size, 13799 in_object_properties); 13800 } 13801 13802 13803 // Output the source code without any allocation in the heap. 13804 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) { 13805 const SharedFunctionInfo* s = v.value; 13806 // For some native functions there is no source. 13807 if (!s->HasSourceCode()) return os << "<No Source>"; 13808 13809 // Get the source for the script which this function came from. 13810 // Don't use String::cast because we don't want more assertion errors while 13811 // we are already creating a stack dump. 13812 String* script_source = 13813 reinterpret_cast<String*>(Script::cast(s->script())->source()); 13814 13815 if (!script_source->LooksValid()) return os << "<Invalid Source>"; 13816 13817 if (!s->is_toplevel()) { 13818 os << "function "; 13819 Object* name = s->name(); 13820 if (name->IsString() && String::cast(name)->length() > 0) { 13821 String::cast(name)->PrintUC16(os); 13822 } 13823 } 13824 13825 int len = s->end_position() - s->start_position(); 13826 if (len <= v.max_length || v.max_length < 0) { 13827 script_source->PrintUC16(os, s->start_position(), s->end_position()); 13828 return os; 13829 } else { 13830 script_source->PrintUC16(os, s->start_position(), 13831 s->start_position() + v.max_length); 13832 return os << "...\n"; 13833 } 13834 } 13835 13836 13837 static bool IsCodeEquivalent(Code* code, Code* recompiled) { 13838 if (code->instruction_size() != recompiled->instruction_size()) return false; 13839 ByteArray* code_relocation = code->relocation_info(); 13840 ByteArray* recompiled_relocation = recompiled->relocation_info(); 13841 int length = code_relocation->length(); 13842 if (length != recompiled_relocation->length()) return false; 13843 int compare = memcmp(code_relocation->GetDataStartAddress(), 13844 recompiled_relocation->GetDataStartAddress(), 13845 length); 13846 return compare == 0; 13847 } 13848 13849 13850 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) { 13851 DCHECK(!has_deoptimization_support()); 13852 DisallowHeapAllocation no_allocation; 13853 Code* code = this->code(); 13854 if (IsCodeEquivalent(code, recompiled)) { 13855 // Copy the deoptimization data from the recompiled code. 13856 code->set_deoptimization_data(recompiled->deoptimization_data()); 13857 code->set_has_deoptimization_support(true); 13858 } else { 13859 // TODO(3025757): In case the recompiled isn't equivalent to the 13860 // old code, we have to replace it. We should try to avoid this 13861 // altogether because it flushes valuable type feedback by 13862 // effectively resetting all IC state. 13863 ReplaceCode(recompiled); 13864 } 13865 DCHECK(has_deoptimization_support()); 13866 } 13867 13868 13869 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) { 13870 // Disable optimization for the shared function info and mark the 13871 // code as non-optimizable. The marker on the shared function info 13872 // is there because we flush non-optimized code thereby loosing the 13873 // non-optimizable information for the code. When the code is 13874 // regenerated and set on the shared function info it is marked as 13875 // non-optimizable if optimization is disabled for the shared 13876 // function info. 13877 DCHECK(reason != kNoReason); 13878 set_optimization_disabled(true); 13879 set_disable_optimization_reason(reason); 13880 // Code should be the lazy compilation stub or else unoptimized. 13881 DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION || 13882 abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION || 13883 abstract_code()->kind() == AbstractCode::BUILTIN); 13884 PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this)); 13885 if (FLAG_trace_opt) { 13886 PrintF("[disabled optimization for "); 13887 ShortPrint(); 13888 PrintF(", reason: %s]\n", GetBailoutReason(reason)); 13889 } 13890 } 13891 13892 namespace { 13893 13894 // Sets the expected number of properties based on estimate from parser. 13895 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, 13896 FunctionLiteral* literal) { 13897 int estimate = literal->expected_property_count(); 13898 13899 // If no properties are added in the constructor, they are more likely 13900 // to be added later. 13901 if (estimate == 0) estimate = 2; 13902 13903 // TODO(yangguo): check whether those heuristics are still up-to-date. 13904 // We do not shrink objects that go into a snapshot (yet), so we adjust 13905 // the estimate conservatively. 13906 if (shared->GetIsolate()->serializer_enabled()) { 13907 estimate += 2; 13908 } else { 13909 // Inobject slack tracking will reclaim redundant inobject space later, 13910 // so we can afford to adjust the estimate generously. 13911 estimate += 8; 13912 } 13913 13914 shared->set_expected_nof_properties(estimate); 13915 } 13916 13917 } // namespace 13918 13919 void SharedFunctionInfo::InitFromFunctionLiteral( 13920 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) { 13921 // When adding fields here, make sure DeclarationScope::AnalyzePartially is 13922 // updated accordingly. 13923 shared_info->set_length(lit->function_length()); 13924 shared_info->set_internal_formal_parameter_count(lit->parameter_count()); 13925 shared_info->set_function_token_position(lit->function_token_position()); 13926 shared_info->set_start_position(lit->start_position()); 13927 shared_info->set_end_position(lit->end_position()); 13928 shared_info->set_is_declaration(lit->is_declaration()); 13929 shared_info->set_is_named_expression(lit->is_named_expression()); 13930 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression()); 13931 shared_info->set_inferred_name(*lit->inferred_name()); 13932 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); 13933 shared_info->set_language_mode(lit->language_mode()); 13934 shared_info->set_uses_arguments(lit->scope()->arguments() != NULL); 13935 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); 13936 shared_info->set_is_function(lit->is_function()); 13937 shared_info->set_never_compiled(true); 13938 shared_info->set_kind(lit->kind()); 13939 if (!IsConstructable(lit->kind(), lit->language_mode())) { 13940 shared_info->SetConstructStub( 13941 *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable()); 13942 } 13943 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject()); 13944 shared_info->set_asm_function(lit->scope()->asm_function()); 13945 shared_info->set_requires_class_field_init(lit->requires_class_field_init()); 13946 shared_info->set_is_class_field_initializer( 13947 lit->is_class_field_initializer()); 13948 SetExpectedNofPropertiesFromEstimate(shared_info, lit); 13949 } 13950 13951 13952 bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) { 13953 DCHECK(!id.IsNone()); 13954 Code* unoptimized = code(); 13955 DeoptimizationOutputData* data = 13956 DeoptimizationOutputData::cast(unoptimized->deoptimization_data()); 13957 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this); 13958 USE(ignore); 13959 return true; // Return true if there was no DCHECK. 13960 } 13961 13962 void SharedFunctionInfo::SetConstructStub(Code* code) { 13963 if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true); 13964 set_construct_stub(code); 13965 } 13966 13967 void Map::StartInobjectSlackTracking() { 13968 DCHECK(!IsInobjectSlackTrackingInProgress()); 13969 13970 // No tracking during the snapshot construction phase. 13971 Isolate* isolate = GetIsolate(); 13972 if (isolate->serializer_enabled()) return; 13973 13974 if (unused_property_fields() == 0) return; 13975 13976 set_construction_counter(Map::kSlackTrackingCounterStart); 13977 } 13978 13979 13980 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) { 13981 code()->ClearInlineCaches(); 13982 set_ic_age(new_ic_age); 13983 if (code()->kind() == Code::FUNCTION) { 13984 code()->set_profiler_ticks(0); 13985 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) { 13986 // Re-enable optimizations if they were disabled due to opt_count limit. 13987 set_optimization_disabled(false); 13988 } 13989 set_opt_count(0); 13990 set_deopt_count(0); 13991 } else if (IsInterpreted()) { 13992 set_profiler_ticks(0); 13993 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) { 13994 // Re-enable optimizations if they were disabled due to opt_count limit. 13995 set_optimization_disabled(false); 13996 } 13997 set_opt_count(0); 13998 set_deopt_count(0); 13999 } 14000 } 14001 14002 14003 int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context, 14004 BailoutId osr_ast_id) { 14005 DisallowHeapAllocation no_gc; 14006 DCHECK(native_context->IsNativeContext()); 14007 if (!OptimizedCodeMapIsCleared()) { 14008 FixedArray* optimized_code_map = this->optimized_code_map(); 14009 int length = optimized_code_map->length(); 14010 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt()); 14011 for (int i = kEntriesStart; i < length; i += kEntryLength) { 14012 if (WeakCell::cast(optimized_code_map->get(i + kContextOffset)) 14013 ->value() == native_context && 14014 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) { 14015 return i; 14016 } 14017 } 14018 } 14019 return -1; 14020 } 14021 14022 void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() { 14023 if (!OptimizedCodeMapIsCleared()) { 14024 FixedArray* optimized_code_map = this->optimized_code_map(); 14025 int length = optimized_code_map->length(); 14026 WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell(); 14027 for (int i = kEntriesStart; i < length; i += kEntryLength) { 14028 optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell, 14029 SKIP_WRITE_BARRIER); 14030 } 14031 } 14032 } 14033 14034 CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap( 14035 Context* native_context, BailoutId osr_ast_id) { 14036 CodeAndLiterals result = {nullptr, nullptr}; 14037 int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id); 14038 if (entry != kNotFound) { 14039 FixedArray* code_map = optimized_code_map(); 14040 DCHECK_LE(entry + kEntryLength, code_map->length()); 14041 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset)); 14042 WeakCell* literals_cell = 14043 WeakCell::cast(code_map->get(entry + kLiteralsOffset)); 14044 14045 result = {cell->cleared() ? nullptr : Code::cast(cell->value()), 14046 literals_cell->cleared() ? nullptr : LiteralsArray::cast( 14047 literals_cell->value())}; 14048 } 14049 return result; 14050 } 14051 14052 14053 #define DECLARE_TAG(ignore1, name, ignore2) name, 14054 const char* const VisitorSynchronization::kTags[ 14055 VisitorSynchronization::kNumberOfSyncTags] = { 14056 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG) 14057 }; 14058 #undef DECLARE_TAG 14059 14060 14061 #define DECLARE_TAG(ignore1, ignore2, name) name, 14062 const char* const VisitorSynchronization::kTagNames[ 14063 VisitorSynchronization::kNumberOfSyncTags] = { 14064 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG) 14065 }; 14066 #undef DECLARE_TAG 14067 14068 14069 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { 14070 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); 14071 Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address()); 14072 Object* new_pointer = old_pointer; 14073 VisitPointer(&new_pointer); 14074 DCHECK_EQ(old_pointer, new_pointer); 14075 } 14076 14077 14078 void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) { 14079 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); 14080 Object* old_pointer = rinfo->code_age_stub(); 14081 Object* new_pointer = old_pointer; 14082 if (old_pointer != nullptr) { 14083 VisitPointer(&new_pointer); 14084 DCHECK_EQ(old_pointer, new_pointer); 14085 } 14086 } 14087 14088 14089 void ObjectVisitor::VisitCodeEntry(Address entry_address) { 14090 Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address); 14091 Object* new_pointer = old_pointer; 14092 VisitPointer(&new_pointer); 14093 DCHECK_EQ(old_pointer, new_pointer); 14094 } 14095 14096 14097 void ObjectVisitor::VisitCell(RelocInfo* rinfo) { 14098 DCHECK(rinfo->rmode() == RelocInfo::CELL); 14099 Object* old_pointer = rinfo->target_cell(); 14100 Object* new_pointer = old_pointer; 14101 VisitPointer(&new_pointer); 14102 DCHECK_EQ(old_pointer, new_pointer); 14103 } 14104 14105 14106 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) { 14107 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 14108 rinfo->IsPatchedDebugBreakSlotSequence()); 14109 Object* old_pointer = 14110 Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); 14111 Object* new_pointer = old_pointer; 14112 VisitPointer(&new_pointer); 14113 DCHECK_EQ(old_pointer, new_pointer); 14114 } 14115 14116 14117 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) { 14118 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); 14119 Object* old_pointer = rinfo->target_object(); 14120 Object* new_pointer = old_pointer; 14121 VisitPointer(&new_pointer); 14122 DCHECK_EQ(old_pointer, new_pointer); 14123 } 14124 14125 14126 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) { 14127 Address old_reference = rinfo->target_external_reference(); 14128 Address new_reference = old_reference; 14129 VisitExternalReference(&new_reference); 14130 DCHECK_EQ(old_reference, new_reference); 14131 } 14132 14133 14134 void Code::InvalidateRelocation() { 14135 InvalidateEmbeddedObjects(); 14136 set_relocation_info(GetHeap()->empty_byte_array()); 14137 } 14138 14139 14140 void Code::InvalidateEmbeddedObjects() { 14141 Object* undefined = GetHeap()->undefined_value(); 14142 Cell* undefined_cell = GetHeap()->undefined_cell(); 14143 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 14144 RelocInfo::ModeMask(RelocInfo::CELL); 14145 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 14146 RelocInfo::Mode mode = it.rinfo()->rmode(); 14147 if (mode == RelocInfo::EMBEDDED_OBJECT) { 14148 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER); 14149 } else if (mode == RelocInfo::CELL) { 14150 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER); 14151 } 14152 } 14153 } 14154 14155 14156 void Code::Relocate(intptr_t delta) { 14157 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { 14158 it.rinfo()->apply(delta); 14159 } 14160 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size()); 14161 } 14162 14163 14164 void Code::CopyFrom(const CodeDesc& desc) { 14165 // copy code 14166 CopyBytes(instruction_start(), desc.buffer, 14167 static_cast<size_t>(desc.instr_size)); 14168 14169 // copy unwinding info, if any 14170 if (desc.unwinding_info) { 14171 DCHECK_GT(desc.unwinding_info_size, 0); 14172 set_unwinding_info_size(desc.unwinding_info_size); 14173 CopyBytes(unwinding_info_start(), desc.unwinding_info, 14174 static_cast<size_t>(desc.unwinding_info_size)); 14175 } 14176 14177 // copy reloc info 14178 CopyBytes(relocation_start(), 14179 desc.buffer + desc.buffer_size - desc.reloc_size, 14180 static_cast<size_t>(desc.reloc_size)); 14181 14182 // unbox handles and relocate 14183 intptr_t delta = instruction_start() - desc.buffer; 14184 int mode_mask = RelocInfo::kCodeTargetMask | 14185 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 14186 RelocInfo::ModeMask(RelocInfo::CELL) | 14187 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | 14188 RelocInfo::kApplyMask; 14189 // Needed to find target_object and runtime_entry on X64 14190 Assembler* origin = desc.origin; 14191 AllowDeferredHandleDereference embedding_raw_address; 14192 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 14193 RelocInfo::Mode mode = it.rinfo()->rmode(); 14194 if (mode == RelocInfo::EMBEDDED_OBJECT) { 14195 Handle<Object> p = it.rinfo()->target_object_handle(origin); 14196 it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER, 14197 SKIP_ICACHE_FLUSH); 14198 } else if (mode == RelocInfo::CELL) { 14199 Handle<Cell> cell = it.rinfo()->target_cell_handle(); 14200 it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER, 14201 SKIP_ICACHE_FLUSH); 14202 } else if (RelocInfo::IsCodeTarget(mode)) { 14203 // rewrite code handles in inline cache targets to direct 14204 // pointers to the first instruction in the code object 14205 Handle<Object> p = it.rinfo()->target_object_handle(origin); 14206 Code* code = Code::cast(*p); 14207 it.rinfo()->set_target_address(code->instruction_start(), 14208 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); 14209 } else if (RelocInfo::IsRuntimeEntry(mode)) { 14210 Address p = it.rinfo()->target_runtime_entry(origin); 14211 it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER, 14212 SKIP_ICACHE_FLUSH); 14213 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) { 14214 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin); 14215 Code* code = Code::cast(*p); 14216 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH); 14217 } else { 14218 it.rinfo()->apply(delta); 14219 } 14220 } 14221 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size()); 14222 } 14223 14224 14225 SafepointEntry Code::GetSafepointEntry(Address pc) { 14226 SafepointTable table(this); 14227 return table.FindEntry(pc); 14228 } 14229 14230 14231 Object* Code::FindNthObject(int n, Map* match_map) { 14232 DCHECK(is_inline_cache_stub()); 14233 DisallowHeapAllocation no_allocation; 14234 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 14235 for (RelocIterator it(this, mask); !it.done(); it.next()) { 14236 RelocInfo* info = it.rinfo(); 14237 Object* object = info->target_object(); 14238 if (object->IsWeakCell()) object = WeakCell::cast(object)->value(); 14239 if (object->IsHeapObject()) { 14240 if (HeapObject::cast(object)->map() == match_map) { 14241 if (--n == 0) return object; 14242 } 14243 } 14244 } 14245 return NULL; 14246 } 14247 14248 14249 AllocationSite* Code::FindFirstAllocationSite() { 14250 Object* result = FindNthObject(1, GetHeap()->allocation_site_map()); 14251 return (result != NULL) ? AllocationSite::cast(result) : NULL; 14252 } 14253 14254 14255 Map* Code::FindFirstMap() { 14256 Object* result = FindNthObject(1, GetHeap()->meta_map()); 14257 return (result != NULL) ? Map::cast(result) : NULL; 14258 } 14259 14260 14261 void Code::FindAndReplace(const FindAndReplacePattern& pattern) { 14262 DCHECK(is_inline_cache_stub() || is_handler()); 14263 DisallowHeapAllocation no_allocation; 14264 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 14265 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32); 14266 int current_pattern = 0; 14267 for (RelocIterator it(this, mask); !it.done(); it.next()) { 14268 RelocInfo* info = it.rinfo(); 14269 Object* object = info->target_object(); 14270 if (object->IsHeapObject()) { 14271 if (object->IsWeakCell()) { 14272 object = HeapObject::cast(WeakCell::cast(object)->value()); 14273 } 14274 Map* map = HeapObject::cast(object)->map(); 14275 if (map == *pattern.find_[current_pattern]) { 14276 info->set_target_object(*pattern.replace_[current_pattern]); 14277 if (++current_pattern == pattern.count_) return; 14278 } 14279 } 14280 } 14281 UNREACHABLE(); 14282 } 14283 14284 14285 void Code::ClearInlineCaches() { 14286 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | 14287 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); 14288 for (RelocIterator it(this, mask); !it.done(); it.next()) { 14289 RelocInfo* info = it.rinfo(); 14290 Code* target(Code::GetCodeFromTargetAddress(info->target_address())); 14291 if (target->is_inline_cache_stub()) { 14292 IC::Clear(this->GetIsolate(), info->pc(), info->host()->constant_pool()); 14293 } 14294 } 14295 } 14296 14297 int AbstractCode::SourcePosition(int offset) { 14298 int position = 0; 14299 // Subtract one because the current PC is one instruction after the call site. 14300 if (IsCode()) offset--; 14301 for (SourcePositionTableIterator iterator(source_position_table()); 14302 !iterator.done() && iterator.code_offset() <= offset; 14303 iterator.Advance()) { 14304 position = iterator.source_position().ScriptOffset(); 14305 } 14306 return position; 14307 } 14308 14309 int AbstractCode::SourceStatementPosition(int offset) { 14310 // First find the closest position. 14311 int position = SourcePosition(offset); 14312 // Now find the closest statement position before the position. 14313 int statement_position = 0; 14314 for (SourcePositionTableIterator it(source_position_table()); !it.done(); 14315 it.Advance()) { 14316 if (it.is_statement()) { 14317 int p = it.source_position().ScriptOffset(); 14318 if (statement_position < p && p <= position) { 14319 statement_position = p; 14320 } 14321 } 14322 } 14323 return statement_position; 14324 } 14325 14326 void JSFunction::ClearTypeFeedbackInfo() { 14327 feedback_vector()->ClearSlots(shared()); 14328 } 14329 14330 void JSFunction::ClearTypeFeedbackInfoAtGCTime() { 14331 feedback_vector()->ClearSlotsAtGCTime(shared()); 14332 } 14333 14334 BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) { 14335 DisallowHeapAllocation no_gc; 14336 DCHECK(kind() == FUNCTION); 14337 BackEdgeTable back_edges(this, &no_gc); 14338 for (uint32_t i = 0; i < back_edges.length(); i++) { 14339 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i); 14340 } 14341 return BailoutId::None(); 14342 } 14343 14344 14345 uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) { 14346 DisallowHeapAllocation no_gc; 14347 DCHECK(kind() == FUNCTION); 14348 BackEdgeTable back_edges(this, &no_gc); 14349 for (uint32_t i = 0; i < back_edges.length(); i++) { 14350 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i); 14351 } 14352 UNREACHABLE(); // We expect to find the back edge. 14353 return 0; 14354 } 14355 14356 int Code::LookupRangeInHandlerTable(int code_offset, int* data, 14357 HandlerTable::CatchPrediction* prediction) { 14358 DCHECK(!is_optimized_code()); 14359 HandlerTable* table = HandlerTable::cast(handler_table()); 14360 return table->LookupRange(code_offset, data, prediction); 14361 } 14362 14363 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) { 14364 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY); 14365 } 14366 14367 14368 void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) { 14369 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge, 14370 NO_MARKING_PARITY); 14371 } 14372 14373 14374 // NextAge defines the Code::Age state transitions during a GC cycle. 14375 static Code::Age NextAge(Code::Age age) { 14376 switch (age) { 14377 case Code::kNotExecutedCodeAge: // Keep, until we've been executed. 14378 case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed. 14379 case Code::kLastCodeAge: // Clamp at last Code::Age value. 14380 return age; 14381 case Code::kExecutedOnceCodeAge: 14382 // Pre-age code that has only been executed once. 14383 return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1); 14384 default: 14385 return static_cast<Code::Age>(age + 1); // Default case: Increase age. 14386 } 14387 } 14388 14389 14390 // IsOldAge defines the collection criteria for a Code object. 14391 static bool IsOldAge(Code::Age age) { 14392 return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge; 14393 } 14394 14395 14396 void Code::MakeYoung(Isolate* isolate) { 14397 byte* sequence = FindCodeAgeSequence(); 14398 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate); 14399 } 14400 14401 void Code::PreAge(Isolate* isolate) { 14402 byte* sequence = FindCodeAgeSequence(); 14403 if (sequence != NULL) { 14404 PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge, NO_MARKING_PARITY); 14405 } 14406 } 14407 14408 void Code::MarkToBeExecutedOnce(Isolate* isolate) { 14409 byte* sequence = FindCodeAgeSequence(); 14410 if (sequence != NULL) { 14411 PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge, 14412 NO_MARKING_PARITY); 14413 } 14414 } 14415 14416 void Code::MakeOlder(MarkingParity current_parity) { 14417 byte* sequence = FindCodeAgeSequence(); 14418 if (sequence != NULL) { 14419 Age age; 14420 MarkingParity code_parity; 14421 Isolate* isolate = GetIsolate(); 14422 GetCodeAgeAndParity(isolate, sequence, &age, &code_parity); 14423 Age next_age = NextAge(age); 14424 if (age != next_age && code_parity != current_parity) { 14425 PatchPlatformCodeAge(isolate, sequence, next_age, current_parity); 14426 } 14427 } 14428 } 14429 14430 14431 bool Code::IsOld() { 14432 return IsOldAge(GetAge()); 14433 } 14434 14435 14436 byte* Code::FindCodeAgeSequence() { 14437 return FLAG_age_code && 14438 prologue_offset() != Code::kPrologueOffsetNotSet && 14439 (kind() == OPTIMIZED_FUNCTION || 14440 (kind() == FUNCTION && !has_debug_break_slots())) 14441 ? instruction_start() + prologue_offset() 14442 : NULL; 14443 } 14444 14445 14446 Code::Age Code::GetAge() { 14447 byte* sequence = FindCodeAgeSequence(); 14448 if (sequence == NULL) { 14449 return kNoAgeCodeAge; 14450 } 14451 Age age; 14452 MarkingParity parity; 14453 GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity); 14454 return age; 14455 } 14456 14457 14458 void Code::GetCodeAgeAndParity(Code* code, Age* age, 14459 MarkingParity* parity) { 14460 Isolate* isolate = code->GetIsolate(); 14461 Builtins* builtins = isolate->builtins(); 14462 Code* stub = NULL; 14463 #define HANDLE_CODE_AGE(AGE) \ 14464 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \ 14465 if (code == stub) { \ 14466 *age = k##AGE##CodeAge; \ 14467 *parity = EVEN_MARKING_PARITY; \ 14468 return; \ 14469 } \ 14470 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \ 14471 if (code == stub) { \ 14472 *age = k##AGE##CodeAge; \ 14473 *parity = ODD_MARKING_PARITY; \ 14474 return; \ 14475 } 14476 CODE_AGE_LIST(HANDLE_CODE_AGE) 14477 #undef HANDLE_CODE_AGE 14478 stub = *builtins->MarkCodeAsExecutedOnce(); 14479 if (code == stub) { 14480 *age = kNotExecutedCodeAge; 14481 *parity = NO_MARKING_PARITY; 14482 return; 14483 } 14484 stub = *builtins->MarkCodeAsExecutedTwice(); 14485 if (code == stub) { 14486 *age = kExecutedOnceCodeAge; 14487 *parity = NO_MARKING_PARITY; 14488 return; 14489 } 14490 stub = *builtins->MarkCodeAsToBeExecutedOnce(); 14491 if (code == stub) { 14492 *age = kToBeExecutedOnceCodeAge; 14493 *parity = NO_MARKING_PARITY; 14494 return; 14495 } 14496 UNREACHABLE(); 14497 } 14498 14499 14500 Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) { 14501 Builtins* builtins = isolate->builtins(); 14502 switch (age) { 14503 #define HANDLE_CODE_AGE(AGE) \ 14504 case k##AGE##CodeAge: { \ 14505 Code* stub = parity == EVEN_MARKING_PARITY \ 14506 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \ 14507 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \ 14508 return stub; \ 14509 } 14510 CODE_AGE_LIST(HANDLE_CODE_AGE) 14511 #undef HANDLE_CODE_AGE 14512 case kNotExecutedCodeAge: { 14513 DCHECK(parity == NO_MARKING_PARITY); 14514 return *builtins->MarkCodeAsExecutedOnce(); 14515 } 14516 case kExecutedOnceCodeAge: { 14517 DCHECK(parity == NO_MARKING_PARITY); 14518 return *builtins->MarkCodeAsExecutedTwice(); 14519 } 14520 case kToBeExecutedOnceCodeAge: { 14521 DCHECK(parity == NO_MARKING_PARITY); 14522 return *builtins->MarkCodeAsToBeExecutedOnce(); 14523 } 14524 default: 14525 UNREACHABLE(); 14526 break; 14527 } 14528 return NULL; 14529 } 14530 14531 14532 void Code::PrintDeoptLocation(FILE* out, Address pc) { 14533 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc); 14534 class SourcePosition pos = info.position; 14535 if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) { 14536 if (FLAG_hydrogen_track_positions) { 14537 PrintF(out, " ;;; deoptimize at %d_%d: %s\n", pos.InliningId(), 14538 pos.ScriptOffset(), DeoptimizeReasonToString(info.deopt_reason)); 14539 } else { 14540 PrintF(out, " ;;; deoptimize at "); 14541 OFStream outstr(out); 14542 pos.Print(outstr, this); 14543 PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason)); 14544 } 14545 } 14546 } 14547 14548 14549 bool Code::CanDeoptAt(Address pc) { 14550 DeoptimizationInputData* deopt_data = 14551 DeoptimizationInputData::cast(deoptimization_data()); 14552 Address code_start_address = instruction_start(); 14553 for (int i = 0; i < deopt_data->DeoptCount(); i++) { 14554 if (deopt_data->Pc(i)->value() == -1) continue; 14555 Address address = code_start_address + deopt_data->Pc(i)->value(); 14556 if (address == pc && deopt_data->AstId(i) != BailoutId::None()) { 14557 return true; 14558 } 14559 } 14560 return false; 14561 } 14562 14563 14564 // Identify kind of code. 14565 const char* Code::Kind2String(Kind kind) { 14566 switch (kind) { 14567 #define CASE(name) case name: return #name; 14568 CODE_KIND_LIST(CASE) 14569 #undef CASE 14570 case NUMBER_OF_KINDS: break; 14571 } 14572 UNREACHABLE(); 14573 return NULL; 14574 } 14575 14576 // Identify kind of code. 14577 const char* AbstractCode::Kind2String(Kind kind) { 14578 if (kind < AbstractCode::INTERPRETED_FUNCTION) 14579 return Code::Kind2String((Code::Kind)kind); 14580 if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION"; 14581 UNREACHABLE(); 14582 return NULL; 14583 } 14584 14585 Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) { 14586 DCHECK(code->kind() == OPTIMIZED_FUNCTION); 14587 WeakCell* raw_cell = code->CachedWeakCell(); 14588 if (raw_cell != NULL) return Handle<WeakCell>(raw_cell); 14589 Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code); 14590 DeoptimizationInputData::cast(code->deoptimization_data()) 14591 ->SetWeakCellCache(*cell); 14592 return cell; 14593 } 14594 14595 14596 WeakCell* Code::CachedWeakCell() { 14597 DCHECK(kind() == OPTIMIZED_FUNCTION); 14598 Object* weak_cell_cache = 14599 DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache(); 14600 if (weak_cell_cache->IsWeakCell()) { 14601 DCHECK(this == WeakCell::cast(weak_cell_cache)->value()); 14602 return WeakCell::cast(weak_cell_cache); 14603 } 14604 return NULL; 14605 } 14606 14607 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) 14608 14609 const char* Code::ICState2String(InlineCacheState state) { 14610 switch (state) { 14611 case UNINITIALIZED: 14612 return "UNINITIALIZED"; 14613 case PREMONOMORPHIC: 14614 return "PREMONOMORPHIC"; 14615 case MONOMORPHIC: 14616 return "MONOMORPHIC"; 14617 case RECOMPUTE_HANDLER: 14618 return "RECOMPUTE_HANDLER"; 14619 case POLYMORPHIC: 14620 return "POLYMORPHIC"; 14621 case MEGAMORPHIC: 14622 return "MEGAMORPHIC"; 14623 case GENERIC: 14624 return "GENERIC"; 14625 } 14626 UNREACHABLE(); 14627 return NULL; 14628 } 14629 14630 void Code::PrintExtraICState(std::ostream& os, // NOLINT 14631 Kind kind, ExtraICState extra) { 14632 os << "extra_ic_state = "; 14633 if ((kind == STORE_IC || kind == KEYED_STORE_IC) && 14634 is_strict(static_cast<LanguageMode>(extra))) { 14635 os << "STRICT\n"; 14636 } else { 14637 os << extra << "\n"; 14638 } 14639 } 14640 14641 #endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) 14642 14643 #ifdef ENABLE_DISASSEMBLER 14644 14645 void DeoptimizationInputData::DeoptimizationInputDataPrint( 14646 std::ostream& os) { // NOLINT 14647 disasm::NameConverter converter; 14648 int const inlined_function_count = InlinedFunctionCount()->value(); 14649 os << "Inlined functions (count = " << inlined_function_count << ")\n"; 14650 for (int id = 0; id < inlined_function_count; ++id) { 14651 Object* info = LiteralArray()->get(id); 14652 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n"; 14653 } 14654 os << "\n"; 14655 int deopt_count = DeoptCount(); 14656 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n"; 14657 if (0 != deopt_count) { 14658 os << " index ast id argc pc"; 14659 if (FLAG_print_code_verbose) os << " commands"; 14660 os << "\n"; 14661 } 14662 for (int i = 0; i < deopt_count; i++) { 14663 os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " " 14664 << std::setw(6) << ArgumentsStackHeight(i)->value() << " " 14665 << std::setw(6) << Pc(i)->value(); 14666 14667 if (!FLAG_print_code_verbose) { 14668 os << "\n"; 14669 continue; 14670 } 14671 // Print details of the frame translation. 14672 int translation_index = TranslationIndex(i)->value(); 14673 TranslationIterator iterator(TranslationByteArray(), translation_index); 14674 Translation::Opcode opcode = 14675 static_cast<Translation::Opcode>(iterator.Next()); 14676 DCHECK(Translation::BEGIN == opcode); 14677 int frame_count = iterator.Next(); 14678 int jsframe_count = iterator.Next(); 14679 os << " " << Translation::StringFor(opcode) 14680 << " {frame count=" << frame_count 14681 << ", js frame count=" << jsframe_count << "}\n"; 14682 14683 while (iterator.HasNext() && 14684 Translation::BEGIN != 14685 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) { 14686 os << std::setw(31) << " " << Translation::StringFor(opcode) << " "; 14687 14688 switch (opcode) { 14689 case Translation::BEGIN: 14690 UNREACHABLE(); 14691 break; 14692 14693 case Translation::JS_FRAME: { 14694 int ast_id = iterator.Next(); 14695 int shared_info_id = iterator.Next(); 14696 unsigned height = iterator.Next(); 14697 Object* shared_info = LiteralArray()->get(shared_info_id); 14698 os << "{ast_id=" << ast_id << ", function=" 14699 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14700 << ", height=" << height << "}"; 14701 break; 14702 } 14703 14704 case Translation::INTERPRETED_FRAME: { 14705 int bytecode_offset = iterator.Next(); 14706 int shared_info_id = iterator.Next(); 14707 unsigned height = iterator.Next(); 14708 Object* shared_info = LiteralArray()->get(shared_info_id); 14709 os << "{bytecode_offset=" << bytecode_offset << ", function=" 14710 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14711 << ", height=" << height << "}"; 14712 break; 14713 } 14714 14715 case Translation::COMPILED_STUB_FRAME: { 14716 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next()); 14717 os << "{kind=" << stub_kind << "}"; 14718 break; 14719 } 14720 14721 case Translation::ARGUMENTS_ADAPTOR_FRAME: 14722 case Translation::CONSTRUCT_STUB_FRAME: { 14723 int shared_info_id = iterator.Next(); 14724 Object* shared_info = LiteralArray()->get(shared_info_id); 14725 unsigned height = iterator.Next(); 14726 os << "{function=" 14727 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14728 << ", height=" << height << "}"; 14729 break; 14730 } 14731 14732 case Translation::TAIL_CALLER_FRAME: { 14733 int shared_info_id = iterator.Next(); 14734 Object* shared_info = LiteralArray()->get(shared_info_id); 14735 os << "{function=" 14736 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14737 << "}"; 14738 break; 14739 } 14740 14741 case Translation::GETTER_STUB_FRAME: 14742 case Translation::SETTER_STUB_FRAME: { 14743 int shared_info_id = iterator.Next(); 14744 Object* shared_info = LiteralArray()->get(shared_info_id); 14745 os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info) 14746 ->DebugName()) << "}"; 14747 break; 14748 } 14749 14750 case Translation::REGISTER: { 14751 int reg_code = iterator.Next(); 14752 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}"; 14753 break; 14754 } 14755 14756 case Translation::INT32_REGISTER: { 14757 int reg_code = iterator.Next(); 14758 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}"; 14759 break; 14760 } 14761 14762 case Translation::UINT32_REGISTER: { 14763 int reg_code = iterator.Next(); 14764 os << "{input=" << converter.NameOfCPURegister(reg_code) 14765 << " (unsigned)}"; 14766 break; 14767 } 14768 14769 case Translation::BOOL_REGISTER: { 14770 int reg_code = iterator.Next(); 14771 os << "{input=" << converter.NameOfCPURegister(reg_code) 14772 << " (bool)}"; 14773 break; 14774 } 14775 14776 case Translation::FLOAT_REGISTER: { 14777 int reg_code = iterator.Next(); 14778 os << "{input=" 14779 << RegisterConfiguration::Crankshaft()->GetFloatRegisterName( 14780 reg_code) 14781 << "}"; 14782 break; 14783 } 14784 14785 case Translation::DOUBLE_REGISTER: { 14786 int reg_code = iterator.Next(); 14787 os << "{input=" 14788 << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName( 14789 reg_code) 14790 << "}"; 14791 break; 14792 } 14793 14794 case Translation::STACK_SLOT: { 14795 int input_slot_index = iterator.Next(); 14796 os << "{input=" << input_slot_index << "}"; 14797 break; 14798 } 14799 14800 case Translation::INT32_STACK_SLOT: { 14801 int input_slot_index = iterator.Next(); 14802 os << "{input=" << input_slot_index << "}"; 14803 break; 14804 } 14805 14806 case Translation::UINT32_STACK_SLOT: { 14807 int input_slot_index = iterator.Next(); 14808 os << "{input=" << input_slot_index << " (unsigned)}"; 14809 break; 14810 } 14811 14812 case Translation::BOOL_STACK_SLOT: { 14813 int input_slot_index = iterator.Next(); 14814 os << "{input=" << input_slot_index << " (bool)}"; 14815 break; 14816 } 14817 14818 case Translation::FLOAT_STACK_SLOT: 14819 case Translation::DOUBLE_STACK_SLOT: { 14820 int input_slot_index = iterator.Next(); 14821 os << "{input=" << input_slot_index << "}"; 14822 break; 14823 } 14824 14825 case Translation::LITERAL: { 14826 int literal_index = iterator.Next(); 14827 Object* literal_value = LiteralArray()->get(literal_index); 14828 os << "{literal_id=" << literal_index << " (" << Brief(literal_value) 14829 << ")}"; 14830 break; 14831 } 14832 14833 case Translation::DUPLICATED_OBJECT: { 14834 int object_index = iterator.Next(); 14835 os << "{object_index=" << object_index << "}"; 14836 break; 14837 } 14838 14839 case Translation::ARGUMENTS_OBJECT: 14840 case Translation::CAPTURED_OBJECT: { 14841 int args_length = iterator.Next(); 14842 os << "{length=" << args_length << "}"; 14843 break; 14844 } 14845 } 14846 os << "\n"; 14847 } 14848 } 14849 } 14850 14851 14852 void DeoptimizationOutputData::DeoptimizationOutputDataPrint( 14853 std::ostream& os) { // NOLINT 14854 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints() 14855 << ")\n"; 14856 if (this->DeoptPoints() == 0) return; 14857 14858 os << "ast id pc state\n"; 14859 for (int i = 0; i < this->DeoptPoints(); i++) { 14860 int pc_and_state = this->PcAndState(i)->value(); 14861 os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8) 14862 << FullCodeGenerator::PcField::decode(pc_and_state) << " " 14863 << Deoptimizer::BailoutStateToString( 14864 FullCodeGenerator::BailoutStateField::decode(pc_and_state)) 14865 << "\n"; 14866 } 14867 } 14868 14869 14870 void HandlerTable::HandlerTableRangePrint(std::ostream& os) { 14871 os << " from to hdlr\n"; 14872 for (int i = 0; i < length(); i += kRangeEntrySize) { 14873 int pc_start = Smi::cast(get(i + kRangeStartIndex))->value(); 14874 int pc_end = Smi::cast(get(i + kRangeEndIndex))->value(); 14875 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value(); 14876 int handler_offset = HandlerOffsetField::decode(handler_field); 14877 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 14878 int data = Smi::cast(get(i + kRangeDataIndex))->value(); 14879 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end 14880 << ") -> " << std::setw(4) << handler_offset 14881 << " (prediction=" << prediction << ", data=" << data << ")\n"; 14882 } 14883 } 14884 14885 14886 void HandlerTable::HandlerTableReturnPrint(std::ostream& os) { 14887 os << " off hdlr (c)\n"; 14888 for (int i = 0; i < length(); i += kReturnEntrySize) { 14889 int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value(); 14890 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value(); 14891 int handler_offset = HandlerOffsetField::decode(handler_field); 14892 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 14893 os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4) 14894 << handler_offset << " (prediction=" << prediction << ")\n"; 14895 } 14896 } 14897 14898 14899 void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT 14900 os << "kind = " << Kind2String(kind()) << "\n"; 14901 if (IsCodeStubOrIC()) { 14902 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this)); 14903 os << "major_key = " << (n == NULL ? "null" : n) << "\n"; 14904 } 14905 if (is_inline_cache_stub()) { 14906 if (!IC::ICUseVector(kind())) { 14907 InlineCacheState ic_state = IC::StateFromCode(this); 14908 os << "ic_state = " << ICState2String(ic_state) << "\n"; 14909 } 14910 PrintExtraICState(os, kind(), extra_ic_state()); 14911 if (is_compare_ic_stub()) { 14912 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC); 14913 CompareICStub stub(stub_key(), GetIsolate()); 14914 os << "compare_state = " << CompareICState::GetStateName(stub.left()) 14915 << "*" << CompareICState::GetStateName(stub.right()) << " -> " 14916 << CompareICState::GetStateName(stub.state()) << "\n"; 14917 os << "compare_operation = " << Token::Name(stub.op()) << "\n"; 14918 } 14919 } 14920 if ((name != nullptr) && (name[0] != '\0')) { 14921 os << "name = " << name << "\n"; 14922 } else if (kind() == BUILTIN) { 14923 name = GetIsolate()->builtins()->Lookup(instruction_start()); 14924 if (name != nullptr) { 14925 os << "name = " << name << "\n"; 14926 } 14927 } else if (kind() == BYTECODE_HANDLER) { 14928 name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this); 14929 if (name != nullptr) { 14930 os << "name = " << name << "\n"; 14931 } 14932 } 14933 if (kind() == OPTIMIZED_FUNCTION) { 14934 os << "stack_slots = " << stack_slots() << "\n"; 14935 } 14936 os << "compiler = " << (is_turbofanned() 14937 ? "turbofan" 14938 : is_crankshafted() ? "crankshaft" 14939 : kind() == Code::FUNCTION 14940 ? "full-codegen" 14941 : "unknown") << "\n"; 14942 14943 os << "Instructions (size = " << instruction_size() << ")\n"; 14944 { 14945 Isolate* isolate = GetIsolate(); 14946 int size = instruction_size(); 14947 int safepoint_offset = 14948 is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size; 14949 int back_edge_offset = (kind() == Code::FUNCTION) 14950 ? static_cast<int>(back_edge_table_offset()) 14951 : size; 14952 int constant_pool_offset = FLAG_enable_embedded_constant_pool 14953 ? this->constant_pool_offset() 14954 : size; 14955 14956 // Stop before reaching any embedded tables 14957 int code_size = Min(safepoint_offset, back_edge_offset); 14958 code_size = Min(code_size, constant_pool_offset); 14959 byte* begin = instruction_start(); 14960 byte* end = begin + code_size; 14961 Disassembler::Decode(isolate, &os, begin, end, this); 14962 14963 if (constant_pool_offset < size) { 14964 int constant_pool_size = size - constant_pool_offset; 14965 DCHECK((constant_pool_size & kPointerAlignmentMask) == 0); 14966 os << "\nConstant Pool (size = " << constant_pool_size << ")\n"; 14967 Vector<char> buf = Vector<char>::New(50); 14968 intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset); 14969 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) { 14970 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr); 14971 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n"; 14972 } 14973 } 14974 } 14975 os << "\n"; 14976 14977 SourcePositionTableIterator it(source_position_table()); 14978 if (!it.done()) { 14979 os << "Source positions:\n pc offset position\n"; 14980 for (; !it.done(); it.Advance()) { 14981 os << std::setw(10) << it.code_offset() << std::setw(10) 14982 << it.source_position().ScriptOffset() 14983 << (it.is_statement() ? " statement" : "") << "\n"; 14984 } 14985 os << "\n"; 14986 } 14987 14988 if (kind() == FUNCTION) { 14989 DeoptimizationOutputData* data = 14990 DeoptimizationOutputData::cast(this->deoptimization_data()); 14991 data->DeoptimizationOutputDataPrint(os); 14992 } else if (kind() == OPTIMIZED_FUNCTION) { 14993 DeoptimizationInputData* data = 14994 DeoptimizationInputData::cast(this->deoptimization_data()); 14995 data->DeoptimizationInputDataPrint(os); 14996 } 14997 os << "\n"; 14998 14999 if (is_crankshafted()) { 15000 SafepointTable table(this); 15001 os << "Safepoints (size = " << table.size() << ")\n"; 15002 for (unsigned i = 0; i < table.length(); i++) { 15003 unsigned pc_offset = table.GetPcOffset(i); 15004 os << static_cast<const void*>(instruction_start() + pc_offset) << " "; 15005 os << std::setw(4) << pc_offset << " "; 15006 table.PrintEntry(i, os); 15007 os << " (sp -> fp) "; 15008 SafepointEntry entry = table.GetEntry(i); 15009 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) { 15010 os << std::setw(6) << entry.deoptimization_index(); 15011 } else { 15012 os << "<none>"; 15013 } 15014 if (entry.argument_count() > 0) { 15015 os << " argc: " << entry.argument_count(); 15016 } 15017 os << "\n"; 15018 } 15019 os << "\n"; 15020 } else if (kind() == FUNCTION) { 15021 unsigned offset = back_edge_table_offset(); 15022 // If there is no back edge table, the "table start" will be at or after 15023 // (due to alignment) the end of the instruction stream. 15024 if (static_cast<int>(offset) < instruction_size()) { 15025 DisallowHeapAllocation no_gc; 15026 BackEdgeTable back_edges(this, &no_gc); 15027 15028 os << "Back edges (size = " << back_edges.length() << ")\n"; 15029 os << "ast_id pc_offset loop_depth\n"; 15030 15031 for (uint32_t i = 0; i < back_edges.length(); i++) { 15032 os << std::setw(6) << back_edges.ast_id(i).ToInt() << " " 15033 << std::setw(9) << back_edges.pc_offset(i) << " " << std::setw(10) 15034 << back_edges.loop_depth(i) << "\n"; 15035 } 15036 15037 os << "\n"; 15038 } 15039 #ifdef OBJECT_PRINT 15040 if (!type_feedback_info()->IsUndefined(GetIsolate())) { 15041 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os); 15042 os << "\n"; 15043 } 15044 #endif 15045 } 15046 15047 if (handler_table()->length() > 0) { 15048 os << "Handler Table (size = " << handler_table()->Size() << ")\n"; 15049 if (kind() == FUNCTION) { 15050 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os); 15051 } else if (kind() == OPTIMIZED_FUNCTION) { 15052 HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os); 15053 } 15054 os << "\n"; 15055 } 15056 15057 os << "RelocInfo (size = " << relocation_size() << ")\n"; 15058 for (RelocIterator it(this); !it.done(); it.next()) { 15059 it.rinfo()->Print(GetIsolate(), os); 15060 } 15061 os << "\n"; 15062 15063 if (has_unwinding_info()) { 15064 os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n"; 15065 EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(), 15066 unwinding_info_end()); 15067 eh_frame_disassembler.DisassembleToStream(os); 15068 os << "\n"; 15069 } 15070 } 15071 #endif // ENABLE_DISASSEMBLER 15072 15073 15074 void BytecodeArray::Disassemble(std::ostream& os) { 15075 os << "Parameter count " << parameter_count() << "\n"; 15076 os << "Frame size " << frame_size() << "\n"; 15077 15078 const uint8_t* base_address = GetFirstBytecodeAddress(); 15079 SourcePositionTableIterator source_positions(source_position_table()); 15080 15081 interpreter::BytecodeArrayIterator iterator(handle(this)); 15082 while (!iterator.done()) { 15083 if (!source_positions.done() && 15084 iterator.current_offset() == source_positions.code_offset()) { 15085 os << std::setw(5) << source_positions.source_position().ScriptOffset(); 15086 os << (source_positions.is_statement() ? " S> " : " E> "); 15087 source_positions.Advance(); 15088 } else { 15089 os << " "; 15090 } 15091 const uint8_t* current_address = base_address + iterator.current_offset(); 15092 os << reinterpret_cast<const void*>(current_address) << " @ " 15093 << std::setw(4) << iterator.current_offset() << " : "; 15094 interpreter::BytecodeDecoder::Decode(os, current_address, 15095 parameter_count()); 15096 if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) { 15097 const void* jump_target = base_address + iterator.GetJumpTargetOffset(); 15098 os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset() 15099 << ")"; 15100 } 15101 os << std::endl; 15102 iterator.Advance(); 15103 } 15104 15105 if (constant_pool()->length() > 0) { 15106 os << "Constant pool (size = " << constant_pool()->length() << ")\n"; 15107 constant_pool()->Print(); 15108 } 15109 15110 #ifdef ENABLE_DISASSEMBLER 15111 if (handler_table()->length() > 0) { 15112 os << "Handler Table (size = " << handler_table()->Size() << ")\n"; 15113 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os); 15114 } 15115 #endif 15116 } 15117 15118 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) { 15119 BytecodeArray* from = this; 15120 DCHECK_EQ(from->length(), to->length()); 15121 CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(), 15122 from->length()); 15123 } 15124 15125 int BytecodeArray::LookupRangeInHandlerTable( 15126 int code_offset, int* data, HandlerTable::CatchPrediction* prediction) { 15127 HandlerTable* table = HandlerTable::cast(handler_table()); 15128 code_offset++; // Point after current bytecode. 15129 return table->LookupRange(code_offset, data, prediction); 15130 } 15131 15132 // static 15133 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { 15134 DCHECK(capacity >= 0); 15135 array->GetIsolate()->factory()->NewJSArrayStorage( 15136 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 15137 } 15138 15139 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) { 15140 // We should never end in here with a pixel or external array. 15141 DCHECK(array->AllowsSetLength()); 15142 if (array->SetLengthWouldNormalize(new_length)) { 15143 JSObject::NormalizeElements(array); 15144 } 15145 array->GetElementsAccessor()->SetLength(array, new_length); 15146 } 15147 15148 15149 // static 15150 void Map::AddDependentCode(Handle<Map> map, 15151 DependentCode::DependencyGroup group, 15152 Handle<Code> code) { 15153 Handle<WeakCell> cell = Code::WeakCellFor(code); 15154 Handle<DependentCode> codes = DependentCode::InsertWeakCode( 15155 Handle<DependentCode>(map->dependent_code()), group, cell); 15156 if (*codes != map->dependent_code()) map->set_dependent_code(*codes); 15157 } 15158 15159 15160 Handle<DependentCode> DependentCode::InsertCompilationDependencies( 15161 Handle<DependentCode> entries, DependencyGroup group, 15162 Handle<Foreign> info) { 15163 return Insert(entries, group, info); 15164 } 15165 15166 15167 Handle<DependentCode> DependentCode::InsertWeakCode( 15168 Handle<DependentCode> entries, DependencyGroup group, 15169 Handle<WeakCell> code_cell) { 15170 return Insert(entries, group, code_cell); 15171 } 15172 15173 15174 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries, 15175 DependencyGroup group, 15176 Handle<Object> object) { 15177 if (entries->length() == 0 || entries->group() > group) { 15178 // There is no such group. 15179 return DependentCode::New(group, object, entries); 15180 } 15181 if (entries->group() < group) { 15182 // The group comes later in the list. 15183 Handle<DependentCode> old_next(entries->next_link()); 15184 Handle<DependentCode> new_next = Insert(old_next, group, object); 15185 if (!old_next.is_identical_to(new_next)) { 15186 entries->set_next_link(*new_next); 15187 } 15188 return entries; 15189 } 15190 DCHECK_EQ(group, entries->group()); 15191 int count = entries->count(); 15192 // Check for existing entry to avoid duplicates. 15193 for (int i = 0; i < count; i++) { 15194 if (entries->object_at(i) == *object) return entries; 15195 } 15196 if (entries->length() < kCodesStartIndex + count + 1) { 15197 entries = EnsureSpace(entries); 15198 // Count could have changed, reload it. 15199 count = entries->count(); 15200 } 15201 entries->set_object_at(count, *object); 15202 entries->set_count(count + 1); 15203 return entries; 15204 } 15205 15206 15207 Handle<DependentCode> DependentCode::New(DependencyGroup group, 15208 Handle<Object> object, 15209 Handle<DependentCode> next) { 15210 Isolate* isolate = next->GetIsolate(); 15211 Handle<DependentCode> result = Handle<DependentCode>::cast( 15212 isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED)); 15213 result->set_next_link(*next); 15214 result->set_flags(GroupField::encode(group) | CountField::encode(1)); 15215 result->set_object_at(0, *object); 15216 return result; 15217 } 15218 15219 15220 Handle<DependentCode> DependentCode::EnsureSpace( 15221 Handle<DependentCode> entries) { 15222 if (entries->Compact()) return entries; 15223 Isolate* isolate = entries->GetIsolate(); 15224 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count()); 15225 int grow_by = capacity - entries->length(); 15226 return Handle<DependentCode>::cast( 15227 isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED)); 15228 } 15229 15230 15231 bool DependentCode::Compact() { 15232 int old_count = count(); 15233 int new_count = 0; 15234 for (int i = 0; i < old_count; i++) { 15235 Object* obj = object_at(i); 15236 if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) { 15237 if (i != new_count) { 15238 copy(i, new_count); 15239 } 15240 new_count++; 15241 } 15242 } 15243 set_count(new_count); 15244 for (int i = new_count; i < old_count; i++) { 15245 clear_at(i); 15246 } 15247 return new_count < old_count; 15248 } 15249 15250 15251 void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info, 15252 WeakCell* code_cell) { 15253 if (this->length() == 0 || this->group() > group) { 15254 // There is no such group. 15255 return; 15256 } 15257 if (this->group() < group) { 15258 // The group comes later in the list. 15259 next_link()->UpdateToFinishedCode(group, info, code_cell); 15260 return; 15261 } 15262 DCHECK_EQ(group, this->group()); 15263 DisallowHeapAllocation no_gc; 15264 int count = this->count(); 15265 for (int i = 0; i < count; i++) { 15266 if (object_at(i) == info) { 15267 set_object_at(i, code_cell); 15268 break; 15269 } 15270 } 15271 #ifdef DEBUG 15272 for (int i = 0; i < count; i++) { 15273 DCHECK(object_at(i) != info); 15274 } 15275 #endif 15276 } 15277 15278 15279 void DependentCode::RemoveCompilationDependencies( 15280 DependentCode::DependencyGroup group, Foreign* info) { 15281 if (this->length() == 0 || this->group() > group) { 15282 // There is no such group. 15283 return; 15284 } 15285 if (this->group() < group) { 15286 // The group comes later in the list. 15287 next_link()->RemoveCompilationDependencies(group, info); 15288 return; 15289 } 15290 DCHECK_EQ(group, this->group()); 15291 DisallowHeapAllocation no_allocation; 15292 int old_count = count(); 15293 // Find compilation info wrapper. 15294 int info_pos = -1; 15295 for (int i = 0; i < old_count; i++) { 15296 if (object_at(i) == info) { 15297 info_pos = i; 15298 break; 15299 } 15300 } 15301 if (info_pos == -1) return; // Not found. 15302 // Use the last code to fill the gap. 15303 if (info_pos < old_count - 1) { 15304 copy(old_count - 1, info_pos); 15305 } 15306 clear_at(old_count - 1); 15307 set_count(old_count - 1); 15308 15309 #ifdef DEBUG 15310 for (int i = 0; i < old_count - 1; i++) { 15311 DCHECK(object_at(i) != info); 15312 } 15313 #endif 15314 } 15315 15316 15317 bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) { 15318 if (this->length() == 0 || this->group() > group) { 15319 // There is no such group. 15320 return false; 15321 } 15322 if (this->group() < group) { 15323 // The group comes later in the list. 15324 return next_link()->Contains(group, code_cell); 15325 } 15326 DCHECK_EQ(group, this->group()); 15327 int count = this->count(); 15328 for (int i = 0; i < count; i++) { 15329 if (object_at(i) == code_cell) return true; 15330 } 15331 return false; 15332 } 15333 15334 15335 bool DependentCode::IsEmpty(DependencyGroup group) { 15336 if (this->length() == 0 || this->group() > group) { 15337 // There is no such group. 15338 return true; 15339 } 15340 if (this->group() < group) { 15341 // The group comes later in the list. 15342 return next_link()->IsEmpty(group); 15343 } 15344 DCHECK_EQ(group, this->group()); 15345 return count() == 0; 15346 } 15347 15348 15349 bool DependentCode::MarkCodeForDeoptimization( 15350 Isolate* isolate, 15351 DependentCode::DependencyGroup group) { 15352 if (this->length() == 0 || this->group() > group) { 15353 // There is no such group. 15354 return false; 15355 } 15356 if (this->group() < group) { 15357 // The group comes later in the list. 15358 return next_link()->MarkCodeForDeoptimization(isolate, group); 15359 } 15360 DCHECK_EQ(group, this->group()); 15361 DisallowHeapAllocation no_allocation_scope; 15362 // Mark all the code that needs to be deoptimized. 15363 bool marked = false; 15364 bool invalidate_embedded_objects = group == kWeakCodeGroup; 15365 int count = this->count(); 15366 for (int i = 0; i < count; i++) { 15367 Object* obj = object_at(i); 15368 if (obj->IsWeakCell()) { 15369 WeakCell* cell = WeakCell::cast(obj); 15370 if (cell->cleared()) continue; 15371 Code* code = Code::cast(cell->value()); 15372 if (!code->marked_for_deoptimization()) { 15373 SetMarkedForDeoptimization(code, group); 15374 if (invalidate_embedded_objects) { 15375 code->InvalidateEmbeddedObjects(); 15376 } 15377 marked = true; 15378 } 15379 } else { 15380 DCHECK(obj->IsForeign()); 15381 CompilationDependencies* info = 15382 reinterpret_cast<CompilationDependencies*>( 15383 Foreign::cast(obj)->foreign_address()); 15384 info->Abort(); 15385 } 15386 } 15387 for (int i = 0; i < count; i++) { 15388 clear_at(i); 15389 } 15390 set_count(0); 15391 return marked; 15392 } 15393 15394 15395 void DependentCode::DeoptimizeDependentCodeGroup( 15396 Isolate* isolate, 15397 DependentCode::DependencyGroup group) { 15398 DCHECK(AllowCodeDependencyChange::IsAllowed()); 15399 DisallowHeapAllocation no_allocation_scope; 15400 bool marked = MarkCodeForDeoptimization(isolate, group); 15401 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate); 15402 } 15403 15404 15405 void DependentCode::SetMarkedForDeoptimization(Code* code, 15406 DependencyGroup group) { 15407 code->set_marked_for_deoptimization(true); 15408 if (FLAG_trace_deopt && 15409 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) { 15410 DeoptimizationInputData* deopt_data = 15411 DeoptimizationInputData::cast(code->deoptimization_data()); 15412 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer()); 15413 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR 15414 " (opt #%d) for deoptimization, reason: %s]\n", 15415 reinterpret_cast<intptr_t>(code), 15416 deopt_data->OptimizationId()->value(), DependencyGroupName(group)); 15417 } 15418 } 15419 15420 15421 const char* DependentCode::DependencyGroupName(DependencyGroup group) { 15422 switch (group) { 15423 case kWeakCodeGroup: 15424 return "weak-code"; 15425 case kTransitionGroup: 15426 return "transition"; 15427 case kPrototypeCheckGroup: 15428 return "prototype-check"; 15429 case kPropertyCellChangedGroup: 15430 return "property-cell-changed"; 15431 case kFieldOwnerGroup: 15432 return "field-owner"; 15433 case kInitialMapChangedGroup: 15434 return "initial-map-changed"; 15435 case kAllocationSiteTenuringChangedGroup: 15436 return "allocation-site-tenuring-changed"; 15437 case kAllocationSiteTransitionChangedGroup: 15438 return "allocation-site-transition-changed"; 15439 } 15440 UNREACHABLE(); 15441 return "?"; 15442 } 15443 15444 15445 Handle<Map> Map::TransitionToPrototype(Handle<Map> map, 15446 Handle<Object> prototype, 15447 PrototypeOptimizationMode mode) { 15448 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype); 15449 if (new_map.is_null()) { 15450 new_map = Copy(map, "TransitionToPrototype"); 15451 TransitionArray::PutPrototypeTransition(map, prototype, new_map); 15452 Map::SetPrototype(new_map, prototype, mode); 15453 } 15454 return new_map; 15455 } 15456 15457 15458 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object, 15459 Handle<Object> value, bool from_javascript, 15460 ShouldThrow should_throw) { 15461 if (object->IsJSProxy()) { 15462 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value, 15463 from_javascript, should_throw); 15464 } 15465 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value, 15466 from_javascript, should_throw); 15467 } 15468 15469 15470 // ES6: 9.5.2 [[SetPrototypeOf]] (V) 15471 // static 15472 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value, 15473 bool from_javascript, 15474 ShouldThrow should_throw) { 15475 Isolate* isolate = proxy->GetIsolate(); 15476 STACK_CHECK(isolate, Nothing<bool>()); 15477 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string(); 15478 // 1. Assert: Either Type(V) is Object or Type(V) is Null. 15479 DCHECK(value->IsJSReceiver() || value->IsNull(isolate)); 15480 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 15481 Handle<Object> handler(proxy->handler(), isolate); 15482 // 3. If handler is null, throw a TypeError exception. 15483 // 4. Assert: Type(handler) is Object. 15484 if (proxy->IsRevoked()) { 15485 isolate->Throw(*isolate->factory()->NewTypeError( 15486 MessageTemplate::kProxyRevoked, trap_name)); 15487 return Nothing<bool>(); 15488 } 15489 // 5. Let target be the value of the [[ProxyTarget]] internal slot. 15490 Handle<JSReceiver> target(proxy->target(), isolate); 15491 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf"). 15492 Handle<Object> trap; 15493 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 15494 isolate, trap, 15495 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 15496 Nothing<bool>()); 15497 // 7. If trap is undefined, then return target.[[SetPrototypeOf]](). 15498 if (trap->IsUndefined(isolate)) { 15499 return JSReceiver::SetPrototype(target, value, from_javascript, 15500 should_throw); 15501 } 15502 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, target, V)). 15503 Handle<Object> argv[] = {target, value}; 15504 Handle<Object> trap_result; 15505 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 15506 isolate, trap_result, 15507 Execution::Call(isolate, trap, handler, arraysize(argv), argv), 15508 Nothing<bool>()); 15509 bool bool_trap_result = trap_result->BooleanValue(); 15510 // 9. If booleanTrapResult is false, return false. 15511 if (!bool_trap_result) { 15512 RETURN_FAILURE( 15513 isolate, should_throw, 15514 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 15515 } 15516 // 10. Let extensibleTarget be ? IsExtensible(target). 15517 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 15518 if (is_extensible.IsNothing()) return Nothing<bool>(); 15519 // 11. If extensibleTarget is true, return true. 15520 if (is_extensible.FromJust()) { 15521 if (bool_trap_result) return Just(true); 15522 RETURN_FAILURE( 15523 isolate, should_throw, 15524 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 15525 } 15526 // 12. Let targetProto be ? target.[[GetPrototypeOf]](). 15527 Handle<Object> target_proto; 15528 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto, 15529 JSReceiver::GetPrototype(isolate, target), 15530 Nothing<bool>()); 15531 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception. 15532 if (bool_trap_result && !value->SameValue(*target_proto)) { 15533 isolate->Throw(*isolate->factory()->NewTypeError( 15534 MessageTemplate::kProxySetPrototypeOfNonExtensible)); 15535 return Nothing<bool>(); 15536 } 15537 // 14. Return true. 15538 return Just(true); 15539 } 15540 15541 15542 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, 15543 Handle<Object> value, bool from_javascript, 15544 ShouldThrow should_throw) { 15545 Isolate* isolate = object->GetIsolate(); 15546 15547 #ifdef DEBUG 15548 int size = object->Size(); 15549 #endif 15550 15551 if (from_javascript) { 15552 if (object->IsAccessCheckNeeded() && 15553 !isolate->MayAccess(handle(isolate->context()), object)) { 15554 isolate->ReportFailedAccessCheck(object); 15555 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 15556 RETURN_FAILURE(isolate, should_throw, 15557 NewTypeError(MessageTemplate::kNoAccess)); 15558 } 15559 } else { 15560 DCHECK(!object->IsAccessCheckNeeded()); 15561 } 15562 15563 Heap* heap = isolate->heap(); 15564 // Silently ignore the change if value is not a JSObject or null. 15565 // SpiderMonkey behaves this way. 15566 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true); 15567 15568 bool dictionary_elements_in_chain = 15569 object->map()->DictionaryElementsInPrototypeChainOnly(); 15570 15571 bool all_extensible = object->map()->is_extensible(); 15572 Handle<JSObject> real_receiver = object; 15573 if (from_javascript) { 15574 // Find the first object in the chain whose prototype object is not 15575 // hidden. 15576 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, 15577 PrototypeIterator::END_AT_NON_HIDDEN); 15578 while (!iter.IsAtEnd()) { 15579 // Casting to JSObject is fine because hidden prototypes are never 15580 // JSProxies. 15581 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); 15582 iter.Advance(); 15583 all_extensible = all_extensible && real_receiver->map()->is_extensible(); 15584 } 15585 } 15586 Handle<Map> map(real_receiver->map()); 15587 15588 // Nothing to do if prototype is already set. 15589 if (map->prototype() == *value) return Just(true); 15590 15591 bool immutable_proto = map->is_immutable_proto(); 15592 if (immutable_proto) { 15593 RETURN_FAILURE( 15594 isolate, should_throw, 15595 NewTypeError(MessageTemplate::kImmutablePrototypeSet, object)); 15596 } 15597 15598 // From 8.6.2 Object Internal Methods 15599 // ... 15600 // In addition, if [[Extensible]] is false the value of the [[Class]] and 15601 // [[Prototype]] internal properties of the object may not be modified. 15602 // ... 15603 // Implementation specific extensions that modify [[Class]], [[Prototype]] 15604 // or [[Extensible]] must not violate the invariants defined in the preceding 15605 // paragraph. 15606 if (!all_extensible) { 15607 RETURN_FAILURE(isolate, should_throw, 15608 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); 15609 } 15610 15611 // Before we can set the prototype we need to be sure prototype cycles are 15612 // prevented. It is sufficient to validate that the receiver is not in the 15613 // new prototype chain. 15614 if (value->IsJSReceiver()) { 15615 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value), 15616 kStartAtReceiver); 15617 !iter.IsAtEnd(); iter.Advance()) { 15618 if (iter.GetCurrent<JSReceiver>() == *object) { 15619 // Cycle detected. 15620 RETURN_FAILURE(isolate, should_throw, 15621 NewTypeError(MessageTemplate::kCyclicProto)); 15622 } 15623 } 15624 } 15625 15626 // Set the new prototype of the object. 15627 15628 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); 15629 15630 PrototypeOptimizationMode mode = 15631 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; 15632 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); 15633 DCHECK(new_map->prototype() == *value); 15634 JSObject::MigrateToMap(real_receiver, new_map); 15635 15636 if (from_javascript && !dictionary_elements_in_chain && 15637 new_map->DictionaryElementsInPrototypeChainOnly()) { 15638 // If the prototype chain didn't previously have element callbacks, then 15639 // KeyedStoreICs need to be cleared to ensure any that involve this 15640 // map go generic. 15641 TypeFeedbackVector::ClearAllKeyedStoreICs(isolate); 15642 } 15643 15644 heap->ClearInstanceofCache(); 15645 DCHECK(size == object->Size()); 15646 return Just(true); 15647 } 15648 15649 // static 15650 void JSObject::SetImmutableProto(Handle<JSObject> object) { 15651 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS 15652 Handle<Map> map(object->map()); 15653 15654 // Nothing to do if prototype is already set. 15655 if (map->is_immutable_proto()) return; 15656 15657 Handle<Map> new_map = Map::TransitionToImmutableProto(map); 15658 object->set_map(*new_map); 15659 } 15660 15661 void JSObject::EnsureCanContainElements(Handle<JSObject> object, 15662 Arguments* args, 15663 uint32_t first_arg, 15664 uint32_t arg_count, 15665 EnsureElementsMode mode) { 15666 // Elements in |Arguments| are ordered backwards (because they're on the 15667 // stack), but the method that's called here iterates over them in forward 15668 // direction. 15669 return EnsureCanContainElements( 15670 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode); 15671 } 15672 15673 15674 ElementsAccessor* JSObject::GetElementsAccessor() { 15675 return ElementsAccessor::ForKind(GetElementsKind()); 15676 } 15677 15678 15679 void JSObject::ValidateElements(Handle<JSObject> object) { 15680 #ifdef ENABLE_SLOW_DCHECKS 15681 if (FLAG_enable_slow_asserts) { 15682 ElementsAccessor* accessor = object->GetElementsAccessor(); 15683 accessor->Validate(object); 15684 } 15685 #endif 15686 } 15687 15688 15689 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity, 15690 uint32_t index, 15691 uint32_t* new_capacity) { 15692 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <= 15693 JSObject::kMaxUncheckedFastElementsLength); 15694 if (index < capacity) { 15695 *new_capacity = capacity; 15696 return false; 15697 } 15698 if (index - capacity >= JSObject::kMaxGap) return true; 15699 *new_capacity = JSObject::NewElementsCapacity(index + 1); 15700 DCHECK_LT(index, *new_capacity); 15701 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength || 15702 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength && 15703 object->GetHeap()->InNewSpace(object))) { 15704 return false; 15705 } 15706 // If the fast-case backing storage takes up roughly three times as 15707 // much space (in machine words) as a dictionary backing storage 15708 // would, the object should have slow elements. 15709 int used_elements = object->GetFastElementsUsage(); 15710 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * 15711 SeededNumberDictionary::kEntrySize; 15712 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; 15713 } 15714 15715 15716 bool JSObject::WouldConvertToSlowElements(uint32_t index) { 15717 if (HasFastElements()) { 15718 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); 15719 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); 15720 uint32_t new_capacity; 15721 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity); 15722 } 15723 return false; 15724 } 15725 15726 15727 static ElementsKind BestFittingFastElementsKind(JSObject* object) { 15728 if (object->HasSloppyArgumentsElements()) { 15729 return FAST_SLOPPY_ARGUMENTS_ELEMENTS; 15730 } 15731 if (object->HasStringWrapperElements()) { 15732 return FAST_STRING_WRAPPER_ELEMENTS; 15733 } 15734 DCHECK(object->HasDictionaryElements()); 15735 SeededNumberDictionary* dictionary = object->element_dictionary(); 15736 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; 15737 for (int i = 0; i < dictionary->Capacity(); i++) { 15738 Object* key = dictionary->KeyAt(i); 15739 if (key->IsNumber()) { 15740 Object* value = dictionary->ValueAt(i); 15741 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; 15742 if (!value->IsSmi()) { 15743 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; 15744 kind = FAST_HOLEY_DOUBLE_ELEMENTS; 15745 } 15746 } 15747 } 15748 return kind; 15749 } 15750 15751 15752 static bool ShouldConvertToFastElements(JSObject* object, 15753 SeededNumberDictionary* dictionary, 15754 uint32_t index, 15755 uint32_t* new_capacity) { 15756 // If properties with non-standard attributes or accessors were added, we 15757 // cannot go back to fast elements. 15758 if (dictionary->requires_slow_elements()) return false; 15759 15760 // Adding a property with this index will require slow elements. 15761 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false; 15762 15763 if (object->IsJSArray()) { 15764 Object* length = JSArray::cast(object)->length(); 15765 if (!length->IsSmi()) return false; 15766 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value()); 15767 } else { 15768 *new_capacity = dictionary->max_number_key() + 1; 15769 } 15770 *new_capacity = Max(index + 1, *new_capacity); 15771 15772 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * 15773 SeededNumberDictionary::kEntrySize; 15774 15775 // Turn fast if the dictionary only saves 50% space. 15776 return 2 * dictionary_size >= *new_capacity; 15777 } 15778 15779 15780 // static 15781 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object, 15782 uint32_t index, 15783 Handle<Object> value, 15784 PropertyAttributes attributes) { 15785 MAYBE_RETURN_NULL( 15786 AddDataElement(object, index, value, attributes, THROW_ON_ERROR)); 15787 return value; 15788 } 15789 15790 15791 // static 15792 Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index, 15793 Handle<Object> value, 15794 PropertyAttributes attributes, 15795 ShouldThrow should_throw) { 15796 DCHECK(object->map()->is_extensible()); 15797 15798 Isolate* isolate = object->GetIsolate(); 15799 15800 uint32_t old_length = 0; 15801 uint32_t new_capacity = 0; 15802 15803 if (object->IsJSArray()) { 15804 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); 15805 } 15806 15807 ElementsKind kind = object->GetElementsKind(); 15808 FixedArrayBase* elements = object->elements(); 15809 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; 15810 if (IsSloppyArgumentsElements(kind)) { 15811 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); 15812 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; 15813 } else if (IsStringWrapperElementsKind(kind)) { 15814 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS; 15815 } 15816 15817 if (attributes != NONE) { 15818 kind = dictionary_kind; 15819 } else if (elements->IsSeededNumberDictionary()) { 15820 kind = ShouldConvertToFastElements(*object, 15821 SeededNumberDictionary::cast(elements), 15822 index, &new_capacity) 15823 ? BestFittingFastElementsKind(*object) 15824 : dictionary_kind; // Overwrite in case of arguments. 15825 } else if (ShouldConvertToSlowElements( 15826 *object, static_cast<uint32_t>(elements->length()), index, 15827 &new_capacity)) { 15828 kind = dictionary_kind; 15829 } 15830 15831 ElementsKind to = value->OptimalElementsKind(); 15832 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) { 15833 to = GetHoleyElementsKind(to); 15834 kind = GetHoleyElementsKind(kind); 15835 } 15836 to = GetMoreGeneralElementsKind(kind, to); 15837 ElementsAccessor* accessor = ElementsAccessor::ForKind(to); 15838 accessor->Add(object, index, value, attributes, new_capacity); 15839 15840 uint32_t new_length = old_length; 15841 Handle<Object> new_length_handle; 15842 if (object->IsJSArray() && index >= old_length) { 15843 new_length = index + 1; 15844 new_length_handle = isolate->factory()->NewNumberFromUint(new_length); 15845 JSArray::cast(*object)->set_length(*new_length_handle); 15846 } 15847 15848 return Just(true); 15849 } 15850 15851 15852 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) { 15853 if (!HasFastElements()) return false; 15854 uint32_t capacity = static_cast<uint32_t>(elements()->length()); 15855 uint32_t new_capacity; 15856 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) && 15857 ShouldConvertToSlowElements(this, capacity, new_length - 1, 15858 &new_capacity); 15859 } 15860 15861 15862 const double AllocationSite::kPretenureRatio = 0.85; 15863 15864 15865 void AllocationSite::ResetPretenureDecision() { 15866 set_pretenure_decision(kUndecided); 15867 set_memento_found_count(0); 15868 set_memento_create_count(0); 15869 } 15870 15871 15872 PretenureFlag AllocationSite::GetPretenureMode() { 15873 PretenureDecision mode = pretenure_decision(); 15874 // Zombie objects "decide" to be untenured. 15875 return mode == kTenure ? TENURED : NOT_TENURED; 15876 } 15877 15878 15879 bool AllocationSite::IsNestedSite() { 15880 DCHECK(FLAG_trace_track_allocation_sites); 15881 Object* current = GetHeap()->allocation_sites_list(); 15882 while (current->IsAllocationSite()) { 15883 AllocationSite* current_site = AllocationSite::cast(current); 15884 if (current_site->nested_site() == this) { 15885 return true; 15886 } 15887 current = current_site->weak_next(); 15888 } 15889 return false; 15890 } 15891 15892 template <AllocationSiteUpdateMode update_or_check> 15893 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site, 15894 ElementsKind to_kind) { 15895 Isolate* isolate = site->GetIsolate(); 15896 bool result = false; 15897 15898 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) { 15899 Handle<JSArray> transition_info = 15900 handle(JSArray::cast(site->transition_info())); 15901 ElementsKind kind = transition_info->GetElementsKind(); 15902 // if kind is holey ensure that to_kind is as well. 15903 if (IsHoleyElementsKind(kind)) { 15904 to_kind = GetHoleyElementsKind(to_kind); 15905 } 15906 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { 15907 // If the array is huge, it's not likely to be defined in a local 15908 // function, so we shouldn't make new instances of it very often. 15909 uint32_t length = 0; 15910 CHECK(transition_info->length()->ToArrayLength(&length)); 15911 if (length <= kMaximumArrayBytesToPretransition) { 15912 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) { 15913 return true; 15914 } 15915 if (FLAG_trace_track_allocation_sites) { 15916 bool is_nested = site->IsNestedSite(); 15917 PrintF( 15918 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", 15919 reinterpret_cast<void*>(*site), 15920 is_nested ? "(nested)" : "", 15921 ElementsKindToString(kind), 15922 ElementsKindToString(to_kind)); 15923 } 15924 JSObject::TransitionElementsKind(transition_info, to_kind); 15925 site->dependent_code()->DeoptimizeDependentCodeGroup( 15926 isolate, DependentCode::kAllocationSiteTransitionChangedGroup); 15927 result = true; 15928 } 15929 } 15930 } else { 15931 ElementsKind kind = site->GetElementsKind(); 15932 // if kind is holey ensure that to_kind is as well. 15933 if (IsHoleyElementsKind(kind)) { 15934 to_kind = GetHoleyElementsKind(to_kind); 15935 } 15936 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { 15937 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true; 15938 if (FLAG_trace_track_allocation_sites) { 15939 PrintF("AllocationSite: JSArray %p site updated %s->%s\n", 15940 reinterpret_cast<void*>(*site), 15941 ElementsKindToString(kind), 15942 ElementsKindToString(to_kind)); 15943 } 15944 site->SetElementsKind(to_kind); 15945 site->dependent_code()->DeoptimizeDependentCodeGroup( 15946 isolate, DependentCode::kAllocationSiteTransitionChangedGroup); 15947 result = true; 15948 } 15949 } 15950 return result; 15951 } 15952 15953 AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) { 15954 if (IsFastSmiElementsKind(from) && 15955 IsMoreGeneralElementsKindTransition(from, to)) { 15956 return TRACK_ALLOCATION_SITE; 15957 } 15958 15959 return DONT_TRACK_ALLOCATION_SITE; 15960 } 15961 15962 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) { 15963 switch (decision) { 15964 case kUndecided: return "undecided"; 15965 case kDontTenure: return "don't tenure"; 15966 case kMaybeTenure: return "maybe tenure"; 15967 case kTenure: return "tenure"; 15968 case kZombie: return "zombie"; 15969 default: UNREACHABLE(); 15970 } 15971 return NULL; 15972 } 15973 15974 template <AllocationSiteUpdateMode update_or_check> 15975 bool JSObject::UpdateAllocationSite(Handle<JSObject> object, 15976 ElementsKind to_kind) { 15977 if (!object->IsJSArray()) return false; 15978 15979 Heap* heap = object->GetHeap(); 15980 if (!heap->InNewSpace(*object)) return false; 15981 15982 Handle<AllocationSite> site; 15983 { 15984 DisallowHeapAllocation no_allocation; 15985 15986 AllocationMemento* memento = 15987 heap->FindAllocationMemento<Heap::kForRuntime>(*object); 15988 if (memento == NULL) return false; 15989 15990 // Walk through to the Allocation Site 15991 site = handle(memento->GetAllocationSite()); 15992 } 15993 return AllocationSite::DigestTransitionFeedback<update_or_check>(site, 15994 to_kind); 15995 } 15996 15997 template bool 15998 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>( 15999 Handle<JSObject> object, ElementsKind to_kind); 16000 16001 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>( 16002 Handle<JSObject> object, ElementsKind to_kind); 16003 16004 void JSObject::TransitionElementsKind(Handle<JSObject> object, 16005 ElementsKind to_kind) { 16006 ElementsKind from_kind = object->GetElementsKind(); 16007 16008 if (IsFastHoleyElementsKind(from_kind)) { 16009 to_kind = GetHoleyElementsKind(to_kind); 16010 } 16011 16012 if (from_kind == to_kind) return; 16013 16014 // This method should never be called for any other case. 16015 DCHECK(IsFastElementsKind(from_kind)); 16016 DCHECK(IsFastElementsKind(to_kind)); 16017 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); 16018 16019 UpdateAllocationSite(object, to_kind); 16020 if (object->elements() == object->GetHeap()->empty_fixed_array() || 16021 IsFastDoubleElementsKind(from_kind) == 16022 IsFastDoubleElementsKind(to_kind)) { 16023 // No change is needed to the elements() buffer, the transition 16024 // only requires a map change. 16025 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); 16026 MigrateToMap(object, new_map); 16027 if (FLAG_trace_elements_transitions) { 16028 Handle<FixedArrayBase> elms(object->elements()); 16029 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); 16030 } 16031 } else { 16032 DCHECK((IsFastSmiElementsKind(from_kind) && 16033 IsFastDoubleElementsKind(to_kind)) || 16034 (IsFastDoubleElementsKind(from_kind) && 16035 IsFastObjectElementsKind(to_kind))); 16036 uint32_t c = static_cast<uint32_t>(object->elements()->length()); 16037 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c); 16038 } 16039 } 16040 16041 16042 // static 16043 bool Map::IsValidElementsTransition(ElementsKind from_kind, 16044 ElementsKind to_kind) { 16045 // Transitions can't go backwards. 16046 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { 16047 return false; 16048 } 16049 16050 // Transitions from HOLEY -> PACKED are not allowed. 16051 return !IsFastHoleyElementsKind(from_kind) || 16052 IsFastHoleyElementsKind(to_kind); 16053 } 16054 16055 16056 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { 16057 Map* map = array->map(); 16058 // Fast path: "length" is the first fast property of arrays. Since it's not 16059 // configurable, it's guaranteed to be the first in the descriptor array. 16060 if (!map->is_dictionary_map()) { 16061 DCHECK(map->instance_descriptors()->GetKey(0) == 16062 array->GetHeap()->length_string()); 16063 return map->instance_descriptors()->GetDetails(0).IsReadOnly(); 16064 } 16065 16066 Isolate* isolate = array->GetIsolate(); 16067 LookupIterator it(array, isolate->factory()->length_string(), array, 16068 LookupIterator::OWN_SKIP_INTERCEPTOR); 16069 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); 16070 return it.IsReadOnly(); 16071 } 16072 16073 16074 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, 16075 uint32_t index) { 16076 uint32_t length = 0; 16077 CHECK(array->length()->ToArrayLength(&length)); 16078 if (length <= index) return HasReadOnlyLength(array); 16079 return false; 16080 } 16081 16082 16083 template <typename BackingStore> 16084 static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) { 16085 Isolate* isolate = store->GetIsolate(); 16086 int limit = object->IsJSArray() 16087 ? Smi::cast(JSArray::cast(object)->length())->value() 16088 : store->length(); 16089 int used = 0; 16090 for (int i = 0; i < limit; ++i) { 16091 if (!store->is_the_hole(isolate, i)) ++used; 16092 } 16093 return used; 16094 } 16095 16096 16097 int JSObject::GetFastElementsUsage() { 16098 FixedArrayBase* store = elements(); 16099 switch (GetElementsKind()) { 16100 case FAST_SMI_ELEMENTS: 16101 case FAST_DOUBLE_ELEMENTS: 16102 case FAST_ELEMENTS: 16103 return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value() 16104 : store->length(); 16105 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 16106 store = FixedArray::cast(FixedArray::cast(store)->get(1)); 16107 // Fall through. 16108 case FAST_HOLEY_SMI_ELEMENTS: 16109 case FAST_HOLEY_ELEMENTS: 16110 case FAST_STRING_WRAPPER_ELEMENTS: 16111 return FastHoleyElementsUsage(this, FixedArray::cast(store)); 16112 case FAST_HOLEY_DOUBLE_ELEMENTS: 16113 if (elements()->length() == 0) return 0; 16114 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store)); 16115 16116 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 16117 case SLOW_STRING_WRAPPER_ELEMENTS: 16118 case DICTIONARY_ELEMENTS: 16119 case NO_ELEMENTS: 16120 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 16121 case TYPE##_ELEMENTS: \ 16122 16123 TYPED_ARRAYS(TYPED_ARRAY_CASE) 16124 #undef TYPED_ARRAY_CASE 16125 UNREACHABLE(); 16126 } 16127 return 0; 16128 } 16129 16130 16131 // Certain compilers request function template instantiation when they 16132 // see the definition of the other template functions in the 16133 // class. This requires us to have the template functions put 16134 // together, so even though this function belongs in objects-debug.cc, 16135 // we keep it here instead to satisfy certain compilers. 16136 #ifdef OBJECT_PRINT 16137 template <typename Derived, typename Shape, typename Key> 16138 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT 16139 Isolate* isolate = this->GetIsolate(); 16140 int capacity = this->Capacity(); 16141 for (int i = 0; i < capacity; i++) { 16142 Object* k = this->KeyAt(i); 16143 if (this->IsKey(isolate, k)) { 16144 os << "\n "; 16145 if (k->IsString()) { 16146 String::cast(k)->StringPrint(os); 16147 } else { 16148 os << Brief(k); 16149 } 16150 os << ": " << Brief(this->ValueAt(i)) << " " << this->DetailsAt(i); 16151 } 16152 } 16153 } 16154 template <typename Derived, typename Shape, typename Key> 16155 void Dictionary<Derived, Shape, Key>::Print() { 16156 OFStream os(stdout); 16157 Print(os); 16158 } 16159 #endif 16160 16161 16162 template<typename Derived, typename Shape, typename Key> 16163 void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) { 16164 Isolate* isolate = this->GetIsolate(); 16165 int pos = 0; 16166 int capacity = this->Capacity(); 16167 DisallowHeapAllocation no_gc; 16168 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 16169 for (int i = 0; i < capacity; i++) { 16170 Object* k = this->KeyAt(i); 16171 if (this->IsKey(isolate, k)) { 16172 elements->set(pos++, this->ValueAt(i), mode); 16173 } 16174 } 16175 DCHECK(pos == elements->length()); 16176 } 16177 16178 16179 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it, 16180 bool* done) { 16181 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 16182 return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done); 16183 } 16184 16185 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object, 16186 Handle<Name> name) { 16187 LookupIterator it = LookupIterator::PropertyOrElement( 16188 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 16189 return HasProperty(&it); 16190 } 16191 16192 16193 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object, 16194 uint32_t index) { 16195 Isolate* isolate = object->GetIsolate(); 16196 LookupIterator it(isolate, object, index, object, 16197 LookupIterator::OWN_SKIP_INTERCEPTOR); 16198 return HasProperty(&it); 16199 } 16200 16201 16202 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object, 16203 Handle<Name> name) { 16204 LookupIterator it = LookupIterator::PropertyOrElement( 16205 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 16206 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it); 16207 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR) 16208 : Nothing<bool>(); 16209 } 16210 16211 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) { 16212 return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >> 16213 ElementsKindToShiftSize(kind)); 16214 } 16215 16216 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) { 16217 Object* temp = get(i); 16218 set(i, get(j)); 16219 set(j, temp); 16220 if (this != numbers) { 16221 temp = numbers->get(i); 16222 numbers->set(i, Smi::cast(numbers->get(j))); 16223 numbers->set(j, Smi::cast(temp)); 16224 } 16225 } 16226 16227 16228 static void InsertionSortPairs(FixedArray* content, 16229 FixedArray* numbers, 16230 int len) { 16231 for (int i = 1; i < len; i++) { 16232 int j = i; 16233 while (j > 0 && 16234 (NumberToUint32(numbers->get(j - 1)) > 16235 NumberToUint32(numbers->get(j)))) { 16236 content->SwapPairs(numbers, j - 1, j); 16237 j--; 16238 } 16239 } 16240 } 16241 16242 16243 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) { 16244 // In-place heap sort. 16245 DCHECK(content->length() == numbers->length()); 16246 16247 // Bottom-up max-heap construction. 16248 for (int i = 1; i < len; ++i) { 16249 int child_index = i; 16250 while (child_index > 0) { 16251 int parent_index = ((child_index + 1) >> 1) - 1; 16252 uint32_t parent_value = NumberToUint32(numbers->get(parent_index)); 16253 uint32_t child_value = NumberToUint32(numbers->get(child_index)); 16254 if (parent_value < child_value) { 16255 content->SwapPairs(numbers, parent_index, child_index); 16256 } else { 16257 break; 16258 } 16259 child_index = parent_index; 16260 } 16261 } 16262 16263 // Extract elements and create sorted array. 16264 for (int i = len - 1; i > 0; --i) { 16265 // Put max element at the back of the array. 16266 content->SwapPairs(numbers, 0, i); 16267 // Sift down the new top element. 16268 int parent_index = 0; 16269 while (true) { 16270 int child_index = ((parent_index + 1) << 1) - 1; 16271 if (child_index >= i) break; 16272 uint32_t child1_value = NumberToUint32(numbers->get(child_index)); 16273 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1)); 16274 uint32_t parent_value = NumberToUint32(numbers->get(parent_index)); 16275 if (child_index + 1 >= i || child1_value > child2_value) { 16276 if (parent_value > child1_value) break; 16277 content->SwapPairs(numbers, parent_index, child_index); 16278 parent_index = child_index; 16279 } else { 16280 if (parent_value > child2_value) break; 16281 content->SwapPairs(numbers, parent_index, child_index + 1); 16282 parent_index = child_index + 1; 16283 } 16284 } 16285 } 16286 } 16287 16288 16289 // Sort this array and the numbers as pairs wrt. the (distinct) numbers. 16290 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) { 16291 DCHECK(this->length() == numbers->length()); 16292 // For small arrays, simply use insertion sort. 16293 if (len <= 10) { 16294 InsertionSortPairs(this, numbers, len); 16295 return; 16296 } 16297 // Check the range of indices. 16298 uint32_t min_index = NumberToUint32(numbers->get(0)); 16299 uint32_t max_index = min_index; 16300 uint32_t i; 16301 for (i = 1; i < len; i++) { 16302 if (NumberToUint32(numbers->get(i)) < min_index) { 16303 min_index = NumberToUint32(numbers->get(i)); 16304 } else if (NumberToUint32(numbers->get(i)) > max_index) { 16305 max_index = NumberToUint32(numbers->get(i)); 16306 } 16307 } 16308 if (max_index - min_index + 1 == len) { 16309 // Indices form a contiguous range, unless there are duplicates. 16310 // Do an in-place linear time sort assuming distinct numbers, but 16311 // avoid hanging in case they are not. 16312 for (i = 0; i < len; i++) { 16313 uint32_t p; 16314 uint32_t j = 0; 16315 // While the current element at i is not at its correct position p, 16316 // swap the elements at these two positions. 16317 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i && 16318 j++ < len) { 16319 SwapPairs(numbers, i, p); 16320 } 16321 } 16322 } else { 16323 HeapSortPairs(this, numbers, len); 16324 return; 16325 } 16326 } 16327 16328 bool JSObject::WasConstructedFromApiFunction() { 16329 auto instance_type = map()->instance_type(); 16330 bool is_api_object = instance_type == JS_API_OBJECT_TYPE || 16331 instance_type == JS_SPECIAL_API_OBJECT_TYPE; 16332 #ifdef ENABLE_SLOW_DCHECKS 16333 if (FLAG_enable_slow_asserts) { 16334 Object* maybe_constructor = map()->GetConstructor(); 16335 if (!maybe_constructor->IsJSFunction()) return false; 16336 JSFunction* constructor = JSFunction::cast(maybe_constructor); 16337 if (constructor->shared()->IsApiFunction()) { 16338 DCHECK(is_api_object); 16339 } else { 16340 DCHECK(!is_api_object); 16341 } 16342 } 16343 #endif 16344 return is_api_object; 16345 } 16346 16347 MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate, 16348 Handle<Object> object) { 16349 if (*object == isolate->heap()->undefined_value()) { 16350 return isolate->factory()->undefined_to_string(); 16351 } 16352 if (*object == isolate->heap()->null_value()) { 16353 return isolate->factory()->null_to_string(); 16354 } 16355 16356 Handle<JSReceiver> receiver = 16357 Object::ToObject(isolate, object).ToHandleChecked(); 16358 16359 // For proxies, we must check IsArray() before get(toStringTag) to comply 16360 // with the specification 16361 Maybe<bool> is_array = Nothing<bool>(); 16362 InstanceType instance_type = receiver->map()->instance_type(); 16363 if (instance_type == JS_PROXY_TYPE) { 16364 is_array = Object::IsArray(receiver); 16365 MAYBE_RETURN(is_array, MaybeHandle<String>()); 16366 } 16367 16368 Handle<String> tag; 16369 Handle<Object> to_string_tag; 16370 ASSIGN_RETURN_ON_EXCEPTION( 16371 isolate, to_string_tag, 16372 JSReceiver::GetProperty(receiver, 16373 isolate->factory()->to_string_tag_symbol()), 16374 String); 16375 if (to_string_tag->IsString()) { 16376 tag = Handle<String>::cast(to_string_tag); 16377 } else { 16378 switch (instance_type) { 16379 case JS_API_OBJECT_TYPE: 16380 case JS_SPECIAL_API_OBJECT_TYPE: 16381 tag = handle(receiver->class_name(), isolate); 16382 break; 16383 case JS_ARGUMENTS_TYPE: 16384 return isolate->factory()->arguments_to_string(); 16385 case JS_ARRAY_TYPE: 16386 return isolate->factory()->array_to_string(); 16387 case JS_BOUND_FUNCTION_TYPE: 16388 case JS_FUNCTION_TYPE: 16389 return isolate->factory()->function_to_string(); 16390 case JS_ERROR_TYPE: 16391 return isolate->factory()->error_to_string(); 16392 case JS_DATE_TYPE: 16393 return isolate->factory()->date_to_string(); 16394 case JS_REGEXP_TYPE: 16395 return isolate->factory()->regexp_to_string(); 16396 case JS_PROXY_TYPE: { 16397 if (is_array.FromJust()) { 16398 return isolate->factory()->array_to_string(); 16399 } 16400 if (receiver->IsCallable()) { 16401 return isolate->factory()->function_to_string(); 16402 } 16403 return isolate->factory()->object_to_string(); 16404 } 16405 case JS_VALUE_TYPE: { 16406 Object* value = JSValue::cast(*receiver)->value(); 16407 if (value->IsString()) { 16408 return isolate->factory()->string_to_string(); 16409 } 16410 if (value->IsNumber()) { 16411 return isolate->factory()->number_to_string(); 16412 } 16413 if (value->IsBoolean()) { 16414 return isolate->factory()->boolean_to_string(); 16415 } 16416 if (value->IsSymbol()) { 16417 return isolate->factory()->object_to_string(); 16418 } 16419 UNREACHABLE(); 16420 tag = handle(receiver->class_name(), isolate); 16421 break; 16422 } 16423 default: 16424 return isolate->factory()->object_to_string(); 16425 } 16426 } 16427 16428 IncrementalStringBuilder builder(isolate); 16429 builder.AppendCString("[object "); 16430 builder.AppendString(tag); 16431 builder.AppendCharacter(']'); 16432 return builder.Finish(); 16433 } 16434 16435 const char* Symbol::PrivateSymbolToName() const { 16436 Heap* heap = GetIsolate()->heap(); 16437 #define SYMBOL_CHECK_AND_PRINT(name) \ 16438 if (this == heap->name()) return #name; 16439 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT) 16440 #undef SYMBOL_CHECK_AND_PRINT 16441 return "UNKNOWN"; 16442 } 16443 16444 16445 void Symbol::SymbolShortPrint(std::ostream& os) { 16446 os << "<Symbol:"; 16447 if (!name()->IsUndefined(GetIsolate())) { 16448 os << " "; 16449 HeapStringAllocator allocator; 16450 StringStream accumulator(&allocator); 16451 String::cast(name())->StringShortPrint(&accumulator, false); 16452 os << accumulator.ToCString().get(); 16453 } else { 16454 os << " (" << PrivateSymbolToName() << ")"; 16455 } 16456 os << ">"; 16457 } 16458 16459 16460 // StringSharedKeys are used as keys in the eval cache. 16461 class StringSharedKey : public HashTableKey { 16462 public: 16463 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared, 16464 LanguageMode language_mode, int scope_position) 16465 : source_(source), 16466 shared_(shared), 16467 language_mode_(language_mode), 16468 scope_position_(scope_position) {} 16469 16470 bool IsMatch(Object* other) override { 16471 DisallowHeapAllocation no_allocation; 16472 if (!other->IsFixedArray()) { 16473 if (!other->IsNumber()) return false; 16474 uint32_t other_hash = static_cast<uint32_t>(other->Number()); 16475 return Hash() == other_hash; 16476 } 16477 FixedArray* other_array = FixedArray::cast(other); 16478 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0)); 16479 if (shared != *shared_) return false; 16480 int language_unchecked = Smi::cast(other_array->get(2))->value(); 16481 DCHECK(is_valid_language_mode(language_unchecked)); 16482 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked); 16483 if (language_mode != language_mode_) return false; 16484 int scope_position = Smi::cast(other_array->get(3))->value(); 16485 if (scope_position != scope_position_) return false; 16486 String* source = String::cast(other_array->get(1)); 16487 return source->Equals(*source_); 16488 } 16489 16490 static uint32_t StringSharedHashHelper(String* source, 16491 SharedFunctionInfo* shared, 16492 LanguageMode language_mode, 16493 int scope_position) { 16494 uint32_t hash = source->Hash(); 16495 if (shared->HasSourceCode()) { 16496 // Instead of using the SharedFunctionInfo pointer in the hash 16497 // code computation, we use a combination of the hash of the 16498 // script source code and the start position of the calling scope. 16499 // We do this to ensure that the cache entries can survive garbage 16500 // collection. 16501 Script* script(Script::cast(shared->script())); 16502 hash ^= String::cast(script->source())->Hash(); 16503 STATIC_ASSERT(LANGUAGE_END == 2); 16504 if (is_strict(language_mode)) hash ^= 0x8000; 16505 hash += scope_position; 16506 } 16507 return hash; 16508 } 16509 16510 uint32_t Hash() override { 16511 return StringSharedHashHelper(*source_, *shared_, language_mode_, 16512 scope_position_); 16513 } 16514 16515 uint32_t HashForObject(Object* obj) override { 16516 DisallowHeapAllocation no_allocation; 16517 if (obj->IsNumber()) { 16518 return static_cast<uint32_t>(obj->Number()); 16519 } 16520 FixedArray* other_array = FixedArray::cast(obj); 16521 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0)); 16522 String* source = String::cast(other_array->get(1)); 16523 int language_unchecked = Smi::cast(other_array->get(2))->value(); 16524 DCHECK(is_valid_language_mode(language_unchecked)); 16525 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked); 16526 int scope_position = Smi::cast(other_array->get(3))->value(); 16527 return StringSharedHashHelper(source, shared, language_mode, 16528 scope_position); 16529 } 16530 16531 16532 Handle<Object> AsHandle(Isolate* isolate) override { 16533 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4); 16534 array->set(0, *shared_); 16535 array->set(1, *source_); 16536 array->set(2, Smi::FromInt(language_mode_)); 16537 array->set(3, Smi::FromInt(scope_position_)); 16538 return array; 16539 } 16540 16541 private: 16542 Handle<String> source_; 16543 Handle<SharedFunctionInfo> shared_; 16544 LanguageMode language_mode_; 16545 int scope_position_; 16546 }; 16547 16548 16549 namespace { 16550 16551 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) { 16552 JSRegExp::Flags value = JSRegExp::kNone; 16553 int length = flags->length(); 16554 // A longer flags string cannot be valid. 16555 if (length > 5) return JSRegExp::Flags(0); 16556 for (int i = 0; i < length; i++) { 16557 JSRegExp::Flag flag = JSRegExp::kNone; 16558 switch (flags->Get(i)) { 16559 case 'g': 16560 flag = JSRegExp::kGlobal; 16561 break; 16562 case 'i': 16563 flag = JSRegExp::kIgnoreCase; 16564 break; 16565 case 'm': 16566 flag = JSRegExp::kMultiline; 16567 break; 16568 case 'u': 16569 flag = JSRegExp::kUnicode; 16570 break; 16571 case 'y': 16572 flag = JSRegExp::kSticky; 16573 break; 16574 default: 16575 return JSRegExp::Flags(0); 16576 } 16577 // Duplicate flag. 16578 if (value & flag) return JSRegExp::Flags(0); 16579 value |= flag; 16580 } 16581 *success = true; 16582 return value; 16583 } 16584 16585 } // namespace 16586 16587 16588 // static 16589 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) { 16590 Isolate* isolate = pattern->GetIsolate(); 16591 Handle<JSFunction> constructor = isolate->regexp_function(); 16592 Handle<JSRegExp> regexp = 16593 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor)); 16594 16595 return JSRegExp::Initialize(regexp, pattern, flags); 16596 } 16597 16598 16599 // static 16600 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) { 16601 Isolate* const isolate = regexp->GetIsolate(); 16602 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp)); 16603 } 16604 16605 16606 template <typename Char> 16607 inline int CountRequiredEscapes(Handle<String> source) { 16608 DisallowHeapAllocation no_gc; 16609 int escapes = 0; 16610 Vector<const Char> src = source->GetCharVector<Char>(); 16611 for (int i = 0; i < src.length(); i++) { 16612 if (src[i] == '\\') { 16613 // Escape. Skip next character; 16614 i++; 16615 } else if (src[i] == '/') { 16616 // Not escaped forward-slash needs escape. 16617 escapes++; 16618 } 16619 } 16620 return escapes; 16621 } 16622 16623 16624 template <typename Char, typename StringType> 16625 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, 16626 Handle<StringType> result) { 16627 DisallowHeapAllocation no_gc; 16628 Vector<const Char> src = source->GetCharVector<Char>(); 16629 Vector<Char> dst(result->GetChars(), result->length()); 16630 int s = 0; 16631 int d = 0; 16632 while (s < src.length()) { 16633 if (src[s] == '\\') { 16634 // Escape. Copy this and next character. 16635 dst[d++] = src[s++]; 16636 if (s == src.length()) break; 16637 } else if (src[s] == '/') { 16638 // Not escaped forward-slash needs escape. 16639 dst[d++] = '\\'; 16640 } 16641 dst[d++] = src[s++]; 16642 } 16643 DCHECK_EQ(result->length(), d); 16644 return result; 16645 } 16646 16647 16648 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate, 16649 Handle<String> source) { 16650 String::Flatten(source); 16651 if (source->length() == 0) return isolate->factory()->query_colon_string(); 16652 bool one_byte = source->IsOneByteRepresentationUnderneath(); 16653 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source) 16654 : CountRequiredEscapes<uc16>(source); 16655 if (escapes == 0) return source; 16656 int length = source->length() + escapes; 16657 if (one_byte) { 16658 Handle<SeqOneByteString> result; 16659 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 16660 isolate->factory()->NewRawOneByteString(length), 16661 String); 16662 return WriteEscapedRegExpSource<uint8_t>(source, result); 16663 } else { 16664 Handle<SeqTwoByteString> result; 16665 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 16666 isolate->factory()->NewRawTwoByteString(length), 16667 String); 16668 return WriteEscapedRegExpSource<uc16>(source, result); 16669 } 16670 } 16671 16672 16673 // static 16674 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, 16675 Handle<String> source, 16676 Handle<String> flags_string) { 16677 Isolate* isolate = source->GetIsolate(); 16678 bool success = false; 16679 Flags flags = RegExpFlagsFromString(flags_string, &success); 16680 if (!success) { 16681 THROW_NEW_ERROR( 16682 isolate, 16683 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string), 16684 JSRegExp); 16685 } 16686 return Initialize(regexp, source, flags); 16687 } 16688 16689 16690 // static 16691 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, 16692 Handle<String> source, Flags flags) { 16693 Isolate* isolate = regexp->GetIsolate(); 16694 Factory* factory = isolate->factory(); 16695 // If source is the empty string we set it to "(?:)" instead as 16696 // suggested by ECMA-262, 5th, section 15.10.4.1. 16697 if (source->length() == 0) source = factory->query_colon_string(); 16698 16699 Handle<String> escaped_source; 16700 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source, 16701 EscapeRegExpSource(isolate, source), JSRegExp); 16702 16703 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags), 16704 JSRegExp); 16705 16706 regexp->set_source(*escaped_source); 16707 regexp->set_flags(Smi::FromInt(flags)); 16708 16709 Map* map = regexp->map(); 16710 Object* constructor = map->GetConstructor(); 16711 if (constructor->IsJSFunction() && 16712 JSFunction::cast(constructor)->initial_map() == map) { 16713 // If we still have the original map, set in-object properties directly. 16714 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero, 16715 SKIP_WRITE_BARRIER); 16716 } else { 16717 // Map has changed, so use generic, but slower, method. 16718 RETURN_ON_EXCEPTION(isolate, JSReceiver::SetProperty( 16719 regexp, factory->lastIndex_string(), 16720 Handle<Smi>(Smi::kZero, isolate), STRICT), 16721 JSRegExp); 16722 } 16723 16724 return regexp; 16725 } 16726 16727 16728 // RegExpKey carries the source and flags of a regular expression as key. 16729 class RegExpKey : public HashTableKey { 16730 public: 16731 RegExpKey(Handle<String> string, JSRegExp::Flags flags) 16732 : string_(string), flags_(Smi::FromInt(flags)) {} 16733 16734 // Rather than storing the key in the hash table, a pointer to the 16735 // stored value is stored where the key should be. IsMatch then 16736 // compares the search key to the found object, rather than comparing 16737 // a key to a key. 16738 bool IsMatch(Object* obj) override { 16739 FixedArray* val = FixedArray::cast(obj); 16740 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex))) 16741 && (flags_ == val->get(JSRegExp::kFlagsIndex)); 16742 } 16743 16744 uint32_t Hash() override { return RegExpHash(*string_, flags_); } 16745 16746 Handle<Object> AsHandle(Isolate* isolate) override { 16747 // Plain hash maps, which is where regexp keys are used, don't 16748 // use this function. 16749 UNREACHABLE(); 16750 return MaybeHandle<Object>().ToHandleChecked(); 16751 } 16752 16753 uint32_t HashForObject(Object* obj) override { 16754 FixedArray* val = FixedArray::cast(obj); 16755 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)), 16756 Smi::cast(val->get(JSRegExp::kFlagsIndex))); 16757 } 16758 16759 static uint32_t RegExpHash(String* string, Smi* flags) { 16760 return string->Hash() + flags->value(); 16761 } 16762 16763 Handle<String> string_; 16764 Smi* flags_; 16765 }; 16766 16767 16768 Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) { 16769 if (hash_field_ == 0) Hash(); 16770 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_); 16771 } 16772 16773 16774 Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) { 16775 if (hash_field_ == 0) Hash(); 16776 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_); 16777 } 16778 16779 16780 Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) { 16781 if (hash_field_ == 0) Hash(); 16782 return isolate->factory()->NewOneByteInternalizedSubString( 16783 string_, from_, length_, hash_field_); 16784 } 16785 16786 16787 bool SeqOneByteSubStringKey::IsMatch(Object* string) { 16788 Vector<const uint8_t> chars(string_->GetChars() + from_, length_); 16789 return String::cast(string)->IsOneByteEqualTo(chars); 16790 } 16791 16792 16793 // InternalizedStringKey carries a string/internalized-string object as key. 16794 class InternalizedStringKey : public HashTableKey { 16795 public: 16796 explicit InternalizedStringKey(Handle<String> string) 16797 : string_(String::Flatten(string)) {} 16798 16799 bool IsMatch(Object* string) override { 16800 return String::cast(string)->Equals(*string_); 16801 } 16802 16803 uint32_t Hash() override { return string_->Hash(); } 16804 16805 uint32_t HashForObject(Object* other) override { 16806 return String::cast(other)->Hash(); 16807 } 16808 16809 Handle<Object> AsHandle(Isolate* isolate) override { 16810 // Internalize the string if possible. 16811 MaybeHandle<Map> maybe_map = 16812 isolate->factory()->InternalizedStringMapForString(string_); 16813 Handle<Map> map; 16814 if (maybe_map.ToHandle(&map)) { 16815 string_->set_map_no_write_barrier(*map); 16816 DCHECK(string_->IsInternalizedString()); 16817 return string_; 16818 } 16819 // Otherwise allocate a new internalized string. 16820 return isolate->factory()->NewInternalizedStringImpl( 16821 string_, string_->length(), string_->hash_field()); 16822 } 16823 16824 static uint32_t StringHash(Object* obj) { 16825 return String::cast(obj)->Hash(); 16826 } 16827 16828 Handle<String> string_; 16829 }; 16830 16831 16832 template<typename Derived, typename Shape, typename Key> 16833 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { 16834 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); 16835 } 16836 16837 16838 template<typename Derived, typename Shape, typename Key> 16839 void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) { 16840 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset, 16841 kHeaderSize + length() * kPointerSize, v); 16842 } 16843 16844 16845 template<typename Derived, typename Shape, typename Key> 16846 Handle<Derived> HashTable<Derived, Shape, Key>::New( 16847 Isolate* isolate, 16848 int at_least_space_for, 16849 MinimumCapacity capacity_option, 16850 PretenureFlag pretenure) { 16851 DCHECK(0 <= at_least_space_for); 16852 DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY, 16853 base::bits::IsPowerOfTwo32(at_least_space_for)); 16854 16855 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY) 16856 ? at_least_space_for 16857 : ComputeCapacity(at_least_space_for); 16858 if (capacity > HashTable::kMaxCapacity) { 16859 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true); 16860 } 16861 16862 Factory* factory = isolate->factory(); 16863 int length = EntryToIndex(capacity); 16864 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure); 16865 array->set_map_no_write_barrier(Shape::GetMap(isolate)); 16866 Handle<Derived> table = Handle<Derived>::cast(array); 16867 16868 table->SetNumberOfElements(0); 16869 table->SetNumberOfDeletedElements(0); 16870 table->SetCapacity(capacity); 16871 return table; 16872 } 16873 16874 16875 // Find entry for key otherwise return kNotFound. 16876 template <typename Derived, typename Shape> 16877 int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) { 16878 if (!key->IsUniqueName()) { 16879 return DerivedDictionary::FindEntry(key); 16880 } 16881 16882 // Optimized for unique names. Knowledge of the key type allows: 16883 // 1. Move the check if the key is unique out of the loop. 16884 // 2. Avoid comparing hash codes in unique-to-unique comparison. 16885 // 3. Detect a case when a dictionary key is not unique but the key is. 16886 // In case of positive result the dictionary key may be replaced by the 16887 // internalized string with minimal performance penalty. It gives a chance 16888 // to perform further lookups in code stubs (and significant performance 16889 // boost a certain style of code). 16890 16891 // EnsureCapacity will guarantee the hash table is never full. 16892 uint32_t capacity = this->Capacity(); 16893 uint32_t entry = Derived::FirstProbe(key->Hash(), capacity); 16894 uint32_t count = 1; 16895 Isolate* isolate = this->GetIsolate(); 16896 while (true) { 16897 Object* element = this->KeyAt(entry); 16898 if (element->IsUndefined(isolate)) break; // Empty entry. 16899 if (*key == element) return entry; 16900 DCHECK(element->IsTheHole(isolate) || element->IsUniqueName()); 16901 entry = Derived::NextProbe(entry, count++, capacity); 16902 } 16903 return Derived::kNotFound; 16904 } 16905 16906 16907 template<typename Derived, typename Shape, typename Key> 16908 void HashTable<Derived, Shape, Key>::Rehash( 16909 Handle<Derived> new_table, 16910 Key key) { 16911 DCHECK(NumberOfElements() < new_table->Capacity()); 16912 16913 DisallowHeapAllocation no_gc; 16914 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc); 16915 16916 // Copy prefix to new array. 16917 for (int i = kPrefixStartIndex; 16918 i < kPrefixStartIndex + Shape::kPrefixSize; 16919 i++) { 16920 new_table->set(i, get(i), mode); 16921 } 16922 16923 // Rehash the elements. 16924 int capacity = this->Capacity(); 16925 Heap* heap = new_table->GetHeap(); 16926 Object* the_hole = heap->the_hole_value(); 16927 Object* undefined = heap->undefined_value(); 16928 for (int i = 0; i < capacity; i++) { 16929 uint32_t from_index = EntryToIndex(i); 16930 Object* k = this->get(from_index); 16931 if (k != the_hole && k != undefined) { 16932 uint32_t hash = this->HashForObject(key, k); 16933 uint32_t insertion_index = 16934 EntryToIndex(new_table->FindInsertionEntry(hash)); 16935 for (int j = 0; j < Shape::kEntrySize; j++) { 16936 new_table->set(insertion_index + j, get(from_index + j), mode); 16937 } 16938 } 16939 } 16940 new_table->SetNumberOfElements(NumberOfElements()); 16941 new_table->SetNumberOfDeletedElements(0); 16942 } 16943 16944 16945 template<typename Derived, typename Shape, typename Key> 16946 uint32_t HashTable<Derived, Shape, Key>::EntryForProbe( 16947 Key key, 16948 Object* k, 16949 int probe, 16950 uint32_t expected) { 16951 uint32_t hash = this->HashForObject(key, k); 16952 uint32_t capacity = this->Capacity(); 16953 uint32_t entry = FirstProbe(hash, capacity); 16954 for (int i = 1; i < probe; i++) { 16955 if (entry == expected) return expected; 16956 entry = NextProbe(entry, i, capacity); 16957 } 16958 return entry; 16959 } 16960 16961 16962 template<typename Derived, typename Shape, typename Key> 16963 void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1, 16964 uint32_t entry2, 16965 WriteBarrierMode mode) { 16966 int index1 = EntryToIndex(entry1); 16967 int index2 = EntryToIndex(entry2); 16968 Object* temp[Shape::kEntrySize]; 16969 for (int j = 0; j < Shape::kEntrySize; j++) { 16970 temp[j] = get(index1 + j); 16971 } 16972 for (int j = 0; j < Shape::kEntrySize; j++) { 16973 set(index1 + j, get(index2 + j), mode); 16974 } 16975 for (int j = 0; j < Shape::kEntrySize; j++) { 16976 set(index2 + j, temp[j], mode); 16977 } 16978 } 16979 16980 16981 template<typename Derived, typename Shape, typename Key> 16982 void HashTable<Derived, Shape, Key>::Rehash(Key key) { 16983 DisallowHeapAllocation no_gc; 16984 WriteBarrierMode mode = GetWriteBarrierMode(no_gc); 16985 Isolate* isolate = GetIsolate(); 16986 uint32_t capacity = Capacity(); 16987 bool done = false; 16988 for (int probe = 1; !done; probe++) { 16989 // All elements at entries given by one of the first _probe_ probes 16990 // are placed correctly. Other elements might need to be moved. 16991 done = true; 16992 for (uint32_t current = 0; current < capacity; current++) { 16993 Object* current_key = KeyAt(current); 16994 if (IsKey(isolate, current_key)) { 16995 uint32_t target = EntryForProbe(key, current_key, probe, current); 16996 if (current == target) continue; 16997 Object* target_key = KeyAt(target); 16998 if (!IsKey(target_key) || 16999 EntryForProbe(key, target_key, probe, target) != target) { 17000 // Put the current element into the correct position. 17001 Swap(current, target, mode); 17002 // The other element will be processed on the next iteration. 17003 current--; 17004 } else { 17005 // The place for the current element is occupied. Leave the element 17006 // for the next probe. 17007 done = false; 17008 } 17009 } 17010 } 17011 } 17012 // Wipe deleted entries. 17013 Object* the_hole = isolate->heap()->the_hole_value(); 17014 Object* undefined = isolate->heap()->undefined_value(); 17015 for (uint32_t current = 0; current < capacity; current++) { 17016 if (KeyAt(current) == the_hole) { 17017 set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined); 17018 } 17019 } 17020 SetNumberOfDeletedElements(0); 17021 } 17022 17023 17024 template<typename Derived, typename Shape, typename Key> 17025 Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity( 17026 Handle<Derived> table, 17027 int n, 17028 Key key, 17029 PretenureFlag pretenure) { 17030 Isolate* isolate = table->GetIsolate(); 17031 int capacity = table->Capacity(); 17032 int nof = table->NumberOfElements() + n; 17033 17034 if (table->HasSufficientCapacityToAdd(n)) return table; 17035 17036 const int kMinCapacityForPretenure = 256; 17037 bool should_pretenure = pretenure == TENURED || 17038 ((capacity > kMinCapacityForPretenure) && 17039 !isolate->heap()->InNewSpace(*table)); 17040 Handle<Derived> new_table = HashTable::New( 17041 isolate, 17042 nof * 2, 17043 USE_DEFAULT_MINIMUM_CAPACITY, 17044 should_pretenure ? TENURED : NOT_TENURED); 17045 17046 table->Rehash(new_table, key); 17047 return new_table; 17048 } 17049 17050 template <typename Derived, typename Shape, typename Key> 17051 bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd( 17052 int number_of_additional_elements) { 17053 int capacity = Capacity(); 17054 int nof = NumberOfElements() + number_of_additional_elements; 17055 int nod = NumberOfDeletedElements(); 17056 // Return true if: 17057 // 50% is still free after adding number_of_additional_elements elements and 17058 // at most 50% of the free elements are deleted elements. 17059 if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) { 17060 int needed_free = nof >> 1; 17061 if (nof + needed_free <= capacity) return true; 17062 } 17063 return false; 17064 } 17065 17066 17067 template<typename Derived, typename Shape, typename Key> 17068 Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table, 17069 Key key) { 17070 int capacity = table->Capacity(); 17071 int nof = table->NumberOfElements(); 17072 17073 // Shrink to fit the number of elements if only a quarter of the 17074 // capacity is filled with elements. 17075 if (nof > (capacity >> 2)) return table; 17076 // Allocate a new dictionary with room for at least the current 17077 // number of elements. The allocation method will make sure that 17078 // there is extra room in the dictionary for additions. Don't go 17079 // lower than room for 16 elements. 17080 int at_least_room_for = nof; 17081 if (at_least_room_for < 16) return table; 17082 17083 Isolate* isolate = table->GetIsolate(); 17084 const int kMinCapacityForPretenure = 256; 17085 bool pretenure = 17086 (at_least_room_for > kMinCapacityForPretenure) && 17087 !isolate->heap()->InNewSpace(*table); 17088 Handle<Derived> new_table = HashTable::New( 17089 isolate, 17090 at_least_room_for, 17091 USE_DEFAULT_MINIMUM_CAPACITY, 17092 pretenure ? TENURED : NOT_TENURED); 17093 17094 table->Rehash(new_table, key); 17095 return new_table; 17096 } 17097 17098 17099 template<typename Derived, typename Shape, typename Key> 17100 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) { 17101 uint32_t capacity = Capacity(); 17102 uint32_t entry = FirstProbe(hash, capacity); 17103 uint32_t count = 1; 17104 // EnsureCapacity will guarantee the hash table is never full. 17105 Isolate* isolate = GetIsolate(); 17106 while (true) { 17107 Object* element = KeyAt(entry); 17108 if (!IsKey(isolate, element)) break; 17109 entry = NextProbe(entry, count++, capacity); 17110 } 17111 return entry; 17112 } 17113 17114 17115 // Force instantiation of template instances class. 17116 // Please note this list is compiler dependent. 17117 17118 template class HashTable<StringTable, StringTableShape, HashTableKey*>; 17119 17120 template class HashTable<CompilationCacheTable, 17121 CompilationCacheShape, 17122 HashTableKey*>; 17123 17124 template class HashTable<ObjectHashTable, 17125 ObjectHashTableShape, 17126 Handle<Object> >; 17127 17128 template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >; 17129 17130 template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >; 17131 17132 template class Dictionary<GlobalDictionary, GlobalDictionaryShape, 17133 Handle<Name> >; 17134 17135 template class Dictionary<SeededNumberDictionary, 17136 SeededNumberDictionaryShape, 17137 uint32_t>; 17138 17139 template class Dictionary<UnseededNumberDictionary, 17140 UnseededNumberDictionaryShape, 17141 uint32_t>; 17142 17143 template Handle<SeededNumberDictionary> 17144 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New( 17145 Isolate*, int at_least_space_for, PretenureFlag pretenure, 17146 MinimumCapacity capacity_option); 17147 17148 template Handle<UnseededNumberDictionary> 17149 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, 17150 uint32_t>::New(Isolate*, int at_least_space_for, 17151 PretenureFlag pretenure, 17152 MinimumCapacity capacity_option); 17153 17154 template Handle<NameDictionary> 17155 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New( 17156 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option); 17157 17158 template Handle<GlobalDictionary> 17159 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New( 17160 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option); 17161 17162 template Handle<SeededNumberDictionary> 17163 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 17164 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>); 17165 17166 template Handle<UnseededNumberDictionary> 17167 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>:: 17168 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>); 17169 17170 template Object* 17171 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 17172 SlowReverseLookup(Object* value); 17173 17174 template Object* 17175 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >:: 17176 SlowReverseLookup(Object* value); 17177 17178 template Handle<Object> 17179 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty( 17180 Handle<NameDictionary>, int); 17181 17182 template Handle<Object> 17183 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, 17184 uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int); 17185 17186 template Handle<Object> 17187 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, 17188 uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int); 17189 17190 template Handle<NameDictionary> 17191 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >:: 17192 New(Isolate*, int, MinimumCapacity, PretenureFlag); 17193 17194 template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape, 17195 Handle<Object>>::New(Isolate*, int n, 17196 MinimumCapacity, 17197 PretenureFlag); 17198 17199 template Handle<NameDictionary> 17200 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >:: 17201 Shrink(Handle<NameDictionary>, Handle<Name>); 17202 17203 template Handle<SeededNumberDictionary> 17204 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 17205 Shrink(Handle<SeededNumberDictionary>, uint32_t); 17206 17207 template Handle<UnseededNumberDictionary> 17208 HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape, 17209 uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t); 17210 17211 template Handle<NameDictionary> 17212 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add( 17213 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails, 17214 int*); 17215 17216 template Handle<GlobalDictionary> 17217 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add( 17218 Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails, 17219 int*); 17220 17221 template Handle<FixedArray> Dictionary< 17222 NameDictionary, NameDictionaryShape, 17223 Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>); 17224 17225 template Handle<FixedArray> Dictionary< 17226 NameDictionary, NameDictionaryShape, 17227 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>); 17228 17229 template Handle<SeededNumberDictionary> 17230 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add( 17231 Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails, 17232 int*); 17233 17234 template Handle<UnseededNumberDictionary> 17235 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, 17236 uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t, 17237 Handle<Object>, PropertyDetails, int*); 17238 17239 template Handle<SeededNumberDictionary> 17240 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 17241 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t); 17242 17243 template Handle<UnseededNumberDictionary> 17244 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>:: 17245 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t); 17246 17247 template void Dictionary<NameDictionary, NameDictionaryShape, 17248 Handle<Name> >::SetRequiresCopyOnCapacityChange(); 17249 17250 template Handle<NameDictionary> 17251 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >:: 17252 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>); 17253 17254 template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, 17255 uint32_t>::FindEntry(uint32_t); 17256 17257 template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry( 17258 Handle<Name>); 17259 17260 template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 17261 NumberOfElementsFilterAttributes(PropertyFilter filter); 17262 17263 template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>:: 17264 NumberOfElementsFilterAttributes(PropertyFilter filter); 17265 17266 template void 17267 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 17268 CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape, 17269 Handle<Name>>> 17270 dictionary, 17271 Handle<FixedArray> storage, KeyCollectionMode mode, 17272 KeyAccumulator* accumulator); 17273 17274 template void 17275 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo( 17276 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>> 17277 dictionary, 17278 Handle<FixedArray> storage, KeyCollectionMode mode, 17279 KeyAccumulator* accumulator); 17280 17281 template void 17282 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 17283 CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape, 17284 Handle<Name>>> 17285 dictionary, 17286 KeyAccumulator* keys); 17287 17288 template void 17289 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo( 17290 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>> 17291 dictionary, 17292 KeyAccumulator* keys); 17293 17294 Handle<Object> JSObject::PrepareSlowElementsForSort( 17295 Handle<JSObject> object, uint32_t limit) { 17296 DCHECK(object->HasDictionaryElements()); 17297 Isolate* isolate = object->GetIsolate(); 17298 // Must stay in dictionary mode, either because of requires_slow_elements, 17299 // or because we are not going to sort (and therefore compact) all of the 17300 // elements. 17301 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate); 17302 Handle<SeededNumberDictionary> new_dict = 17303 SeededNumberDictionary::New(isolate, dict->NumberOfElements()); 17304 17305 uint32_t pos = 0; 17306 uint32_t undefs = 0; 17307 int capacity = dict->Capacity(); 17308 Handle<Smi> bailout(Smi::FromInt(-1), isolate); 17309 // Entry to the new dictionary does not cause it to grow, as we have 17310 // allocated one that is large enough for all entries. 17311 DisallowHeapAllocation no_gc; 17312 for (int i = 0; i < capacity; i++) { 17313 Object* k = dict->KeyAt(i); 17314 if (!dict->IsKey(isolate, k)) continue; 17315 17316 DCHECK(k->IsNumber()); 17317 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0); 17318 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0); 17319 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32); 17320 17321 HandleScope scope(isolate); 17322 Handle<Object> value(dict->ValueAt(i), isolate); 17323 PropertyDetails details = dict->DetailsAt(i); 17324 if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) { 17325 // Bail out and do the sorting of undefineds and array holes in JS. 17326 // Also bail out if the element is not supposed to be moved. 17327 return bailout; 17328 } 17329 17330 uint32_t key = NumberToUint32(k); 17331 if (key < limit) { 17332 if (value->IsUndefined(isolate)) { 17333 undefs++; 17334 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { 17335 // Adding an entry with the key beyond smi-range requires 17336 // allocation. Bailout. 17337 return bailout; 17338 } else { 17339 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 17340 new_dict, pos, value, details, object->map()->is_prototype_map()); 17341 DCHECK(result.is_identical_to(new_dict)); 17342 USE(result); 17343 pos++; 17344 } 17345 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) { 17346 // Adding an entry with the key beyond smi-range requires 17347 // allocation. Bailout. 17348 return bailout; 17349 } else { 17350 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 17351 new_dict, key, value, details, object->map()->is_prototype_map()); 17352 DCHECK(result.is_identical_to(new_dict)); 17353 USE(result); 17354 } 17355 } 17356 17357 uint32_t result = pos; 17358 PropertyDetails no_details = PropertyDetails::Empty(); 17359 while (undefs > 0) { 17360 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { 17361 // Adding an entry with the key beyond smi-range requires 17362 // allocation. Bailout. 17363 return bailout; 17364 } 17365 HandleScope scope(isolate); 17366 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 17367 new_dict, pos, isolate->factory()->undefined_value(), no_details, 17368 object->map()->is_prototype_map()); 17369 DCHECK(result.is_identical_to(new_dict)); 17370 USE(result); 17371 pos++; 17372 undefs--; 17373 } 17374 17375 object->set_elements(*new_dict); 17376 17377 AllowHeapAllocation allocate_return_value; 17378 return isolate->factory()->NewNumberFromUint(result); 17379 } 17380 17381 17382 // Collects all defined (non-hole) and non-undefined (array) elements at 17383 // the start of the elements array. 17384 // If the object is in dictionary mode, it is converted to fast elements 17385 // mode. 17386 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object, 17387 uint32_t limit) { 17388 Isolate* isolate = object->GetIsolate(); 17389 if (object->HasSloppyArgumentsElements()) { 17390 return handle(Smi::FromInt(-1), isolate); 17391 } 17392 17393 if (object->HasStringWrapperElements()) { 17394 int len = String::cast(Handle<JSValue>::cast(object)->value())->length(); 17395 return handle(Smi::FromInt(len), isolate); 17396 } 17397 17398 if (object->HasDictionaryElements()) { 17399 // Convert to fast elements containing only the existing properties. 17400 // Ordering is irrelevant, since we are going to sort anyway. 17401 Handle<SeededNumberDictionary> dict(object->element_dictionary()); 17402 if (object->IsJSArray() || dict->requires_slow_elements() || 17403 dict->max_number_key() >= limit) { 17404 return JSObject::PrepareSlowElementsForSort(object, limit); 17405 } 17406 // Convert to fast elements. 17407 17408 Handle<Map> new_map = 17409 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS); 17410 17411 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ? 17412 NOT_TENURED: TENURED; 17413 Handle<FixedArray> fast_elements = 17414 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure); 17415 dict->CopyValuesTo(*fast_elements); 17416 JSObject::ValidateElements(object); 17417 17418 JSObject::SetMapAndElements(object, new_map, fast_elements); 17419 } else if (object->HasFixedTypedArrayElements()) { 17420 // Typed arrays cannot have holes or undefined elements. 17421 return handle(Smi::FromInt( 17422 FixedArrayBase::cast(object->elements())->length()), isolate); 17423 } else if (!object->HasFastDoubleElements()) { 17424 EnsureWritableFastElements(object); 17425 } 17426 DCHECK(object->HasFastSmiOrObjectElements() || 17427 object->HasFastDoubleElements()); 17428 17429 // Collect holes at the end, undefined before that and the rest at the 17430 // start, and return the number of non-hole, non-undefined values. 17431 17432 Handle<FixedArrayBase> elements_base(object->elements()); 17433 uint32_t elements_length = static_cast<uint32_t>(elements_base->length()); 17434 if (limit > elements_length) { 17435 limit = elements_length; 17436 } 17437 if (limit == 0) { 17438 return handle(Smi::kZero, isolate); 17439 } 17440 17441 uint32_t result = 0; 17442 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) { 17443 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base); 17444 // Split elements into defined and the_hole, in that order. 17445 unsigned int holes = limit; 17446 // Assume most arrays contain no holes and undefined values, so minimize the 17447 // number of stores of non-undefined, non-the-hole values. 17448 for (unsigned int i = 0; i < holes; i++) { 17449 if (elements->is_the_hole(i)) { 17450 holes--; 17451 } else { 17452 continue; 17453 } 17454 // Position i needs to be filled. 17455 while (holes > i) { 17456 if (elements->is_the_hole(holes)) { 17457 holes--; 17458 } else { 17459 elements->set(i, elements->get_scalar(holes)); 17460 break; 17461 } 17462 } 17463 } 17464 result = holes; 17465 while (holes < limit) { 17466 elements->set_the_hole(holes); 17467 holes++; 17468 } 17469 } else { 17470 FixedArray* elements = FixedArray::cast(*elements_base); 17471 DisallowHeapAllocation no_gc; 17472 17473 // Split elements into defined, undefined and the_hole, in that order. Only 17474 // count locations for undefined and the hole, and fill them afterwards. 17475 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc); 17476 unsigned int undefs = limit; 17477 unsigned int holes = limit; 17478 // Assume most arrays contain no holes and undefined values, so minimize the 17479 // number of stores of non-undefined, non-the-hole values. 17480 for (unsigned int i = 0; i < undefs; i++) { 17481 Object* current = elements->get(i); 17482 if (current->IsTheHole(isolate)) { 17483 holes--; 17484 undefs--; 17485 } else if (current->IsUndefined(isolate)) { 17486 undefs--; 17487 } else { 17488 continue; 17489 } 17490 // Position i needs to be filled. 17491 while (undefs > i) { 17492 current = elements->get(undefs); 17493 if (current->IsTheHole(isolate)) { 17494 holes--; 17495 undefs--; 17496 } else if (current->IsUndefined(isolate)) { 17497 undefs--; 17498 } else { 17499 elements->set(i, current, write_barrier); 17500 break; 17501 } 17502 } 17503 } 17504 result = undefs; 17505 while (undefs < holes) { 17506 elements->set_undefined(undefs); 17507 undefs++; 17508 } 17509 while (holes < limit) { 17510 elements->set_the_hole(holes); 17511 holes++; 17512 } 17513 } 17514 17515 return isolate->factory()->NewNumberFromUint(result); 17516 } 17517 17518 17519 ExternalArrayType JSTypedArray::type() { 17520 switch (elements()->map()->instance_type()) { 17521 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \ 17522 case FIXED_##TYPE##_ARRAY_TYPE: \ 17523 return kExternal##Type##Array; 17524 17525 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE) 17526 #undef INSTANCE_TYPE_TO_ARRAY_TYPE 17527 17528 default: 17529 UNREACHABLE(); 17530 return static_cast<ExternalArrayType>(-1); 17531 } 17532 } 17533 17534 17535 size_t JSTypedArray::element_size() { 17536 switch (elements()->map()->instance_type()) { 17537 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \ 17538 case FIXED_##TYPE##_ARRAY_TYPE: \ 17539 return size; 17540 17541 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE) 17542 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE 17543 17544 default: 17545 UNREACHABLE(); 17546 return 0; 17547 } 17548 } 17549 17550 17551 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global, 17552 Handle<Name> name) { 17553 DCHECK(!global->HasFastProperties()); 17554 auto dictionary = handle(global->global_dictionary()); 17555 int entry = dictionary->FindEntry(name); 17556 if (entry == GlobalDictionary::kNotFound) return; 17557 PropertyCell::InvalidateEntry(dictionary, entry); 17558 } 17559 17560 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell( 17561 Handle<JSGlobalObject> global, Handle<Name> name, 17562 PropertyCellType cell_type, int* entry_out) { 17563 Isolate* isolate = global->GetIsolate(); 17564 DCHECK(!global->HasFastProperties()); 17565 Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate); 17566 int entry = dictionary->FindEntry(name); 17567 Handle<PropertyCell> cell; 17568 if (entry != GlobalDictionary::kNotFound) { 17569 if (entry_out) *entry_out = entry; 17570 // This call should be idempotent. 17571 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 17572 cell = handle(PropertyCell::cast(dictionary->ValueAt(entry))); 17573 PropertyCellType original_cell_type = cell->property_details().cell_type(); 17574 DCHECK(original_cell_type == PropertyCellType::kInvalidated || 17575 original_cell_type == PropertyCellType::kUninitialized); 17576 DCHECK(cell->value()->IsTheHole(isolate)); 17577 if (original_cell_type == PropertyCellType::kInvalidated) { 17578 cell = PropertyCell::InvalidateEntry(dictionary, entry); 17579 } 17580 PropertyDetails details(NONE, DATA, 0, cell_type); 17581 cell->set_property_details(details); 17582 return cell; 17583 } 17584 cell = isolate->factory()->NewPropertyCell(); 17585 PropertyDetails details(NONE, DATA, 0, cell_type); 17586 dictionary = 17587 GlobalDictionary::Add(dictionary, name, cell, details, entry_out); 17588 // {*entry_out} is initialized inside GlobalDictionary::Add(). 17589 global->set_properties(*dictionary); 17590 return cell; 17591 } 17592 17593 17594 // This class is used for looking up two character strings in the string table. 17595 // If we don't have a hit we don't want to waste much time so we unroll the 17596 // string hash calculation loop here for speed. Doesn't work if the two 17597 // characters form a decimal integer, since such strings have a different hash 17598 // algorithm. 17599 class TwoCharHashTableKey : public HashTableKey { 17600 public: 17601 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed) 17602 : c1_(c1), c2_(c2) { 17603 // Char 1. 17604 uint32_t hash = seed; 17605 hash += c1; 17606 hash += hash << 10; 17607 hash ^= hash >> 6; 17608 // Char 2. 17609 hash += c2; 17610 hash += hash << 10; 17611 hash ^= hash >> 6; 17612 // GetHash. 17613 hash += hash << 3; 17614 hash ^= hash >> 11; 17615 hash += hash << 15; 17616 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash; 17617 hash_ = hash; 17618 #ifdef DEBUG 17619 // If this assert fails then we failed to reproduce the two-character 17620 // version of the string hashing algorithm above. One reason could be 17621 // that we were passed two digits as characters, since the hash 17622 // algorithm is different in that case. 17623 uint16_t chars[2] = {c1, c2}; 17624 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed); 17625 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask; 17626 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash)); 17627 #endif 17628 } 17629 17630 bool IsMatch(Object* o) override { 17631 if (!o->IsString()) return false; 17632 String* other = String::cast(o); 17633 if (other->length() != 2) return false; 17634 if (other->Get(0) != c1_) return false; 17635 return other->Get(1) == c2_; 17636 } 17637 17638 uint32_t Hash() override { return hash_; } 17639 uint32_t HashForObject(Object* key) override { 17640 if (!key->IsString()) return 0; 17641 return String::cast(key)->Hash(); 17642 } 17643 17644 Handle<Object> AsHandle(Isolate* isolate) override { 17645 // The TwoCharHashTableKey is only used for looking in the string 17646 // table, not for adding to it. 17647 UNREACHABLE(); 17648 return MaybeHandle<Object>().ToHandleChecked(); 17649 } 17650 17651 private: 17652 uint16_t c1_; 17653 uint16_t c2_; 17654 uint32_t hash_; 17655 }; 17656 17657 17658 MaybeHandle<String> StringTable::InternalizeStringIfExists( 17659 Isolate* isolate, 17660 Handle<String> string) { 17661 if (string->IsInternalizedString()) { 17662 return string; 17663 } 17664 return LookupStringIfExists(isolate, string); 17665 } 17666 17667 17668 MaybeHandle<String> StringTable::LookupStringIfExists( 17669 Isolate* isolate, 17670 Handle<String> string) { 17671 Handle<StringTable> string_table = isolate->factory()->string_table(); 17672 InternalizedStringKey key(string); 17673 int entry = string_table->FindEntry(&key); 17674 if (entry == kNotFound) { 17675 return MaybeHandle<String>(); 17676 } else { 17677 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate); 17678 DCHECK(StringShape(*result).IsInternalized()); 17679 return result; 17680 } 17681 } 17682 17683 17684 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists( 17685 Isolate* isolate, 17686 uint16_t c1, 17687 uint16_t c2) { 17688 Handle<StringTable> string_table = isolate->factory()->string_table(); 17689 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed()); 17690 int entry = string_table->FindEntry(&key); 17691 if (entry == kNotFound) { 17692 return MaybeHandle<String>(); 17693 } else { 17694 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate); 17695 DCHECK(StringShape(*result).IsInternalized()); 17696 return result; 17697 } 17698 } 17699 17700 17701 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, 17702 int expected) { 17703 Handle<StringTable> table = isolate->factory()->string_table(); 17704 // We need a key instance for the virtual hash function. 17705 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); 17706 table = StringTable::EnsureCapacity(table, expected, &dummy_key); 17707 isolate->heap()->SetRootStringTable(*table); 17708 } 17709 17710 17711 Handle<String> StringTable::LookupString(Isolate* isolate, 17712 Handle<String> string) { 17713 if (string->IsConsString() && string->IsFlat()) { 17714 string = String::Flatten(string); 17715 if (string->IsInternalizedString()) return string; 17716 } 17717 17718 InternalizedStringKey key(string); 17719 Handle<String> result = LookupKey(isolate, &key); 17720 17721 if (string->IsConsString()) { 17722 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17723 cons->set_first(*result); 17724 cons->set_second(isolate->heap()->empty_string()); 17725 } else if (string->IsSlicedString()) { 17726 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); 17727 DisallowHeapAllocation no_gc; 17728 bool one_byte = result->IsOneByteRepresentation(); 17729 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map() 17730 : isolate->factory()->cons_string_map(); 17731 string->set_map(*map); 17732 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17733 cons->set_first(*result); 17734 cons->set_second(isolate->heap()->empty_string()); 17735 } 17736 return result; 17737 } 17738 17739 17740 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { 17741 Handle<StringTable> table = isolate->factory()->string_table(); 17742 int entry = table->FindEntry(key); 17743 17744 // String already in table. 17745 if (entry != kNotFound) { 17746 return handle(String::cast(table->KeyAt(entry)), isolate); 17747 } 17748 17749 // Adding new string. Grow table if needed. 17750 table = StringTable::EnsureCapacity(table, 1, key); 17751 17752 // Create string object. 17753 Handle<Object> string = key->AsHandle(isolate); 17754 // There must be no attempts to internalize strings that could throw 17755 // InvalidStringLength error. 17756 CHECK(!string.is_null()); 17757 17758 // Add the new string and return it along with the string table. 17759 entry = table->FindInsertionEntry(key->Hash()); 17760 table->set(EntryToIndex(entry), *string); 17761 table->ElementAdded(); 17762 17763 isolate->heap()->SetRootStringTable(*table); 17764 return Handle<String>::cast(string); 17765 } 17766 17767 17768 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) { 17769 Handle<StringTable> table = isolate->factory()->string_table(); 17770 int entry = table->FindEntry(key); 17771 if (entry != kNotFound) return String::cast(table->KeyAt(entry)); 17772 return NULL; 17773 } 17774 17775 Handle<StringSet> StringSet::New(Isolate* isolate) { 17776 return HashTable::New(isolate, 0); 17777 } 17778 17779 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset, 17780 Handle<String> name) { 17781 if (!stringset->Has(name)) { 17782 stringset = EnsureCapacity(stringset, 1, *name); 17783 uint32_t hash = StringSetShape::Hash(*name); 17784 int entry = stringset->FindInsertionEntry(hash); 17785 stringset->set(EntryToIndex(entry), *name); 17786 stringset->ElementAdded(); 17787 } 17788 return stringset; 17789 } 17790 17791 bool StringSet::Has(Handle<String> name) { 17792 return FindEntry(*name) != kNotFound; 17793 } 17794 17795 Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set, 17796 Handle<Object> key) { 17797 Isolate* isolate = set->GetIsolate(); 17798 int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); 17799 17800 if (!set->Has(isolate, key, hash)) { 17801 set = EnsureCapacity(set, 1, key); 17802 int entry = set->FindInsertionEntry(hash); 17803 set->set(EntryToIndex(entry), *key); 17804 set->ElementAdded(); 17805 } 17806 return set; 17807 } 17808 17809 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src, 17810 Handle<Context> context, 17811 LanguageMode language_mode) { 17812 Isolate* isolate = GetIsolate(); 17813 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 17814 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17815 int entry = FindEntry(&key); 17816 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17817 int index = EntryToIndex(entry); 17818 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value(); 17819 return Handle<Object>(get(index + 1), isolate); 17820 } 17821 17822 17823 Handle<Object> CompilationCacheTable::LookupEval( 17824 Handle<String> src, Handle<SharedFunctionInfo> outer_info, 17825 LanguageMode language_mode, int scope_position) { 17826 Isolate* isolate = GetIsolate(); 17827 // Cache key is the tuple (source, outer shared function info, scope position) 17828 // to unambiguously identify the context chain the cached eval code assumes. 17829 StringSharedKey key(src, outer_info, language_mode, scope_position); 17830 int entry = FindEntry(&key); 17831 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17832 int index = EntryToIndex(entry); 17833 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value(); 17834 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate); 17835 } 17836 17837 17838 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src, 17839 JSRegExp::Flags flags) { 17840 Isolate* isolate = GetIsolate(); 17841 DisallowHeapAllocation no_allocation; 17842 RegExpKey key(src, flags); 17843 int entry = FindEntry(&key); 17844 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17845 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate); 17846 } 17847 17848 17849 Handle<CompilationCacheTable> CompilationCacheTable::Put( 17850 Handle<CompilationCacheTable> cache, Handle<String> src, 17851 Handle<Context> context, LanguageMode language_mode, Handle<Object> value) { 17852 Isolate* isolate = cache->GetIsolate(); 17853 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 17854 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17855 Handle<Object> k = key.AsHandle(isolate); 17856 cache = EnsureCapacity(cache, 1, &key); 17857 int entry = cache->FindInsertionEntry(key.Hash()); 17858 cache->set(EntryToIndex(entry), *k); 17859 cache->set(EntryToIndex(entry) + 1, *value); 17860 cache->ElementAdded(); 17861 return cache; 17862 } 17863 17864 17865 Handle<CompilationCacheTable> CompilationCacheTable::PutEval( 17866 Handle<CompilationCacheTable> cache, Handle<String> src, 17867 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value, 17868 int scope_position) { 17869 Isolate* isolate = cache->GetIsolate(); 17870 StringSharedKey key(src, outer_info, value->language_mode(), scope_position); 17871 { 17872 Handle<Object> k = key.AsHandle(isolate); 17873 DisallowHeapAllocation no_allocation_scope; 17874 int entry = cache->FindEntry(&key); 17875 if (entry != kNotFound) { 17876 cache->set(EntryToIndex(entry), *k); 17877 cache->set(EntryToIndex(entry) + 1, *value); 17878 return cache; 17879 } 17880 } 17881 17882 cache = EnsureCapacity(cache, 1, &key); 17883 int entry = cache->FindInsertionEntry(key.Hash()); 17884 Handle<Object> k = 17885 isolate->factory()->NewNumber(static_cast<double>(key.Hash())); 17886 cache->set(EntryToIndex(entry), *k); 17887 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations)); 17888 cache->ElementAdded(); 17889 return cache; 17890 } 17891 17892 17893 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp( 17894 Handle<CompilationCacheTable> cache, Handle<String> src, 17895 JSRegExp::Flags flags, Handle<FixedArray> value) { 17896 RegExpKey key(src, flags); 17897 cache = EnsureCapacity(cache, 1, &key); 17898 int entry = cache->FindInsertionEntry(key.Hash()); 17899 // We store the value in the key slot, and compare the search key 17900 // to the stored value with a custon IsMatch function during lookups. 17901 cache->set(EntryToIndex(entry), *value); 17902 cache->set(EntryToIndex(entry) + 1, *value); 17903 cache->ElementAdded(); 17904 return cache; 17905 } 17906 17907 17908 void CompilationCacheTable::Age() { 17909 DisallowHeapAllocation no_allocation; 17910 Object* the_hole_value = GetHeap()->the_hole_value(); 17911 for (int entry = 0, size = Capacity(); entry < size; entry++) { 17912 int entry_index = EntryToIndex(entry); 17913 int value_index = entry_index + 1; 17914 17915 if (get(entry_index)->IsNumber()) { 17916 Smi* count = Smi::cast(get(value_index)); 17917 count = Smi::FromInt(count->value() - 1); 17918 if (count->value() == 0) { 17919 NoWriteBarrierSet(this, entry_index, the_hole_value); 17920 NoWriteBarrierSet(this, value_index, the_hole_value); 17921 ElementRemoved(); 17922 } else { 17923 NoWriteBarrierSet(this, value_index, count); 17924 } 17925 } else if (get(entry_index)->IsFixedArray()) { 17926 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index)); 17927 if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) { 17928 NoWriteBarrierSet(this, entry_index, the_hole_value); 17929 NoWriteBarrierSet(this, value_index, the_hole_value); 17930 ElementRemoved(); 17931 } 17932 } 17933 } 17934 } 17935 17936 17937 void CompilationCacheTable::Remove(Object* value) { 17938 DisallowHeapAllocation no_allocation; 17939 Object* the_hole_value = GetHeap()->the_hole_value(); 17940 for (int entry = 0, size = Capacity(); entry < size; entry++) { 17941 int entry_index = EntryToIndex(entry); 17942 int value_index = entry_index + 1; 17943 if (get(value_index) == value) { 17944 NoWriteBarrierSet(this, entry_index, the_hole_value); 17945 NoWriteBarrierSet(this, value_index, the_hole_value); 17946 ElementRemoved(); 17947 } 17948 } 17949 return; 17950 } 17951 17952 template <typename Derived, typename Shape, typename Key> 17953 Handle<Derived> Dictionary<Derived, Shape, Key>::New( 17954 Isolate* isolate, int at_least_space_for, PretenureFlag pretenure, 17955 MinimumCapacity capacity_option) { 17956 DCHECK(0 <= at_least_space_for); 17957 Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for, 17958 capacity_option, pretenure); 17959 17960 // Initialize the next enumeration index. 17961 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex); 17962 return dict; 17963 } 17964 17965 17966 template <typename Derived, typename Shape, typename Key> 17967 Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray( 17968 Handle<Derived> dictionary) { 17969 Isolate* isolate = dictionary->GetIsolate(); 17970 Factory* factory = isolate->factory(); 17971 int length = dictionary->NumberOfElements(); 17972 17973 Handle<FixedArray> iteration_order = factory->NewFixedArray(length); 17974 Handle<FixedArray> enumeration_order = factory->NewFixedArray(length); 17975 17976 // Fill both the iteration order array and the enumeration order array 17977 // with property details. 17978 int capacity = dictionary->Capacity(); 17979 int pos = 0; 17980 for (int i = 0; i < capacity; i++) { 17981 if (dictionary->IsKey(isolate, dictionary->KeyAt(i))) { 17982 int index = dictionary->DetailsAt(i).dictionary_index(); 17983 iteration_order->set(pos, Smi::FromInt(i)); 17984 enumeration_order->set(pos, Smi::FromInt(index)); 17985 pos++; 17986 } 17987 } 17988 DCHECK(pos == length); 17989 17990 // Sort the arrays wrt. enumeration order. 17991 iteration_order->SortPairs(*enumeration_order, enumeration_order->length()); 17992 return iteration_order; 17993 } 17994 17995 17996 template <typename Derived, typename Shape, typename Key> 17997 Handle<FixedArray> 17998 Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices( 17999 Handle<Derived> dictionary) { 18000 int length = dictionary->NumberOfElements(); 18001 18002 Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary); 18003 DCHECK(iteration_order->length() == length); 18004 18005 // Iterate over the dictionary using the enumeration order and update 18006 // the dictionary with new enumeration indices. 18007 for (int i = 0; i < length; i++) { 18008 int index = Smi::cast(iteration_order->get(i))->value(); 18009 DCHECK(dictionary->IsKey(dictionary->KeyAt(index))); 18010 18011 int enum_index = PropertyDetails::kInitialIndex + i; 18012 18013 PropertyDetails details = dictionary->DetailsAt(index); 18014 PropertyDetails new_details = details.set_index(enum_index); 18015 dictionary->DetailsAtPut(index, new_details); 18016 } 18017 18018 // Set the next enumeration index. 18019 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length); 18020 return iteration_order; 18021 } 18022 18023 18024 template <typename Derived, typename Shape, typename Key> 18025 void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() { 18026 DCHECK_EQ(0, DerivedHashTable::NumberOfElements()); 18027 DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements()); 18028 // Make sure that HashTable::EnsureCapacity will create a copy. 18029 DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity()); 18030 DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1)); 18031 } 18032 18033 18034 template <typename Derived, typename Shape, typename Key> 18035 Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity( 18036 Handle<Derived> dictionary, int n, Key key) { 18037 // Check whether there are enough enumeration indices to add n elements. 18038 if (Shape::kIsEnumerable && 18039 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) { 18040 // If not, we generate new indices for the properties. 18041 GenerateNewEnumerationIndices(dictionary); 18042 } 18043 return DerivedHashTable::EnsureCapacity(dictionary, n, key); 18044 } 18045 18046 18047 template <typename Derived, typename Shape, typename Key> 18048 Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty( 18049 Handle<Derived> dictionary, int entry) { 18050 Factory* factory = dictionary->GetIsolate()->factory(); 18051 PropertyDetails details = dictionary->DetailsAt(entry); 18052 if (!details.IsConfigurable()) return factory->false_value(); 18053 18054 dictionary->SetEntry( 18055 entry, factory->the_hole_value(), factory->the_hole_value()); 18056 dictionary->ElementRemoved(); 18057 return factory->true_value(); 18058 } 18059 18060 18061 template<typename Derived, typename Shape, typename Key> 18062 Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut( 18063 Handle<Derived> dictionary, Key key, Handle<Object> value) { 18064 int entry = dictionary->FindEntry(key); 18065 18066 // If the entry is present set the value; 18067 if (entry != Dictionary::kNotFound) { 18068 dictionary->ValueAtPut(entry, *value); 18069 return dictionary; 18070 } 18071 18072 // Check whether the dictionary should be extended. 18073 dictionary = EnsureCapacity(dictionary, 1, key); 18074 #ifdef DEBUG 18075 USE(Shape::AsHandle(dictionary->GetIsolate(), key)); 18076 #endif 18077 PropertyDetails details = PropertyDetails::Empty(); 18078 18079 AddEntry(dictionary, key, value, details, dictionary->Hash(key)); 18080 return dictionary; 18081 } 18082 18083 template <typename Derived, typename Shape, typename Key> 18084 Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary, 18085 Key key, 18086 Handle<Object> value, 18087 PropertyDetails details, 18088 int* entry_out) { 18089 // Valdate key is absent. 18090 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound)); 18091 // Check whether the dictionary should be extended. 18092 dictionary = EnsureCapacity(dictionary, 1, key); 18093 18094 int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key)); 18095 if (entry_out) *entry_out = entry; 18096 return dictionary; 18097 } 18098 18099 // Add a key, value pair to the dictionary. Returns entry value. 18100 template <typename Derived, typename Shape, typename Key> 18101 int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary, 18102 Key key, Handle<Object> value, 18103 PropertyDetails details, 18104 uint32_t hash) { 18105 // Compute the key object. 18106 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key); 18107 18108 uint32_t entry = dictionary->FindInsertionEntry(hash); 18109 // Insert element at empty or deleted entry 18110 if (details.dictionary_index() == 0 && Shape::kIsEnumerable) { 18111 // Assign an enumeration index to the property and update 18112 // SetNextEnumerationIndex. 18113 int index = dictionary->NextEnumerationIndex(); 18114 details = details.set_index(index); 18115 dictionary->SetNextEnumerationIndex(index + 1); 18116 } 18117 dictionary->SetEntry(entry, k, value, details); 18118 DCHECK((dictionary->KeyAt(entry)->IsNumber() || 18119 dictionary->KeyAt(entry)->IsName())); 18120 dictionary->ElementAdded(); 18121 return entry; 18122 } 18123 18124 bool SeededNumberDictionary::HasComplexElements() { 18125 if (!requires_slow_elements()) return false; 18126 Isolate* isolate = this->GetIsolate(); 18127 int capacity = this->Capacity(); 18128 for (int i = 0; i < capacity; i++) { 18129 Object* k = this->KeyAt(i); 18130 if (!this->IsKey(isolate, k)) continue; 18131 DCHECK(!IsDeleted(i)); 18132 PropertyDetails details = this->DetailsAt(i); 18133 if (details.type() == ACCESSOR_CONSTANT) return true; 18134 PropertyAttributes attr = details.attributes(); 18135 if (attr & ALL_ATTRIBUTES_MASK) return true; 18136 } 18137 return false; 18138 } 18139 18140 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key, 18141 bool used_as_prototype) { 18142 DisallowHeapAllocation no_allocation; 18143 // If the dictionary requires slow elements an element has already 18144 // been added at a high index. 18145 if (requires_slow_elements()) return; 18146 // Check if this index is high enough that we should require slow 18147 // elements. 18148 if (key > kRequiresSlowElementsLimit) { 18149 if (used_as_prototype) { 18150 // TODO(verwaest): Remove this hack. 18151 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate()); 18152 } 18153 set_requires_slow_elements(); 18154 return; 18155 } 18156 // Update max key value. 18157 Object* max_index_object = get(kMaxNumberKeyIndex); 18158 if (!max_index_object->IsSmi() || max_number_key() < key) { 18159 FixedArray::set(kMaxNumberKeyIndex, 18160 Smi::FromInt(key << kRequiresSlowElementsTagSize)); 18161 } 18162 } 18163 18164 18165 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry( 18166 Handle<SeededNumberDictionary> dictionary, uint32_t key, 18167 Handle<Object> value, PropertyDetails details, bool used_as_prototype) { 18168 dictionary->UpdateMaxNumberKey(key, used_as_prototype); 18169 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); 18170 return Add(dictionary, key, value, details); 18171 } 18172 18173 18174 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry( 18175 Handle<UnseededNumberDictionary> dictionary, 18176 uint32_t key, 18177 Handle<Object> value) { 18178 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); 18179 return Add(dictionary, key, value, PropertyDetails::Empty()); 18180 } 18181 18182 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey( 18183 Handle<UnseededNumberDictionary> dictionary, uint32_t key) { 18184 int entry = dictionary->FindEntry(key); 18185 if (entry == kNotFound) return dictionary; 18186 18187 Factory* factory = dictionary->GetIsolate()->factory(); 18188 dictionary->SetEntry(entry, factory->the_hole_value(), 18189 factory->the_hole_value()); 18190 dictionary->ElementRemoved(); 18191 return dictionary->Shrink(dictionary, key); 18192 } 18193 18194 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut( 18195 Handle<SeededNumberDictionary> dictionary, uint32_t key, 18196 Handle<Object> value, bool used_as_prototype) { 18197 dictionary->UpdateMaxNumberKey(key, used_as_prototype); 18198 return AtPut(dictionary, key, value); 18199 } 18200 18201 18202 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut( 18203 Handle<UnseededNumberDictionary> dictionary, 18204 uint32_t key, 18205 Handle<Object> value) { 18206 return AtPut(dictionary, key, value); 18207 } 18208 18209 18210 Handle<SeededNumberDictionary> SeededNumberDictionary::Set( 18211 Handle<SeededNumberDictionary> dictionary, uint32_t key, 18212 Handle<Object> value, PropertyDetails details, bool used_as_prototype) { 18213 int entry = dictionary->FindEntry(key); 18214 if (entry == kNotFound) { 18215 return AddNumberEntry(dictionary, key, value, details, used_as_prototype); 18216 } 18217 // Preserve enumeration index. 18218 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index()); 18219 Handle<Object> object_key = 18220 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); 18221 dictionary->SetEntry(entry, object_key, value, details); 18222 return dictionary; 18223 } 18224 18225 18226 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set( 18227 Handle<UnseededNumberDictionary> dictionary, 18228 uint32_t key, 18229 Handle<Object> value) { 18230 int entry = dictionary->FindEntry(key); 18231 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value); 18232 Handle<Object> object_key = 18233 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); 18234 dictionary->SetEntry(entry, object_key, value); 18235 return dictionary; 18236 } 18237 18238 18239 template <typename Derived, typename Shape, typename Key> 18240 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes( 18241 PropertyFilter filter) { 18242 Isolate* isolate = this->GetIsolate(); 18243 int capacity = this->Capacity(); 18244 int result = 0; 18245 for (int i = 0; i < capacity; i++) { 18246 Object* k = this->KeyAt(i); 18247 if (this->IsKey(isolate, k) && !k->FilterKey(filter)) { 18248 if (this->IsDeleted(i)) continue; 18249 PropertyDetails details = this->DetailsAt(i); 18250 PropertyAttributes attr = details.attributes(); 18251 if ((attr & filter) == 0) result++; 18252 } 18253 } 18254 return result; 18255 } 18256 18257 18258 template <typename Dictionary> 18259 struct EnumIndexComparator { 18260 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {} 18261 bool operator() (Smi* a, Smi* b) { 18262 PropertyDetails da(dict->DetailsAt(a->value())); 18263 PropertyDetails db(dict->DetailsAt(b->value())); 18264 return da.dictionary_index() < db.dictionary_index(); 18265 } 18266 Dictionary* dict; 18267 }; 18268 18269 template <typename Derived, typename Shape, typename Key> 18270 void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo( 18271 Handle<Dictionary<Derived, Shape, Key>> dictionary, 18272 Handle<FixedArray> storage, KeyCollectionMode mode, 18273 KeyAccumulator* accumulator) { 18274 Isolate* isolate = dictionary->GetIsolate(); 18275 int length = storage->length(); 18276 int capacity = dictionary->Capacity(); 18277 int properties = 0; 18278 for (int i = 0; i < capacity; i++) { 18279 Object* key = dictionary->KeyAt(i); 18280 bool is_shadowing_key = false; 18281 if (!dictionary->IsKey(isolate, key)) continue; 18282 if (key->IsSymbol()) continue; 18283 PropertyDetails details = dictionary->DetailsAt(i); 18284 if (details.IsDontEnum()) { 18285 if (mode == KeyCollectionMode::kIncludePrototypes) { 18286 is_shadowing_key = true; 18287 } else { 18288 continue; 18289 } 18290 } 18291 if (dictionary->IsDeleted(i)) continue; 18292 if (is_shadowing_key) { 18293 accumulator->AddShadowingKey(key); 18294 continue; 18295 } else { 18296 storage->set(properties, Smi::FromInt(i)); 18297 } 18298 properties++; 18299 if (properties == length) break; 18300 } 18301 18302 CHECK_EQ(length, properties); 18303 DisallowHeapAllocation no_gc; 18304 Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary; 18305 FixedArray* raw_storage = *storage; 18306 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary)); 18307 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress()); 18308 std::sort(start, start + length, cmp); 18309 for (int i = 0; i < length; i++) { 18310 int index = Smi::cast(raw_storage->get(i))->value(); 18311 raw_storage->set(i, raw_dictionary->KeyAt(index)); 18312 } 18313 } 18314 18315 template <typename Derived, typename Shape, typename Key> 18316 void Dictionary<Derived, Shape, Key>::CollectKeysTo( 18317 Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) { 18318 Isolate* isolate = keys->isolate(); 18319 int capacity = dictionary->Capacity(); 18320 Handle<FixedArray> array = 18321 isolate->factory()->NewFixedArray(dictionary->NumberOfElements()); 18322 int array_size = 0; 18323 PropertyFilter filter = keys->filter(); 18324 { 18325 DisallowHeapAllocation no_gc; 18326 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary; 18327 for (int i = 0; i < capacity; i++) { 18328 Object* k = raw_dict->KeyAt(i); 18329 if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue; 18330 if (raw_dict->IsDeleted(i)) continue; 18331 PropertyDetails details = raw_dict->DetailsAt(i); 18332 if ((details.attributes() & filter) != 0) { 18333 keys->AddShadowingKey(k); 18334 continue; 18335 } 18336 if (filter & ONLY_ALL_CAN_READ) { 18337 if (details.kind() != kAccessor) continue; 18338 Object* accessors = raw_dict->ValueAt(i); 18339 if (accessors->IsPropertyCell()) { 18340 accessors = PropertyCell::cast(accessors)->value(); 18341 } 18342 if (!accessors->IsAccessorInfo()) continue; 18343 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; 18344 } 18345 array->set(array_size++, Smi::FromInt(i)); 18346 } 18347 18348 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict)); 18349 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress()); 18350 std::sort(start, start + array_size, cmp); 18351 } 18352 18353 bool has_seen_symbol = false; 18354 for (int i = 0; i < array_size; i++) { 18355 int index = Smi::cast(array->get(i))->value(); 18356 Object* key = dictionary->KeyAt(index); 18357 if (key->IsSymbol()) { 18358 has_seen_symbol = true; 18359 continue; 18360 } 18361 keys->AddKey(key, DO_NOT_CONVERT); 18362 } 18363 if (has_seen_symbol) { 18364 for (int i = 0; i < array_size; i++) { 18365 int index = Smi::cast(array->get(i))->value(); 18366 Object* key = dictionary->KeyAt(index); 18367 if (!key->IsSymbol()) continue; 18368 keys->AddKey(key, DO_NOT_CONVERT); 18369 } 18370 } 18371 } 18372 18373 18374 // Backwards lookup (slow). 18375 template<typename Derived, typename Shape, typename Key> 18376 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { 18377 Isolate* isolate = this->GetIsolate(); 18378 int capacity = this->Capacity(); 18379 for (int i = 0; i < capacity; i++) { 18380 Object* k = this->KeyAt(i); 18381 if (!this->IsKey(isolate, k)) continue; 18382 Object* e = this->ValueAt(i); 18383 // TODO(dcarney): this should be templatized. 18384 if (e->IsPropertyCell()) { 18385 e = PropertyCell::cast(e)->value(); 18386 } 18387 if (e == value) return k; 18388 } 18389 return isolate->heap()->undefined_value(); 18390 } 18391 18392 18393 Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key, 18394 int32_t hash) { 18395 DisallowHeapAllocation no_gc; 18396 DCHECK(IsKey(isolate, *key)); 18397 18398 int entry = FindEntry(isolate, key, hash); 18399 if (entry == kNotFound) return isolate->heap()->the_hole_value(); 18400 return get(EntryToIndex(entry) + 1); 18401 } 18402 18403 18404 Object* ObjectHashTable::Lookup(Handle<Object> key) { 18405 DisallowHeapAllocation no_gc; 18406 18407 Isolate* isolate = GetIsolate(); 18408 DCHECK(IsKey(isolate, *key)); 18409 18410 // If the object does not have an identity hash, it was never used as a key. 18411 Object* hash = key->GetHash(); 18412 if (hash->IsUndefined(isolate)) { 18413 return isolate->heap()->the_hole_value(); 18414 } 18415 return Lookup(isolate, key, Smi::cast(hash)->value()); 18416 } 18417 18418 Object* ObjectHashTable::ValueAt(int entry) { 18419 return get(EntryToValueIndex(entry)); 18420 } 18421 18422 Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) { 18423 return Lookup(GetIsolate(), key, hash); 18424 } 18425 18426 18427 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table, 18428 Handle<Object> key, 18429 Handle<Object> value) { 18430 Isolate* isolate = table->GetIsolate(); 18431 DCHECK(table->IsKey(isolate, *key)); 18432 DCHECK(!value->IsTheHole(isolate)); 18433 18434 // Make sure the key object has an identity hash code. 18435 int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); 18436 18437 return Put(table, key, value, hash); 18438 } 18439 18440 18441 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table, 18442 Handle<Object> key, 18443 Handle<Object> value, 18444 int32_t hash) { 18445 Isolate* isolate = table->GetIsolate(); 18446 DCHECK(table->IsKey(isolate, *key)); 18447 DCHECK(!value->IsTheHole(isolate)); 18448 18449 int entry = table->FindEntry(isolate, key, hash); 18450 18451 // Key is already in table, just overwrite value. 18452 if (entry != kNotFound) { 18453 table->set(EntryToIndex(entry) + 1, *value); 18454 return table; 18455 } 18456 18457 // Rehash if more than 33% of the entries are deleted entries. 18458 // TODO(jochen): Consider to shrink the fixed array in place. 18459 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) { 18460 table->Rehash(isolate->factory()->undefined_value()); 18461 } 18462 // If we're out of luck, we didn't get a GC recently, and so rehashing 18463 // isn't enough to avoid a crash. 18464 if (!table->HasSufficientCapacityToAdd(1)) { 18465 int nof = table->NumberOfElements() + 1; 18466 int capacity = ObjectHashTable::ComputeCapacity(nof * 2); 18467 if (capacity > ObjectHashTable::kMaxCapacity) { 18468 for (size_t i = 0; i < 2; ++i) { 18469 isolate->heap()->CollectAllGarbage( 18470 Heap::kFinalizeIncrementalMarkingMask, 18471 GarbageCollectionReason::kFullHashtable); 18472 } 18473 table->Rehash(isolate->factory()->undefined_value()); 18474 } 18475 } 18476 18477 // Check whether the hash table should be extended. 18478 table = EnsureCapacity(table, 1, key); 18479 table->AddEntry(table->FindInsertionEntry(hash), *key, *value); 18480 return table; 18481 } 18482 18483 18484 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table, 18485 Handle<Object> key, 18486 bool* was_present) { 18487 DCHECK(table->IsKey(table->GetIsolate(), *key)); 18488 18489 Object* hash = key->GetHash(); 18490 if (hash->IsUndefined(table->GetIsolate())) { 18491 *was_present = false; 18492 return table; 18493 } 18494 18495 return Remove(table, key, was_present, Smi::cast(hash)->value()); 18496 } 18497 18498 18499 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table, 18500 Handle<Object> key, 18501 bool* was_present, 18502 int32_t hash) { 18503 Isolate* isolate = table->GetIsolate(); 18504 DCHECK(table->IsKey(isolate, *key)); 18505 18506 int entry = table->FindEntry(isolate, key, hash); 18507 if (entry == kNotFound) { 18508 *was_present = false; 18509 return table; 18510 } 18511 18512 *was_present = true; 18513 table->RemoveEntry(entry); 18514 return Shrink(table, key); 18515 } 18516 18517 18518 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) { 18519 set(EntryToIndex(entry), key); 18520 set(EntryToIndex(entry) + 1, value); 18521 ElementAdded(); 18522 } 18523 18524 18525 void ObjectHashTable::RemoveEntry(int entry) { 18526 set_the_hole(EntryToIndex(entry)); 18527 set_the_hole(EntryToIndex(entry) + 1); 18528 ElementRemoved(); 18529 } 18530 18531 18532 Object* WeakHashTable::Lookup(Handle<HeapObject> key) { 18533 DisallowHeapAllocation no_gc; 18534 Isolate* isolate = GetIsolate(); 18535 DCHECK(IsKey(isolate, *key)); 18536 int entry = FindEntry(key); 18537 if (entry == kNotFound) return isolate->heap()->the_hole_value(); 18538 return get(EntryToValueIndex(entry)); 18539 } 18540 18541 18542 Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table, 18543 Handle<HeapObject> key, 18544 Handle<HeapObject> value) { 18545 Isolate* isolate = key->GetIsolate(); 18546 DCHECK(table->IsKey(isolate, *key)); 18547 int entry = table->FindEntry(key); 18548 // Key is already in table, just overwrite value. 18549 if (entry != kNotFound) { 18550 table->set(EntryToValueIndex(entry), *value); 18551 return table; 18552 } 18553 18554 Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key); 18555 18556 // Check whether the hash table should be extended. 18557 table = EnsureCapacity(table, 1, key, TENURED); 18558 18559 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value); 18560 return table; 18561 } 18562 18563 18564 void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell, 18565 Handle<HeapObject> value) { 18566 DisallowHeapAllocation no_allocation; 18567 set(EntryToIndex(entry), *key_cell); 18568 set(EntryToValueIndex(entry), *value); 18569 ElementAdded(); 18570 } 18571 18572 18573 template<class Derived, class Iterator, int entrysize> 18574 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate( 18575 Isolate* isolate, int capacity, PretenureFlag pretenure) { 18576 // Capacity must be a power of two, since we depend on being able 18577 // to divide and multiple by 2 (kLoadFactor) to derive capacity 18578 // from number of buckets. If we decide to change kLoadFactor 18579 // to something other than 2, capacity should be stored as another 18580 // field of this object. 18581 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity)); 18582 if (capacity > kMaxCapacity) { 18583 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true); 18584 } 18585 int num_buckets = capacity / kLoadFactor; 18586 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray( 18587 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure); 18588 backing_store->set_map_no_write_barrier( 18589 isolate->heap()->ordered_hash_table_map()); 18590 Handle<Derived> table = Handle<Derived>::cast(backing_store); 18591 for (int i = 0; i < num_buckets; ++i) { 18592 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound)); 18593 } 18594 table->SetNumberOfBuckets(num_buckets); 18595 table->SetNumberOfElements(0); 18596 table->SetNumberOfDeletedElements(0); 18597 return table; 18598 } 18599 18600 18601 template<class Derived, class Iterator, int entrysize> 18602 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable( 18603 Handle<Derived> table) { 18604 DCHECK(!table->IsObsolete()); 18605 18606 int nof = table->NumberOfElements(); 18607 int nod = table->NumberOfDeletedElements(); 18608 int capacity = table->Capacity(); 18609 if ((nof + nod) < capacity) return table; 18610 // Don't need to grow if we can simply clear out deleted entries instead. 18611 // Note that we can't compact in place, though, so we always allocate 18612 // a new table. 18613 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity); 18614 } 18615 18616 18617 template<class Derived, class Iterator, int entrysize> 18618 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink( 18619 Handle<Derived> table) { 18620 DCHECK(!table->IsObsolete()); 18621 18622 int nof = table->NumberOfElements(); 18623 int capacity = table->Capacity(); 18624 if (nof >= (capacity >> 2)) return table; 18625 return Rehash(table, capacity / 2); 18626 } 18627 18628 18629 template<class Derived, class Iterator, int entrysize> 18630 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear( 18631 Handle<Derived> table) { 18632 DCHECK(!table->IsObsolete()); 18633 18634 Handle<Derived> new_table = 18635 Allocate(table->GetIsolate(), 18636 kMinCapacity, 18637 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED); 18638 18639 table->SetNextTable(*new_table); 18640 table->SetNumberOfDeletedElements(kClearedTableSentinel); 18641 18642 return new_table; 18643 } 18644 18645 template <class Derived, class Iterator, int entrysize> 18646 bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey( 18647 Handle<Derived> table, Handle<Object> key) { 18648 DisallowHeapAllocation no_gc; 18649 Isolate* isolate = table->GetIsolate(); 18650 Object* raw_key = *key; 18651 int entry = table->KeyToFirstEntry(isolate, raw_key); 18652 // Walk the chain in the bucket to find the key. 18653 while (entry != kNotFound) { 18654 Object* candidate_key = table->KeyAt(entry); 18655 if (candidate_key->SameValueZero(raw_key)) return true; 18656 entry = table->NextChainEntry(entry); 18657 } 18658 return false; 18659 } 18660 18661 18662 Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table, 18663 Handle<Object> key) { 18664 int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value(); 18665 int entry = table->HashToEntry(hash); 18666 // Walk the chain of the bucket and try finding the key. 18667 while (entry != kNotFound) { 18668 Object* candidate_key = table->KeyAt(entry); 18669 // Do not add if we have the key already 18670 if (candidate_key->SameValueZero(*key)) return table; 18671 entry = table->NextChainEntry(entry); 18672 } 18673 18674 table = OrderedHashSet::EnsureGrowable(table); 18675 // Read the existing bucket values. 18676 int bucket = table->HashToBucket(hash); 18677 int previous_entry = table->HashToEntry(hash); 18678 int nof = table->NumberOfElements(); 18679 // Insert a new entry at the end, 18680 int new_entry = nof + table->NumberOfDeletedElements(); 18681 int new_index = table->EntryToIndex(new_entry); 18682 table->set(new_index, *key); 18683 table->set(new_index + kChainOffset, Smi::FromInt(previous_entry)); 18684 // and point the bucket to the new entry. 18685 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); 18686 table->SetNumberOfElements(nof + 1); 18687 return table; 18688 } 18689 18690 Handle<FixedArray> OrderedHashSet::ConvertToKeysArray( 18691 Handle<OrderedHashSet> table, GetKeysConversion convert) { 18692 Isolate* isolate = table->GetIsolate(); 18693 int length = table->NumberOfElements(); 18694 int nof_buckets = table->NumberOfBuckets(); 18695 // Convert the dictionary to a linear list. 18696 Handle<FixedArray> result = Handle<FixedArray>::cast(table); 18697 // From this point on table is no longer a valid OrderedHashSet. 18698 result->set_map(isolate->heap()->fixed_array_map()); 18699 for (int i = 0; i < length; i++) { 18700 int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize); 18701 Object* key = table->get(index); 18702 if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) { 18703 key = *isolate->factory()->NumberToString(handle(key, isolate)); 18704 } 18705 result->set(i, key); 18706 } 18707 result->Shrink(length); 18708 return result; 18709 } 18710 18711 template<class Derived, class Iterator, int entrysize> 18712 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash( 18713 Handle<Derived> table, int new_capacity) { 18714 Isolate* isolate = table->GetIsolate(); 18715 DCHECK(!table->IsObsolete()); 18716 18717 Handle<Derived> new_table = 18718 Allocate(isolate, new_capacity, 18719 isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED); 18720 int nof = table->NumberOfElements(); 18721 int nod = table->NumberOfDeletedElements(); 18722 int new_buckets = new_table->NumberOfBuckets(); 18723 int new_entry = 0; 18724 int removed_holes_index = 0; 18725 18726 DisallowHeapAllocation no_gc; 18727 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) { 18728 Object* key = table->KeyAt(old_entry); 18729 if (key->IsTheHole(isolate)) { 18730 table->SetRemovedIndexAt(removed_holes_index++, old_entry); 18731 continue; 18732 } 18733 18734 Object* hash = key->GetHash(); 18735 int bucket = Smi::cast(hash)->value() & (new_buckets - 1); 18736 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket); 18737 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); 18738 int new_index = new_table->EntryToIndex(new_entry); 18739 int old_index = table->EntryToIndex(old_entry); 18740 for (int i = 0; i < entrysize; ++i) { 18741 Object* value = table->get(old_index + i); 18742 new_table->set(new_index + i, value); 18743 } 18744 new_table->set(new_index + kChainOffset, chain_entry); 18745 ++new_entry; 18746 } 18747 18748 DCHECK_EQ(nod, removed_holes_index); 18749 18750 new_table->SetNumberOfElements(nof); 18751 table->SetNextTable(*new_table); 18752 18753 return new_table; 18754 } 18755 18756 18757 template Handle<OrderedHashSet> 18758 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate( 18759 Isolate* isolate, int capacity, PretenureFlag pretenure); 18760 18761 template Handle<OrderedHashSet> 18762 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable( 18763 Handle<OrderedHashSet> table); 18764 18765 template Handle<OrderedHashSet> 18766 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink( 18767 Handle<OrderedHashSet> table); 18768 18769 template Handle<OrderedHashSet> 18770 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear( 18771 Handle<OrderedHashSet> table); 18772 18773 template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey( 18774 Handle<OrderedHashSet> table, Handle<Object> key); 18775 18776 18777 template Handle<OrderedHashMap> 18778 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate( 18779 Isolate* isolate, int capacity, PretenureFlag pretenure); 18780 18781 template Handle<OrderedHashMap> 18782 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable( 18783 Handle<OrderedHashMap> table); 18784 18785 template Handle<OrderedHashMap> 18786 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink( 18787 Handle<OrderedHashMap> table); 18788 18789 template Handle<OrderedHashMap> 18790 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear( 18791 Handle<OrderedHashMap> table); 18792 18793 template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey( 18794 Handle<OrderedHashMap> table, Handle<Object> key); 18795 18796 18797 template<class Derived, class TableType> 18798 void OrderedHashTableIterator<Derived, TableType>::Transition() { 18799 DisallowHeapAllocation no_allocation; 18800 TableType* table = TableType::cast(this->table()); 18801 if (!table->IsObsolete()) return; 18802 18803 int index = Smi::cast(this->index())->value(); 18804 while (table->IsObsolete()) { 18805 TableType* next_table = table->NextTable(); 18806 18807 if (index > 0) { 18808 int nod = table->NumberOfDeletedElements(); 18809 18810 if (nod == TableType::kClearedTableSentinel) { 18811 index = 0; 18812 } else { 18813 int old_index = index; 18814 for (int i = 0; i < nod; ++i) { 18815 int removed_index = table->RemovedIndexAt(i); 18816 if (removed_index >= old_index) break; 18817 --index; 18818 } 18819 } 18820 } 18821 18822 table = next_table; 18823 } 18824 18825 set_table(table); 18826 set_index(Smi::FromInt(index)); 18827 } 18828 18829 18830 template<class Derived, class TableType> 18831 bool OrderedHashTableIterator<Derived, TableType>::HasMore() { 18832 DisallowHeapAllocation no_allocation; 18833 Isolate* isolate = this->GetIsolate(); 18834 if (this->table()->IsUndefined(isolate)) return false; 18835 18836 Transition(); 18837 18838 TableType* table = TableType::cast(this->table()); 18839 int index = Smi::cast(this->index())->value(); 18840 int used_capacity = table->UsedCapacity(); 18841 18842 while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) { 18843 index++; 18844 } 18845 18846 set_index(Smi::FromInt(index)); 18847 18848 if (index < used_capacity) return true; 18849 18850 set_table(isolate->heap()->undefined_value()); 18851 return false; 18852 } 18853 18854 18855 template<class Derived, class TableType> 18856 Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) { 18857 DisallowHeapAllocation no_allocation; 18858 if (HasMore()) { 18859 FixedArray* array = FixedArray::cast(value_array->elements()); 18860 static_cast<Derived*>(this)->PopulateValueArray(array); 18861 MoveNext(); 18862 return Smi::cast(kind()); 18863 } 18864 return Smi::kZero; 18865 } 18866 18867 18868 template Smi* 18869 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next( 18870 JSArray* value_array); 18871 18872 template bool 18873 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore(); 18874 18875 template void 18876 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext(); 18877 18878 template Object* 18879 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey(); 18880 18881 template void 18882 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition(); 18883 18884 18885 template Smi* 18886 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next( 18887 JSArray* value_array); 18888 18889 template bool 18890 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore(); 18891 18892 template void 18893 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext(); 18894 18895 template Object* 18896 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey(); 18897 18898 template void 18899 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition(); 18900 18901 18902 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) { 18903 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet(); 18904 set->set_table(*table); 18905 } 18906 18907 18908 void JSSet::Clear(Handle<JSSet> set) { 18909 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); 18910 table = OrderedHashSet::Clear(table); 18911 set->set_table(*table); 18912 } 18913 18914 18915 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) { 18916 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap(); 18917 map->set_table(*table); 18918 } 18919 18920 18921 void JSMap::Clear(Handle<JSMap> map) { 18922 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); 18923 table = OrderedHashMap::Clear(table); 18924 map->set_table(*table); 18925 } 18926 18927 18928 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection, 18929 Isolate* isolate) { 18930 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0); 18931 weak_collection->set_table(*table); 18932 } 18933 18934 18935 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection, 18936 Handle<Object> key, Handle<Object> value, 18937 int32_t hash) { 18938 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 18939 Handle<ObjectHashTable> table( 18940 ObjectHashTable::cast(weak_collection->table())); 18941 DCHECK(table->IsKey(*key)); 18942 Handle<ObjectHashTable> new_table = 18943 ObjectHashTable::Put(table, key, value, hash); 18944 weak_collection->set_table(*new_table); 18945 if (*table != *new_table) { 18946 // Zap the old table since we didn't record slots for its elements. 18947 table->FillWithHoles(0, table->length()); 18948 } 18949 } 18950 18951 18952 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection, 18953 Handle<Object> key, int32_t hash) { 18954 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 18955 Handle<ObjectHashTable> table( 18956 ObjectHashTable::cast(weak_collection->table())); 18957 DCHECK(table->IsKey(*key)); 18958 bool was_present = false; 18959 Handle<ObjectHashTable> new_table = 18960 ObjectHashTable::Remove(table, key, &was_present, hash); 18961 weak_collection->set_table(*new_table); 18962 if (*table != *new_table) { 18963 // Zap the old table since we didn't record slots for its elements. 18964 table->FillWithHoles(0, table->length()); 18965 } 18966 return was_present; 18967 } 18968 18969 // Check if there is a break point at this source position. 18970 bool DebugInfo::HasBreakPoint(int source_position) { 18971 // Get the break point info object for this code offset. 18972 Object* break_point_info = GetBreakPointInfo(source_position); 18973 18974 // If there is no break point info object or no break points in the break 18975 // point info object there is no break point at this code offset. 18976 if (break_point_info->IsUndefined(GetIsolate())) return false; 18977 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0; 18978 } 18979 18980 // Get the break point info object for this source position. 18981 Object* DebugInfo::GetBreakPointInfo(int source_position) { 18982 Isolate* isolate = GetIsolate(); 18983 if (!break_points()->IsUndefined(isolate)) { 18984 for (int i = 0; i < break_points()->length(); i++) { 18985 if (!break_points()->get(i)->IsUndefined(isolate)) { 18986 BreakPointInfo* break_point_info = 18987 BreakPointInfo::cast(break_points()->get(i)); 18988 if (break_point_info->source_position() == source_position) { 18989 return break_point_info; 18990 } 18991 } 18992 } 18993 } 18994 return isolate->heap()->undefined_value(); 18995 } 18996 18997 bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, 18998 Handle<Object> break_point_object) { 18999 Isolate* isolate = debug_info->GetIsolate(); 19000 if (debug_info->break_points()->IsUndefined(isolate)) return false; 19001 19002 for (int i = 0; i < debug_info->break_points()->length(); i++) { 19003 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue; 19004 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>( 19005 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate); 19006 if (BreakPointInfo::HasBreakPointObject(break_point_info, 19007 break_point_object)) { 19008 BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object); 19009 return true; 19010 } 19011 } 19012 return false; 19013 } 19014 19015 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position, 19016 Handle<Object> break_point_object) { 19017 Isolate* isolate = debug_info->GetIsolate(); 19018 Handle<Object> break_point_info( 19019 debug_info->GetBreakPointInfo(source_position), isolate); 19020 if (!break_point_info->IsUndefined(isolate)) { 19021 BreakPointInfo::SetBreakPoint( 19022 Handle<BreakPointInfo>::cast(break_point_info), 19023 break_point_object); 19024 return; 19025 } 19026 19027 // Adding a new break point for a code offset which did not have any 19028 // break points before. Try to find a free slot. 19029 static const int kNoBreakPointInfo = -1; 19030 int index = kNoBreakPointInfo; 19031 for (int i = 0; i < debug_info->break_points()->length(); i++) { 19032 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) { 19033 index = i; 19034 break; 19035 } 19036 } 19037 if (index == kNoBreakPointInfo) { 19038 // No free slot - extend break point info array. 19039 Handle<FixedArray> old_break_points = Handle<FixedArray>( 19040 FixedArray::cast(debug_info->break_points()), isolate); 19041 Handle<FixedArray> new_break_points = 19042 isolate->factory()->NewFixedArray( 19043 old_break_points->length() + 19044 DebugInfo::kEstimatedNofBreakPointsInFunction); 19045 19046 debug_info->set_break_points(*new_break_points); 19047 for (int i = 0; i < old_break_points->length(); i++) { 19048 new_break_points->set(i, old_break_points->get(i)); 19049 } 19050 index = old_break_points->length(); 19051 } 19052 DCHECK(index != kNoBreakPointInfo); 19053 19054 // Allocate new BreakPointInfo object and set the break point. 19055 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast( 19056 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE)); 19057 new_break_point_info->set_source_position(source_position); 19058 new_break_point_info->set_break_point_objects( 19059 isolate->heap()->undefined_value()); 19060 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object); 19061 debug_info->break_points()->set(index, *new_break_point_info); 19062 } 19063 19064 // Get the break point objects for a source position. 19065 Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) { 19066 Object* break_point_info = GetBreakPointInfo(source_position); 19067 Isolate* isolate = GetIsolate(); 19068 if (break_point_info->IsUndefined(isolate)) { 19069 return isolate->factory()->undefined_value(); 19070 } 19071 return Handle<Object>( 19072 BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate); 19073 } 19074 19075 19076 // Get the total number of break points. 19077 int DebugInfo::GetBreakPointCount() { 19078 Isolate* isolate = GetIsolate(); 19079 if (break_points()->IsUndefined(isolate)) return 0; 19080 int count = 0; 19081 for (int i = 0; i < break_points()->length(); i++) { 19082 if (!break_points()->get(i)->IsUndefined(isolate)) { 19083 BreakPointInfo* break_point_info = 19084 BreakPointInfo::cast(break_points()->get(i)); 19085 count += break_point_info->GetBreakPointCount(); 19086 } 19087 } 19088 return count; 19089 } 19090 19091 19092 Handle<Object> DebugInfo::FindBreakPointInfo( 19093 Handle<DebugInfo> debug_info, Handle<Object> break_point_object) { 19094 Isolate* isolate = debug_info->GetIsolate(); 19095 if (!debug_info->break_points()->IsUndefined(isolate)) { 19096 for (int i = 0; i < debug_info->break_points()->length(); i++) { 19097 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { 19098 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>( 19099 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate); 19100 if (BreakPointInfo::HasBreakPointObject(break_point_info, 19101 break_point_object)) { 19102 return break_point_info; 19103 } 19104 } 19105 } 19106 } 19107 return isolate->factory()->undefined_value(); 19108 } 19109 19110 // Remove the specified break point object. 19111 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, 19112 Handle<Object> break_point_object) { 19113 Isolate* isolate = break_point_info->GetIsolate(); 19114 // If there are no break points just ignore. 19115 if (break_point_info->break_point_objects()->IsUndefined(isolate)) return; 19116 // If there is a single break point clear it if it is the same. 19117 if (!break_point_info->break_point_objects()->IsFixedArray()) { 19118 if (break_point_info->break_point_objects() == *break_point_object) { 19119 break_point_info->set_break_point_objects( 19120 isolate->heap()->undefined_value()); 19121 } 19122 return; 19123 } 19124 // If there are multiple break points shrink the array 19125 DCHECK(break_point_info->break_point_objects()->IsFixedArray()); 19126 Handle<FixedArray> old_array = 19127 Handle<FixedArray>( 19128 FixedArray::cast(break_point_info->break_point_objects())); 19129 Handle<FixedArray> new_array = 19130 isolate->factory()->NewFixedArray(old_array->length() - 1); 19131 int found_count = 0; 19132 for (int i = 0; i < old_array->length(); i++) { 19133 if (old_array->get(i) == *break_point_object) { 19134 DCHECK(found_count == 0); 19135 found_count++; 19136 } else { 19137 new_array->set(i - found_count, old_array->get(i)); 19138 } 19139 } 19140 // If the break point was found in the list change it. 19141 if (found_count > 0) break_point_info->set_break_point_objects(*new_array); 19142 } 19143 19144 19145 // Add the specified break point object. 19146 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info, 19147 Handle<Object> break_point_object) { 19148 Isolate* isolate = break_point_info->GetIsolate(); 19149 19150 // If there was no break point objects before just set it. 19151 if (break_point_info->break_point_objects()->IsUndefined(isolate)) { 19152 break_point_info->set_break_point_objects(*break_point_object); 19153 return; 19154 } 19155 // If the break point object is the same as before just ignore. 19156 if (break_point_info->break_point_objects() == *break_point_object) return; 19157 // If there was one break point object before replace with array. 19158 if (!break_point_info->break_point_objects()->IsFixedArray()) { 19159 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2); 19160 array->set(0, break_point_info->break_point_objects()); 19161 array->set(1, *break_point_object); 19162 break_point_info->set_break_point_objects(*array); 19163 return; 19164 } 19165 // If there was more than one break point before extend array. 19166 Handle<FixedArray> old_array = 19167 Handle<FixedArray>( 19168 FixedArray::cast(break_point_info->break_point_objects())); 19169 Handle<FixedArray> new_array = 19170 isolate->factory()->NewFixedArray(old_array->length() + 1); 19171 for (int i = 0; i < old_array->length(); i++) { 19172 // If the break point was there before just ignore. 19173 if (old_array->get(i) == *break_point_object) return; 19174 new_array->set(i, old_array->get(i)); 19175 } 19176 // Add the new break point. 19177 new_array->set(old_array->length(), *break_point_object); 19178 break_point_info->set_break_point_objects(*new_array); 19179 } 19180 19181 19182 bool BreakPointInfo::HasBreakPointObject( 19183 Handle<BreakPointInfo> break_point_info, 19184 Handle<Object> break_point_object) { 19185 // No break point. 19186 Isolate* isolate = break_point_info->GetIsolate(); 19187 if (break_point_info->break_point_objects()->IsUndefined(isolate)) { 19188 return false; 19189 } 19190 // Single break point. 19191 if (!break_point_info->break_point_objects()->IsFixedArray()) { 19192 return break_point_info->break_point_objects() == *break_point_object; 19193 } 19194 // Multiple break points. 19195 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects()); 19196 for (int i = 0; i < array->length(); i++) { 19197 if (array->get(i) == *break_point_object) { 19198 return true; 19199 } 19200 } 19201 return false; 19202 } 19203 19204 19205 // Get the number of break points. 19206 int BreakPointInfo::GetBreakPointCount() { 19207 // No break point. 19208 if (break_point_objects()->IsUndefined(GetIsolate())) return 0; 19209 // Single break point. 19210 if (!break_point_objects()->IsFixedArray()) return 1; 19211 // Multiple break points. 19212 return FixedArray::cast(break_point_objects())->length(); 19213 } 19214 19215 19216 // static 19217 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor, 19218 Handle<JSReceiver> new_target, double tv) { 19219 Isolate* const isolate = constructor->GetIsolate(); 19220 Handle<JSObject> result; 19221 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 19222 JSObject::New(constructor, new_target), JSDate); 19223 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) { 19224 tv = DoubleToInteger(tv) + 0.0; 19225 } else { 19226 tv = std::numeric_limits<double>::quiet_NaN(); 19227 } 19228 Handle<Object> value = isolate->factory()->NewNumber(tv); 19229 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv)); 19230 return Handle<JSDate>::cast(result); 19231 } 19232 19233 19234 // static 19235 double JSDate::CurrentTimeValue(Isolate* isolate) { 19236 if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent()); 19237 19238 // According to ECMA-262, section 15.9.1, page 117, the precision of 19239 // the number in a Date object representing a particular instant in 19240 // time is milliseconds. Therefore, we floor the result of getting 19241 // the OS time. 19242 return Floor(FLAG_verify_predictable 19243 ? isolate->heap()->MonotonicallyIncreasingTimeInMs() 19244 : base::OS::TimeCurrentMillis()); 19245 } 19246 19247 19248 // static 19249 Object* JSDate::GetField(Object* object, Smi* index) { 19250 return JSDate::cast(object)->DoGetField( 19251 static_cast<FieldIndex>(index->value())); 19252 } 19253 19254 19255 Object* JSDate::DoGetField(FieldIndex index) { 19256 DCHECK(index != kDateValue); 19257 19258 DateCache* date_cache = GetIsolate()->date_cache(); 19259 19260 if (index < kFirstUncachedField) { 19261 Object* stamp = cache_stamp(); 19262 if (stamp != date_cache->stamp() && stamp->IsSmi()) { 19263 // Since the stamp is not NaN, the value is also not NaN. 19264 int64_t local_time_ms = 19265 date_cache->ToLocal(static_cast<int64_t>(value()->Number())); 19266 SetCachedFields(local_time_ms, date_cache); 19267 } 19268 switch (index) { 19269 case kYear: return year(); 19270 case kMonth: return month(); 19271 case kDay: return day(); 19272 case kWeekday: return weekday(); 19273 case kHour: return hour(); 19274 case kMinute: return min(); 19275 case kSecond: return sec(); 19276 default: UNREACHABLE(); 19277 } 19278 } 19279 19280 if (index >= kFirstUTCField) { 19281 return GetUTCField(index, value()->Number(), date_cache); 19282 } 19283 19284 double time = value()->Number(); 19285 if (std::isnan(time)) return GetIsolate()->heap()->nan_value(); 19286 19287 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time)); 19288 int days = DateCache::DaysFromTime(local_time_ms); 19289 19290 if (index == kDays) return Smi::FromInt(days); 19291 19292 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days); 19293 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000); 19294 DCHECK(index == kTimeInDay); 19295 return Smi::FromInt(time_in_day_ms); 19296 } 19297 19298 19299 Object* JSDate::GetUTCField(FieldIndex index, 19300 double value, 19301 DateCache* date_cache) { 19302 DCHECK(index >= kFirstUTCField); 19303 19304 if (std::isnan(value)) return GetIsolate()->heap()->nan_value(); 19305 19306 int64_t time_ms = static_cast<int64_t>(value); 19307 19308 if (index == kTimezoneOffset) { 19309 return Smi::FromInt(date_cache->TimezoneOffset(time_ms)); 19310 } 19311 19312 int days = DateCache::DaysFromTime(time_ms); 19313 19314 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days)); 19315 19316 if (index <= kDayUTC) { 19317 int year, month, day; 19318 date_cache->YearMonthDayFromDays(days, &year, &month, &day); 19319 if (index == kYearUTC) return Smi::FromInt(year); 19320 if (index == kMonthUTC) return Smi::FromInt(month); 19321 DCHECK(index == kDayUTC); 19322 return Smi::FromInt(day); 19323 } 19324 19325 int time_in_day_ms = DateCache::TimeInDay(time_ms, days); 19326 switch (index) { 19327 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000)); 19328 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60); 19329 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60); 19330 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000); 19331 case kDaysUTC: return Smi::FromInt(days); 19332 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms); 19333 default: UNREACHABLE(); 19334 } 19335 19336 UNREACHABLE(); 19337 return NULL; 19338 } 19339 19340 19341 // static 19342 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) { 19343 Isolate* const isolate = date->GetIsolate(); 19344 Handle<Object> value = isolate->factory()->NewNumber(v); 19345 bool value_is_nan = std::isnan(v); 19346 date->SetValue(*value, value_is_nan); 19347 return value; 19348 } 19349 19350 19351 void JSDate::SetValue(Object* value, bool is_value_nan) { 19352 set_value(value); 19353 if (is_value_nan) { 19354 HeapNumber* nan = GetIsolate()->heap()->nan_value(); 19355 set_cache_stamp(nan, SKIP_WRITE_BARRIER); 19356 set_year(nan, SKIP_WRITE_BARRIER); 19357 set_month(nan, SKIP_WRITE_BARRIER); 19358 set_day(nan, SKIP_WRITE_BARRIER); 19359 set_hour(nan, SKIP_WRITE_BARRIER); 19360 set_min(nan, SKIP_WRITE_BARRIER); 19361 set_sec(nan, SKIP_WRITE_BARRIER); 19362 set_weekday(nan, SKIP_WRITE_BARRIER); 19363 } else { 19364 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER); 19365 } 19366 } 19367 19368 19369 // static 19370 MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver, 19371 Handle<Object> hint) { 19372 Isolate* const isolate = receiver->GetIsolate(); 19373 if (hint->IsString()) { 19374 Handle<String> hint_string = Handle<String>::cast(hint); 19375 if (hint_string->Equals(isolate->heap()->number_string())) { 19376 return JSReceiver::OrdinaryToPrimitive(receiver, 19377 OrdinaryToPrimitiveHint::kNumber); 19378 } 19379 if (hint_string->Equals(isolate->heap()->default_string()) || 19380 hint_string->Equals(isolate->heap()->string_string())) { 19381 return JSReceiver::OrdinaryToPrimitive(receiver, 19382 OrdinaryToPrimitiveHint::kString); 19383 } 19384 } 19385 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint), 19386 Object); 19387 } 19388 19389 19390 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) { 19391 int days = DateCache::DaysFromTime(local_time_ms); 19392 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days); 19393 int year, month, day; 19394 date_cache->YearMonthDayFromDays(days, &year, &month, &day); 19395 int weekday = date_cache->Weekday(days); 19396 int hour = time_in_day_ms / (60 * 60 * 1000); 19397 int min = (time_in_day_ms / (60 * 1000)) % 60; 19398 int sec = (time_in_day_ms / 1000) % 60; 19399 set_cache_stamp(date_cache->stamp()); 19400 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 19401 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 19402 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 19403 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 19404 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 19405 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 19406 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 19407 } 19408 19409 namespace { 19410 19411 Script* ScriptFromJSValue(Object* in) { 19412 DCHECK(in->IsJSValue()); 19413 JSValue* jsvalue = JSValue::cast(in); 19414 DCHECK(jsvalue->value()->IsScript()); 19415 return Script::cast(jsvalue->value()); 19416 } 19417 19418 } // namespace 19419 19420 int JSMessageObject::GetLineNumber() const { 19421 if (start_position() == -1) return Message::kNoLineNumberInfo; 19422 19423 Handle<Script> the_script = handle(ScriptFromJSValue(script())); 19424 19425 Script::PositionInfo info; 19426 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 19427 if (!Script::GetPositionInfo(the_script, start_position(), &info, 19428 offset_flag)) { 19429 return Message::kNoLineNumberInfo; 19430 } 19431 19432 return info.line + 1; 19433 } 19434 19435 int JSMessageObject::GetColumnNumber() const { 19436 if (start_position() == -1) return -1; 19437 19438 Handle<Script> the_script = handle(ScriptFromJSValue(script())); 19439 19440 Script::PositionInfo info; 19441 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 19442 if (!Script::GetPositionInfo(the_script, start_position(), &info, 19443 offset_flag)) { 19444 return -1; 19445 } 19446 19447 return info.column; // Note: No '+1' in contrast to GetLineNumber. 19448 } 19449 19450 Handle<String> JSMessageObject::GetSourceLine() const { 19451 Handle<Script> the_script = handle(ScriptFromJSValue(script())); 19452 19453 Isolate* isolate = the_script->GetIsolate(); 19454 if (the_script->type() == Script::TYPE_WASM) { 19455 return isolate->factory()->empty_string(); 19456 } 19457 19458 Script::PositionInfo info; 19459 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 19460 if (!Script::GetPositionInfo(the_script, start_position(), &info, 19461 offset_flag)) { 19462 return isolate->factory()->empty_string(); 19463 } 19464 19465 Handle<String> src = handle(String::cast(the_script->source()), isolate); 19466 return isolate->factory()->NewSubString(src, info.line_start, info.line_end); 19467 } 19468 19469 void JSArrayBuffer::Neuter() { 19470 CHECK(is_neuterable()); 19471 CHECK(is_external()); 19472 set_backing_store(NULL); 19473 set_byte_length(Smi::kZero); 19474 set_was_neutered(true); 19475 } 19476 19477 19478 void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate, 19479 bool is_external, void* data, size_t allocated_length, 19480 SharedFlag shared) { 19481 DCHECK(array_buffer->GetInternalFieldCount() == 19482 v8::ArrayBuffer::kInternalFieldCount); 19483 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { 19484 array_buffer->SetInternalField(i, Smi::kZero); 19485 } 19486 array_buffer->set_bit_field(0); 19487 array_buffer->set_is_external(is_external); 19488 array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared); 19489 array_buffer->set_is_shared(shared == SharedFlag::kShared); 19490 19491 Handle<Object> byte_length = 19492 isolate->factory()->NewNumberFromSize(allocated_length); 19493 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); 19494 array_buffer->set_byte_length(*byte_length); 19495 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that 19496 // are currently being constructed in the |ArrayBufferTracker|. The 19497 // registration method below handles the case of registering a buffer that has 19498 // already been promoted. 19499 array_buffer->set_backing_store(data); 19500 19501 if (data && !is_external) { 19502 isolate->heap()->RegisterNewArrayBuffer(*array_buffer); 19503 } 19504 } 19505 19506 19507 bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer, 19508 Isolate* isolate, 19509 size_t allocated_length, 19510 bool initialize, SharedFlag shared) { 19511 void* data; 19512 CHECK(isolate->array_buffer_allocator() != NULL); 19513 // Prevent creating array buffers when serializing. 19514 DCHECK(!isolate->serializer_enabled()); 19515 if (allocated_length != 0) { 19516 if (initialize) { 19517 data = isolate->array_buffer_allocator()->Allocate(allocated_length); 19518 } else { 19519 data = isolate->array_buffer_allocator()->AllocateUninitialized( 19520 allocated_length); 19521 } 19522 if (data == NULL) return false; 19523 } else { 19524 data = NULL; 19525 } 19526 19527 JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length, 19528 shared); 19529 return true; 19530 } 19531 19532 19533 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer( 19534 Handle<JSTypedArray> typed_array) { 19535 19536 Handle<Map> map(typed_array->map()); 19537 Isolate* isolate = typed_array->GetIsolate(); 19538 19539 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind())); 19540 19541 Handle<FixedTypedArrayBase> fixed_typed_array( 19542 FixedTypedArrayBase::cast(typed_array->elements())); 19543 19544 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()), 19545 isolate); 19546 void* backing_store = 19547 isolate->array_buffer_allocator()->AllocateUninitialized( 19548 fixed_typed_array->DataSize()); 19549 buffer->set_is_external(false); 19550 DCHECK(buffer->byte_length()->IsSmi() || 19551 buffer->byte_length()->IsHeapNumber()); 19552 DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize()); 19553 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that 19554 // are currently being constructed in the |ArrayBufferTracker|. The 19555 // registration method below handles the case of registering a buffer that has 19556 // already been promoted. 19557 buffer->set_backing_store(backing_store); 19558 isolate->heap()->RegisterNewArrayBuffer(*buffer); 19559 memcpy(buffer->backing_store(), 19560 fixed_typed_array->DataPtr(), 19561 fixed_typed_array->DataSize()); 19562 Handle<FixedTypedArrayBase> new_elements = 19563 isolate->factory()->NewFixedTypedArrayWithExternalPointer( 19564 fixed_typed_array->length(), typed_array->type(), 19565 static_cast<uint8_t*>(buffer->backing_store())); 19566 19567 typed_array->set_elements(*new_elements); 19568 19569 return buffer; 19570 } 19571 19572 19573 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() { 19574 Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()), 19575 GetIsolate()); 19576 if (array_buffer->was_neutered() || 19577 array_buffer->backing_store() != nullptr) { 19578 return array_buffer; 19579 } 19580 Handle<JSTypedArray> self(this); 19581 return MaterializeArrayBuffer(self); 19582 } 19583 19584 Handle<PropertyCell> PropertyCell::InvalidateEntry( 19585 Handle<GlobalDictionary> dictionary, int entry) { 19586 Isolate* isolate = dictionary->GetIsolate(); 19587 // Swap with a copy. 19588 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 19589 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry))); 19590 Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(); 19591 new_cell->set_value(cell->value()); 19592 dictionary->ValueAtPut(entry, *new_cell); 19593 bool is_the_hole = cell->value()->IsTheHole(isolate); 19594 // Cell is officially mutable henceforth. 19595 PropertyDetails details = cell->property_details(); 19596 details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized 19597 : PropertyCellType::kMutable); 19598 new_cell->set_property_details(details); 19599 // Old cell is ready for invalidation. 19600 if (is_the_hole) { 19601 cell->set_value(isolate->heap()->undefined_value()); 19602 } else { 19603 cell->set_value(isolate->heap()->the_hole_value()); 19604 } 19605 details = details.set_cell_type(PropertyCellType::kInvalidated); 19606 cell->set_property_details(details); 19607 cell->dependent_code()->DeoptimizeDependentCodeGroup( 19608 isolate, DependentCode::kPropertyCellChangedGroup); 19609 return new_cell; 19610 } 19611 19612 19613 PropertyCellConstantType PropertyCell::GetConstantType() { 19614 if (value()->IsSmi()) return PropertyCellConstantType::kSmi; 19615 return PropertyCellConstantType::kStableMap; 19616 } 19617 19618 19619 static bool RemainsConstantType(Handle<PropertyCell> cell, 19620 Handle<Object> value) { 19621 // TODO(dcarney): double->smi and smi->double transition from kConstant 19622 if (cell->value()->IsSmi() && value->IsSmi()) { 19623 return true; 19624 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) { 19625 return HeapObject::cast(cell->value())->map() == 19626 HeapObject::cast(*value)->map() && 19627 HeapObject::cast(*value)->map()->is_stable(); 19628 } 19629 return false; 19630 } 19631 19632 19633 PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell, 19634 Handle<Object> value, 19635 PropertyDetails details) { 19636 PropertyCellType type = details.cell_type(); 19637 Isolate* isolate = cell->GetIsolate(); 19638 DCHECK(!value->IsTheHole(isolate)); 19639 if (cell->value()->IsTheHole(isolate)) { 19640 switch (type) { 19641 // Only allow a cell to transition once into constant state. 19642 case PropertyCellType::kUninitialized: 19643 if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined; 19644 return PropertyCellType::kConstant; 19645 case PropertyCellType::kInvalidated: 19646 return PropertyCellType::kMutable; 19647 default: 19648 UNREACHABLE(); 19649 return PropertyCellType::kMutable; 19650 } 19651 } 19652 switch (type) { 19653 case PropertyCellType::kUndefined: 19654 return PropertyCellType::kConstant; 19655 case PropertyCellType::kConstant: 19656 if (*value == cell->value()) return PropertyCellType::kConstant; 19657 // Fall through. 19658 case PropertyCellType::kConstantType: 19659 if (RemainsConstantType(cell, value)) { 19660 return PropertyCellType::kConstantType; 19661 } 19662 // Fall through. 19663 case PropertyCellType::kMutable: 19664 return PropertyCellType::kMutable; 19665 } 19666 UNREACHABLE(); 19667 return PropertyCellType::kMutable; 19668 } 19669 19670 Handle<PropertyCell> PropertyCell::PrepareForValue( 19671 Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value, 19672 PropertyDetails details) { 19673 Isolate* isolate = dictionary->GetIsolate(); 19674 DCHECK(!value->IsTheHole(isolate)); 19675 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 19676 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry))); 19677 const PropertyDetails original_details = cell->property_details(); 19678 // Data accesses could be cached in ics or optimized code. 19679 bool invalidate = 19680 original_details.kind() == kData && details.kind() == kAccessor; 19681 int index = original_details.dictionary_index(); 19682 PropertyCellType old_type = original_details.cell_type(); 19683 // Preserve the enumeration index unless the property was deleted or never 19684 // initialized. 19685 if (cell->value()->IsTheHole(isolate)) { 19686 index = dictionary->NextEnumerationIndex(); 19687 dictionary->SetNextEnumerationIndex(index + 1); 19688 } 19689 DCHECK(index > 0); 19690 details = details.set_index(index); 19691 19692 PropertyCellType new_type = UpdatedType(cell, value, original_details); 19693 if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry); 19694 19695 // Install new property details. 19696 details = details.set_cell_type(new_type); 19697 cell->set_property_details(details); 19698 19699 // Deopt when transitioning from a constant type. 19700 if (!invalidate && (old_type != new_type || 19701 original_details.IsReadOnly() != details.IsReadOnly())) { 19702 cell->dependent_code()->DeoptimizeDependentCodeGroup( 19703 isolate, DependentCode::kPropertyCellChangedGroup); 19704 } 19705 return cell; 19706 } 19707 19708 19709 // static 19710 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, 19711 Handle<Object> new_value) { 19712 if (cell->value() != *new_value) { 19713 cell->set_value(*new_value); 19714 Isolate* isolate = cell->GetIsolate(); 19715 cell->dependent_code()->DeoptimizeDependentCodeGroup( 19716 isolate, DependentCode::kPropertyCellChangedGroup); 19717 } 19718 } 19719 19720 int JSGeneratorObject::source_position() const { 19721 CHECK(is_suspended()); 19722 AbstractCode* code; 19723 int code_offset; 19724 if (function()->shared()->HasBytecodeArray()) { 19725 // New-style generators. 19726 DCHECK(!function()->shared()->HasBaselineCode()); 19727 code_offset = Smi::cast(input_or_debug_pos())->value(); 19728 // The stored bytecode offset is relative to a different base than what 19729 // is used in the source position table, hence the subtraction. 19730 code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag; 19731 code = AbstractCode::cast(function()->shared()->bytecode_array()); 19732 } else { 19733 // Old-style generators. 19734 DCHECK(function()->shared()->HasBaselineCode()); 19735 code_offset = continuation(); 19736 CHECK(0 <= code_offset); 19737 CHECK(code_offset < function()->code()->instruction_size()); 19738 code = AbstractCode::cast(function()->shared()->code()); 19739 } 19740 return code->SourcePosition(code_offset); 19741 } 19742 19743 // static 19744 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate, 19745 Handle<JSObject> receiver) { 19746 DisallowHeapAllocation no_gc; 19747 DCHECK(receiver->map()->is_access_check_needed()); 19748 Object* maybe_constructor = receiver->map()->GetConstructor(); 19749 // Might happen for a detached context. 19750 if (!maybe_constructor->IsJSFunction()) return nullptr; 19751 JSFunction* constructor = JSFunction::cast(maybe_constructor); 19752 // Might happen for the debug context. 19753 if (!constructor->shared()->IsApiFunction()) return nullptr; 19754 19755 Object* data_obj = 19756 constructor->shared()->get_api_func_data()->access_check_info(); 19757 if (data_obj->IsUndefined(isolate)) return nullptr; 19758 19759 return AccessCheckInfo::cast(data_obj); 19760 } 19761 19762 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) { 19763 for (PrototypeIterator iter(isolate, this, kStartAtReceiver, 19764 PrototypeIterator::END_AT_NULL); 19765 !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) { 19766 if (iter.GetCurrent<Object>()->IsJSProxy()) return true; 19767 } 19768 return false; 19769 } 19770 19771 MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) { 19772 Isolate* isolate = name->GetIsolate(); 19773 19774 Handle<Object> object(module()->exports()->Lookup(name), isolate); 19775 if (object->IsTheHole(isolate)) { 19776 return isolate->factory()->undefined_value(); 19777 } 19778 19779 Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate); 19780 if (value->IsTheHole(isolate)) { 19781 THROW_NEW_ERROR( 19782 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object); 19783 } 19784 19785 return value; 19786 } 19787 19788 namespace { 19789 19790 struct ModuleHandleHash { 19791 V8_INLINE size_t operator()(Handle<Module> module) const { 19792 return module->hash(); 19793 } 19794 }; 19795 19796 struct ModuleHandleEqual { 19797 V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const { 19798 return *lhs == *rhs; 19799 } 19800 }; 19801 19802 struct StringHandleHash { 19803 V8_INLINE size_t operator()(Handle<String> string) const { 19804 return string->Hash(); 19805 } 19806 }; 19807 19808 struct StringHandleEqual { 19809 V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const { 19810 return lhs->Equals(*rhs); 19811 } 19812 }; 19813 19814 class UnorderedStringSet 19815 : public std::unordered_set<Handle<String>, StringHandleHash, 19816 StringHandleEqual, 19817 zone_allocator<Handle<String>>> { 19818 public: 19819 explicit UnorderedStringSet(Zone* zone) 19820 : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual, 19821 zone_allocator<Handle<String>>>( 19822 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), 19823 zone_allocator<Handle<String>>(zone)) {} 19824 }; 19825 19826 class UnorderedModuleSet 19827 : public std::unordered_set<Handle<Module>, ModuleHandleHash, 19828 ModuleHandleEqual, 19829 zone_allocator<Handle<Module>>> { 19830 public: 19831 explicit UnorderedModuleSet(Zone* zone) 19832 : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual, 19833 zone_allocator<Handle<Module>>>( 19834 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), 19835 zone_allocator<Handle<Module>>(zone)) {} 19836 }; 19837 19838 class UnorderedStringMap 19839 : public std::unordered_map< 19840 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, 19841 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>> { 19842 public: 19843 explicit UnorderedStringMap(Zone* zone) 19844 : std::unordered_map< 19845 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, 19846 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>>( 19847 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), 19848 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>( 19849 zone)) {} 19850 }; 19851 19852 } // anonymous namespace 19853 19854 class Module::ResolveSet 19855 : public std::unordered_map< 19856 Handle<Module>, UnorderedStringSet*, ModuleHandleHash, 19857 ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>, 19858 UnorderedStringSet*>>> { 19859 public: 19860 explicit ResolveSet(Zone* zone) 19861 : std::unordered_map<Handle<Module>, UnorderedStringSet*, 19862 ModuleHandleHash, ModuleHandleEqual, 19863 zone_allocator<std::pair<const Handle<Module>, 19864 UnorderedStringSet*>>>( 19865 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), 19866 zone_allocator< 19867 std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)), 19868 zone_(zone) {} 19869 19870 Zone* zone() const { return zone_; } 19871 19872 private: 19873 Zone* zone_; 19874 }; 19875 19876 namespace { 19877 19878 int ExportIndex(int cell_index) { 19879 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 19880 ModuleDescriptor::kExport); 19881 return cell_index - 1; 19882 } 19883 19884 int ImportIndex(int cell_index) { 19885 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 19886 ModuleDescriptor::kImport); 19887 return -cell_index - 1; 19888 } 19889 19890 } // anonymous namespace 19891 19892 void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name, 19893 Handle<ModuleInfoEntry> entry) { 19894 Isolate* isolate = module->GetIsolate(); 19895 Handle<ObjectHashTable> exports(module->exports(), isolate); 19896 DCHECK(exports->Lookup(name)->IsTheHole(isolate)); 19897 exports = ObjectHashTable::Put(exports, name, entry); 19898 module->set_exports(*exports); 19899 } 19900 19901 void Module::CreateExport(Handle<Module> module, int cell_index, 19902 Handle<FixedArray> names) { 19903 DCHECK_LT(0, names->length()); 19904 Isolate* isolate = module->GetIsolate(); 19905 19906 Handle<Cell> cell = 19907 isolate->factory()->NewCell(isolate->factory()->undefined_value()); 19908 module->regular_exports()->set(ExportIndex(cell_index), *cell); 19909 19910 Handle<ObjectHashTable> exports(module->exports(), isolate); 19911 for (int i = 0, n = names->length(); i < n; ++i) { 19912 Handle<String> name(String::cast(names->get(i)), isolate); 19913 DCHECK(exports->Lookup(name)->IsTheHole(isolate)); 19914 exports = ObjectHashTable::Put(exports, name, cell); 19915 } 19916 module->set_exports(*exports); 19917 } 19918 19919 Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) { 19920 Isolate* isolate = module->GetIsolate(); 19921 Handle<Object> object; 19922 switch (ModuleDescriptor::GetCellIndexKind(cell_index)) { 19923 case ModuleDescriptor::kImport: 19924 object = handle(module->regular_imports()->get(ImportIndex(cell_index)), 19925 isolate); 19926 break; 19927 case ModuleDescriptor::kExport: 19928 object = handle(module->regular_exports()->get(ExportIndex(cell_index)), 19929 isolate); 19930 break; 19931 case ModuleDescriptor::kInvalid: 19932 UNREACHABLE(); 19933 break; 19934 } 19935 return handle(Handle<Cell>::cast(object)->value(), isolate); 19936 } 19937 19938 void Module::StoreVariable(Handle<Module> module, int cell_index, 19939 Handle<Object> value) { 19940 Isolate* isolate = module->GetIsolate(); 19941 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 19942 ModuleDescriptor::kExport); 19943 Handle<Object> object(module->regular_exports()->get(ExportIndex(cell_index)), 19944 isolate); 19945 Handle<Cell>::cast(object)->set_value(*value); 19946 } 19947 19948 MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module, 19949 Handle<String> name, int module_request, 19950 MessageLocation loc, bool must_resolve, 19951 Module::ResolveSet* resolve_set) { 19952 Isolate* isolate = module->GetIsolate(); 19953 Handle<Module> requested_module( 19954 Module::cast(module->requested_modules()->get(module_request)), isolate); 19955 return Module::ResolveExport(requested_module, name, loc, must_resolve, 19956 resolve_set); 19957 } 19958 19959 MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module, 19960 Handle<String> name, 19961 MessageLocation loc, bool must_resolve, 19962 Module::ResolveSet* resolve_set) { 19963 Isolate* isolate = module->GetIsolate(); 19964 Handle<Object> object(module->exports()->Lookup(name), isolate); 19965 if (object->IsCell()) { 19966 // Already resolved (e.g. because it's a local export). 19967 return Handle<Cell>::cast(object); 19968 } 19969 19970 // Check for cycle before recursing. 19971 { 19972 // Attempt insertion with a null string set. 19973 auto result = resolve_set->insert({module, nullptr}); 19974 UnorderedStringSet*& name_set = result.first->second; 19975 if (result.second) { 19976 // |module| wasn't in the map previously, so allocate a new name set. 19977 Zone* zone = resolve_set->zone(); 19978 name_set = 19979 new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone); 19980 } else if (name_set->count(name)) { 19981 // Cycle detected. 19982 if (must_resolve) { 19983 return isolate->Throw<Cell>( 19984 isolate->factory()->NewSyntaxError( 19985 MessageTemplate::kCyclicModuleDependency, name), 19986 &loc); 19987 } 19988 return MaybeHandle<Cell>(); 19989 } 19990 name_set->insert(name); 19991 } 19992 19993 if (object->IsModuleInfoEntry()) { 19994 // Not yet resolved indirect export. 19995 Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object); 19996 Handle<String> import_name(String::cast(entry->import_name()), isolate); 19997 Handle<Script> script( 19998 Script::cast(JSFunction::cast(module->code())->shared()->script()), 19999 isolate); 20000 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); 20001 20002 Handle<Cell> cell; 20003 if (!ResolveImport(module, import_name, entry->module_request(), new_loc, 20004 true, resolve_set) 20005 .ToHandle(&cell)) { 20006 DCHECK(isolate->has_pending_exception()); 20007 return MaybeHandle<Cell>(); 20008 } 20009 20010 // The export table may have changed but the entry in question should be 20011 // unchanged. 20012 Handle<ObjectHashTable> exports(module->exports(), isolate); 20013 DCHECK(exports->Lookup(name)->IsModuleInfoEntry()); 20014 20015 exports = ObjectHashTable::Put(exports, name, cell); 20016 module->set_exports(*exports); 20017 return cell; 20018 } 20019 20020 DCHECK(object->IsTheHole(isolate)); 20021 return Module::ResolveExportUsingStarExports(module, name, loc, must_resolve, 20022 resolve_set); 20023 } 20024 20025 MaybeHandle<Cell> Module::ResolveExportUsingStarExports( 20026 Handle<Module> module, Handle<String> name, MessageLocation loc, 20027 bool must_resolve, Module::ResolveSet* resolve_set) { 20028 Isolate* isolate = module->GetIsolate(); 20029 if (!name->Equals(isolate->heap()->default_string())) { 20030 // Go through all star exports looking for the given name. If multiple star 20031 // exports provide the name, make sure they all map it to the same cell. 20032 Handle<Cell> unique_cell; 20033 Handle<FixedArray> special_exports(module->info()->special_exports(), 20034 isolate); 20035 for (int i = 0, n = special_exports->length(); i < n; ++i) { 20036 i::Handle<i::ModuleInfoEntry> entry( 20037 i::ModuleInfoEntry::cast(special_exports->get(i)), isolate); 20038 if (!entry->export_name()->IsUndefined(isolate)) { 20039 continue; // Indirect export. 20040 } 20041 20042 Handle<Script> script( 20043 Script::cast(JSFunction::cast(module->code())->shared()->script()), 20044 isolate); 20045 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); 20046 20047 Handle<Cell> cell; 20048 if (ResolveImport(module, name, entry->module_request(), new_loc, false, 20049 resolve_set) 20050 .ToHandle(&cell)) { 20051 if (unique_cell.is_null()) unique_cell = cell; 20052 if (*unique_cell != *cell) { 20053 return isolate->Throw<Cell>( 20054 isolate->factory()->NewSyntaxError( 20055 MessageTemplate::kAmbiguousExport, name), 20056 &loc); 20057 } 20058 } else if (isolate->has_pending_exception()) { 20059 return MaybeHandle<Cell>(); 20060 } 20061 } 20062 20063 if (!unique_cell.is_null()) { 20064 // Found a unique star export for this name. 20065 Handle<ObjectHashTable> exports(module->exports(), isolate); 20066 DCHECK(exports->Lookup(name)->IsTheHole(isolate)); 20067 exports = ObjectHashTable::Put(exports, name, unique_cell); 20068 module->set_exports(*exports); 20069 return unique_cell; 20070 } 20071 } 20072 20073 // Unresolvable. 20074 if (must_resolve) { 20075 return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError( 20076 MessageTemplate::kUnresolvableExport, name), 20077 &loc); 20078 } 20079 return MaybeHandle<Cell>(); 20080 } 20081 20082 bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context, 20083 v8::Module::ResolveCallback callback) { 20084 if (module->instantiated()) return true; 20085 20086 Isolate* isolate = module->GetIsolate(); 20087 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()), 20088 isolate); 20089 Handle<JSFunction> function = 20090 isolate->factory()->NewFunctionFromSharedFunctionInfo( 20091 shared, 20092 handle(Utils::OpenHandle(*context)->native_context(), isolate)); 20093 module->set_code(*function); 20094 DCHECK(module->instantiated()); 20095 20096 Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(), 20097 isolate); 20098 20099 // Set up local exports. 20100 // TODO(neis): Create regular_exports array here instead of in factory method? 20101 for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) { 20102 int cell_index = module_info->RegularExportCellIndex(i); 20103 Handle<FixedArray> export_names(module_info->RegularExportExportNames(i), 20104 isolate); 20105 CreateExport(module, cell_index, export_names); 20106 } 20107 20108 // Partially set up indirect exports. 20109 // For each indirect export, we create the appropriate slot in the export 20110 // table and store its ModuleInfoEntry there. When we later find the correct 20111 // Cell in the module that actually provides the value, we replace the 20112 // ModuleInfoEntry by that Cell (see ResolveExport). 20113 Handle<FixedArray> special_exports(module_info->special_exports(), isolate); 20114 for (int i = 0, n = special_exports->length(); i < n; ++i) { 20115 Handle<ModuleInfoEntry> entry( 20116 ModuleInfoEntry::cast(special_exports->get(i)), isolate); 20117 Handle<Object> export_name(entry->export_name(), isolate); 20118 if (export_name->IsUndefined(isolate)) continue; // Star export. 20119 CreateIndirectExport(module, Handle<String>::cast(export_name), entry); 20120 } 20121 20122 Handle<FixedArray> module_requests(module_info->module_requests(), isolate); 20123 for (int i = 0, length = module_requests->length(); i < length; ++i) { 20124 Handle<String> specifier(String::cast(module_requests->get(i)), isolate); 20125 v8::Local<v8::Module> api_requested_module; 20126 // TODO(adamk): Revisit these failure cases once d8 knows how to 20127 // persist a module_map across multiple top-level module loads, as 20128 // the current module is left in a "half-instantiated" state. 20129 if (!callback(context, v8::Utils::ToLocal(specifier), 20130 v8::Utils::ToLocal(module)) 20131 .ToLocal(&api_requested_module)) { 20132 // TODO(adamk): Give this a better error message. But this is a 20133 // misuse of the API anyway. 20134 isolate->ThrowIllegalOperation(); 20135 return false; 20136 } 20137 Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module); 20138 module->requested_modules()->set(i, *requested_module); 20139 if (!Instantiate(requested_module, context, callback)) { 20140 return false; 20141 } 20142 } 20143 20144 Zone zone(isolate->allocator(), ZONE_NAME); 20145 20146 // Resolve imports. 20147 Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate); 20148 for (int i = 0, n = regular_imports->length(); i < n; ++i) { 20149 Handle<ModuleInfoEntry> entry( 20150 ModuleInfoEntry::cast(regular_imports->get(i)), isolate); 20151 Handle<String> name(String::cast(entry->import_name()), isolate); 20152 Handle<Script> script( 20153 Script::cast(JSFunction::cast(module->code())->shared()->script()), 20154 isolate); 20155 MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); 20156 ResolveSet resolve_set(&zone); 20157 Handle<Cell> cell; 20158 if (!ResolveImport(module, name, entry->module_request(), loc, true, 20159 &resolve_set) 20160 .ToHandle(&cell)) { 20161 return false; 20162 } 20163 module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell); 20164 } 20165 20166 // Resolve indirect exports. 20167 for (int i = 0, n = special_exports->length(); i < n; ++i) { 20168 Handle<ModuleInfoEntry> entry( 20169 ModuleInfoEntry::cast(special_exports->get(i)), isolate); 20170 Handle<Object> name(entry->export_name(), isolate); 20171 if (name->IsUndefined(isolate)) continue; // Star export. 20172 Handle<Script> script( 20173 Script::cast(JSFunction::cast(module->code())->shared()->script()), 20174 isolate); 20175 MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); 20176 ResolveSet resolve_set(&zone); 20177 if (ResolveExport(module, Handle<String>::cast(name), loc, true, 20178 &resolve_set) 20179 .is_null()) { 20180 return false; 20181 } 20182 } 20183 20184 return true; 20185 } 20186 20187 MaybeHandle<Object> Module::Evaluate(Handle<Module> module) { 20188 DCHECK(module->instantiated()); 20189 20190 // Each module can only be evaluated once. 20191 Isolate* isolate = module->GetIsolate(); 20192 if (module->evaluated()) return isolate->factory()->undefined_value(); 20193 Handle<JSFunction> function(JSFunction::cast(module->code()), isolate); 20194 module->set_evaluated(); 20195 20196 // Initialization. 20197 DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type()); 20198 Handle<Object> receiver = isolate->factory()->undefined_value(); 20199 Handle<Object> argv[] = {module}; 20200 Handle<Object> generator; 20201 ASSIGN_RETURN_ON_EXCEPTION( 20202 isolate, generator, 20203 Execution::Call(isolate, function, receiver, arraysize(argv), argv), 20204 Object); 20205 20206 // Recursion. 20207 Handle<FixedArray> requested_modules(module->requested_modules(), isolate); 20208 for (int i = 0, length = requested_modules->length(); i < length; ++i) { 20209 Handle<Module> import(Module::cast(requested_modules->get(i)), isolate); 20210 RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object); 20211 } 20212 20213 // Evaluation of module body. 20214 Handle<JSFunction> resume( 20215 isolate->native_context()->generator_next_internal(), isolate); 20216 return Execution::Call(isolate, resume, generator, 0, nullptr); 20217 } 20218 20219 namespace { 20220 20221 void FetchStarExports(Handle<Module> module, Zone* zone, 20222 UnorderedModuleSet* visited) { 20223 DCHECK(module->instantiated()); 20224 20225 bool cycle = !visited->insert(module).second; 20226 if (cycle) return; 20227 20228 Isolate* isolate = module->GetIsolate(); 20229 Handle<ObjectHashTable> exports(module->exports(), isolate); 20230 UnorderedStringMap more_exports(zone); 20231 20232 // TODO(neis): Only allocate more_exports if there are star exports. 20233 // Maybe split special_exports into indirect_exports and star_exports. 20234 20235 Handle<FixedArray> special_exports(module->info()->special_exports(), 20236 isolate); 20237 for (int i = 0, n = special_exports->length(); i < n; ++i) { 20238 Handle<ModuleInfoEntry> entry( 20239 ModuleInfoEntry::cast(special_exports->get(i)), isolate); 20240 if (!entry->export_name()->IsUndefined(isolate)) { 20241 continue; // Indirect export. 20242 } 20243 20244 Handle<Module> requested_module( 20245 Module::cast(module->requested_modules()->get(entry->module_request())), 20246 isolate); 20247 20248 // Recurse. 20249 FetchStarExports(requested_module, zone, visited); 20250 20251 // Collect all of [requested_module]'s exports that must be added to 20252 // [module]'s exports (i.e. to [exports]). We record these in 20253 // [more_exports]. Ambiguities (conflicting exports) are marked by mapping 20254 // the name to undefined instead of a Cell. 20255 Handle<ObjectHashTable> requested_exports(requested_module->exports(), 20256 isolate); 20257 for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) { 20258 Handle<Object> key(requested_exports->KeyAt(i), isolate); 20259 if (!requested_exports->IsKey(isolate, *key)) continue; 20260 Handle<String> name = Handle<String>::cast(key); 20261 20262 if (name->Equals(isolate->heap()->default_string())) continue; 20263 if (!exports->Lookup(name)->IsTheHole(isolate)) continue; 20264 20265 Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate); 20266 auto insert_result = more_exports.insert(std::make_pair(name, cell)); 20267 if (!insert_result.second) { 20268 auto it = insert_result.first; 20269 if (*it->second == *cell || it->second->IsUndefined(isolate)) { 20270 // We already recorded this mapping before, or the name is already 20271 // known to be ambiguous. In either case, there's nothing to do. 20272 } else { 20273 DCHECK(it->second->IsCell()); 20274 // Different star exports provide different cells for this name, hence 20275 // mark the name as ambiguous. 20276 it->second = isolate->factory()->undefined_value(); 20277 } 20278 } 20279 } 20280 } 20281 20282 // Copy [more_exports] into [exports]. 20283 for (const auto& elem : more_exports) { 20284 if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export. 20285 DCHECK(!elem.first->Equals(isolate->heap()->default_string())); 20286 DCHECK(elem.second->IsCell()); 20287 exports = ObjectHashTable::Put(exports, elem.first, elem.second); 20288 } 20289 module->set_exports(*exports); 20290 } 20291 20292 } // anonymous namespace 20293 20294 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module, 20295 int module_request) { 20296 Isolate* isolate = module->GetIsolate(); 20297 Handle<Module> requested_module( 20298 Module::cast(module->requested_modules()->get(module_request)), isolate); 20299 return Module::GetModuleNamespace(requested_module); 20300 } 20301 20302 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) { 20303 Isolate* isolate = module->GetIsolate(); 20304 20305 Handle<HeapObject> object(module->module_namespace(), isolate); 20306 if (!object->IsUndefined(isolate)) { 20307 // Namespace object already exists. 20308 return Handle<JSModuleNamespace>::cast(object); 20309 } 20310 20311 // Create the namespace object (initially empty). 20312 Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace(); 20313 ns->set_module(*module); 20314 module->set_module_namespace(*ns); 20315 20316 // Collect the export names. 20317 Zone zone(isolate->allocator(), ZONE_NAME); 20318 UnorderedModuleSet visited(&zone); 20319 FetchStarExports(module, &zone, &visited); 20320 Handle<ObjectHashTable> exports(module->exports(), isolate); 20321 ZoneVector<Handle<String>> names(&zone); 20322 names.reserve(exports->NumberOfElements()); 20323 for (int i = 0, n = exports->Capacity(); i < n; ++i) { 20324 Handle<Object> key(exports->KeyAt(i), isolate); 20325 if (!exports->IsKey(isolate, *key)) continue; 20326 DCHECK(exports->ValueAt(i)->IsCell()); 20327 names.push_back(Handle<String>::cast(key)); 20328 } 20329 DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements()); 20330 20331 // Sort them alphabetically. 20332 struct { 20333 bool operator()(Handle<String> a, Handle<String> b) { 20334 return String::Compare(a, b) == ComparisonResult::kLessThan; 20335 } 20336 } StringLess; 20337 std::sort(names.begin(), names.end(), StringLess); 20338 20339 // Create the corresponding properties in the namespace object. 20340 PropertyAttributes attr = DONT_DELETE; 20341 for (const auto& name : names) { 20342 JSObject::SetAccessor( 20343 ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr)) 20344 .Check(); 20345 } 20346 JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked(); 20347 20348 return ns; 20349 } 20350 20351 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName( 20352 Isolate* isolate, Handle<Object> getter) { 20353 if (getter->IsFunctionTemplateInfo()) { 20354 Handle<FunctionTemplateInfo> fti = 20355 Handle<FunctionTemplateInfo>::cast(getter); 20356 // Check if the accessor uses a cached property. 20357 if (!fti->cached_property_name()->IsTheHole(isolate)) { 20358 return handle(Name::cast(fti->cached_property_name())); 20359 } 20360 } 20361 return MaybeHandle<Name>(); 20362 } 20363 20364 // static 20365 ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) { 20366 DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE); 20367 DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE); 20368 20369 if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) { 20370 // Should be ignored for key iterators. 20371 return FAST_ELEMENTS; 20372 } else { 20373 ElementsKind kind; 20374 if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) { 20375 // Convert `type` to a value iterator from an entries iterator 20376 type = static_cast<InstanceType>(type + 20377 (FIRST_ARRAY_VALUE_ITERATOR_TYPE - 20378 FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE)); 20379 DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE); 20380 DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE); 20381 } 20382 20383 if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) { 20384 kind = 20385 static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 20386 (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE)); 20387 DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); 20388 } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) { 20389 kind = static_cast<ElementsKind>( 20390 FIRST_FAST_ELEMENTS_KIND + 20391 (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE)); 20392 DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND); 20393 } else { 20394 // For any slow element cases, the actual elements kind is not known. 20395 // Simply 20396 // return a slow elements kind in this case. Users of this function must 20397 // not 20398 // depend on this. 20399 return DICTIONARY_ELEMENTS; 20400 } 20401 DCHECK_LE(kind, LAST_ELEMENTS_KIND); 20402 return kind; 20403 } 20404 } 20405 20406 } // namespace internal 20407 } // namespace v8 20408