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 <sstream> 10 11 #include "src/objects-inl.h" 12 13 #include "src/accessors.h" 14 #include "src/allocation-site-scopes.h" 15 #include "src/api-arguments-inl.h" 16 #include "src/api-natives.h" 17 #include "src/api.h" 18 #include "src/base/bits.h" 19 #include "src/base/utils/random-number-generator.h" 20 #include "src/bootstrapper.h" 21 #include "src/code-stubs.h" 22 #include "src/codegen.h" 23 #include "src/compilation-dependencies.h" 24 #include "src/compiler.h" 25 #include "src/counters-inl.h" 26 #include "src/counters.h" 27 #include "src/date.h" 28 #include "src/debug/debug.h" 29 #include "src/deoptimizer.h" 30 #include "src/elements.h" 31 #include "src/execution.h" 32 #include "src/field-index-inl.h" 33 #include "src/field-index.h" 34 #include "src/field-type.h" 35 #include "src/frames-inl.h" 36 #include "src/full-codegen/full-codegen.h" 37 #include "src/ic/ic.h" 38 #include "src/identity-map.h" 39 #include "src/interpreter/bytecode-array-iterator.h" 40 #include "src/interpreter/interpreter.h" 41 #include "src/interpreter/source-position-table.h" 42 #include "src/isolate-inl.h" 43 #include "src/keys.h" 44 #include "src/list.h" 45 #include "src/log.h" 46 #include "src/lookup.h" 47 #include "src/macro-assembler.h" 48 #include "src/messages.h" 49 #include "src/objects-body-descriptors-inl.h" 50 #include "src/property-descriptor.h" 51 #include "src/prototype.h" 52 #include "src/regexp/jsregexp.h" 53 #include "src/safepoint-table.h" 54 #include "src/string-builder.h" 55 #include "src/string-search.h" 56 #include "src/string-stream.h" 57 #include "src/utils.h" 58 #include "src/zone.h" 59 60 #ifdef ENABLE_DISASSEMBLER 61 #include "src/disasm.h" 62 #include "src/disassembler.h" 63 #endif 64 65 namespace v8 { 66 namespace internal { 67 68 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) { 69 switch (instance_type) { 70 #define WRITE_TYPE(TYPE) \ 71 case TYPE: \ 72 return os << #TYPE; 73 INSTANCE_TYPE_LIST(WRITE_TYPE) 74 #undef WRITE_TYPE 75 } 76 UNREACHABLE(); 77 return os << "UNKNOWN"; // Keep the compiler happy. 78 } 79 80 Handle<FieldType> Object::OptimalType(Isolate* isolate, 81 Representation representation) { 82 if (representation.IsNone()) return FieldType::None(isolate); 83 if (FLAG_track_field_types) { 84 if (representation.IsHeapObject() && IsHeapObject()) { 85 // We can track only JavaScript objects with stable maps. 86 Handle<Map> map(HeapObject::cast(this)->map(), isolate); 87 if (map->is_stable() && map->IsJSReceiverMap()) { 88 return FieldType::Class(map, isolate); 89 } 90 } 91 } 92 return FieldType::Any(isolate); 93 } 94 95 96 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate, 97 Handle<Object> object, 98 Handle<Context> native_context) { 99 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 100 Handle<JSFunction> constructor; 101 if (object->IsSmi()) { 102 constructor = handle(native_context->number_function(), isolate); 103 } else { 104 int constructor_function_index = 105 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex(); 106 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 107 THROW_NEW_ERROR(isolate, 108 NewTypeError(MessageTemplate::kUndefinedOrNullToObject), 109 JSReceiver); 110 } 111 constructor = handle( 112 JSFunction::cast(native_context->get(constructor_function_index)), 113 isolate); 114 } 115 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); 116 Handle<JSValue>::cast(result)->set_value(*object); 117 return result; 118 } 119 120 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. 121 // static 122 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate, 123 Handle<Object> object) { 124 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 125 if (*object == isolate->heap()->null_value() || 126 object->IsUndefined(isolate)) { 127 return isolate->global_proxy(); 128 } 129 return Object::ToObject(isolate, object); 130 } 131 132 // static 133 MaybeHandle<Object> Object::ToNumber(Handle<Object> input) { 134 while (true) { 135 if (input->IsNumber()) { 136 return input; 137 } 138 if (input->IsString()) { 139 return String::ToNumber(Handle<String>::cast(input)); 140 } 141 if (input->IsOddball()) { 142 return Oddball::ToNumber(Handle<Oddball>::cast(input)); 143 } 144 Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate(); 145 if (input->IsSymbol()) { 146 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), 147 Object); 148 } 149 if (input->IsSimd128Value()) { 150 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber), 151 Object); 152 } 153 ASSIGN_RETURN_ON_EXCEPTION( 154 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), 155 ToPrimitiveHint::kNumber), 156 Object); 157 } 158 } 159 160 161 // static 162 MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) { 163 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 164 return isolate->factory()->NewNumber(DoubleToInteger(input->Number())); 165 } 166 167 168 // static 169 MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) { 170 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 171 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number())); 172 } 173 174 175 // static 176 MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) { 177 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 178 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number())); 179 } 180 181 182 // static 183 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate, 184 Handle<Object> input) { 185 ASSIGN_RETURN_ON_EXCEPTION( 186 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString), 187 Name); 188 if (input->IsName()) return Handle<Name>::cast(input); 189 return ToString(isolate, input); 190 } 191 192 // static 193 MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) { 194 while (true) { 195 if (input->IsString()) { 196 return Handle<String>::cast(input); 197 } 198 if (input->IsOddball()) { 199 return handle(Handle<Oddball>::cast(input)->to_string(), isolate); 200 } 201 if (input->IsNumber()) { 202 return isolate->factory()->NumberToString(input); 203 } 204 if (input->IsSymbol()) { 205 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString), 206 String); 207 } 208 if (input->IsSimd128Value()) { 209 return Simd128Value::ToString(Handle<Simd128Value>::cast(input)); 210 } 211 ASSIGN_RETURN_ON_EXCEPTION( 212 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), 213 ToPrimitiveHint::kString), 214 String); 215 } 216 } 217 218 219 // static 220 MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) { 221 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); 222 double len = DoubleToInteger(input->Number()); 223 if (len <= 0.0) { 224 len = 0.0; 225 } else if (len >= kMaxSafeInteger) { 226 len = kMaxSafeInteger; 227 } 228 return isolate->factory()->NewNumber(len); 229 } 230 231 232 bool Object::BooleanValue() { 233 if (IsSmi()) return Smi::cast(this)->value() != 0; 234 DCHECK(IsHeapObject()); 235 Isolate* isolate = HeapObject::cast(this)->GetIsolate(); 236 if (IsBoolean()) return IsTrue(isolate); 237 if (IsUndefined(isolate) || IsNull(isolate)) return false; 238 if (IsUndetectable()) return false; // Undetectable object is false. 239 if (IsString()) return String::cast(this)->length() != 0; 240 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue(); 241 return true; 242 } 243 244 245 namespace { 246 247 // TODO(bmeurer): Maybe we should introduce a marker interface Number, 248 // where we put all these methods at some point? 249 ComparisonResult NumberCompare(double x, double y) { 250 if (std::isnan(x) || std::isnan(y)) { 251 return ComparisonResult::kUndefined; 252 } else if (x < y) { 253 return ComparisonResult::kLessThan; 254 } else if (x > y) { 255 return ComparisonResult::kGreaterThan; 256 } else { 257 return ComparisonResult::kEqual; 258 } 259 } 260 261 262 bool NumberEquals(double x, double y) { 263 // Must check explicitly for NaN's on Windows, but -0 works fine. 264 if (std::isnan(x)) return false; 265 if (std::isnan(y)) return false; 266 return x == y; 267 } 268 269 270 bool NumberEquals(const Object* x, const Object* y) { 271 return NumberEquals(x->Number(), y->Number()); 272 } 273 274 275 bool NumberEquals(Handle<Object> x, Handle<Object> y) { 276 return NumberEquals(*x, *y); 277 } 278 279 } // namespace 280 281 282 // static 283 Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) { 284 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4. 285 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) || 286 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) { 287 return Nothing<ComparisonResult>(); 288 } 289 if (x->IsString() && y->IsString()) { 290 // ES6 section 7.2.11 Abstract Relational Comparison step 5. 291 return Just( 292 String::Compare(Handle<String>::cast(x), Handle<String>::cast(y))); 293 } 294 // ES6 section 7.2.11 Abstract Relational Comparison step 6. 295 if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) { 296 return Nothing<ComparisonResult>(); 297 } 298 return Just(NumberCompare(x->Number(), y->Number())); 299 } 300 301 302 // static 303 Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) { 304 // This is the generic version of Abstract Equality Comparison; a version in 305 // JavaScript land is available in the EqualStub and NotEqualStub. Whenever 306 // you change something functionality wise in here, remember to update the 307 // TurboFan code stubs as well. 308 while (true) { 309 if (x->IsNumber()) { 310 if (y->IsNumber()) { 311 return Just(NumberEquals(x, y)); 312 } else if (y->IsBoolean()) { 313 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 314 } else if (y->IsString()) { 315 return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y)))); 316 } else if (y->IsJSReceiver()) { 317 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 318 .ToHandle(&y)) { 319 return Nothing<bool>(); 320 } 321 } else { 322 return Just(false); 323 } 324 } else if (x->IsString()) { 325 if (y->IsString()) { 326 return Just( 327 String::Equals(Handle<String>::cast(x), Handle<String>::cast(y))); 328 } else if (y->IsNumber()) { 329 x = String::ToNumber(Handle<String>::cast(x)); 330 return Just(NumberEquals(x, y)); 331 } else if (y->IsBoolean()) { 332 x = String::ToNumber(Handle<String>::cast(x)); 333 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 334 } else if (y->IsJSReceiver()) { 335 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 336 .ToHandle(&y)) { 337 return Nothing<bool>(); 338 } 339 } else { 340 return Just(false); 341 } 342 } else if (x->IsBoolean()) { 343 if (y->IsOddball()) { 344 return Just(x.is_identical_to(y)); 345 } else if (y->IsNumber()) { 346 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 347 } else if (y->IsString()) { 348 y = String::ToNumber(Handle<String>::cast(y)); 349 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 350 } else if (y->IsJSReceiver()) { 351 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 352 .ToHandle(&y)) { 353 return Nothing<bool>(); 354 } 355 x = Oddball::ToNumber(Handle<Oddball>::cast(x)); 356 } else { 357 return Just(false); 358 } 359 } else if (x->IsSymbol()) { 360 if (y->IsSymbol()) { 361 return Just(x.is_identical_to(y)); 362 } else if (y->IsJSReceiver()) { 363 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 364 .ToHandle(&y)) { 365 return Nothing<bool>(); 366 } 367 } else { 368 return Just(false); 369 } 370 } else if (x->IsSimd128Value()) { 371 if (y->IsSimd128Value()) { 372 return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x), 373 Handle<Simd128Value>::cast(y))); 374 } else if (y->IsJSReceiver()) { 375 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 376 .ToHandle(&y)) { 377 return Nothing<bool>(); 378 } 379 } else { 380 return Just(false); 381 } 382 } else if (x->IsJSReceiver()) { 383 if (y->IsJSReceiver()) { 384 return Just(x.is_identical_to(y)); 385 } else if (y->IsUndetectable()) { 386 return Just(x->IsUndetectable()); 387 } else if (y->IsBoolean()) { 388 y = Oddball::ToNumber(Handle<Oddball>::cast(y)); 389 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x)) 390 .ToHandle(&x)) { 391 return Nothing<bool>(); 392 } 393 } else { 394 return Just(x->IsUndetectable() && y->IsUndetectable()); 395 } 396 } 397 } 398 399 400 bool Object::StrictEquals(Object* that) { 401 if (this->IsNumber()) { 402 if (!that->IsNumber()) return false; 403 return NumberEquals(this, that); 404 } else if (this->IsString()) { 405 if (!that->IsString()) return false; 406 return String::cast(this)->Equals(String::cast(that)); 407 } else if (this->IsSimd128Value()) { 408 if (!that->IsSimd128Value()) return false; 409 return Simd128Value::cast(this)->Equals(Simd128Value::cast(that)); 410 } 411 return this == that; 412 } 413 414 415 // static 416 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) { 417 if (object->IsNumber()) return isolate->factory()->number_string(); 418 if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of()); 419 if (object->IsUndetectable()) { 420 return isolate->factory()->undefined_string(); 421 } 422 if (object->IsString()) return isolate->factory()->string_string(); 423 if (object->IsSymbol()) return isolate->factory()->symbol_string(); 424 if (object->IsString()) return isolate->factory()->string_string(); 425 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 426 if (object->Is##Type()) return isolate->factory()->type##_string(); 427 SIMD128_TYPES(SIMD128_TYPE) 428 #undef SIMD128_TYPE 429 if (object->IsCallable()) return isolate->factory()->function_string(); 430 return isolate->factory()->object_string(); 431 } 432 433 434 // static 435 MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs, 436 Handle<Object> rhs) { 437 if (!lhs->IsNumber() || !rhs->IsNumber()) { 438 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 439 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 440 } 441 return isolate->factory()->NewNumber(lhs->Number() * rhs->Number()); 442 } 443 444 445 // static 446 MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs, 447 Handle<Object> rhs) { 448 if (!lhs->IsNumber() || !rhs->IsNumber()) { 449 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 450 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 451 } 452 return isolate->factory()->NewNumber(lhs->Number() / rhs->Number()); 453 } 454 455 456 // static 457 MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs, 458 Handle<Object> rhs) { 459 if (!lhs->IsNumber() || !rhs->IsNumber()) { 460 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 461 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 462 } 463 return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number())); 464 } 465 466 467 // static 468 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs, 469 Handle<Object> rhs) { 470 if (lhs->IsNumber() && rhs->IsNumber()) { 471 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 472 } else if (lhs->IsString() && rhs->IsString()) { 473 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 474 Handle<String>::cast(rhs)); 475 } 476 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object); 477 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object); 478 if (lhs->IsString() || rhs->IsString()) { 479 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs), 480 Object); 481 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs), 482 Object); 483 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 484 Handle<String>::cast(rhs)); 485 } 486 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 487 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 488 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 489 } 490 491 492 // static 493 MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs, 494 Handle<Object> rhs) { 495 if (!lhs->IsNumber() || !rhs->IsNumber()) { 496 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 497 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 498 } 499 return isolate->factory()->NewNumber(lhs->Number() - rhs->Number()); 500 } 501 502 503 // static 504 MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs, 505 Handle<Object> rhs) { 506 if (!lhs->IsNumber() || !rhs->IsNumber()) { 507 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 508 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 509 } 510 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) 511 << (NumberToUint32(*rhs) & 0x1F)); 512 } 513 514 515 // static 516 MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs, 517 Handle<Object> rhs) { 518 if (!lhs->IsNumber() || !rhs->IsNumber()) { 519 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 520 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 521 } 522 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >> 523 (NumberToUint32(*rhs) & 0x1F)); 524 } 525 526 527 // static 528 MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate, 529 Handle<Object> lhs, 530 Handle<Object> rhs) { 531 if (!lhs->IsNumber() || !rhs->IsNumber()) { 532 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 533 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 534 } 535 return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >> 536 (NumberToUint32(*rhs) & 0x1F)); 537 } 538 539 540 // static 541 MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs, 542 Handle<Object> rhs) { 543 if (!lhs->IsNumber() || !rhs->IsNumber()) { 544 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 545 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 546 } 547 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) & 548 NumberToInt32(*rhs)); 549 } 550 551 552 // static 553 MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs, 554 Handle<Object> rhs) { 555 if (!lhs->IsNumber() || !rhs->IsNumber()) { 556 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 557 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 558 } 559 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) | 560 NumberToInt32(*rhs)); 561 } 562 563 564 // static 565 MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs, 566 Handle<Object> rhs) { 567 if (!lhs->IsNumber() || !rhs->IsNumber()) { 568 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); 569 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); 570 } 571 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^ 572 NumberToInt32(*rhs)); 573 } 574 575 // static 576 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate, 577 Handle<Object> callable, 578 Handle<Object> object) { 579 // The {callable} must have a [[Call]] internal method. 580 if (!callable->IsCallable()) return isolate->factory()->false_value(); 581 582 // Check if {callable} is a bound function, and if so retrieve its 583 // [[BoundTargetFunction]] and use that instead of {callable}. 584 if (callable->IsJSBoundFunction()) { 585 Handle<Object> bound_callable( 586 Handle<JSBoundFunction>::cast(callable)->bound_target_function(), 587 isolate); 588 return Object::InstanceOf(isolate, object, bound_callable); 589 } 590 591 // If {object} is not a receiver, return false. 592 if (!object->IsJSReceiver()) return isolate->factory()->false_value(); 593 594 // Get the "prototype" of {callable}; raise an error if it's not a receiver. 595 Handle<Object> prototype; 596 ASSIGN_RETURN_ON_EXCEPTION( 597 isolate, prototype, 598 Object::GetProperty(callable, isolate->factory()->prototype_string()), 599 Object); 600 if (!prototype->IsJSReceiver()) { 601 THROW_NEW_ERROR( 602 isolate, 603 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype), 604 Object); 605 } 606 607 // Return whether or not {prototype} is in the prototype chain of {object}. 608 Maybe<bool> result = JSReceiver::HasInPrototypeChain( 609 isolate, Handle<JSReceiver>::cast(object), prototype); 610 if (result.IsNothing()) return MaybeHandle<Object>(); 611 return isolate->factory()->ToBoolean(result.FromJust()); 612 } 613 614 // static 615 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object, 616 Handle<Object> callable) { 617 // The {callable} must be a receiver. 618 if (!callable->IsJSReceiver()) { 619 THROW_NEW_ERROR(isolate, 620 NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck), 621 Object); 622 } 623 624 // Lookup the @@hasInstance method on {callable}. 625 Handle<Object> inst_of_handler; 626 ASSIGN_RETURN_ON_EXCEPTION( 627 isolate, inst_of_handler, 628 JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable), 629 isolate->factory()->has_instance_symbol()), 630 Object); 631 if (!inst_of_handler->IsUndefined(isolate)) { 632 // Call the {inst_of_handler} on the {callable}. 633 Handle<Object> result; 634 ASSIGN_RETURN_ON_EXCEPTION( 635 isolate, result, 636 Execution::Call(isolate, inst_of_handler, callable, 1, &object), 637 Object); 638 return isolate->factory()->ToBoolean(result->BooleanValue()); 639 } 640 641 // The {callable} must have a [[Call]] internal method. 642 if (!callable->IsCallable()) { 643 THROW_NEW_ERROR( 644 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck), 645 Object); 646 } 647 648 // Fall back to OrdinaryHasInstance with {callable} and {object}. 649 Handle<Object> result; 650 ASSIGN_RETURN_ON_EXCEPTION( 651 isolate, result, 652 JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object); 653 return result; 654 } 655 656 Maybe<bool> Object::IsArray(Handle<Object> object) { 657 if (object->IsJSArray()) return Just(true); 658 if (object->IsJSProxy()) { 659 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object); 660 Isolate* isolate = proxy->GetIsolate(); 661 if (proxy->IsRevoked()) { 662 isolate->Throw(*isolate->factory()->NewTypeError( 663 MessageTemplate::kProxyRevoked, 664 isolate->factory()->NewStringFromAsciiChecked("IsArray"))); 665 return Nothing<bool>(); 666 } 667 return Object::IsArray(handle(proxy->target(), isolate)); 668 } 669 return Just(false); 670 } 671 672 673 // static 674 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver, 675 Handle<Name> name) { 676 Handle<Object> func; 677 Isolate* isolate = receiver->GetIsolate(); 678 ASSIGN_RETURN_ON_EXCEPTION(isolate, func, 679 JSReceiver::GetProperty(receiver, name), Object); 680 if (func->IsNull(isolate) || func->IsUndefined(isolate)) { 681 return isolate->factory()->undefined_value(); 682 } 683 if (!func->IsCallable()) { 684 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction, 685 func, name, receiver), 686 Object); 687 } 688 return func; 689 } 690 691 692 // static 693 MaybeHandle<FixedArray> Object::CreateListFromArrayLike( 694 Isolate* isolate, Handle<Object> object, ElementTypes element_types) { 695 // 1. ReturnIfAbrupt(object). 696 // 2. (default elementTypes -- not applicable.) 697 // 3. If Type(obj) is not Object, throw a TypeError exception. 698 if (!object->IsJSReceiver()) { 699 THROW_NEW_ERROR(isolate, 700 NewTypeError(MessageTemplate::kCalledOnNonObject, 701 isolate->factory()->NewStringFromAsciiChecked( 702 "CreateListFromArrayLike")), 703 FixedArray); 704 } 705 // 4. Let len be ? ToLength(? Get(obj, "length")). 706 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); 707 Handle<Object> raw_length_number; 708 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number, 709 Object::GetLengthFromArrayLike(isolate, receiver), 710 FixedArray); 711 uint32_t len; 712 if (!raw_length_number->ToUint32(&len) || 713 len > static_cast<uint32_t>(FixedArray::kMaxLength)) { 714 THROW_NEW_ERROR(isolate, 715 NewRangeError(MessageTemplate::kInvalidArrayLength), 716 FixedArray); 717 } 718 // 5. Let list be an empty List. 719 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len); 720 // 6. Let index be 0. 721 // 7. Repeat while index < len: 722 for (uint32_t index = 0; index < len; ++index) { 723 // 7a. Let indexName be ToString(index). 724 // 7b. Let next be ? Get(obj, indexName). 725 Handle<Object> next; 726 ASSIGN_RETURN_ON_EXCEPTION(isolate, next, 727 JSReceiver::GetElement(isolate, receiver, index), 728 FixedArray); 729 switch (element_types) { 730 case ElementTypes::kAll: 731 // Nothing to do. 732 break; 733 case ElementTypes::kStringAndSymbol: { 734 // 7c. If Type(next) is not an element of elementTypes, throw a 735 // TypeError exception. 736 if (!next->IsName()) { 737 THROW_NEW_ERROR(isolate, 738 NewTypeError(MessageTemplate::kNotPropertyName, next), 739 FixedArray); 740 } 741 // 7d. Append next as the last element of list. 742 // Internalize on the fly so we can use pointer identity later. 743 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next)); 744 break; 745 } 746 } 747 list->set(index, *next); 748 // 7e. Set index to index + 1. (See loop header.) 749 } 750 // 8. Return list. 751 return list; 752 } 753 754 755 // static 756 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate, 757 Handle<Object> object) { 758 Handle<Object> val; 759 Handle<Object> key = isolate->factory()->length_string(); 760 ASSIGN_RETURN_ON_EXCEPTION( 761 isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object); 762 return Object::ToLength(isolate, val); 763 } 764 765 // static 766 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) { 767 for (; it->IsFound(); it->Next()) { 768 switch (it->state()) { 769 case LookupIterator::NOT_FOUND: 770 case LookupIterator::TRANSITION: 771 UNREACHABLE(); 772 case LookupIterator::JSPROXY: 773 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(), 774 it->GetName()); 775 case LookupIterator::INTERCEPTOR: { 776 Maybe<PropertyAttributes> result = 777 JSObject::GetPropertyAttributesWithInterceptor(it); 778 if (result.IsNothing()) return Nothing<bool>(); 779 if (result.FromJust() != ABSENT) return Just(true); 780 break; 781 } 782 case LookupIterator::ACCESS_CHECK: { 783 if (it->HasAccess()) break; 784 Maybe<PropertyAttributes> result = 785 JSObject::GetPropertyAttributesWithFailedAccessCheck(it); 786 if (result.IsNothing()) return Nothing<bool>(); 787 return Just(result.FromJust() != ABSENT); 788 } 789 case LookupIterator::INTEGER_INDEXED_EXOTIC: 790 // TypedArray out-of-bounds access. 791 return Just(false); 792 case LookupIterator::ACCESSOR: 793 case LookupIterator::DATA: 794 return Just(true); 795 } 796 } 797 return Just(false); 798 } 799 800 801 // static 802 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) { 803 for (; it->IsFound(); it->Next()) { 804 switch (it->state()) { 805 case LookupIterator::NOT_FOUND: 806 case LookupIterator::TRANSITION: 807 UNREACHABLE(); 808 case LookupIterator::JSPROXY: { 809 bool was_found; 810 MaybeHandle<Object> result = 811 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(), 812 it->GetName(), it->GetReceiver(), &was_found); 813 if (!was_found) it->NotFound(); 814 return result; 815 } 816 case LookupIterator::INTERCEPTOR: { 817 bool done; 818 Handle<Object> result; 819 ASSIGN_RETURN_ON_EXCEPTION( 820 it->isolate(), result, 821 JSObject::GetPropertyWithInterceptor(it, &done), Object); 822 if (done) return result; 823 break; 824 } 825 case LookupIterator::ACCESS_CHECK: 826 if (it->HasAccess()) break; 827 return JSObject::GetPropertyWithFailedAccessCheck(it); 828 case LookupIterator::ACCESSOR: 829 return GetPropertyWithAccessor(it); 830 case LookupIterator::INTEGER_INDEXED_EXOTIC: 831 return ReadAbsentProperty(it); 832 case LookupIterator::DATA: 833 return it->GetDataValue(); 834 } 835 } 836 return ReadAbsentProperty(it); 837 } 838 839 840 // static 841 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate, 842 Handle<JSProxy> proxy, 843 Handle<Name> name, 844 Handle<Object> receiver, 845 bool* was_found) { 846 *was_found = true; 847 if (receiver->IsJSGlobalObject()) { 848 THROW_NEW_ERROR( 849 isolate, 850 NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name), 851 Object); 852 } 853 854 DCHECK(!name->IsPrivate()); 855 STACK_CHECK(isolate, MaybeHandle<Object>()); 856 Handle<Name> trap_name = isolate->factory()->get_string(); 857 // 1. Assert: IsPropertyKey(P) is true. 858 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 859 Handle<Object> handler(proxy->handler(), isolate); 860 // 3. If handler is null, throw a TypeError exception. 861 // 4. Assert: Type(handler) is Object. 862 if (proxy->IsRevoked()) { 863 THROW_NEW_ERROR(isolate, 864 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 865 Object); 866 } 867 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 868 Handle<JSReceiver> target(proxy->target(), isolate); 869 // 6. Let trap be ? GetMethod(handler, "get"). 870 Handle<Object> trap; 871 ASSIGN_RETURN_ON_EXCEPTION( 872 isolate, trap, 873 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object); 874 // 7. If trap is undefined, then 875 if (trap->IsUndefined(isolate)) { 876 // 7.a Return target.[[Get]](P, Receiver). 877 LookupIterator it = 878 LookupIterator::PropertyOrElement(isolate, receiver, name, target); 879 MaybeHandle<Object> result = Object::GetProperty(&it); 880 *was_found = it.IsFound(); 881 return result; 882 } 883 // 8. Let trapResult be ? Call(trap, handler, target, P, Receiver). 884 Handle<Object> trap_result; 885 Handle<Object> args[] = {target, name, receiver}; 886 ASSIGN_RETURN_ON_EXCEPTION( 887 isolate, trap_result, 888 Execution::Call(isolate, trap, handler, arraysize(args), args), Object); 889 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). 890 PropertyDescriptor target_desc; 891 Maybe<bool> target_found = 892 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 893 MAYBE_RETURN_NULL(target_found); 894 // 10. If targetDesc is not undefined, then 895 if (target_found.FromJust()) { 896 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is 897 // false and targetDesc.[[Writable]] is false, then 898 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false, 899 // throw a TypeError exception. 900 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && 901 !target_desc.configurable() && 902 !target_desc.writable() && 903 !trap_result->SameValue(*target_desc.value()); 904 if (inconsistent) { 905 THROW_NEW_ERROR( 906 isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, 907 name, target_desc.value(), trap_result), 908 Object); 909 } 910 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] 911 // is false and targetDesc.[[Get]] is undefined, then 912 // 10.b.i. If trapResult is not undefined, throw a TypeError exception. 913 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 914 !target_desc.configurable() && 915 target_desc.get()->IsUndefined(isolate) && 916 !trap_result->IsUndefined(isolate); 917 if (inconsistent) { 918 THROW_NEW_ERROR( 919 isolate, 920 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name, 921 trap_result), 922 Object); 923 } 924 } 925 // 11. Return trap_result 926 return trap_result; 927 } 928 929 930 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) { 931 for (; it->IsFound(); it->Next()) { 932 switch (it->state()) { 933 case LookupIterator::INTERCEPTOR: 934 case LookupIterator::NOT_FOUND: 935 case LookupIterator::TRANSITION: 936 UNREACHABLE(); 937 case LookupIterator::ACCESS_CHECK: 938 // Support calling this method without an active context, but refuse 939 // access to access-checked objects in that case. 940 if (it->isolate()->context() != nullptr && it->HasAccess()) continue; 941 // Fall through. 942 case LookupIterator::JSPROXY: 943 it->NotFound(); 944 return it->isolate()->factory()->undefined_value(); 945 case LookupIterator::ACCESSOR: 946 // TODO(verwaest): For now this doesn't call into AccessorInfo, since 947 // clients don't need it. Update once relevant. 948 it->NotFound(); 949 return it->isolate()->factory()->undefined_value(); 950 case LookupIterator::INTEGER_INDEXED_EXOTIC: 951 return it->isolate()->factory()->undefined_value(); 952 case LookupIterator::DATA: 953 return it->GetDataValue(); 954 } 955 } 956 return it->isolate()->factory()->undefined_value(); 957 } 958 959 960 bool Object::ToInt32(int32_t* value) { 961 if (IsSmi()) { 962 *value = Smi::cast(this)->value(); 963 return true; 964 } 965 if (IsHeapNumber()) { 966 double num = HeapNumber::cast(this)->value(); 967 if (FastI2D(FastD2I(num)) == num) { 968 *value = FastD2I(num); 969 return true; 970 } 971 } 972 return false; 973 } 974 975 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( 976 Isolate* isolate, Handle<FunctionTemplateInfo> info) { 977 Object* current_info = info->shared_function_info(); 978 if (current_info->IsSharedFunctionInfo()) { 979 return handle(SharedFunctionInfo::cast(current_info), isolate); 980 } 981 982 Handle<Object> class_name(info->class_name(), isolate); 983 Handle<String> name = class_name->IsString() 984 ? Handle<String>::cast(class_name) 985 : isolate->factory()->empty_string(); 986 Handle<Code> code; 987 if (info->call_code()->IsCallHandlerInfo() && 988 CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) { 989 code = isolate->builtins()->HandleFastApiCall(); 990 } else { 991 code = isolate->builtins()->HandleApiCall(); 992 } 993 bool is_constructor = !info->remove_prototype(); 994 Handle<SharedFunctionInfo> result = 995 isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor); 996 if (is_constructor) { 997 result->set_construct_stub(*isolate->builtins()->JSConstructStubApi()); 998 } 999 1000 result->set_length(info->length()); 1001 if (class_name->IsString()) result->set_instance_class_name(*class_name); 1002 result->set_api_func_data(*info); 1003 result->DontAdaptArguments(); 1004 DCHECK(result->IsApiFunction()); 1005 1006 info->set_shared_function_info(*result); 1007 return result; 1008 } 1009 1010 bool FunctionTemplateInfo::IsTemplateFor(Map* map) { 1011 // There is a constraint on the object; check. 1012 if (!map->IsJSObjectMap()) return false; 1013 // Fetch the constructor function of the object. 1014 Object* cons_obj = map->GetConstructor(); 1015 if (!cons_obj->IsJSFunction()) return false; 1016 JSFunction* fun = JSFunction::cast(cons_obj); 1017 // Iterate through the chain of inheriting function templates to 1018 // see if the required one occurs. 1019 for (Object* type = fun->shared()->function_data(); 1020 type->IsFunctionTemplateInfo(); 1021 type = FunctionTemplateInfo::cast(type)->parent_template()) { 1022 if (type == this) return true; 1023 } 1024 // Didn't find the required type in the inheritance chain. 1025 return false; 1026 } 1027 1028 1029 // static 1030 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor, 1031 Handle<JSReceiver> new_target, 1032 Handle<AllocationSite> site) { 1033 // If called through new, new.target can be: 1034 // - a subclass of constructor, 1035 // - a proxy wrapper around constructor, or 1036 // - the constructor itself. 1037 // If called through Reflect.construct, it's guaranteed to be a constructor. 1038 Isolate* const isolate = constructor->GetIsolate(); 1039 DCHECK(constructor->IsConstructor()); 1040 DCHECK(new_target->IsConstructor()); 1041 DCHECK(!constructor->has_initial_map() || 1042 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE); 1043 1044 Handle<Map> initial_map; 1045 ASSIGN_RETURN_ON_EXCEPTION( 1046 isolate, initial_map, 1047 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject); 1048 Handle<JSObject> result = 1049 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site); 1050 isolate->counters()->constructed_objects()->Increment(); 1051 isolate->counters()->constructed_objects_runtime()->Increment(); 1052 return result; 1053 } 1054 1055 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) { 1056 DCHECK(object->HasFastSmiOrObjectElements() || 1057 object->HasFastStringWrapperElements()); 1058 FixedArray* raw_elems = FixedArray::cast(object->elements()); 1059 Heap* heap = object->GetHeap(); 1060 if (raw_elems->map() != heap->fixed_cow_array_map()) return; 1061 Isolate* isolate = heap->isolate(); 1062 Handle<FixedArray> elems(raw_elems, isolate); 1063 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap( 1064 elems, isolate->factory()->fixed_array_map()); 1065 object->set_elements(*writable_elems); 1066 isolate->counters()->cow_arrays_converted()->Increment(); 1067 } 1068 1069 1070 // ES6 9.5.1 1071 // static 1072 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) { 1073 Isolate* isolate = proxy->GetIsolate(); 1074 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string(); 1075 1076 STACK_CHECK(isolate, MaybeHandle<Object>()); 1077 1078 // 1. Let handler be the value of the [[ProxyHandler]] internal slot. 1079 // 2. If handler is null, throw a TypeError exception. 1080 // 3. Assert: Type(handler) is Object. 1081 // 4. Let target be the value of the [[ProxyTarget]] internal slot. 1082 if (proxy->IsRevoked()) { 1083 THROW_NEW_ERROR(isolate, 1084 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1085 Object); 1086 } 1087 Handle<JSReceiver> target(proxy->target(), isolate); 1088 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 1089 1090 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). 1091 Handle<Object> trap; 1092 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name), 1093 Object); 1094 // 6. If trap is undefined, then return target.[[GetPrototypeOf]](). 1095 if (trap->IsUndefined(isolate)) { 1096 return JSReceiver::GetPrototype(isolate, target); 1097 } 1098 // 7. Let handlerProto be ? Call(trap, handler, target). 1099 Handle<Object> argv[] = {target}; 1100 Handle<Object> handler_proto; 1101 ASSIGN_RETURN_ON_EXCEPTION( 1102 isolate, handler_proto, 1103 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object); 1104 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError. 1105 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) { 1106 THROW_NEW_ERROR(isolate, 1107 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid), 1108 Object); 1109 } 1110 // 9. Let extensibleTarget be ? IsExtensible(target). 1111 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 1112 MAYBE_RETURN_NULL(is_extensible); 1113 // 10. If extensibleTarget is true, return handlerProto. 1114 if (is_extensible.FromJust()) return handler_proto; 1115 // 11. Let targetProto be ? target.[[GetPrototypeOf]](). 1116 Handle<Object> target_proto; 1117 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto, 1118 JSReceiver::GetPrototype(isolate, target), Object); 1119 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError. 1120 if (!handler_proto->SameValue(*target_proto)) { 1121 THROW_NEW_ERROR( 1122 isolate, 1123 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible), 1124 Object); 1125 } 1126 // 13. Return handlerProto. 1127 return handler_proto; 1128 } 1129 1130 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) { 1131 Isolate* isolate = it->isolate(); 1132 Handle<Object> structure = it->GetAccessors(); 1133 Handle<Object> receiver = it->GetReceiver(); 1134 1135 // We should never get here to initialize a const with the hole value since a 1136 // const declaration would conflict with the getter. 1137 DCHECK(!structure->IsForeign()); 1138 1139 // API style callbacks. 1140 if (structure->IsAccessorInfo()) { 1141 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1142 Handle<Name> name = it->GetName(); 1143 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1144 if (!info->IsCompatibleReceiver(*receiver)) { 1145 THROW_NEW_ERROR(isolate, 1146 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, 1147 name, receiver), 1148 Object); 1149 } 1150 1151 v8::AccessorNameGetterCallback call_fun = 1152 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter()); 1153 if (call_fun == nullptr) return isolate->factory()->undefined_value(); 1154 1155 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1156 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver, 1157 Object::ConvertReceiver(isolate, receiver), 1158 Object); 1159 } 1160 1161 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1162 Object::DONT_THROW); 1163 Handle<Object> result = args.Call(call_fun, name); 1164 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1165 if (result.is_null()) return ReadAbsentProperty(isolate, receiver, name); 1166 // Rebox handle before return. 1167 return handle(*result, isolate); 1168 } 1169 1170 // Regular accessor. 1171 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate); 1172 if (getter->IsFunctionTemplateInfo()) { 1173 return Builtins::InvokeApiFunction( 1174 isolate, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, 1175 nullptr); 1176 } else if (getter->IsCallable()) { 1177 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1178 return Object::GetPropertyWithDefinedGetter( 1179 receiver, Handle<JSReceiver>::cast(getter)); 1180 } 1181 // Getter is not a function. 1182 return ReadAbsentProperty(isolate, receiver, it->GetName()); 1183 } 1184 1185 // static 1186 Address AccessorInfo::redirect(Isolate* isolate, Address address, 1187 AccessorComponent component) { 1188 ApiFunction fun(address); 1189 DCHECK_EQ(ACCESSOR_GETTER, component); 1190 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; 1191 return ExternalReference(&fun, type, isolate).address(); 1192 } 1193 1194 Address AccessorInfo::redirected_getter() const { 1195 Address accessor = v8::ToCData<Address>(getter()); 1196 if (accessor == nullptr) return nullptr; 1197 return redirect(GetIsolate(), accessor, ACCESSOR_GETTER); 1198 } 1199 1200 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate, 1201 Handle<AccessorInfo> info, 1202 Handle<Map> map) { 1203 if (!info->HasExpectedReceiverType()) return true; 1204 if (!map->IsJSObjectMap()) return false; 1205 return FunctionTemplateInfo::cast(info->expected_receiver_type()) 1206 ->IsTemplateFor(*map); 1207 } 1208 1209 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it, 1210 Handle<Object> value, 1211 ShouldThrow should_throw) { 1212 Isolate* isolate = it->isolate(); 1213 Handle<Object> structure = it->GetAccessors(); 1214 Handle<Object> receiver = it->GetReceiver(); 1215 1216 // We should never get here to initialize a const with the hole value since a 1217 // const declaration would conflict with the setter. 1218 DCHECK(!structure->IsForeign()); 1219 1220 // API style callbacks. 1221 if (structure->IsAccessorInfo()) { 1222 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1223 Handle<Name> name = it->GetName(); 1224 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1225 if (!info->IsCompatibleReceiver(*receiver)) { 1226 isolate->Throw(*isolate->factory()->NewTypeError( 1227 MessageTemplate::kIncompatibleMethodReceiver, name, receiver)); 1228 return Nothing<bool>(); 1229 } 1230 1231 v8::AccessorNameSetterCallback call_fun = 1232 v8::ToCData<v8::AccessorNameSetterCallback>(info->setter()); 1233 // TODO(verwaest): We should not get here anymore once all AccessorInfos are 1234 // marked as special_data_property. They cannot both be writable and not 1235 // have a setter. 1236 if (call_fun == nullptr) return Just(true); 1237 1238 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1239 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1240 isolate, receiver, Object::ConvertReceiver(isolate, receiver), 1241 Nothing<bool>()); 1242 } 1243 1244 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1245 should_throw); 1246 args.Call(call_fun, name, value); 1247 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1248 return Just(true); 1249 } 1250 1251 // Regular accessor. 1252 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); 1253 if (setter->IsFunctionTemplateInfo()) { 1254 Handle<Object> argv[] = {value}; 1255 RETURN_ON_EXCEPTION_VALUE( 1256 isolate, Builtins::InvokeApiFunction( 1257 isolate, Handle<FunctionTemplateInfo>::cast(setter), 1258 receiver, arraysize(argv), argv), 1259 Nothing<bool>()); 1260 return Just(true); 1261 } else if (setter->IsCallable()) { 1262 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1263 return SetPropertyWithDefinedSetter( 1264 receiver, Handle<JSReceiver>::cast(setter), value, should_throw); 1265 } 1266 1267 RETURN_FAILURE(isolate, should_throw, 1268 NewTypeError(MessageTemplate::kNoSetterInCallback, 1269 it->GetName(), it->GetHolder<JSObject>())); 1270 } 1271 1272 1273 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter( 1274 Handle<Object> receiver, 1275 Handle<JSReceiver> getter) { 1276 Isolate* isolate = getter->GetIsolate(); 1277 1278 // Platforms with simulators like arm/arm64 expose a funny issue. If the 1279 // simulator has a separate JS stack pointer from the C++ stack pointer, it 1280 // can miss C++ stack overflows in the stack guard at the start of JavaScript 1281 // functions. It would be very expensive to check the C++ stack pointer at 1282 // that location. The best solution seems to be to break the impasse by 1283 // adding checks at possible recursion points. What's more, we don't put 1284 // this stack check behind the USE_SIMULATOR define in order to keep 1285 // behavior the same between hardware and simulators. 1286 StackLimitCheck check(isolate); 1287 if (check.JsHasOverflowed()) { 1288 isolate->StackOverflow(); 1289 return MaybeHandle<Object>(); 1290 } 1291 1292 return Execution::Call(isolate, getter, receiver, 0, NULL); 1293 } 1294 1295 1296 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver, 1297 Handle<JSReceiver> setter, 1298 Handle<Object> value, 1299 ShouldThrow should_throw) { 1300 Isolate* isolate = setter->GetIsolate(); 1301 1302 Handle<Object> argv[] = { value }; 1303 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver, 1304 arraysize(argv), argv), 1305 Nothing<bool>()); 1306 return Just(true); 1307 } 1308 1309 1310 // static 1311 bool JSObject::AllCanRead(LookupIterator* it) { 1312 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of 1313 // which have already been checked. 1314 DCHECK(it->state() == LookupIterator::ACCESS_CHECK || 1315 it->state() == LookupIterator::INTERCEPTOR); 1316 for (it->Next(); it->IsFound(); it->Next()) { 1317 if (it->state() == LookupIterator::ACCESSOR) { 1318 auto accessors = it->GetAccessors(); 1319 if (accessors->IsAccessorInfo()) { 1320 if (AccessorInfo::cast(*accessors)->all_can_read()) return true; 1321 } 1322 } else if (it->state() == LookupIterator::INTERCEPTOR) { 1323 if (it->GetInterceptor()->all_can_read()) return true; 1324 } else if (it->state() == LookupIterator::JSPROXY) { 1325 // Stop lookupiterating. And no, AllCanNotRead. 1326 return false; 1327 } 1328 } 1329 return false; 1330 } 1331 1332 namespace { 1333 1334 MaybeHandle<Object> GetPropertyWithInterceptorInternal( 1335 LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) { 1336 *done = false; 1337 Isolate* isolate = it->isolate(); 1338 // Make sure that the top context does not change when doing callbacks or 1339 // interceptor calls. 1340 AssertNoContextChange ncc(isolate); 1341 1342 if (interceptor->getter()->IsUndefined(isolate)) { 1343 return isolate->factory()->undefined_value(); 1344 } 1345 1346 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1347 Handle<Object> result; 1348 Handle<Object> receiver = it->GetReceiver(); 1349 if (!receiver->IsJSReceiver()) { 1350 ASSIGN_RETURN_ON_EXCEPTION( 1351 isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object); 1352 } 1353 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1354 *holder, Object::DONT_THROW); 1355 1356 if (it->IsElement()) { 1357 uint32_t index = it->index(); 1358 v8::IndexedPropertyGetterCallback getter = 1359 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); 1360 result = args.Call(getter, index); 1361 } else { 1362 Handle<Name> name = it->name(); 1363 DCHECK(!name->IsPrivate()); 1364 1365 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { 1366 return isolate->factory()->undefined_value(); 1367 } 1368 1369 v8::GenericNamedPropertyGetterCallback getter = 1370 v8::ToCData<v8::GenericNamedPropertyGetterCallback>( 1371 interceptor->getter()); 1372 result = args.Call(getter, name); 1373 } 1374 1375 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1376 if (result.is_null()) return isolate->factory()->undefined_value(); 1377 *done = true; 1378 // Rebox handle before return 1379 return handle(*result, isolate); 1380 } 1381 1382 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal( 1383 LookupIterator* it, Handle<InterceptorInfo> interceptor) { 1384 Isolate* isolate = it->isolate(); 1385 // Make sure that the top context does not change when doing 1386 // callbacks or interceptor calls. 1387 AssertNoContextChange ncc(isolate); 1388 HandleScope scope(isolate); 1389 1390 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1391 if (!it->IsElement() && it->name()->IsSymbol() && 1392 !interceptor->can_intercept_symbols()) { 1393 return Just(ABSENT); 1394 } 1395 Handle<Object> receiver = it->GetReceiver(); 1396 if (!receiver->IsJSReceiver()) { 1397 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1398 Object::ConvertReceiver(isolate, receiver), 1399 Nothing<PropertyAttributes>()); 1400 } 1401 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1402 *holder, Object::DONT_THROW); 1403 if (!interceptor->query()->IsUndefined(isolate)) { 1404 Handle<Object> result; 1405 if (it->IsElement()) { 1406 uint32_t index = it->index(); 1407 v8::IndexedPropertyQueryCallback query = 1408 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query()); 1409 result = args.Call(query, index); 1410 } else { 1411 Handle<Name> name = it->name(); 1412 DCHECK(!name->IsPrivate()); 1413 v8::GenericNamedPropertyQueryCallback query = 1414 v8::ToCData<v8::GenericNamedPropertyQueryCallback>( 1415 interceptor->query()); 1416 result = args.Call(query, name); 1417 } 1418 if (!result.is_null()) { 1419 int32_t value; 1420 CHECK(result->ToInt32(&value)); 1421 return Just(static_cast<PropertyAttributes>(value)); 1422 } 1423 } else if (!interceptor->getter()->IsUndefined(isolate)) { 1424 // TODO(verwaest): Use GetPropertyWithInterceptor? 1425 Handle<Object> result; 1426 if (it->IsElement()) { 1427 uint32_t index = it->index(); 1428 v8::IndexedPropertyGetterCallback getter = 1429 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); 1430 result = args.Call(getter, index); 1431 } else { 1432 Handle<Name> name = it->name(); 1433 DCHECK(!name->IsPrivate()); 1434 v8::GenericNamedPropertyGetterCallback getter = 1435 v8::ToCData<v8::GenericNamedPropertyGetterCallback>( 1436 interceptor->getter()); 1437 result = args.Call(getter, name); 1438 } 1439 if (!result.is_null()) return Just(DONT_ENUM); 1440 } 1441 1442 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1443 return Just(ABSENT); 1444 } 1445 1446 Maybe<bool> SetPropertyWithInterceptorInternal( 1447 LookupIterator* it, Handle<InterceptorInfo> interceptor, 1448 Object::ShouldThrow should_throw, Handle<Object> value) { 1449 Isolate* isolate = it->isolate(); 1450 // Make sure that the top context does not change when doing callbacks or 1451 // interceptor calls. 1452 AssertNoContextChange ncc(isolate); 1453 1454 if (interceptor->setter()->IsUndefined(isolate)) return Just(false); 1455 1456 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1457 bool result; 1458 Handle<Object> receiver = it->GetReceiver(); 1459 if (!receiver->IsJSReceiver()) { 1460 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1461 Object::ConvertReceiver(isolate, receiver), 1462 Nothing<bool>()); 1463 } 1464 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1465 *holder, should_throw); 1466 1467 if (it->IsElement()) { 1468 uint32_t index = it->index(); 1469 v8::IndexedPropertySetterCallback setter = 1470 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter()); 1471 // TODO(neis): In the future, we may want to actually return the 1472 // interceptor's result, which then should be a boolean. 1473 result = !args.Call(setter, index, value).is_null(); 1474 } else { 1475 Handle<Name> name = it->name(); 1476 DCHECK(!name->IsPrivate()); 1477 1478 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { 1479 return Just(false); 1480 } 1481 1482 v8::GenericNamedPropertySetterCallback setter = 1483 v8::ToCData<v8::GenericNamedPropertySetterCallback>( 1484 interceptor->setter()); 1485 result = !args.Call(setter, name, value).is_null(); 1486 } 1487 1488 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 1489 return Just(result); 1490 } 1491 1492 } // namespace 1493 1494 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( 1495 LookupIterator* it) { 1496 Isolate* isolate = it->isolate(); 1497 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1498 Handle<InterceptorInfo> interceptor = 1499 it->GetInterceptorForFailedAccessCheck(); 1500 if (interceptor.is_null()) { 1501 while (AllCanRead(it)) { 1502 if (it->state() == LookupIterator::ACCESSOR) { 1503 return GetPropertyWithAccessor(it); 1504 } 1505 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 1506 bool done; 1507 Handle<Object> result; 1508 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 1509 GetPropertyWithInterceptor(it, &done), Object); 1510 if (done) return result; 1511 } 1512 } else { 1513 MaybeHandle<Object> result; 1514 bool done; 1515 result = GetPropertyWithInterceptorInternal(it, interceptor, &done); 1516 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1517 if (done) return result; 1518 } 1519 1520 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns 1521 // undefined. 1522 Handle<Name> name = it->GetName(); 1523 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) { 1524 return it->factory()->undefined_value(); 1525 } 1526 1527 isolate->ReportFailedAccessCheck(checked); 1528 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1529 return it->factory()->undefined_value(); 1530 } 1531 1532 1533 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck( 1534 LookupIterator* it) { 1535 Isolate* isolate = it->isolate(); 1536 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1537 Handle<InterceptorInfo> interceptor = 1538 it->GetInterceptorForFailedAccessCheck(); 1539 if (interceptor.is_null()) { 1540 while (AllCanRead(it)) { 1541 if (it->state() == LookupIterator::ACCESSOR) { 1542 return Just(it->property_attributes()); 1543 } 1544 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 1545 auto result = GetPropertyAttributesWithInterceptor(it); 1546 if (isolate->has_scheduled_exception()) break; 1547 if (result.IsJust() && result.FromJust() != ABSENT) return result; 1548 } 1549 } else { 1550 Maybe<PropertyAttributes> result = 1551 GetPropertyAttributesWithInterceptorInternal(it, interceptor); 1552 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1553 if (result.FromMaybe(ABSENT) != ABSENT) return result; 1554 } 1555 isolate->ReportFailedAccessCheck(checked); 1556 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1557 return Just(ABSENT); 1558 } 1559 1560 1561 // static 1562 bool JSObject::AllCanWrite(LookupIterator* it) { 1563 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) { 1564 if (it->state() == LookupIterator::ACCESSOR) { 1565 Handle<Object> accessors = it->GetAccessors(); 1566 if (accessors->IsAccessorInfo()) { 1567 if (AccessorInfo::cast(*accessors)->all_can_write()) return true; 1568 } 1569 } 1570 } 1571 return false; 1572 } 1573 1574 1575 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck( 1576 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) { 1577 Isolate* isolate = it->isolate(); 1578 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1579 Handle<InterceptorInfo> interceptor = 1580 it->GetInterceptorForFailedAccessCheck(); 1581 if (interceptor.is_null()) { 1582 if (AllCanWrite(it)) { 1583 return SetPropertyWithAccessor(it, value, should_throw); 1584 } 1585 } else { 1586 Maybe<bool> result = SetPropertyWithInterceptorInternal( 1587 it, interceptor, should_throw, value); 1588 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1589 if (result.IsJust()) return result; 1590 } 1591 1592 isolate->ReportFailedAccessCheck(checked); 1593 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1594 return Just(true); 1595 } 1596 1597 1598 void JSObject::SetNormalizedProperty(Handle<JSObject> object, 1599 Handle<Name> name, 1600 Handle<Object> value, 1601 PropertyDetails details) { 1602 DCHECK(!object->HasFastProperties()); 1603 if (!name->IsUniqueName()) { 1604 name = object->GetIsolate()->factory()->InternalizeString( 1605 Handle<String>::cast(name)); 1606 } 1607 1608 if (object->IsJSGlobalObject()) { 1609 Handle<GlobalDictionary> property_dictionary(object->global_dictionary()); 1610 1611 int entry = property_dictionary->FindEntry(name); 1612 if (entry == GlobalDictionary::kNotFound) { 1613 Isolate* isolate = object->GetIsolate(); 1614 auto cell = isolate->factory()->NewPropertyCell(); 1615 cell->set_value(*value); 1616 auto cell_type = value->IsUndefined(isolate) 1617 ? PropertyCellType::kUndefined 1618 : PropertyCellType::kConstant; 1619 details = details.set_cell_type(cell_type); 1620 value = cell; 1621 property_dictionary = 1622 GlobalDictionary::Add(property_dictionary, name, value, details); 1623 object->set_properties(*property_dictionary); 1624 } else { 1625 PropertyCell::UpdateCell(property_dictionary, entry, value, details); 1626 } 1627 } else { 1628 Handle<NameDictionary> property_dictionary(object->property_dictionary()); 1629 1630 int entry = property_dictionary->FindEntry(name); 1631 if (entry == NameDictionary::kNotFound) { 1632 property_dictionary = 1633 NameDictionary::Add(property_dictionary, name, value, details); 1634 object->set_properties(*property_dictionary); 1635 } else { 1636 PropertyDetails original_details = property_dictionary->DetailsAt(entry); 1637 int enumeration_index = original_details.dictionary_index(); 1638 DCHECK(enumeration_index > 0); 1639 details = details.set_index(enumeration_index); 1640 property_dictionary->SetEntry(entry, name, value, details); 1641 } 1642 } 1643 } 1644 1645 // static 1646 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate, 1647 Handle<JSReceiver> object, 1648 Handle<Object> proto) { 1649 PrototypeIterator iter(isolate, object, kStartAtReceiver); 1650 while (true) { 1651 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); 1652 if (iter.IsAtEnd()) return Just(false); 1653 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { 1654 return Just(true); 1655 } 1656 } 1657 } 1658 1659 Map* Object::GetRootMap(Isolate* isolate) { 1660 DisallowHeapAllocation no_alloc; 1661 if (IsSmi()) { 1662 Context* native_context = isolate->context()->native_context(); 1663 return native_context->number_function()->initial_map(); 1664 } 1665 1666 // The object is either a number, a string, a symbol, a boolean, a SIMD value, 1667 // a real JS object, or a Harmony proxy. 1668 HeapObject* heap_object = HeapObject::cast(this); 1669 if (heap_object->IsJSReceiver()) { 1670 return heap_object->map(); 1671 } 1672 int constructor_function_index = 1673 heap_object->map()->GetConstructorFunctionIndex(); 1674 if (constructor_function_index != Map::kNoConstructorFunctionIndex) { 1675 Context* native_context = isolate->context()->native_context(); 1676 JSFunction* constructor_function = 1677 JSFunction::cast(native_context->get(constructor_function_index)); 1678 return constructor_function->initial_map(); 1679 } 1680 return isolate->heap()->null_value()->map(); 1681 } 1682 1683 namespace { 1684 1685 // Returns a non-SMI for JSObjects, but returns the hash code for simple 1686 // objects. This avoids a double lookup in the cases where we know we will 1687 // add the hash to the JSObject if it does not already exist. 1688 Object* GetSimpleHash(Object* object) { 1689 // The object is either a Smi, a HeapNumber, a name, an odd-ball, 1690 // a SIMD value type, a real JS object, or a Harmony proxy. 1691 if (object->IsSmi()) { 1692 uint32_t hash = 1693 ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed); 1694 return Smi::FromInt(hash & Smi::kMaxValue); 1695 } 1696 if (object->IsHeapNumber()) { 1697 double num = HeapNumber::cast(object)->value(); 1698 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue); 1699 if (i::IsMinusZero(num)) num = 0; 1700 if (IsSmiDouble(num)) { 1701 return Smi::FromInt(FastD2I(num))->GetHash(); 1702 } 1703 uint32_t hash = ComputeLongHash(double_to_uint64(num)); 1704 return Smi::FromInt(hash & Smi::kMaxValue); 1705 } 1706 if (object->IsName()) { 1707 uint32_t hash = Name::cast(object)->Hash(); 1708 return Smi::FromInt(hash); 1709 } 1710 if (object->IsOddball()) { 1711 uint32_t hash = Oddball::cast(object)->to_string()->Hash(); 1712 return Smi::FromInt(hash); 1713 } 1714 if (object->IsSimd128Value()) { 1715 uint32_t hash = Simd128Value::cast(object)->Hash(); 1716 return Smi::FromInt(hash & Smi::kMaxValue); 1717 } 1718 DCHECK(object->IsJSReceiver()); 1719 // Simply return the receiver as it is guaranteed to not be a SMI. 1720 return object; 1721 } 1722 1723 } // namespace 1724 1725 Object* Object::GetHash() { 1726 Object* hash = GetSimpleHash(this); 1727 if (hash->IsSmi()) return hash; 1728 1729 DisallowHeapAllocation no_gc; 1730 DCHECK(IsJSReceiver()); 1731 JSReceiver* receiver = JSReceiver::cast(this); 1732 Isolate* isolate = receiver->GetIsolate(); 1733 return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate)); 1734 } 1735 1736 Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) { 1737 Object* hash = GetSimpleHash(*object); 1738 if (hash->IsSmi()) return Smi::cast(hash); 1739 1740 DCHECK(object->IsJSReceiver()); 1741 return JSReceiver::GetOrCreateIdentityHash(isolate, 1742 Handle<JSReceiver>::cast(object)); 1743 } 1744 1745 1746 bool Object::SameValue(Object* other) { 1747 if (other == this) return true; 1748 1749 // The object is either a number, a name, an odd-ball, 1750 // a real JS object, or a Harmony proxy. 1751 if (IsNumber() && other->IsNumber()) { 1752 double this_value = Number(); 1753 double other_value = other->Number(); 1754 // SameValue(NaN, NaN) is true. 1755 if (this_value != other_value) { 1756 return std::isnan(this_value) && std::isnan(other_value); 1757 } 1758 // SameValue(0.0, -0.0) is false. 1759 return (std::signbit(this_value) == std::signbit(other_value)); 1760 } 1761 if (IsString() && other->IsString()) { 1762 return String::cast(this)->Equals(String::cast(other)); 1763 } 1764 if (IsFloat32x4() && other->IsFloat32x4()) { 1765 Float32x4* a = Float32x4::cast(this); 1766 Float32x4* b = Float32x4::cast(other); 1767 for (int i = 0; i < 4; i++) { 1768 float x = a->get_lane(i); 1769 float y = b->get_lane(i); 1770 // Implements the ES5 SameValue operation for floating point types. 1771 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue 1772 if (x != y && !(std::isnan(x) && std::isnan(y))) return false; 1773 if (std::signbit(x) != std::signbit(y)) return false; 1774 } 1775 return true; 1776 } else if (IsSimd128Value() && other->IsSimd128Value()) { 1777 Simd128Value* a = Simd128Value::cast(this); 1778 Simd128Value* b = Simd128Value::cast(other); 1779 return a->map() == b->map() && a->BitwiseEquals(b); 1780 } 1781 return false; 1782 } 1783 1784 1785 bool Object::SameValueZero(Object* other) { 1786 if (other == this) return true; 1787 1788 // The object is either a number, a name, an odd-ball, 1789 // a real JS object, or a Harmony proxy. 1790 if (IsNumber() && other->IsNumber()) { 1791 double this_value = Number(); 1792 double other_value = other->Number(); 1793 // +0 == -0 is true 1794 return this_value == other_value || 1795 (std::isnan(this_value) && std::isnan(other_value)); 1796 } 1797 if (IsString() && other->IsString()) { 1798 return String::cast(this)->Equals(String::cast(other)); 1799 } 1800 if (IsFloat32x4() && other->IsFloat32x4()) { 1801 Float32x4* a = Float32x4::cast(this); 1802 Float32x4* b = Float32x4::cast(other); 1803 for (int i = 0; i < 4; i++) { 1804 float x = a->get_lane(i); 1805 float y = b->get_lane(i); 1806 // Implements the ES6 SameValueZero operation for floating point types. 1807 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero 1808 if (x != y && !(std::isnan(x) && std::isnan(y))) return false; 1809 // SameValueZero doesn't distinguish between 0 and -0. 1810 } 1811 return true; 1812 } else if (IsSimd128Value() && other->IsSimd128Value()) { 1813 Simd128Value* a = Simd128Value::cast(this); 1814 Simd128Value* b = Simd128Value::cast(other); 1815 return a->map() == b->map() && a->BitwiseEquals(b); 1816 } 1817 return false; 1818 } 1819 1820 1821 MaybeHandle<Object> Object::ArraySpeciesConstructor( 1822 Isolate* isolate, Handle<Object> original_array) { 1823 Handle<Object> default_species = isolate->array_function(); 1824 if (original_array->IsJSArray() && 1825 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) && 1826 isolate->IsArraySpeciesLookupChainIntact()) { 1827 return default_species; 1828 } 1829 Handle<Object> constructor = isolate->factory()->undefined_value(); 1830 Maybe<bool> is_array = Object::IsArray(original_array); 1831 MAYBE_RETURN_NULL(is_array); 1832 if (is_array.FromJust()) { 1833 ASSIGN_RETURN_ON_EXCEPTION( 1834 isolate, constructor, 1835 Object::GetProperty(original_array, 1836 isolate->factory()->constructor_string()), 1837 Object); 1838 if (constructor->IsConstructor()) { 1839 Handle<Context> constructor_context; 1840 ASSIGN_RETURN_ON_EXCEPTION( 1841 isolate, constructor_context, 1842 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)), 1843 Object); 1844 if (*constructor_context != *isolate->native_context() && 1845 *constructor == constructor_context->array_function()) { 1846 constructor = isolate->factory()->undefined_value(); 1847 } 1848 } 1849 if (constructor->IsJSReceiver()) { 1850 ASSIGN_RETURN_ON_EXCEPTION( 1851 isolate, constructor, 1852 JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor), 1853 isolate->factory()->species_symbol()), 1854 Object); 1855 if (constructor->IsNull(isolate)) { 1856 constructor = isolate->factory()->undefined_value(); 1857 } 1858 } 1859 } 1860 if (constructor->IsUndefined(isolate)) { 1861 return default_species; 1862 } else { 1863 if (!constructor->IsConstructor()) { 1864 THROW_NEW_ERROR(isolate, 1865 NewTypeError(MessageTemplate::kSpeciesNotConstructor), 1866 Object); 1867 } 1868 return constructor; 1869 } 1870 } 1871 1872 1873 void Object::ShortPrint(FILE* out) { 1874 OFStream os(out); 1875 os << Brief(this); 1876 } 1877 1878 1879 void Object::ShortPrint(StringStream* accumulator) { 1880 std::ostringstream os; 1881 os << Brief(this); 1882 accumulator->Add(os.str().c_str()); 1883 } 1884 1885 1886 void Object::ShortPrint(std::ostream& os) { os << Brief(this); } 1887 1888 1889 std::ostream& operator<<(std::ostream& os, const Brief& v) { 1890 if (v.value->IsSmi()) { 1891 Smi::cast(v.value)->SmiPrint(os); 1892 } else { 1893 // TODO(svenpanne) Const-correct HeapObjectShortPrint! 1894 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value)); 1895 obj->HeapObjectShortPrint(os); 1896 } 1897 return os; 1898 } 1899 1900 1901 void Smi::SmiPrint(std::ostream& os) const { // NOLINT 1902 os << value(); 1903 } 1904 1905 1906 // Should a word be prefixed by 'a' or 'an' in order to read naturally in 1907 // English? Returns false for non-ASCII or words that don't start with 1908 // a capital letter. The a/an rule follows pronunciation in English. 1909 // We don't use the BBC's overcorrect "an historic occasion" though if 1910 // you speak a dialect you may well say "an 'istoric occasion". 1911 static bool AnWord(String* str) { 1912 if (str->length() == 0) return false; // A nothing. 1913 int c0 = str->Get(0); 1914 int c1 = str->length() > 1 ? str->Get(1) : 0; 1915 if (c0 == 'U') { 1916 if (c1 > 'Z') { 1917 return true; // An Umpire, but a UTF8String, a U. 1918 } 1919 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { 1920 return true; // An Ape, an ABCBook. 1921 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && 1922 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || 1923 c0 == 'S' || c0 == 'X')) { 1924 return true; // An MP3File, an M. 1925 } 1926 return false; 1927 } 1928 1929 1930 Handle<String> String::SlowFlatten(Handle<ConsString> cons, 1931 PretenureFlag pretenure) { 1932 DCHECK(AllowHeapAllocation::IsAllowed()); 1933 DCHECK(cons->second()->length() != 0); 1934 Isolate* isolate = cons->GetIsolate(); 1935 int length = cons->length(); 1936 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure 1937 : TENURED; 1938 Handle<SeqString> result; 1939 if (cons->IsOneByteRepresentation()) { 1940 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString( 1941 length, tenure).ToHandleChecked(); 1942 DisallowHeapAllocation no_gc; 1943 WriteToFlat(*cons, flat->GetChars(), 0, length); 1944 result = flat; 1945 } else { 1946 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString( 1947 length, tenure).ToHandleChecked(); 1948 DisallowHeapAllocation no_gc; 1949 WriteToFlat(*cons, flat->GetChars(), 0, length); 1950 result = flat; 1951 } 1952 cons->set_first(*result); 1953 cons->set_second(isolate->heap()->empty_string()); 1954 DCHECK(result->IsFlat()); 1955 return result; 1956 } 1957 1958 1959 1960 bool String::MakeExternal(v8::String::ExternalStringResource* resource) { 1961 // Externalizing twice leaks the external resource, so it's 1962 // prohibited by the API. 1963 DCHECK(!this->IsExternalString()); 1964 DCHECK(!resource->IsCompressible()); 1965 #ifdef ENABLE_SLOW_DCHECKS 1966 if (FLAG_enable_slow_asserts) { 1967 // Assert that the resource and the string are equivalent. 1968 DCHECK(static_cast<size_t>(this->length()) == resource->length()); 1969 ScopedVector<uc16> smart_chars(this->length()); 1970 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 1971 DCHECK(memcmp(smart_chars.start(), 1972 resource->data(), 1973 resource->length() * sizeof(smart_chars[0])) == 0); 1974 } 1975 #endif // DEBUG 1976 int size = this->Size(); // Byte size of the original string. 1977 // Abort if size does not allow in-place conversion. 1978 if (size < ExternalString::kShortSize) return false; 1979 Heap* heap = GetHeap(); 1980 bool is_one_byte = this->IsOneByteRepresentation(); 1981 bool is_internalized = this->IsInternalizedString(); 1982 1983 // Morph the string to an external string by replacing the map and 1984 // reinitializing the fields. This won't work if the space the existing 1985 // string occupies is too small for a regular external string. 1986 // Instead, we resort to a short external string instead, omitting 1987 // the field caching the address of the backing store. When we encounter 1988 // short external strings in generated code, we need to bailout to runtime. 1989 Map* new_map; 1990 if (size < ExternalString::kSize) { 1991 new_map = is_internalized 1992 ? (is_one_byte 1993 ? heap->short_external_internalized_string_with_one_byte_data_map() 1994 : heap->short_external_internalized_string_map()) 1995 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map() 1996 : heap->short_external_string_map()); 1997 } else { 1998 new_map = is_internalized 1999 ? (is_one_byte 2000 ? heap->external_internalized_string_with_one_byte_data_map() 2001 : heap->external_internalized_string_map()) 2002 : (is_one_byte ? heap->external_string_with_one_byte_data_map() 2003 : heap->external_string_map()); 2004 } 2005 2006 // Byte size of the external String object. 2007 int new_size = this->SizeFromMap(new_map); 2008 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, 2009 ClearRecordedSlots::kNo); 2010 2011 // We are storing the new map using release store after creating a filler for 2012 // the left-over space to avoid races with the sweeper thread. 2013 this->synchronized_set_map(new_map); 2014 2015 ExternalTwoByteString* self = ExternalTwoByteString::cast(this); 2016 self->set_resource(resource); 2017 if (is_internalized) self->Hash(); // Force regeneration of the hash value. 2018 2019 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER); 2020 return true; 2021 } 2022 2023 2024 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) { 2025 // Externalizing twice leaks the external resource, so it's 2026 // prohibited by the API. 2027 DCHECK(!this->IsExternalString()); 2028 DCHECK(!resource->IsCompressible()); 2029 #ifdef ENABLE_SLOW_DCHECKS 2030 if (FLAG_enable_slow_asserts) { 2031 // Assert that the resource and the string are equivalent. 2032 DCHECK(static_cast<size_t>(this->length()) == resource->length()); 2033 if (this->IsTwoByteRepresentation()) { 2034 ScopedVector<uint16_t> smart_chars(this->length()); 2035 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2036 DCHECK(String::IsOneByte(smart_chars.start(), this->length())); 2037 } 2038 ScopedVector<char> smart_chars(this->length()); 2039 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2040 DCHECK(memcmp(smart_chars.start(), 2041 resource->data(), 2042 resource->length() * sizeof(smart_chars[0])) == 0); 2043 } 2044 #endif // DEBUG 2045 int size = this->Size(); // Byte size of the original string. 2046 // Abort if size does not allow in-place conversion. 2047 if (size < ExternalString::kShortSize) return false; 2048 Heap* heap = GetHeap(); 2049 bool is_internalized = this->IsInternalizedString(); 2050 2051 // Morph the string to an external string by replacing the map and 2052 // reinitializing the fields. This won't work if the space the existing 2053 // string occupies is too small for a regular external string. 2054 // Instead, we resort to a short external string instead, omitting 2055 // the field caching the address of the backing store. When we encounter 2056 // short external strings in generated code, we need to bailout to runtime. 2057 Map* new_map; 2058 if (size < ExternalString::kSize) { 2059 new_map = is_internalized 2060 ? heap->short_external_one_byte_internalized_string_map() 2061 : heap->short_external_one_byte_string_map(); 2062 } else { 2063 new_map = is_internalized 2064 ? heap->external_one_byte_internalized_string_map() 2065 : heap->external_one_byte_string_map(); 2066 } 2067 2068 // Byte size of the external String object. 2069 int new_size = this->SizeFromMap(new_map); 2070 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, 2071 ClearRecordedSlots::kNo); 2072 2073 // We are storing the new map using release store after creating a filler for 2074 // the left-over space to avoid races with the sweeper thread. 2075 this->synchronized_set_map(new_map); 2076 2077 ExternalOneByteString* self = ExternalOneByteString::cast(this); 2078 self->set_resource(resource); 2079 if (is_internalized) self->Hash(); // Force regeneration of the hash value. 2080 2081 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER); 2082 return true; 2083 } 2084 2085 void String::StringShortPrint(StringStream* accumulator, bool show_details) { 2086 int len = length(); 2087 if (len > kMaxShortPrintLength) { 2088 accumulator->Add("<Very long string[%u]>", len); 2089 return; 2090 } 2091 2092 if (!LooksValid()) { 2093 accumulator->Add("<Invalid String>"); 2094 return; 2095 } 2096 2097 StringCharacterStream stream(this); 2098 2099 bool truncated = false; 2100 if (len > kMaxShortPrintLength) { 2101 len = kMaxShortPrintLength; 2102 truncated = true; 2103 } 2104 bool one_byte = true; 2105 for (int i = 0; i < len; i++) { 2106 uint16_t c = stream.GetNext(); 2107 2108 if (c < 32 || c >= 127) { 2109 one_byte = false; 2110 } 2111 } 2112 stream.Reset(this); 2113 if (one_byte) { 2114 if (show_details) accumulator->Add("<String[%u]: ", length()); 2115 for (int i = 0; i < len; i++) { 2116 accumulator->Put(static_cast<char>(stream.GetNext())); 2117 } 2118 if (show_details) accumulator->Put('>'); 2119 } else { 2120 // Backslash indicates that the string contains control 2121 // characters and that backslashes are therefore escaped. 2122 if (show_details) accumulator->Add("<String[%u]\\: ", length()); 2123 for (int i = 0; i < len; i++) { 2124 uint16_t c = stream.GetNext(); 2125 if (c == '\n') { 2126 accumulator->Add("\\n"); 2127 } else if (c == '\r') { 2128 accumulator->Add("\\r"); 2129 } else if (c == '\\') { 2130 accumulator->Add("\\\\"); 2131 } else if (c < 32 || c > 126) { 2132 accumulator->Add("\\x%02x", c); 2133 } else { 2134 accumulator->Put(static_cast<char>(c)); 2135 } 2136 } 2137 if (truncated) { 2138 accumulator->Put('.'); 2139 accumulator->Put('.'); 2140 accumulator->Put('.'); 2141 } 2142 if (show_details) accumulator->Put('>'); 2143 } 2144 return; 2145 } 2146 2147 2148 void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT 2149 if (end < 0) end = length(); 2150 StringCharacterStream stream(this, start); 2151 for (int i = start; i < end && stream.HasMore(); i++) { 2152 os << AsUC16(stream.GetNext()); 2153 } 2154 } 2155 2156 2157 void JSObject::JSObjectShortPrint(StringStream* accumulator) { 2158 switch (map()->instance_type()) { 2159 case JS_ARRAY_TYPE: { 2160 double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate()) 2161 ? 0 2162 : JSArray::cast(this)->length()->Number(); 2163 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length)); 2164 break; 2165 } 2166 case JS_BOUND_FUNCTION_TYPE: { 2167 JSBoundFunction* bound_function = JSBoundFunction::cast(this); 2168 accumulator->Add("<JS BoundFunction"); 2169 accumulator->Add( 2170 " (BoundTargetFunction %p)>", 2171 reinterpret_cast<void*>(bound_function->bound_target_function())); 2172 break; 2173 } 2174 case JS_WEAK_MAP_TYPE: { 2175 accumulator->Add("<JS WeakMap>"); 2176 break; 2177 } 2178 case JS_WEAK_SET_TYPE: { 2179 accumulator->Add("<JS WeakSet>"); 2180 break; 2181 } 2182 case JS_REGEXP_TYPE: { 2183 accumulator->Add("<JS RegExp>"); 2184 break; 2185 } 2186 case JS_FUNCTION_TYPE: { 2187 JSFunction* function = JSFunction::cast(this); 2188 Object* fun_name = function->shared()->DebugName(); 2189 bool printed = false; 2190 if (fun_name->IsString()) { 2191 String* str = String::cast(fun_name); 2192 if (str->length() > 0) { 2193 accumulator->Add("<JS Function "); 2194 accumulator->Put(str); 2195 printed = true; 2196 } 2197 } 2198 if (!printed) { 2199 accumulator->Add("<JS Function"); 2200 } 2201 if (FLAG_trace_file_names) { 2202 Object* source_name = 2203 Script::cast(function->shared()->script())->name(); 2204 if (source_name->IsString()) { 2205 String* str = String::cast(source_name); 2206 if (str->length() > 0) { 2207 accumulator->Add(" <"); 2208 accumulator->Put(str); 2209 accumulator->Add(">"); 2210 } 2211 } 2212 } 2213 accumulator->Add(" (SharedFunctionInfo %p)", 2214 reinterpret_cast<void*>(function->shared())); 2215 accumulator->Put('>'); 2216 break; 2217 } 2218 case JS_GENERATOR_OBJECT_TYPE: { 2219 accumulator->Add("<JS Generator>"); 2220 break; 2221 } 2222 case JS_MODULE_TYPE: { 2223 accumulator->Add("<JS Module>"); 2224 break; 2225 } 2226 // All other JSObjects are rather similar to each other (JSObject, 2227 // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue). 2228 default: { 2229 Map* map_of_this = map(); 2230 Heap* heap = GetHeap(); 2231 Object* constructor = map_of_this->GetConstructor(); 2232 bool printed = false; 2233 if (constructor->IsHeapObject() && 2234 !heap->Contains(HeapObject::cast(constructor))) { 2235 accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); 2236 } else { 2237 bool global_object = IsJSGlobalProxy(); 2238 if (constructor->IsJSFunction()) { 2239 if (!heap->Contains(JSFunction::cast(constructor)->shared())) { 2240 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); 2241 } else { 2242 Object* constructor_name = 2243 JSFunction::cast(constructor)->shared()->name(); 2244 if (constructor_name->IsString()) { 2245 String* str = String::cast(constructor_name); 2246 if (str->length() > 0) { 2247 bool vowel = AnWord(str); 2248 accumulator->Add("<%sa%s ", 2249 global_object ? "Global Object: " : "", 2250 vowel ? "n" : ""); 2251 accumulator->Put(str); 2252 accumulator->Add(" with %smap %p", 2253 map_of_this->is_deprecated() ? "deprecated " : "", 2254 map_of_this); 2255 printed = true; 2256 } 2257 } 2258 } 2259 } 2260 if (!printed) { 2261 accumulator->Add("<JS %sObject", global_object ? "Global " : ""); 2262 } 2263 } 2264 if (IsJSValue()) { 2265 accumulator->Add(" value = "); 2266 JSValue::cast(this)->value()->ShortPrint(accumulator); 2267 } 2268 accumulator->Put('>'); 2269 break; 2270 } 2271 } 2272 } 2273 2274 2275 void JSObject::PrintElementsTransition( 2276 FILE* file, Handle<JSObject> object, 2277 ElementsKind from_kind, Handle<FixedArrayBase> from_elements, 2278 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) { 2279 if (from_kind != to_kind) { 2280 OFStream os(file); 2281 os << "elements transition [" << ElementsKindToString(from_kind) << " -> " 2282 << ElementsKindToString(to_kind) << "] in "; 2283 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true); 2284 PrintF(file, " for "); 2285 object->ShortPrint(file); 2286 PrintF(file, " from "); 2287 from_elements->ShortPrint(file); 2288 PrintF(file, " to "); 2289 to_elements->ShortPrint(file); 2290 PrintF(file, "\n"); 2291 } 2292 } 2293 2294 2295 // static 2296 MaybeHandle<JSFunction> Map::GetConstructorFunction( 2297 Handle<Map> map, Handle<Context> native_context) { 2298 if (map->IsPrimitiveMap()) { 2299 int const constructor_function_index = map->GetConstructorFunctionIndex(); 2300 if (constructor_function_index != kNoConstructorFunctionIndex) { 2301 return handle( 2302 JSFunction::cast(native_context->get(constructor_function_index))); 2303 } 2304 } 2305 return MaybeHandle<JSFunction>(); 2306 } 2307 2308 2309 void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind, 2310 PropertyAttributes attributes) { 2311 OFStream os(file); 2312 os << "[reconfiguring]"; 2313 Name* name = instance_descriptors()->GetKey(modify_index); 2314 if (name->IsString()) { 2315 String::cast(name)->PrintOn(file); 2316 } else { 2317 os << "{symbol " << static_cast<void*>(name) << "}"; 2318 } 2319 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: "; 2320 os << attributes << " ["; 2321 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true); 2322 os << "]\n"; 2323 } 2324 2325 void Map::PrintGeneralization( 2326 FILE* file, const char* reason, int modify_index, int split, 2327 int descriptors, bool constant_to_field, Representation old_representation, 2328 Representation new_representation, MaybeHandle<FieldType> old_field_type, 2329 MaybeHandle<Object> old_value, MaybeHandle<FieldType> new_field_type, 2330 MaybeHandle<Object> new_value) { 2331 OFStream os(file); 2332 os << "[generalizing]"; 2333 Name* name = instance_descriptors()->GetKey(modify_index); 2334 if (name->IsString()) { 2335 String::cast(name)->PrintOn(file); 2336 } else { 2337 os << "{symbol " << static_cast<void*>(name) << "}"; 2338 } 2339 os << ":"; 2340 if (constant_to_field) { 2341 os << "c"; 2342 } else { 2343 os << old_representation.Mnemonic() << "{"; 2344 if (old_field_type.is_null()) { 2345 os << Brief(*(old_value.ToHandleChecked())); 2346 } else { 2347 old_field_type.ToHandleChecked()->PrintTo(os); 2348 } 2349 os << "}"; 2350 } 2351 os << "->" << new_representation.Mnemonic() << "{"; 2352 if (new_field_type.is_null()) { 2353 os << Brief(*(new_value.ToHandleChecked())); 2354 } else { 2355 new_field_type.ToHandleChecked()->PrintTo(os); 2356 } 2357 os << "} ("; 2358 if (strlen(reason) > 0) { 2359 os << reason; 2360 } else { 2361 os << "+" << (descriptors - split) << " maps"; 2362 } 2363 os << ") ["; 2364 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true); 2365 os << "]\n"; 2366 } 2367 2368 2369 void JSObject::PrintInstanceMigration(FILE* file, 2370 Map* original_map, 2371 Map* new_map) { 2372 PrintF(file, "[migrating]"); 2373 DescriptorArray* o = original_map->instance_descriptors(); 2374 DescriptorArray* n = new_map->instance_descriptors(); 2375 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) { 2376 Representation o_r = o->GetDetails(i).representation(); 2377 Representation n_r = n->GetDetails(i).representation(); 2378 if (!o_r.Equals(n_r)) { 2379 String::cast(o->GetKey(i))->PrintOn(file); 2380 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic()); 2381 } else if (o->GetDetails(i).type() == DATA_CONSTANT && 2382 n->GetDetails(i).type() == DATA) { 2383 Name* name = o->GetKey(i); 2384 if (name->IsString()) { 2385 String::cast(name)->PrintOn(file); 2386 } else { 2387 PrintF(file, "{symbol %p}", static_cast<void*>(name)); 2388 } 2389 PrintF(file, " "); 2390 } 2391 } 2392 PrintF(file, "\n"); 2393 } 2394 2395 2396 void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT 2397 Heap* heap = GetHeap(); 2398 Isolate* isolate = heap->isolate(); 2399 if (!heap->Contains(this)) { 2400 os << "!!!INVALID POINTER!!!"; 2401 return; 2402 } 2403 if (!heap->Contains(map())) { 2404 os << "!!!INVALID MAP!!!"; 2405 return; 2406 } 2407 2408 os << this << " "; 2409 2410 if (IsString()) { 2411 HeapStringAllocator allocator; 2412 StringStream accumulator(&allocator); 2413 String::cast(this)->StringShortPrint(&accumulator); 2414 os << accumulator.ToCString().get(); 2415 return; 2416 } 2417 if (IsJSObject()) { 2418 HeapStringAllocator allocator; 2419 StringStream accumulator(&allocator); 2420 JSObject::cast(this)->JSObjectShortPrint(&accumulator); 2421 os << accumulator.ToCString().get(); 2422 return; 2423 } 2424 switch (map()->instance_type()) { 2425 case MAP_TYPE: 2426 os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind()) 2427 << ")>"; 2428 break; 2429 case FIXED_ARRAY_TYPE: 2430 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>"; 2431 break; 2432 case FIXED_DOUBLE_ARRAY_TYPE: 2433 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length() 2434 << "]>"; 2435 break; 2436 case BYTE_ARRAY_TYPE: 2437 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>"; 2438 break; 2439 case BYTECODE_ARRAY_TYPE: 2440 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>"; 2441 break; 2442 case TRANSITION_ARRAY_TYPE: 2443 os << "<TransitionArray[" << TransitionArray::cast(this)->length() 2444 << "]>"; 2445 break; 2446 case FREE_SPACE_TYPE: 2447 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>"; 2448 break; 2449 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \ 2450 case FIXED_##TYPE##_ARRAY_TYPE: \ 2451 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \ 2452 << "]>"; \ 2453 break; 2454 2455 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT) 2456 #undef TYPED_ARRAY_SHORT_PRINT 2457 2458 case SHARED_FUNCTION_INFO_TYPE: { 2459 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this); 2460 base::SmartArrayPointer<char> debug_name = 2461 shared->DebugName()->ToCString(); 2462 if (debug_name[0] != 0) { 2463 os << "<SharedFunctionInfo " << debug_name.get() << ">"; 2464 } else { 2465 os << "<SharedFunctionInfo>"; 2466 } 2467 break; 2468 } 2469 case JS_MESSAGE_OBJECT_TYPE: 2470 os << "<JSMessageObject>"; 2471 break; 2472 #define MAKE_STRUCT_CASE(NAME, Name, name) \ 2473 case NAME##_TYPE: \ 2474 os << "<" #Name ">"; \ 2475 break; 2476 STRUCT_LIST(MAKE_STRUCT_CASE) 2477 #undef MAKE_STRUCT_CASE 2478 case CODE_TYPE: { 2479 Code* code = Code::cast(this); 2480 os << "<Code: " << Code::Kind2String(code->kind()) << ">"; 2481 break; 2482 } 2483 case ODDBALL_TYPE: { 2484 if (IsUndefined(isolate)) { 2485 os << "<undefined>"; 2486 } else if (IsTheHole(isolate)) { 2487 os << "<the hole>"; 2488 } else if (IsNull(isolate)) { 2489 os << "<null>"; 2490 } else if (IsTrue(isolate)) { 2491 os << "<true>"; 2492 } else if (IsFalse(isolate)) { 2493 os << "<false>"; 2494 } else { 2495 os << "<Odd Oddball: "; 2496 os << Oddball::cast(this)->to_string()->ToCString().get(); 2497 os << ">"; 2498 } 2499 break; 2500 } 2501 case SYMBOL_TYPE: { 2502 Symbol* symbol = Symbol::cast(this); 2503 symbol->SymbolShortPrint(os); 2504 break; 2505 } 2506 case HEAP_NUMBER_TYPE: { 2507 os << "<Number: "; 2508 HeapNumber::cast(this)->HeapNumberPrint(os); 2509 os << ">"; 2510 break; 2511 } 2512 case MUTABLE_HEAP_NUMBER_TYPE: { 2513 os << "<MutableNumber: "; 2514 HeapNumber::cast(this)->HeapNumberPrint(os); 2515 os << '>'; 2516 break; 2517 } 2518 case SIMD128_VALUE_TYPE: { 2519 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 2520 if (Is##Type()) { \ 2521 os << "<" #Type ">"; \ 2522 break; \ 2523 } 2524 SIMD128_TYPES(SIMD128_TYPE) 2525 #undef SIMD128_TYPE 2526 UNREACHABLE(); 2527 break; 2528 } 2529 case JS_PROXY_TYPE: 2530 os << "<JSProxy>"; 2531 break; 2532 case FOREIGN_TYPE: 2533 os << "<Foreign>"; 2534 break; 2535 case CELL_TYPE: { 2536 os << "Cell for "; 2537 HeapStringAllocator allocator; 2538 StringStream accumulator(&allocator); 2539 Cell::cast(this)->value()->ShortPrint(&accumulator); 2540 os << accumulator.ToCString().get(); 2541 break; 2542 } 2543 case PROPERTY_CELL_TYPE: { 2544 os << "PropertyCell for "; 2545 HeapStringAllocator allocator; 2546 StringStream accumulator(&allocator); 2547 PropertyCell* cell = PropertyCell::cast(this); 2548 cell->value()->ShortPrint(&accumulator); 2549 os << accumulator.ToCString().get(); 2550 break; 2551 } 2552 case WEAK_CELL_TYPE: { 2553 os << "WeakCell for "; 2554 HeapStringAllocator allocator; 2555 StringStream accumulator(&allocator); 2556 WeakCell::cast(this)->value()->ShortPrint(&accumulator); 2557 os << accumulator.ToCString().get(); 2558 break; 2559 } 2560 default: 2561 os << "<Other heap object (" << map()->instance_type() << ")>"; 2562 break; 2563 } 2564 } 2565 2566 2567 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); } 2568 2569 2570 void HeapObject::IterateBody(ObjectVisitor* v) { 2571 Map* m = map(); 2572 IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v); 2573 } 2574 2575 2576 void HeapObject::IterateBody(InstanceType type, int object_size, 2577 ObjectVisitor* v) { 2578 IterateBodyFast<ObjectVisitor>(type, object_size, v); 2579 } 2580 2581 2582 struct CallIsValidSlot { 2583 template <typename BodyDescriptor> 2584 static bool apply(HeapObject* obj, int offset, int) { 2585 return BodyDescriptor::IsValidSlot(obj, offset); 2586 } 2587 }; 2588 2589 2590 bool HeapObject::IsValidSlot(int offset) { 2591 DCHECK_NE(0, offset); 2592 return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(), 2593 this, offset, 0); 2594 } 2595 2596 2597 bool HeapNumber::HeapNumberBooleanValue() { 2598 return DoubleToBoolean(value()); 2599 } 2600 2601 2602 void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT 2603 os << value(); 2604 } 2605 2606 2607 #define FIELD_ADDR_CONST(p, offset) \ 2608 (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag) 2609 2610 #define READ_INT32_FIELD(p, offset) \ 2611 (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset))) 2612 2613 #define READ_INT64_FIELD(p, offset) \ 2614 (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset))) 2615 2616 #define READ_BYTE_FIELD(p, offset) \ 2617 (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset))) 2618 2619 2620 // static 2621 Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) { 2622 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 2623 if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input)); 2624 SIMD128_TYPES(SIMD128_TYPE) 2625 #undef SIMD128_TYPE 2626 UNREACHABLE(); 2627 return Handle<String>::null(); 2628 } 2629 2630 2631 // static 2632 Handle<String> Float32x4::ToString(Handle<Float32x4> input) { 2633 Isolate* const isolate = input->GetIsolate(); 2634 char arr[100]; 2635 Vector<char> buffer(arr, arraysize(arr)); 2636 std::ostringstream os; 2637 os << "SIMD.Float32x4(" 2638 << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", " 2639 << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", " 2640 << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", " 2641 << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")"; 2642 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); 2643 } 2644 2645 2646 #define SIMD128_BOOL_TO_STRING(Type, lane_count) \ 2647 Handle<String> Type::ToString(Handle<Type> input) { \ 2648 Isolate* const isolate = input->GetIsolate(); \ 2649 std::ostringstream os; \ 2650 os << "SIMD." #Type "("; \ 2651 os << (input->get_lane(0) ? "true" : "false"); \ 2652 for (int i = 1; i < lane_count; i++) { \ 2653 os << ", " << (input->get_lane(i) ? "true" : "false"); \ 2654 } \ 2655 os << ")"; \ 2656 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \ 2657 } 2658 SIMD128_BOOL_TO_STRING(Bool32x4, 4) 2659 SIMD128_BOOL_TO_STRING(Bool16x8, 8) 2660 SIMD128_BOOL_TO_STRING(Bool8x16, 16) 2661 #undef SIMD128_BOOL_TO_STRING 2662 2663 2664 #define SIMD128_INT_TO_STRING(Type, lane_count) \ 2665 Handle<String> Type::ToString(Handle<Type> input) { \ 2666 Isolate* const isolate = input->GetIsolate(); \ 2667 char arr[100]; \ 2668 Vector<char> buffer(arr, arraysize(arr)); \ 2669 std::ostringstream os; \ 2670 os << "SIMD." #Type "("; \ 2671 os << IntToCString(input->get_lane(0), buffer); \ 2672 for (int i = 1; i < lane_count; i++) { \ 2673 os << ", " << IntToCString(input->get_lane(i), buffer); \ 2674 } \ 2675 os << ")"; \ 2676 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \ 2677 } 2678 SIMD128_INT_TO_STRING(Int32x4, 4) 2679 SIMD128_INT_TO_STRING(Uint32x4, 4) 2680 SIMD128_INT_TO_STRING(Int16x8, 8) 2681 SIMD128_INT_TO_STRING(Uint16x8, 8) 2682 SIMD128_INT_TO_STRING(Int8x16, 16) 2683 SIMD128_INT_TO_STRING(Uint8x16, 16) 2684 #undef SIMD128_INT_TO_STRING 2685 2686 2687 bool Simd128Value::BitwiseEquals(const Simd128Value* other) const { 2688 return READ_INT64_FIELD(this, kValueOffset) == 2689 READ_INT64_FIELD(other, kValueOffset) && 2690 READ_INT64_FIELD(this, kValueOffset + kInt64Size) == 2691 READ_INT64_FIELD(other, kValueOffset + kInt64Size); 2692 } 2693 2694 2695 uint32_t Simd128Value::Hash() const { 2696 uint32_t seed = v8::internal::kZeroHashSeed; 2697 uint32_t hash; 2698 hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed); 2699 hash = ComputeIntegerHash( 2700 READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31); 2701 hash = ComputeIntegerHash( 2702 READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31); 2703 hash = ComputeIntegerHash( 2704 READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31); 2705 return hash; 2706 } 2707 2708 2709 void Simd128Value::CopyBits(void* destination) const { 2710 memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size); 2711 } 2712 2713 2714 String* JSReceiver::class_name() { 2715 if (IsFunction()) { 2716 return GetHeap()->Function_string(); 2717 } 2718 Object* maybe_constructor = map()->GetConstructor(); 2719 if (maybe_constructor->IsJSFunction()) { 2720 JSFunction* constructor = JSFunction::cast(maybe_constructor); 2721 return String::cast(constructor->shared()->instance_class_name()); 2722 } 2723 // If the constructor is not present, return "Object". 2724 return GetHeap()->Object_string(); 2725 } 2726 2727 2728 // static 2729 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) { 2730 Isolate* isolate = receiver->GetIsolate(); 2731 2732 // If the object was instantiated simply with base == new.target, the 2733 // constructor on the map provides the most accurate name. 2734 // Don't provide the info for prototypes, since their constructors are 2735 // reclaimed and replaced by Object in OptimizeAsPrototype. 2736 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() && 2737 !receiver->map()->is_prototype_map()) { 2738 Object* maybe_constructor = receiver->map()->GetConstructor(); 2739 if (maybe_constructor->IsJSFunction()) { 2740 JSFunction* constructor = JSFunction::cast(maybe_constructor); 2741 String* name = String::cast(constructor->shared()->name()); 2742 if (name->length() == 0) name = constructor->shared()->inferred_name(); 2743 if (name->length() != 0 && 2744 !name->Equals(isolate->heap()->Object_string())) { 2745 return handle(name, isolate); 2746 } 2747 } 2748 } 2749 2750 Handle<Object> maybe_tag = JSReceiver::GetDataProperty( 2751 receiver, isolate->factory()->to_string_tag_symbol()); 2752 if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag); 2753 2754 PrototypeIterator iter(isolate, receiver); 2755 if (iter.IsAtEnd()) return handle(receiver->class_name()); 2756 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter); 2757 LookupIterator it(receiver, isolate->factory()->constructor_string(), start, 2758 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); 2759 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it); 2760 Handle<String> result = isolate->factory()->Object_string(); 2761 if (maybe_constructor->IsJSFunction()) { 2762 JSFunction* constructor = JSFunction::cast(*maybe_constructor); 2763 String* name = String::cast(constructor->shared()->name()); 2764 if (name->length() == 0) name = constructor->shared()->inferred_name(); 2765 if (name->length() > 0) result = handle(name, isolate); 2766 } 2767 2768 return result.is_identical_to(isolate->factory()->Object_string()) 2769 ? handle(receiver->class_name()) 2770 : result; 2771 } 2772 2773 2774 Context* JSReceiver::GetCreationContext() { 2775 JSReceiver* receiver = this; 2776 while (receiver->IsJSBoundFunction()) { 2777 receiver = JSBoundFunction::cast(receiver)->bound_target_function(); 2778 } 2779 Object* constructor = receiver->map()->GetConstructor(); 2780 JSFunction* function; 2781 if (constructor->IsJSFunction()) { 2782 function = JSFunction::cast(constructor); 2783 } else { 2784 // Functions have null as a constructor, 2785 // but any JSFunction knows its context immediately. 2786 CHECK(receiver->IsJSFunction()); 2787 function = JSFunction::cast(receiver); 2788 } 2789 2790 return function->context()->native_context(); 2791 } 2792 2793 static Handle<Object> WrapType(Handle<FieldType> type) { 2794 if (type->IsClass()) return Map::WeakCellForMap(type->AsClass()); 2795 return type; 2796 } 2797 2798 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name, 2799 Handle<FieldType> type, 2800 PropertyAttributes attributes, 2801 Representation representation, 2802 TransitionFlag flag) { 2803 DCHECK(DescriptorArray::kNotFound == 2804 map->instance_descriptors()->Search( 2805 *name, map->NumberOfOwnDescriptors())); 2806 2807 // Ensure the descriptor array does not get too big. 2808 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { 2809 return MaybeHandle<Map>(); 2810 } 2811 2812 Isolate* isolate = map->GetIsolate(); 2813 2814 // Compute the new index for new field. 2815 int index = map->NextFreePropertyIndex(); 2816 2817 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) { 2818 representation = Representation::Tagged(); 2819 type = FieldType::Any(isolate); 2820 } 2821 2822 Handle<Object> wrapped_type(WrapType(type)); 2823 2824 DataDescriptor new_field_desc(name, index, wrapped_type, attributes, 2825 representation); 2826 Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag); 2827 int unused_property_fields = new_map->unused_property_fields() - 1; 2828 if (unused_property_fields < 0) { 2829 unused_property_fields += JSObject::kFieldsAdded; 2830 } 2831 new_map->set_unused_property_fields(unused_property_fields); 2832 return new_map; 2833 } 2834 2835 2836 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map, 2837 Handle<Name> name, 2838 Handle<Object> constant, 2839 PropertyAttributes attributes, 2840 TransitionFlag flag) { 2841 // Ensure the descriptor array does not get too big. 2842 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { 2843 return MaybeHandle<Map>(); 2844 } 2845 2846 // Allocate new instance descriptors with (name, constant) added. 2847 DataConstantDescriptor new_constant_desc(name, constant, attributes); 2848 return Map::CopyAddDescriptor(map, &new_constant_desc, flag); 2849 } 2850 2851 2852 void JSObject::AddSlowProperty(Handle<JSObject> object, 2853 Handle<Name> name, 2854 Handle<Object> value, 2855 PropertyAttributes attributes) { 2856 DCHECK(!object->HasFastProperties()); 2857 Isolate* isolate = object->GetIsolate(); 2858 if (object->IsJSGlobalObject()) { 2859 Handle<GlobalDictionary> dict(object->global_dictionary()); 2860 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); 2861 int entry = dict->FindEntry(name); 2862 // If there's a cell there, just invalidate and set the property. 2863 if (entry != GlobalDictionary::kNotFound) { 2864 PropertyCell::UpdateCell(dict, entry, value, details); 2865 // TODO(ishell): move this to UpdateCell. 2866 // Need to adjust the details. 2867 int index = dict->NextEnumerationIndex(); 2868 dict->SetNextEnumerationIndex(index + 1); 2869 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(entry)); 2870 details = cell->property_details().set_index(index); 2871 cell->set_property_details(details); 2872 2873 } else { 2874 auto cell = isolate->factory()->NewPropertyCell(); 2875 cell->set_value(*value); 2876 auto cell_type = value->IsUndefined(isolate) 2877 ? PropertyCellType::kUndefined 2878 : PropertyCellType::kConstant; 2879 details = details.set_cell_type(cell_type); 2880 value = cell; 2881 2882 Handle<GlobalDictionary> result = 2883 GlobalDictionary::Add(dict, name, value, details); 2884 if (*dict != *result) object->set_properties(*result); 2885 } 2886 } else { 2887 Handle<NameDictionary> dict(object->property_dictionary()); 2888 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); 2889 Handle<NameDictionary> result = 2890 NameDictionary::Add(dict, name, value, details); 2891 if (*dict != *result) object->set_properties(*result); 2892 } 2893 } 2894 2895 2896 const char* Representation::Mnemonic() const { 2897 switch (kind_) { 2898 case kNone: return "v"; 2899 case kTagged: return "t"; 2900 case kSmi: return "s"; 2901 case kDouble: return "d"; 2902 case kInteger32: return "i"; 2903 case kHeapObject: return "h"; 2904 case kExternal: return "x"; 2905 default: 2906 UNREACHABLE(); 2907 return NULL; 2908 } 2909 } 2910 2911 bool Map::InstancesNeedRewriting(Map* target) { 2912 int target_number_of_fields = target->NumberOfFields(); 2913 int target_inobject = target->GetInObjectProperties(); 2914 int target_unused = target->unused_property_fields(); 2915 int old_number_of_fields; 2916 2917 return InstancesNeedRewriting(target, target_number_of_fields, 2918 target_inobject, target_unused, 2919 &old_number_of_fields); 2920 } 2921 2922 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields, 2923 int target_inobject, int target_unused, 2924 int* old_number_of_fields) { 2925 // If fields were added (or removed), rewrite the instance. 2926 *old_number_of_fields = NumberOfFields(); 2927 DCHECK(target_number_of_fields >= *old_number_of_fields); 2928 if (target_number_of_fields != *old_number_of_fields) return true; 2929 2930 // If smi descriptors were replaced by double descriptors, rewrite. 2931 DescriptorArray* old_desc = instance_descriptors(); 2932 DescriptorArray* new_desc = target->instance_descriptors(); 2933 int limit = NumberOfOwnDescriptors(); 2934 for (int i = 0; i < limit; i++) { 2935 if (new_desc->GetDetails(i).representation().IsDouble() != 2936 old_desc->GetDetails(i).representation().IsDouble()) { 2937 return true; 2938 } 2939 } 2940 2941 // If no fields were added, and no inobject properties were removed, setting 2942 // the map is sufficient. 2943 if (target_inobject == GetInObjectProperties()) return false; 2944 // In-object slack tracking may have reduced the object size of the new map. 2945 // In that case, succeed if all existing fields were inobject, and they still 2946 // fit within the new inobject size. 2947 DCHECK(target_inobject < GetInObjectProperties()); 2948 if (target_number_of_fields <= target_inobject) { 2949 DCHECK(target_number_of_fields + target_unused == target_inobject); 2950 return false; 2951 } 2952 // Otherwise, properties will need to be moved to the backing store. 2953 return true; 2954 } 2955 2956 2957 // static 2958 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map, 2959 Handle<Map> new_map, 2960 Isolate* isolate) { 2961 if (!old_map->is_prototype_map()) return; 2962 DCHECK(new_map->is_prototype_map()); 2963 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate); 2964 new_map->set_prototype_info(old_map->prototype_info()); 2965 old_map->set_prototype_info(Smi::FromInt(0)); 2966 if (FLAG_trace_prototype_users) { 2967 PrintF("Moving prototype_info %p from map %p to map %p.\n", 2968 reinterpret_cast<void*>(new_map->prototype_info()), 2969 reinterpret_cast<void*>(*old_map), 2970 reinterpret_cast<void*>(*new_map)); 2971 } 2972 if (was_registered) { 2973 if (new_map->prototype_info()->IsPrototypeInfo()) { 2974 // The new map isn't registered with its prototype yet; reflect this fact 2975 // in the PrototypeInfo it just inherited from the old map. 2976 PrototypeInfo::cast(new_map->prototype_info()) 2977 ->set_registry_slot(PrototypeInfo::UNREGISTERED); 2978 } 2979 JSObject::LazyRegisterPrototypeUser(new_map, isolate); 2980 } 2981 } 2982 2983 namespace { 2984 // To migrate a fast instance to a fast map: 2985 // - First check whether the instance needs to be rewritten. If not, simply 2986 // change the map. 2987 // - Otherwise, allocate a fixed array large enough to hold all fields, in 2988 // addition to unused space. 2989 // - Copy all existing properties in, in the following order: backing store 2990 // properties, unused fields, inobject properties. 2991 // - If all allocation succeeded, commit the state atomically: 2992 // * Copy inobject properties from the backing store back into the object. 2993 // * Trim the difference in instance size of the object. This also cleanly 2994 // frees inobject properties that moved to the backing store. 2995 // * If there are properties left in the backing store, trim of the space used 2996 // to temporarily store the inobject properties. 2997 // * If there are properties left in the backing store, install the backing 2998 // store. 2999 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { 3000 Isolate* isolate = object->GetIsolate(); 3001 Handle<Map> old_map(object->map()); 3002 // In case of a regular transition. 3003 if (new_map->GetBackPointer() == *old_map) { 3004 // If the map does not add named properties, simply set the map. 3005 if (old_map->NumberOfOwnDescriptors() == 3006 new_map->NumberOfOwnDescriptors()) { 3007 object->synchronized_set_map(*new_map); 3008 return; 3009 } 3010 3011 PropertyDetails details = new_map->GetLastDescriptorDetails(); 3012 // Either new_map adds an kDescriptor property, or a kField property for 3013 // which there is still space, and which does not require a mutable double 3014 // box (an out-of-object double). 3015 if (details.location() == kDescriptor || 3016 (old_map->unused_property_fields() > 0 && 3017 ((FLAG_unbox_double_fields && object->properties()->length() == 0) || 3018 !details.representation().IsDouble()))) { 3019 object->synchronized_set_map(*new_map); 3020 return; 3021 } 3022 3023 // If there is still space in the object, we need to allocate a mutable 3024 // double box. 3025 if (old_map->unused_property_fields() > 0) { 3026 FieldIndex index = 3027 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded()); 3028 DCHECK(details.representation().IsDouble()); 3029 DCHECK(!new_map->IsUnboxedDoubleField(index)); 3030 Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE); 3031 object->RawFastPropertyAtPut(index, *value); 3032 object->synchronized_set_map(*new_map); 3033 return; 3034 } 3035 3036 // This migration is a transition from a map that has run out of property 3037 // space. Extend the backing store. 3038 int grow_by = new_map->unused_property_fields() + 1; 3039 Handle<FixedArray> old_storage = handle(object->properties(), isolate); 3040 Handle<FixedArray> new_storage = 3041 isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by); 3042 3043 // Properly initialize newly added property. 3044 Handle<Object> value; 3045 if (details.representation().IsDouble()) { 3046 value = isolate->factory()->NewHeapNumber(0, MUTABLE); 3047 } else { 3048 value = isolate->factory()->uninitialized_value(); 3049 } 3050 DCHECK_EQ(DATA, details.type()); 3051 int target_index = details.field_index() - new_map->GetInObjectProperties(); 3052 DCHECK(target_index >= 0); // Must be a backing store index. 3053 new_storage->set(target_index, *value); 3054 3055 // From here on we cannot fail and we shouldn't GC anymore. 3056 DisallowHeapAllocation no_allocation; 3057 3058 // Set the new property value and do the map transition. 3059 object->set_properties(*new_storage); 3060 object->synchronized_set_map(*new_map); 3061 return; 3062 } 3063 3064 int old_number_of_fields; 3065 int number_of_fields = new_map->NumberOfFields(); 3066 int inobject = new_map->GetInObjectProperties(); 3067 int unused = new_map->unused_property_fields(); 3068 3069 // Nothing to do if no functions were converted to fields and no smis were 3070 // converted to doubles. 3071 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject, 3072 unused, &old_number_of_fields)) { 3073 object->synchronized_set_map(*new_map); 3074 return; 3075 } 3076 3077 int total_size = number_of_fields + unused; 3078 int external = total_size - inobject; 3079 3080 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size); 3081 3082 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); 3083 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors()); 3084 int old_nof = old_map->NumberOfOwnDescriptors(); 3085 int new_nof = new_map->NumberOfOwnDescriptors(); 3086 3087 // This method only supports generalizing instances to at least the same 3088 // number of properties. 3089 DCHECK(old_nof <= new_nof); 3090 3091 for (int i = 0; i < old_nof; i++) { 3092 PropertyDetails details = new_descriptors->GetDetails(i); 3093 if (details.type() != DATA) continue; 3094 PropertyDetails old_details = old_descriptors->GetDetails(i); 3095 Representation old_representation = old_details.representation(); 3096 Representation representation = details.representation(); 3097 Handle<Object> value; 3098 if (old_details.type() == ACCESSOR_CONSTANT) { 3099 // In case of kAccessor -> kData property reconfiguration, the property 3100 // must already be prepared for data or certain type. 3101 DCHECK(!details.representation().IsNone()); 3102 if (details.representation().IsDouble()) { 3103 value = isolate->factory()->NewHeapNumber(0, MUTABLE); 3104 } else { 3105 value = isolate->factory()->uninitialized_value(); 3106 } 3107 } else if (old_details.type() == DATA_CONSTANT) { 3108 value = handle(old_descriptors->GetValue(i), isolate); 3109 DCHECK(!old_representation.IsDouble() && !representation.IsDouble()); 3110 } else { 3111 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i); 3112 if (object->IsUnboxedDoubleField(index)) { 3113 double old = object->RawFastDoublePropertyAt(index); 3114 value = isolate->factory()->NewHeapNumber( 3115 old, representation.IsDouble() ? MUTABLE : IMMUTABLE); 3116 3117 } else { 3118 value = handle(object->RawFastPropertyAt(index), isolate); 3119 if (!old_representation.IsDouble() && representation.IsDouble()) { 3120 if (old_representation.IsNone()) { 3121 value = handle(Smi::FromInt(0), isolate); 3122 } 3123 value = Object::NewStorageFor(isolate, value, representation); 3124 } else if (old_representation.IsDouble() && 3125 !representation.IsDouble()) { 3126 value = Object::WrapForRead(isolate, value, old_representation); 3127 } 3128 } 3129 } 3130 DCHECK(!(representation.IsDouble() && value->IsSmi())); 3131 int target_index = new_descriptors->GetFieldIndex(i) - inobject; 3132 if (target_index < 0) target_index += total_size; 3133 array->set(target_index, *value); 3134 } 3135 3136 for (int i = old_nof; i < new_nof; i++) { 3137 PropertyDetails details = new_descriptors->GetDetails(i); 3138 if (details.type() != DATA) continue; 3139 Handle<Object> value; 3140 if (details.representation().IsDouble()) { 3141 value = isolate->factory()->NewHeapNumber(0, MUTABLE); 3142 } else { 3143 value = isolate->factory()->uninitialized_value(); 3144 } 3145 int target_index = new_descriptors->GetFieldIndex(i) - inobject; 3146 if (target_index < 0) target_index += total_size; 3147 array->set(target_index, *value); 3148 } 3149 3150 // From here on we cannot fail and we shouldn't GC anymore. 3151 DisallowHeapAllocation no_allocation; 3152 3153 Heap* heap = isolate->heap(); 3154 3155 // Copy (real) inobject properties. If necessary, stop at number_of_fields to 3156 // avoid overwriting |one_pointer_filler_map|. 3157 int limit = Min(inobject, number_of_fields); 3158 for (int i = 0; i < limit; i++) { 3159 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); 3160 Object* value = array->get(external + i); 3161 // Can't use JSObject::FastPropertyAtPut() because proper map was not set 3162 // yet. 3163 if (new_map->IsUnboxedDoubleField(index)) { 3164 DCHECK(value->IsMutableHeapNumber()); 3165 object->RawFastDoublePropertyAtPut(index, 3166 HeapNumber::cast(value)->value()); 3167 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) { 3168 // Transition from tagged to untagged slot. 3169 heap->ClearRecordedSlot(*object, 3170 HeapObject::RawField(*object, index.offset())); 3171 } 3172 } else { 3173 object->RawFastPropertyAtPut(index, value); 3174 } 3175 } 3176 3177 3178 // If there are properties in the new backing store, trim it to the correct 3179 // size and install the backing store into the object. 3180 if (external > 0) { 3181 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, inobject); 3182 object->set_properties(*array); 3183 } 3184 3185 // Create filler object past the new instance size. 3186 int new_instance_size = new_map->instance_size(); 3187 int instance_size_delta = old_map->instance_size() - new_instance_size; 3188 DCHECK(instance_size_delta >= 0); 3189 3190 if (instance_size_delta > 0) { 3191 Address address = object->address(); 3192 heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta, 3193 ClearRecordedSlots::kYes); 3194 heap->AdjustLiveBytes(*object, -instance_size_delta, 3195 Heap::CONCURRENT_TO_SWEEPER); 3196 } 3197 3198 // We are storing the new map using release store after creating a filler for 3199 // the left-over space to avoid races with the sweeper thread. 3200 object->synchronized_set_map(*new_map); 3201 } 3202 3203 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map, 3204 int expected_additional_properties) { 3205 // The global object is always normalized. 3206 DCHECK(!object->IsJSGlobalObject()); 3207 // JSGlobalProxy must never be normalized 3208 DCHECK(!object->IsJSGlobalProxy()); 3209 3210 Isolate* isolate = object->GetIsolate(); 3211 HandleScope scope(isolate); 3212 Handle<Map> map(object->map()); 3213 3214 // Allocate new content. 3215 int real_size = map->NumberOfOwnDescriptors(); 3216 int property_count = real_size; 3217 if (expected_additional_properties > 0) { 3218 property_count += expected_additional_properties; 3219 } else { 3220 property_count += 2; // Make space for two more properties. 3221 } 3222 Handle<NameDictionary> dictionary = 3223 NameDictionary::New(isolate, property_count); 3224 3225 Handle<DescriptorArray> descs(map->instance_descriptors()); 3226 for (int i = 0; i < real_size; i++) { 3227 PropertyDetails details = descs->GetDetails(i); 3228 Handle<Name> key(descs->GetKey(i)); 3229 switch (details.type()) { 3230 case DATA_CONSTANT: { 3231 Handle<Object> value(descs->GetConstant(i), isolate); 3232 PropertyDetails d(details.attributes(), DATA, i + 1, 3233 PropertyCellType::kNoCell); 3234 dictionary = NameDictionary::Add(dictionary, key, value, d); 3235 break; 3236 } 3237 case DATA: { 3238 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 3239 Handle<Object> value; 3240 if (object->IsUnboxedDoubleField(index)) { 3241 double old_value = object->RawFastDoublePropertyAt(index); 3242 value = isolate->factory()->NewHeapNumber(old_value); 3243 } else { 3244 value = handle(object->RawFastPropertyAt(index), isolate); 3245 if (details.representation().IsDouble()) { 3246 DCHECK(value->IsMutableHeapNumber()); 3247 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value); 3248 value = isolate->factory()->NewHeapNumber(old->value()); 3249 } 3250 } 3251 PropertyDetails d(details.attributes(), DATA, i + 1, 3252 PropertyCellType::kNoCell); 3253 dictionary = NameDictionary::Add(dictionary, key, value, d); 3254 break; 3255 } 3256 case ACCESSOR: { 3257 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 3258 Handle<Object> value(object->RawFastPropertyAt(index), isolate); 3259 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1, 3260 PropertyCellType::kNoCell); 3261 dictionary = NameDictionary::Add(dictionary, key, value, d); 3262 break; 3263 } 3264 case ACCESSOR_CONSTANT: { 3265 Handle<Object> value(descs->GetCallbacksObject(i), isolate); 3266 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1, 3267 PropertyCellType::kNoCell); 3268 dictionary = NameDictionary::Add(dictionary, key, value, d); 3269 break; 3270 } 3271 } 3272 } 3273 3274 // Copy the next enumeration index from instance descriptor. 3275 dictionary->SetNextEnumerationIndex(real_size + 1); 3276 3277 // From here on we cannot fail and we shouldn't GC anymore. 3278 DisallowHeapAllocation no_allocation; 3279 3280 // Resize the object in the heap if necessary. 3281 int new_instance_size = new_map->instance_size(); 3282 int instance_size_delta = map->instance_size() - new_instance_size; 3283 DCHECK(instance_size_delta >= 0); 3284 3285 if (instance_size_delta > 0) { 3286 Heap* heap = isolate->heap(); 3287 heap->CreateFillerObjectAt(object->address() + new_instance_size, 3288 instance_size_delta, ClearRecordedSlots::kYes); 3289 heap->AdjustLiveBytes(*object, -instance_size_delta, 3290 Heap::CONCURRENT_TO_SWEEPER); 3291 } 3292 3293 // We are storing the new map using release store after creating a filler for 3294 // the left-over space to avoid races with the sweeper thread. 3295 object->synchronized_set_map(*new_map); 3296 3297 object->set_properties(*dictionary); 3298 3299 // Ensure that in-object space of slow-mode object does not contain random 3300 // garbage. 3301 int inobject_properties = new_map->GetInObjectProperties(); 3302 for (int i = 0; i < inobject_properties; i++) { 3303 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); 3304 object->RawFastPropertyAtPut(index, Smi::FromInt(0)); 3305 } 3306 3307 isolate->counters()->props_to_dictionary()->Increment(); 3308 3309 #ifdef DEBUG 3310 if (FLAG_trace_normalization) { 3311 OFStream os(stdout); 3312 os << "Object properties have been normalized:\n"; 3313 object->Print(os); 3314 } 3315 #endif 3316 } 3317 3318 } // namespace 3319 3320 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, 3321 int expected_additional_properties) { 3322 if (object->map() == *new_map) return; 3323 Handle<Map> old_map(object->map()); 3324 if (old_map->is_prototype_map()) { 3325 // If this object is a prototype (the callee will check), invalidate any 3326 // prototype chains involving it. 3327 InvalidatePrototypeChains(object->map()); 3328 3329 // If the map was registered with its prototype before, ensure that it 3330 // registers with its new prototype now. This preserves the invariant that 3331 // when a map on a prototype chain is registered with its prototype, then 3332 // all prototypes further up the chain are also registered with their 3333 // respective prototypes. 3334 UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate()); 3335 } 3336 3337 if (old_map->is_dictionary_map()) { 3338 // For slow-to-fast migrations JSObject::MigrateSlowToFast() 3339 // must be used instead. 3340 CHECK(new_map->is_dictionary_map()); 3341 3342 // Slow-to-slow migration is trivial. 3343 object->set_map(*new_map); 3344 } else if (!new_map->is_dictionary_map()) { 3345 MigrateFastToFast(object, new_map); 3346 if (old_map->is_prototype_map()) { 3347 DCHECK(!old_map->is_stable()); 3348 DCHECK(new_map->is_stable()); 3349 // Clear out the old descriptor array to avoid problems to sharing 3350 // the descriptor array without using an explicit. 3351 old_map->InitializeDescriptors( 3352 old_map->GetHeap()->empty_descriptor_array(), 3353 LayoutDescriptor::FastPointerLayout()); 3354 // Ensure that no transition was inserted for prototype migrations. 3355 DCHECK_EQ( 3356 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions())); 3357 DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate())); 3358 } 3359 } else { 3360 MigrateFastToSlow(object, new_map, expected_additional_properties); 3361 } 3362 3363 // Careful: Don't allocate here! 3364 // For some callers of this method, |object| might be in an inconsistent 3365 // state now: the new map might have a new elements_kind, but the object's 3366 // elements pointer hasn't been updated yet. Callers will fix this, but in 3367 // the meantime, (indirectly) calling JSObjectVerify() must be avoided. 3368 // When adding code here, add a DisallowHeapAllocation too. 3369 } 3370 3371 int Map::NumberOfFields() { 3372 DescriptorArray* descriptors = instance_descriptors(); 3373 int result = 0; 3374 for (int i = 0; i < NumberOfOwnDescriptors(); i++) { 3375 if (descriptors->GetDetails(i).location() == kField) result++; 3376 } 3377 return result; 3378 } 3379 3380 Handle<Map> Map::CopyGeneralizeAllRepresentations( 3381 Handle<Map> map, ElementsKind elements_kind, int modify_index, 3382 StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes, 3383 const char* reason) { 3384 Isolate* isolate = map->GetIsolate(); 3385 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 3386 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 3387 Handle<DescriptorArray> descriptors = 3388 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors); 3389 3390 for (int i = 0; i < number_of_own_descriptors; i++) { 3391 descriptors->SetRepresentation(i, Representation::Tagged()); 3392 if (descriptors->GetDetails(i).type() == DATA) { 3393 descriptors->SetValue(i, FieldType::Any()); 3394 } 3395 } 3396 3397 Handle<LayoutDescriptor> new_layout_descriptor( 3398 LayoutDescriptor::FastPointerLayout(), isolate); 3399 Handle<Map> new_map = CopyReplaceDescriptors( 3400 map, descriptors, new_layout_descriptor, OMIT_TRANSITION, 3401 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION); 3402 3403 // Unless the instance is being migrated, ensure that modify_index is a field. 3404 if (modify_index >= 0) { 3405 PropertyDetails details = descriptors->GetDetails(modify_index); 3406 if (store_mode == FORCE_FIELD && 3407 (details.type() != DATA || details.attributes() != attributes)) { 3408 int field_index = details.type() == DATA ? details.field_index() 3409 : new_map->NumberOfFields(); 3410 DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate), 3411 field_index, attributes, Representation::Tagged()); 3412 descriptors->Replace(modify_index, &d); 3413 if (details.type() != DATA) { 3414 int unused_property_fields = new_map->unused_property_fields() - 1; 3415 if (unused_property_fields < 0) { 3416 unused_property_fields += JSObject::kFieldsAdded; 3417 } 3418 new_map->set_unused_property_fields(unused_property_fields); 3419 } 3420 } else { 3421 DCHECK(details.attributes() == attributes); 3422 } 3423 3424 if (FLAG_trace_generalization) { 3425 MaybeHandle<FieldType> field_type = FieldType::None(isolate); 3426 if (details.type() == DATA) { 3427 field_type = handle( 3428 map->instance_descriptors()->GetFieldType(modify_index), isolate); 3429 } 3430 map->PrintGeneralization( 3431 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(), 3432 new_map->NumberOfOwnDescriptors(), 3433 details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD, 3434 details.representation(), Representation::Tagged(), field_type, 3435 MaybeHandle<Object>(), FieldType::Any(isolate), 3436 MaybeHandle<Object>()); 3437 } 3438 } 3439 new_map->set_elements_kind(elements_kind); 3440 return new_map; 3441 } 3442 3443 3444 void Map::DeprecateTransitionTree() { 3445 if (is_deprecated()) return; 3446 Object* transitions = raw_transitions(); 3447 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 3448 for (int i = 0; i < num_transitions; ++i) { 3449 TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree(); 3450 } 3451 deprecate(); 3452 dependent_code()->DeoptimizeDependentCodeGroup( 3453 GetIsolate(), DependentCode::kTransitionGroup); 3454 NotifyLeafMapLayoutChange(); 3455 } 3456 3457 3458 static inline bool EqualImmutableValues(Object* obj1, Object* obj2) { 3459 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds. 3460 // TODO(ishell): compare AccessorPairs. 3461 return false; 3462 } 3463 3464 3465 // Installs |new_descriptors| over the current instance_descriptors to ensure 3466 // proper sharing of descriptor arrays. 3467 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors, 3468 LayoutDescriptor* new_layout_descriptor) { 3469 Isolate* isolate = GetIsolate(); 3470 // Don't overwrite the empty descriptor array or initial map's descriptors. 3471 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) { 3472 return; 3473 } 3474 3475 DescriptorArray* to_replace = instance_descriptors(); 3476 isolate->heap()->incremental_marking()->IterateBlackObject(to_replace); 3477 Map* current = this; 3478 while (current->instance_descriptors() == to_replace) { 3479 Object* next = current->GetBackPointer(); 3480 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map. 3481 current->SetEnumLength(kInvalidEnumCacheSentinel); 3482 current->UpdateDescriptors(new_descriptors, new_layout_descriptor); 3483 current = Map::cast(next); 3484 } 3485 set_owns_descriptors(false); 3486 } 3487 3488 3489 Map* Map::FindRootMap() { 3490 Map* result = this; 3491 Isolate* isolate = GetIsolate(); 3492 while (true) { 3493 Object* back = result->GetBackPointer(); 3494 if (back->IsUndefined(isolate)) { 3495 // Initial map always owns descriptors and doesn't have unused entries 3496 // in the descriptor array. 3497 DCHECK(result->owns_descriptors()); 3498 DCHECK_EQ(result->NumberOfOwnDescriptors(), 3499 result->instance_descriptors()->number_of_descriptors()); 3500 return result; 3501 } 3502 result = Map::cast(back); 3503 } 3504 } 3505 3506 3507 Map* Map::FindLastMatchMap(int verbatim, 3508 int length, 3509 DescriptorArray* descriptors) { 3510 DisallowHeapAllocation no_allocation; 3511 3512 // This can only be called on roots of transition trees. 3513 DCHECK_EQ(verbatim, NumberOfOwnDescriptors()); 3514 3515 Map* current = this; 3516 3517 for (int i = verbatim; i < length; i++) { 3518 Name* name = descriptors->GetKey(i); 3519 PropertyDetails details = descriptors->GetDetails(i); 3520 Map* next = TransitionArray::SearchTransition(current, details.kind(), name, 3521 details.attributes()); 3522 if (next == NULL) break; 3523 DescriptorArray* next_descriptors = next->instance_descriptors(); 3524 3525 PropertyDetails next_details = next_descriptors->GetDetails(i); 3526 DCHECK_EQ(details.kind(), next_details.kind()); 3527 DCHECK_EQ(details.attributes(), next_details.attributes()); 3528 if (details.location() != next_details.location()) break; 3529 if (!details.representation().Equals(next_details.representation())) break; 3530 3531 if (next_details.location() == kField) { 3532 FieldType* next_field_type = next_descriptors->GetFieldType(i); 3533 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) { 3534 break; 3535 } 3536 } else { 3537 if (!EqualImmutableValues(descriptors->GetValue(i), 3538 next_descriptors->GetValue(i))) { 3539 break; 3540 } 3541 } 3542 current = next; 3543 } 3544 return current; 3545 } 3546 3547 3548 Map* Map::FindFieldOwner(int descriptor) { 3549 DisallowHeapAllocation no_allocation; 3550 DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type()); 3551 Map* result = this; 3552 Isolate* isolate = GetIsolate(); 3553 while (true) { 3554 Object* back = result->GetBackPointer(); 3555 if (back->IsUndefined(isolate)) break; 3556 Map* parent = Map::cast(back); 3557 if (parent->NumberOfOwnDescriptors() <= descriptor) break; 3558 result = parent; 3559 } 3560 return result; 3561 } 3562 3563 3564 void Map::UpdateFieldType(int descriptor, Handle<Name> name, 3565 Representation new_representation, 3566 Handle<Object> new_wrapped_type) { 3567 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell()); 3568 // We store raw pointers in the queue, so no allocations are allowed. 3569 DisallowHeapAllocation no_allocation; 3570 PropertyDetails details = instance_descriptors()->GetDetails(descriptor); 3571 if (details.type() != DATA) return; 3572 3573 Zone zone(GetIsolate()->allocator()); 3574 ZoneQueue<Map*> backlog(&zone); 3575 backlog.push(this); 3576 3577 while (!backlog.empty()) { 3578 Map* current = backlog.front(); 3579 backlog.pop(); 3580 3581 Object* transitions = current->raw_transitions(); 3582 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 3583 for (int i = 0; i < num_transitions; ++i) { 3584 Map* target = TransitionArray::GetTarget(transitions, i); 3585 backlog.push(target); 3586 } 3587 DescriptorArray* descriptors = current->instance_descriptors(); 3588 PropertyDetails details = descriptors->GetDetails(descriptor); 3589 3590 // It is allowed to change representation here only from None to something. 3591 DCHECK(details.representation().Equals(new_representation) || 3592 details.representation().IsNone()); 3593 3594 // Skip if already updated the shared descriptor. 3595 if (descriptors->GetValue(descriptor) != *new_wrapped_type) { 3596 DataDescriptor d(name, descriptors->GetFieldIndex(descriptor), 3597 new_wrapped_type, details.attributes(), 3598 new_representation); 3599 descriptors->Replace(descriptor, &d); 3600 } 3601 } 3602 } 3603 3604 bool FieldTypeIsCleared(Representation rep, FieldType* type) { 3605 return type->IsNone() && rep.IsHeapObject(); 3606 } 3607 3608 3609 // static 3610 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1, 3611 Handle<FieldType> type1, 3612 Representation rep2, 3613 Handle<FieldType> type2, 3614 Isolate* isolate) { 3615 // Cleared field types need special treatment. They represent lost knowledge, 3616 // so we must be conservative, so their generalization with any other type 3617 // is "Any". 3618 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) { 3619 return FieldType::Any(isolate); 3620 } 3621 if (type1->NowIs(type2)) return type2; 3622 if (type2->NowIs(type1)) return type1; 3623 return FieldType::Any(isolate); 3624 } 3625 3626 3627 // static 3628 void Map::GeneralizeFieldType(Handle<Map> map, int modify_index, 3629 Representation new_representation, 3630 Handle<FieldType> new_field_type) { 3631 Isolate* isolate = map->GetIsolate(); 3632 3633 // Check if we actually need to generalize the field type at all. 3634 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 3635 Representation old_representation = 3636 old_descriptors->GetDetails(modify_index).representation(); 3637 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index), 3638 isolate); 3639 3640 if (old_representation.Equals(new_representation) && 3641 !FieldTypeIsCleared(new_representation, *new_field_type) && 3642 // Checking old_field_type for being cleared is not necessary because 3643 // the NowIs check below would fail anyway in that case. 3644 new_field_type->NowIs(old_field_type)) { 3645 DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type, 3646 new_representation, new_field_type, isolate) 3647 ->NowIs(old_field_type)); 3648 return; 3649 } 3650 3651 // Determine the field owner. 3652 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate); 3653 Handle<DescriptorArray> descriptors( 3654 field_owner->instance_descriptors(), isolate); 3655 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index)); 3656 3657 new_field_type = 3658 Map::GeneralizeFieldType(old_representation, old_field_type, 3659 new_representation, new_field_type, isolate); 3660 3661 PropertyDetails details = descriptors->GetDetails(modify_index); 3662 Handle<Name> name(descriptors->GetKey(modify_index)); 3663 3664 Handle<Object> wrapped_type(WrapType(new_field_type)); 3665 field_owner->UpdateFieldType(modify_index, name, new_representation, 3666 wrapped_type); 3667 field_owner->dependent_code()->DeoptimizeDependentCodeGroup( 3668 isolate, DependentCode::kFieldTypeGroup); 3669 3670 if (FLAG_trace_generalization) { 3671 map->PrintGeneralization( 3672 stdout, "field type generalization", modify_index, 3673 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false, 3674 details.representation(), details.representation(), old_field_type, 3675 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>()); 3676 } 3677 } 3678 3679 static inline Handle<FieldType> GetFieldType( 3680 Isolate* isolate, Handle<DescriptorArray> descriptors, int descriptor, 3681 PropertyLocation location, Representation representation) { 3682 #ifdef DEBUG 3683 PropertyDetails details = descriptors->GetDetails(descriptor); 3684 DCHECK_EQ(kData, details.kind()); 3685 DCHECK_EQ(details.location(), location); 3686 #endif 3687 if (location == kField) { 3688 return handle(descriptors->GetFieldType(descriptor), isolate); 3689 } else { 3690 return descriptors->GetValue(descriptor) 3691 ->OptimalType(isolate, representation); 3692 } 3693 } 3694 3695 // Reconfigures elements kind to |new_elements_kind| and/or property at 3696 // |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or 3697 // |new_representation|/|new_field_type|. 3698 // If |modify_index| is negative then no properties are reconfigured but the 3699 // map is migrated to the up-to-date non-deprecated state. 3700 // 3701 // This method rewrites or completes the transition tree to reflect the new 3702 // change. To avoid high degrees over polymorphism, and to stabilize quickly, 3703 // on every rewrite the new type is deduced by merging the current type with 3704 // any potential new (partial) version of the type in the transition tree. 3705 // To do this, on each rewrite: 3706 // - Search the root of the transition tree using FindRootMap. 3707 // - Find/create a |root_map| with requested |new_elements_kind|. 3708 // - Find |target_map|, the newest matching version of this map using the 3709 // virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at 3710 // |modify_index| is considered to be of |new_kind| and having 3711 // |new_attributes|) to walk the transition tree. 3712 // - Merge/generalize the "enhanced" descriptor array of the |old_map| and 3713 // descriptor array of the |target_map|. 3714 // - Generalize the |modify_index| descriptor using |new_representation| and 3715 // |new_field_type|. 3716 // - Walk the tree again starting from the root towards |target_map|. Stop at 3717 // |split_map|, the first map who's descriptor array does not match the merged 3718 // descriptor array. 3719 // - If |target_map| == |split_map|, |target_map| is in the expected state. 3720 // Return it. 3721 // - Otherwise, invalidate the outdated transition target from |target_map|, and 3722 // replace its transition tree with a new branch for the updated descriptors. 3723 Handle<Map> Map::Reconfigure(Handle<Map> old_map, 3724 ElementsKind new_elements_kind, int modify_index, 3725 PropertyKind new_kind, 3726 PropertyAttributes new_attributes, 3727 Representation new_representation, 3728 Handle<FieldType> new_field_type, 3729 StoreMode store_mode) { 3730 DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet. 3731 DCHECK(store_mode != FORCE_FIELD || modify_index >= 0); 3732 Isolate* isolate = old_map->GetIsolate(); 3733 3734 Handle<DescriptorArray> old_descriptors( 3735 old_map->instance_descriptors(), isolate); 3736 int old_nof = old_map->NumberOfOwnDescriptors(); 3737 3738 // If it's just a representation generalization case (i.e. property kind and 3739 // attributes stays unchanged) it's fine to transition from None to anything 3740 // but double without any modification to the object, because the default 3741 // uninitialized value for representation None can be overwritten by both 3742 // smi and tagged values. Doubles, however, would require a box allocation. 3743 if (modify_index >= 0 && !new_representation.IsNone() && 3744 !new_representation.IsDouble() && 3745 old_map->elements_kind() == new_elements_kind) { 3746 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); 3747 Representation old_representation = old_details.representation(); 3748 3749 if (old_representation.IsNone()) { 3750 DCHECK_EQ(new_kind, old_details.kind()); 3751 DCHECK_EQ(new_attributes, old_details.attributes()); 3752 DCHECK_EQ(DATA, old_details.type()); 3753 if (FLAG_trace_generalization) { 3754 old_map->PrintGeneralization( 3755 stdout, "uninitialized field", modify_index, 3756 old_map->NumberOfOwnDescriptors(), 3757 old_map->NumberOfOwnDescriptors(), false, old_representation, 3758 new_representation, 3759 handle(old_descriptors->GetFieldType(modify_index), isolate), 3760 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>()); 3761 } 3762 Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate); 3763 3764 GeneralizeFieldType(field_owner, modify_index, new_representation, 3765 new_field_type); 3766 DCHECK(old_descriptors->GetDetails(modify_index) 3767 .representation() 3768 .Equals(new_representation)); 3769 DCHECK( 3770 old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type)); 3771 return old_map; 3772 } 3773 } 3774 3775 // Check the state of the root map. 3776 Handle<Map> root_map(old_map->FindRootMap(), isolate); 3777 if (!old_map->EquivalentToForTransition(*root_map)) { 3778 return CopyGeneralizeAllRepresentations( 3779 old_map, new_elements_kind, modify_index, store_mode, new_kind, 3780 new_attributes, "GenAll_NotEquivalent"); 3781 } 3782 3783 ElementsKind from_kind = root_map->elements_kind(); 3784 ElementsKind to_kind = new_elements_kind; 3785 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS. 3786 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS && 3787 to_kind != SLOW_STRING_WRAPPER_ELEMENTS && 3788 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS && 3789 !(IsTransitionableFastElementsKind(from_kind) && 3790 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) { 3791 return CopyGeneralizeAllRepresentations( 3792 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 3793 "GenAll_InvalidElementsTransition"); 3794 } 3795 int root_nof = root_map->NumberOfOwnDescriptors(); 3796 if (modify_index >= 0 && modify_index < root_nof) { 3797 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); 3798 if (old_details.kind() != new_kind || 3799 old_details.attributes() != new_attributes) { 3800 return CopyGeneralizeAllRepresentations( 3801 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 3802 "GenAll_RootModification1"); 3803 } 3804 if ((old_details.type() != DATA && store_mode == FORCE_FIELD) || 3805 (old_details.type() == DATA && 3806 (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) || 3807 !new_representation.fits_into(old_details.representation())))) { 3808 return CopyGeneralizeAllRepresentations( 3809 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 3810 "GenAll_RootModification2"); 3811 } 3812 } 3813 3814 // From here on, use the map with correct elements kind as root map. 3815 if (from_kind != to_kind) { 3816 root_map = Map::AsElementsKind(root_map, to_kind); 3817 } 3818 3819 Handle<Map> target_map = root_map; 3820 for (int i = root_nof; i < old_nof; ++i) { 3821 PropertyDetails old_details = old_descriptors->GetDetails(i); 3822 PropertyKind next_kind; 3823 PropertyLocation next_location; 3824 PropertyAttributes next_attributes; 3825 Representation next_representation; 3826 bool property_kind_reconfiguration = false; 3827 3828 if (modify_index == i) { 3829 DCHECK_EQ(FORCE_FIELD, store_mode); 3830 property_kind_reconfiguration = old_details.kind() != new_kind; 3831 3832 next_kind = new_kind; 3833 next_location = kField; 3834 next_attributes = new_attributes; 3835 // If property kind is not reconfigured merge the result with 3836 // representation/field type from the old descriptor. 3837 next_representation = new_representation; 3838 if (!property_kind_reconfiguration) { 3839 next_representation = 3840 next_representation.generalize(old_details.representation()); 3841 } 3842 3843 } else { 3844 next_kind = old_details.kind(); 3845 next_location = old_details.location(); 3846 next_attributes = old_details.attributes(); 3847 next_representation = old_details.representation(); 3848 } 3849 Map* transition = TransitionArray::SearchTransition( 3850 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes); 3851 if (transition == NULL) break; 3852 Handle<Map> tmp_map(transition, isolate); 3853 3854 Handle<DescriptorArray> tmp_descriptors = handle( 3855 tmp_map->instance_descriptors(), isolate); 3856 3857 // Check if target map is incompatible. 3858 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); 3859 DCHECK_EQ(next_kind, tmp_details.kind()); 3860 DCHECK_EQ(next_attributes, tmp_details.attributes()); 3861 if (next_kind == kAccessor && 3862 !EqualImmutableValues(old_descriptors->GetValue(i), 3863 tmp_descriptors->GetValue(i))) { 3864 return CopyGeneralizeAllRepresentations( 3865 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 3866 "GenAll_Incompatible"); 3867 } 3868 if (next_location == kField && tmp_details.location() == kDescriptor) break; 3869 3870 Representation tmp_representation = tmp_details.representation(); 3871 if (!next_representation.fits_into(tmp_representation)) break; 3872 3873 PropertyLocation old_location = old_details.location(); 3874 PropertyLocation tmp_location = tmp_details.location(); 3875 if (tmp_location == kField) { 3876 if (next_kind == kData) { 3877 Handle<FieldType> next_field_type; 3878 if (modify_index == i) { 3879 next_field_type = new_field_type; 3880 if (!property_kind_reconfiguration) { 3881 Handle<FieldType> old_field_type = 3882 GetFieldType(isolate, old_descriptors, i, 3883 old_details.location(), tmp_representation); 3884 Representation old_representation = old_details.representation(); 3885 next_field_type = GeneralizeFieldType( 3886 old_representation, old_field_type, new_representation, 3887 next_field_type, isolate); 3888 } 3889 } else { 3890 Handle<FieldType> old_field_type = 3891 GetFieldType(isolate, old_descriptors, i, old_details.location(), 3892 tmp_representation); 3893 next_field_type = old_field_type; 3894 } 3895 GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type); 3896 } 3897 } else if (old_location == kField || 3898 !EqualImmutableValues(old_descriptors->GetValue(i), 3899 tmp_descriptors->GetValue(i))) { 3900 break; 3901 } 3902 DCHECK(!tmp_map->is_deprecated()); 3903 target_map = tmp_map; 3904 } 3905 3906 // Directly change the map if the target map is more general. 3907 Handle<DescriptorArray> target_descriptors( 3908 target_map->instance_descriptors(), isolate); 3909 int target_nof = target_map->NumberOfOwnDescriptors(); 3910 if (target_nof == old_nof && 3911 (store_mode != FORCE_FIELD || 3912 (modify_index >= 0 && 3913 target_descriptors->GetDetails(modify_index).location() == kField))) { 3914 #ifdef DEBUG 3915 if (modify_index >= 0) { 3916 PropertyDetails details = target_descriptors->GetDetails(modify_index); 3917 DCHECK_EQ(new_kind, details.kind()); 3918 DCHECK_EQ(new_attributes, details.attributes()); 3919 DCHECK(new_representation.fits_into(details.representation())); 3920 DCHECK(details.location() != kField || 3921 new_field_type->NowIs( 3922 target_descriptors->GetFieldType(modify_index))); 3923 } 3924 #endif 3925 if (*target_map != *old_map) { 3926 old_map->NotifyLeafMapLayoutChange(); 3927 } 3928 return target_map; 3929 } 3930 3931 // Find the last compatible target map in the transition tree. 3932 for (int i = target_nof; i < old_nof; ++i) { 3933 PropertyDetails old_details = old_descriptors->GetDetails(i); 3934 PropertyKind next_kind; 3935 PropertyAttributes next_attributes; 3936 if (modify_index == i) { 3937 next_kind = new_kind; 3938 next_attributes = new_attributes; 3939 } else { 3940 next_kind = old_details.kind(); 3941 next_attributes = old_details.attributes(); 3942 } 3943 Map* transition = TransitionArray::SearchTransition( 3944 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes); 3945 if (transition == NULL) break; 3946 Handle<Map> tmp_map(transition, isolate); 3947 Handle<DescriptorArray> tmp_descriptors( 3948 tmp_map->instance_descriptors(), isolate); 3949 3950 // Check if target map is compatible. 3951 #ifdef DEBUG 3952 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); 3953 DCHECK_EQ(next_kind, tmp_details.kind()); 3954 DCHECK_EQ(next_attributes, tmp_details.attributes()); 3955 #endif 3956 if (next_kind == kAccessor && 3957 !EqualImmutableValues(old_descriptors->GetValue(i), 3958 tmp_descriptors->GetValue(i))) { 3959 return CopyGeneralizeAllRepresentations( 3960 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 3961 "GenAll_Incompatible"); 3962 } 3963 DCHECK(!tmp_map->is_deprecated()); 3964 target_map = tmp_map; 3965 } 3966 target_nof = target_map->NumberOfOwnDescriptors(); 3967 target_descriptors = handle(target_map->instance_descriptors(), isolate); 3968 3969 // Allocate a new descriptor array large enough to hold the required 3970 // descriptors, with minimally the exact same size as the old descriptor 3971 // array. 3972 int new_slack = Max( 3973 old_nof, old_descriptors->number_of_descriptors()) - old_nof; 3974 Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate( 3975 isolate, old_nof, new_slack); 3976 DCHECK(new_descriptors->length() > target_descriptors->length() || 3977 new_descriptors->NumberOfSlackDescriptors() > 0 || 3978 new_descriptors->number_of_descriptors() == 3979 old_descriptors->number_of_descriptors()); 3980 DCHECK(new_descriptors->number_of_descriptors() == old_nof); 3981 3982 // 0 -> |root_nof| 3983 int current_offset = 0; 3984 for (int i = 0; i < root_nof; ++i) { 3985 PropertyDetails old_details = old_descriptors->GetDetails(i); 3986 if (old_details.location() == kField) { 3987 current_offset += old_details.field_width_in_words(); 3988 } 3989 Descriptor d(handle(old_descriptors->GetKey(i), isolate), 3990 handle(old_descriptors->GetValue(i), isolate), 3991 old_details); 3992 new_descriptors->Set(i, &d); 3993 } 3994 3995 // |root_nof| -> |target_nof| 3996 for (int i = root_nof; i < target_nof; ++i) { 3997 Handle<Name> target_key(target_descriptors->GetKey(i), isolate); 3998 PropertyDetails old_details = old_descriptors->GetDetails(i); 3999 PropertyDetails target_details = target_descriptors->GetDetails(i); 4000 4001 PropertyKind next_kind; 4002 PropertyAttributes next_attributes; 4003 PropertyLocation next_location; 4004 Representation next_representation; 4005 bool property_kind_reconfiguration = false; 4006 4007 if (modify_index == i) { 4008 DCHECK_EQ(FORCE_FIELD, store_mode); 4009 property_kind_reconfiguration = old_details.kind() != new_kind; 4010 4011 next_kind = new_kind; 4012 next_attributes = new_attributes; 4013 next_location = kField; 4014 4015 // Merge new representation/field type with ones from the target 4016 // descriptor. If property kind is not reconfigured merge the result with 4017 // representation/field type from the old descriptor. 4018 next_representation = 4019 new_representation.generalize(target_details.representation()); 4020 if (!property_kind_reconfiguration) { 4021 next_representation = 4022 next_representation.generalize(old_details.representation()); 4023 } 4024 } else { 4025 // Merge old_descriptor and target_descriptor entries. 4026 DCHECK_EQ(target_details.kind(), old_details.kind()); 4027 next_kind = target_details.kind(); 4028 next_attributes = target_details.attributes(); 4029 next_location = 4030 old_details.location() == kField || 4031 target_details.location() == kField || 4032 !EqualImmutableValues(target_descriptors->GetValue(i), 4033 old_descriptors->GetValue(i)) 4034 ? kField 4035 : kDescriptor; 4036 4037 next_representation = old_details.representation().generalize( 4038 target_details.representation()); 4039 } 4040 DCHECK_EQ(next_kind, target_details.kind()); 4041 DCHECK_EQ(next_attributes, target_details.attributes()); 4042 4043 if (next_location == kField) { 4044 if (next_kind == kData) { 4045 Handle<FieldType> target_field_type = 4046 GetFieldType(isolate, target_descriptors, i, 4047 target_details.location(), next_representation); 4048 4049 Handle<FieldType> next_field_type; 4050 if (modify_index == i) { 4051 next_field_type = GeneralizeFieldType( 4052 target_details.representation(), target_field_type, 4053 new_representation, new_field_type, isolate); 4054 if (!property_kind_reconfiguration) { 4055 Handle<FieldType> old_field_type = 4056 GetFieldType(isolate, old_descriptors, i, 4057 old_details.location(), next_representation); 4058 next_field_type = GeneralizeFieldType( 4059 old_details.representation(), old_field_type, 4060 next_representation, next_field_type, isolate); 4061 } 4062 } else { 4063 Handle<FieldType> old_field_type = 4064 GetFieldType(isolate, old_descriptors, i, old_details.location(), 4065 next_representation); 4066 next_field_type = GeneralizeFieldType( 4067 old_details.representation(), old_field_type, next_representation, 4068 target_field_type, isolate); 4069 } 4070 Handle<Object> wrapped_type(WrapType(next_field_type)); 4071 DataDescriptor d(target_key, current_offset, wrapped_type, 4072 next_attributes, next_representation); 4073 current_offset += d.GetDetails().field_width_in_words(); 4074 new_descriptors->Set(i, &d); 4075 } else { 4076 UNIMPLEMENTED(); // TODO(ishell): implement. 4077 } 4078 } else { 4079 PropertyDetails details(next_attributes, next_kind, next_location, 4080 next_representation); 4081 Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate), 4082 details); 4083 new_descriptors->Set(i, &d); 4084 } 4085 } 4086 4087 // |target_nof| -> |old_nof| 4088 for (int i = target_nof; i < old_nof; ++i) { 4089 PropertyDetails old_details = old_descriptors->GetDetails(i); 4090 Handle<Name> old_key(old_descriptors->GetKey(i), isolate); 4091 4092 // Merge old_descriptor entry and modified details together. 4093 PropertyKind next_kind; 4094 PropertyAttributes next_attributes; 4095 PropertyLocation next_location; 4096 Representation next_representation; 4097 bool property_kind_reconfiguration = false; 4098 4099 if (modify_index == i) { 4100 DCHECK_EQ(FORCE_FIELD, store_mode); 4101 // In case of property kind reconfiguration it is not necessary to 4102 // take into account representation/field type of the old descriptor. 4103 property_kind_reconfiguration = old_details.kind() != new_kind; 4104 4105 next_kind = new_kind; 4106 next_attributes = new_attributes; 4107 next_location = kField; 4108 next_representation = new_representation; 4109 if (!property_kind_reconfiguration) { 4110 next_representation = 4111 next_representation.generalize(old_details.representation()); 4112 } 4113 } else { 4114 next_kind = old_details.kind(); 4115 next_attributes = old_details.attributes(); 4116 next_location = old_details.location(); 4117 next_representation = old_details.representation(); 4118 } 4119 4120 if (next_location == kField) { 4121 if (next_kind == kData) { 4122 Handle<FieldType> next_field_type; 4123 if (modify_index == i) { 4124 next_field_type = new_field_type; 4125 if (!property_kind_reconfiguration) { 4126 Handle<FieldType> old_field_type = 4127 GetFieldType(isolate, old_descriptors, i, 4128 old_details.location(), next_representation); 4129 next_field_type = GeneralizeFieldType( 4130 old_details.representation(), old_field_type, 4131 next_representation, next_field_type, isolate); 4132 } 4133 } else { 4134 Handle<FieldType> old_field_type = 4135 GetFieldType(isolate, old_descriptors, i, old_details.location(), 4136 next_representation); 4137 next_field_type = old_field_type; 4138 } 4139 4140 Handle<Object> wrapped_type(WrapType(next_field_type)); 4141 4142 DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes, 4143 next_representation); 4144 current_offset += d.GetDetails().field_width_in_words(); 4145 new_descriptors->Set(i, &d); 4146 } else { 4147 UNIMPLEMENTED(); // TODO(ishell): implement. 4148 } 4149 } else { 4150 PropertyDetails details(next_attributes, next_kind, next_location, 4151 next_representation); 4152 Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate), 4153 details); 4154 new_descriptors->Set(i, &d); 4155 } 4156 } 4157 4158 new_descriptors->Sort(); 4159 4160 DCHECK(store_mode != FORCE_FIELD || 4161 new_descriptors->GetDetails(modify_index).location() == kField); 4162 4163 Handle<Map> split_map(root_map->FindLastMatchMap( 4164 root_nof, old_nof, *new_descriptors), isolate); 4165 int split_nof = split_map->NumberOfOwnDescriptors(); 4166 DCHECK_NE(old_nof, split_nof); 4167 4168 PropertyKind split_kind; 4169 PropertyAttributes split_attributes; 4170 if (modify_index == split_nof) { 4171 split_kind = new_kind; 4172 split_attributes = new_attributes; 4173 } else { 4174 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof); 4175 split_kind = split_prop_details.kind(); 4176 split_attributes = split_prop_details.attributes(); 4177 } 4178 4179 // Invalidate a transition target at |key|. 4180 Map* maybe_transition = TransitionArray::SearchTransition( 4181 *split_map, split_kind, old_descriptors->GetKey(split_nof), 4182 split_attributes); 4183 if (maybe_transition != NULL) { 4184 maybe_transition->DeprecateTransitionTree(); 4185 } 4186 4187 // If |maybe_transition| is not NULL then the transition array already 4188 // contains entry for given descriptor. This means that the transition 4189 // could be inserted regardless of whether transitions array is full or not. 4190 if (maybe_transition == NULL && 4191 !TransitionArray::CanHaveMoreTransitions(split_map)) { 4192 return CopyGeneralizeAllRepresentations( 4193 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, 4194 "GenAll_CantHaveMoreTransitions"); 4195 } 4196 4197 old_map->NotifyLeafMapLayoutChange(); 4198 4199 if (FLAG_trace_generalization && modify_index >= 0) { 4200 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); 4201 PropertyDetails new_details = new_descriptors->GetDetails(modify_index); 4202 MaybeHandle<FieldType> old_field_type; 4203 MaybeHandle<FieldType> new_field_type; 4204 MaybeHandle<Object> old_value; 4205 MaybeHandle<Object> new_value; 4206 if (old_details.type() == DATA) { 4207 old_field_type = 4208 handle(old_descriptors->GetFieldType(modify_index), isolate); 4209 } else { 4210 old_value = handle(old_descriptors->GetValue(modify_index), isolate); 4211 } 4212 if (new_details.type() == DATA) { 4213 new_field_type = 4214 handle(new_descriptors->GetFieldType(modify_index), isolate); 4215 } else { 4216 new_value = handle(new_descriptors->GetValue(modify_index), isolate); 4217 } 4218 4219 old_map->PrintGeneralization( 4220 stdout, "", modify_index, split_nof, old_nof, 4221 old_details.location() == kDescriptor && store_mode == FORCE_FIELD, 4222 old_details.representation(), new_details.representation(), 4223 old_field_type, old_value, new_field_type, new_value); 4224 } 4225 4226 Handle<LayoutDescriptor> new_layout_descriptor = 4227 LayoutDescriptor::New(split_map, new_descriptors, old_nof); 4228 4229 Handle<Map> new_map = 4230 AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor); 4231 4232 // Deprecated part of the transition tree is no longer reachable, so replace 4233 // current instance descriptors in the "survived" part of the tree with 4234 // the new descriptors to maintain descriptors sharing invariant. 4235 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor); 4236 return new_map; 4237 } 4238 4239 4240 // Generalize the representation of all DATA descriptors. 4241 Handle<Map> Map::GeneralizeAllFieldRepresentations( 4242 Handle<Map> map) { 4243 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 4244 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) { 4245 PropertyDetails details = descriptors->GetDetails(i); 4246 if (details.type() == DATA) { 4247 map = ReconfigureProperty(map, i, kData, details.attributes(), 4248 Representation::Tagged(), 4249 FieldType::Any(map->GetIsolate()), FORCE_FIELD); 4250 } 4251 } 4252 return map; 4253 } 4254 4255 4256 // static 4257 MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) { 4258 DisallowHeapAllocation no_allocation; 4259 DisallowDeoptimization no_deoptimization(old_map->GetIsolate()); 4260 4261 if (!old_map->is_deprecated()) return old_map; 4262 4263 // Check the state of the root map. 4264 Map* root_map = old_map->FindRootMap(); 4265 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>(); 4266 4267 ElementsKind from_kind = root_map->elements_kind(); 4268 ElementsKind to_kind = old_map->elements_kind(); 4269 if (from_kind != to_kind) { 4270 // Try to follow existing elements kind transitions. 4271 root_map = root_map->LookupElementsTransitionMap(to_kind); 4272 if (root_map == NULL) return MaybeHandle<Map>(); 4273 // From here on, use the map with correct elements kind as root map. 4274 } 4275 Map* new_map = root_map->TryReplayPropertyTransitions(*old_map); 4276 if (new_map == nullptr) return MaybeHandle<Map>(); 4277 return handle(new_map); 4278 } 4279 4280 Map* Map::TryReplayPropertyTransitions(Map* old_map) { 4281 DisallowHeapAllocation no_allocation; 4282 DisallowDeoptimization no_deoptimization(GetIsolate()); 4283 4284 int root_nof = NumberOfOwnDescriptors(); 4285 4286 int old_nof = old_map->NumberOfOwnDescriptors(); 4287 DescriptorArray* old_descriptors = old_map->instance_descriptors(); 4288 4289 Map* new_map = this; 4290 for (int i = root_nof; i < old_nof; ++i) { 4291 PropertyDetails old_details = old_descriptors->GetDetails(i); 4292 Map* transition = TransitionArray::SearchTransition( 4293 new_map, old_details.kind(), old_descriptors->GetKey(i), 4294 old_details.attributes()); 4295 if (transition == NULL) return nullptr; 4296 new_map = transition; 4297 DescriptorArray* new_descriptors = new_map->instance_descriptors(); 4298 4299 PropertyDetails new_details = new_descriptors->GetDetails(i); 4300 DCHECK_EQ(old_details.kind(), new_details.kind()); 4301 DCHECK_EQ(old_details.attributes(), new_details.attributes()); 4302 if (!old_details.representation().fits_into(new_details.representation())) { 4303 return nullptr; 4304 } 4305 switch (new_details.type()) { 4306 case DATA: { 4307 FieldType* new_type = new_descriptors->GetFieldType(i); 4308 // Cleared field types need special treatment. They represent lost 4309 // knowledge, so we must first generalize the new_type to "Any". 4310 if (FieldTypeIsCleared(new_details.representation(), new_type)) { 4311 return nullptr; 4312 } 4313 PropertyType old_property_type = old_details.type(); 4314 if (old_property_type == DATA) { 4315 FieldType* old_type = old_descriptors->GetFieldType(i); 4316 if (FieldTypeIsCleared(old_details.representation(), old_type) || 4317 !old_type->NowIs(new_type)) { 4318 return nullptr; 4319 } 4320 } else { 4321 DCHECK(old_property_type == DATA_CONSTANT); 4322 Object* old_value = old_descriptors->GetValue(i); 4323 if (!new_type->NowContains(old_value)) { 4324 return nullptr; 4325 } 4326 } 4327 break; 4328 } 4329 case ACCESSOR: { 4330 #ifdef DEBUG 4331 FieldType* new_type = new_descriptors->GetFieldType(i); 4332 DCHECK(new_type->IsAny()); 4333 #endif 4334 break; 4335 } 4336 4337 case DATA_CONSTANT: 4338 case ACCESSOR_CONSTANT: { 4339 Object* old_value = old_descriptors->GetValue(i); 4340 Object* new_value = new_descriptors->GetValue(i); 4341 if (old_details.location() == kField || old_value != new_value) { 4342 return nullptr; 4343 } 4344 break; 4345 } 4346 } 4347 } 4348 if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr; 4349 return new_map; 4350 } 4351 4352 4353 // static 4354 Handle<Map> Map::Update(Handle<Map> map) { 4355 if (!map->is_deprecated()) return map; 4356 return ReconfigureProperty(map, -1, kData, NONE, Representation::None(), 4357 FieldType::None(map->GetIsolate()), 4358 ALLOW_IN_DESCRIPTOR); 4359 } 4360 4361 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it, 4362 ShouldThrow should_throw, 4363 Handle<Object> value) { 4364 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 4365 return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(), 4366 should_throw, value); 4367 } 4368 4369 MaybeHandle<Object> Object::SetProperty(Handle<Object> object, 4370 Handle<Name> name, Handle<Object> value, 4371 LanguageMode language_mode, 4372 StoreFromKeyed store_mode) { 4373 LookupIterator it(object, name); 4374 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode)); 4375 return value; 4376 } 4377 4378 4379 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it, 4380 Handle<Object> value, 4381 LanguageMode language_mode, 4382 StoreFromKeyed store_mode, 4383 bool* found) { 4384 it->UpdateProtector(); 4385 DCHECK(it->IsFound()); 4386 ShouldThrow should_throw = 4387 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4388 4389 // Make sure that the top context does not change when doing callbacks or 4390 // interceptor calls. 4391 AssertNoContextChange ncc(it->isolate()); 4392 4393 do { 4394 switch (it->state()) { 4395 case LookupIterator::NOT_FOUND: 4396 UNREACHABLE(); 4397 4398 case LookupIterator::ACCESS_CHECK: 4399 if (it->HasAccess()) break; 4400 // Check whether it makes sense to reuse the lookup iterator. Here it 4401 // might still call into setters up the prototype chain. 4402 return JSObject::SetPropertyWithFailedAccessCheck(it, value, 4403 should_throw); 4404 4405 case LookupIterator::JSPROXY: 4406 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(), 4407 value, it->GetReceiver(), language_mode); 4408 4409 case LookupIterator::INTERCEPTOR: { 4410 Handle<Map> store_target_map; 4411 if (it->GetReceiver()->IsJSObject()) { 4412 store_target_map = handle(it->GetStoreTarget()->map(), it->isolate()); 4413 } 4414 if (it->HolderIsReceiverOrHiddenPrototype()) { 4415 Maybe<bool> result = 4416 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 4417 if (result.IsNothing() || result.FromJust()) return result; 4418 // Interceptor modified the store target but failed to set the 4419 // property. 4420 Utils::ApiCheck(store_target_map.is_null() || 4421 *store_target_map == it->GetStoreTarget()->map(), 4422 it->IsElement() ? "v8::IndexedPropertySetterCallback" 4423 : "v8::NamedPropertySetterCallback", 4424 "Interceptor silently changed store target."); 4425 } else { 4426 Maybe<PropertyAttributes> maybe_attributes = 4427 JSObject::GetPropertyAttributesWithInterceptor(it); 4428 if (!maybe_attributes.IsJust()) return Nothing<bool>(); 4429 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) { 4430 return WriteToReadOnlyProperty(it, value, should_throw); 4431 } 4432 // Interceptor modified the store target but failed to set the 4433 // property. 4434 Utils::ApiCheck(store_target_map.is_null() || 4435 *store_target_map == it->GetStoreTarget()->map(), 4436 it->IsElement() ? "v8::IndexedPropertySetterCallback" 4437 : "v8::NamedPropertySetterCallback", 4438 "Interceptor silently changed store target."); 4439 if (maybe_attributes.FromJust() == ABSENT) break; 4440 *found = false; 4441 return Nothing<bool>(); 4442 } 4443 break; 4444 } 4445 4446 case LookupIterator::ACCESSOR: { 4447 if (it->IsReadOnly()) { 4448 return WriteToReadOnlyProperty(it, value, should_throw); 4449 } 4450 Handle<Object> accessors = it->GetAccessors(); 4451 if (accessors->IsAccessorInfo() && 4452 !it->HolderIsReceiverOrHiddenPrototype() && 4453 AccessorInfo::cast(*accessors)->is_special_data_property()) { 4454 *found = false; 4455 return Nothing<bool>(); 4456 } 4457 return SetPropertyWithAccessor(it, value, should_throw); 4458 } 4459 case LookupIterator::INTEGER_INDEXED_EXOTIC: 4460 // TODO(verwaest): We should throw an exception if holder is receiver. 4461 return Just(true); 4462 4463 case LookupIterator::DATA: 4464 if (it->IsReadOnly()) { 4465 return WriteToReadOnlyProperty(it, value, should_throw); 4466 } 4467 if (it->HolderIsReceiverOrHiddenPrototype()) { 4468 return SetDataProperty(it, value); 4469 } 4470 // Fall through. 4471 case LookupIterator::TRANSITION: 4472 *found = false; 4473 return Nothing<bool>(); 4474 } 4475 it->Next(); 4476 } while (it->IsFound()); 4477 4478 *found = false; 4479 return Nothing<bool>(); 4480 } 4481 4482 4483 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value, 4484 LanguageMode language_mode, 4485 StoreFromKeyed store_mode) { 4486 if (it->IsFound()) { 4487 bool found = true; 4488 Maybe<bool> result = 4489 SetPropertyInternal(it, value, language_mode, store_mode, &found); 4490 if (found) return result; 4491 } 4492 4493 // If the receiver is the JSGlobalObject, the store was contextual. In case 4494 // the property did not exist yet on the global object itself, we have to 4495 // throw a reference error in strict mode. In sloppy mode, we continue. 4496 if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) { 4497 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError( 4498 MessageTemplate::kNotDefined, it->name())); 4499 return Nothing<bool>(); 4500 } 4501 4502 ShouldThrow should_throw = 4503 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4504 return AddDataProperty(it, value, NONE, should_throw, store_mode); 4505 } 4506 4507 4508 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, 4509 LanguageMode language_mode, 4510 StoreFromKeyed store_mode) { 4511 Isolate* isolate = it->isolate(); 4512 4513 if (it->IsFound()) { 4514 bool found = true; 4515 Maybe<bool> result = 4516 SetPropertyInternal(it, value, language_mode, store_mode, &found); 4517 if (found) return result; 4518 } 4519 4520 it->UpdateProtector(); 4521 4522 // The property either doesn't exist on the holder or exists there as a data 4523 // property. 4524 4525 ShouldThrow should_throw = 4526 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 4527 4528 if (!it->GetReceiver()->IsJSReceiver()) { 4529 return WriteToReadOnlyProperty(it, value, should_throw); 4530 } 4531 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 4532 4533 LookupIterator::Configuration c = LookupIterator::OWN; 4534 LookupIterator own_lookup = 4535 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c) 4536 : LookupIterator(receiver, it->name(), c); 4537 4538 for (; own_lookup.IsFound(); own_lookup.Next()) { 4539 switch (own_lookup.state()) { 4540 case LookupIterator::ACCESS_CHECK: 4541 if (!own_lookup.HasAccess()) { 4542 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value, 4543 should_throw); 4544 } 4545 break; 4546 4547 case LookupIterator::ACCESSOR: 4548 if (own_lookup.GetAccessors()->IsAccessorInfo()) { 4549 if (own_lookup.IsReadOnly()) { 4550 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 4551 } 4552 return JSObject::SetPropertyWithAccessor(&own_lookup, value, 4553 should_throw); 4554 } 4555 // Fall through. 4556 case LookupIterator::INTEGER_INDEXED_EXOTIC: 4557 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 4558 should_throw); 4559 4560 case LookupIterator::DATA: { 4561 if (own_lookup.IsReadOnly()) { 4562 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 4563 } 4564 return SetDataProperty(&own_lookup, value); 4565 } 4566 4567 case LookupIterator::INTERCEPTOR: 4568 case LookupIterator::JSPROXY: { 4569 PropertyDescriptor desc; 4570 Maybe<bool> owned = 4571 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc); 4572 MAYBE_RETURN(owned, Nothing<bool>()); 4573 if (!owned.FromJust()) { 4574 return JSReceiver::CreateDataProperty(&own_lookup, value, 4575 should_throw); 4576 } 4577 if (PropertyDescriptor::IsAccessorDescriptor(&desc) || 4578 !desc.writable()) { 4579 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 4580 should_throw); 4581 } 4582 4583 PropertyDescriptor value_desc; 4584 value_desc.set_value(value); 4585 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 4586 &value_desc, should_throw); 4587 } 4588 4589 case LookupIterator::NOT_FOUND: 4590 case LookupIterator::TRANSITION: 4591 UNREACHABLE(); 4592 } 4593 } 4594 4595 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode); 4596 } 4597 4598 MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it) { 4599 return it->isolate()->factory()->undefined_value(); 4600 } 4601 4602 MaybeHandle<Object> Object::ReadAbsentProperty(Isolate* isolate, 4603 Handle<Object> receiver, 4604 Handle<Object> name) { 4605 return isolate->factory()->undefined_value(); 4606 } 4607 4608 4609 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate, 4610 Handle<Object> receiver, 4611 Handle<Object> name, 4612 Handle<Object> value, 4613 ShouldThrow should_throw) { 4614 RETURN_FAILURE( 4615 isolate, should_throw, 4616 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name, 4617 Object::TypeOf(isolate, receiver), receiver)); 4618 } 4619 4620 4621 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it, 4622 Handle<Object> value, 4623 ShouldThrow should_throw) { 4624 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), 4625 it->GetName(), value, should_throw); 4626 } 4627 4628 4629 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate, 4630 Handle<Object> receiver, 4631 Handle<Object> name, 4632 Handle<Object> value, 4633 ShouldThrow should_throw) { 4634 RETURN_FAILURE(isolate, should_throw, 4635 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name, 4636 Object::TypeOf(isolate, receiver), receiver)); 4637 } 4638 4639 4640 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate, 4641 Handle<Object> name, 4642 Handle<Object> value, 4643 ShouldThrow should_throw) { 4644 RETURN_FAILURE(isolate, should_throw, 4645 NewTypeError(MessageTemplate::kRedefineDisallowed, name)); 4646 } 4647 4648 4649 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { 4650 // Proxies are handled elsewhere. Other non-JSObjects cannot have own 4651 // properties. 4652 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); 4653 4654 // Store on the holder which may be hidden behind the receiver. 4655 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); 4656 4657 Handle<Object> to_assign = value; 4658 // Convert the incoming value to a number for storing into typed arrays. 4659 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) { 4660 if (!value->IsNumber() && !value->IsUndefined(it->isolate())) { 4661 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 4662 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>()); 4663 // We have to recheck the length. However, it can only change if the 4664 // underlying buffer was neutered, so just check that. 4665 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) { 4666 return Just(true); 4667 // TODO(neis): According to the spec, this should throw a TypeError. 4668 } 4669 } 4670 } 4671 4672 // Possibly migrate to the most up-to-date map that will be able to store 4673 // |value| under it->name(). 4674 it->PrepareForDataProperty(to_assign); 4675 4676 // Write the property value. 4677 it->WriteDataValue(to_assign); 4678 4679 #if VERIFY_HEAP 4680 if (FLAG_verify_heap) { 4681 receiver->JSObjectVerify(); 4682 } 4683 #endif 4684 return Just(true); 4685 } 4686 4687 4688 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, 4689 PropertyAttributes attributes, 4690 ShouldThrow should_throw, 4691 StoreFromKeyed store_mode) { 4692 if (!it->GetReceiver()->IsJSObject()) { 4693 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) { 4694 RETURN_FAILURE(it->isolate(), should_throw, 4695 NewTypeError(MessageTemplate::kProxyPrivate)); 4696 } 4697 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(), 4698 value, should_throw); 4699 } 4700 4701 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state()); 4702 4703 Handle<JSObject> receiver = it->GetStoreTarget(); 4704 4705 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) 4706 // instead. If the prototype is Null, the proxy is detached. 4707 if (receiver->IsJSGlobalProxy()) return Just(true); 4708 4709 Isolate* isolate = it->isolate(); 4710 4711 if (it->ExtendingNonExtensible(receiver)) { 4712 RETURN_FAILURE( 4713 isolate, should_throw, 4714 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName())); 4715 } 4716 4717 if (it->IsElement()) { 4718 if (receiver->IsJSArray()) { 4719 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 4720 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) { 4721 RETURN_FAILURE(array->GetIsolate(), should_throw, 4722 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, 4723 isolate->factory()->length_string(), 4724 Object::TypeOf(isolate, array), array)); 4725 } 4726 4727 if (FLAG_trace_external_array_abuse && 4728 array->HasFixedTypedArrayElements()) { 4729 CheckArrayAbuse(array, "typed elements write", it->index(), true); 4730 } 4731 4732 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) { 4733 CheckArrayAbuse(array, "elements write", it->index(), false); 4734 } 4735 } 4736 4737 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value, 4738 attributes, should_throw); 4739 JSObject::ValidateElements(receiver); 4740 return result; 4741 } else { 4742 it->UpdateProtector(); 4743 // Migrate to the most up-to-date map that will be able to store |value| 4744 // under it->name() with |attributes|. 4745 it->PrepareTransitionToDataProperty(receiver, value, attributes, 4746 store_mode); 4747 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); 4748 it->ApplyTransitionToDataProperty(receiver); 4749 4750 // TODO(verwaest): Encapsulate dictionary handling better. 4751 if (receiver->map()->is_dictionary_map()) { 4752 // TODO(dcarney): just populate TransitionPropertyCell here? 4753 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); 4754 } else { 4755 // Write the property value. 4756 it->WriteDataValue(value); 4757 } 4758 4759 #if VERIFY_HEAP 4760 if (FLAG_verify_heap) { 4761 receiver->JSObjectVerify(); 4762 } 4763 #endif 4764 } 4765 4766 return Just(true); 4767 } 4768 4769 4770 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { 4771 // Only supports adding slack to owned descriptors. 4772 DCHECK(map->owns_descriptors()); 4773 4774 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 4775 int old_size = map->NumberOfOwnDescriptors(); 4776 if (slack <= descriptors->NumberOfSlackDescriptors()) return; 4777 4778 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 4779 descriptors, old_size, slack); 4780 4781 DisallowHeapAllocation no_allocation; 4782 // The descriptors are still the same, so keep the layout descriptor. 4783 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor(); 4784 4785 if (old_size == 0) { 4786 map->UpdateDescriptors(*new_descriptors, layout_descriptor); 4787 return; 4788 } 4789 4790 // If the source descriptors had an enum cache we copy it. This ensures 4791 // that the maps to which we push the new descriptor array back can rely 4792 // on a cache always being available once it is set. If the map has more 4793 // enumerated descriptors than available in the original cache, the cache 4794 // will be lazily replaced by the extended cache when needed. 4795 if (descriptors->HasEnumCache()) { 4796 new_descriptors->CopyEnumCacheFrom(*descriptors); 4797 } 4798 4799 Isolate* isolate = map->GetIsolate(); 4800 // Replace descriptors by new_descriptors in all maps that share it. 4801 isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors); 4802 4803 Map* current = *map; 4804 while (current->instance_descriptors() == *descriptors) { 4805 Object* next = current->GetBackPointer(); 4806 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map. 4807 current->UpdateDescriptors(*new_descriptors, layout_descriptor); 4808 current = Map::cast(next); 4809 } 4810 map->UpdateDescriptors(*new_descriptors, layout_descriptor); 4811 } 4812 4813 4814 template<class T> 4815 static int AppendUniqueCallbacks(NeanderArray* callbacks, 4816 Handle<typename T::Array> array, 4817 int valid_descriptors) { 4818 int nof_callbacks = callbacks->length(); 4819 4820 Isolate* isolate = array->GetIsolate(); 4821 // Ensure the keys are unique names before writing them into the 4822 // instance descriptor. Since it may cause a GC, it has to be done before we 4823 // temporarily put the heap in an invalid state while appending descriptors. 4824 for (int i = 0; i < nof_callbacks; ++i) { 4825 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i))); 4826 if (entry->name()->IsUniqueName()) continue; 4827 Handle<String> key = 4828 isolate->factory()->InternalizeString( 4829 Handle<String>(String::cast(entry->name()))); 4830 entry->set_name(*key); 4831 } 4832 4833 // Fill in new callback descriptors. Process the callbacks from 4834 // back to front so that the last callback with a given name takes 4835 // precedence over previously added callbacks with that name. 4836 for (int i = nof_callbacks - 1; i >= 0; i--) { 4837 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i))); 4838 Handle<Name> key(Name::cast(entry->name())); 4839 // Check if a descriptor with this name already exists before writing. 4840 if (!T::Contains(key, entry, valid_descriptors, array)) { 4841 T::Insert(key, entry, valid_descriptors, array); 4842 valid_descriptors++; 4843 } 4844 } 4845 4846 return valid_descriptors; 4847 } 4848 4849 struct DescriptorArrayAppender { 4850 typedef DescriptorArray Array; 4851 static bool Contains(Handle<Name> key, 4852 Handle<AccessorInfo> entry, 4853 int valid_descriptors, 4854 Handle<DescriptorArray> array) { 4855 DisallowHeapAllocation no_gc; 4856 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound; 4857 } 4858 static void Insert(Handle<Name> key, 4859 Handle<AccessorInfo> entry, 4860 int valid_descriptors, 4861 Handle<DescriptorArray> array) { 4862 DisallowHeapAllocation no_gc; 4863 AccessorConstantDescriptor desc(key, entry, entry->property_attributes()); 4864 array->Append(&desc); 4865 } 4866 }; 4867 4868 4869 struct FixedArrayAppender { 4870 typedef FixedArray Array; 4871 static bool Contains(Handle<Name> key, 4872 Handle<AccessorInfo> entry, 4873 int valid_descriptors, 4874 Handle<FixedArray> array) { 4875 for (int i = 0; i < valid_descriptors; i++) { 4876 if (*key == AccessorInfo::cast(array->get(i))->name()) return true; 4877 } 4878 return false; 4879 } 4880 static void Insert(Handle<Name> key, 4881 Handle<AccessorInfo> entry, 4882 int valid_descriptors, 4883 Handle<FixedArray> array) { 4884 DisallowHeapAllocation no_gc; 4885 array->set(valid_descriptors, *entry); 4886 } 4887 }; 4888 4889 4890 void Map::AppendCallbackDescriptors(Handle<Map> map, 4891 Handle<Object> descriptors) { 4892 int nof = map->NumberOfOwnDescriptors(); 4893 Handle<DescriptorArray> array(map->instance_descriptors()); 4894 NeanderArray callbacks(descriptors); 4895 DCHECK(array->NumberOfSlackDescriptors() >= callbacks.length()); 4896 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof); 4897 map->SetNumberOfOwnDescriptors(nof); 4898 } 4899 4900 4901 int AccessorInfo::AppendUnique(Handle<Object> descriptors, 4902 Handle<FixedArray> array, 4903 int valid_descriptors) { 4904 NeanderArray callbacks(descriptors); 4905 DCHECK(array->length() >= callbacks.length() + valid_descriptors); 4906 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks, 4907 array, 4908 valid_descriptors); 4909 } 4910 4911 4912 static bool ContainsMap(MapHandleList* maps, Map* map) { 4913 DCHECK_NOT_NULL(map); 4914 for (int i = 0; i < maps->length(); ++i) { 4915 if (!maps->at(i).is_null() && *maps->at(i) == map) return true; 4916 } 4917 return false; 4918 } 4919 4920 Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) { 4921 DisallowHeapAllocation no_allocation; 4922 DisallowDeoptimization no_deoptimization(GetIsolate()); 4923 4924 ElementsKind kind = elements_kind(); 4925 bool packed = IsFastPackedElementsKind(kind); 4926 4927 Map* transition = nullptr; 4928 if (IsTransitionableFastElementsKind(kind)) { 4929 // Check the state of the root map. 4930 Map* root_map = FindRootMap(); 4931 if (!EquivalentToForTransition(root_map)) return nullptr; 4932 root_map = root_map->LookupElementsTransitionMap(kind); 4933 DCHECK_NOT_NULL(root_map); 4934 // Starting from the next existing elements kind transition try to 4935 // replay the property transitions that does not involve instance rewriting 4936 // (ElementsTransitionAndStoreStub does not support that). 4937 for (root_map = root_map->ElementsTransitionMap(); 4938 root_map != nullptr && root_map->has_fast_elements(); 4939 root_map = root_map->ElementsTransitionMap()) { 4940 Map* current = root_map->TryReplayPropertyTransitions(this); 4941 if (current == nullptr) continue; 4942 if (InstancesNeedRewriting(current)) continue; 4943 4944 if (ContainsMap(candidates, current) && 4945 (packed || !IsFastPackedElementsKind(current->elements_kind()))) { 4946 transition = current; 4947 packed = packed && IsFastPackedElementsKind(current->elements_kind()); 4948 } 4949 } 4950 } 4951 return transition; 4952 } 4953 4954 4955 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { 4956 // Ensure we are requested to search elements kind transition "near the root". 4957 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(), 4958 map->NumberOfOwnDescriptors()); 4959 Map* current_map = map; 4960 4961 ElementsKind kind = map->elements_kind(); 4962 while (kind != to_kind) { 4963 Map* next_map = current_map->ElementsTransitionMap(); 4964 if (next_map == nullptr) return current_map; 4965 kind = next_map->elements_kind(); 4966 current_map = next_map; 4967 } 4968 4969 DCHECK_EQ(to_kind, current_map->elements_kind()); 4970 return current_map; 4971 } 4972 4973 4974 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { 4975 Map* to_map = FindClosestElementsTransition(this, to_kind); 4976 if (to_map->elements_kind() == to_kind) return to_map; 4977 return nullptr; 4978 } 4979 4980 4981 bool Map::IsMapInArrayPrototypeChain() { 4982 Isolate* isolate = GetIsolate(); 4983 if (isolate->initial_array_prototype()->map() == this) { 4984 return true; 4985 } 4986 4987 if (isolate->initial_object_prototype()->map() == this) { 4988 return true; 4989 } 4990 4991 return false; 4992 } 4993 4994 4995 Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) { 4996 Isolate* isolate = map->GetIsolate(); 4997 if (map->weak_cell_cache()->IsWeakCell()) { 4998 return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache())); 4999 } 5000 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map); 5001 map->set_weak_cell_cache(*weak_cell); 5002 return weak_cell; 5003 } 5004 5005 5006 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map, 5007 ElementsKind to_kind) { 5008 DCHECK(IsTransitionElementsKind(map->elements_kind())); 5009 5010 Handle<Map> current_map = map; 5011 5012 ElementsKind kind = map->elements_kind(); 5013 TransitionFlag flag; 5014 if (map->is_prototype_map()) { 5015 flag = OMIT_TRANSITION; 5016 } else { 5017 flag = INSERT_TRANSITION; 5018 if (IsFastElementsKind(kind)) { 5019 while (kind != to_kind && !IsTerminalElementsKind(kind)) { 5020 kind = GetNextTransitionElementsKind(kind); 5021 current_map = Map::CopyAsElementsKind(current_map, kind, flag); 5022 } 5023 } 5024 } 5025 5026 // In case we are exiting the fast elements kind system, just add the map in 5027 // the end. 5028 if (kind != to_kind) { 5029 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag); 5030 } 5031 5032 DCHECK(current_map->elements_kind() == to_kind); 5033 return current_map; 5034 } 5035 5036 5037 Handle<Map> Map::TransitionElementsTo(Handle<Map> map, 5038 ElementsKind to_kind) { 5039 ElementsKind from_kind = map->elements_kind(); 5040 if (from_kind == to_kind) return map; 5041 5042 Isolate* isolate = map->GetIsolate(); 5043 Context* native_context = isolate->context()->native_context(); 5044 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) { 5045 if (*map == native_context->fast_aliased_arguments_map()) { 5046 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); 5047 return handle(native_context->slow_aliased_arguments_map()); 5048 } 5049 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) { 5050 if (*map == native_context->slow_aliased_arguments_map()) { 5051 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); 5052 return handle(native_context->fast_aliased_arguments_map()); 5053 } 5054 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { 5055 // Reuse map transitions for JSArrays. 5056 DisallowHeapAllocation no_gc; 5057 if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) { 5058 Object* maybe_transitioned_map = 5059 native_context->get(Context::ArrayMapIndex(to_kind)); 5060 if (maybe_transitioned_map->IsMap()) { 5061 return handle(Map::cast(maybe_transitioned_map), isolate); 5062 } 5063 } 5064 } 5065 5066 DCHECK(!map->IsUndefined(isolate)); 5067 // Check if we can go back in the elements kind transition chain. 5068 if (IsHoleyElementsKind(from_kind) && 5069 to_kind == GetPackedElementsKind(from_kind) && 5070 map->GetBackPointer()->IsMap() && 5071 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) { 5072 return handle(Map::cast(map->GetBackPointer())); 5073 } 5074 5075 bool allow_store_transition = IsTransitionElementsKind(from_kind); 5076 // Only store fast element maps in ascending generality. 5077 if (IsFastElementsKind(to_kind)) { 5078 allow_store_transition = 5079 allow_store_transition && IsTransitionableFastElementsKind(from_kind) && 5080 IsMoreGeneralElementsKindTransition(from_kind, to_kind); 5081 } 5082 5083 if (!allow_store_transition) { 5084 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION); 5085 } 5086 5087 return Map::ReconfigureElementsKind(map, to_kind); 5088 } 5089 5090 5091 // static 5092 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) { 5093 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind)); 5094 5095 if (closest_map->elements_kind() == kind) { 5096 return closest_map; 5097 } 5098 5099 return AddMissingElementsTransitions(closest_map, kind); 5100 } 5101 5102 5103 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, 5104 ElementsKind to_kind) { 5105 Handle<Map> map(object->map()); 5106 return Map::TransitionElementsTo(map, to_kind); 5107 } 5108 5109 5110 void JSProxy::Revoke(Handle<JSProxy> proxy) { 5111 Isolate* isolate = proxy->GetIsolate(); 5112 if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value()); 5113 DCHECK(proxy->IsRevoked()); 5114 } 5115 5116 5117 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy, 5118 Handle<Name> name) { 5119 DCHECK(!name->IsPrivate()); 5120 STACK_CHECK(isolate, Nothing<bool>()); 5121 // 1. (Assert) 5122 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 5123 Handle<Object> handler(proxy->handler(), isolate); 5124 // 3. If handler is null, throw a TypeError exception. 5125 // 4. Assert: Type(handler) is Object. 5126 if (proxy->IsRevoked()) { 5127 isolate->Throw(*isolate->factory()->NewTypeError( 5128 MessageTemplate::kProxyRevoked, isolate->factory()->has_string())); 5129 return Nothing<bool>(); 5130 } 5131 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 5132 Handle<JSReceiver> target(proxy->target(), isolate); 5133 // 6. Let trap be ? GetMethod(handler, "has"). 5134 Handle<Object> trap; 5135 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5136 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), 5137 isolate->factory()->has_string()), 5138 Nothing<bool>()); 5139 // 7. If trap is undefined, then 5140 if (trap->IsUndefined(isolate)) { 5141 // 7a. Return target.[[HasProperty]](P). 5142 return JSReceiver::HasProperty(target, name); 5143 } 5144 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, target, P)). 5145 Handle<Object> trap_result_obj; 5146 Handle<Object> args[] = {target, name}; 5147 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5148 isolate, trap_result_obj, 5149 Execution::Call(isolate, trap, handler, arraysize(args), args), 5150 Nothing<bool>()); 5151 bool boolean_trap_result = trap_result_obj->BooleanValue(); 5152 // 9. If booleanTrapResult is false, then: 5153 if (!boolean_trap_result) { 5154 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P). 5155 PropertyDescriptor target_desc; 5156 Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor( 5157 isolate, target, name, &target_desc); 5158 MAYBE_RETURN(target_found, Nothing<bool>()); 5159 // 9b. If targetDesc is not undefined, then: 5160 if (target_found.FromJust()) { 5161 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError 5162 // exception. 5163 if (!target_desc.configurable()) { 5164 isolate->Throw(*isolate->factory()->NewTypeError( 5165 MessageTemplate::kProxyHasNonConfigurable, name)); 5166 return Nothing<bool>(); 5167 } 5168 // 9b ii. Let extensibleTarget be ? IsExtensible(target). 5169 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 5170 MAYBE_RETURN(extensible_target, Nothing<bool>()); 5171 // 9b iii. If extensibleTarget is false, throw a TypeError exception. 5172 if (!extensible_target.FromJust()) { 5173 isolate->Throw(*isolate->factory()->NewTypeError( 5174 MessageTemplate::kProxyHasNonExtensible, name)); 5175 return Nothing<bool>(); 5176 } 5177 } 5178 } 5179 // 10. Return booleanTrapResult. 5180 return Just(boolean_trap_result); 5181 } 5182 5183 5184 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name, 5185 Handle<Object> value, Handle<Object> receiver, 5186 LanguageMode language_mode) { 5187 DCHECK(!name->IsPrivate()); 5188 Isolate* isolate = proxy->GetIsolate(); 5189 STACK_CHECK(isolate, Nothing<bool>()); 5190 Factory* factory = isolate->factory(); 5191 Handle<String> trap_name = factory->set_string(); 5192 ShouldThrow should_throw = 5193 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 5194 5195 if (proxy->IsRevoked()) { 5196 isolate->Throw( 5197 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 5198 return Nothing<bool>(); 5199 } 5200 Handle<JSReceiver> target(proxy->target(), isolate); 5201 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 5202 5203 Handle<Object> trap; 5204 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5205 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 5206 if (trap->IsUndefined(isolate)) { 5207 LookupIterator it = 5208 LookupIterator::PropertyOrElement(isolate, receiver, name, target); 5209 return Object::SetSuperProperty(&it, value, language_mode, 5210 Object::MAY_BE_STORE_FROM_KEYED); 5211 } 5212 5213 Handle<Object> trap_result; 5214 Handle<Object> args[] = {target, name, value, receiver}; 5215 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5216 isolate, trap_result, 5217 Execution::Call(isolate, trap, handler, arraysize(args), args), 5218 Nothing<bool>()); 5219 if (!trap_result->BooleanValue()) { 5220 RETURN_FAILURE(isolate, should_throw, 5221 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 5222 trap_name, name)); 5223 } 5224 5225 // Enforce the invariant. 5226 PropertyDescriptor target_desc; 5227 Maybe<bool> owned = 5228 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 5229 MAYBE_RETURN(owned, Nothing<bool>()); 5230 if (owned.FromJust()) { 5231 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && 5232 !target_desc.configurable() && 5233 !target_desc.writable() && 5234 !value->SameValue(*target_desc.value()); 5235 if (inconsistent) { 5236 isolate->Throw(*isolate->factory()->NewTypeError( 5237 MessageTemplate::kProxySetFrozenData, name)); 5238 return Nothing<bool>(); 5239 } 5240 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 5241 !target_desc.configurable() && 5242 target_desc.set()->IsUndefined(isolate); 5243 if (inconsistent) { 5244 isolate->Throw(*isolate->factory()->NewTypeError( 5245 MessageTemplate::kProxySetFrozenAccessor, name)); 5246 return Nothing<bool>(); 5247 } 5248 } 5249 return Just(true); 5250 } 5251 5252 5253 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy, 5254 Handle<Name> name, 5255 LanguageMode language_mode) { 5256 DCHECK(!name->IsPrivate()); 5257 ShouldThrow should_throw = 5258 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 5259 Isolate* isolate = proxy->GetIsolate(); 5260 STACK_CHECK(isolate, Nothing<bool>()); 5261 Factory* factory = isolate->factory(); 5262 Handle<String> trap_name = factory->deleteProperty_string(); 5263 5264 if (proxy->IsRevoked()) { 5265 isolate->Throw( 5266 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 5267 return Nothing<bool>(); 5268 } 5269 Handle<JSReceiver> target(proxy->target(), isolate); 5270 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 5271 5272 Handle<Object> trap; 5273 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5274 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 5275 if (trap->IsUndefined(isolate)) { 5276 return JSReceiver::DeletePropertyOrElement(target, name, language_mode); 5277 } 5278 5279 Handle<Object> trap_result; 5280 Handle<Object> args[] = {target, name}; 5281 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5282 isolate, trap_result, 5283 Execution::Call(isolate, trap, handler, arraysize(args), args), 5284 Nothing<bool>()); 5285 if (!trap_result->BooleanValue()) { 5286 RETURN_FAILURE(isolate, should_throw, 5287 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 5288 trap_name, name)); 5289 } 5290 5291 // Enforce the invariant. 5292 PropertyDescriptor target_desc; 5293 Maybe<bool> owned = 5294 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 5295 MAYBE_RETURN(owned, Nothing<bool>()); 5296 if (owned.FromJust() && !target_desc.configurable()) { 5297 isolate->Throw(*factory->NewTypeError( 5298 MessageTemplate::kProxyDeletePropertyNonConfigurable, name)); 5299 return Nothing<bool>(); 5300 } 5301 return Just(true); 5302 } 5303 5304 5305 // static 5306 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target, 5307 Handle<Object> handler) { 5308 if (!target->IsJSReceiver()) { 5309 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 5310 JSProxy); 5311 } 5312 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) { 5313 THROW_NEW_ERROR(isolate, 5314 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked), 5315 JSProxy); 5316 } 5317 if (!handler->IsJSReceiver()) { 5318 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 5319 JSProxy); 5320 } 5321 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) { 5322 THROW_NEW_ERROR(isolate, 5323 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked), 5324 JSProxy); 5325 } 5326 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target), 5327 Handle<JSReceiver>::cast(handler)); 5328 } 5329 5330 5331 // static 5332 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) { 5333 DCHECK(proxy->map()->is_constructor()); 5334 if (proxy->IsRevoked()) { 5335 THROW_NEW_ERROR(proxy->GetIsolate(), 5336 NewTypeError(MessageTemplate::kProxyRevoked), Context); 5337 } 5338 Handle<JSReceiver> target(JSReceiver::cast(proxy->target())); 5339 return JSReceiver::GetFunctionRealm(target); 5340 } 5341 5342 5343 // static 5344 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm( 5345 Handle<JSBoundFunction> function) { 5346 DCHECK(function->map()->is_constructor()); 5347 return JSReceiver::GetFunctionRealm( 5348 handle(function->bound_target_function())); 5349 } 5350 5351 // static 5352 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate, 5353 Handle<JSBoundFunction> function) { 5354 Handle<String> prefix = isolate->factory()->bound__string(); 5355 if (!function->bound_target_function()->IsJSFunction()) return prefix; 5356 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()), 5357 isolate); 5358 Handle<Object> target_name = JSFunction::GetName(isolate, target); 5359 if (!target_name->IsString()) return prefix; 5360 Factory* factory = isolate->factory(); 5361 return factory->NewConsString(prefix, Handle<String>::cast(target_name)); 5362 } 5363 5364 // static 5365 Handle<Object> JSFunction::GetName(Isolate* isolate, 5366 Handle<JSFunction> function) { 5367 if (function->shared()->name_should_print_as_anonymous()) { 5368 return isolate->factory()->anonymous_string(); 5369 } 5370 return handle(function->shared()->name(), isolate); 5371 } 5372 5373 // static 5374 MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate, 5375 Handle<JSFunction> function) { 5376 int length = 0; 5377 if (function->shared()->is_compiled()) { 5378 length = function->shared()->length(); 5379 } else { 5380 // If the function isn't compiled yet, the length is not computed 5381 // correctly yet. Compile it now and return the right length. 5382 if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) { 5383 length = function->shared()->length(); 5384 } 5385 if (isolate->has_pending_exception()) return MaybeHandle<Smi>(); 5386 } 5387 return handle(Smi::FromInt(length), isolate); 5388 } 5389 5390 // static 5391 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) { 5392 DCHECK(function->map()->is_constructor()); 5393 return handle(function->context()->native_context()); 5394 } 5395 5396 5397 // static 5398 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) { 5399 DCHECK(object->map()->is_constructor()); 5400 DCHECK(!object->IsJSFunction()); 5401 return handle(object->GetCreationContext()); 5402 } 5403 5404 5405 // static 5406 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) { 5407 if (receiver->IsJSProxy()) { 5408 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver)); 5409 } 5410 5411 if (receiver->IsJSFunction()) { 5412 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver)); 5413 } 5414 5415 if (receiver->IsJSBoundFunction()) { 5416 return JSBoundFunction::GetFunctionRealm( 5417 Handle<JSBoundFunction>::cast(receiver)); 5418 } 5419 5420 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver)); 5421 } 5422 5423 5424 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) { 5425 PropertyDescriptor desc; 5426 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor( 5427 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc); 5428 MAYBE_RETURN(found, Nothing<PropertyAttributes>()); 5429 if (!found.FromJust()) return Just(ABSENT); 5430 return Just(desc.ToAttributes()); 5431 } 5432 5433 5434 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { 5435 DCHECK(object->map()->GetInObjectProperties() == 5436 map->GetInObjectProperties()); 5437 ElementsKind obj_kind = object->map()->elements_kind(); 5438 ElementsKind map_kind = map->elements_kind(); 5439 if (map_kind != obj_kind) { 5440 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind); 5441 if (IsDictionaryElementsKind(obj_kind)) { 5442 to_kind = obj_kind; 5443 } 5444 if (IsDictionaryElementsKind(to_kind)) { 5445 NormalizeElements(object); 5446 } else { 5447 TransitionElementsKind(object, to_kind); 5448 } 5449 map = Map::ReconfigureElementsKind(map, to_kind); 5450 } 5451 JSObject::MigrateToMap(object, map); 5452 } 5453 5454 5455 void JSObject::MigrateInstance(Handle<JSObject> object) { 5456 Handle<Map> original_map(object->map()); 5457 Handle<Map> map = Map::Update(original_map); 5458 map->set_migration_target(true); 5459 MigrateToMap(object, map); 5460 if (FLAG_trace_migration) { 5461 object->PrintInstanceMigration(stdout, *original_map, *map); 5462 } 5463 #if VERIFY_HEAP 5464 if (FLAG_verify_heap) { 5465 object->JSObjectVerify(); 5466 } 5467 #endif 5468 } 5469 5470 5471 // static 5472 bool JSObject::TryMigrateInstance(Handle<JSObject> object) { 5473 Isolate* isolate = object->GetIsolate(); 5474 DisallowDeoptimization no_deoptimization(isolate); 5475 Handle<Map> original_map(object->map(), isolate); 5476 Handle<Map> new_map; 5477 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) { 5478 return false; 5479 } 5480 JSObject::MigrateToMap(object, new_map); 5481 if (FLAG_trace_migration) { 5482 object->PrintInstanceMigration(stdout, *original_map, object->map()); 5483 } 5484 #if VERIFY_HEAP 5485 if (FLAG_verify_heap) { 5486 object->JSObjectVerify(); 5487 } 5488 #endif 5489 return true; 5490 } 5491 5492 5493 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name, 5494 Handle<Object> value, 5495 PropertyAttributes attributes) { 5496 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR); 5497 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); 5498 #ifdef DEBUG 5499 uint32_t index; 5500 DCHECK(!object->IsJSProxy()); 5501 DCHECK(!name->AsArrayIndex(&index)); 5502 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); 5503 DCHECK(maybe.IsJust()); 5504 DCHECK(!it.IsFound()); 5505 DCHECK(object->map()->is_extensible() || name->IsPrivate()); 5506 #endif 5507 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR, 5508 CERTAINLY_NOT_STORE_FROM_KEYED) 5509 .IsJust()); 5510 } 5511 5512 5513 // Reconfigures a property to a data property with attributes, even if it is not 5514 // reconfigurable. 5515 // Requires a LookupIterator that does not look at the prototype chain beyond 5516 // hidden prototypes. 5517 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes( 5518 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 5519 AccessorInfoHandling handling) { 5520 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes( 5521 it, value, attributes, THROW_ON_ERROR, handling)); 5522 return value; 5523 } 5524 5525 5526 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( 5527 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 5528 ShouldThrow should_throw, AccessorInfoHandling handling) { 5529 it->UpdateProtector(); 5530 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 5531 5532 for (; it->IsFound(); it->Next()) { 5533 switch (it->state()) { 5534 case LookupIterator::JSPROXY: 5535 case LookupIterator::NOT_FOUND: 5536 case LookupIterator::TRANSITION: 5537 UNREACHABLE(); 5538 5539 case LookupIterator::ACCESS_CHECK: 5540 if (!it->HasAccess()) { 5541 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 5542 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 5543 return Just(true); 5544 } 5545 break; 5546 5547 // If there's an interceptor, try to store the property with the 5548 // interceptor. 5549 // In case of success, the attributes will have been reset to the default 5550 // attributes of the interceptor, rather than the incoming attributes. 5551 // 5552 // TODO(verwaest): JSProxy afterwards verify the attributes that the 5553 // JSProxy claims it has, and verifies that they are compatible. If not, 5554 // they throw. Here we should do the same. 5555 case LookupIterator::INTERCEPTOR: 5556 if (handling == DONT_FORCE_FIELD) { 5557 Maybe<bool> result = 5558 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 5559 if (result.IsNothing() || result.FromJust()) return result; 5560 } 5561 break; 5562 5563 case LookupIterator::ACCESSOR: { 5564 Handle<Object> accessors = it->GetAccessors(); 5565 5566 // Special handling for AccessorInfo, which behaves like a data 5567 // property. 5568 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) { 5569 PropertyAttributes current_attributes = it->property_attributes(); 5570 // Ensure the context isn't changed after calling into accessors. 5571 AssertNoContextChange ncc(it->isolate()); 5572 5573 // Update the attributes before calling the setter. The setter may 5574 // later change the shape of the property. 5575 if (current_attributes != attributes) { 5576 it->TransitionToAccessorPair(accessors, attributes); 5577 } 5578 5579 Maybe<bool> result = 5580 JSObject::SetPropertyWithAccessor(it, value, should_throw); 5581 5582 if (current_attributes == attributes || result.IsNothing()) { 5583 return result; 5584 } 5585 5586 } else { 5587 it->ReconfigureDataProperty(value, attributes); 5588 } 5589 5590 return Just(true); 5591 } 5592 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5593 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value, 5594 should_throw); 5595 5596 case LookupIterator::DATA: { 5597 // Regular property update if the attributes match. 5598 if (it->property_attributes() == attributes) { 5599 return SetDataProperty(it, value); 5600 } 5601 5602 // Special case: properties of typed arrays cannot be reconfigured to 5603 // non-writable nor to non-enumerable. 5604 if (it->IsElement() && object->HasFixedTypedArrayElements()) { 5605 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), 5606 value, should_throw); 5607 } 5608 5609 // Reconfigure the data property if the attributes mismatch. 5610 it->ReconfigureDataProperty(value, attributes); 5611 5612 return Just(true); 5613 } 5614 } 5615 } 5616 5617 return AddDataProperty(it, value, attributes, should_throw, 5618 CERTAINLY_NOT_STORE_FROM_KEYED); 5619 } 5620 5621 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( 5622 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, 5623 PropertyAttributes attributes) { 5624 DCHECK(!value->IsTheHole(object->GetIsolate())); 5625 LookupIterator it(object, name, object, LookupIterator::OWN); 5626 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5627 } 5628 5629 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes( 5630 Handle<JSObject> object, uint32_t index, Handle<Object> value, 5631 PropertyAttributes attributes) { 5632 Isolate* isolate = object->GetIsolate(); 5633 LookupIterator it(isolate, object, index, object, LookupIterator::OWN); 5634 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5635 } 5636 5637 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes( 5638 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, 5639 PropertyAttributes attributes) { 5640 Isolate* isolate = object->GetIsolate(); 5641 LookupIterator it = LookupIterator::PropertyOrElement( 5642 isolate, object, name, object, LookupIterator::OWN); 5643 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 5644 } 5645 5646 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( 5647 LookupIterator* it) { 5648 return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor()); 5649 } 5650 5651 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes( 5652 LookupIterator* it) { 5653 for (; it->IsFound(); it->Next()) { 5654 switch (it->state()) { 5655 case LookupIterator::NOT_FOUND: 5656 case LookupIterator::TRANSITION: 5657 UNREACHABLE(); 5658 case LookupIterator::JSPROXY: 5659 return JSProxy::GetPropertyAttributes(it); 5660 case LookupIterator::INTERCEPTOR: { 5661 Maybe<PropertyAttributes> result = 5662 JSObject::GetPropertyAttributesWithInterceptor(it); 5663 if (!result.IsJust()) return result; 5664 if (result.FromJust() != ABSENT) return result; 5665 break; 5666 } 5667 case LookupIterator::ACCESS_CHECK: 5668 if (it->HasAccess()) break; 5669 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it); 5670 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5671 return Just(ABSENT); 5672 case LookupIterator::ACCESSOR: 5673 case LookupIterator::DATA: 5674 return Just(it->property_attributes()); 5675 } 5676 } 5677 return Just(ABSENT); 5678 } 5679 5680 5681 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) { 5682 Handle<FixedArray> array( 5683 isolate->factory()->NewFixedArray(kEntries, TENURED)); 5684 return Handle<NormalizedMapCache>::cast(array); 5685 } 5686 5687 5688 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map, 5689 PropertyNormalizationMode mode) { 5690 DisallowHeapAllocation no_gc; 5691 Object* value = FixedArray::get(GetIndex(fast_map)); 5692 if (!value->IsMap() || 5693 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) { 5694 return MaybeHandle<Map>(); 5695 } 5696 return handle(Map::cast(value)); 5697 } 5698 5699 5700 void NormalizedMapCache::Set(Handle<Map> fast_map, 5701 Handle<Map> normalized_map) { 5702 DisallowHeapAllocation no_gc; 5703 DCHECK(normalized_map->is_dictionary_map()); 5704 FixedArray::set(GetIndex(fast_map), *normalized_map); 5705 } 5706 5707 5708 void NormalizedMapCache::Clear() { 5709 int entries = length(); 5710 for (int i = 0; i != entries; i++) { 5711 set_undefined(i); 5712 } 5713 } 5714 5715 5716 void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object, 5717 Handle<Name> name, 5718 Handle<Code> code) { 5719 Handle<Map> map(object->map()); 5720 Map::UpdateCodeCache(map, name, code); 5721 } 5722 5723 5724 void JSObject::NormalizeProperties(Handle<JSObject> object, 5725 PropertyNormalizationMode mode, 5726 int expected_additional_properties, 5727 const char* reason) { 5728 if (!object->HasFastProperties()) return; 5729 5730 Handle<Map> map(object->map()); 5731 Handle<Map> new_map = Map::Normalize(map, mode, reason); 5732 5733 MigrateToMap(object, new_map, expected_additional_properties); 5734 } 5735 5736 5737 void JSObject::MigrateSlowToFast(Handle<JSObject> object, 5738 int unused_property_fields, 5739 const char* reason) { 5740 if (object->HasFastProperties()) return; 5741 DCHECK(!object->IsJSGlobalObject()); 5742 Isolate* isolate = object->GetIsolate(); 5743 Factory* factory = isolate->factory(); 5744 Handle<NameDictionary> dictionary(object->property_dictionary()); 5745 5746 // Make sure we preserve dictionary representation if there are too many 5747 // descriptors. 5748 int number_of_elements = dictionary->NumberOfElements(); 5749 if (number_of_elements > kMaxNumberOfDescriptors) return; 5750 5751 Handle<FixedArray> iteration_order; 5752 if (number_of_elements != dictionary->NextEnumerationIndex()) { 5753 iteration_order = 5754 NameDictionary::DoGenerateNewEnumerationIndices(dictionary); 5755 } else { 5756 iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary); 5757 } 5758 5759 int instance_descriptor_length = iteration_order->length(); 5760 int number_of_fields = 0; 5761 5762 // Compute the length of the instance descriptor. 5763 for (int i = 0; i < instance_descriptor_length; i++) { 5764 int index = Smi::cast(iteration_order->get(i))->value(); 5765 DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index))); 5766 5767 Object* value = dictionary->ValueAt(index); 5768 PropertyType type = dictionary->DetailsAt(index).type(); 5769 if (type == DATA && !value->IsJSFunction()) { 5770 number_of_fields += 1; 5771 } 5772 } 5773 5774 Handle<Map> old_map(object->map(), isolate); 5775 5776 int inobject_props = old_map->GetInObjectProperties(); 5777 5778 // Allocate new map. 5779 Handle<Map> new_map = Map::CopyDropDescriptors(old_map); 5780 new_map->set_dictionary_map(false); 5781 5782 UpdatePrototypeUserRegistration(old_map, new_map, isolate); 5783 5784 #if TRACE_MAPS 5785 if (FLAG_trace_maps) { 5786 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n", 5787 reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map), 5788 reason); 5789 } 5790 #endif 5791 5792 if (instance_descriptor_length == 0) { 5793 DisallowHeapAllocation no_gc; 5794 DCHECK_LE(unused_property_fields, inobject_props); 5795 // Transform the object. 5796 new_map->set_unused_property_fields(inobject_props); 5797 object->synchronized_set_map(*new_map); 5798 object->set_properties(isolate->heap()->empty_fixed_array()); 5799 // Check that it really works. 5800 DCHECK(object->HasFastProperties()); 5801 return; 5802 } 5803 5804 // Allocate the instance descriptor. 5805 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate( 5806 isolate, instance_descriptor_length, 0, TENURED); 5807 5808 int number_of_allocated_fields = 5809 number_of_fields + unused_property_fields - inobject_props; 5810 if (number_of_allocated_fields < 0) { 5811 // There is enough inobject space for all fields (including unused). 5812 number_of_allocated_fields = 0; 5813 unused_property_fields = inobject_props - number_of_fields; 5814 } 5815 5816 // Allocate the fixed array for the fields. 5817 Handle<FixedArray> fields = factory->NewFixedArray( 5818 number_of_allocated_fields); 5819 5820 // Fill in the instance descriptor and the fields. 5821 int current_offset = 0; 5822 for (int i = 0; i < instance_descriptor_length; i++) { 5823 int index = Smi::cast(iteration_order->get(i))->value(); 5824 Object* k = dictionary->KeyAt(index); 5825 DCHECK(dictionary->IsKey(k)); 5826 // Dictionary keys are internalized upon insertion. 5827 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild. 5828 CHECK(k->IsUniqueName()); 5829 Handle<Name> key(Name::cast(k), isolate); 5830 5831 Object* value = dictionary->ValueAt(index); 5832 5833 PropertyDetails details = dictionary->DetailsAt(index); 5834 int enumeration_index = details.dictionary_index(); 5835 PropertyType type = details.type(); 5836 5837 if (value->IsJSFunction()) { 5838 DataConstantDescriptor d(key, handle(value, isolate), 5839 details.attributes()); 5840 descriptors->Set(enumeration_index - 1, &d); 5841 } else if (type == DATA) { 5842 if (current_offset < inobject_props) { 5843 object->InObjectPropertyAtPut(current_offset, value, 5844 UPDATE_WRITE_BARRIER); 5845 } else { 5846 int offset = current_offset - inobject_props; 5847 fields->set(offset, value); 5848 } 5849 DataDescriptor d(key, current_offset, details.attributes(), 5850 // TODO(verwaest): value->OptimalRepresentation(); 5851 Representation::Tagged()); 5852 current_offset += d.GetDetails().field_width_in_words(); 5853 descriptors->Set(enumeration_index - 1, &d); 5854 } else if (type == ACCESSOR_CONSTANT) { 5855 AccessorConstantDescriptor d(key, handle(value, isolate), 5856 details.attributes()); 5857 descriptors->Set(enumeration_index - 1, &d); 5858 } else { 5859 UNREACHABLE(); 5860 } 5861 } 5862 DCHECK(current_offset == number_of_fields); 5863 5864 descriptors->Sort(); 5865 5866 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New( 5867 new_map, descriptors, descriptors->number_of_descriptors()); 5868 5869 DisallowHeapAllocation no_gc; 5870 new_map->InitializeDescriptors(*descriptors, *layout_descriptor); 5871 new_map->set_unused_property_fields(unused_property_fields); 5872 5873 // Transform the object. 5874 object->synchronized_set_map(*new_map); 5875 5876 object->set_properties(*fields); 5877 DCHECK(object->IsJSObject()); 5878 5879 // Check that it really works. 5880 DCHECK(object->HasFastProperties()); 5881 } 5882 5883 5884 void JSObject::ResetElements(Handle<JSObject> object) { 5885 Isolate* isolate = object->GetIsolate(); 5886 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map()); 5887 if (object->map()->has_dictionary_elements()) { 5888 Handle<SeededNumberDictionary> new_elements = 5889 SeededNumberDictionary::New(isolate, 0); 5890 object->set_elements(*new_elements); 5891 } else { 5892 object->set_elements(object->map()->GetInitialElements()); 5893 } 5894 } 5895 5896 5897 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) { 5898 if (dictionary->requires_slow_elements()) return; 5899 dictionary->set_requires_slow_elements(); 5900 // TODO(verwaest): Remove this hack. 5901 if (map()->is_prototype_map()) { 5902 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate()); 5903 } 5904 } 5905 5906 5907 Handle<SeededNumberDictionary> JSObject::NormalizeElements( 5908 Handle<JSObject> object) { 5909 DCHECK(!object->HasFixedTypedArrayElements()); 5910 Isolate* isolate = object->GetIsolate(); 5911 bool is_arguments = object->HasSloppyArgumentsElements(); 5912 { 5913 DisallowHeapAllocation no_gc; 5914 FixedArrayBase* elements = object->elements(); 5915 5916 if (is_arguments) { 5917 FixedArray* parameter_map = FixedArray::cast(elements); 5918 elements = FixedArrayBase::cast(parameter_map->get(1)); 5919 } 5920 5921 if (elements->IsDictionary()) { 5922 return handle(SeededNumberDictionary::cast(elements), isolate); 5923 } 5924 } 5925 5926 DCHECK(object->HasFastSmiOrObjectElements() || 5927 object->HasFastDoubleElements() || 5928 object->HasFastArgumentsElements() || 5929 object->HasFastStringWrapperElements()); 5930 5931 Handle<SeededNumberDictionary> dictionary = 5932 object->GetElementsAccessor()->Normalize(object); 5933 5934 // Switch to using the dictionary as the backing storage for elements. 5935 ElementsKind target_kind = is_arguments 5936 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS 5937 : object->HasFastStringWrapperElements() 5938 ? SLOW_STRING_WRAPPER_ELEMENTS 5939 : DICTIONARY_ELEMENTS; 5940 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); 5941 // Set the new map first to satify the elements type assert in set_elements(). 5942 JSObject::MigrateToMap(object, new_map); 5943 5944 if (is_arguments) { 5945 FixedArray::cast(object->elements())->set(1, *dictionary); 5946 } else { 5947 object->set_elements(*dictionary); 5948 } 5949 5950 isolate->counters()->elements_to_dictionary()->Increment(); 5951 5952 #ifdef DEBUG 5953 if (FLAG_trace_normalization) { 5954 OFStream os(stdout); 5955 os << "Object elements have been normalized:\n"; 5956 object->Print(os); 5957 } 5958 #endif 5959 5960 DCHECK(object->HasDictionaryElements() || 5961 object->HasSlowArgumentsElements() || 5962 object->HasSlowStringWrapperElements()); 5963 return dictionary; 5964 } 5965 5966 5967 static Smi* GenerateIdentityHash(Isolate* isolate) { 5968 int hash_value; 5969 int attempts = 0; 5970 do { 5971 // Generate a random 32-bit hash value but limit range to fit 5972 // within a smi. 5973 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue; 5974 attempts++; 5975 } while (hash_value == 0 && attempts < 30); 5976 hash_value = hash_value != 0 ? hash_value : 1; // never return 0 5977 5978 return Smi::FromInt(hash_value); 5979 } 5980 5981 template <typename ProxyType> 5982 static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate, 5983 Handle<ProxyType> proxy) { 5984 Object* maybe_hash = proxy->hash(); 5985 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash); 5986 5987 Smi* hash = GenerateIdentityHash(isolate); 5988 proxy->set_hash(hash); 5989 return hash; 5990 } 5991 5992 // static 5993 Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) { 5994 if (object->IsJSGlobalProxy()) { 5995 return JSGlobalProxy::cast(*object)->hash(); 5996 } 5997 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol(); 5998 return *JSReceiver::GetDataProperty(object, hash_code_symbol); 5999 } 6000 6001 // static 6002 Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate, 6003 Handle<JSObject> object) { 6004 if (object->IsJSGlobalProxy()) { 6005 return GetOrCreateIdentityHashHelper(isolate, 6006 Handle<JSGlobalProxy>::cast(object)); 6007 } 6008 6009 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol(); 6010 LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN); 6011 if (it.IsFound()) { 6012 DCHECK_EQ(LookupIterator::DATA, it.state()); 6013 Object* maybe_hash = *it.GetDataValue(); 6014 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash); 6015 } 6016 6017 Smi* hash = GenerateIdentityHash(isolate); 6018 CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR, 6019 CERTAINLY_NOT_STORE_FROM_KEYED) 6020 .IsJust()); 6021 return hash; 6022 } 6023 6024 // static 6025 Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) { 6026 return proxy->hash(); 6027 } 6028 6029 Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) { 6030 return GetOrCreateIdentityHashHelper(isolate, proxy); 6031 } 6032 6033 6034 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it, 6035 ShouldThrow should_throw) { 6036 Isolate* isolate = it->isolate(); 6037 // Make sure that the top context does not change when doing callbacks or 6038 // interceptor calls. 6039 AssertNoContextChange ncc(isolate); 6040 6041 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 6042 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); 6043 if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>(); 6044 6045 Handle<JSObject> holder = it->GetHolder<JSObject>(); 6046 Handle<Object> receiver = it->GetReceiver(); 6047 if (!receiver->IsJSReceiver()) { 6048 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 6049 Object::ConvertReceiver(isolate, receiver), 6050 Nothing<bool>()); 6051 } 6052 6053 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 6054 *holder, should_throw); 6055 Handle<Object> result; 6056 if (it->IsElement()) { 6057 uint32_t index = it->index(); 6058 v8::IndexedPropertyDeleterCallback deleter = 6059 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter()); 6060 result = args.Call(deleter, index); 6061 } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) { 6062 return Nothing<bool>(); 6063 } else { 6064 Handle<Name> name = it->name(); 6065 DCHECK(!name->IsPrivate()); 6066 v8::GenericNamedPropertyDeleterCallback deleter = 6067 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>( 6068 interceptor->deleter()); 6069 result = args.Call(deleter, name); 6070 } 6071 6072 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6073 if (result.is_null()) return Nothing<bool>(); 6074 6075 DCHECK(result->IsBoolean()); 6076 // Rebox CustomArguments::kReturnValueOffset before returning. 6077 return Just(result->IsTrue(isolate)); 6078 } 6079 6080 6081 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object, 6082 Handle<Name> name, int entry) { 6083 DCHECK(!object->HasFastProperties()); 6084 Isolate* isolate = object->GetIsolate(); 6085 6086 if (object->IsJSGlobalObject()) { 6087 // If we have a global object, invalidate the cell and swap in a new one. 6088 Handle<GlobalDictionary> dictionary( 6089 JSObject::cast(*object)->global_dictionary()); 6090 DCHECK_NE(GlobalDictionary::kNotFound, entry); 6091 6092 auto cell = PropertyCell::InvalidateEntry(dictionary, entry); 6093 cell->set_value(isolate->heap()->the_hole_value()); 6094 // TODO(ishell): InvalidateForDelete 6095 cell->set_property_details( 6096 cell->property_details().set_cell_type(PropertyCellType::kInvalidated)); 6097 } else { 6098 Handle<NameDictionary> dictionary(object->property_dictionary()); 6099 DCHECK_NE(NameDictionary::kNotFound, entry); 6100 6101 NameDictionary::DeleteProperty(dictionary, entry); 6102 Handle<NameDictionary> new_properties = 6103 NameDictionary::Shrink(dictionary, name); 6104 object->set_properties(*new_properties); 6105 } 6106 } 6107 6108 6109 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it, 6110 LanguageMode language_mode) { 6111 it->UpdateProtector(); 6112 6113 Isolate* isolate = it->isolate(); 6114 6115 if (it->state() == LookupIterator::JSPROXY) { 6116 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(), 6117 it->GetName(), language_mode); 6118 } 6119 6120 if (it->GetReceiver()->IsJSProxy()) { 6121 if (it->state() != LookupIterator::NOT_FOUND) { 6122 DCHECK_EQ(LookupIterator::DATA, it->state()); 6123 DCHECK(it->name()->IsPrivate()); 6124 it->Delete(); 6125 } 6126 return Just(true); 6127 } 6128 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); 6129 6130 for (; it->IsFound(); it->Next()) { 6131 switch (it->state()) { 6132 case LookupIterator::JSPROXY: 6133 case LookupIterator::NOT_FOUND: 6134 case LookupIterator::TRANSITION: 6135 UNREACHABLE(); 6136 case LookupIterator::ACCESS_CHECK: 6137 if (it->HasAccess()) break; 6138 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 6139 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6140 return Just(false); 6141 case LookupIterator::INTERCEPTOR: { 6142 ShouldThrow should_throw = 6143 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; 6144 Maybe<bool> result = 6145 JSObject::DeletePropertyWithInterceptor(it, should_throw); 6146 // An exception was thrown in the interceptor. Propagate. 6147 if (isolate->has_pending_exception()) return Nothing<bool>(); 6148 // Delete with interceptor succeeded. Return result. 6149 // TODO(neis): In strict mode, we should probably throw if the 6150 // interceptor returns false. 6151 if (result.IsJust()) return result; 6152 break; 6153 } 6154 case LookupIterator::INTEGER_INDEXED_EXOTIC: 6155 return Just(true); 6156 case LookupIterator::DATA: 6157 case LookupIterator::ACCESSOR: { 6158 if (!it->IsConfigurable()) { 6159 // Fail if the property is not configurable. 6160 if (is_strict(language_mode)) { 6161 isolate->Throw(*isolate->factory()->NewTypeError( 6162 MessageTemplate::kStrictDeleteProperty, it->GetName(), 6163 receiver)); 6164 return Nothing<bool>(); 6165 } 6166 return Just(false); 6167 } 6168 6169 it->Delete(); 6170 6171 return Just(true); 6172 } 6173 } 6174 } 6175 6176 return Just(true); 6177 } 6178 6179 6180 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index, 6181 LanguageMode language_mode) { 6182 LookupIterator it(object->GetIsolate(), object, index, object, 6183 LookupIterator::OWN); 6184 return DeleteProperty(&it, language_mode); 6185 } 6186 6187 6188 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object, 6189 Handle<Name> name, 6190 LanguageMode language_mode) { 6191 LookupIterator it(object, name, object, LookupIterator::OWN); 6192 return DeleteProperty(&it, language_mode); 6193 } 6194 6195 6196 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object, 6197 Handle<Name> name, 6198 LanguageMode language_mode) { 6199 LookupIterator it = LookupIterator::PropertyOrElement( 6200 name->GetIsolate(), object, name, object, LookupIterator::OWN); 6201 return DeleteProperty(&it, language_mode); 6202 } 6203 6204 6205 // ES6 7.1.14 6206 // static 6207 MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate, 6208 Handle<Object> value) { 6209 // 1. Let key be ToPrimitive(argument, hint String). 6210 MaybeHandle<Object> maybe_key = 6211 Object::ToPrimitive(value, ToPrimitiveHint::kString); 6212 // 2. ReturnIfAbrupt(key). 6213 Handle<Object> key; 6214 if (!maybe_key.ToHandle(&key)) return key; 6215 // 3. If Type(key) is Symbol, then return key. 6216 if (key->IsSymbol()) return key; 6217 // 4. Return ToString(key). 6218 // Extending spec'ed behavior, we'd be happy to return an element index. 6219 if (key->IsSmi()) return key; 6220 if (key->IsHeapNumber()) { 6221 uint32_t uint_value; 6222 if (value->ToArrayLength(&uint_value) && 6223 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) { 6224 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate); 6225 } 6226 } 6227 return Object::ToString(isolate, key); 6228 } 6229 6230 6231 // ES6 19.1.2.4 6232 // static 6233 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object, 6234 Handle<Object> key, 6235 Handle<Object> attributes) { 6236 // 1. If Type(O) is not Object, throw a TypeError exception. 6237 if (!object->IsJSReceiver()) { 6238 Handle<String> fun_name = 6239 isolate->factory()->InternalizeUtf8String("Object.defineProperty"); 6240 THROW_NEW_ERROR_RETURN_FAILURE( 6241 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name)); 6242 } 6243 // 2. Let key be ToPropertyKey(P). 6244 // 3. ReturnIfAbrupt(key). 6245 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key)); 6246 // 4. Let desc be ToPropertyDescriptor(Attributes). 6247 // 5. ReturnIfAbrupt(desc). 6248 PropertyDescriptor desc; 6249 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) { 6250 return isolate->heap()->exception(); 6251 } 6252 // 6. Let success be DefinePropertyOrThrow(O,key, desc). 6253 Maybe<bool> success = DefineOwnProperty( 6254 isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR); 6255 // 7. ReturnIfAbrupt(success). 6256 MAYBE_RETURN(success, isolate->heap()->exception()); 6257 CHECK(success.FromJust()); 6258 // 8. Return O. 6259 return *object; 6260 } 6261 6262 6263 // ES6 19.1.2.3.1 6264 // static 6265 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate, 6266 Handle<Object> object, 6267 Handle<Object> properties) { 6268 // 1. If Type(O) is not Object, throw a TypeError exception. 6269 if (!object->IsJSReceiver()) { 6270 Handle<String> fun_name = 6271 isolate->factory()->InternalizeUtf8String("Object.defineProperties"); 6272 THROW_NEW_ERROR(isolate, 6273 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name), 6274 Object); 6275 } 6276 // 2. Let props be ToObject(Properties). 6277 // 3. ReturnIfAbrupt(props). 6278 Handle<JSReceiver> props; 6279 if (!Object::ToObject(isolate, properties).ToHandle(&props)) { 6280 THROW_NEW_ERROR(isolate, 6281 NewTypeError(MessageTemplate::kUndefinedOrNullToObject), 6282 Object); 6283 } 6284 // 4. Let keys be props.[[OwnPropertyKeys]](). 6285 // 5. ReturnIfAbrupt(keys). 6286 Handle<FixedArray> keys; 6287 ASSIGN_RETURN_ON_EXCEPTION( 6288 isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly, 6289 ALL_PROPERTIES), 6290 Object); 6291 // 6. Let descriptors be an empty List. 6292 int capacity = keys->length(); 6293 std::vector<PropertyDescriptor> descriptors(capacity); 6294 size_t descriptors_index = 0; 6295 // 7. Repeat for each element nextKey of keys in List order, 6296 for (int i = 0; i < keys->length(); ++i) { 6297 Handle<Object> next_key(keys->get(i), isolate); 6298 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey). 6299 // 7b. ReturnIfAbrupt(propDesc). 6300 bool success = false; 6301 LookupIterator it = LookupIterator::PropertyOrElement( 6302 isolate, props, next_key, &success, LookupIterator::OWN); 6303 DCHECK(success); 6304 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 6305 if (!maybe.IsJust()) return MaybeHandle<Object>(); 6306 PropertyAttributes attrs = maybe.FromJust(); 6307 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true: 6308 if (attrs == ABSENT) continue; 6309 if (attrs & DONT_ENUM) continue; 6310 // 7c i. Let descObj be Get(props, nextKey). 6311 // 7c ii. ReturnIfAbrupt(descObj). 6312 Handle<Object> desc_obj; 6313 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it), 6314 Object); 6315 // 7c iii. Let desc be ToPropertyDescriptor(descObj). 6316 success = PropertyDescriptor::ToPropertyDescriptor( 6317 isolate, desc_obj, &descriptors[descriptors_index]); 6318 // 7c iv. ReturnIfAbrupt(desc). 6319 if (!success) return MaybeHandle<Object>(); 6320 // 7c v. Append the pair (a two element List) consisting of nextKey and 6321 // desc to the end of descriptors. 6322 descriptors[descriptors_index].set_name(next_key); 6323 descriptors_index++; 6324 } 6325 // 8. For each pair from descriptors in list order, 6326 for (size_t i = 0; i < descriptors_index; ++i) { 6327 PropertyDescriptor* desc = &descriptors[i]; 6328 // 8a. Let P be the first element of pair. 6329 // 8b. Let desc be the second element of pair. 6330 // 8c. Let status be DefinePropertyOrThrow(O, P, desc). 6331 Maybe<bool> status = 6332 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object), 6333 desc->name(), desc, THROW_ON_ERROR); 6334 // 8d. ReturnIfAbrupt(status). 6335 if (!status.IsJust()) return MaybeHandle<Object>(); 6336 CHECK(status.FromJust()); 6337 } 6338 // 9. Return o. 6339 return object; 6340 } 6341 6342 6343 // static 6344 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate, 6345 Handle<JSReceiver> object, 6346 Handle<Object> key, 6347 PropertyDescriptor* desc, 6348 ShouldThrow should_throw) { 6349 if (object->IsJSArray()) { 6350 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object), 6351 key, desc, should_throw); 6352 } 6353 if (object->IsJSProxy()) { 6354 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object), 6355 key, desc, should_throw); 6356 } 6357 // TODO(jkummerow): Support Modules (ES6 9.4.6.6) 6358 6359 // OrdinaryDefineOwnProperty, by virtue of calling 6360 // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2) 6361 // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception: 6362 // TODO(jkummerow): Setting an indexed accessor on a typed array should throw. 6363 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key, 6364 desc, should_throw); 6365 } 6366 6367 6368 // static 6369 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, 6370 Handle<JSObject> object, 6371 Handle<Object> key, 6372 PropertyDescriptor* desc, 6373 ShouldThrow should_throw) { 6374 bool success = false; 6375 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... 6376 LookupIterator it = LookupIterator::PropertyOrElement( 6377 isolate, object, key, &success, LookupIterator::OWN); 6378 DCHECK(success); // ...so creating a LookupIterator can't fail. 6379 6380 // Deal with access checks first. 6381 if (it.state() == LookupIterator::ACCESS_CHECK) { 6382 if (!it.HasAccess()) { 6383 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); 6384 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6385 return Just(true); 6386 } 6387 it.Next(); 6388 } 6389 6390 return OrdinaryDefineOwnProperty(&it, desc, should_throw); 6391 } 6392 6393 6394 // ES6 9.1.6.1 6395 // static 6396 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it, 6397 PropertyDescriptor* desc, 6398 ShouldThrow should_throw) { 6399 Isolate* isolate = it->isolate(); 6400 // 1. Let current be O.[[GetOwnProperty]](P). 6401 // 2. ReturnIfAbrupt(current). 6402 PropertyDescriptor current; 6403 MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>()); 6404 6405 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset 6406 // the iterator every time. Currently, the reasons why we need it are: 6407 // - handle interceptors correctly 6408 // - handle accessors correctly (which might change the holder's map) 6409 it->Restart(); 6410 // 3. Let extensible be the value of the [[Extensible]] internal slot of O. 6411 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 6412 bool extensible = JSObject::IsExtensible(object); 6413 6414 return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc, 6415 ¤t, should_throw); 6416 } 6417 6418 6419 // ES6 9.1.6.2 6420 // static 6421 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor( 6422 Isolate* isolate, bool extensible, PropertyDescriptor* desc, 6423 PropertyDescriptor* current, Handle<Name> property_name, 6424 ShouldThrow should_throw) { 6425 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, 6426 // Extensible, Desc, Current). 6427 return ValidateAndApplyPropertyDescriptor( 6428 isolate, NULL, extensible, desc, current, should_throw, property_name); 6429 } 6430 6431 6432 // ES6 9.1.6.3 6433 // static 6434 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor( 6435 Isolate* isolate, LookupIterator* it, bool extensible, 6436 PropertyDescriptor* desc, PropertyDescriptor* current, 6437 ShouldThrow should_throw, Handle<Name> property_name) { 6438 // We either need a LookupIterator, or a property name. 6439 DCHECK((it == NULL) != property_name.is_null()); 6440 Handle<JSObject> object; 6441 if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver()); 6442 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc); 6443 bool desc_is_accessor_descriptor = 6444 PropertyDescriptor::IsAccessorDescriptor(desc); 6445 bool desc_is_generic_descriptor = 6446 PropertyDescriptor::IsGenericDescriptor(desc); 6447 // 1. (Assert) 6448 // 2. If current is undefined, then 6449 if (current->is_empty()) { 6450 // 2a. If extensible is false, return false. 6451 if (!extensible) { 6452 RETURN_FAILURE(isolate, should_throw, 6453 NewTypeError(MessageTemplate::kDefineDisallowed, 6454 it != NULL ? it->GetName() : property_name)); 6455 } 6456 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then: 6457 // (This is equivalent to !IsAccessorDescriptor(desc).) 6458 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) == 6459 !desc_is_accessor_descriptor); 6460 if (!desc_is_accessor_descriptor) { 6461 // 2c i. If O is not undefined, create an own data property named P of 6462 // object O whose [[Value]], [[Writable]], [[Enumerable]] and 6463 // [[Configurable]] attribute values are described by Desc. If the value 6464 // of an attribute field of Desc is absent, the attribute of the newly 6465 // created property is set to its default value. 6466 if (it != NULL) { 6467 if (!desc->has_writable()) desc->set_writable(false); 6468 if (!desc->has_enumerable()) desc->set_enumerable(false); 6469 if (!desc->has_configurable()) desc->set_configurable(false); 6470 Handle<Object> value( 6471 desc->has_value() 6472 ? desc->value() 6473 : Handle<Object>::cast(isolate->factory()->undefined_value())); 6474 MaybeHandle<Object> result = 6475 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, 6476 desc->ToAttributes()); 6477 if (result.is_null()) return Nothing<bool>(); 6478 } 6479 } else { 6480 // 2d. Else Desc must be an accessor Property Descriptor, 6481 DCHECK(desc_is_accessor_descriptor); 6482 // 2d i. If O is not undefined, create an own accessor property named P 6483 // of object O whose [[Get]], [[Set]], [[Enumerable]] and 6484 // [[Configurable]] attribute values are described by Desc. If the value 6485 // of an attribute field of Desc is absent, the attribute of the newly 6486 // created property is set to its default value. 6487 if (it != NULL) { 6488 if (!desc->has_enumerable()) desc->set_enumerable(false); 6489 if (!desc->has_configurable()) desc->set_configurable(false); 6490 Handle<Object> getter( 6491 desc->has_get() 6492 ? desc->get() 6493 : Handle<Object>::cast(isolate->factory()->null_value())); 6494 Handle<Object> setter( 6495 desc->has_set() 6496 ? desc->set() 6497 : Handle<Object>::cast(isolate->factory()->null_value())); 6498 MaybeHandle<Object> result = 6499 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes()); 6500 if (result.is_null()) return Nothing<bool>(); 6501 } 6502 } 6503 // 2e. Return true. 6504 return Just(true); 6505 } 6506 // 3. Return true, if every field in Desc is absent. 6507 // 4. Return true, if every field in Desc also occurs in current and the 6508 // value of every field in Desc is the same value as the corresponding field 6509 // in current when compared using the SameValue algorithm. 6510 if ((!desc->has_enumerable() || 6511 desc->enumerable() == current->enumerable()) && 6512 (!desc->has_configurable() || 6513 desc->configurable() == current->configurable()) && 6514 (!desc->has_value() || 6515 (current->has_value() && current->value()->SameValue(*desc->value()))) && 6516 (!desc->has_writable() || 6517 (current->has_writable() && current->writable() == desc->writable())) && 6518 (!desc->has_get() || 6519 (current->has_get() && current->get()->SameValue(*desc->get()))) && 6520 (!desc->has_set() || 6521 (current->has_set() && current->set()->SameValue(*desc->set())))) { 6522 return Just(true); 6523 } 6524 // 5. If the [[Configurable]] field of current is false, then 6525 if (!current->configurable()) { 6526 // 5a. Return false, if the [[Configurable]] field of Desc is true. 6527 if (desc->has_configurable() && desc->configurable()) { 6528 RETURN_FAILURE(isolate, should_throw, 6529 NewTypeError(MessageTemplate::kRedefineDisallowed, 6530 it != NULL ? it->GetName() : property_name)); 6531 } 6532 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the 6533 // [[Enumerable]] fields of current and Desc are the Boolean negation of 6534 // each other. 6535 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) { 6536 RETURN_FAILURE(isolate, should_throw, 6537 NewTypeError(MessageTemplate::kRedefineDisallowed, 6538 it != NULL ? it->GetName() : property_name)); 6539 } 6540 } 6541 6542 bool current_is_data_descriptor = 6543 PropertyDescriptor::IsDataDescriptor(current); 6544 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required. 6545 if (desc_is_generic_descriptor) { 6546 // Nothing to see here. 6547 6548 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have 6549 // different results, then: 6550 } else if (current_is_data_descriptor != desc_is_data_descriptor) { 6551 // 7a. Return false, if the [[Configurable]] field of current is false. 6552 if (!current->configurable()) { 6553 RETURN_FAILURE(isolate, should_throw, 6554 NewTypeError(MessageTemplate::kRedefineDisallowed, 6555 it != NULL ? it->GetName() : property_name)); 6556 } 6557 // 7b. If IsDataDescriptor(current) is true, then: 6558 if (current_is_data_descriptor) { 6559 // 7b i. If O is not undefined, convert the property named P of object O 6560 // from a data property to an accessor property. Preserve the existing 6561 // values of the converted property's [[Configurable]] and [[Enumerable]] 6562 // attributes and set the rest of the property's attributes to their 6563 // default values. 6564 // --> Folded into step 10. 6565 } else { 6566 // 7c i. If O is not undefined, convert the property named P of object O 6567 // from an accessor property to a data property. Preserve the existing 6568 // values of the converted propertys [[Configurable]] and [[Enumerable]] 6569 // attributes and set the rest of the propertys attributes to their 6570 // default values. 6571 // --> Folded into step 10. 6572 } 6573 6574 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both 6575 // true, then: 6576 } else if (current_is_data_descriptor && desc_is_data_descriptor) { 6577 // 8a. If the [[Configurable]] field of current is false, then: 6578 if (!current->configurable()) { 6579 // 8a i. Return false, if the [[Writable]] field of current is false and 6580 // the [[Writable]] field of Desc is true. 6581 if (!current->writable() && desc->has_writable() && desc->writable()) { 6582 RETURN_FAILURE( 6583 isolate, should_throw, 6584 NewTypeError(MessageTemplate::kRedefineDisallowed, 6585 it != NULL ? it->GetName() : property_name)); 6586 } 6587 // 8a ii. If the [[Writable]] field of current is false, then: 6588 if (!current->writable()) { 6589 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and 6590 // SameValue(Desc.[[Value]], current.[[Value]]) is false. 6591 if (desc->has_value() && !desc->value()->SameValue(*current->value())) { 6592 RETURN_FAILURE( 6593 isolate, should_throw, 6594 NewTypeError(MessageTemplate::kRedefineDisallowed, 6595 it != NULL ? it->GetName() : property_name)); 6596 } 6597 } 6598 } 6599 } else { 6600 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) 6601 // are both true, 6602 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) && 6603 desc_is_accessor_descriptor); 6604 // 9a. If the [[Configurable]] field of current is false, then: 6605 if (!current->configurable()) { 6606 // 9a i. Return false, if the [[Set]] field of Desc is present and 6607 // SameValue(Desc.[[Set]], current.[[Set]]) is false. 6608 if (desc->has_set() && !desc->set()->SameValue(*current->set())) { 6609 RETURN_FAILURE( 6610 isolate, should_throw, 6611 NewTypeError(MessageTemplate::kRedefineDisallowed, 6612 it != NULL ? it->GetName() : property_name)); 6613 } 6614 // 9a ii. Return false, if the [[Get]] field of Desc is present and 6615 // SameValue(Desc.[[Get]], current.[[Get]]) is false. 6616 if (desc->has_get() && !desc->get()->SameValue(*current->get())) { 6617 RETURN_FAILURE( 6618 isolate, should_throw, 6619 NewTypeError(MessageTemplate::kRedefineDisallowed, 6620 it != NULL ? it->GetName() : property_name)); 6621 } 6622 } 6623 } 6624 6625 // 10. If O is not undefined, then: 6626 if (it != NULL) { 6627 // 10a. For each field of Desc that is present, set the corresponding 6628 // attribute of the property named P of object O to the value of the field. 6629 PropertyAttributes attrs = NONE; 6630 6631 if (desc->has_enumerable()) { 6632 attrs = static_cast<PropertyAttributes>( 6633 attrs | (desc->enumerable() ? NONE : DONT_ENUM)); 6634 } else { 6635 attrs = static_cast<PropertyAttributes>( 6636 attrs | (current->enumerable() ? NONE : DONT_ENUM)); 6637 } 6638 if (desc->has_configurable()) { 6639 attrs = static_cast<PropertyAttributes>( 6640 attrs | (desc->configurable() ? NONE : DONT_DELETE)); 6641 } else { 6642 attrs = static_cast<PropertyAttributes>( 6643 attrs | (current->configurable() ? NONE : DONT_DELETE)); 6644 } 6645 if (desc_is_data_descriptor || 6646 (desc_is_generic_descriptor && current_is_data_descriptor)) { 6647 if (desc->has_writable()) { 6648 attrs = static_cast<PropertyAttributes>( 6649 attrs | (desc->writable() ? NONE : READ_ONLY)); 6650 } else { 6651 attrs = static_cast<PropertyAttributes>( 6652 attrs | (current->writable() ? NONE : READ_ONLY)); 6653 } 6654 Handle<Object> value( 6655 desc->has_value() ? desc->value() 6656 : current->has_value() 6657 ? current->value() 6658 : Handle<Object>::cast( 6659 isolate->factory()->undefined_value())); 6660 MaybeHandle<Object> result = 6661 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs); 6662 if (result.is_null()) return Nothing<bool>(); 6663 } else { 6664 DCHECK(desc_is_accessor_descriptor || 6665 (desc_is_generic_descriptor && 6666 PropertyDescriptor::IsAccessorDescriptor(current))); 6667 Handle<Object> getter( 6668 desc->has_get() 6669 ? desc->get() 6670 : current->has_get() 6671 ? current->get() 6672 : Handle<Object>::cast(isolate->factory()->null_value())); 6673 Handle<Object> setter( 6674 desc->has_set() 6675 ? desc->set() 6676 : current->has_set() 6677 ? current->set() 6678 : Handle<Object>::cast(isolate->factory()->null_value())); 6679 MaybeHandle<Object> result = 6680 JSObject::DefineAccessor(it, getter, setter, attrs); 6681 if (result.is_null()) return Nothing<bool>(); 6682 } 6683 } 6684 6685 // 11. Return true. 6686 return Just(true); 6687 } 6688 6689 6690 // static 6691 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it, 6692 Handle<Object> value, 6693 ShouldThrow should_throw) { 6694 DCHECK(!it->check_prototype_chain()); 6695 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 6696 Isolate* isolate = receiver->GetIsolate(); 6697 6698 if (receiver->IsJSObject()) { 6699 return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut. 6700 } 6701 6702 PropertyDescriptor new_desc; 6703 new_desc.set_value(value); 6704 new_desc.set_writable(true); 6705 new_desc.set_enumerable(true); 6706 new_desc.set_configurable(true); 6707 6708 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 6709 &new_desc, should_throw); 6710 } 6711 6712 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it, 6713 Handle<Object> value, 6714 ShouldThrow should_throw) { 6715 DCHECK(it->GetReceiver()->IsJSObject()); 6716 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>()); 6717 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 6718 Isolate* isolate = receiver->GetIsolate(); 6719 6720 if (it->IsFound()) { 6721 Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it); 6722 MAYBE_RETURN(attributes, Nothing<bool>()); 6723 if ((attributes.FromJust() & DONT_DELETE) != 0) { 6724 RETURN_FAILURE( 6725 isolate, should_throw, 6726 NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName())); 6727 } 6728 } else { 6729 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) { 6730 RETURN_FAILURE( 6731 isolate, should_throw, 6732 NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName())); 6733 } 6734 } 6735 6736 RETURN_ON_EXCEPTION_VALUE(it->isolate(), 6737 DefineOwnPropertyIgnoreAttributes(it, value, NONE), 6738 Nothing<bool>()); 6739 6740 return Just(true); 6741 } 6742 6743 6744 // TODO(jkummerow): Consider unification with FastAsArrayLength() in 6745 // accessors.cc. 6746 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) { 6747 DCHECK(value->IsNumber() || value->IsName()); 6748 if (value->ToArrayLength(length)) return true; 6749 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length); 6750 return false; 6751 } 6752 6753 6754 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) { 6755 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32; 6756 } 6757 6758 6759 // ES6 9.4.2.1 6760 // static 6761 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o, 6762 Handle<Object> name, 6763 PropertyDescriptor* desc, 6764 ShouldThrow should_throw) { 6765 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.) 6766 // 2. If P is "length", then: 6767 // TODO(jkummerow): Check if we need slow string comparison. 6768 if (*name == isolate->heap()->length_string()) { 6769 // 2a. Return ArraySetLength(A, Desc). 6770 return ArraySetLength(isolate, o, desc, should_throw); 6771 } 6772 // 3. Else if P is an array index, then: 6773 uint32_t index = 0; 6774 if (PropertyKeyToArrayIndex(name, &index)) { 6775 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 6776 PropertyDescriptor old_len_desc; 6777 Maybe<bool> success = GetOwnPropertyDescriptor( 6778 isolate, o, isolate->factory()->length_string(), &old_len_desc); 6779 // 3b. (Assert) 6780 DCHECK(success.FromJust()); 6781 USE(success); 6782 // 3c. Let oldLen be oldLenDesc.[[Value]]. 6783 uint32_t old_len = 0; 6784 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 6785 // 3d. Let index be ToUint32(P). 6786 // (Already done above.) 6787 // 3e. (Assert) 6788 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false, 6789 // return false. 6790 if (index >= old_len && old_len_desc.has_writable() && 6791 !old_len_desc.writable()) { 6792 RETURN_FAILURE(isolate, should_throw, 6793 NewTypeError(MessageTemplate::kDefineDisallowed, name)); 6794 } 6795 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc). 6796 Maybe<bool> succeeded = 6797 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 6798 // 3h. Assert: succeeded is not an abrupt completion. 6799 // In our case, if should_throw == THROW_ON_ERROR, it can be! 6800 // 3i. If succeeded is false, return false. 6801 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded; 6802 // 3j. If index >= oldLen, then: 6803 if (index >= old_len) { 6804 // 3j i. Set oldLenDesc.[[Value]] to index + 1. 6805 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1)); 6806 // 3j ii. Let succeeded be 6807 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc). 6808 succeeded = OrdinaryDefineOwnProperty(isolate, o, 6809 isolate->factory()->length_string(), 6810 &old_len_desc, should_throw); 6811 // 3j iii. Assert: succeeded is true. 6812 DCHECK(succeeded.FromJust()); 6813 USE(succeeded); 6814 } 6815 // 3k. Return true. 6816 return Just(true); 6817 } 6818 6819 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc). 6820 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 6821 } 6822 6823 6824 // Part of ES6 9.4.2.4 ArraySetLength. 6825 // static 6826 bool JSArray::AnythingToArrayLength(Isolate* isolate, 6827 Handle<Object> length_object, 6828 uint32_t* output) { 6829 // Fast path: check numbers and strings that can be converted directly 6830 // and unobservably. 6831 if (length_object->ToArrayLength(output)) return true; 6832 if (length_object->IsString() && 6833 Handle<String>::cast(length_object)->AsArrayIndex(output)) { 6834 return true; 6835 } 6836 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength". 6837 // 3. Let newLen be ToUint32(Desc.[[Value]]). 6838 Handle<Object> uint32_v; 6839 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) { 6840 // 4. ReturnIfAbrupt(newLen). 6841 return false; 6842 } 6843 // 5. Let numberLen be ToNumber(Desc.[[Value]]). 6844 Handle<Object> number_v; 6845 if (!Object::ToNumber(length_object).ToHandle(&number_v)) { 6846 // 6. ReturnIfAbrupt(newLen). 6847 return false; 6848 } 6849 // 7. If newLen != numberLen, throw a RangeError exception. 6850 if (uint32_v->Number() != number_v->Number()) { 6851 Handle<Object> exception = 6852 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength); 6853 isolate->Throw(*exception); 6854 return false; 6855 } 6856 CHECK(uint32_v->ToArrayLength(output)); 6857 return true; 6858 } 6859 6860 6861 // ES6 9.4.2.4 6862 // static 6863 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a, 6864 PropertyDescriptor* desc, 6865 ShouldThrow should_throw) { 6866 // 1. If the [[Value]] field of Desc is absent, then 6867 if (!desc->has_value()) { 6868 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc). 6869 return OrdinaryDefineOwnProperty( 6870 isolate, a, isolate->factory()->length_string(), desc, should_throw); 6871 } 6872 // 2. Let newLenDesc be a copy of Desc. 6873 // (Actual copying is not necessary.) 6874 PropertyDescriptor* new_len_desc = desc; 6875 // 3. - 7. Convert Desc.[[Value]] to newLen. 6876 uint32_t new_len = 0; 6877 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) { 6878 DCHECK(isolate->has_pending_exception()); 6879 return Nothing<bool>(); 6880 } 6881 // 8. Set newLenDesc.[[Value]] to newLen. 6882 // (Done below, if needed.) 6883 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 6884 PropertyDescriptor old_len_desc; 6885 Maybe<bool> success = GetOwnPropertyDescriptor( 6886 isolate, a, isolate->factory()->length_string(), &old_len_desc); 6887 // 10. (Assert) 6888 DCHECK(success.FromJust()); 6889 USE(success); 6890 // 11. Let oldLen be oldLenDesc.[[Value]]. 6891 uint32_t old_len = 0; 6892 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 6893 // 12. If newLen >= oldLen, then 6894 if (new_len >= old_len) { 6895 // 8. Set newLenDesc.[[Value]] to newLen. 6896 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc). 6897 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len)); 6898 return OrdinaryDefineOwnProperty(isolate, a, 6899 isolate->factory()->length_string(), 6900 new_len_desc, should_throw); 6901 } 6902 // 13. If oldLenDesc.[[Writable]] is false, return false. 6903 if (!old_len_desc.writable()) { 6904 RETURN_FAILURE(isolate, should_throw, 6905 NewTypeError(MessageTemplate::kRedefineDisallowed, 6906 isolate->factory()->length_string())); 6907 } 6908 // 14. If newLenDesc.[[Writable]] is absent or has the value true, 6909 // let newWritable be true. 6910 bool new_writable = false; 6911 if (!new_len_desc->has_writable() || new_len_desc->writable()) { 6912 new_writable = true; 6913 } else { 6914 // 15. Else, 6915 // 15a. Need to defer setting the [[Writable]] attribute to false in case 6916 // any elements cannot be deleted. 6917 // 15b. Let newWritable be false. (It's initialized as "false" anyway.) 6918 // 15c. Set newLenDesc.[[Writable]] to true. 6919 // (Not needed.) 6920 } 6921 // Most of steps 16 through 19 is implemented by JSArray::SetLength. 6922 JSArray::SetLength(a, new_len); 6923 // Steps 19d-ii, 20. 6924 if (!new_writable) { 6925 PropertyDescriptor readonly; 6926 readonly.set_writable(false); 6927 Maybe<bool> success = OrdinaryDefineOwnProperty( 6928 isolate, a, isolate->factory()->length_string(), &readonly, 6929 should_throw); 6930 DCHECK(success.FromJust()); 6931 USE(success); 6932 } 6933 uint32_t actual_new_len = 0; 6934 CHECK(a->length()->ToArrayLength(&actual_new_len)); 6935 // Steps 19d-v, 21. Return false if there were non-deletable elements. 6936 bool result = actual_new_len == new_len; 6937 if (!result) { 6938 RETURN_FAILURE( 6939 isolate, should_throw, 6940 NewTypeError(MessageTemplate::kStrictDeleteProperty, 6941 isolate->factory()->NewNumberFromUint(actual_new_len - 1), 6942 a)); 6943 } 6944 return Just(result); 6945 } 6946 6947 6948 // ES6 9.5.6 6949 // static 6950 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy, 6951 Handle<Object> key, 6952 PropertyDescriptor* desc, 6953 ShouldThrow should_throw) { 6954 STACK_CHECK(isolate, Nothing<bool>()); 6955 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) { 6956 return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc, 6957 should_throw); 6958 } 6959 Handle<String> trap_name = isolate->factory()->defineProperty_string(); 6960 // 1. Assert: IsPropertyKey(P) is true. 6961 DCHECK(key->IsName() || key->IsNumber()); 6962 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 6963 Handle<Object> handler(proxy->handler(), isolate); 6964 // 3. If handler is null, throw a TypeError exception. 6965 // 4. Assert: Type(handler) is Object. 6966 if (proxy->IsRevoked()) { 6967 isolate->Throw(*isolate->factory()->NewTypeError( 6968 MessageTemplate::kProxyRevoked, trap_name)); 6969 return Nothing<bool>(); 6970 } 6971 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 6972 Handle<JSReceiver> target(proxy->target(), isolate); 6973 // 6. Let trap be ? GetMethod(handler, "defineProperty"). 6974 Handle<Object> trap; 6975 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 6976 isolate, trap, 6977 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 6978 Nothing<bool>()); 6979 // 7. If trap is undefined, then: 6980 if (trap->IsUndefined(isolate)) { 6981 // 7a. Return target.[[DefineOwnProperty]](P, Desc). 6982 return JSReceiver::DefineOwnProperty(isolate, target, key, desc, 6983 should_throw); 6984 } 6985 // 8. Let descObj be FromPropertyDescriptor(Desc). 6986 Handle<Object> desc_obj = desc->ToObject(isolate); 6987 // 9. Let booleanTrapResult be 6988 // ToBoolean(? Call(trap, handler, target, P, descObj)). 6989 Handle<Name> property_name = 6990 key->IsName() 6991 ? Handle<Name>::cast(key) 6992 : Handle<Name>::cast(isolate->factory()->NumberToString(key)); 6993 // Do not leak private property names. 6994 DCHECK(!property_name->IsPrivate()); 6995 Handle<Object> trap_result_obj; 6996 Handle<Object> args[] = {target, property_name, desc_obj}; 6997 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 6998 isolate, trap_result_obj, 6999 Execution::Call(isolate, trap, handler, arraysize(args), args), 7000 Nothing<bool>()); 7001 // 10. If booleanTrapResult is false, return false. 7002 if (!trap_result_obj->BooleanValue()) { 7003 RETURN_FAILURE(isolate, should_throw, 7004 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 7005 trap_name, property_name)); 7006 } 7007 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P). 7008 PropertyDescriptor target_desc; 7009 Maybe<bool> target_found = 7010 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc); 7011 MAYBE_RETURN(target_found, Nothing<bool>()); 7012 // 12. Let extensibleTarget be ? IsExtensible(target). 7013 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target); 7014 MAYBE_RETURN(maybe_extensible, Nothing<bool>()); 7015 bool extensible_target = maybe_extensible.FromJust(); 7016 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] 7017 // is false, then: 7018 // 13a. Let settingConfigFalse be true. 7019 // 14. Else let settingConfigFalse be false. 7020 bool setting_config_false = desc->has_configurable() && !desc->configurable(); 7021 // 15. If targetDesc is undefined, then 7022 if (!target_found.FromJust()) { 7023 // 15a. If extensibleTarget is false, throw a TypeError exception. 7024 if (!extensible_target) { 7025 isolate->Throw(*isolate->factory()->NewTypeError( 7026 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name)); 7027 return Nothing<bool>(); 7028 } 7029 // 15b. If settingConfigFalse is true, throw a TypeError exception. 7030 if (setting_config_false) { 7031 isolate->Throw(*isolate->factory()->NewTypeError( 7032 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 7033 return Nothing<bool>(); 7034 } 7035 } else { 7036 // 16. Else targetDesc is not undefined, 7037 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, 7038 // targetDesc) is false, throw a TypeError exception. 7039 Maybe<bool> valid = 7040 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc, 7041 &target_desc, property_name, DONT_THROW); 7042 MAYBE_RETURN(valid, Nothing<bool>()); 7043 if (!valid.FromJust()) { 7044 isolate->Throw(*isolate->factory()->NewTypeError( 7045 MessageTemplate::kProxyDefinePropertyIncompatible, property_name)); 7046 return Nothing<bool>(); 7047 } 7048 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is 7049 // true, throw a TypeError exception. 7050 if (setting_config_false && target_desc.configurable()) { 7051 isolate->Throw(*isolate->factory()->NewTypeError( 7052 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 7053 return Nothing<bool>(); 7054 } 7055 } 7056 // 17. Return true. 7057 return Just(true); 7058 } 7059 7060 7061 // static 7062 Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy, 7063 Handle<Symbol> private_name, 7064 PropertyDescriptor* desc, 7065 ShouldThrow should_throw) { 7066 // Despite the generic name, this can only add private data properties. 7067 if (!PropertyDescriptor::IsDataDescriptor(desc) || 7068 desc->ToAttributes() != DONT_ENUM) { 7069 RETURN_FAILURE(isolate, should_throw, 7070 NewTypeError(MessageTemplate::kProxyPrivate)); 7071 } 7072 DCHECK(proxy->map()->is_dictionary_map()); 7073 Handle<Object> value = 7074 desc->has_value() 7075 ? desc->value() 7076 : Handle<Object>::cast(isolate->factory()->undefined_value()); 7077 7078 LookupIterator it(proxy, private_name, proxy); 7079 7080 if (it.IsFound()) { 7081 DCHECK_EQ(LookupIterator::DATA, it.state()); 7082 DCHECK_EQ(DONT_ENUM, it.property_attributes()); 7083 it.WriteDataValue(value); 7084 return Just(true); 7085 } 7086 7087 Handle<NameDictionary> dict(proxy->property_dictionary()); 7088 PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell); 7089 Handle<NameDictionary> result = 7090 NameDictionary::Add(dict, private_name, value, details); 7091 if (!dict.is_identical_to(result)) proxy->set_properties(*result); 7092 return Just(true); 7093 } 7094 7095 7096 // static 7097 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate, 7098 Handle<JSReceiver> object, 7099 Handle<Object> key, 7100 PropertyDescriptor* desc) { 7101 bool success = false; 7102 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... 7103 LookupIterator it = LookupIterator::PropertyOrElement( 7104 isolate, object, key, &success, LookupIterator::OWN); 7105 DCHECK(success); // ...so creating a LookupIterator can't fail. 7106 return GetOwnPropertyDescriptor(&it, desc); 7107 } 7108 7109 7110 // ES6 9.1.5.1 7111 // Returns true on success, false if the property didn't exist, nothing if 7112 // an exception was thrown. 7113 // static 7114 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it, 7115 PropertyDescriptor* desc) { 7116 Isolate* isolate = it->isolate(); 7117 // "Virtual" dispatch. 7118 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) { 7119 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(), 7120 it->GetName(), desc); 7121 } 7122 7123 // 1. (Assert) 7124 // 2. If O does not have an own property with key P, return undefined. 7125 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it); 7126 MAYBE_RETURN(maybe, Nothing<bool>()); 7127 PropertyAttributes attrs = maybe.FromJust(); 7128 if (attrs == ABSENT) return Just(false); 7129 DCHECK(!isolate->has_pending_exception()); 7130 7131 // 3. Let D be a newly created Property Descriptor with no fields. 7132 DCHECK(desc->is_empty()); 7133 // 4. Let X be O's own property whose key is P. 7134 // 5. If X is a data property, then 7135 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR && 7136 it->GetAccessors()->IsAccessorPair(); 7137 if (!is_accessor_pair) { 7138 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute. 7139 Handle<Object> value; 7140 if (!Object::GetProperty(it).ToHandle(&value)) { 7141 DCHECK(isolate->has_pending_exception()); 7142 return Nothing<bool>(); 7143 } 7144 desc->set_value(value); 7145 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute 7146 desc->set_writable((attrs & READ_ONLY) == 0); 7147 } else { 7148 // 6. Else X is an accessor property, so 7149 Handle<AccessorPair> accessors = 7150 Handle<AccessorPair>::cast(it->GetAccessors()); 7151 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute. 7152 desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER)); 7153 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute. 7154 desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER)); 7155 } 7156 7157 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute. 7158 desc->set_enumerable((attrs & DONT_ENUM) == 0); 7159 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute. 7160 desc->set_configurable((attrs & DONT_DELETE) == 0); 7161 // 9. Return D. 7162 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) != 7163 PropertyDescriptor::IsDataDescriptor(desc)); 7164 return Just(true); 7165 } 7166 7167 7168 // ES6 9.5.5 7169 // static 7170 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate, 7171 Handle<JSProxy> proxy, 7172 Handle<Name> name, 7173 PropertyDescriptor* desc) { 7174 DCHECK(!name->IsPrivate()); 7175 STACK_CHECK(isolate, Nothing<bool>()); 7176 7177 Handle<String> trap_name = 7178 isolate->factory()->getOwnPropertyDescriptor_string(); 7179 // 1. (Assert) 7180 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 7181 Handle<Object> handler(proxy->handler(), isolate); 7182 // 3. If handler is null, throw a TypeError exception. 7183 // 4. Assert: Type(handler) is Object. 7184 if (proxy->IsRevoked()) { 7185 isolate->Throw(*isolate->factory()->NewTypeError( 7186 MessageTemplate::kProxyRevoked, trap_name)); 7187 return Nothing<bool>(); 7188 } 7189 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 7190 Handle<JSReceiver> target(proxy->target(), isolate); 7191 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor"). 7192 Handle<Object> trap; 7193 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7194 isolate, trap, 7195 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 7196 Nothing<bool>()); 7197 // 7. If trap is undefined, then 7198 if (trap->IsUndefined(isolate)) { 7199 // 7a. Return target.[[GetOwnProperty]](P). 7200 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc); 7201 } 7202 // 8. Let trapResultObj be ? Call(trap, handler, target, P). 7203 Handle<Object> trap_result_obj; 7204 Handle<Object> args[] = {target, name}; 7205 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7206 isolate, trap_result_obj, 7207 Execution::Call(isolate, trap, handler, arraysize(args), args), 7208 Nothing<bool>()); 7209 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a 7210 // TypeError exception. 7211 if (!trap_result_obj->IsJSReceiver() && 7212 !trap_result_obj->IsUndefined(isolate)) { 7213 isolate->Throw(*isolate->factory()->NewTypeError( 7214 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name)); 7215 return Nothing<bool>(); 7216 } 7217 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). 7218 PropertyDescriptor target_desc; 7219 Maybe<bool> found = 7220 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 7221 MAYBE_RETURN(found, Nothing<bool>()); 7222 // 11. If trapResultObj is undefined, then 7223 if (trap_result_obj->IsUndefined(isolate)) { 7224 // 11a. If targetDesc is undefined, return undefined. 7225 if (!found.FromJust()) return Just(false); 7226 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError 7227 // exception. 7228 if (!target_desc.configurable()) { 7229 isolate->Throw(*isolate->factory()->NewTypeError( 7230 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name)); 7231 return Nothing<bool>(); 7232 } 7233 // 11c. Let extensibleTarget be ? IsExtensible(target). 7234 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 7235 MAYBE_RETURN(extensible_target, Nothing<bool>()); 7236 // 11d. (Assert) 7237 // 11e. If extensibleTarget is false, throw a TypeError exception. 7238 if (!extensible_target.FromJust()) { 7239 isolate->Throw(*isolate->factory()->NewTypeError( 7240 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name)); 7241 return Nothing<bool>(); 7242 } 7243 // 11f. Return undefined. 7244 return Just(false); 7245 } 7246 // 12. Let extensibleTarget be ? IsExtensible(target). 7247 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 7248 MAYBE_RETURN(extensible_target, Nothing<bool>()); 7249 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj). 7250 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj, 7251 desc)) { 7252 DCHECK(isolate->has_pending_exception()); 7253 return Nothing<bool>(); 7254 } 7255 // 14. Call CompletePropertyDescriptor(resultDesc). 7256 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc); 7257 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget, 7258 // resultDesc, targetDesc). 7259 Maybe<bool> valid = 7260 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(), 7261 desc, &target_desc, name, DONT_THROW); 7262 MAYBE_RETURN(valid, Nothing<bool>()); 7263 // 16. If valid is false, throw a TypeError exception. 7264 if (!valid.FromJust()) { 7265 isolate->Throw(*isolate->factory()->NewTypeError( 7266 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name)); 7267 return Nothing<bool>(); 7268 } 7269 // 17. If resultDesc.[[Configurable]] is false, then 7270 if (!desc->configurable()) { 7271 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true: 7272 if (target_desc.is_empty() || target_desc.configurable()) { 7273 // 17a i. Throw a TypeError exception. 7274 isolate->Throw(*isolate->factory()->NewTypeError( 7275 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable, 7276 name)); 7277 return Nothing<bool>(); 7278 } 7279 } 7280 // 18. Return resultDesc. 7281 return Just(true); 7282 } 7283 7284 7285 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, 7286 ElementsKind kind, 7287 Object* object) { 7288 Isolate* isolate = elements->GetIsolate(); 7289 if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) { 7290 int length = IsJSArray() 7291 ? Smi::cast(JSArray::cast(this)->length())->value() 7292 : elements->length(); 7293 for (int i = 0; i < length; ++i) { 7294 Object* element = elements->get(i); 7295 if (!element->IsTheHole(isolate) && element == object) return true; 7296 } 7297 } else { 7298 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS); 7299 Object* key = 7300 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object); 7301 if (!key->IsUndefined(isolate)) return true; 7302 } 7303 return false; 7304 } 7305 7306 7307 // Check whether this object references another object. 7308 bool JSObject::ReferencesObject(Object* obj) { 7309 Map* map_of_this = map(); 7310 Heap* heap = GetHeap(); 7311 DisallowHeapAllocation no_allocation; 7312 7313 // Is the object the constructor for this object? 7314 if (map_of_this->GetConstructor() == obj) { 7315 return true; 7316 } 7317 7318 // Is the object the prototype for this object? 7319 if (map_of_this->prototype() == obj) { 7320 return true; 7321 } 7322 7323 // Check if the object is among the named properties. 7324 Object* key = SlowReverseLookup(obj); 7325 if (!key->IsUndefined(heap->isolate())) { 7326 return true; 7327 } 7328 7329 // Check if the object is among the indexed properties. 7330 ElementsKind kind = GetElementsKind(); 7331 switch (kind) { 7332 // Raw pixels and external arrays do not reference other 7333 // objects. 7334 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 7335 case TYPE##_ELEMENTS: \ 7336 break; 7337 7338 TYPED_ARRAYS(TYPED_ARRAY_CASE) 7339 #undef TYPED_ARRAY_CASE 7340 7341 case FAST_DOUBLE_ELEMENTS: 7342 case FAST_HOLEY_DOUBLE_ELEMENTS: 7343 break; 7344 case FAST_SMI_ELEMENTS: 7345 case FAST_HOLEY_SMI_ELEMENTS: 7346 break; 7347 case FAST_ELEMENTS: 7348 case FAST_HOLEY_ELEMENTS: 7349 case DICTIONARY_ELEMENTS: 7350 case FAST_STRING_WRAPPER_ELEMENTS: 7351 case SLOW_STRING_WRAPPER_ELEMENTS: { 7352 FixedArray* elements = FixedArray::cast(this->elements()); 7353 if (ReferencesObjectFromElements(elements, kind, obj)) return true; 7354 break; 7355 } 7356 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 7357 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 7358 FixedArray* parameter_map = FixedArray::cast(elements()); 7359 // Check the mapped parameters. 7360 int length = parameter_map->length(); 7361 for (int i = 2; i < length; ++i) { 7362 Object* value = parameter_map->get(i); 7363 if (!value->IsTheHole(heap->isolate()) && value == obj) return true; 7364 } 7365 // Check the arguments. 7366 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); 7367 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : 7368 FAST_HOLEY_ELEMENTS; 7369 if (ReferencesObjectFromElements(arguments, kind, obj)) return true; 7370 break; 7371 } 7372 case NO_ELEMENTS: 7373 break; 7374 } 7375 7376 // For functions check the context. 7377 if (IsJSFunction()) { 7378 // Get the constructor function for arguments array. 7379 Map* arguments_map = 7380 heap->isolate()->context()->native_context()->sloppy_arguments_map(); 7381 JSFunction* arguments_function = 7382 JSFunction::cast(arguments_map->GetConstructor()); 7383 7384 // Get the context and don't check if it is the native context. 7385 JSFunction* f = JSFunction::cast(this); 7386 Context* context = f->context(); 7387 if (context->IsNativeContext()) { 7388 return false; 7389 } 7390 7391 // Check the non-special context slots. 7392 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) { 7393 // Only check JS objects. 7394 if (context->get(i)->IsJSObject()) { 7395 JSObject* ctxobj = JSObject::cast(context->get(i)); 7396 // If it is an arguments array check the content. 7397 if (ctxobj->map()->GetConstructor() == arguments_function) { 7398 if (ctxobj->ReferencesObject(obj)) { 7399 return true; 7400 } 7401 } else if (ctxobj == obj) { 7402 return true; 7403 } 7404 } 7405 } 7406 7407 // Check the context extension (if any) if it can have references. 7408 if (context->has_extension() && !context->IsCatchContext()) { 7409 // With harmony scoping, a JSFunction may have a script context. 7410 // TODO(mvstanton): walk into the ScopeInfo. 7411 if (context->IsScriptContext()) { 7412 return false; 7413 } 7414 7415 return context->extension_object()->ReferencesObject(obj); 7416 } 7417 } 7418 7419 // No references to object. 7420 return false; 7421 } 7422 7423 7424 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver, 7425 IntegrityLevel level, 7426 ShouldThrow should_throw) { 7427 DCHECK(level == SEALED || level == FROZEN); 7428 7429 if (receiver->IsJSObject()) { 7430 Handle<JSObject> object = Handle<JSObject>::cast(receiver); 7431 if (!object->HasSloppyArgumentsElements()) { // Fast path. 7432 if (level == SEALED) { 7433 return JSObject::PreventExtensionsWithTransition<SEALED>(object, 7434 should_throw); 7435 } else { 7436 return JSObject::PreventExtensionsWithTransition<FROZEN>(object, 7437 should_throw); 7438 } 7439 } 7440 } 7441 7442 Isolate* isolate = receiver->GetIsolate(); 7443 7444 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw), 7445 Nothing<bool>()); 7446 7447 Handle<FixedArray> keys; 7448 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7449 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>()); 7450 7451 PropertyDescriptor no_conf; 7452 no_conf.set_configurable(false); 7453 7454 PropertyDescriptor no_conf_no_write; 7455 no_conf_no_write.set_configurable(false); 7456 no_conf_no_write.set_writable(false); 7457 7458 if (level == SEALED) { 7459 for (int i = 0; i < keys->length(); ++i) { 7460 Handle<Object> key(keys->get(i), isolate); 7461 MAYBE_RETURN( 7462 DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR), 7463 Nothing<bool>()); 7464 } 7465 return Just(true); 7466 } 7467 7468 for (int i = 0; i < keys->length(); ++i) { 7469 Handle<Object> key(keys->get(i), isolate); 7470 PropertyDescriptor current_desc; 7471 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( 7472 isolate, receiver, key, ¤t_desc); 7473 MAYBE_RETURN(owned, Nothing<bool>()); 7474 if (owned.FromJust()) { 7475 PropertyDescriptor desc = 7476 PropertyDescriptor::IsAccessorDescriptor(¤t_desc) 7477 ? no_conf 7478 : no_conf_no_write; 7479 MAYBE_RETURN( 7480 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR), 7481 Nothing<bool>()); 7482 } 7483 } 7484 return Just(true); 7485 } 7486 7487 7488 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object, 7489 IntegrityLevel level) { 7490 DCHECK(level == SEALED || level == FROZEN); 7491 Isolate* isolate = object->GetIsolate(); 7492 7493 Maybe<bool> extensible = JSReceiver::IsExtensible(object); 7494 MAYBE_RETURN(extensible, Nothing<bool>()); 7495 if (extensible.FromJust()) return Just(false); 7496 7497 Handle<FixedArray> keys; 7498 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7499 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>()); 7500 7501 for (int i = 0; i < keys->length(); ++i) { 7502 Handle<Object> key(keys->get(i), isolate); 7503 PropertyDescriptor current_desc; 7504 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( 7505 isolate, object, key, ¤t_desc); 7506 MAYBE_RETURN(owned, Nothing<bool>()); 7507 if (owned.FromJust()) { 7508 if (current_desc.configurable()) return Just(false); 7509 if (level == FROZEN && 7510 PropertyDescriptor::IsDataDescriptor(¤t_desc) && 7511 current_desc.writable()) { 7512 return Just(false); 7513 } 7514 } 7515 } 7516 return Just(true); 7517 } 7518 7519 7520 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, 7521 ShouldThrow should_throw) { 7522 if (object->IsJSProxy()) { 7523 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object), 7524 should_throw); 7525 } 7526 DCHECK(object->IsJSObject()); 7527 return JSObject::PreventExtensions(Handle<JSObject>::cast(object), 7528 should_throw); 7529 } 7530 7531 7532 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy, 7533 ShouldThrow should_throw) { 7534 Isolate* isolate = proxy->GetIsolate(); 7535 STACK_CHECK(isolate, Nothing<bool>()); 7536 Factory* factory = isolate->factory(); 7537 Handle<String> trap_name = factory->preventExtensions_string(); 7538 7539 if (proxy->IsRevoked()) { 7540 isolate->Throw( 7541 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 7542 return Nothing<bool>(); 7543 } 7544 Handle<JSReceiver> target(proxy->target(), isolate); 7545 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 7546 7547 Handle<Object> trap; 7548 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7549 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 7550 if (trap->IsUndefined(isolate)) { 7551 return JSReceiver::PreventExtensions(target, should_throw); 7552 } 7553 7554 Handle<Object> trap_result; 7555 Handle<Object> args[] = {target}; 7556 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7557 isolate, trap_result, 7558 Execution::Call(isolate, trap, handler, arraysize(args), args), 7559 Nothing<bool>()); 7560 if (!trap_result->BooleanValue()) { 7561 RETURN_FAILURE( 7562 isolate, should_throw, 7563 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 7564 } 7565 7566 // Enforce the invariant. 7567 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 7568 MAYBE_RETURN(target_result, Nothing<bool>()); 7569 if (target_result.FromJust()) { 7570 isolate->Throw(*factory->NewTypeError( 7571 MessageTemplate::kProxyPreventExtensionsExtensible)); 7572 return Nothing<bool>(); 7573 } 7574 return Just(true); 7575 } 7576 7577 7578 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, 7579 ShouldThrow should_throw) { 7580 Isolate* isolate = object->GetIsolate(); 7581 7582 if (!object->HasSloppyArgumentsElements()) { 7583 return PreventExtensionsWithTransition<NONE>(object, should_throw); 7584 } 7585 7586 if (object->IsAccessCheckNeeded() && 7587 !isolate->MayAccess(handle(isolate->context()), object)) { 7588 isolate->ReportFailedAccessCheck(object); 7589 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 7590 RETURN_FAILURE(isolate, should_throw, 7591 NewTypeError(MessageTemplate::kNoAccess)); 7592 } 7593 7594 if (!object->map()->is_extensible()) return Just(true); 7595 7596 if (object->IsJSGlobalProxy()) { 7597 PrototypeIterator iter(isolate, object); 7598 if (iter.IsAtEnd()) return Just(true); 7599 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); 7600 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter), 7601 should_throw); 7602 } 7603 7604 if (!object->HasFixedTypedArrayElements()) { 7605 // If there are fast elements we normalize. 7606 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); 7607 DCHECK(object->HasDictionaryElements() || 7608 object->HasSlowArgumentsElements()); 7609 7610 // Make sure that we never go back to fast case. 7611 object->RequireSlowElements(*dictionary); 7612 } 7613 7614 // Do a map transition, other objects with this map may still 7615 // be extensible. 7616 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. 7617 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions"); 7618 7619 new_map->set_is_extensible(false); 7620 JSObject::MigrateToMap(object, new_map); 7621 DCHECK(!object->map()->is_extensible()); 7622 7623 return Just(true); 7624 } 7625 7626 7627 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) { 7628 if (object->IsJSProxy()) { 7629 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object)); 7630 } 7631 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object))); 7632 } 7633 7634 7635 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) { 7636 Isolate* isolate = proxy->GetIsolate(); 7637 STACK_CHECK(isolate, Nothing<bool>()); 7638 Factory* factory = isolate->factory(); 7639 Handle<String> trap_name = factory->isExtensible_string(); 7640 7641 if (proxy->IsRevoked()) { 7642 isolate->Throw( 7643 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 7644 return Nothing<bool>(); 7645 } 7646 Handle<JSReceiver> target(proxy->target(), isolate); 7647 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 7648 7649 Handle<Object> trap; 7650 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7651 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 7652 if (trap->IsUndefined(isolate)) { 7653 return JSReceiver::IsExtensible(target); 7654 } 7655 7656 Handle<Object> trap_result; 7657 Handle<Object> args[] = {target}; 7658 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7659 isolate, trap_result, 7660 Execution::Call(isolate, trap, handler, arraysize(args), args), 7661 Nothing<bool>()); 7662 7663 // Enforce the invariant. 7664 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 7665 MAYBE_RETURN(target_result, Nothing<bool>()); 7666 if (target_result.FromJust() != trap_result->BooleanValue()) { 7667 isolate->Throw( 7668 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent, 7669 factory->ToBoolean(target_result.FromJust()))); 7670 return Nothing<bool>(); 7671 } 7672 return target_result; 7673 } 7674 7675 7676 bool JSObject::IsExtensible(Handle<JSObject> object) { 7677 Isolate* isolate = object->GetIsolate(); 7678 if (object->IsAccessCheckNeeded() && 7679 !isolate->MayAccess(handle(isolate->context()), object)) { 7680 return true; 7681 } 7682 if (object->IsJSGlobalProxy()) { 7683 PrototypeIterator iter(isolate, *object); 7684 if (iter.IsAtEnd()) return false; 7685 DCHECK(iter.GetCurrent()->IsJSGlobalObject()); 7686 return iter.GetCurrent<JSObject>()->map()->is_extensible(); 7687 } 7688 return object->map()->is_extensible(); 7689 } 7690 7691 7692 template <typename Dictionary> 7693 static void ApplyAttributesToDictionary(Dictionary* dictionary, 7694 const PropertyAttributes attributes) { 7695 int capacity = dictionary->Capacity(); 7696 Isolate* isolate = dictionary->GetIsolate(); 7697 for (int i = 0; i < capacity; i++) { 7698 Object* k = dictionary->KeyAt(i); 7699 if (dictionary->IsKey(isolate, k) && 7700 !(k->IsSymbol() && Symbol::cast(k)->is_private())) { 7701 PropertyDetails details = dictionary->DetailsAt(i); 7702 int attrs = attributes; 7703 // READ_ONLY is an invalid attribute for JS setters/getters. 7704 if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) { 7705 Object* v = dictionary->ValueAt(i); 7706 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value(); 7707 if (v->IsAccessorPair()) attrs &= ~READ_ONLY; 7708 } 7709 details = details.CopyAddAttributes( 7710 static_cast<PropertyAttributes>(attrs)); 7711 dictionary->DetailsAtPut(i, details); 7712 } 7713 } 7714 } 7715 7716 7717 template <PropertyAttributes attrs> 7718 Maybe<bool> JSObject::PreventExtensionsWithTransition( 7719 Handle<JSObject> object, ShouldThrow should_throw) { 7720 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN); 7721 7722 // Sealing/freezing sloppy arguments should be handled elsewhere. 7723 DCHECK(!object->HasSloppyArgumentsElements()); 7724 7725 Isolate* isolate = object->GetIsolate(); 7726 if (object->IsAccessCheckNeeded() && 7727 !isolate->MayAccess(handle(isolate->context()), object)) { 7728 isolate->ReportFailedAccessCheck(object); 7729 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 7730 RETURN_FAILURE(isolate, should_throw, 7731 NewTypeError(MessageTemplate::kNoAccess)); 7732 } 7733 7734 if (attrs == NONE && !object->map()->is_extensible()) return Just(true); 7735 7736 if (object->IsJSGlobalProxy()) { 7737 PrototypeIterator iter(isolate, object); 7738 if (iter.IsAtEnd()) return Just(true); 7739 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); 7740 return PreventExtensionsWithTransition<attrs>( 7741 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw); 7742 } 7743 7744 Handle<SeededNumberDictionary> new_element_dictionary; 7745 if (!object->HasFixedTypedArrayElements() && 7746 !object->HasDictionaryElements() && 7747 !object->HasSlowStringWrapperElements()) { 7748 int length = 7749 object->IsJSArray() 7750 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() 7751 : object->elements()->length(); 7752 new_element_dictionary = 7753 length == 0 ? isolate->factory()->empty_slow_element_dictionary() 7754 : object->GetElementsAccessor()->Normalize(object); 7755 } 7756 7757 Handle<Symbol> transition_marker; 7758 if (attrs == NONE) { 7759 transition_marker = isolate->factory()->nonextensible_symbol(); 7760 } else if (attrs == SEALED) { 7761 transition_marker = isolate->factory()->sealed_symbol(); 7762 } else { 7763 DCHECK(attrs == FROZEN); 7764 transition_marker = isolate->factory()->frozen_symbol(); 7765 } 7766 7767 Handle<Map> old_map(object->map(), isolate); 7768 Map* transition = 7769 TransitionArray::SearchSpecial(*old_map, *transition_marker); 7770 if (transition != NULL) { 7771 Handle<Map> transition_map(transition, isolate); 7772 DCHECK(transition_map->has_dictionary_elements() || 7773 transition_map->has_fixed_typed_array_elements() || 7774 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS); 7775 DCHECK(!transition_map->is_extensible()); 7776 JSObject::MigrateToMap(object, transition_map); 7777 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) { 7778 // Create a new descriptor array with the appropriate property attributes 7779 Handle<Map> new_map = Map::CopyForPreventExtensions( 7780 old_map, attrs, transition_marker, "CopyForPreventExtensions"); 7781 JSObject::MigrateToMap(object, new_map); 7782 } else { 7783 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map()); 7784 // Slow path: need to normalize properties for safety 7785 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, 7786 "SlowPreventExtensions"); 7787 7788 // Create a new map, since other objects with this map may be extensible. 7789 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. 7790 Handle<Map> new_map = 7791 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions"); 7792 new_map->set_is_extensible(false); 7793 if (!new_element_dictionary.is_null()) { 7794 ElementsKind new_kind = 7795 IsStringWrapperElementsKind(old_map->elements_kind()) 7796 ? SLOW_STRING_WRAPPER_ELEMENTS 7797 : DICTIONARY_ELEMENTS; 7798 new_map->set_elements_kind(new_kind); 7799 } 7800 JSObject::MigrateToMap(object, new_map); 7801 7802 if (attrs != NONE) { 7803 if (object->IsJSGlobalObject()) { 7804 ApplyAttributesToDictionary(object->global_dictionary(), attrs); 7805 } else { 7806 ApplyAttributesToDictionary(object->property_dictionary(), attrs); 7807 } 7808 } 7809 } 7810 7811 // Both seal and preventExtensions always go through without modifications to 7812 // typed array elements. Freeze works only if there are no actual elements. 7813 if (object->HasFixedTypedArrayElements()) { 7814 if (attrs == FROZEN && 7815 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) { 7816 isolate->Throw(*isolate->factory()->NewTypeError( 7817 MessageTemplate::kCannotFreezeArrayBufferView)); 7818 return Nothing<bool>(); 7819 } 7820 return Just(true); 7821 } 7822 7823 DCHECK(object->map()->has_dictionary_elements() || 7824 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS); 7825 if (!new_element_dictionary.is_null()) { 7826 object->set_elements(*new_element_dictionary); 7827 } 7828 7829 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) { 7830 SeededNumberDictionary* dictionary = object->element_dictionary(); 7831 // Make sure we never go back to the fast case 7832 object->RequireSlowElements(dictionary); 7833 if (attrs != NONE) { 7834 ApplyAttributesToDictionary(dictionary, attrs); 7835 } 7836 } 7837 7838 return Just(true); 7839 } 7840 7841 7842 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object, 7843 Representation representation, 7844 FieldIndex index) { 7845 Isolate* isolate = object->GetIsolate(); 7846 if (object->IsUnboxedDoubleField(index)) { 7847 double value = object->RawFastDoublePropertyAt(index); 7848 return isolate->factory()->NewHeapNumber(value); 7849 } 7850 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate); 7851 return Object::WrapForRead(isolate, raw_value, representation); 7852 } 7853 7854 template <class ContextObject> 7855 class JSObjectWalkVisitor { 7856 public: 7857 JSObjectWalkVisitor(ContextObject* site_context, bool copying, 7858 JSObject::DeepCopyHints hints) 7859 : site_context_(site_context), 7860 copying_(copying), 7861 hints_(hints) {} 7862 7863 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object); 7864 7865 protected: 7866 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty( 7867 Handle<JSObject> object, 7868 Handle<JSObject> value) { 7869 Handle<AllocationSite> current_site = site_context()->EnterNewScope(); 7870 MaybeHandle<JSObject> copy_of_value = StructureWalk(value); 7871 site_context()->ExitScope(current_site, value); 7872 return copy_of_value; 7873 } 7874 7875 inline ContextObject* site_context() { return site_context_; } 7876 inline Isolate* isolate() { return site_context()->isolate(); } 7877 7878 inline bool copying() const { return copying_; } 7879 7880 private: 7881 ContextObject* site_context_; 7882 const bool copying_; 7883 const JSObject::DeepCopyHints hints_; 7884 }; 7885 7886 template <class ContextObject> 7887 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk( 7888 Handle<JSObject> object) { 7889 Isolate* isolate = this->isolate(); 7890 bool copying = this->copying(); 7891 bool shallow = hints_ == JSObject::kObjectIsShallow; 7892 7893 if (!shallow) { 7894 StackLimitCheck check(isolate); 7895 7896 if (check.HasOverflowed()) { 7897 isolate->StackOverflow(); 7898 return MaybeHandle<JSObject>(); 7899 } 7900 } 7901 7902 if (object->map()->is_deprecated()) { 7903 JSObject::MigrateInstance(object); 7904 } 7905 7906 Handle<JSObject> copy; 7907 if (copying) { 7908 // JSFunction objects are not allowed to be in normal boilerplates at all. 7909 DCHECK(!object->IsJSFunction()); 7910 Handle<AllocationSite> site_to_pass; 7911 if (site_context()->ShouldCreateMemento(object)) { 7912 site_to_pass = site_context()->current(); 7913 } 7914 copy = isolate->factory()->CopyJSObjectWithAllocationSite( 7915 object, site_to_pass); 7916 } else { 7917 copy = object; 7918 } 7919 7920 DCHECK(copying || copy.is_identical_to(object)); 7921 7922 ElementsKind kind = copy->GetElementsKind(); 7923 if (copying && IsFastSmiOrObjectElementsKind(kind) && 7924 FixedArray::cast(copy->elements())->map() == 7925 isolate->heap()->fixed_cow_array_map()) { 7926 isolate->counters()->cow_arrays_created_runtime()->Increment(); 7927 } 7928 7929 if (!shallow) { 7930 HandleScope scope(isolate); 7931 7932 // Deep copy own properties. 7933 if (copy->HasFastProperties()) { 7934 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors()); 7935 int limit = copy->map()->NumberOfOwnDescriptors(); 7936 for (int i = 0; i < limit; i++) { 7937 PropertyDetails details = descriptors->GetDetails(i); 7938 if (details.type() != DATA) continue; 7939 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i); 7940 if (object->IsUnboxedDoubleField(index)) { 7941 if (copying) { 7942 double value = object->RawFastDoublePropertyAt(index); 7943 copy->RawFastDoublePropertyAtPut(index, value); 7944 } 7945 } else { 7946 Handle<Object> value(object->RawFastPropertyAt(index), isolate); 7947 if (value->IsJSObject()) { 7948 ASSIGN_RETURN_ON_EXCEPTION( 7949 isolate, value, 7950 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 7951 JSObject); 7952 if (copying) { 7953 copy->FastPropertyAtPut(index, *value); 7954 } 7955 } else { 7956 if (copying) { 7957 Representation representation = details.representation(); 7958 value = Object::NewStorageFor(isolate, value, representation); 7959 copy->FastPropertyAtPut(index, *value); 7960 } 7961 } 7962 } 7963 } 7964 } else { 7965 // Only deep copy fields from the object literal expression. 7966 // In particular, don't try to copy the length attribute of 7967 // an array. 7968 PropertyFilter filter = static_cast<PropertyFilter>( 7969 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE); 7970 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter); 7971 accumulator.CollectOwnPropertyNames(copy, copy); 7972 Handle<FixedArray> names = accumulator.GetKeys(); 7973 for (int i = 0; i < names->length(); i++) { 7974 DCHECK(names->get(i)->IsName()); 7975 Handle<Name> name(Name::cast(names->get(i))); 7976 Handle<Object> value = 7977 JSObject::GetProperty(copy, name).ToHandleChecked(); 7978 if (value->IsJSObject()) { 7979 Handle<JSObject> result; 7980 ASSIGN_RETURN_ON_EXCEPTION( 7981 isolate, result, 7982 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 7983 JSObject); 7984 if (copying) { 7985 // Creating object copy for literals. No strict mode needed. 7986 JSObject::SetProperty(copy, name, result, SLOPPY).Assert(); 7987 } 7988 } 7989 } 7990 } 7991 7992 // Deep copy own elements. 7993 switch (kind) { 7994 case FAST_ELEMENTS: 7995 case FAST_HOLEY_ELEMENTS: { 7996 Handle<FixedArray> elements(FixedArray::cast(copy->elements())); 7997 if (elements->map() == isolate->heap()->fixed_cow_array_map()) { 7998 #ifdef DEBUG 7999 for (int i = 0; i < elements->length(); i++) { 8000 DCHECK(!elements->get(i)->IsJSObject()); 8001 } 8002 #endif 8003 } else { 8004 for (int i = 0; i < elements->length(); i++) { 8005 Handle<Object> value(elements->get(i), isolate); 8006 if (value->IsJSObject()) { 8007 Handle<JSObject> result; 8008 ASSIGN_RETURN_ON_EXCEPTION( 8009 isolate, result, 8010 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 8011 JSObject); 8012 if (copying) { 8013 elements->set(i, *result); 8014 } 8015 } 8016 } 8017 } 8018 break; 8019 } 8020 case DICTIONARY_ELEMENTS: { 8021 Handle<SeededNumberDictionary> element_dictionary( 8022 copy->element_dictionary()); 8023 int capacity = element_dictionary->Capacity(); 8024 for (int i = 0; i < capacity; i++) { 8025 Object* k = element_dictionary->KeyAt(i); 8026 if (element_dictionary->IsKey(isolate, k)) { 8027 Handle<Object> value(element_dictionary->ValueAt(i), isolate); 8028 if (value->IsJSObject()) { 8029 Handle<JSObject> result; 8030 ASSIGN_RETURN_ON_EXCEPTION( 8031 isolate, result, 8032 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), 8033 JSObject); 8034 if (copying) { 8035 element_dictionary->ValueAtPut(i, *result); 8036 } 8037 } 8038 } 8039 } 8040 break; 8041 } 8042 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 8043 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 8044 UNIMPLEMENTED(); 8045 break; 8046 case FAST_STRING_WRAPPER_ELEMENTS: 8047 case SLOW_STRING_WRAPPER_ELEMENTS: 8048 UNREACHABLE(); 8049 break; 8050 8051 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 8052 case TYPE##_ELEMENTS: \ 8053 8054 TYPED_ARRAYS(TYPED_ARRAY_CASE) 8055 #undef TYPED_ARRAY_CASE 8056 // Typed elements cannot be created using an object literal. 8057 UNREACHABLE(); 8058 break; 8059 8060 case FAST_SMI_ELEMENTS: 8061 case FAST_HOLEY_SMI_ELEMENTS: 8062 case FAST_DOUBLE_ELEMENTS: 8063 case FAST_HOLEY_DOUBLE_ELEMENTS: 8064 case NO_ELEMENTS: 8065 // No contained objects, nothing to do. 8066 break; 8067 } 8068 } 8069 8070 return copy; 8071 } 8072 8073 8074 MaybeHandle<JSObject> JSObject::DeepWalk( 8075 Handle<JSObject> object, 8076 AllocationSiteCreationContext* site_context) { 8077 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false, 8078 kNoHints); 8079 MaybeHandle<JSObject> result = v.StructureWalk(object); 8080 Handle<JSObject> for_assert; 8081 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object)); 8082 return result; 8083 } 8084 8085 8086 MaybeHandle<JSObject> JSObject::DeepCopy( 8087 Handle<JSObject> object, 8088 AllocationSiteUsageContext* site_context, 8089 DeepCopyHints hints) { 8090 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints); 8091 MaybeHandle<JSObject> copy = v.StructureWalk(object); 8092 Handle<JSObject> for_assert; 8093 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object)); 8094 return copy; 8095 } 8096 8097 // static 8098 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver, 8099 ToPrimitiveHint hint) { 8100 Isolate* const isolate = receiver->GetIsolate(); 8101 Handle<Object> exotic_to_prim; 8102 ASSIGN_RETURN_ON_EXCEPTION( 8103 isolate, exotic_to_prim, 8104 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object); 8105 if (!exotic_to_prim->IsUndefined(isolate)) { 8106 Handle<Object> hint_string; 8107 switch (hint) { 8108 case ToPrimitiveHint::kDefault: 8109 hint_string = isolate->factory()->default_string(); 8110 break; 8111 case ToPrimitiveHint::kNumber: 8112 hint_string = isolate->factory()->number_string(); 8113 break; 8114 case ToPrimitiveHint::kString: 8115 hint_string = isolate->factory()->string_string(); 8116 break; 8117 } 8118 Handle<Object> result; 8119 ASSIGN_RETURN_ON_EXCEPTION( 8120 isolate, result, 8121 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string), 8122 Object); 8123 if (result->IsPrimitive()) return result; 8124 THROW_NEW_ERROR(isolate, 8125 NewTypeError(MessageTemplate::kCannotConvertToPrimitive), 8126 Object); 8127 } 8128 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString) 8129 ? OrdinaryToPrimitiveHint::kString 8130 : OrdinaryToPrimitiveHint::kNumber); 8131 } 8132 8133 8134 // static 8135 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive( 8136 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) { 8137 Isolate* const isolate = receiver->GetIsolate(); 8138 Handle<String> method_names[2]; 8139 switch (hint) { 8140 case OrdinaryToPrimitiveHint::kNumber: 8141 method_names[0] = isolate->factory()->valueOf_string(); 8142 method_names[1] = isolate->factory()->toString_string(); 8143 break; 8144 case OrdinaryToPrimitiveHint::kString: 8145 method_names[0] = isolate->factory()->toString_string(); 8146 method_names[1] = isolate->factory()->valueOf_string(); 8147 break; 8148 } 8149 for (Handle<String> name : method_names) { 8150 Handle<Object> method; 8151 ASSIGN_RETURN_ON_EXCEPTION(isolate, method, 8152 JSReceiver::GetProperty(receiver, name), Object); 8153 if (method->IsCallable()) { 8154 Handle<Object> result; 8155 ASSIGN_RETURN_ON_EXCEPTION( 8156 isolate, result, Execution::Call(isolate, method, receiver, 0, NULL), 8157 Object); 8158 if (result->IsPrimitive()) return result; 8159 } 8160 } 8161 THROW_NEW_ERROR(isolate, 8162 NewTypeError(MessageTemplate::kCannotConvertToPrimitive), 8163 Object); 8164 } 8165 8166 8167 // TODO(cbruni/jkummerow): Consider moving this into elements.cc. 8168 bool JSObject::HasEnumerableElements() { 8169 // TODO(cbruni): cleanup 8170 JSObject* object = this; 8171 switch (object->GetElementsKind()) { 8172 case FAST_SMI_ELEMENTS: 8173 case FAST_ELEMENTS: 8174 case FAST_DOUBLE_ELEMENTS: { 8175 int length = object->IsJSArray() 8176 ? Smi::cast(JSArray::cast(object)->length())->value() 8177 : object->elements()->length(); 8178 return length > 0; 8179 } 8180 case FAST_HOLEY_SMI_ELEMENTS: 8181 case FAST_HOLEY_ELEMENTS: { 8182 FixedArray* elements = FixedArray::cast(object->elements()); 8183 int length = object->IsJSArray() 8184 ? Smi::cast(JSArray::cast(object)->length())->value() 8185 : elements->length(); 8186 for (int i = 0; i < length; i++) { 8187 if (!elements->is_the_hole(i)) return true; 8188 } 8189 return false; 8190 } 8191 case FAST_HOLEY_DOUBLE_ELEMENTS: { 8192 int length = object->IsJSArray() 8193 ? Smi::cast(JSArray::cast(object)->length())->value() 8194 : object->elements()->length(); 8195 // Zero-length arrays would use the empty FixedArray... 8196 if (length == 0) return false; 8197 // ...so only cast to FixedDoubleArray otherwise. 8198 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements()); 8199 for (int i = 0; i < length; i++) { 8200 if (!elements->is_the_hole(i)) return true; 8201 } 8202 return false; 8203 } 8204 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 8205 case TYPE##_ELEMENTS: 8206 8207 TYPED_ARRAYS(TYPED_ARRAY_CASE) 8208 #undef TYPED_ARRAY_CASE 8209 { 8210 int length = object->elements()->length(); 8211 return length > 0; 8212 } 8213 case DICTIONARY_ELEMENTS: { 8214 SeededNumberDictionary* elements = 8215 SeededNumberDictionary::cast(object->elements()); 8216 return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0; 8217 } 8218 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 8219 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 8220 // We're approximating non-empty arguments objects here. 8221 return true; 8222 case FAST_STRING_WRAPPER_ELEMENTS: 8223 case SLOW_STRING_WRAPPER_ELEMENTS: 8224 if (String::cast(JSValue::cast(object)->value())->length() > 0) { 8225 return true; 8226 } 8227 return object->elements()->length() > 0; 8228 case NO_ELEMENTS: 8229 return false; 8230 } 8231 UNREACHABLE(); 8232 return true; 8233 } 8234 8235 8236 int Map::NumberOfDescribedProperties(DescriptorFlag which, 8237 PropertyFilter filter) { 8238 int result = 0; 8239 DescriptorArray* descs = instance_descriptors(); 8240 int limit = which == ALL_DESCRIPTORS 8241 ? descs->number_of_descriptors() 8242 : NumberOfOwnDescriptors(); 8243 for (int i = 0; i < limit; i++) { 8244 if ((descs->GetDetails(i).attributes() & filter) == 0 && 8245 !descs->GetKey(i)->FilterKey(filter)) { 8246 result++; 8247 } 8248 } 8249 return result; 8250 } 8251 8252 8253 int Map::NextFreePropertyIndex() { 8254 int free_index = 0; 8255 int number_of_own_descriptors = NumberOfOwnDescriptors(); 8256 DescriptorArray* descs = instance_descriptors(); 8257 for (int i = 0; i < number_of_own_descriptors; i++) { 8258 PropertyDetails details = descs->GetDetails(i); 8259 if (details.location() == kField) { 8260 int candidate = details.field_index() + details.field_width_in_words(); 8261 if (candidate > free_index) free_index = candidate; 8262 } 8263 } 8264 return free_index; 8265 } 8266 8267 8268 bool Map::OnlyHasSimpleProperties() { 8269 // Wrapped string elements aren't explicitly stored in the elements backing 8270 // store, but are loaded indirectly from the underlying string. 8271 return !IsStringWrapperElementsKind(elements_kind()) && 8272 instance_type() > LAST_SPECIAL_RECEIVER_TYPE && 8273 !has_hidden_prototype() && !is_dictionary_map(); 8274 } 8275 8276 MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries( 8277 Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries, 8278 Handle<FixedArray>* result) { 8279 Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate); 8280 8281 if (!map->IsJSObjectMap()) return Just(false); 8282 if (!map->OnlyHasSimpleProperties()) return Just(false); 8283 8284 Handle<JSObject> object(JSObject::cast(*receiver)); 8285 8286 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 8287 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 8288 int number_of_own_elements = 8289 object->GetElementsAccessor()->GetCapacity(*object, object->elements()); 8290 Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray( 8291 number_of_own_descriptors + number_of_own_elements); 8292 int count = 0; 8293 8294 if (object->elements() != isolate->heap()->empty_fixed_array()) { 8295 MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries( 8296 isolate, object, values_or_entries, get_entries, &count, 8297 ENUMERABLE_STRINGS), 8298 Nothing<bool>()); 8299 } 8300 8301 bool stable = object->map() == *map; 8302 8303 for (int index = 0; index < number_of_own_descriptors; index++) { 8304 Handle<Name> next_key(descriptors->GetKey(index), isolate); 8305 if (!next_key->IsString()) continue; 8306 Handle<Object> prop_value; 8307 8308 // Directly decode from the descriptor array if |from| did not change shape. 8309 if (stable) { 8310 PropertyDetails details = descriptors->GetDetails(index); 8311 if (!details.IsEnumerable()) continue; 8312 if (details.kind() == kData) { 8313 if (details.location() == kDescriptor) { 8314 prop_value = handle(descriptors->GetValue(index), isolate); 8315 } else { 8316 Representation representation = details.representation(); 8317 FieldIndex field_index = FieldIndex::ForDescriptor(*map, index); 8318 prop_value = 8319 JSObject::FastPropertyAt(object, representation, field_index); 8320 } 8321 } else { 8322 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8323 isolate, prop_value, JSReceiver::GetProperty(object, next_key), 8324 Nothing<bool>()); 8325 stable = object->map() == *map; 8326 } 8327 } else { 8328 // If the map did change, do a slower lookup. We are still guaranteed that 8329 // the object has a simple shape, and that the key is a name. 8330 LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR); 8331 if (!it.IsFound()) continue; 8332 DCHECK(it.state() == LookupIterator::DATA || 8333 it.state() == LookupIterator::ACCESSOR); 8334 if (!it.IsEnumerable()) continue; 8335 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8336 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); 8337 } 8338 8339 if (get_entries) { 8340 prop_value = MakeEntryPair(isolate, next_key, prop_value); 8341 } 8342 8343 values_or_entries->set(count, *prop_value); 8344 count++; 8345 } 8346 8347 if (count < values_or_entries->length()) values_or_entries->Shrink(count); 8348 *result = values_or_entries; 8349 return Just(true); 8350 } 8351 8352 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, 8353 Handle<JSReceiver> object, 8354 PropertyFilter filter, 8355 bool get_entries) { 8356 Handle<FixedArray> values_or_entries; 8357 if (filter == ENUMERABLE_STRINGS) { 8358 Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries( 8359 isolate, object, get_entries, &values_or_entries); 8360 if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>(); 8361 if (fast_values_or_entries.FromJust()) return values_or_entries; 8362 } 8363 8364 PropertyFilter key_filter = 8365 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE); 8366 8367 Handle<FixedArray> keys; 8368 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8369 isolate, keys, 8370 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter, 8371 GetKeysConversion::kConvertToString), 8372 MaybeHandle<FixedArray>()); 8373 8374 values_or_entries = isolate->factory()->NewFixedArray(keys->length()); 8375 int length = 0; 8376 8377 for (int i = 0; i < keys->length(); ++i) { 8378 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate)); 8379 8380 if (filter & ONLY_ENUMERABLE) { 8381 PropertyDescriptor descriptor; 8382 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor( 8383 isolate, object, key, &descriptor); 8384 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>()); 8385 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue; 8386 } 8387 8388 Handle<Object> value; 8389 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8390 isolate, value, JSReceiver::GetPropertyOrElement(object, key), 8391 MaybeHandle<FixedArray>()); 8392 8393 if (get_entries) { 8394 Handle<FixedArray> entry_storage = 8395 isolate->factory()->NewUninitializedFixedArray(2); 8396 entry_storage->set(0, *key); 8397 entry_storage->set(1, *value); 8398 value = isolate->factory()->NewJSArrayWithElements(entry_storage, 8399 FAST_ELEMENTS, 2); 8400 } 8401 8402 values_or_entries->set(length, *value); 8403 length++; 8404 } 8405 if (length < values_or_entries->length()) values_or_entries->Shrink(length); 8406 return values_or_entries; 8407 } 8408 8409 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object, 8410 PropertyFilter filter) { 8411 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false); 8412 } 8413 8414 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object, 8415 PropertyFilter filter) { 8416 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true); 8417 } 8418 8419 bool Map::DictionaryElementsInPrototypeChainOnly() { 8420 if (IsDictionaryElementsKind(elements_kind())) { 8421 return false; 8422 } 8423 8424 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) { 8425 // Be conservative, don't walk into proxies. 8426 if (iter.GetCurrent()->IsJSProxy()) return true; 8427 // String wrappers have non-configurable, non-writable elements. 8428 if (iter.GetCurrent()->IsStringWrapper()) return true; 8429 JSObject* current = iter.GetCurrent<JSObject>(); 8430 8431 if (current->HasDictionaryElements() && 8432 current->element_dictionary()->requires_slow_elements()) { 8433 return true; 8434 } 8435 8436 if (current->HasSlowArgumentsElements()) { 8437 FixedArray* parameter_map = FixedArray::cast(current->elements()); 8438 Object* arguments = parameter_map->get(1); 8439 if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) { 8440 return true; 8441 } 8442 } 8443 } 8444 8445 return false; 8446 } 8447 8448 8449 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object, 8450 Handle<Name> name, 8451 Handle<Object> getter, 8452 Handle<Object> setter, 8453 PropertyAttributes attributes) { 8454 Isolate* isolate = object->GetIsolate(); 8455 8456 LookupIterator it = LookupIterator::PropertyOrElement( 8457 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 8458 return DefineAccessor(&it, getter, setter, attributes); 8459 } 8460 8461 8462 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it, 8463 Handle<Object> getter, 8464 Handle<Object> setter, 8465 PropertyAttributes attributes) { 8466 Isolate* isolate = it->isolate(); 8467 8468 it->UpdateProtector(); 8469 8470 if (it->state() == LookupIterator::ACCESS_CHECK) { 8471 if (!it->HasAccess()) { 8472 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 8473 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 8474 return isolate->factory()->undefined_value(); 8475 } 8476 it->Next(); 8477 } 8478 8479 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 8480 // Ignore accessors on typed arrays. 8481 if (it->IsElement() && object->HasFixedTypedArrayElements()) { 8482 return it->factory()->undefined_value(); 8483 } 8484 8485 DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) || 8486 getter->IsNull(isolate) || getter->IsFunctionTemplateInfo()); 8487 DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) || 8488 setter->IsNull(isolate) || getter->IsFunctionTemplateInfo()); 8489 it->TransitionToAccessorProperty(getter, setter, attributes); 8490 8491 return isolate->factory()->undefined_value(); 8492 } 8493 8494 8495 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object, 8496 Handle<AccessorInfo> info) { 8497 Isolate* isolate = object->GetIsolate(); 8498 Handle<Name> name(Name::cast(info->name()), isolate); 8499 8500 LookupIterator it = LookupIterator::PropertyOrElement( 8501 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 8502 8503 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that 8504 // the FailedAccessCheckCallbackFunction doesn't throw an exception. 8505 // 8506 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can 8507 // remove reliance on default return values. 8508 if (it.state() == LookupIterator::ACCESS_CHECK) { 8509 if (!it.HasAccess()) { 8510 isolate->ReportFailedAccessCheck(object); 8511 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 8512 return it.factory()->undefined_value(); 8513 } 8514 it.Next(); 8515 } 8516 8517 // Ignore accessors on typed arrays. 8518 if (it.IsElement() && object->HasFixedTypedArrayElements()) { 8519 return it.factory()->undefined_value(); 8520 } 8521 8522 CHECK(GetPropertyAttributes(&it).IsJust()); 8523 8524 // ES5 forbids turning a property into an accessor if it's not 8525 // configurable. See 8.6.1 (Table 5). 8526 if (it.IsFound() && !it.IsConfigurable()) { 8527 return it.factory()->undefined_value(); 8528 } 8529 8530 it.TransitionToAccessorPair(info, info->property_attributes()); 8531 8532 return object; 8533 } 8534 8535 Object* JSObject::SlowReverseLookup(Object* value) { 8536 if (HasFastProperties()) { 8537 int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); 8538 DescriptorArray* descs = map()->instance_descriptors(); 8539 bool value_is_number = value->IsNumber(); 8540 for (int i = 0; i < number_of_own_descriptors; i++) { 8541 if (descs->GetType(i) == DATA) { 8542 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i); 8543 if (IsUnboxedDoubleField(field_index)) { 8544 if (value_is_number) { 8545 double property = RawFastDoublePropertyAt(field_index); 8546 if (property == value->Number()) { 8547 return descs->GetKey(i); 8548 } 8549 } 8550 } else { 8551 Object* property = RawFastPropertyAt(field_index); 8552 if (field_index.is_double()) { 8553 DCHECK(property->IsMutableHeapNumber()); 8554 if (value_is_number && property->Number() == value->Number()) { 8555 return descs->GetKey(i); 8556 } 8557 } else if (property == value) { 8558 return descs->GetKey(i); 8559 } 8560 } 8561 } else if (descs->GetType(i) == DATA_CONSTANT) { 8562 if (descs->GetConstant(i) == value) { 8563 return descs->GetKey(i); 8564 } 8565 } 8566 } 8567 return GetHeap()->undefined_value(); 8568 } else if (IsJSGlobalObject()) { 8569 return global_dictionary()->SlowReverseLookup(value); 8570 } else { 8571 return property_dictionary()->SlowReverseLookup(value); 8572 } 8573 } 8574 8575 8576 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) { 8577 Isolate* isolate = map->GetIsolate(); 8578 Handle<Map> result = 8579 isolate->factory()->NewMap(map->instance_type(), instance_size); 8580 Handle<Object> prototype(map->prototype(), isolate); 8581 Map::SetPrototype(result, prototype); 8582 result->set_constructor_or_backpointer(map->GetConstructor()); 8583 result->set_bit_field(map->bit_field()); 8584 result->set_bit_field2(map->bit_field2()); 8585 int new_bit_field3 = map->bit_field3(); 8586 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); 8587 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); 8588 new_bit_field3 = EnumLengthBits::update(new_bit_field3, 8589 kInvalidEnumCacheSentinel); 8590 new_bit_field3 = Deprecated::update(new_bit_field3, false); 8591 if (!map->is_dictionary_map()) { 8592 new_bit_field3 = IsUnstable::update(new_bit_field3, false); 8593 } 8594 result->set_bit_field3(new_bit_field3); 8595 return result; 8596 } 8597 8598 8599 Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode, 8600 const char* reason) { 8601 DCHECK(!fast_map->is_dictionary_map()); 8602 8603 Isolate* isolate = fast_map->GetIsolate(); 8604 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(), 8605 isolate); 8606 bool use_cache = 8607 !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate); 8608 Handle<NormalizedMapCache> cache; 8609 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache); 8610 8611 Handle<Map> new_map; 8612 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) { 8613 #ifdef VERIFY_HEAP 8614 if (FLAG_verify_heap) new_map->DictionaryMapVerify(); 8615 #endif 8616 #ifdef ENABLE_SLOW_DCHECKS 8617 if (FLAG_enable_slow_asserts) { 8618 // The cached map should match newly created normalized map bit-by-bit, 8619 // except for the code cache, which can contain some ics which can be 8620 // applied to the shared map, dependent code and weak cell cache. 8621 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode); 8622 8623 if (new_map->is_prototype_map()) { 8624 // For prototype maps, the PrototypeInfo is not copied. 8625 DCHECK(memcmp(fresh->address(), new_map->address(), 8626 kTransitionsOrPrototypeInfoOffset) == 0); 8627 DCHECK(fresh->raw_transitions() == Smi::FromInt(0)); 8628 STATIC_ASSERT(kDescriptorsOffset == 8629 kTransitionsOrPrototypeInfoOffset + kPointerSize); 8630 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset), 8631 HeapObject::RawField(*new_map, kDescriptorsOffset), 8632 kCodeCacheOffset - kDescriptorsOffset) == 0); 8633 } else { 8634 DCHECK(memcmp(fresh->address(), new_map->address(), 8635 Map::kCodeCacheOffset) == 0); 8636 } 8637 STATIC_ASSERT(Map::kDependentCodeOffset == 8638 Map::kCodeCacheOffset + kPointerSize); 8639 STATIC_ASSERT(Map::kWeakCellCacheOffset == 8640 Map::kDependentCodeOffset + kPointerSize); 8641 int offset = Map::kWeakCellCacheOffset + kPointerSize; 8642 DCHECK(memcmp(fresh->address() + offset, 8643 new_map->address() + offset, 8644 Map::kSize - offset) == 0); 8645 } 8646 #endif 8647 } else { 8648 new_map = Map::CopyNormalized(fast_map, mode); 8649 if (use_cache) { 8650 cache->Set(fast_map, new_map); 8651 isolate->counters()->maps_normalized()->Increment(); 8652 } 8653 #if TRACE_MAPS 8654 if (FLAG_trace_maps) { 8655 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n", 8656 reinterpret_cast<void*>(*fast_map), 8657 reinterpret_cast<void*>(*new_map), reason); 8658 } 8659 #endif 8660 } 8661 fast_map->NotifyLeafMapLayoutChange(); 8662 return new_map; 8663 } 8664 8665 8666 Handle<Map> Map::CopyNormalized(Handle<Map> map, 8667 PropertyNormalizationMode mode) { 8668 int new_instance_size = map->instance_size(); 8669 if (mode == CLEAR_INOBJECT_PROPERTIES) { 8670 new_instance_size -= map->GetInObjectProperties() * kPointerSize; 8671 } 8672 8673 Handle<Map> result = RawCopy(map, new_instance_size); 8674 8675 if (mode != CLEAR_INOBJECT_PROPERTIES) { 8676 result->SetInObjectProperties(map->GetInObjectProperties()); 8677 } 8678 8679 result->set_dictionary_map(true); 8680 result->set_migration_target(false); 8681 result->set_construction_counter(kNoSlackTracking); 8682 8683 #ifdef VERIFY_HEAP 8684 if (FLAG_verify_heap) result->DictionaryMapVerify(); 8685 #endif 8686 8687 return result; 8688 } 8689 8690 8691 Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size, 8692 int in_object_properties, 8693 int unused_property_fields) { 8694 #ifdef DEBUG 8695 Isolate* isolate = map->GetIsolate(); 8696 // Strict function maps have Function as a constructor but the 8697 // Function's initial map is a sloppy function map. Same holds for 8698 // GeneratorFunction and its initial map. 8699 Object* constructor = map->GetConstructor(); 8700 DCHECK(constructor->IsJSFunction()); 8701 DCHECK(*map == JSFunction::cast(constructor)->initial_map() || 8702 *map == *isolate->strict_function_map() || 8703 *map == *isolate->strict_generator_function_map()); 8704 #endif 8705 // Initial maps must always own their descriptors and it's descriptor array 8706 // does not contain descriptors that do not belong to the map. 8707 DCHECK(map->owns_descriptors()); 8708 DCHECK_EQ(map->NumberOfOwnDescriptors(), 8709 map->instance_descriptors()->number_of_descriptors()); 8710 8711 Handle<Map> result = RawCopy(map, instance_size); 8712 8713 // Please note instance_type and instance_size are set when allocated. 8714 result->SetInObjectProperties(in_object_properties); 8715 result->set_unused_property_fields(unused_property_fields); 8716 8717 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 8718 if (number_of_own_descriptors > 0) { 8719 // The copy will use the same descriptors array. 8720 result->UpdateDescriptors(map->instance_descriptors(), 8721 map->GetLayoutDescriptor()); 8722 result->SetNumberOfOwnDescriptors(number_of_own_descriptors); 8723 8724 DCHECK_EQ(result->NumberOfFields(), 8725 in_object_properties - unused_property_fields); 8726 } 8727 8728 return result; 8729 } 8730 8731 8732 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) { 8733 Handle<Map> result = RawCopy(map, map->instance_size()); 8734 8735 // Please note instance_type and instance_size are set when allocated. 8736 if (map->IsJSObjectMap()) { 8737 result->SetInObjectProperties(map->GetInObjectProperties()); 8738 result->set_unused_property_fields(map->unused_property_fields()); 8739 } 8740 result->ClearCodeCache(map->GetHeap()); 8741 map->NotifyLeafMapLayoutChange(); 8742 return result; 8743 } 8744 8745 8746 Handle<Map> Map::ShareDescriptor(Handle<Map> map, 8747 Handle<DescriptorArray> descriptors, 8748 Descriptor* descriptor) { 8749 // Sanity check. This path is only to be taken if the map owns its descriptor 8750 // array, implying that its NumberOfOwnDescriptors equals the number of 8751 // descriptors in the descriptor array. 8752 DCHECK_EQ(map->NumberOfOwnDescriptors(), 8753 map->instance_descriptors()->number_of_descriptors()); 8754 8755 Handle<Map> result = CopyDropDescriptors(map); 8756 Handle<Name> name = descriptor->GetKey(); 8757 8758 // Ensure there's space for the new descriptor in the shared descriptor array. 8759 if (descriptors->NumberOfSlackDescriptors() == 0) { 8760 int old_size = descriptors->number_of_descriptors(); 8761 if (old_size == 0) { 8762 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1); 8763 } else { 8764 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors); 8765 EnsureDescriptorSlack(map, slack); 8766 descriptors = handle(map->instance_descriptors()); 8767 } 8768 } 8769 8770 Handle<LayoutDescriptor> layout_descriptor = 8771 FLAG_unbox_double_fields 8772 ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails()) 8773 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate()); 8774 8775 { 8776 DisallowHeapAllocation no_gc; 8777 descriptors->Append(descriptor); 8778 result->InitializeDescriptors(*descriptors, *layout_descriptor); 8779 } 8780 8781 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1); 8782 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION); 8783 8784 return result; 8785 } 8786 8787 8788 #if TRACE_MAPS 8789 8790 // static 8791 void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) { 8792 if (FLAG_trace_maps) { 8793 PrintF("[TraceMaps: %s from= %p to= %p name= ", what, 8794 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to)); 8795 name->NameShortPrint(); 8796 PrintF(" ]\n"); 8797 } 8798 } 8799 8800 8801 // static 8802 void Map::TraceAllTransitions(Map* map) { 8803 Object* transitions = map->raw_transitions(); 8804 int num_transitions = TransitionArray::NumberOfTransitions(transitions); 8805 for (int i = -0; i < num_transitions; ++i) { 8806 Map* target = TransitionArray::GetTarget(transitions, i); 8807 Name* key = TransitionArray::GetKey(transitions, i); 8808 Map::TraceTransition("Transition", map, target, key); 8809 Map::TraceAllTransitions(target); 8810 } 8811 } 8812 8813 #endif // TRACE_MAPS 8814 8815 8816 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child, 8817 Handle<Name> name, SimpleTransitionFlag flag) { 8818 if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) { 8819 parent->set_owns_descriptors(false); 8820 } else { 8821 // |parent| is initial map and it must keep the ownership, there must be no 8822 // descriptors in the descriptors array that do not belong to the map. 8823 DCHECK(parent->owns_descriptors()); 8824 DCHECK_EQ(parent->NumberOfOwnDescriptors(), 8825 parent->instance_descriptors()->number_of_descriptors()); 8826 } 8827 if (parent->is_prototype_map()) { 8828 DCHECK(child->is_prototype_map()); 8829 #if TRACE_MAPS 8830 Map::TraceTransition("NoTransition", *parent, *child, *name); 8831 #endif 8832 } else { 8833 TransitionArray::Insert(parent, name, child, flag); 8834 #if TRACE_MAPS 8835 Map::TraceTransition("Transition", *parent, *child, *name); 8836 #endif 8837 } 8838 } 8839 8840 8841 Handle<Map> Map::CopyReplaceDescriptors( 8842 Handle<Map> map, Handle<DescriptorArray> descriptors, 8843 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag, 8844 MaybeHandle<Name> maybe_name, const char* reason, 8845 SimpleTransitionFlag simple_flag) { 8846 DCHECK(descriptors->IsSortedNoDuplicates()); 8847 8848 Handle<Map> result = CopyDropDescriptors(map); 8849 8850 if (!map->is_prototype_map()) { 8851 if (flag == INSERT_TRANSITION && 8852 TransitionArray::CanHaveMoreTransitions(map)) { 8853 result->InitializeDescriptors(*descriptors, *layout_descriptor); 8854 8855 Handle<Name> name; 8856 CHECK(maybe_name.ToHandle(&name)); 8857 ConnectTransition(map, result, name, simple_flag); 8858 } else { 8859 int length = descriptors->number_of_descriptors(); 8860 for (int i = 0; i < length; i++) { 8861 descriptors->SetRepresentation(i, Representation::Tagged()); 8862 if (descriptors->GetDetails(i).type() == DATA) { 8863 descriptors->SetValue(i, FieldType::Any()); 8864 } 8865 } 8866 result->InitializeDescriptors(*descriptors, 8867 LayoutDescriptor::FastPointerLayout()); 8868 } 8869 } else { 8870 result->InitializeDescriptors(*descriptors, *layout_descriptor); 8871 } 8872 #if TRACE_MAPS 8873 if (FLAG_trace_maps && 8874 // Mirror conditions above that did not call ConnectTransition(). 8875 (map->is_prototype_map() || 8876 !(flag == INSERT_TRANSITION && 8877 TransitionArray::CanHaveMoreTransitions(map)))) { 8878 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n", 8879 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result), 8880 reason); 8881 } 8882 #endif 8883 8884 return result; 8885 } 8886 8887 8888 // Creates transition tree starting from |split_map| and adding all descriptors 8889 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors(). 8890 // The way how it is done is tricky because of GC and special descriptors 8891 // marking logic. 8892 Handle<Map> Map::AddMissingTransitions( 8893 Handle<Map> split_map, Handle<DescriptorArray> descriptors, 8894 Handle<LayoutDescriptor> full_layout_descriptor) { 8895 DCHECK(descriptors->IsSortedNoDuplicates()); 8896 int split_nof = split_map->NumberOfOwnDescriptors(); 8897 int nof_descriptors = descriptors->number_of_descriptors(); 8898 DCHECK_LT(split_nof, nof_descriptors); 8899 8900 // Start with creating last map which will own full descriptors array. 8901 // This is necessary to guarantee that GC will mark the whole descriptor 8902 // array if any of the allocations happening below fail. 8903 // Number of unused properties is temporarily incorrect and the layout 8904 // descriptor could unnecessarily be in slow mode but we will fix after 8905 // all the other intermediate maps are created. 8906 Handle<Map> last_map = CopyDropDescriptors(split_map); 8907 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor); 8908 last_map->set_unused_property_fields(0); 8909 8910 // During creation of intermediate maps we violate descriptors sharing 8911 // invariant since the last map is not yet connected to the transition tree 8912 // we create here. But it is safe because GC never trims map's descriptors 8913 // if there are no dead transitions from that map and this is exactly the 8914 // case for all the intermediate maps we create here. 8915 Handle<Map> map = split_map; 8916 for (int i = split_nof; i < nof_descriptors - 1; ++i) { 8917 Handle<Map> new_map = CopyDropDescriptors(map); 8918 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor); 8919 map = new_map; 8920 } 8921 map->NotifyLeafMapLayoutChange(); 8922 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors, 8923 full_layout_descriptor); 8924 return last_map; 8925 } 8926 8927 8928 // Since this method is used to rewrite an existing transition tree, it can 8929 // always insert transitions without checking. 8930 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child, 8931 int new_descriptor, 8932 Handle<DescriptorArray> descriptors, 8933 Handle<LayoutDescriptor> full_layout_descriptor) { 8934 DCHECK(descriptors->IsSortedNoDuplicates()); 8935 8936 child->set_instance_descriptors(*descriptors); 8937 child->SetNumberOfOwnDescriptors(new_descriptor + 1); 8938 8939 int unused_property_fields = parent->unused_property_fields(); 8940 PropertyDetails details = descriptors->GetDetails(new_descriptor); 8941 if (details.location() == kField) { 8942 unused_property_fields = parent->unused_property_fields() - 1; 8943 if (unused_property_fields < 0) { 8944 unused_property_fields += JSObject::kFieldsAdded; 8945 } 8946 } 8947 child->set_unused_property_fields(unused_property_fields); 8948 8949 if (FLAG_unbox_double_fields) { 8950 Handle<LayoutDescriptor> layout_descriptor = 8951 LayoutDescriptor::AppendIfFastOrUseFull(parent, details, 8952 full_layout_descriptor); 8953 child->set_layout_descriptor(*layout_descriptor); 8954 #ifdef VERIFY_HEAP 8955 // TODO(ishell): remove these checks from VERIFY_HEAP mode. 8956 if (FLAG_verify_heap) { 8957 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); 8958 } 8959 #else 8960 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); 8961 #endif 8962 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child)); 8963 } 8964 8965 Handle<Name> name = handle(descriptors->GetKey(new_descriptor)); 8966 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION); 8967 } 8968 8969 8970 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind, 8971 TransitionFlag flag) { 8972 Map* maybe_elements_transition_map = NULL; 8973 if (flag == INSERT_TRANSITION) { 8974 // Ensure we are requested to add elements kind transition "near the root". 8975 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(), 8976 map->NumberOfOwnDescriptors()); 8977 8978 maybe_elements_transition_map = map->ElementsTransitionMap(); 8979 DCHECK(maybe_elements_transition_map == NULL || 8980 (maybe_elements_transition_map->elements_kind() == 8981 DICTIONARY_ELEMENTS && 8982 kind == DICTIONARY_ELEMENTS)); 8983 DCHECK(!IsFastElementsKind(kind) || 8984 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind)); 8985 DCHECK(kind != map->elements_kind()); 8986 } 8987 8988 bool insert_transition = flag == INSERT_TRANSITION && 8989 TransitionArray::CanHaveMoreTransitions(map) && 8990 maybe_elements_transition_map == NULL; 8991 8992 if (insert_transition) { 8993 Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind"); 8994 new_map->set_elements_kind(kind); 8995 8996 Isolate* isolate = map->GetIsolate(); 8997 Handle<Name> name = isolate->factory()->elements_transition_symbol(); 8998 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION); 8999 return new_map; 9000 } 9001 9002 // Create a new free-floating map only if we are not allowed to store it. 9003 Handle<Map> new_map = Copy(map, "CopyAsElementsKind"); 9004 new_map->set_elements_kind(kind); 9005 return new_map; 9006 } 9007 9008 9009 Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map, 9010 LanguageMode language_mode, FunctionKind kind) { 9011 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type()); 9012 // Initial map for sloppy mode function is stored in the function 9013 // constructor. Initial maps for strict mode are cached as special transitions 9014 // using |strict_function_transition_symbol| as a key. 9015 if (language_mode == SLOPPY) return initial_map; 9016 Isolate* isolate = initial_map->GetIsolate(); 9017 Factory* factory = isolate->factory(); 9018 Handle<Symbol> transition_symbol; 9019 9020 int map_index = Context::FunctionMapIndex(language_mode, kind); 9021 Handle<Map> function_map( 9022 Map::cast(isolate->native_context()->get(map_index))); 9023 9024 STATIC_ASSERT(LANGUAGE_END == 3); 9025 switch (language_mode) { 9026 case STRICT: 9027 transition_symbol = factory->strict_function_transition_symbol(); 9028 break; 9029 default: 9030 UNREACHABLE(); 9031 break; 9032 } 9033 Map* maybe_transition = 9034 TransitionArray::SearchSpecial(*initial_map, *transition_symbol); 9035 if (maybe_transition != NULL) { 9036 return handle(maybe_transition, isolate); 9037 } 9038 initial_map->NotifyLeafMapLayoutChange(); 9039 9040 // Create new map taking descriptors from the |function_map| and all 9041 // the other details from the |initial_map|. 9042 Handle<Map> map = 9043 Map::CopyInitialMap(function_map, initial_map->instance_size(), 9044 initial_map->GetInObjectProperties(), 9045 initial_map->unused_property_fields()); 9046 map->SetConstructor(initial_map->GetConstructor()); 9047 map->set_prototype(initial_map->prototype()); 9048 9049 if (TransitionArray::CanHaveMoreTransitions(initial_map)) { 9050 Map::ConnectTransition(initial_map, map, transition_symbol, 9051 SPECIAL_TRANSITION); 9052 } 9053 return map; 9054 } 9055 9056 9057 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) { 9058 DCHECK(!map->is_prototype_map()); 9059 Handle<Map> new_map = CopyDropDescriptors(map); 9060 9061 if (map->owns_descriptors()) { 9062 // In case the map owned its own descriptors, share the descriptors and 9063 // transfer ownership to the new map. 9064 // The properties did not change, so reuse descriptors. 9065 new_map->InitializeDescriptors(map->instance_descriptors(), 9066 map->GetLayoutDescriptor()); 9067 } else { 9068 // In case the map did not own its own descriptors, a split is forced by 9069 // copying the map; creating a new descriptor array cell. 9070 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 9071 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9072 Handle<DescriptorArray> new_descriptors = 9073 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors); 9074 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9075 map->GetIsolate()); 9076 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); 9077 } 9078 9079 #if TRACE_MAPS 9080 if (FLAG_trace_maps) { 9081 PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n", 9082 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map), 9083 reason); 9084 } 9085 #endif 9086 9087 return new_map; 9088 } 9089 9090 9091 Handle<Map> Map::Copy(Handle<Map> map, const char* reason) { 9092 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 9093 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9094 Handle<DescriptorArray> new_descriptors = 9095 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors); 9096 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9097 map->GetIsolate()); 9098 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9099 OMIT_TRANSITION, MaybeHandle<Name>(), reason, 9100 SPECIAL_TRANSITION); 9101 } 9102 9103 9104 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) { 9105 Handle<Map> copy = 9106 Copy(handle(isolate->object_function()->initial_map()), "MapCreate"); 9107 9108 // Check that we do not overflow the instance size when adding the extra 9109 // inobject properties. If the instance size overflows, we allocate as many 9110 // properties as we can as inobject properties. 9111 int max_extra_properties = 9112 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2; 9113 9114 if (inobject_properties > max_extra_properties) { 9115 inobject_properties = max_extra_properties; 9116 } 9117 9118 int new_instance_size = 9119 JSObject::kHeaderSize + kPointerSize * inobject_properties; 9120 9121 // Adjust the map with the extra inobject properties. 9122 copy->SetInObjectProperties(inobject_properties); 9123 copy->set_unused_property_fields(inobject_properties); 9124 copy->set_instance_size(new_instance_size); 9125 copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy)); 9126 return copy; 9127 } 9128 9129 9130 Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map, 9131 PropertyAttributes attrs_to_add, 9132 Handle<Symbol> transition_marker, 9133 const char* reason) { 9134 int num_descriptors = map->NumberOfOwnDescriptors(); 9135 Isolate* isolate = map->GetIsolate(); 9136 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes( 9137 handle(map->instance_descriptors(), isolate), num_descriptors, 9138 attrs_to_add); 9139 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9140 isolate); 9141 Handle<Map> new_map = CopyReplaceDescriptors( 9142 map, new_desc, new_layout_descriptor, INSERT_TRANSITION, 9143 transition_marker, reason, SPECIAL_TRANSITION); 9144 new_map->set_is_extensible(false); 9145 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) { 9146 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind()) 9147 ? SLOW_STRING_WRAPPER_ELEMENTS 9148 : DICTIONARY_ELEMENTS; 9149 new_map->set_elements_kind(new_kind); 9150 } 9151 return new_map; 9152 } 9153 9154 FieldType* DescriptorArray::GetFieldType(int descriptor_number) { 9155 DCHECK(GetDetails(descriptor_number).location() == kField); 9156 Object* value = GetValue(descriptor_number); 9157 if (value->IsWeakCell()) { 9158 if (WeakCell::cast(value)->cleared()) return FieldType::None(); 9159 value = WeakCell::cast(value)->value(); 9160 } 9161 return FieldType::cast(value); 9162 } 9163 9164 namespace { 9165 9166 bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) { 9167 PropertyDetails details = descriptors->GetDetails(descriptor); 9168 switch (details.type()) { 9169 case DATA: 9170 return value->FitsRepresentation(details.representation()) && 9171 descriptors->GetFieldType(descriptor)->NowContains(value); 9172 9173 case DATA_CONSTANT: 9174 DCHECK(descriptors->GetConstant(descriptor) != value || 9175 value->FitsRepresentation(details.representation())); 9176 return descriptors->GetConstant(descriptor) == value; 9177 9178 case ACCESSOR: 9179 case ACCESSOR_CONSTANT: 9180 return false; 9181 } 9182 9183 UNREACHABLE(); 9184 return false; 9185 } 9186 9187 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor, 9188 Handle<Object> value) { 9189 if (CanHoldValue(map->instance_descriptors(), descriptor, *value)) return map; 9190 9191 Isolate* isolate = map->GetIsolate(); 9192 PropertyAttributes attributes = 9193 map->instance_descriptors()->GetDetails(descriptor).attributes(); 9194 Representation representation = value->OptimalRepresentation(); 9195 Handle<FieldType> type = value->OptimalType(isolate, representation); 9196 9197 return Map::ReconfigureProperty(map, descriptor, kData, attributes, 9198 representation, type, FORCE_FIELD); 9199 } 9200 9201 } // namespace 9202 9203 // static 9204 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, 9205 Handle<Object> value) { 9206 // Dictionaries can store any property value. 9207 DCHECK(!map->is_dictionary_map()); 9208 // Update to the newest map before storing the property. 9209 return UpdateDescriptorForValue(Update(map), descriptor, value); 9210 } 9211 9212 9213 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, 9214 Handle<Object> value, 9215 PropertyAttributes attributes, 9216 StoreFromKeyed store_mode) { 9217 RuntimeCallTimerScope stats_scope( 9218 *map, map->is_prototype_map() 9219 ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty 9220 : &RuntimeCallStats::Map_TransitionToDataProperty); 9221 9222 DCHECK(name->IsUniqueName()); 9223 DCHECK(!map->is_dictionary_map()); 9224 9225 // Migrate to the newest map before storing the property. 9226 map = Update(map); 9227 9228 Map* maybe_transition = 9229 TransitionArray::SearchTransition(*map, kData, *name, attributes); 9230 if (maybe_transition != NULL) { 9231 Handle<Map> transition(maybe_transition); 9232 int descriptor = transition->LastAdded(); 9233 9234 DCHECK_EQ(attributes, transition->instance_descriptors() 9235 ->GetDetails(descriptor) 9236 .attributes()); 9237 9238 return UpdateDescriptorForValue(transition, descriptor, value); 9239 } 9240 9241 TransitionFlag flag = INSERT_TRANSITION; 9242 MaybeHandle<Map> maybe_map; 9243 if (value->IsJSFunction()) { 9244 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag); 9245 } else if (!map->TooManyFastProperties(store_mode)) { 9246 Isolate* isolate = name->GetIsolate(); 9247 Representation representation = value->OptimalRepresentation(); 9248 Handle<FieldType> type = value->OptimalType(isolate, representation); 9249 maybe_map = 9250 Map::CopyWithField(map, name, type, attributes, representation, flag); 9251 } 9252 9253 Handle<Map> result; 9254 if (!maybe_map.ToHandle(&result)) { 9255 #if TRACE_MAPS 9256 if (FLAG_trace_maps) { 9257 Vector<char> name_buffer = Vector<char>::New(100); 9258 name->NameShortPrint(name_buffer); 9259 Vector<char> buffer = Vector<char>::New(128); 9260 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start()); 9261 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start()); 9262 } 9263 #endif 9264 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, 9265 "TooManyFastProperties"); 9266 } 9267 9268 return result; 9269 } 9270 9271 9272 Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor, 9273 PropertyKind kind, 9274 PropertyAttributes attributes) { 9275 // Dictionaries have to be reconfigured in-place. 9276 DCHECK(!map->is_dictionary_map()); 9277 9278 if (!map->GetBackPointer()->IsMap()) { 9279 // There is no benefit from reconstructing transition tree for maps without 9280 // back pointers. 9281 return CopyGeneralizeAllRepresentations( 9282 map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes, 9283 "GenAll_AttributesMismatchProtoMap"); 9284 } 9285 9286 if (FLAG_trace_generalization) { 9287 map->PrintReconfiguration(stdout, descriptor, kind, attributes); 9288 } 9289 9290 Isolate* isolate = map->GetIsolate(); 9291 Handle<Map> new_map = ReconfigureProperty( 9292 map, descriptor, kind, attributes, Representation::None(), 9293 FieldType::None(isolate), FORCE_FIELD); 9294 return new_map; 9295 } 9296 9297 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map, 9298 Handle<Name> name, int descriptor, 9299 Handle<Object> getter, 9300 Handle<Object> setter, 9301 PropertyAttributes attributes) { 9302 RuntimeCallTimerScope stats_scope( 9303 isolate, 9304 map->is_prototype_map() 9305 ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty 9306 : &RuntimeCallStats::Map_TransitionToAccessorProperty); 9307 9308 // At least one of the accessors needs to be a new value. 9309 DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate)); 9310 DCHECK(name->IsUniqueName()); 9311 9312 // Dictionary maps can always have additional data properties. 9313 if (map->is_dictionary_map()) return map; 9314 9315 // Migrate to the newest map before transitioning to the new property. 9316 map = Update(map); 9317 9318 PropertyNormalizationMode mode = map->is_prototype_map() 9319 ? KEEP_INOBJECT_PROPERTIES 9320 : CLEAR_INOBJECT_PROPERTIES; 9321 9322 Map* maybe_transition = 9323 TransitionArray::SearchTransition(*map, kAccessor, *name, attributes); 9324 if (maybe_transition != NULL) { 9325 Handle<Map> transition(maybe_transition, isolate); 9326 DescriptorArray* descriptors = transition->instance_descriptors(); 9327 int descriptor = transition->LastAdded(); 9328 DCHECK(descriptors->GetKey(descriptor)->Equals(*name)); 9329 9330 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind()); 9331 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes()); 9332 9333 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate); 9334 if (!maybe_pair->IsAccessorPair()) { 9335 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair"); 9336 } 9337 9338 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair); 9339 if (!pair->Equals(*getter, *setter)) { 9340 return Map::Normalize(map, mode, "TransitionToDifferentAccessor"); 9341 } 9342 9343 return transition; 9344 } 9345 9346 Handle<AccessorPair> pair; 9347 DescriptorArray* old_descriptors = map->instance_descriptors(); 9348 if (descriptor != DescriptorArray::kNotFound) { 9349 if (descriptor != map->LastAdded()) { 9350 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast"); 9351 } 9352 PropertyDetails old_details = old_descriptors->GetDetails(descriptor); 9353 if (old_details.type() != ACCESSOR_CONSTANT) { 9354 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors"); 9355 } 9356 9357 if (old_details.attributes() != attributes) { 9358 return Map::Normalize(map, mode, "AccessorsWithAttributes"); 9359 } 9360 9361 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate); 9362 if (!maybe_pair->IsAccessorPair()) { 9363 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair"); 9364 } 9365 9366 Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair); 9367 if (current_pair->Equals(*getter, *setter)) return map; 9368 9369 bool overwriting_accessor = false; 9370 if (!getter->IsNull(isolate) && 9371 !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) && 9372 current_pair->get(ACCESSOR_GETTER) != *getter) { 9373 overwriting_accessor = true; 9374 } 9375 if (!setter->IsNull(isolate) && 9376 !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) && 9377 current_pair->get(ACCESSOR_SETTER) != *setter) { 9378 overwriting_accessor = true; 9379 } 9380 if (overwriting_accessor) { 9381 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors"); 9382 } 9383 9384 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair)); 9385 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors || 9386 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) { 9387 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors"); 9388 } else { 9389 pair = isolate->factory()->NewAccessorPair(); 9390 } 9391 9392 pair->SetComponents(*getter, *setter); 9393 9394 TransitionFlag flag = INSERT_TRANSITION; 9395 AccessorConstantDescriptor new_desc(name, pair, attributes); 9396 return Map::CopyInsertDescriptor(map, &new_desc, flag); 9397 } 9398 9399 9400 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, 9401 Descriptor* descriptor, 9402 TransitionFlag flag) { 9403 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 9404 9405 // Share descriptors only if map owns descriptors and it not an initial map. 9406 if (flag == INSERT_TRANSITION && map->owns_descriptors() && 9407 !map->GetBackPointer()->IsUndefined(map->GetIsolate()) && 9408 TransitionArray::CanHaveMoreTransitions(map)) { 9409 return ShareDescriptor(map, descriptors, descriptor); 9410 } 9411 9412 int nof = map->NumberOfOwnDescriptors(); 9413 Handle<DescriptorArray> new_descriptors = 9414 DescriptorArray::CopyUpTo(descriptors, nof, 1); 9415 new_descriptors->Append(descriptor); 9416 9417 Handle<LayoutDescriptor> new_layout_descriptor = 9418 FLAG_unbox_double_fields 9419 ? LayoutDescriptor::New(map, new_descriptors, nof + 1) 9420 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate()); 9421 9422 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9423 flag, descriptor->GetKey(), "CopyAddDescriptor", 9424 SIMPLE_PROPERTY_TRANSITION); 9425 } 9426 9427 9428 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map, 9429 Descriptor* descriptor, 9430 TransitionFlag flag) { 9431 Handle<DescriptorArray> old_descriptors(map->instance_descriptors()); 9432 9433 // We replace the key if it is already present. 9434 int index = old_descriptors->SearchWithCache(map->GetIsolate(), 9435 *descriptor->GetKey(), *map); 9436 if (index != DescriptorArray::kNotFound) { 9437 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag); 9438 } 9439 return CopyAddDescriptor(map, descriptor, flag); 9440 } 9441 9442 9443 Handle<DescriptorArray> DescriptorArray::CopyUpTo( 9444 Handle<DescriptorArray> desc, 9445 int enumeration_index, 9446 int slack) { 9447 return DescriptorArray::CopyUpToAddAttributes( 9448 desc, enumeration_index, NONE, slack); 9449 } 9450 9451 9452 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes( 9453 Handle<DescriptorArray> desc, 9454 int enumeration_index, 9455 PropertyAttributes attributes, 9456 int slack) { 9457 if (enumeration_index + slack == 0) { 9458 return desc->GetIsolate()->factory()->empty_descriptor_array(); 9459 } 9460 9461 int size = enumeration_index; 9462 9463 Handle<DescriptorArray> descriptors = 9464 DescriptorArray::Allocate(desc->GetIsolate(), size, slack); 9465 9466 if (attributes != NONE) { 9467 for (int i = 0; i < size; ++i) { 9468 Object* value = desc->GetValue(i); 9469 Name* key = desc->GetKey(i); 9470 PropertyDetails details = desc->GetDetails(i); 9471 // Bulk attribute changes never affect private properties. 9472 if (!key->IsPrivate()) { 9473 int mask = DONT_DELETE | DONT_ENUM; 9474 // READ_ONLY is an invalid attribute for JS setters/getters. 9475 if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) { 9476 mask |= READ_ONLY; 9477 } 9478 details = details.CopyAddAttributes( 9479 static_cast<PropertyAttributes>(attributes & mask)); 9480 } 9481 Descriptor inner_desc( 9482 handle(key), handle(value, desc->GetIsolate()), details); 9483 descriptors->SetDescriptor(i, &inner_desc); 9484 } 9485 } else { 9486 for (int i = 0; i < size; ++i) { 9487 descriptors->CopyFrom(i, *desc); 9488 } 9489 } 9490 9491 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort(); 9492 9493 return descriptors; 9494 } 9495 9496 9497 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) { 9498 for (int i = 0; i < nof_descriptors; i++) { 9499 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) { 9500 return false; 9501 } 9502 PropertyDetails details = GetDetails(i); 9503 PropertyDetails other_details = desc->GetDetails(i); 9504 if (details.type() != other_details.type() || 9505 !details.representation().Equals(other_details.representation())) { 9506 return false; 9507 } 9508 } 9509 return true; 9510 } 9511 9512 9513 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map, 9514 Handle<DescriptorArray> descriptors, 9515 Descriptor* descriptor, 9516 int insertion_index, 9517 TransitionFlag flag) { 9518 Handle<Name> key = descriptor->GetKey(); 9519 DCHECK(*key == descriptors->GetKey(insertion_index)); 9520 9521 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 9522 descriptors, map->NumberOfOwnDescriptors()); 9523 9524 new_descriptors->Replace(insertion_index, descriptor); 9525 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New( 9526 map, new_descriptors, new_descriptors->number_of_descriptors()); 9527 9528 SimpleTransitionFlag simple_flag = 9529 (insertion_index == descriptors->number_of_descriptors() - 1) 9530 ? SIMPLE_PROPERTY_TRANSITION 9531 : PROPERTY_TRANSITION; 9532 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, 9533 flag, key, "CopyReplaceDescriptor", 9534 simple_flag); 9535 } 9536 9537 // Helper class to manage a Map's code cache. The layout depends on the number 9538 // of entries; this is worthwhile because most code caches are very small, 9539 // but some are huge (thousands of entries). 9540 // For zero entries, the EmptyFixedArray is used. 9541 // For one entry, we use a 2-element FixedArray containing [name, code]. 9542 // For 2..100 entries, we use a FixedArray with linear lookups, the layout is: 9543 // [0] - number of slots that are currently in use 9544 // [1] - first name 9545 // [2] - first code 9546 // [3] - second name 9547 // [4] - second code 9548 // etc. 9549 // For more than 128 entries, we use a CodeCacheHashTable. 9550 class CodeCache : public AllStatic { 9551 public: 9552 // Returns the new cache, to be stored on the map. 9553 static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache, 9554 Handle<Name> name, Handle<Code> code) { 9555 int length = cache->length(); 9556 if (length == 0) return PutFirstElement(isolate, name, code); 9557 if (length == kEntrySize) { 9558 return PutSecondElement(isolate, cache, name, code); 9559 } 9560 if (length <= kLinearMaxSize) { 9561 Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code); 9562 if (!result.is_null()) return result; 9563 // Fall through if linear storage is getting too large. 9564 } 9565 return PutHashTableElement(isolate, cache, name, code); 9566 } 9567 9568 static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) { 9569 int length = cache->length(); 9570 if (length == 0) return nullptr; 9571 if (length == kEntrySize) return OneElementLookup(cache, name, flags); 9572 if (!cache->IsCodeCacheHashTable()) { 9573 return LinearLookup(cache, name, flags); 9574 } else { 9575 return CodeCacheHashTable::cast(cache)->Lookup(name, flags); 9576 } 9577 } 9578 9579 private: 9580 static const int kNameIndex = 0; 9581 static const int kCodeIndex = 1; 9582 static const int kEntrySize = 2; 9583 9584 static const int kLinearUsageIndex = 0; 9585 static const int kLinearReservedSlots = 1; 9586 static const int kLinearInitialCapacity = 2; 9587 static const int kLinearMaxSize = 257; // == LinearSizeFor(128); 9588 9589 static const int kHashTableInitialCapacity = 200; // Number of entries. 9590 9591 static int LinearSizeFor(int entries) { 9592 return kLinearReservedSlots + kEntrySize * entries; 9593 } 9594 9595 static int LinearNewSize(int old_size) { 9596 int old_entries = (old_size - kLinearReservedSlots) / kEntrySize; 9597 return LinearSizeFor(old_entries * 2); 9598 } 9599 9600 static Code* OneElementLookup(FixedArray* cache, Name* name, 9601 Code::Flags flags) { 9602 DCHECK_EQ(cache->length(), kEntrySize); 9603 if (cache->get(kNameIndex) != name) return nullptr; 9604 Code* maybe_code = Code::cast(cache->get(kCodeIndex)); 9605 if (maybe_code->flags() != flags) return nullptr; 9606 return maybe_code; 9607 } 9608 9609 static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) { 9610 DCHECK_GE(cache->length(), kEntrySize); 9611 DCHECK(!cache->IsCodeCacheHashTable()); 9612 int usage = GetLinearUsage(cache); 9613 for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) { 9614 if (cache->get(i + kNameIndex) != name) continue; 9615 Code* code = Code::cast(cache->get(i + kCodeIndex)); 9616 if (code->flags() == flags) return code; 9617 } 9618 return nullptr; 9619 } 9620 9621 static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name, 9622 Handle<Code> code) { 9623 Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize); 9624 cache->set(kNameIndex, *name); 9625 cache->set(kCodeIndex, *code); 9626 return cache; 9627 } 9628 9629 static Handle<FixedArray> PutSecondElement(Isolate* isolate, 9630 Handle<FixedArray> cache, 9631 Handle<Name> name, 9632 Handle<Code> code) { 9633 DCHECK_EQ(cache->length(), kEntrySize); 9634 Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray( 9635 LinearSizeFor(kLinearInitialCapacity)); 9636 new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex)); 9637 new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex)); 9638 new_cache->set(LinearSizeFor(1) + kNameIndex, *name); 9639 new_cache->set(LinearSizeFor(1) + kCodeIndex, *code); 9640 new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2))); 9641 return new_cache; 9642 } 9643 9644 static Handle<FixedArray> PutLinearElement(Isolate* isolate, 9645 Handle<FixedArray> cache, 9646 Handle<Name> name, 9647 Handle<Code> code) { 9648 int length = cache->length(); 9649 int usage = GetLinearUsage(*cache); 9650 DCHECK_LE(usage, length); 9651 // Check if we need to grow. 9652 if (usage == length) { 9653 int new_length = LinearNewSize(length); 9654 if (new_length > kLinearMaxSize) return Handle<FixedArray>::null(); 9655 Handle<FixedArray> new_cache = 9656 isolate->factory()->NewFixedArray(new_length); 9657 for (int i = kLinearReservedSlots; i < length; i++) { 9658 new_cache->set(i, cache->get(i)); 9659 } 9660 cache = new_cache; 9661 } 9662 // Store new entry. 9663 DCHECK_GE(cache->length(), usage + kEntrySize); 9664 cache->set(usage + kNameIndex, *name); 9665 cache->set(usage + kCodeIndex, *code); 9666 cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize)); 9667 return cache; 9668 } 9669 9670 static Handle<FixedArray> PutHashTableElement(Isolate* isolate, 9671 Handle<FixedArray> cache, 9672 Handle<Name> name, 9673 Handle<Code> code) { 9674 // Check if we need to transition from linear to hash table storage. 9675 if (!cache->IsCodeCacheHashTable()) { 9676 // Check that the initial hash table capacity is large enough. 9677 DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128)); 9678 STATIC_ASSERT(kHashTableInitialCapacity > 128); 9679 9680 int length = cache->length(); 9681 // Only migrate from linear storage when it's full. 9682 DCHECK_EQ(length, GetLinearUsage(*cache)); 9683 DCHECK_EQ(length, kLinearMaxSize); 9684 Handle<CodeCacheHashTable> table = 9685 CodeCacheHashTable::New(isolate, kHashTableInitialCapacity); 9686 HandleScope scope(isolate); 9687 for (int i = kLinearReservedSlots; i < length; i += kEntrySize) { 9688 Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate); 9689 Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate); 9690 CodeCacheHashTable::Put(table, old_name, old_code); 9691 } 9692 cache = table; 9693 } 9694 // Store new entry. 9695 DCHECK(cache->IsCodeCacheHashTable()); 9696 return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache), 9697 name, code); 9698 } 9699 9700 static inline int GetLinearUsage(FixedArray* linear_cache) { 9701 DCHECK_GT(linear_cache->length(), kEntrySize); 9702 return Smi::cast(linear_cache->get(kLinearUsageIndex))->value(); 9703 } 9704 }; 9705 9706 void Map::UpdateCodeCache(Handle<Map> map, 9707 Handle<Name> name, 9708 Handle<Code> code) { 9709 Isolate* isolate = map->GetIsolate(); 9710 Handle<FixedArray> cache(map->code_cache(), isolate); 9711 Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code); 9712 map->set_code_cache(*new_cache); 9713 } 9714 9715 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) { 9716 return CodeCache::Lookup(code_cache(), name, flags); 9717 } 9718 9719 9720 // The key in the code cache hash table consists of the property name and the 9721 // code object. The actual match is on the name and the code flags. If a key 9722 // is created using the flags and not a code object it can only be used for 9723 // lookup not to create a new entry. 9724 class CodeCacheHashTableKey : public HashTableKey { 9725 public: 9726 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags) 9727 : name_(name), flags_(flags), code_() { 9728 DCHECK(name_->IsUniqueName()); 9729 } 9730 9731 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code) 9732 : name_(name), flags_(code->flags()), code_(code) { 9733 DCHECK(name_->IsUniqueName()); 9734 } 9735 9736 bool IsMatch(Object* other) override { 9737 DCHECK(other->IsFixedArray()); 9738 FixedArray* pair = FixedArray::cast(other); 9739 Name* name = Name::cast(pair->get(0)); 9740 Code::Flags flags = Code::cast(pair->get(1))->flags(); 9741 if (flags != flags_) return false; 9742 DCHECK(name->IsUniqueName()); 9743 return *name_ == name; 9744 } 9745 9746 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) { 9747 return name->Hash() ^ flags; 9748 } 9749 9750 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); } 9751 9752 uint32_t HashForObject(Object* obj) override { 9753 FixedArray* pair = FixedArray::cast(obj); 9754 Name* name = Name::cast(pair->get(0)); 9755 Code* code = Code::cast(pair->get(1)); 9756 return NameFlagsHashHelper(name, code->flags()); 9757 } 9758 9759 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override { 9760 Handle<Code> code = code_.ToHandleChecked(); 9761 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2); 9762 pair->set(0, *name_); 9763 pair->set(1, *code); 9764 return pair; 9765 } 9766 9767 private: 9768 Handle<Name> name_; 9769 Code::Flags flags_; 9770 // TODO(jkummerow): We should be able to get by without this. 9771 MaybeHandle<Code> code_; 9772 }; 9773 9774 9775 Handle<CodeCacheHashTable> CodeCacheHashTable::Put( 9776 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) { 9777 CodeCacheHashTableKey key(name, code); 9778 9779 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key); 9780 9781 int entry = new_cache->FindInsertionEntry(key.Hash()); 9782 Handle<Object> k = key.AsHandle(cache->GetIsolate()); 9783 9784 new_cache->set(EntryToIndex(entry), *k); 9785 new_cache->ElementAdded(); 9786 return new_cache; 9787 } 9788 9789 Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) { 9790 DisallowHeapAllocation no_alloc; 9791 CodeCacheHashTableKey key(handle(name), flags); 9792 int entry = FindEntry(&key); 9793 if (entry == kNotFound) return nullptr; 9794 return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1)); 9795 } 9796 9797 void FixedArray::Shrink(int new_length) { 9798 DCHECK(0 <= new_length && new_length <= length()); 9799 if (new_length < length()) { 9800 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( 9801 this, length() - new_length); 9802 } 9803 } 9804 9805 9806 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) { 9807 DisallowHeapAllocation no_gc; 9808 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc); 9809 for (int index = 0; index < len; index++) { 9810 dest->set(dest_pos+index, get(pos+index), mode); 9811 } 9812 } 9813 9814 9815 #ifdef DEBUG 9816 bool FixedArray::IsEqualTo(FixedArray* other) { 9817 if (length() != other->length()) return false; 9818 for (int i = 0 ; i < length(); ++i) { 9819 if (get(i) != other->get(i)) return false; 9820 } 9821 return true; 9822 } 9823 #endif 9824 9825 9826 // static 9827 void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index, 9828 Handle<HeapObject> value) { 9829 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything. 9830 Handle<WeakCell> cell = 9831 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value)) 9832 : array->GetIsolate()->factory()->NewWeakCell(value); 9833 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell); 9834 if (FLAG_trace_weak_arrays) { 9835 PrintF("[WeakFixedArray: storing at index %d ]\n", index); 9836 } 9837 array->set_last_used_index(index); 9838 } 9839 9840 9841 // static 9842 Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array, 9843 Handle<HeapObject> value, 9844 int* assigned_index) { 9845 Handle<WeakFixedArray> array = 9846 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) 9847 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) 9848 : Handle<WeakFixedArray>::cast(maybe_array); 9849 // Try to store the new entry if there's room. Optimize for consecutive 9850 // accesses. 9851 int first_index = array->last_used_index(); 9852 int length = array->Length(); 9853 if (length > 0) { 9854 for (int i = first_index;;) { 9855 if (array->IsEmptySlot((i))) { 9856 WeakFixedArray::Set(array, i, value); 9857 if (assigned_index != NULL) *assigned_index = i; 9858 return array; 9859 } 9860 if (FLAG_trace_weak_arrays) { 9861 PrintF("[WeakFixedArray: searching for free slot]\n"); 9862 } 9863 i = (i + 1) % length; 9864 if (i == first_index) break; 9865 } 9866 } 9867 9868 // No usable slot found, grow the array. 9869 int new_length = length == 0 ? 1 : length + (length >> 1) + 4; 9870 Handle<WeakFixedArray> new_array = 9871 Allocate(array->GetIsolate(), new_length, array); 9872 if (FLAG_trace_weak_arrays) { 9873 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length); 9874 } 9875 WeakFixedArray::Set(new_array, length, value); 9876 if (assigned_index != NULL) *assigned_index = length; 9877 return new_array; 9878 } 9879 9880 9881 template <class CompactionCallback> 9882 void WeakFixedArray::Compact() { 9883 FixedArray* array = FixedArray::cast(this); 9884 int new_length = kFirstIndex; 9885 for (int i = kFirstIndex; i < array->length(); i++) { 9886 Object* element = array->get(i); 9887 if (element->IsSmi()) continue; 9888 if (WeakCell::cast(element)->cleared()) continue; 9889 Object* value = WeakCell::cast(element)->value(); 9890 CompactionCallback::Callback(value, i - kFirstIndex, 9891 new_length - kFirstIndex); 9892 array->set(new_length++, element); 9893 } 9894 array->Shrink(new_length); 9895 set_last_used_index(0); 9896 } 9897 9898 9899 void WeakFixedArray::Iterator::Reset(Object* maybe_array) { 9900 if (maybe_array->IsWeakFixedArray()) { 9901 list_ = WeakFixedArray::cast(maybe_array); 9902 index_ = 0; 9903 #ifdef DEBUG 9904 last_used_index_ = list_->last_used_index(); 9905 #endif // DEBUG 9906 } 9907 } 9908 9909 9910 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value, 9911 int old_index, 9912 int new_index) { 9913 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map()); 9914 Map* map = Map::cast(value); 9915 DCHECK(map->prototype_info()->IsPrototypeInfo()); 9916 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info()); 9917 DCHECK_EQ(old_index, proto_info->registry_slot()); 9918 proto_info->set_registry_slot(new_index); 9919 } 9920 9921 9922 template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>(); 9923 template void 9924 WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>(); 9925 9926 9927 bool WeakFixedArray::Remove(Handle<HeapObject> value) { 9928 if (Length() == 0) return false; 9929 // Optimize for the most recently added element to be removed again. 9930 int first_index = last_used_index(); 9931 for (int i = first_index;;) { 9932 if (Get(i) == *value) { 9933 Clear(i); 9934 // Users of WeakFixedArray should make sure that there are no duplicates. 9935 return true; 9936 } 9937 i = (i + 1) % Length(); 9938 if (i == first_index) return false; 9939 } 9940 UNREACHABLE(); 9941 } 9942 9943 9944 // static 9945 Handle<WeakFixedArray> WeakFixedArray::Allocate( 9946 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) { 9947 DCHECK(0 <= size); 9948 Handle<FixedArray> result = 9949 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex); 9950 int index = 0; 9951 if (!initialize_from.is_null()) { 9952 DCHECK(initialize_from->Length() <= size); 9953 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from); 9954 // Copy the entries without compacting, since the PrototypeInfo relies on 9955 // the index of the entries not to change. 9956 while (index < raw_source->length()) { 9957 result->set(index, raw_source->get(index)); 9958 index++; 9959 } 9960 } 9961 while (index < result->length()) { 9962 result->set(index, Smi::FromInt(0)); 9963 index++; 9964 } 9965 return Handle<WeakFixedArray>::cast(result); 9966 } 9967 9968 9969 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj, 9970 AddMode mode) { 9971 int length = array->Length(); 9972 array = EnsureSpace(array, length + 1); 9973 if (mode == kReloadLengthAfterAllocation) { 9974 DCHECK(array->Length() <= length); 9975 length = array->Length(); 9976 } 9977 array->Set(length, *obj); 9978 array->SetLength(length + 1); 9979 return array; 9980 } 9981 9982 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1, 9983 Handle<Object> obj2, AddMode mode) { 9984 int length = array->Length(); 9985 array = EnsureSpace(array, length + 2); 9986 if (mode == kReloadLengthAfterAllocation) { 9987 length = array->Length(); 9988 } 9989 array->Set(length, *obj1); 9990 array->Set(length + 1, *obj2); 9991 array->SetLength(length + 2); 9992 return array; 9993 } 9994 9995 9996 bool ArrayList::IsFull() { 9997 int capacity = length(); 9998 return kFirstIndex + Length() == capacity; 9999 } 10000 10001 10002 Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) { 10003 int capacity = array->length(); 10004 bool empty = (capacity == 0); 10005 if (capacity < kFirstIndex + length) { 10006 Isolate* isolate = array->GetIsolate(); 10007 int new_capacity = kFirstIndex + length; 10008 new_capacity = new_capacity + Max(new_capacity / 2, 2); 10009 int grow_by = new_capacity - capacity; 10010 array = Handle<ArrayList>::cast( 10011 isolate->factory()->CopyFixedArrayAndGrow(array, grow_by)); 10012 if (empty) array->SetLength(0); 10013 } 10014 return array; 10015 } 10016 10017 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate, 10018 int number_of_descriptors, 10019 int slack, 10020 PretenureFlag pretenure) { 10021 DCHECK(0 <= number_of_descriptors); 10022 Factory* factory = isolate->factory(); 10023 // Do not use DescriptorArray::cast on incomplete object. 10024 int size = number_of_descriptors + slack; 10025 if (size == 0) return factory->empty_descriptor_array(); 10026 // Allocate the array of keys. 10027 Handle<FixedArray> result = 10028 factory->NewFixedArray(LengthFor(size), pretenure); 10029 10030 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); 10031 result->set(kEnumCacheIndex, Smi::FromInt(0)); 10032 return Handle<DescriptorArray>::cast(result); 10033 } 10034 10035 10036 void DescriptorArray::ClearEnumCache() { 10037 set(kEnumCacheIndex, Smi::FromInt(0)); 10038 } 10039 10040 10041 void DescriptorArray::Replace(int index, Descriptor* descriptor) { 10042 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index)); 10043 Set(index, descriptor); 10044 } 10045 10046 10047 // static 10048 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors, 10049 Isolate* isolate, 10050 Handle<FixedArray> new_cache, 10051 Handle<FixedArray> new_index_cache) { 10052 DCHECK(!descriptors->IsEmpty()); 10053 FixedArray* bridge_storage; 10054 bool needs_new_enum_cache = !descriptors->HasEnumCache(); 10055 if (needs_new_enum_cache) { 10056 bridge_storage = *isolate->factory()->NewFixedArray( 10057 DescriptorArray::kEnumCacheBridgeLength); 10058 } else { 10059 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex)); 10060 } 10061 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache); 10062 bridge_storage->set(kEnumCacheBridgeIndicesCacheIndex, 10063 new_index_cache.is_null() ? Object::cast(Smi::FromInt(0)) 10064 : *new_index_cache); 10065 if (needs_new_enum_cache) { 10066 descriptors->set(kEnumCacheIndex, bridge_storage); 10067 } 10068 } 10069 10070 10071 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) { 10072 Object* value = src->GetValue(index); 10073 PropertyDetails details = src->GetDetails(index); 10074 Descriptor desc(handle(src->GetKey(index)), 10075 handle(value, src->GetIsolate()), 10076 details); 10077 SetDescriptor(index, &desc); 10078 } 10079 10080 10081 void DescriptorArray::Sort() { 10082 // In-place heap sort. 10083 int len = number_of_descriptors(); 10084 // Reset sorting since the descriptor array might contain invalid pointers. 10085 for (int i = 0; i < len; ++i) SetSortedKey(i, i); 10086 // Bottom-up max-heap construction. 10087 // Index of the last node with children 10088 const int max_parent_index = (len / 2) - 1; 10089 for (int i = max_parent_index; i >= 0; --i) { 10090 int parent_index = i; 10091 const uint32_t parent_hash = GetSortedKey(i)->Hash(); 10092 while (parent_index <= max_parent_index) { 10093 int child_index = 2 * parent_index + 1; 10094 uint32_t child_hash = GetSortedKey(child_index)->Hash(); 10095 if (child_index + 1 < len) { 10096 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash(); 10097 if (right_child_hash > child_hash) { 10098 child_index++; 10099 child_hash = right_child_hash; 10100 } 10101 } 10102 if (child_hash <= parent_hash) break; 10103 SwapSortedKeys(parent_index, child_index); 10104 // Now element at child_index could be < its children. 10105 parent_index = child_index; // parent_hash remains correct. 10106 } 10107 } 10108 10109 // Extract elements and create sorted array. 10110 for (int i = len - 1; i > 0; --i) { 10111 // Put max element at the back of the array. 10112 SwapSortedKeys(0, i); 10113 // Shift down the new top element. 10114 int parent_index = 0; 10115 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash(); 10116 const int max_parent_index = (i / 2) - 1; 10117 while (parent_index <= max_parent_index) { 10118 int child_index = parent_index * 2 + 1; 10119 uint32_t child_hash = GetSortedKey(child_index)->Hash(); 10120 if (child_index + 1 < i) { 10121 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash(); 10122 if (right_child_hash > child_hash) { 10123 child_index++; 10124 child_hash = right_child_hash; 10125 } 10126 } 10127 if (child_hash <= parent_hash) break; 10128 SwapSortedKeys(parent_index, child_index); 10129 parent_index = child_index; 10130 } 10131 } 10132 DCHECK(IsSortedNoDuplicates()); 10133 } 10134 10135 10136 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) { 10137 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair(); 10138 copy->set_getter(pair->getter()); 10139 copy->set_setter(pair->setter()); 10140 return copy; 10141 } 10142 10143 Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair, 10144 AccessorComponent component) { 10145 Object* accessor = accessor_pair->get(component); 10146 if (accessor->IsFunctionTemplateInfo()) { 10147 return ApiNatives::InstantiateFunction( 10148 handle(FunctionTemplateInfo::cast(accessor))) 10149 .ToHandleChecked(); 10150 } 10151 Isolate* isolate = accessor_pair->GetIsolate(); 10152 if (accessor->IsNull(isolate)) { 10153 return isolate->factory()->undefined_value(); 10154 } 10155 return handle(accessor, isolate); 10156 } 10157 10158 Handle<DeoptimizationInputData> DeoptimizationInputData::New( 10159 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) { 10160 return Handle<DeoptimizationInputData>::cast( 10161 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count), 10162 pretenure)); 10163 } 10164 10165 10166 Handle<DeoptimizationOutputData> DeoptimizationOutputData::New( 10167 Isolate* isolate, 10168 int number_of_deopt_points, 10169 PretenureFlag pretenure) { 10170 Handle<FixedArray> result; 10171 if (number_of_deopt_points == 0) { 10172 result = isolate->factory()->empty_fixed_array(); 10173 } else { 10174 result = isolate->factory()->NewFixedArray( 10175 LengthOfFixedArray(number_of_deopt_points), pretenure); 10176 } 10177 return Handle<DeoptimizationOutputData>::cast(result); 10178 } 10179 10180 const int LiteralsArray::kFeedbackVectorOffset = 10181 LiteralsArray::OffsetOfElementAt(LiteralsArray::kVectorIndex); 10182 10183 const int LiteralsArray::kOffsetToFirstLiteral = 10184 LiteralsArray::OffsetOfElementAt(LiteralsArray::kFirstLiteralIndex); 10185 10186 // static 10187 Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate, 10188 Handle<TypeFeedbackVector> vector, 10189 int number_of_literals, 10190 PretenureFlag pretenure) { 10191 if (vector->is_empty() && number_of_literals == 0) { 10192 return Handle<LiteralsArray>::cast( 10193 isolate->factory()->empty_literals_array()); 10194 } 10195 Handle<FixedArray> literals = isolate->factory()->NewFixedArray( 10196 number_of_literals + kFirstLiteralIndex, pretenure); 10197 Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals); 10198 casted_literals->set_feedback_vector(*vector); 10199 return casted_literals; 10200 } 10201 10202 int HandlerTable::LookupRange(int pc_offset, int* data_out, 10203 CatchPrediction* prediction_out) { 10204 int innermost_handler = -1; 10205 #ifdef DEBUG 10206 // Assuming that ranges are well nested, we don't need to track the innermost 10207 // offsets. This is just to verify that the table is actually well nested. 10208 int innermost_start = std::numeric_limits<int>::min(); 10209 int innermost_end = std::numeric_limits<int>::max(); 10210 #endif 10211 for (int i = 0; i < length(); i += kRangeEntrySize) { 10212 int start_offset = Smi::cast(get(i + kRangeStartIndex))->value(); 10213 int end_offset = Smi::cast(get(i + kRangeEndIndex))->value(); 10214 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value(); 10215 int handler_offset = HandlerOffsetField::decode(handler_field); 10216 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 10217 int handler_data = Smi::cast(get(i + kRangeDataIndex))->value(); 10218 if (pc_offset > start_offset && pc_offset <= end_offset) { 10219 DCHECK_GE(start_offset, innermost_start); 10220 DCHECK_LT(end_offset, innermost_end); 10221 innermost_handler = handler_offset; 10222 #ifdef DEBUG 10223 innermost_start = start_offset; 10224 innermost_end = end_offset; 10225 #endif 10226 if (data_out) *data_out = handler_data; 10227 if (prediction_out) *prediction_out = prediction; 10228 } 10229 } 10230 return innermost_handler; 10231 } 10232 10233 10234 // TODO(turbofan): Make sure table is sorted and use binary search. 10235 int HandlerTable::LookupReturn(int pc_offset, CatchPrediction* prediction_out) { 10236 for (int i = 0; i < length(); i += kReturnEntrySize) { 10237 int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value(); 10238 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value(); 10239 if (pc_offset == return_offset) { 10240 if (prediction_out) { 10241 *prediction_out = HandlerPredictionField::decode(handler_field); 10242 } 10243 return HandlerOffsetField::decode(handler_field); 10244 } 10245 } 10246 return -1; 10247 } 10248 10249 10250 #ifdef DEBUG 10251 bool DescriptorArray::IsEqualTo(DescriptorArray* other) { 10252 if (IsEmpty()) return other->IsEmpty(); 10253 if (other->IsEmpty()) return false; 10254 if (length() != other->length()) return false; 10255 for (int i = 0; i < length(); ++i) { 10256 if (get(i) != other->get(i)) return false; 10257 } 10258 return true; 10259 } 10260 #endif 10261 10262 // static 10263 Handle<String> String::Trim(Handle<String> string, TrimMode mode) { 10264 Isolate* const isolate = string->GetIsolate(); 10265 string = String::Flatten(string); 10266 int const length = string->length(); 10267 10268 // Perform left trimming if requested. 10269 int left = 0; 10270 UnicodeCache* unicode_cache = isolate->unicode_cache(); 10271 if (mode == kTrim || mode == kTrimLeft) { 10272 while (left < length && 10273 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { 10274 left++; 10275 } 10276 } 10277 10278 // Perform right trimming if requested. 10279 int right = length; 10280 if (mode == kTrim || mode == kTrimRight) { 10281 while ( 10282 right > left && 10283 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { 10284 right--; 10285 } 10286 } 10287 10288 return isolate->factory()->NewSubString(string, left, right); 10289 } 10290 10291 bool String::LooksValid() { 10292 if (!GetIsolate()->heap()->Contains(this)) return false; 10293 return true; 10294 } 10295 10296 10297 // static 10298 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { 10299 if (name->IsString()) return Handle<String>::cast(name); 10300 // ES6 section 9.2.11 SetFunctionName, step 4. 10301 Isolate* const isolate = name->GetIsolate(); 10302 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); 10303 if (description->IsUndefined(isolate)) { 10304 return isolate->factory()->empty_string(); 10305 } 10306 IncrementalStringBuilder builder(isolate); 10307 builder.AppendCharacter('['); 10308 builder.AppendString(Handle<String>::cast(description)); 10309 builder.AppendCharacter(']'); 10310 return builder.Finish(); 10311 } 10312 10313 // static 10314 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name, 10315 Handle<String> prefix) { 10316 Handle<String> name_string; 10317 Isolate* const isolate = name->GetIsolate(); 10318 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name), 10319 String); 10320 IncrementalStringBuilder builder(isolate); 10321 builder.AppendString(prefix); 10322 builder.AppendCharacter(' '); 10323 builder.AppendString(name_string); 10324 return builder.Finish(); 10325 } 10326 10327 namespace { 10328 10329 bool AreDigits(const uint8_t* s, int from, int to) { 10330 for (int i = from; i < to; i++) { 10331 if (s[i] < '0' || s[i] > '9') return false; 10332 } 10333 10334 return true; 10335 } 10336 10337 10338 int ParseDecimalInteger(const uint8_t* s, int from, int to) { 10339 DCHECK(to - from < 10); // Overflow is not possible. 10340 DCHECK(from < to); 10341 int d = s[from] - '0'; 10342 10343 for (int i = from + 1; i < to; i++) { 10344 d = 10 * d + (s[i] - '0'); 10345 } 10346 10347 return d; 10348 } 10349 10350 } // namespace 10351 10352 10353 // static 10354 Handle<Object> String::ToNumber(Handle<String> subject) { 10355 Isolate* const isolate = subject->GetIsolate(); 10356 10357 // Flatten {subject} string first. 10358 subject = String::Flatten(subject); 10359 10360 // Fast array index case. 10361 uint32_t index; 10362 if (subject->AsArrayIndex(&index)) { 10363 return isolate->factory()->NewNumberFromUint(index); 10364 } 10365 10366 // Fast case: short integer or some sorts of junk values. 10367 if (subject->IsSeqOneByteString()) { 10368 int len = subject->length(); 10369 if (len == 0) return handle(Smi::FromInt(0), isolate); 10370 10371 DisallowHeapAllocation no_gc; 10372 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars(); 10373 bool minus = (data[0] == '-'); 10374 int start_pos = (minus ? 1 : 0); 10375 10376 if (start_pos == len) { 10377 return isolate->factory()->nan_value(); 10378 } else if (data[start_pos] > '9') { 10379 // Fast check for a junk value. A valid string may start from a 10380 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit 10381 // or the 'I' character ('Infinity'). All of that have codes not greater 10382 // than '9' except 'I' and . 10383 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { 10384 return isolate->factory()->nan_value(); 10385 } 10386 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 10387 // The maximal/minimal smi has 10 digits. If the string has less digits 10388 // we know it will fit into the smi-data type. 10389 int d = ParseDecimalInteger(data, start_pos, len); 10390 if (minus) { 10391 if (d == 0) return isolate->factory()->minus_zero_value(); 10392 d = -d; 10393 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize && 10394 (len == 1 || data[0] != '0')) { 10395 // String hash is not calculated yet but all the data are present. 10396 // Update the hash field to speed up sequential convertions. 10397 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); 10398 #ifdef DEBUG 10399 subject->Hash(); // Force hash calculation. 10400 DCHECK_EQ(static_cast<int>(subject->hash_field()), 10401 static_cast<int>(hash)); 10402 #endif 10403 subject->set_hash_field(hash); 10404 } 10405 return handle(Smi::FromInt(d), isolate); 10406 } 10407 } 10408 10409 // Slower case. 10410 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY; 10411 return isolate->factory()->NewNumber( 10412 StringToDouble(isolate->unicode_cache(), subject, flags)); 10413 } 10414 10415 10416 String::FlatContent String::GetFlatContent() { 10417 DCHECK(!AllowHeapAllocation::IsAllowed()); 10418 int length = this->length(); 10419 StringShape shape(this); 10420 String* string = this; 10421 int offset = 0; 10422 if (shape.representation_tag() == kConsStringTag) { 10423 ConsString* cons = ConsString::cast(string); 10424 if (cons->second()->length() != 0) { 10425 return FlatContent(); 10426 } 10427 string = cons->first(); 10428 shape = StringShape(string); 10429 } 10430 if (shape.representation_tag() == kSlicedStringTag) { 10431 SlicedString* slice = SlicedString::cast(string); 10432 offset = slice->offset(); 10433 string = slice->parent(); 10434 shape = StringShape(string); 10435 DCHECK(shape.representation_tag() != kConsStringTag && 10436 shape.representation_tag() != kSlicedStringTag); 10437 } 10438 if (shape.encoding_tag() == kOneByteStringTag) { 10439 const uint8_t* start; 10440 if (shape.representation_tag() == kSeqStringTag) { 10441 start = SeqOneByteString::cast(string)->GetChars(); 10442 } else { 10443 start = ExternalOneByteString::cast(string)->GetChars(); 10444 } 10445 return FlatContent(start + offset, length); 10446 } else { 10447 DCHECK(shape.encoding_tag() == kTwoByteStringTag); 10448 const uc16* start; 10449 if (shape.representation_tag() == kSeqStringTag) { 10450 start = SeqTwoByteString::cast(string)->GetChars(); 10451 } else { 10452 start = ExternalTwoByteString::cast(string)->GetChars(); 10453 } 10454 return FlatContent(start + offset, length); 10455 } 10456 } 10457 10458 10459 base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls, 10460 RobustnessFlag robust_flag, 10461 int offset, int length, 10462 int* length_return) { 10463 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { 10464 return base::SmartArrayPointer<char>(NULL); 10465 } 10466 // Negative length means the to the end of the string. 10467 if (length < 0) length = kMaxInt - offset; 10468 10469 // Compute the size of the UTF-8 string. Start at the specified offset. 10470 StringCharacterStream stream(this, offset); 10471 int character_position = offset; 10472 int utf8_bytes = 0; 10473 int last = unibrow::Utf16::kNoPreviousCharacter; 10474 while (stream.HasMore() && character_position++ < offset + length) { 10475 uint16_t character = stream.GetNext(); 10476 utf8_bytes += unibrow::Utf8::Length(character, last); 10477 last = character; 10478 } 10479 10480 if (length_return) { 10481 *length_return = utf8_bytes; 10482 } 10483 10484 char* result = NewArray<char>(utf8_bytes + 1); 10485 10486 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset. 10487 stream.Reset(this, offset); 10488 character_position = offset; 10489 int utf8_byte_position = 0; 10490 last = unibrow::Utf16::kNoPreviousCharacter; 10491 while (stream.HasMore() && character_position++ < offset + length) { 10492 uint16_t character = stream.GetNext(); 10493 if (allow_nulls == DISALLOW_NULLS && character == 0) { 10494 character = ' '; 10495 } 10496 utf8_byte_position += 10497 unibrow::Utf8::Encode(result + utf8_byte_position, character, last); 10498 last = character; 10499 } 10500 result[utf8_byte_position] = 0; 10501 return base::SmartArrayPointer<char>(result); 10502 } 10503 10504 10505 base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls, 10506 RobustnessFlag robust_flag, 10507 int* length_return) { 10508 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); 10509 } 10510 10511 10512 const uc16* String::GetTwoByteData(unsigned start) { 10513 DCHECK(!IsOneByteRepresentationUnderneath()); 10514 switch (StringShape(this).representation_tag()) { 10515 case kSeqStringTag: 10516 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); 10517 case kExternalStringTag: 10518 return ExternalTwoByteString::cast(this)-> 10519 ExternalTwoByteStringGetData(start); 10520 case kSlicedStringTag: { 10521 SlicedString* slice = SlicedString::cast(this); 10522 return slice->parent()->GetTwoByteData(start + slice->offset()); 10523 } 10524 case kConsStringTag: 10525 UNREACHABLE(); 10526 return NULL; 10527 } 10528 UNREACHABLE(); 10529 return NULL; 10530 } 10531 10532 10533 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { 10534 return reinterpret_cast<uc16*>( 10535 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start; 10536 } 10537 10538 10539 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) { 10540 Relocatable* current = isolate->relocatable_top(); 10541 while (current != NULL) { 10542 current->PostGarbageCollection(); 10543 current = current->prev_; 10544 } 10545 } 10546 10547 10548 // Reserve space for statics needing saving and restoring. 10549 int Relocatable::ArchiveSpacePerThread() { 10550 return sizeof(Relocatable*); // NOLINT 10551 } 10552 10553 10554 // Archive statics that are thread-local. 10555 char* Relocatable::ArchiveState(Isolate* isolate, char* to) { 10556 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top(); 10557 isolate->set_relocatable_top(NULL); 10558 return to + ArchiveSpacePerThread(); 10559 } 10560 10561 10562 // Restore statics that are thread-local. 10563 char* Relocatable::RestoreState(Isolate* isolate, char* from) { 10564 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from)); 10565 return from + ArchiveSpacePerThread(); 10566 } 10567 10568 10569 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) { 10570 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage); 10571 Iterate(v, top); 10572 return thread_storage + ArchiveSpacePerThread(); 10573 } 10574 10575 10576 void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) { 10577 Iterate(v, isolate->relocatable_top()); 10578 } 10579 10580 10581 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) { 10582 Relocatable* current = top; 10583 while (current != NULL) { 10584 current->IterateInstance(v); 10585 current = current->prev_; 10586 } 10587 } 10588 10589 10590 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str) 10591 : Relocatable(isolate), 10592 str_(str.location()), 10593 length_(str->length()) { 10594 PostGarbageCollection(); 10595 } 10596 10597 10598 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input) 10599 : Relocatable(isolate), 10600 str_(0), 10601 is_one_byte_(true), 10602 length_(input.length()), 10603 start_(input.start()) {} 10604 10605 10606 void FlatStringReader::PostGarbageCollection() { 10607 if (str_ == NULL) return; 10608 Handle<String> str(str_); 10609 DCHECK(str->IsFlat()); 10610 DisallowHeapAllocation no_gc; 10611 // This does not actually prevent the vector from being relocated later. 10612 String::FlatContent content = str->GetFlatContent(); 10613 DCHECK(content.IsFlat()); 10614 is_one_byte_ = content.IsOneByte(); 10615 if (is_one_byte_) { 10616 start_ = content.ToOneByteVector().start(); 10617 } else { 10618 start_ = content.ToUC16Vector().start(); 10619 } 10620 } 10621 10622 10623 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) { 10624 DCHECK(cons_string != NULL); 10625 root_ = cons_string; 10626 consumed_ = offset; 10627 // Force stack blown condition to trigger restart. 10628 depth_ = 1; 10629 maximum_depth_ = kStackSize + depth_; 10630 DCHECK(StackBlown()); 10631 } 10632 10633 10634 String* ConsStringIterator::Continue(int* offset_out) { 10635 DCHECK(depth_ != 0); 10636 DCHECK_EQ(0, *offset_out); 10637 bool blew_stack = StackBlown(); 10638 String* string = NULL; 10639 // Get the next leaf if there is one. 10640 if (!blew_stack) string = NextLeaf(&blew_stack); 10641 // Restart search from root. 10642 if (blew_stack) { 10643 DCHECK(string == NULL); 10644 string = Search(offset_out); 10645 } 10646 // Ensure future calls return null immediately. 10647 if (string == NULL) Reset(NULL); 10648 return string; 10649 } 10650 10651 10652 String* ConsStringIterator::Search(int* offset_out) { 10653 ConsString* cons_string = root_; 10654 // Reset the stack, pushing the root string. 10655 depth_ = 1; 10656 maximum_depth_ = 1; 10657 frames_[0] = cons_string; 10658 const int consumed = consumed_; 10659 int offset = 0; 10660 while (true) { 10661 // Loop until the string is found which contains the target offset. 10662 String* string = cons_string->first(); 10663 int length = string->length(); 10664 int32_t type; 10665 if (consumed < offset + length) { 10666 // Target offset is in the left branch. 10667 // Keep going if we're still in a ConString. 10668 type = string->map()->instance_type(); 10669 if ((type & kStringRepresentationMask) == kConsStringTag) { 10670 cons_string = ConsString::cast(string); 10671 PushLeft(cons_string); 10672 continue; 10673 } 10674 // Tell the stack we're done descending. 10675 AdjustMaximumDepth(); 10676 } else { 10677 // Descend right. 10678 // Update progress through the string. 10679 offset += length; 10680 // Keep going if we're still in a ConString. 10681 string = cons_string->second(); 10682 type = string->map()->instance_type(); 10683 if ((type & kStringRepresentationMask) == kConsStringTag) { 10684 cons_string = ConsString::cast(string); 10685 PushRight(cons_string); 10686 continue; 10687 } 10688 // Need this to be updated for the current string. 10689 length = string->length(); 10690 // Account for the possibility of an empty right leaf. 10691 // This happens only if we have asked for an offset outside the string. 10692 if (length == 0) { 10693 // Reset so future operations will return null immediately. 10694 Reset(NULL); 10695 return NULL; 10696 } 10697 // Tell the stack we're done descending. 10698 AdjustMaximumDepth(); 10699 // Pop stack so next iteration is in correct place. 10700 Pop(); 10701 } 10702 DCHECK(length != 0); 10703 // Adjust return values and exit. 10704 consumed_ = offset + length; 10705 *offset_out = consumed - offset; 10706 return string; 10707 } 10708 UNREACHABLE(); 10709 return NULL; 10710 } 10711 10712 10713 String* ConsStringIterator::NextLeaf(bool* blew_stack) { 10714 while (true) { 10715 // Tree traversal complete. 10716 if (depth_ == 0) { 10717 *blew_stack = false; 10718 return NULL; 10719 } 10720 // We've lost track of higher nodes. 10721 if (StackBlown()) { 10722 *blew_stack = true; 10723 return NULL; 10724 } 10725 // Go right. 10726 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)]; 10727 String* string = cons_string->second(); 10728 int32_t type = string->map()->instance_type(); 10729 if ((type & kStringRepresentationMask) != kConsStringTag) { 10730 // Pop stack so next iteration is in correct place. 10731 Pop(); 10732 int length = string->length(); 10733 // Could be a flattened ConsString. 10734 if (length == 0) continue; 10735 consumed_ += length; 10736 return string; 10737 } 10738 cons_string = ConsString::cast(string); 10739 PushRight(cons_string); 10740 // Need to traverse all the way left. 10741 while (true) { 10742 // Continue left. 10743 string = cons_string->first(); 10744 type = string->map()->instance_type(); 10745 if ((type & kStringRepresentationMask) != kConsStringTag) { 10746 AdjustMaximumDepth(); 10747 int length = string->length(); 10748 DCHECK(length != 0); 10749 consumed_ += length; 10750 return string; 10751 } 10752 cons_string = ConsString::cast(string); 10753 PushLeft(cons_string); 10754 } 10755 } 10756 UNREACHABLE(); 10757 return NULL; 10758 } 10759 10760 10761 uint16_t ConsString::ConsStringGet(int index) { 10762 DCHECK(index >= 0 && index < this->length()); 10763 10764 // Check for a flattened cons string 10765 if (second()->length() == 0) { 10766 String* left = first(); 10767 return left->Get(index); 10768 } 10769 10770 String* string = String::cast(this); 10771 10772 while (true) { 10773 if (StringShape(string).IsCons()) { 10774 ConsString* cons_string = ConsString::cast(string); 10775 String* left = cons_string->first(); 10776 if (left->length() > index) { 10777 string = left; 10778 } else { 10779 index -= left->length(); 10780 string = cons_string->second(); 10781 } 10782 } else { 10783 return string->Get(index); 10784 } 10785 } 10786 10787 UNREACHABLE(); 10788 return 0; 10789 } 10790 10791 10792 uint16_t SlicedString::SlicedStringGet(int index) { 10793 return parent()->Get(offset() + index); 10794 } 10795 10796 10797 template <typename sinkchar> 10798 void String::WriteToFlat(String* src, 10799 sinkchar* sink, 10800 int f, 10801 int t) { 10802 String* source = src; 10803 int from = f; 10804 int to = t; 10805 while (true) { 10806 DCHECK(0 <= from && from <= to && to <= source->length()); 10807 switch (StringShape(source).full_representation_tag()) { 10808 case kOneByteStringTag | kExternalStringTag: { 10809 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from, 10810 to - from); 10811 return; 10812 } 10813 case kTwoByteStringTag | kExternalStringTag: { 10814 const uc16* data = 10815 ExternalTwoByteString::cast(source)->GetChars(); 10816 CopyChars(sink, 10817 data + from, 10818 to - from); 10819 return; 10820 } 10821 case kOneByteStringTag | kSeqStringTag: { 10822 CopyChars(sink, 10823 SeqOneByteString::cast(source)->GetChars() + from, 10824 to - from); 10825 return; 10826 } 10827 case kTwoByteStringTag | kSeqStringTag: { 10828 CopyChars(sink, 10829 SeqTwoByteString::cast(source)->GetChars() + from, 10830 to - from); 10831 return; 10832 } 10833 case kOneByteStringTag | kConsStringTag: 10834 case kTwoByteStringTag | kConsStringTag: { 10835 ConsString* cons_string = ConsString::cast(source); 10836 String* first = cons_string->first(); 10837 int boundary = first->length(); 10838 if (to - boundary >= boundary - from) { 10839 // Right hand side is longer. Recurse over left. 10840 if (from < boundary) { 10841 WriteToFlat(first, sink, from, boundary); 10842 if (from == 0 && cons_string->second() == first) { 10843 CopyChars(sink + boundary, sink, boundary); 10844 return; 10845 } 10846 sink += boundary - from; 10847 from = 0; 10848 } else { 10849 from -= boundary; 10850 } 10851 to -= boundary; 10852 source = cons_string->second(); 10853 } else { 10854 // Left hand side is longer. Recurse over right. 10855 if (to > boundary) { 10856 String* second = cons_string->second(); 10857 // When repeatedly appending to a string, we get a cons string that 10858 // is unbalanced to the left, a list, essentially. We inline the 10859 // common case of sequential one-byte right child. 10860 if (to - boundary == 1) { 10861 sink[boundary - from] = static_cast<sinkchar>(second->Get(0)); 10862 } else if (second->IsSeqOneByteString()) { 10863 CopyChars(sink + boundary - from, 10864 SeqOneByteString::cast(second)->GetChars(), 10865 to - boundary); 10866 } else { 10867 WriteToFlat(second, 10868 sink + boundary - from, 10869 0, 10870 to - boundary); 10871 } 10872 to = boundary; 10873 } 10874 source = first; 10875 } 10876 break; 10877 } 10878 case kOneByteStringTag | kSlicedStringTag: 10879 case kTwoByteStringTag | kSlicedStringTag: { 10880 SlicedString* slice = SlicedString::cast(source); 10881 unsigned offset = slice->offset(); 10882 WriteToFlat(slice->parent(), sink, from + offset, to + offset); 10883 return; 10884 } 10885 } 10886 } 10887 } 10888 10889 10890 10891 template <typename SourceChar> 10892 static void CalculateLineEndsImpl(Isolate* isolate, 10893 List<int>* line_ends, 10894 Vector<const SourceChar> src, 10895 bool include_ending_line) { 10896 const int src_len = src.length(); 10897 UnicodeCache* cache = isolate->unicode_cache(); 10898 for (int i = 0; i < src_len - 1; i++) { 10899 SourceChar current = src[i]; 10900 SourceChar next = src[i + 1]; 10901 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i); 10902 } 10903 10904 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) { 10905 line_ends->Add(src_len - 1); 10906 } 10907 if (include_ending_line) { 10908 // Include one character beyond the end of script. The rewriter uses that 10909 // position for the implicit return statement. 10910 line_ends->Add(src_len); 10911 } 10912 } 10913 10914 10915 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src, 10916 bool include_ending_line) { 10917 src = Flatten(src); 10918 // Rough estimate of line count based on a roughly estimated average 10919 // length of (unpacked) code. 10920 int line_count_estimate = src->length() >> 4; 10921 List<int> line_ends(line_count_estimate); 10922 Isolate* isolate = src->GetIsolate(); 10923 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid. 10924 // Dispatch on type of strings. 10925 String::FlatContent content = src->GetFlatContent(); 10926 DCHECK(content.IsFlat()); 10927 if (content.IsOneByte()) { 10928 CalculateLineEndsImpl(isolate, 10929 &line_ends, 10930 content.ToOneByteVector(), 10931 include_ending_line); 10932 } else { 10933 CalculateLineEndsImpl(isolate, 10934 &line_ends, 10935 content.ToUC16Vector(), 10936 include_ending_line); 10937 } 10938 } 10939 int line_count = line_ends.length(); 10940 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count); 10941 for (int i = 0; i < line_count; i++) { 10942 array->set(i, Smi::FromInt(line_ends[i])); 10943 } 10944 return array; 10945 } 10946 10947 10948 // Compares the contents of two strings by reading and comparing 10949 // int-sized blocks of characters. 10950 template <typename Char> 10951 static inline bool CompareRawStringContents(const Char* const a, 10952 const Char* const b, 10953 int length) { 10954 return CompareChars(a, b, length) == 0; 10955 } 10956 10957 10958 template<typename Chars1, typename Chars2> 10959 class RawStringComparator : public AllStatic { 10960 public: 10961 static inline bool compare(const Chars1* a, const Chars2* b, int len) { 10962 DCHECK(sizeof(Chars1) != sizeof(Chars2)); 10963 for (int i = 0; i < len; i++) { 10964 if (a[i] != b[i]) { 10965 return false; 10966 } 10967 } 10968 return true; 10969 } 10970 }; 10971 10972 10973 template<> 10974 class RawStringComparator<uint16_t, uint16_t> { 10975 public: 10976 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) { 10977 return CompareRawStringContents(a, b, len); 10978 } 10979 }; 10980 10981 10982 template<> 10983 class RawStringComparator<uint8_t, uint8_t> { 10984 public: 10985 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) { 10986 return CompareRawStringContents(a, b, len); 10987 } 10988 }; 10989 10990 10991 class StringComparator { 10992 class State { 10993 public: 10994 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {} 10995 10996 void Init(String* string) { 10997 ConsString* cons_string = String::VisitFlat(this, string); 10998 iter_.Reset(cons_string); 10999 if (cons_string != NULL) { 11000 int offset; 11001 string = iter_.Next(&offset); 11002 String::VisitFlat(this, string, offset); 11003 } 11004 } 11005 11006 inline void VisitOneByteString(const uint8_t* chars, int length) { 11007 is_one_byte_ = true; 11008 buffer8_ = chars; 11009 length_ = length; 11010 } 11011 11012 inline void VisitTwoByteString(const uint16_t* chars, int length) { 11013 is_one_byte_ = false; 11014 buffer16_ = chars; 11015 length_ = length; 11016 } 11017 11018 void Advance(int consumed) { 11019 DCHECK(consumed <= length_); 11020 // Still in buffer. 11021 if (length_ != consumed) { 11022 if (is_one_byte_) { 11023 buffer8_ += consumed; 11024 } else { 11025 buffer16_ += consumed; 11026 } 11027 length_ -= consumed; 11028 return; 11029 } 11030 // Advance state. 11031 int offset; 11032 String* next = iter_.Next(&offset); 11033 DCHECK_EQ(0, offset); 11034 DCHECK(next != NULL); 11035 String::VisitFlat(this, next); 11036 } 11037 11038 ConsStringIterator iter_; 11039 bool is_one_byte_; 11040 int length_; 11041 union { 11042 const uint8_t* buffer8_; 11043 const uint16_t* buffer16_; 11044 }; 11045 11046 private: 11047 DISALLOW_COPY_AND_ASSIGN(State); 11048 }; 11049 11050 public: 11051 inline StringComparator() {} 11052 11053 template<typename Chars1, typename Chars2> 11054 static inline bool Equals(State* state_1, State* state_2, int to_check) { 11055 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_); 11056 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_); 11057 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check); 11058 } 11059 11060 bool Equals(String* string_1, String* string_2) { 11061 int length = string_1->length(); 11062 state_1_.Init(string_1); 11063 state_2_.Init(string_2); 11064 while (true) { 11065 int to_check = Min(state_1_.length_, state_2_.length_); 11066 DCHECK(to_check > 0 && to_check <= length); 11067 bool is_equal; 11068 if (state_1_.is_one_byte_) { 11069 if (state_2_.is_one_byte_) { 11070 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check); 11071 } else { 11072 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check); 11073 } 11074 } else { 11075 if (state_2_.is_one_byte_) { 11076 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check); 11077 } else { 11078 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check); 11079 } 11080 } 11081 // Looping done. 11082 if (!is_equal) return false; 11083 length -= to_check; 11084 // Exit condition. Strings are equal. 11085 if (length == 0) return true; 11086 state_1_.Advance(to_check); 11087 state_2_.Advance(to_check); 11088 } 11089 } 11090 11091 private: 11092 State state_1_; 11093 State state_2_; 11094 11095 DISALLOW_COPY_AND_ASSIGN(StringComparator); 11096 }; 11097 11098 11099 bool String::SlowEquals(String* other) { 11100 DisallowHeapAllocation no_gc; 11101 // Fast check: negative check with lengths. 11102 int len = length(); 11103 if (len != other->length()) return false; 11104 if (len == 0) return true; 11105 11106 // Fast check: if hash code is computed for both strings 11107 // a fast negative check can be performed. 11108 if (HasHashCode() && other->HasHashCode()) { 11109 #ifdef ENABLE_SLOW_DCHECKS 11110 if (FLAG_enable_slow_asserts) { 11111 if (Hash() != other->Hash()) { 11112 bool found_difference = false; 11113 for (int i = 0; i < len; i++) { 11114 if (Get(i) != other->Get(i)) { 11115 found_difference = true; 11116 break; 11117 } 11118 } 11119 DCHECK(found_difference); 11120 } 11121 } 11122 #endif 11123 if (Hash() != other->Hash()) return false; 11124 } 11125 11126 // We know the strings are both non-empty. Compare the first chars 11127 // before we try to flatten the strings. 11128 if (this->Get(0) != other->Get(0)) return false; 11129 11130 if (IsSeqOneByteString() && other->IsSeqOneByteString()) { 11131 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars(); 11132 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(); 11133 return CompareRawStringContents(str1, str2, len); 11134 } 11135 11136 StringComparator comparator; 11137 return comparator.Equals(this, other); 11138 } 11139 11140 11141 bool String::SlowEquals(Handle<String> one, Handle<String> two) { 11142 // Fast check: negative check with lengths. 11143 int one_length = one->length(); 11144 if (one_length != two->length()) return false; 11145 if (one_length == 0) return true; 11146 11147 // Fast check: if hash code is computed for both strings 11148 // a fast negative check can be performed. 11149 if (one->HasHashCode() && two->HasHashCode()) { 11150 #ifdef ENABLE_SLOW_DCHECKS 11151 if (FLAG_enable_slow_asserts) { 11152 if (one->Hash() != two->Hash()) { 11153 bool found_difference = false; 11154 for (int i = 0; i < one_length; i++) { 11155 if (one->Get(i) != two->Get(i)) { 11156 found_difference = true; 11157 break; 11158 } 11159 } 11160 DCHECK(found_difference); 11161 } 11162 } 11163 #endif 11164 if (one->Hash() != two->Hash()) return false; 11165 } 11166 11167 // We know the strings are both non-empty. Compare the first chars 11168 // before we try to flatten the strings. 11169 if (one->Get(0) != two->Get(0)) return false; 11170 11171 one = String::Flatten(one); 11172 two = String::Flatten(two); 11173 11174 DisallowHeapAllocation no_gc; 11175 String::FlatContent flat1 = one->GetFlatContent(); 11176 String::FlatContent flat2 = two->GetFlatContent(); 11177 11178 if (flat1.IsOneByte() && flat2.IsOneByte()) { 11179 return CompareRawStringContents(flat1.ToOneByteVector().start(), 11180 flat2.ToOneByteVector().start(), 11181 one_length); 11182 } else { 11183 for (int i = 0; i < one_length; i++) { 11184 if (flat1.Get(i) != flat2.Get(i)) return false; 11185 } 11186 return true; 11187 } 11188 } 11189 11190 11191 // static 11192 ComparisonResult String::Compare(Handle<String> x, Handle<String> y) { 11193 // A few fast case tests before we flatten. 11194 if (x.is_identical_to(y)) { 11195 return ComparisonResult::kEqual; 11196 } else if (y->length() == 0) { 11197 return x->length() == 0 ? ComparisonResult::kEqual 11198 : ComparisonResult::kGreaterThan; 11199 } else if (x->length() == 0) { 11200 return ComparisonResult::kLessThan; 11201 } 11202 11203 int const d = x->Get(0) - y->Get(0); 11204 if (d < 0) { 11205 return ComparisonResult::kLessThan; 11206 } else if (d > 0) { 11207 return ComparisonResult::kGreaterThan; 11208 } 11209 11210 // Slow case. 11211 x = String::Flatten(x); 11212 y = String::Flatten(y); 11213 11214 DisallowHeapAllocation no_gc; 11215 ComparisonResult result = ComparisonResult::kEqual; 11216 int prefix_length = x->length(); 11217 if (y->length() < prefix_length) { 11218 prefix_length = y->length(); 11219 result = ComparisonResult::kGreaterThan; 11220 } else if (y->length() > prefix_length) { 11221 result = ComparisonResult::kLessThan; 11222 } 11223 int r; 11224 String::FlatContent x_content = x->GetFlatContent(); 11225 String::FlatContent y_content = y->GetFlatContent(); 11226 if (x_content.IsOneByte()) { 11227 Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); 11228 if (y_content.IsOneByte()) { 11229 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 11230 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11231 } else { 11232 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 11233 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11234 } 11235 } else { 11236 Vector<const uc16> x_chars = x_content.ToUC16Vector(); 11237 if (y_content.IsOneByte()) { 11238 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 11239 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11240 } else { 11241 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 11242 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11243 } 11244 } 11245 if (r < 0) { 11246 result = ComparisonResult::kLessThan; 11247 } else if (r > 0) { 11248 result = ComparisonResult::kGreaterThan; 11249 } 11250 return result; 11251 } 11252 11253 11254 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) { 11255 int slen = length(); 11256 // Can't check exact length equality, but we can check bounds. 11257 int str_len = str.length(); 11258 if (!allow_prefix_match && 11259 (str_len < slen || 11260 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) { 11261 return false; 11262 } 11263 int i; 11264 size_t remaining_in_str = static_cast<size_t>(str_len); 11265 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start()); 11266 for (i = 0; i < slen && remaining_in_str > 0; i++) { 11267 size_t cursor = 0; 11268 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor); 11269 DCHECK(cursor > 0 && cursor <= remaining_in_str); 11270 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) { 11271 if (i > slen - 1) return false; 11272 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false; 11273 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false; 11274 } else { 11275 if (Get(i) != r) return false; 11276 } 11277 utf8_data += cursor; 11278 remaining_in_str -= cursor; 11279 } 11280 return (allow_prefix_match || i == slen) && remaining_in_str == 0; 11281 } 11282 11283 11284 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) { 11285 int slen = length(); 11286 if (str.length() != slen) return false; 11287 DisallowHeapAllocation no_gc; 11288 FlatContent content = GetFlatContent(); 11289 if (content.IsOneByte()) { 11290 return CompareChars(content.ToOneByteVector().start(), 11291 str.start(), slen) == 0; 11292 } 11293 for (int i = 0; i < slen; i++) { 11294 if (Get(i) != static_cast<uint16_t>(str[i])) return false; 11295 } 11296 return true; 11297 } 11298 11299 11300 bool String::IsTwoByteEqualTo(Vector<const uc16> str) { 11301 int slen = length(); 11302 if (str.length() != slen) return false; 11303 DisallowHeapAllocation no_gc; 11304 FlatContent content = GetFlatContent(); 11305 if (content.IsTwoByte()) { 11306 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0; 11307 } 11308 for (int i = 0; i < slen; i++) { 11309 if (Get(i) != str[i]) return false; 11310 } 11311 return true; 11312 } 11313 11314 11315 uint32_t String::ComputeAndSetHash() { 11316 // Should only be called if hash code has not yet been computed. 11317 DCHECK(!HasHashCode()); 11318 11319 // Store the hash code in the object. 11320 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed()); 11321 set_hash_field(field); 11322 11323 // Check the hash code is there. 11324 DCHECK(HasHashCode()); 11325 uint32_t result = field >> kHashShift; 11326 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed. 11327 return result; 11328 } 11329 11330 11331 bool String::ComputeArrayIndex(uint32_t* index) { 11332 int length = this->length(); 11333 if (length == 0 || length > kMaxArrayIndexSize) return false; 11334 StringCharacterStream stream(this); 11335 return StringToArrayIndex(&stream, index); 11336 } 11337 11338 11339 bool String::SlowAsArrayIndex(uint32_t* index) { 11340 if (length() <= kMaxCachedArrayIndexLength) { 11341 Hash(); // force computation of hash code 11342 uint32_t field = hash_field(); 11343 if ((field & kIsNotArrayIndexMask) != 0) return false; 11344 // Isolate the array index form the full hash field. 11345 *index = ArrayIndexValueBits::decode(field); 11346 return true; 11347 } else { 11348 return ComputeArrayIndex(index); 11349 } 11350 } 11351 11352 11353 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) { 11354 int new_size, old_size; 11355 int old_length = string->length(); 11356 if (old_length <= new_length) return string; 11357 11358 if (string->IsSeqOneByteString()) { 11359 old_size = SeqOneByteString::SizeFor(old_length); 11360 new_size = SeqOneByteString::SizeFor(new_length); 11361 } else { 11362 DCHECK(string->IsSeqTwoByteString()); 11363 old_size = SeqTwoByteString::SizeFor(old_length); 11364 new_size = SeqTwoByteString::SizeFor(new_length); 11365 } 11366 11367 int delta = old_size - new_size; 11368 11369 Address start_of_string = string->address(); 11370 DCHECK_OBJECT_ALIGNED(start_of_string); 11371 DCHECK_OBJECT_ALIGNED(start_of_string + new_size); 11372 11373 Heap* heap = string->GetHeap(); 11374 // Sizes are pointer size aligned, so that we can use filler objects 11375 // that are a multiple of pointer size. 11376 heap->CreateFillerObjectAt(start_of_string + new_size, delta, 11377 ClearRecordedSlots::kNo); 11378 heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER); 11379 11380 // We are storing the new length using release store after creating a filler 11381 // for the left-over space to avoid races with the sweeper thread. 11382 string->synchronized_set_length(new_length); 11383 11384 if (new_length == 0) return heap->isolate()->factory()->empty_string(); 11385 return string; 11386 } 11387 11388 11389 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { 11390 // For array indexes mix the length into the hash as an array index could 11391 // be zero. 11392 DCHECK(length > 0); 11393 DCHECK(length <= String::kMaxArrayIndexSize); 11394 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 11395 (1 << String::kArrayIndexValueBits)); 11396 11397 value <<= String::ArrayIndexValueBits::kShift; 11398 value |= length << String::ArrayIndexLengthBits::kShift; 11399 11400 DCHECK((value & String::kIsNotArrayIndexMask) == 0); 11401 DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength, 11402 (value & String::kContainsCachedArrayIndexMask) == 0); 11403 return value; 11404 } 11405 11406 11407 uint32_t StringHasher::GetHashField() { 11408 if (length_ <= String::kMaxHashCalcLength) { 11409 if (is_array_index_) { 11410 return MakeArrayIndexHash(array_index_, length_); 11411 } 11412 return (GetHashCore(raw_running_hash_) << String::kHashShift) | 11413 String::kIsNotArrayIndexMask; 11414 } else { 11415 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask; 11416 } 11417 } 11418 11419 11420 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, 11421 uint32_t seed, 11422 int* utf16_length_out) { 11423 int vector_length = chars.length(); 11424 // Handle some edge cases 11425 if (vector_length <= 1) { 11426 DCHECK(vector_length == 0 || 11427 static_cast<uint8_t>(chars.start()[0]) <= 11428 unibrow::Utf8::kMaxOneByteChar); 11429 *utf16_length_out = vector_length; 11430 return HashSequentialString(chars.start(), vector_length, seed); 11431 } 11432 // Start with a fake length which won't affect computation. 11433 // It will be updated later. 11434 StringHasher hasher(String::kMaxArrayIndexSize, seed); 11435 size_t remaining = static_cast<size_t>(vector_length); 11436 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start()); 11437 int utf16_length = 0; 11438 bool is_index = true; 11439 DCHECK(hasher.is_array_index_); 11440 while (remaining > 0) { 11441 size_t consumed = 0; 11442 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed); 11443 DCHECK(consumed > 0 && consumed <= remaining); 11444 stream += consumed; 11445 remaining -= consumed; 11446 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode; 11447 utf16_length += is_two_characters ? 2 : 1; 11448 // No need to keep hashing. But we do need to calculate utf16_length. 11449 if (utf16_length > String::kMaxHashCalcLength) continue; 11450 if (is_two_characters) { 11451 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c); 11452 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c); 11453 hasher.AddCharacter(c1); 11454 hasher.AddCharacter(c2); 11455 if (is_index) is_index = hasher.UpdateIndex(c1); 11456 if (is_index) is_index = hasher.UpdateIndex(c2); 11457 } else { 11458 hasher.AddCharacter(c); 11459 if (is_index) is_index = hasher.UpdateIndex(c); 11460 } 11461 } 11462 *utf16_length_out = static_cast<int>(utf16_length); 11463 // Must set length here so that hash computation is correct. 11464 hasher.length_ = utf16_length; 11465 return hasher.GetHashField(); 11466 } 11467 11468 11469 void IteratingStringHasher::VisitConsString(ConsString* cons_string) { 11470 // Run small ConsStrings through ConsStringIterator. 11471 if (cons_string->length() < 64) { 11472 ConsStringIterator iter(cons_string); 11473 int offset; 11474 String* string; 11475 while (nullptr != (string = iter.Next(&offset))) { 11476 DCHECK_EQ(0, offset); 11477 String::VisitFlat(this, string, 0); 11478 } 11479 return; 11480 } 11481 // Slow case. 11482 const int max_length = String::kMaxHashCalcLength; 11483 int length = std::min(cons_string->length(), max_length); 11484 if (cons_string->HasOnlyOneByteChars()) { 11485 uint8_t* buffer = new uint8_t[length]; 11486 String::WriteToFlat(cons_string, buffer, 0, length); 11487 AddCharacters(buffer, length); 11488 delete[] buffer; 11489 } else { 11490 uint16_t* buffer = new uint16_t[length]; 11491 String::WriteToFlat(cons_string, buffer, 0, length); 11492 AddCharacters(buffer, length); 11493 delete[] buffer; 11494 } 11495 } 11496 11497 11498 void String::PrintOn(FILE* file) { 11499 int length = this->length(); 11500 for (int i = 0; i < length; i++) { 11501 PrintF(file, "%c", Get(i)); 11502 } 11503 } 11504 11505 11506 int Map::Hash() { 11507 // For performance reasons we only hash the 3 most variable fields of a map: 11508 // constructor, prototype and bit_field2. For predictability reasons we 11509 // use objects' offsets in respective pages for hashing instead of raw 11510 // addresses. 11511 11512 // Shift away the tag. 11513 int hash = ObjectAddressForHashing(GetConstructor()) >> 2; 11514 11515 // XOR-ing the prototype and constructor directly yields too many zero bits 11516 // when the two pointers are close (which is fairly common). 11517 // To avoid this we shift the prototype bits relatively to the constructor. 11518 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits); 11519 11520 return hash ^ (hash >> 16) ^ bit_field2(); 11521 } 11522 11523 11524 namespace { 11525 11526 bool CheckEquivalent(Map* first, Map* second) { 11527 return first->GetConstructor() == second->GetConstructor() && 11528 first->prototype() == second->prototype() && 11529 first->instance_type() == second->instance_type() && 11530 first->bit_field() == second->bit_field() && 11531 first->is_extensible() == second->is_extensible() && 11532 first->new_target_is_base() == second->new_target_is_base() && 11533 first->has_hidden_prototype() == second->has_hidden_prototype(); 11534 } 11535 11536 } // namespace 11537 11538 11539 bool Map::EquivalentToForTransition(Map* other) { 11540 if (!CheckEquivalent(this, other)) return false; 11541 if (instance_type() == JS_FUNCTION_TYPE) { 11542 // JSFunctions require more checks to ensure that sloppy function is 11543 // not equvalent to strict function. 11544 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors()); 11545 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(), 11546 nof); 11547 } 11548 return true; 11549 } 11550 11551 11552 bool Map::EquivalentToForNormalization(Map* other, 11553 PropertyNormalizationMode mode) { 11554 int properties = 11555 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties(); 11556 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() && 11557 GetInObjectProperties() == properties; 11558 } 11559 11560 11561 bool JSFunction::Inlines(SharedFunctionInfo* candidate) { 11562 DisallowHeapAllocation no_gc; 11563 if (shared() == candidate) return true; 11564 if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false; 11565 DeoptimizationInputData* const data = 11566 DeoptimizationInputData::cast(code()->deoptimization_data()); 11567 if (data->length() == 0) return false; 11568 FixedArray* const literals = data->LiteralArray(); 11569 int const inlined_count = data->InlinedFunctionCount()->value(); 11570 for (int i = 0; i < inlined_count; ++i) { 11571 if (SharedFunctionInfo::cast(literals->get(i)) == candidate) { 11572 return true; 11573 } 11574 } 11575 return false; 11576 } 11577 11578 void JSFunction::MarkForBaseline() { 11579 Isolate* isolate = GetIsolate(); 11580 set_code_no_write_barrier( 11581 isolate->builtins()->builtin(Builtins::kCompileBaseline)); 11582 // No write barrier required, since the builtin is part of the root set. 11583 } 11584 11585 void JSFunction::MarkForOptimization() { 11586 Isolate* isolate = GetIsolate(); 11587 DCHECK(!IsOptimized()); 11588 DCHECK(shared()->allows_lazy_compilation() || 11589 !shared()->optimization_disabled()); 11590 set_code_no_write_barrier( 11591 isolate->builtins()->builtin(Builtins::kCompileOptimized)); 11592 // No write barrier required, since the builtin is part of the root set. 11593 } 11594 11595 11596 void JSFunction::AttemptConcurrentOptimization() { 11597 Isolate* isolate = GetIsolate(); 11598 if (!isolate->concurrent_recompilation_enabled() || 11599 isolate->bootstrapper()->IsActive()) { 11600 MarkForOptimization(); 11601 return; 11602 } 11603 DCHECK(!IsInOptimizationQueue()); 11604 DCHECK(!IsOptimized()); 11605 DCHECK(shared()->allows_lazy_compilation() || 11606 !shared()->optimization_disabled()); 11607 DCHECK(isolate->concurrent_recompilation_enabled()); 11608 if (FLAG_trace_concurrent_recompilation) { 11609 PrintF(" ** Marking "); 11610 ShortPrint(); 11611 PrintF(" for concurrent recompilation.\n"); 11612 } 11613 set_code_no_write_barrier( 11614 isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent)); 11615 // No write barrier required, since the builtin is part of the root set. 11616 } 11617 11618 // static 11619 Handle<LiteralsArray> SharedFunctionInfo::FindOrCreateLiterals( 11620 Handle<SharedFunctionInfo> shared, Handle<Context> native_context) { 11621 Isolate* isolate = shared->GetIsolate(); 11622 CodeAndLiterals result = 11623 shared->SearchOptimizedCodeMap(*native_context, BailoutId::None()); 11624 if (result.literals != nullptr) { 11625 DCHECK(shared->feedback_metadata()->is_empty() || 11626 !result.literals->feedback_vector()->is_empty()); 11627 return handle(result.literals, isolate); 11628 } 11629 11630 Handle<TypeFeedbackVector> feedback_vector = 11631 TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata())); 11632 Handle<LiteralsArray> literals = LiteralsArray::New( 11633 isolate, feedback_vector, shared->num_literals(), TENURED); 11634 Handle<Code> code; 11635 if (result.code != nullptr) { 11636 code = Handle<Code>(result.code, isolate); 11637 } 11638 AddToOptimizedCodeMap(shared, native_context, code, literals, 11639 BailoutId::None()); 11640 return literals; 11641 } 11642 11643 void SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap( 11644 Handle<SharedFunctionInfo> shared, Handle<Code> code) { 11645 Isolate* isolate = shared->GetIsolate(); 11646 if (isolate->serializer_enabled()) return; 11647 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION); 11648 // Empty code maps are unsupported. 11649 if (!shared->OptimizedCodeMapIsCleared()) { 11650 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(code); 11651 // A collection may have occured and cleared the optimized code map in the 11652 // allocation above. 11653 if (!shared->OptimizedCodeMapIsCleared()) { 11654 shared->optimized_code_map()->set(kSharedCodeIndex, *cell); 11655 } 11656 } 11657 } 11658 11659 // static 11660 void SharedFunctionInfo::AddToOptimizedCodeMap( 11661 Handle<SharedFunctionInfo> shared, Handle<Context> native_context, 11662 MaybeHandle<Code> code, Handle<LiteralsArray> literals, 11663 BailoutId osr_ast_id) { 11664 Isolate* isolate = shared->GetIsolate(); 11665 if (isolate->serializer_enabled()) return; 11666 DCHECK(code.is_null() || 11667 code.ToHandleChecked()->kind() == Code::OPTIMIZED_FUNCTION); 11668 DCHECK(native_context->IsNativeContext()); 11669 STATIC_ASSERT(kEntryLength == 4); 11670 Handle<FixedArray> new_code_map; 11671 int entry; 11672 11673 if (shared->OptimizedCodeMapIsCleared()) { 11674 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED); 11675 new_code_map->set(kSharedCodeIndex, *isolate->factory()->empty_weak_cell(), 11676 SKIP_WRITE_BARRIER); 11677 entry = kEntriesStart; 11678 } else { 11679 Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate); 11680 entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id); 11681 if (entry > kSharedCodeIndex) { 11682 // Just set the code and literals of the entry. 11683 if (!code.is_null()) { 11684 Handle<WeakCell> code_cell = 11685 isolate->factory()->NewWeakCell(code.ToHandleChecked()); 11686 old_code_map->set(entry + kCachedCodeOffset, *code_cell); 11687 } 11688 if (literals->literals_count() == 0) { 11689 old_code_map->set(entry + kLiteralsOffset, *literals); 11690 } else { 11691 Handle<WeakCell> literals_cell = 11692 isolate->factory()->NewWeakCell(literals); 11693 old_code_map->set(entry + kLiteralsOffset, *literals_cell); 11694 } 11695 return; 11696 } 11697 11698 // Can we reuse an entry? 11699 DCHECK(entry < kEntriesStart); 11700 int length = old_code_map->length(); 11701 for (int i = kEntriesStart; i < length; i += kEntryLength) { 11702 if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) { 11703 new_code_map = old_code_map; 11704 entry = i; 11705 break; 11706 } 11707 } 11708 11709 if (entry < kEntriesStart) { 11710 // Copy old optimized code map and append one new entry. 11711 new_code_map = isolate->factory()->CopyFixedArrayAndGrow( 11712 old_code_map, kEntryLength, TENURED); 11713 // TODO(mstarzinger): Temporary workaround. The allocation above might 11714 // have flushed the optimized code map and the copy we created is full of 11715 // holes. For now we just give up on adding the entry and pretend it got 11716 // flushed. 11717 if (shared->OptimizedCodeMapIsCleared()) return; 11718 entry = old_code_map->length(); 11719 } 11720 } 11721 11722 Handle<WeakCell> code_cell = 11723 code.is_null() ? isolate->factory()->empty_weak_cell() 11724 : isolate->factory()->NewWeakCell(code.ToHandleChecked()); 11725 WeakCell* context_cell = native_context->self_weak_cell(); 11726 11727 new_code_map->set(entry + kContextOffset, context_cell); 11728 new_code_map->set(entry + kCachedCodeOffset, *code_cell); 11729 11730 if (literals->literals_count() == 0) { 11731 new_code_map->set(entry + kLiteralsOffset, *literals); 11732 } else { 11733 Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals); 11734 new_code_map->set(entry + kLiteralsOffset, *literals_cell); 11735 } 11736 11737 new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt())); 11738 11739 #ifdef DEBUG 11740 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) { 11741 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset)); 11742 DCHECK(cell->cleared() || cell->value()->IsNativeContext()); 11743 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset)); 11744 DCHECK(cell->cleared() || 11745 (cell->value()->IsCode() && 11746 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION)); 11747 Object* lits = new_code_map->get(i + kLiteralsOffset); 11748 if (lits->IsWeakCell()) { 11749 cell = WeakCell::cast(lits); 11750 DCHECK(cell->cleared() || 11751 (cell->value()->IsLiteralsArray() && 11752 LiteralsArray::cast(cell->value())->literals_count() > 0)); 11753 } else { 11754 DCHECK(lits->IsLiteralsArray() && 11755 LiteralsArray::cast(lits)->literals_count() == 0); 11756 } 11757 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi()); 11758 } 11759 #endif 11760 11761 FixedArray* old_code_map = shared->optimized_code_map(); 11762 if (old_code_map != *new_code_map) { 11763 shared->set_optimized_code_map(*new_code_map); 11764 } 11765 } 11766 11767 11768 void SharedFunctionInfo::ClearOptimizedCodeMap() { 11769 FixedArray* cleared_map = GetHeap()->cleared_optimized_code_map(); 11770 set_optimized_code_map(cleared_map, SKIP_WRITE_BARRIER); 11771 } 11772 11773 11774 void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code, 11775 const char* reason) { 11776 DisallowHeapAllocation no_gc; 11777 if (OptimizedCodeMapIsCleared()) return; 11778 11779 Heap* heap = GetHeap(); 11780 FixedArray* code_map = optimized_code_map(); 11781 int dst = kEntriesStart; 11782 int length = code_map->length(); 11783 for (int src = kEntriesStart; src < length; src += kEntryLength) { 11784 DCHECK(WeakCell::cast(code_map->get(src))->cleared() || 11785 WeakCell::cast(code_map->get(src))->value()->IsNativeContext()); 11786 if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() == 11787 optimized_code) { 11788 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value()); 11789 if (FLAG_trace_opt) { 11790 PrintF("[evicting entry from optimizing code map (%s) for ", reason); 11791 ShortPrint(); 11792 if (osr.IsNone()) { 11793 PrintF("]\n"); 11794 } else { 11795 PrintF(" (osr ast id %d)]\n", osr.ToInt()); 11796 } 11797 } 11798 if (!osr.IsNone()) { 11799 // Evict the src entry by not copying it to the dst entry. 11800 continue; 11801 } 11802 // In case of non-OSR entry just clear the code in order to proceed 11803 // sharing literals. 11804 code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(), 11805 SKIP_WRITE_BARRIER); 11806 } 11807 11808 // Keep the src entry by copying it to the dst entry. 11809 if (dst != src) { 11810 code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset)); 11811 code_map->set(dst + kCachedCodeOffset, 11812 code_map->get(src + kCachedCodeOffset)); 11813 code_map->set(dst + kLiteralsOffset, 11814 code_map->get(src + kLiteralsOffset)); 11815 code_map->set(dst + kOsrAstIdOffset, 11816 code_map->get(src + kOsrAstIdOffset)); 11817 } 11818 dst += kEntryLength; 11819 } 11820 if (WeakCell::cast(code_map->get(kSharedCodeIndex))->value() == 11821 optimized_code) { 11822 // Evict context-independent code as well. 11823 code_map->set(kSharedCodeIndex, heap->empty_weak_cell(), 11824 SKIP_WRITE_BARRIER); 11825 if (FLAG_trace_opt) { 11826 PrintF("[evicting entry from optimizing code map (%s) for ", reason); 11827 ShortPrint(); 11828 PrintF(" (context-independent code)]\n"); 11829 } 11830 } 11831 if (dst != length) { 11832 // Always trim even when array is cleared because of heap verifier. 11833 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map, 11834 length - dst); 11835 if (code_map->length() == kEntriesStart && 11836 WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) { 11837 ClearOptimizedCodeMap(); 11838 } 11839 } 11840 } 11841 11842 11843 void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) { 11844 FixedArray* code_map = optimized_code_map(); 11845 DCHECK(shrink_by % kEntryLength == 0); 11846 DCHECK(shrink_by <= code_map->length() - kEntriesStart); 11847 // Always trim even when array is cleared because of heap verifier. 11848 GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map, 11849 shrink_by); 11850 if (code_map->length() == kEntriesStart && 11851 WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) { 11852 ClearOptimizedCodeMap(); 11853 } 11854 } 11855 11856 // static 11857 void JSFunction::EnsureLiterals(Handle<JSFunction> function) { 11858 Handle<SharedFunctionInfo> shared(function->shared()); 11859 Handle<Context> native_context(function->context()->native_context()); 11860 if (function->literals() == 11861 function->GetIsolate()->heap()->empty_literals_array()) { 11862 Handle<LiteralsArray> literals = 11863 SharedFunctionInfo::FindOrCreateLiterals(shared, native_context); 11864 function->set_literals(*literals); 11865 } 11866 } 11867 11868 static void GetMinInobjectSlack(Map* map, void* data) { 11869 int slack = map->unused_property_fields(); 11870 if (*reinterpret_cast<int*>(data) > slack) { 11871 *reinterpret_cast<int*>(data) = slack; 11872 } 11873 } 11874 11875 11876 static void ShrinkInstanceSize(Map* map, void* data) { 11877 int slack = *reinterpret_cast<int*>(data); 11878 map->SetInObjectProperties(map->GetInObjectProperties() - slack); 11879 map->set_unused_property_fields(map->unused_property_fields() - slack); 11880 map->set_instance_size(map->instance_size() - slack * kPointerSize); 11881 map->set_construction_counter(Map::kNoSlackTracking); 11882 11883 // Visitor id might depend on the instance size, recalculate it. 11884 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map)); 11885 } 11886 11887 static void StopSlackTracking(Map* map, void* data) { 11888 map->set_construction_counter(Map::kNoSlackTracking); 11889 } 11890 11891 void Map::CompleteInobjectSlackTracking() { 11892 // Has to be an initial map. 11893 DCHECK(GetBackPointer()->IsUndefined(GetIsolate())); 11894 11895 int slack = unused_property_fields(); 11896 TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack); 11897 if (slack != 0) { 11898 // Resize the initial map and all maps in its transition tree. 11899 TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack); 11900 } else { 11901 TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr); 11902 } 11903 } 11904 11905 11906 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) { 11907 DisallowHeapAllocation no_gc; 11908 if (!object->HasFastProperties()) return false; 11909 Map* map = object->map(); 11910 if (map->is_prototype_map()) return false; 11911 DescriptorArray* descriptors = map->instance_descriptors(); 11912 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { 11913 PropertyDetails details = descriptors->GetDetails(i); 11914 if (details.location() == kDescriptor) continue; 11915 if (details.representation().IsHeapObject() || 11916 details.representation().IsTagged()) { 11917 FieldIndex index = FieldIndex::ForDescriptor(map, i); 11918 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true; 11919 } 11920 } 11921 return false; 11922 } 11923 11924 // static 11925 void JSObject::MakePrototypesFast(Handle<Object> receiver, 11926 WhereToStart where_to_start, 11927 Isolate* isolate) { 11928 if (!receiver->IsJSReceiver()) return; 11929 for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver), 11930 where_to_start); 11931 !iter.IsAtEnd(); iter.Advance()) { 11932 Handle<Object> current = PrototypeIterator::GetCurrent(iter); 11933 if (!current->IsJSObject()) return; 11934 Handle<JSObject> current_obj = Handle<JSObject>::cast(current); 11935 Map* current_map = current_obj->map(); 11936 if (current_map->is_prototype_map() && 11937 !current_map->should_be_fast_prototype_map()) { 11938 Handle<Map> map(current_map); 11939 Map::SetShouldBeFastPrototypeMap(map, true, isolate); 11940 JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE); 11941 } 11942 } 11943 } 11944 11945 // static 11946 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, 11947 PrototypeOptimizationMode mode) { 11948 if (object->IsJSGlobalObject()) return; 11949 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { 11950 // First normalize to ensure all JSFunctions are DATA_CONSTANT. 11951 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, 11952 "NormalizeAsPrototype"); 11953 } 11954 Handle<Map> previous_map(object->map()); 11955 if (object->map()->is_prototype_map()) { 11956 if (object->map()->should_be_fast_prototype_map() && 11957 !object->HasFastProperties()) { 11958 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); 11959 } 11960 } else { 11961 if (object->map() == *previous_map) { 11962 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); 11963 JSObject::MigrateToMap(object, new_map); 11964 } 11965 object->map()->set_is_prototype_map(true); 11966 11967 // Replace the pointer to the exact constructor with the Object function 11968 // from the same context if undetectable from JS. This is to avoid keeping 11969 // memory alive unnecessarily. 11970 Object* maybe_constructor = object->map()->GetConstructor(); 11971 if (maybe_constructor->IsJSFunction()) { 11972 JSFunction* constructor = JSFunction::cast(maybe_constructor); 11973 Isolate* isolate = object->GetIsolate(); 11974 if (!constructor->shared()->IsApiFunction() && 11975 object->class_name() == isolate->heap()->Object_string()) { 11976 Context* context = constructor->context()->native_context(); 11977 JSFunction* object_function = context->object_function(); 11978 object->map()->SetConstructor(object_function); 11979 } 11980 } 11981 } 11982 } 11983 11984 11985 // static 11986 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { 11987 if (!object->map()->is_prototype_map()) return; 11988 if (!object->map()->should_be_fast_prototype_map()) return; 11989 OptimizeAsPrototype(object, FAST_PROTOTYPE); 11990 } 11991 11992 11993 // static 11994 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) { 11995 // Contract: In line with InvalidatePrototypeChains()'s requirements, 11996 // leaf maps don't need to register as users, only prototypes do. 11997 DCHECK(user->is_prototype_map()); 11998 11999 Handle<Map> current_user = user; 12000 Handle<PrototypeInfo> current_user_info = 12001 Map::GetOrCreatePrototypeInfo(user, isolate); 12002 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) { 12003 // Walk up the prototype chain as far as links haven't been registered yet. 12004 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) { 12005 break; 12006 } 12007 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter); 12008 // Proxies on the prototype chain are not supported. They make it 12009 // impossible to make any assumptions about the prototype chain anyway. 12010 if (maybe_proto->IsJSProxy()) return; 12011 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto); 12012 Handle<PrototypeInfo> proto_info = 12013 Map::GetOrCreatePrototypeInfo(proto, isolate); 12014 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); 12015 int slot = 0; 12016 Handle<WeakFixedArray> new_array = 12017 WeakFixedArray::Add(maybe_registry, current_user, &slot); 12018 current_user_info->set_registry_slot(slot); 12019 if (!maybe_registry.is_identical_to(new_array)) { 12020 proto_info->set_prototype_users(*new_array); 12021 } 12022 if (FLAG_trace_prototype_users) { 12023 PrintF("Registering %p as a user of prototype %p (map=%p).\n", 12024 reinterpret_cast<void*>(*current_user), 12025 reinterpret_cast<void*>(*proto), 12026 reinterpret_cast<void*>(proto->map())); 12027 } 12028 12029 current_user = handle(proto->map(), isolate); 12030 current_user_info = proto_info; 12031 } 12032 } 12033 12034 12035 // Can be called regardless of whether |user| was actually registered with 12036 // |prototype|. Returns true when there was a registration. 12037 // static 12038 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) { 12039 DCHECK(user->is_prototype_map()); 12040 // If it doesn't have a PrototypeInfo, it was never registered. 12041 if (!user->prototype_info()->IsPrototypeInfo()) return false; 12042 // If it had no prototype before, see if it had users that might expect 12043 // registration. 12044 if (!user->prototype()->IsJSObject()) { 12045 Object* users = 12046 PrototypeInfo::cast(user->prototype_info())->prototype_users(); 12047 return users->IsWeakFixedArray(); 12048 } 12049 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate); 12050 Handle<PrototypeInfo> user_info = 12051 Map::GetOrCreatePrototypeInfo(user, isolate); 12052 int slot = user_info->registry_slot(); 12053 if (slot == PrototypeInfo::UNREGISTERED) return false; 12054 DCHECK(prototype->map()->is_prototype_map()); 12055 Object* maybe_proto_info = prototype->map()->prototype_info(); 12056 // User knows its registry slot, prototype info and user registry must exist. 12057 DCHECK(maybe_proto_info->IsPrototypeInfo()); 12058 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), 12059 isolate); 12060 Object* maybe_registry = proto_info->prototype_users(); 12061 DCHECK(maybe_registry->IsWeakFixedArray()); 12062 DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user); 12063 WeakFixedArray::cast(maybe_registry)->Clear(slot); 12064 if (FLAG_trace_prototype_users) { 12065 PrintF("Unregistering %p as a user of prototype %p.\n", 12066 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); 12067 } 12068 return true; 12069 } 12070 12071 12072 static void InvalidatePrototypeChainsInternal(Map* map) { 12073 if (!map->is_prototype_map()) return; 12074 if (FLAG_trace_prototype_users) { 12075 PrintF("Invalidating prototype map %p 's cell\n", 12076 reinterpret_cast<void*>(map)); 12077 } 12078 Object* maybe_proto_info = map->prototype_info(); 12079 if (!maybe_proto_info->IsPrototypeInfo()) return; 12080 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); 12081 Object* maybe_cell = proto_info->validity_cell(); 12082 if (maybe_cell->IsCell()) { 12083 // Just set the value; the cell will be replaced lazily. 12084 Cell* cell = Cell::cast(maybe_cell); 12085 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); 12086 } 12087 12088 WeakFixedArray::Iterator iterator(proto_info->prototype_users()); 12089 // For now, only maps register themselves as users. 12090 Map* user; 12091 while ((user = iterator.Next<Map>())) { 12092 // Walk the prototype chain (backwards, towards leaf objects) if necessary. 12093 InvalidatePrototypeChainsInternal(user); 12094 } 12095 } 12096 12097 12098 // static 12099 void JSObject::InvalidatePrototypeChains(Map* map) { 12100 DisallowHeapAllocation no_gc; 12101 InvalidatePrototypeChainsInternal(map); 12102 } 12103 12104 12105 // static 12106 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype, 12107 Isolate* isolate) { 12108 Object* maybe_proto_info = prototype->map()->prototype_info(); 12109 if (maybe_proto_info->IsPrototypeInfo()) { 12110 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); 12111 } 12112 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); 12113 prototype->map()->set_prototype_info(*proto_info); 12114 return proto_info; 12115 } 12116 12117 12118 // static 12119 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map, 12120 Isolate* isolate) { 12121 Object* maybe_proto_info = prototype_map->prototype_info(); 12122 if (maybe_proto_info->IsPrototypeInfo()) { 12123 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); 12124 } 12125 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); 12126 prototype_map->set_prototype_info(*proto_info); 12127 return proto_info; 12128 } 12129 12130 // static 12131 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value, 12132 Isolate* isolate) { 12133 if (value == false && !map->prototype_info()->IsPrototypeInfo()) { 12134 // "False" is the implicit default value, so there's nothing to do. 12135 return; 12136 } 12137 GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value); 12138 } 12139 12140 // static 12141 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, 12142 Isolate* isolate) { 12143 Handle<Object> maybe_prototype(map->prototype(), isolate); 12144 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); 12145 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); 12146 // Ensure the prototype is registered with its own prototypes so its cell 12147 // will be invalidated when necessary. 12148 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), 12149 isolate); 12150 Handle<PrototypeInfo> proto_info = 12151 GetOrCreatePrototypeInfo(prototype, isolate); 12152 Object* maybe_cell = proto_info->validity_cell(); 12153 // Return existing cell if it's still valid. 12154 if (maybe_cell->IsCell()) { 12155 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); 12156 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { 12157 return cell; 12158 } 12159 } 12160 // Otherwise create a new cell. 12161 Handle<Cell> cell = isolate->factory()->NewCell( 12162 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); 12163 proto_info->set_validity_cell(*cell); 12164 return cell; 12165 } 12166 12167 12168 // static 12169 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, 12170 PrototypeOptimizationMode proto_mode) { 12171 RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype); 12172 12173 bool is_hidden = false; 12174 if (prototype->IsJSObject()) { 12175 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); 12176 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); 12177 12178 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor(); 12179 if (maybe_constructor->IsJSFunction()) { 12180 JSFunction* constructor = JSFunction::cast(maybe_constructor); 12181 Object* data = constructor->shared()->function_data(); 12182 is_hidden = (data->IsFunctionTemplateInfo() && 12183 FunctionTemplateInfo::cast(data)->hidden_prototype()) || 12184 prototype->IsJSGlobalObject(); 12185 } 12186 } 12187 map->set_has_hidden_prototype(is_hidden); 12188 12189 WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate()) 12190 ? SKIP_WRITE_BARRIER 12191 : UPDATE_WRITE_BARRIER; 12192 map->set_prototype(*prototype, wb_mode); 12193 } 12194 12195 12196 Handle<Object> CacheInitialJSArrayMaps( 12197 Handle<Context> native_context, Handle<Map> initial_map) { 12198 // Replace all of the cached initial array maps in the native context with 12199 // the appropriate transitioned elements kind maps. 12200 Handle<Map> current_map = initial_map; 12201 ElementsKind kind = current_map->elements_kind(); 12202 DCHECK_EQ(GetInitialFastElementsKind(), kind); 12203 native_context->set(Context::ArrayMapIndex(kind), *current_map); 12204 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1; 12205 i < kFastElementsKindCount; ++i) { 12206 Handle<Map> new_map; 12207 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); 12208 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) { 12209 new_map = handle(maybe_elements_transition); 12210 } else { 12211 new_map = Map::CopyAsElementsKind( 12212 current_map, next_kind, INSERT_TRANSITION); 12213 } 12214 DCHECK_EQ(next_kind, new_map->elements_kind()); 12215 native_context->set(Context::ArrayMapIndex(next_kind), *new_map); 12216 current_map = new_map; 12217 } 12218 return initial_map; 12219 } 12220 12221 12222 void JSFunction::SetInstancePrototype(Handle<JSFunction> function, 12223 Handle<Object> value) { 12224 Isolate* isolate = function->GetIsolate(); 12225 12226 DCHECK(value->IsJSReceiver()); 12227 12228 // Now some logic for the maps of the objects that are created by using this 12229 // function as a constructor. 12230 if (function->has_initial_map()) { 12231 // If the function has allocated the initial map replace it with a 12232 // copy containing the new prototype. Also complete any in-object 12233 // slack tracking that is in progress at this point because it is 12234 // still tracking the old copy. 12235 function->CompleteInobjectSlackTrackingIfActive(); 12236 12237 Handle<Map> initial_map(function->initial_map(), isolate); 12238 12239 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() && 12240 initial_map->instance_type() == JS_OBJECT_TYPE) { 12241 // Put the value in the initial map field until an initial map is needed. 12242 // At that point, a new initial map is created and the prototype is put 12243 // into the initial map where it belongs. 12244 function->set_prototype_or_initial_map(*value); 12245 } else { 12246 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype"); 12247 JSFunction::SetInitialMap(function, new_map, value); 12248 12249 // If the function is used as the global Array function, cache the 12250 // updated initial maps (and transitioned versions) in the native context. 12251 Handle<Context> native_context(function->context()->native_context(), 12252 isolate); 12253 Handle<Object> array_function( 12254 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate); 12255 if (array_function->IsJSFunction() && 12256 *function == JSFunction::cast(*array_function)) { 12257 CacheInitialJSArrayMaps(native_context, new_map); 12258 } 12259 } 12260 12261 // Deoptimize all code that embeds the previous initial map. 12262 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( 12263 isolate, DependentCode::kInitialMapChangedGroup); 12264 } else { 12265 // Put the value in the initial map field until an initial map is 12266 // needed. At that point, a new initial map is created and the 12267 // prototype is put into the initial map where it belongs. 12268 function->set_prototype_or_initial_map(*value); 12269 if (value->IsJSObject()) { 12270 // Optimize as prototype to detach it from its transition tree. 12271 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), 12272 FAST_PROTOTYPE); 12273 } 12274 } 12275 isolate->heap()->ClearInstanceofCache(); 12276 } 12277 12278 12279 void JSFunction::SetPrototype(Handle<JSFunction> function, 12280 Handle<Object> value) { 12281 DCHECK(function->IsConstructor() || 12282 IsGeneratorFunction(function->shared()->kind())); 12283 Handle<Object> construct_prototype = value; 12284 12285 // If the value is not a JSReceiver, store the value in the map's 12286 // constructor field so it can be accessed. Also, set the prototype 12287 // used for constructing objects to the original object prototype. 12288 // See ECMA-262 13.2.2. 12289 if (!value->IsJSReceiver()) { 12290 // Copy the map so this does not affect unrelated functions. 12291 // Remove map transitions because they point to maps with a 12292 // different prototype. 12293 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype"); 12294 12295 JSObject::MigrateToMap(function, new_map); 12296 new_map->SetConstructor(*value); 12297 new_map->set_non_instance_prototype(true); 12298 Isolate* isolate = new_map->GetIsolate(); 12299 12300 construct_prototype = handle( 12301 IsGeneratorFunction(function->shared()->kind()) 12302 ? function->context() 12303 ->native_context() 12304 ->initial_generator_prototype() 12305 : function->context()->native_context()->initial_object_prototype(), 12306 isolate); 12307 } else { 12308 function->map()->set_non_instance_prototype(false); 12309 } 12310 12311 return SetInstancePrototype(function, construct_prototype); 12312 } 12313 12314 12315 bool JSFunction::RemovePrototype() { 12316 Context* native_context = context()->native_context(); 12317 Map* no_prototype_map = 12318 is_strict(shared()->language_mode()) 12319 ? native_context->strict_function_without_prototype_map() 12320 : native_context->sloppy_function_without_prototype_map(); 12321 12322 if (map() == no_prototype_map) return true; 12323 12324 #ifdef DEBUG 12325 if (map() != (is_strict(shared()->language_mode()) 12326 ? native_context->strict_function_map() 12327 : native_context->sloppy_function_map())) { 12328 return false; 12329 } 12330 #endif 12331 12332 set_map(no_prototype_map); 12333 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value()); 12334 return true; 12335 } 12336 12337 12338 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map, 12339 Handle<Object> prototype) { 12340 if (map->prototype() != *prototype) { 12341 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 12342 } 12343 function->set_prototype_or_initial_map(*map); 12344 map->SetConstructor(*function); 12345 #if TRACE_MAPS 12346 if (FLAG_trace_maps) { 12347 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n", 12348 reinterpret_cast<void*>(*map), function->shared()->unique_id(), 12349 function->shared()->DebugName()->ToCString().get()); 12350 } 12351 #endif 12352 } 12353 12354 12355 #ifdef DEBUG 12356 namespace { 12357 12358 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) { 12359 switch (instance_type) { 12360 case JS_API_OBJECT_TYPE: 12361 case JS_ARRAY_BUFFER_TYPE: 12362 case JS_ARRAY_TYPE: 12363 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 12364 case JS_DATA_VIEW_TYPE: 12365 case JS_DATE_TYPE: 12366 case JS_FUNCTION_TYPE: 12367 case JS_GENERATOR_OBJECT_TYPE: 12368 case JS_MAP_ITERATOR_TYPE: 12369 case JS_MAP_TYPE: 12370 case JS_MESSAGE_OBJECT_TYPE: 12371 case JS_MODULE_TYPE: 12372 case JS_OBJECT_TYPE: 12373 case JS_ERROR_TYPE: 12374 case JS_ARGUMENTS_TYPE: 12375 case JS_PROMISE_TYPE: 12376 case JS_REGEXP_TYPE: 12377 case JS_SET_ITERATOR_TYPE: 12378 case JS_SET_TYPE: 12379 case JS_SPECIAL_API_OBJECT_TYPE: 12380 case JS_TYPED_ARRAY_TYPE: 12381 case JS_VALUE_TYPE: 12382 case JS_WEAK_MAP_TYPE: 12383 case JS_WEAK_SET_TYPE: 12384 return true; 12385 12386 case BYTECODE_ARRAY_TYPE: 12387 case BYTE_ARRAY_TYPE: 12388 case CELL_TYPE: 12389 case CODE_TYPE: 12390 case FILLER_TYPE: 12391 case FIXED_ARRAY_TYPE: 12392 case FIXED_DOUBLE_ARRAY_TYPE: 12393 case FOREIGN_TYPE: 12394 case FREE_SPACE_TYPE: 12395 case HEAP_NUMBER_TYPE: 12396 case JS_BOUND_FUNCTION_TYPE: 12397 case JS_GLOBAL_OBJECT_TYPE: 12398 case JS_GLOBAL_PROXY_TYPE: 12399 case JS_PROXY_TYPE: 12400 case MAP_TYPE: 12401 case MUTABLE_HEAP_NUMBER_TYPE: 12402 case ODDBALL_TYPE: 12403 case PROPERTY_CELL_TYPE: 12404 case SHARED_FUNCTION_INFO_TYPE: 12405 case SIMD128_VALUE_TYPE: 12406 case SYMBOL_TYPE: 12407 case WEAK_CELL_TYPE: 12408 12409 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 12410 case FIXED_##TYPE##_ARRAY_TYPE: 12411 #undef TYPED_ARRAY_CASE 12412 12413 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: 12414 STRUCT_LIST(MAKE_STRUCT_CASE) 12415 #undef MAKE_STRUCT_CASE 12416 // We must not end up here for these instance types at all. 12417 UNREACHABLE(); 12418 // Fall through. 12419 default: 12420 return false; 12421 } 12422 } 12423 12424 } // namespace 12425 #endif 12426 12427 12428 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { 12429 DCHECK(function->IsConstructor() || function->shared()->is_resumable()); 12430 if (function->has_initial_map()) return; 12431 Isolate* isolate = function->GetIsolate(); 12432 12433 // The constructor should be compiled for the optimization hints to be 12434 // available. 12435 Compiler::Compile(function, Compiler::CLEAR_EXCEPTION); 12436 12437 // First create a new map with the size and number of in-object properties 12438 // suggested by the function. 12439 InstanceType instance_type; 12440 if (function->shared()->is_resumable()) { 12441 instance_type = JS_GENERATOR_OBJECT_TYPE; 12442 } else { 12443 instance_type = JS_OBJECT_TYPE; 12444 } 12445 int instance_size; 12446 int in_object_properties; 12447 function->CalculateInstanceSize(instance_type, 0, &instance_size, 12448 &in_object_properties); 12449 12450 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size); 12451 12452 // Fetch or allocate prototype. 12453 Handle<Object> prototype; 12454 if (function->has_instance_prototype()) { 12455 prototype = handle(function->instance_prototype(), isolate); 12456 } else { 12457 prototype = isolate->factory()->NewFunctionPrototype(function); 12458 } 12459 map->SetInObjectProperties(in_object_properties); 12460 map->set_unused_property_fields(in_object_properties); 12461 DCHECK(map->has_fast_object_elements()); 12462 12463 // Finally link initial map and constructor function. 12464 DCHECK(prototype->IsJSReceiver()); 12465 JSFunction::SetInitialMap(function, map, prototype); 12466 map->StartInobjectSlackTracking(); 12467 } 12468 12469 12470 // static 12471 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate, 12472 Handle<JSFunction> constructor, 12473 Handle<JSReceiver> new_target) { 12474 EnsureHasInitialMap(constructor); 12475 12476 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate); 12477 if (*new_target == *constructor) return constructor_initial_map; 12478 12479 // Fast case, new.target is a subclass of constructor. The map is cacheable 12480 // (and may already have been cached). new.target.prototype is guaranteed to 12481 // be a JSReceiver. 12482 if (new_target->IsJSFunction()) { 12483 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); 12484 12485 // Check that |function|'s initial map still in sync with the |constructor|, 12486 // otherwise we must create a new initial map for |function|. 12487 if (function->has_initial_map() && 12488 function->initial_map()->GetConstructor() == *constructor) { 12489 return handle(function->initial_map(), isolate); 12490 } 12491 12492 // Create a new map with the size and number of in-object properties 12493 // suggested by |function|. 12494 12495 // Link initial map and constructor function if the new.target is actually a 12496 // subclass constructor. 12497 if (IsSubclassConstructor(function->shared()->kind())) { 12498 Handle<Object> prototype(function->instance_prototype(), isolate); 12499 InstanceType instance_type = constructor_initial_map->instance_type(); 12500 DCHECK(CanSubclassHaveInobjectProperties(instance_type)); 12501 int internal_fields = 12502 JSObject::GetInternalFieldCount(*constructor_initial_map); 12503 int pre_allocated = constructor_initial_map->GetInObjectProperties() - 12504 constructor_initial_map->unused_property_fields(); 12505 int instance_size; 12506 int in_object_properties; 12507 function->CalculateInstanceSizeForDerivedClass( 12508 instance_type, internal_fields, &instance_size, 12509 &in_object_properties); 12510 12511 int unused_property_fields = in_object_properties - pre_allocated; 12512 Handle<Map> map = 12513 Map::CopyInitialMap(constructor_initial_map, instance_size, 12514 in_object_properties, unused_property_fields); 12515 map->set_new_target_is_base(false); 12516 12517 JSFunction::SetInitialMap(function, map, prototype); 12518 map->SetConstructor(*constructor); 12519 map->set_construction_counter(Map::kNoSlackTracking); 12520 map->StartInobjectSlackTracking(); 12521 return map; 12522 } 12523 } 12524 12525 // Slow path, new.target is either a proxy or can't cache the map. 12526 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to 12527 // fall back to the intrinsicDefaultProto. 12528 Handle<Object> prototype; 12529 if (new_target->IsJSFunction()) { 12530 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); 12531 // Make sure the new.target.prototype is cached. 12532 EnsureHasInitialMap(function); 12533 prototype = handle(function->prototype(), isolate); 12534 } else { 12535 Handle<String> prototype_string = isolate->factory()->prototype_string(); 12536 ASSIGN_RETURN_ON_EXCEPTION( 12537 isolate, prototype, 12538 JSReceiver::GetProperty(new_target, prototype_string), Map); 12539 // The above prototype lookup might change the constructor and its 12540 // prototype, hence we have to reload the initial map. 12541 EnsureHasInitialMap(constructor); 12542 constructor_initial_map = handle(constructor->initial_map(), isolate); 12543 } 12544 12545 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the 12546 // correct realm. Rather than directly fetching the .prototype, we fetch the 12547 // constructor that points to the .prototype. This relies on 12548 // constructor.prototype being FROZEN for those constructors. 12549 if (!prototype->IsJSReceiver()) { 12550 Handle<Context> context; 12551 ASSIGN_RETURN_ON_EXCEPTION(isolate, context, 12552 JSReceiver::GetFunctionRealm(new_target), Map); 12553 DCHECK(context->IsNativeContext()); 12554 Handle<Object> maybe_index = JSReceiver::GetDataProperty( 12555 constructor, isolate->factory()->native_context_index_symbol()); 12556 int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value() 12557 : Context::OBJECT_FUNCTION_INDEX; 12558 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index))); 12559 prototype = handle(realm_constructor->prototype(), isolate); 12560 } 12561 12562 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); 12563 map->set_new_target_is_base(false); 12564 DCHECK(prototype->IsJSReceiver()); 12565 if (map->prototype() != *prototype) { 12566 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 12567 } 12568 map->SetConstructor(*constructor); 12569 return map; 12570 } 12571 12572 12573 void JSFunction::PrintName(FILE* out) { 12574 base::SmartArrayPointer<char> name = shared()->DebugName()->ToCString(); 12575 PrintF(out, "%s", name.get()); 12576 } 12577 12578 12579 Handle<String> JSFunction::GetName(Handle<JSFunction> function) { 12580 Isolate* isolate = function->GetIsolate(); 12581 Handle<Object> name = 12582 JSReceiver::GetDataProperty(function, isolate->factory()->name_string()); 12583 if (name->IsString()) return Handle<String>::cast(name); 12584 return handle(function->shared()->DebugName(), isolate); 12585 } 12586 12587 12588 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) { 12589 Isolate* isolate = function->GetIsolate(); 12590 Handle<Object> name = JSReceiver::GetDataProperty( 12591 function, isolate->factory()->display_name_string()); 12592 if (name->IsString()) return Handle<String>::cast(name); 12593 return JSFunction::GetName(function); 12594 } 12595 12596 void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name, 12597 Handle<String> prefix) { 12598 Isolate* isolate = function->GetIsolate(); 12599 Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked(); 12600 if (prefix->length() > 0) { 12601 IncrementalStringBuilder builder(isolate); 12602 builder.AppendString(prefix); 12603 builder.AppendCharacter(' '); 12604 builder.AppendString(function_name); 12605 function_name = builder.Finish().ToHandleChecked(); 12606 } 12607 JSObject::DefinePropertyOrElementIgnoreAttributes( 12608 function, isolate->factory()->name_string(), function_name, 12609 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)) 12610 .ToHandleChecked(); 12611 } 12612 12613 namespace { 12614 12615 char const kNativeCodeSource[] = "function () { [native code] }"; 12616 12617 12618 Handle<String> NativeCodeFunctionSourceString( 12619 Handle<SharedFunctionInfo> shared_info) { 12620 Isolate* const isolate = shared_info->GetIsolate(); 12621 if (shared_info->name()->IsString()) { 12622 IncrementalStringBuilder builder(isolate); 12623 builder.AppendCString("function "); 12624 builder.AppendString(handle(String::cast(shared_info->name()), isolate)); 12625 builder.AppendCString("() { [native code] }"); 12626 return builder.Finish().ToHandleChecked(); 12627 } 12628 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource); 12629 } 12630 12631 } // namespace 12632 12633 12634 // static 12635 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) { 12636 Isolate* const isolate = function->GetIsolate(); 12637 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource); 12638 } 12639 12640 12641 // static 12642 Handle<String> JSFunction::ToString(Handle<JSFunction> function) { 12643 Isolate* const isolate = function->GetIsolate(); 12644 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate); 12645 12646 // Check if {function} should hide its source code. 12647 if (!shared_info->script()->IsScript() || 12648 Script::cast(shared_info->script())->hide_source()) { 12649 return NativeCodeFunctionSourceString(shared_info); 12650 } 12651 12652 // Check if we should print {function} as a class. 12653 Handle<Object> class_start_position = JSReceiver::GetDataProperty( 12654 function, isolate->factory()->class_start_position_symbol()); 12655 if (class_start_position->IsSmi()) { 12656 Handle<Object> class_end_position = JSReceiver::GetDataProperty( 12657 function, isolate->factory()->class_end_position_symbol()); 12658 Handle<String> script_source( 12659 String::cast(Script::cast(shared_info->script())->source()), isolate); 12660 return isolate->factory()->NewSubString( 12661 script_source, Handle<Smi>::cast(class_start_position)->value(), 12662 Handle<Smi>::cast(class_end_position)->value()); 12663 } 12664 12665 // Check if we have source code for the {function}. 12666 if (!shared_info->HasSourceCode()) { 12667 return NativeCodeFunctionSourceString(shared_info); 12668 } 12669 12670 IncrementalStringBuilder builder(isolate); 12671 if (!shared_info->is_arrow()) { 12672 if (shared_info->is_concise_method()) { 12673 if (shared_info->is_generator()) { 12674 builder.AppendCharacter('*'); 12675 } else if (shared_info->is_async()) { 12676 builder.AppendCString("async "); 12677 } 12678 } else { 12679 if (shared_info->is_generator()) { 12680 builder.AppendCString("function* "); 12681 } else if (shared_info->is_async()) { 12682 builder.AppendCString("async function "); 12683 } else { 12684 builder.AppendCString("function "); 12685 } 12686 } 12687 if (shared_info->name_should_print_as_anonymous()) { 12688 builder.AppendCString("anonymous"); 12689 } else if (!shared_info->is_anonymous_expression()) { 12690 builder.AppendString(handle(String::cast(shared_info->name()), isolate)); 12691 } 12692 } 12693 builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode())); 12694 return builder.Finish().ToHandleChecked(); 12695 } 12696 12697 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball, 12698 const char* to_string, Handle<Object> to_number, 12699 bool to_boolean, const char* type_of, byte kind) { 12700 Handle<String> internalized_to_string = 12701 isolate->factory()->InternalizeUtf8String(to_string); 12702 Handle<String> internalized_type_of = 12703 isolate->factory()->InternalizeUtf8String(type_of); 12704 oddball->set_to_number_raw(to_number->Number()); 12705 oddball->set_to_boolean(isolate->heap()->ToBoolean(to_boolean)); 12706 oddball->set_to_number(*to_number); 12707 oddball->set_to_string(*internalized_to_string); 12708 oddball->set_type_of(*internalized_type_of); 12709 oddball->set_kind(kind); 12710 } 12711 12712 void Script::SetEvalOrigin(Handle<Script> script, 12713 Handle<SharedFunctionInfo> outer_info, 12714 int eval_position) { 12715 if (eval_position == RelocInfo::kNoPosition) { 12716 // If the position is missing, attempt to get the code offset from the 12717 // current activation. Do not translate the code offset into source 12718 // position, but store it as negative value for lazy translation. 12719 StackTraceFrameIterator it(script->GetIsolate()); 12720 if (!it.done() && it.is_javascript()) { 12721 FrameSummary summary = FrameSummary::GetFirst(it.javascript_frame()); 12722 script->set_eval_from_shared(summary.function()->shared()); 12723 script->set_eval_from_position(-summary.code_offset()); 12724 return; 12725 } 12726 eval_position = 0; 12727 } 12728 script->set_eval_from_shared(*outer_info); 12729 script->set_eval_from_position(eval_position); 12730 } 12731 12732 int Script::GetEvalPosition() { 12733 DisallowHeapAllocation no_gc; 12734 DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL); 12735 int position = eval_from_position(); 12736 if (position < 0) { 12737 // Due to laziness, the position may not have been translated from code 12738 // offset yet, which would be encoded as negative integer. In that case, 12739 // translate and set the position. 12740 if (eval_from_shared()->IsUndefined(GetIsolate())) { 12741 position = 0; 12742 } else { 12743 SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared()); 12744 position = shared->abstract_code()->SourcePosition(-position); 12745 } 12746 DCHECK(position >= 0); 12747 set_eval_from_position(position); 12748 } 12749 return position; 12750 } 12751 12752 void Script::InitLineEnds(Handle<Script> script) { 12753 Isolate* isolate = script->GetIsolate(); 12754 if (!script->line_ends()->IsUndefined(isolate)) return; 12755 12756 if (!script->source()->IsString()) { 12757 DCHECK(script->source()->IsUndefined(isolate)); 12758 Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0); 12759 script->set_line_ends(*empty); 12760 DCHECK(script->line_ends()->IsFixedArray()); 12761 return; 12762 } 12763 12764 Handle<String> src(String::cast(script->source()), isolate); 12765 12766 Handle<FixedArray> array = String::CalculateLineEnds(src, true); 12767 12768 if (*array != isolate->heap()->empty_fixed_array()) { 12769 array->set_map(isolate->heap()->fixed_cow_array_map()); 12770 } 12771 12772 script->set_line_ends(*array); 12773 DCHECK(script->line_ends()->IsFixedArray()); 12774 } 12775 12776 #define SMI_VALUE(x) (Smi::cast(x)->value()) 12777 bool Script::GetPositionInfo(int position, PositionInfo* info, 12778 OffsetFlag offset_flag) { 12779 Handle<Script> script(this); 12780 InitLineEnds(script); 12781 12782 DisallowHeapAllocation no_allocation; 12783 12784 DCHECK(script->line_ends()->IsFixedArray()); 12785 FixedArray* ends = FixedArray::cast(script->line_ends()); 12786 12787 const int ends_len = ends->length(); 12788 if (ends_len == 0) return false; 12789 12790 // Return early on invalid positions. Negative positions behave as if 0 was 12791 // passed, and positions beyond the end of the script return as failure. 12792 if (position < 0) { 12793 position = 0; 12794 } else if (position > SMI_VALUE(ends->get(ends_len - 1))) { 12795 return false; 12796 } 12797 12798 // Determine line number by doing a binary search on the line ends array. 12799 if (SMI_VALUE(ends->get(0)) >= position) { 12800 info->line = 0; 12801 info->line_start = 0; 12802 info->column = position; 12803 } else { 12804 int left = 0; 12805 int right = ends_len - 1; 12806 12807 while (right > 0) { 12808 DCHECK_LE(left, right); 12809 const int mid = (left + right) / 2; 12810 if (position > SMI_VALUE(ends->get(mid))) { 12811 left = mid + 1; 12812 } else if (position <= SMI_VALUE(ends->get(mid - 1))) { 12813 right = mid - 1; 12814 } else { 12815 info->line = mid; 12816 break; 12817 } 12818 } 12819 DCHECK(SMI_VALUE(ends->get(info->line)) >= position && 12820 SMI_VALUE(ends->get(info->line - 1)) < position); 12821 info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1; 12822 info->column = position - info->line_start; 12823 } 12824 12825 // Line end is position of the linebreak character. 12826 info->line_end = SMI_VALUE(ends->get(info->line)); 12827 if (info->line_end > 0) { 12828 DCHECK(script->source()->IsString()); 12829 Handle<String> src(String::cast(script->source())); 12830 if (src->Get(info->line_end - 1) == '\r') { 12831 info->line_end--; 12832 } 12833 } 12834 12835 // Add offsets if requested. 12836 if (offset_flag == WITH_OFFSET) { 12837 if (info->line == 0) { 12838 info->column += script->column_offset(); 12839 } 12840 info->line += script->line_offset(); 12841 } 12842 12843 return true; 12844 } 12845 #undef SMI_VALUE 12846 12847 int Script::GetColumnNumber(Handle<Script> script, int code_pos) { 12848 PositionInfo info; 12849 if (!script->GetPositionInfo(code_pos, &info, WITH_OFFSET)) { 12850 return -1; 12851 } 12852 12853 return info.column; 12854 } 12855 12856 int Script::GetLineNumberWithArray(int code_pos) { 12857 PositionInfo info; 12858 if (!GetPositionInfo(code_pos, &info, WITH_OFFSET)) { 12859 return -1; 12860 } 12861 12862 return info.line; 12863 } 12864 12865 12866 int Script::GetLineNumber(Handle<Script> script, int code_pos) { 12867 InitLineEnds(script); 12868 return script->GetLineNumberWithArray(code_pos); 12869 } 12870 12871 12872 int Script::GetLineNumber(int code_pos) { 12873 DisallowHeapAllocation no_allocation; 12874 if (!line_ends()->IsUndefined(GetIsolate())) { 12875 return GetLineNumberWithArray(code_pos); 12876 } 12877 12878 // Slow mode: we do not have line_ends. We have to iterate through source. 12879 if (!source()->IsString()) return -1; 12880 12881 String* source_string = String::cast(source()); 12882 int line = 0; 12883 int len = source_string->length(); 12884 for (int pos = 0; pos < len; pos++) { 12885 if (pos == code_pos) break; 12886 if (source_string->Get(pos) == '\n') line++; 12887 } 12888 return line; 12889 } 12890 12891 12892 Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) { 12893 Isolate* isolate = script->GetIsolate(); 12894 Handle<String> name_or_source_url_key = 12895 isolate->factory()->InternalizeOneByteString( 12896 STATIC_CHAR_VECTOR("nameOrSourceURL")); 12897 Handle<JSObject> script_wrapper = Script::GetWrapper(script); 12898 Handle<Object> property = 12899 JSReceiver::GetProperty(script_wrapper, name_or_source_url_key) 12900 .ToHandleChecked(); 12901 DCHECK(property->IsJSFunction()); 12902 Handle<Object> result; 12903 // Do not check against pending exception, since this function may be called 12904 // when an exception has already been pending. 12905 if (!Execution::TryCall(isolate, property, script_wrapper, 0, NULL) 12906 .ToHandle(&result)) { 12907 return isolate->factory()->undefined_value(); 12908 } 12909 return result; 12910 } 12911 12912 12913 Handle<JSObject> Script::GetWrapper(Handle<Script> script) { 12914 Isolate* isolate = script->GetIsolate(); 12915 if (!script->wrapper()->IsUndefined(isolate)) { 12916 DCHECK(script->wrapper()->IsWeakCell()); 12917 Handle<WeakCell> cell(WeakCell::cast(script->wrapper())); 12918 if (!cell->cleared()) { 12919 // Return a handle for the existing script wrapper from the cache. 12920 return handle(JSObject::cast(cell->value())); 12921 } 12922 // If we found an empty WeakCell, that means the script wrapper was 12923 // GCed. We are not notified directly of that, so we decrement here 12924 // so that we at least don't count double for any given script. 12925 isolate->counters()->script_wrappers()->Decrement(); 12926 } 12927 // Construct a new script wrapper. 12928 isolate->counters()->script_wrappers()->Increment(); 12929 Handle<JSFunction> constructor = isolate->script_function(); 12930 Handle<JSValue> result = 12931 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor)); 12932 result->set_value(*script); 12933 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result); 12934 script->set_wrapper(*cell); 12935 return result; 12936 } 12937 12938 12939 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( 12940 FunctionLiteral* fun) { 12941 WeakFixedArray::Iterator iterator(shared_function_infos()); 12942 SharedFunctionInfo* shared; 12943 while ((shared = iterator.Next<SharedFunctionInfo>())) { 12944 if (fun->function_token_position() == shared->function_token_position() && 12945 fun->start_position() == shared->start_position() && 12946 fun->end_position() == shared->end_position()) { 12947 return Handle<SharedFunctionInfo>(shared); 12948 } 12949 } 12950 return MaybeHandle<SharedFunctionInfo>(); 12951 } 12952 12953 12954 Script::Iterator::Iterator(Isolate* isolate) 12955 : iterator_(isolate->heap()->script_list()) {} 12956 12957 12958 Script* Script::Iterator::Next() { return iterator_.Next<Script>(); } 12959 12960 12961 SharedFunctionInfo::Iterator::Iterator(Isolate* isolate) 12962 : script_iterator_(isolate), 12963 sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {} 12964 12965 12966 bool SharedFunctionInfo::Iterator::NextScript() { 12967 Script* script = script_iterator_.Next(); 12968 if (script == NULL) return false; 12969 sfi_iterator_.Reset(script->shared_function_infos()); 12970 return true; 12971 } 12972 12973 12974 SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() { 12975 do { 12976 SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>(); 12977 if (next != NULL) return next; 12978 } while (NextScript()); 12979 return NULL; 12980 } 12981 12982 12983 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared, 12984 Handle<Object> script_object) { 12985 if (shared->script() == *script_object) return; 12986 Isolate* isolate = shared->GetIsolate(); 12987 12988 // Add shared function info to new script's list. If a collection occurs, 12989 // the shared function info may be temporarily in two lists. 12990 // This is okay because the gc-time processing of these lists can tolerate 12991 // duplicates. 12992 Handle<Object> list; 12993 if (script_object->IsScript()) { 12994 Handle<Script> script = Handle<Script>::cast(script_object); 12995 list = handle(script->shared_function_infos(), isolate); 12996 } else { 12997 list = isolate->factory()->noscript_shared_function_infos(); 12998 } 12999 13000 #ifdef DEBUG 13001 if (FLAG_enable_slow_asserts) { 13002 WeakFixedArray::Iterator iterator(*list); 13003 SharedFunctionInfo* next; 13004 while ((next = iterator.Next<SharedFunctionInfo>())) { 13005 DCHECK_NE(next, *shared); 13006 } 13007 } 13008 #endif // DEBUG 13009 list = WeakFixedArray::Add(list, shared); 13010 13011 if (script_object->IsScript()) { 13012 Handle<Script> script = Handle<Script>::cast(script_object); 13013 script->set_shared_function_infos(*list); 13014 } else { 13015 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list); 13016 } 13017 13018 // Remove shared function info from old script's list. 13019 if (shared->script()->IsScript()) { 13020 Script* old_script = Script::cast(shared->script()); 13021 if (old_script->shared_function_infos()->IsWeakFixedArray()) { 13022 WeakFixedArray* list = 13023 WeakFixedArray::cast(old_script->shared_function_infos()); 13024 list->Remove(shared); 13025 } 13026 } else { 13027 // Remove shared function info from root array. 13028 Object* list = isolate->heap()->noscript_shared_function_infos(); 13029 CHECK(WeakFixedArray::cast(list)->Remove(shared)); 13030 } 13031 13032 // Finally set new script. 13033 shared->set_script(*script_object); 13034 } 13035 13036 13037 String* SharedFunctionInfo::DebugName() { 13038 Object* n = name(); 13039 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name(); 13040 return String::cast(n); 13041 } 13042 13043 // The filter is a pattern that matches function names in this way: 13044 // "*" all; the default 13045 // "-" all but the top-level function 13046 // "-name" all but the function "name" 13047 // "" only the top-level function 13048 // "name" only the function "name" 13049 // "name*" only functions starting with "name" 13050 // "~" none; the tilde is not an identifier 13051 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) { 13052 if (*raw_filter == '*') return true; 13053 String* name = DebugName(); 13054 Vector<const char> filter = CStrVector(raw_filter); 13055 if (filter.length() == 0) return name->length() == 0; 13056 if (filter[0] == '-') { 13057 // Negative filter. 13058 if (filter.length() == 1) { 13059 return (name->length() != 0); 13060 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) { 13061 return false; 13062 } 13063 if (filter[filter.length() - 1] == '*' && 13064 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) { 13065 return false; 13066 } 13067 return true; 13068 13069 } else if (name->IsUtf8EqualTo(filter)) { 13070 return true; 13071 } 13072 if (filter[filter.length() - 1] == '*' && 13073 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) { 13074 return true; 13075 } 13076 return false; 13077 } 13078 13079 bool SharedFunctionInfo::HasSourceCode() const { 13080 Isolate* isolate = GetIsolate(); 13081 return !script()->IsUndefined(isolate) && 13082 !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate); 13083 } 13084 13085 13086 Handle<Object> SharedFunctionInfo::GetSourceCode() { 13087 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value(); 13088 Handle<String> source(String::cast(Script::cast(script())->source())); 13089 return GetIsolate()->factory()->NewSubString( 13090 source, start_position(), end_position()); 13091 } 13092 13093 13094 bool SharedFunctionInfo::IsInlineable() { 13095 // Check that the function has a script associated with it. 13096 if (!script()->IsScript()) return false; 13097 return !optimization_disabled(); 13098 } 13099 13100 13101 int SharedFunctionInfo::SourceSize() { 13102 return end_position() - start_position(); 13103 } 13104 13105 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type, 13106 int requested_internal_fields, 13107 int requested_in_object_properties, 13108 int* instance_size, 13109 int* in_object_properties) { 13110 int header_size = JSObject::GetHeaderSize(instance_type); 13111 DCHECK_LE(requested_internal_fields, 13112 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2); 13113 *instance_size = 13114 Min(header_size + 13115 ((requested_internal_fields + requested_in_object_properties) 13116 << kPointerSizeLog2), 13117 JSObject::kMaxInstanceSize); 13118 *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) - 13119 requested_internal_fields; 13120 } 13121 13122 13123 void JSFunction::CalculateInstanceSize(InstanceType instance_type, 13124 int requested_internal_fields, 13125 int* instance_size, 13126 int* in_object_properties) { 13127 CalculateInstanceSizeHelper(instance_type, requested_internal_fields, 13128 shared()->expected_nof_properties(), 13129 instance_size, in_object_properties); 13130 } 13131 13132 13133 void JSFunction::CalculateInstanceSizeForDerivedClass( 13134 InstanceType instance_type, int requested_internal_fields, 13135 int* instance_size, int* in_object_properties) { 13136 Isolate* isolate = GetIsolate(); 13137 int expected_nof_properties = 0; 13138 for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd(); 13139 iter.Advance()) { 13140 JSReceiver* current = iter.GetCurrent<JSReceiver>(); 13141 if (!current->IsJSFunction()) break; 13142 JSFunction* func = JSFunction::cast(current); 13143 SharedFunctionInfo* shared = func->shared(); 13144 expected_nof_properties += shared->expected_nof_properties(); 13145 if (!IsSubclassConstructor(shared->kind())) { 13146 break; 13147 } 13148 } 13149 CalculateInstanceSizeHelper(instance_type, requested_internal_fields, 13150 expected_nof_properties, instance_size, 13151 in_object_properties); 13152 } 13153 13154 13155 // Output the source code without any allocation in the heap. 13156 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) { 13157 const SharedFunctionInfo* s = v.value; 13158 // For some native functions there is no source. 13159 if (!s->HasSourceCode()) return os << "<No Source>"; 13160 13161 // Get the source for the script which this function came from. 13162 // Don't use String::cast because we don't want more assertion errors while 13163 // we are already creating a stack dump. 13164 String* script_source = 13165 reinterpret_cast<String*>(Script::cast(s->script())->source()); 13166 13167 if (!script_source->LooksValid()) return os << "<Invalid Source>"; 13168 13169 if (!s->is_toplevel()) { 13170 os << "function "; 13171 Object* name = s->name(); 13172 if (name->IsString() && String::cast(name)->length() > 0) { 13173 String::cast(name)->PrintUC16(os); 13174 } 13175 } 13176 13177 int len = s->end_position() - s->start_position(); 13178 if (len <= v.max_length || v.max_length < 0) { 13179 script_source->PrintUC16(os, s->start_position(), s->end_position()); 13180 return os; 13181 } else { 13182 script_source->PrintUC16(os, s->start_position(), 13183 s->start_position() + v.max_length); 13184 return os << "...\n"; 13185 } 13186 } 13187 13188 13189 static bool IsCodeEquivalent(Code* code, Code* recompiled) { 13190 if (code->instruction_size() != recompiled->instruction_size()) return false; 13191 ByteArray* code_relocation = code->relocation_info(); 13192 ByteArray* recompiled_relocation = recompiled->relocation_info(); 13193 int length = code_relocation->length(); 13194 if (length != recompiled_relocation->length()) return false; 13195 int compare = memcmp(code_relocation->GetDataStartAddress(), 13196 recompiled_relocation->GetDataStartAddress(), 13197 length); 13198 return compare == 0; 13199 } 13200 13201 13202 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) { 13203 DCHECK(!has_deoptimization_support()); 13204 DisallowHeapAllocation no_allocation; 13205 Code* code = this->code(); 13206 if (IsCodeEquivalent(code, recompiled)) { 13207 // Copy the deoptimization data from the recompiled code. 13208 code->set_deoptimization_data(recompiled->deoptimization_data()); 13209 code->set_has_deoptimization_support(true); 13210 } else { 13211 // TODO(3025757): In case the recompiled isn't equivalent to the 13212 // old code, we have to replace it. We should try to avoid this 13213 // altogether because it flushes valuable type feedback by 13214 // effectively resetting all IC state. 13215 ReplaceCode(recompiled); 13216 } 13217 DCHECK(has_deoptimization_support()); 13218 } 13219 13220 13221 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) { 13222 // Disable optimization for the shared function info and mark the 13223 // code as non-optimizable. The marker on the shared function info 13224 // is there because we flush non-optimized code thereby loosing the 13225 // non-optimizable information for the code. When the code is 13226 // regenerated and set on the shared function info it is marked as 13227 // non-optimizable if optimization is disabled for the shared 13228 // function info. 13229 DCHECK(reason != kNoReason); 13230 set_optimization_disabled(true); 13231 set_disable_optimization_reason(reason); 13232 // Code should be the lazy compilation stub or else unoptimized. 13233 DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION || 13234 abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION || 13235 abstract_code()->kind() == AbstractCode::BUILTIN); 13236 PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this)); 13237 if (FLAG_trace_opt) { 13238 PrintF("[disabled optimization for "); 13239 ShortPrint(); 13240 PrintF(", reason: %s]\n", GetBailoutReason(reason)); 13241 } 13242 } 13243 13244 namespace { 13245 13246 // Sets the expected number of properties based on estimate from parser. 13247 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, 13248 FunctionLiteral* literal) { 13249 int estimate = literal->expected_property_count(); 13250 13251 // If no properties are added in the constructor, they are more likely 13252 // to be added later. 13253 if (estimate == 0) estimate = 2; 13254 13255 // TODO(yangguo): check whether those heuristics are still up-to-date. 13256 // We do not shrink objects that go into a snapshot (yet), so we adjust 13257 // the estimate conservatively. 13258 if (shared->GetIsolate()->serializer_enabled()) { 13259 estimate += 2; 13260 } else { 13261 // Inobject slack tracking will reclaim redundant inobject space later, 13262 // so we can afford to adjust the estimate generously. 13263 estimate += 8; 13264 } 13265 13266 shared->set_expected_nof_properties(estimate); 13267 } 13268 13269 } // namespace 13270 13271 void SharedFunctionInfo::InitFromFunctionLiteral( 13272 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) { 13273 shared_info->set_length(lit->scope()->default_function_length()); 13274 shared_info->set_internal_formal_parameter_count(lit->parameter_count()); 13275 shared_info->set_function_token_position(lit->function_token_position()); 13276 shared_info->set_start_position(lit->start_position()); 13277 shared_info->set_end_position(lit->end_position()); 13278 shared_info->set_is_declaration(lit->is_declaration()); 13279 shared_info->set_is_named_expression(lit->is_named_expression()); 13280 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression()); 13281 shared_info->set_inferred_name(*lit->inferred_name()); 13282 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); 13283 shared_info->set_allows_lazy_compilation_without_context( 13284 lit->AllowsLazyCompilationWithoutContext()); 13285 shared_info->set_language_mode(lit->language_mode()); 13286 shared_info->set_uses_arguments(lit->scope()->arguments() != NULL); 13287 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); 13288 shared_info->set_is_function(lit->is_function()); 13289 shared_info->set_never_compiled(true); 13290 shared_info->set_kind(lit->kind()); 13291 if (!IsConstructable(lit->kind(), lit->language_mode())) { 13292 shared_info->set_construct_stub( 13293 *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable()); 13294 } 13295 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject()); 13296 shared_info->set_asm_function(lit->scope()->asm_function()); 13297 SetExpectedNofPropertiesFromEstimate(shared_info, lit); 13298 } 13299 13300 13301 bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) { 13302 DCHECK(!id.IsNone()); 13303 Code* unoptimized = code(); 13304 DeoptimizationOutputData* data = 13305 DeoptimizationOutputData::cast(unoptimized->deoptimization_data()); 13306 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this); 13307 USE(ignore); 13308 return true; // Return true if there was no DCHECK. 13309 } 13310 13311 13312 void Map::StartInobjectSlackTracking() { 13313 DCHECK(!IsInobjectSlackTrackingInProgress()); 13314 13315 // No tracking during the snapshot construction phase. 13316 Isolate* isolate = GetIsolate(); 13317 if (isolate->serializer_enabled()) return; 13318 13319 if (unused_property_fields() == 0) return; 13320 13321 set_construction_counter(Map::kSlackTrackingCounterStart); 13322 } 13323 13324 13325 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) { 13326 code()->ClearInlineCaches(); 13327 set_ic_age(new_ic_age); 13328 if (code()->kind() == Code::FUNCTION) { 13329 code()->set_profiler_ticks(0); 13330 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) { 13331 // Re-enable optimizations if they were disabled due to opt_count limit. 13332 set_optimization_disabled(false); 13333 } 13334 set_opt_count(0); 13335 set_deopt_count(0); 13336 } else if (code()->is_interpreter_trampoline_builtin()) { 13337 set_profiler_ticks(0); 13338 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) { 13339 // Re-enable optimizations if they were disabled due to opt_count limit. 13340 set_optimization_disabled(false); 13341 } 13342 set_opt_count(0); 13343 set_deopt_count(0); 13344 } 13345 } 13346 13347 13348 int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context, 13349 BailoutId osr_ast_id) { 13350 DisallowHeapAllocation no_gc; 13351 DCHECK(native_context->IsNativeContext()); 13352 if (!OptimizedCodeMapIsCleared()) { 13353 FixedArray* optimized_code_map = this->optimized_code_map(); 13354 int length = optimized_code_map->length(); 13355 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt()); 13356 for (int i = kEntriesStart; i < length; i += kEntryLength) { 13357 if (WeakCell::cast(optimized_code_map->get(i + kContextOffset)) 13358 ->value() == native_context && 13359 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) { 13360 return i; 13361 } 13362 } 13363 Object* shared_code = 13364 WeakCell::cast(optimized_code_map->get(kSharedCodeIndex))->value(); 13365 if (shared_code->IsCode() && osr_ast_id.IsNone()) { 13366 return kSharedCodeIndex; 13367 } 13368 } 13369 return -1; 13370 } 13371 13372 void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() { 13373 if (!OptimizedCodeMapIsCleared()) { 13374 FixedArray* optimized_code_map = this->optimized_code_map(); 13375 int length = optimized_code_map->length(); 13376 WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell(); 13377 for (int i = kEntriesStart; i < length; i += kEntryLength) { 13378 optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell, 13379 SKIP_WRITE_BARRIER); 13380 } 13381 optimized_code_map->set(kSharedCodeIndex, empty_weak_cell, 13382 SKIP_WRITE_BARRIER); 13383 } 13384 } 13385 13386 CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap( 13387 Context* native_context, BailoutId osr_ast_id) { 13388 CodeAndLiterals result = {nullptr, nullptr}; 13389 int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id); 13390 if (entry != kNotFound) { 13391 FixedArray* code_map = optimized_code_map(); 13392 if (entry == kSharedCodeIndex) { 13393 // We know the weak cell isn't cleared because we made sure of it in 13394 // SearchOptimizedCodeMapEntry and performed no allocations since that 13395 // call. 13396 result = { 13397 Code::cast(WeakCell::cast(code_map->get(kSharedCodeIndex))->value()), 13398 nullptr}; 13399 } else { 13400 DCHECK_LE(entry + kEntryLength, code_map->length()); 13401 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset)); 13402 Object* lits = code_map->get(entry + kLiteralsOffset); 13403 LiteralsArray* literals = nullptr; 13404 if (lits->IsWeakCell()) { 13405 WeakCell* literal_cell = WeakCell::cast(lits); 13406 if (!literal_cell->cleared()) { 13407 literals = LiteralsArray::cast(literal_cell->value()); 13408 } 13409 } else { 13410 literals = LiteralsArray::cast(lits); 13411 } 13412 result = {cell->cleared() ? nullptr : Code::cast(cell->value()), 13413 literals}; 13414 } 13415 } 13416 return result; 13417 } 13418 13419 13420 #define DECLARE_TAG(ignore1, name, ignore2) name, 13421 const char* const VisitorSynchronization::kTags[ 13422 VisitorSynchronization::kNumberOfSyncTags] = { 13423 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG) 13424 }; 13425 #undef DECLARE_TAG 13426 13427 13428 #define DECLARE_TAG(ignore1, ignore2, name) name, 13429 const char* const VisitorSynchronization::kTagNames[ 13430 VisitorSynchronization::kNumberOfSyncTags] = { 13431 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG) 13432 }; 13433 #undef DECLARE_TAG 13434 13435 13436 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { 13437 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); 13438 Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address()); 13439 Object* new_pointer = old_pointer; 13440 VisitPointer(&new_pointer); 13441 DCHECK_EQ(old_pointer, new_pointer); 13442 } 13443 13444 13445 void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) { 13446 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); 13447 Object* old_pointer = rinfo->code_age_stub(); 13448 Object* new_pointer = old_pointer; 13449 if (old_pointer != nullptr) { 13450 VisitPointer(&new_pointer); 13451 DCHECK_EQ(old_pointer, new_pointer); 13452 } 13453 } 13454 13455 13456 void ObjectVisitor::VisitCodeEntry(Address entry_address) { 13457 Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address); 13458 Object* new_pointer = old_pointer; 13459 VisitPointer(&new_pointer); 13460 DCHECK_EQ(old_pointer, new_pointer); 13461 } 13462 13463 13464 void ObjectVisitor::VisitCell(RelocInfo* rinfo) { 13465 DCHECK(rinfo->rmode() == RelocInfo::CELL); 13466 Object* old_pointer = rinfo->target_cell(); 13467 Object* new_pointer = old_pointer; 13468 VisitPointer(&new_pointer); 13469 DCHECK_EQ(old_pointer, new_pointer); 13470 } 13471 13472 13473 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) { 13474 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 13475 rinfo->IsPatchedDebugBreakSlotSequence()); 13476 Object* old_pointer = 13477 Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); 13478 Object* new_pointer = old_pointer; 13479 VisitPointer(&new_pointer); 13480 DCHECK_EQ(old_pointer, new_pointer); 13481 } 13482 13483 13484 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) { 13485 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); 13486 Object* old_pointer = rinfo->target_object(); 13487 Object* new_pointer = old_pointer; 13488 VisitPointer(&new_pointer); 13489 DCHECK_EQ(old_pointer, new_pointer); 13490 } 13491 13492 13493 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) { 13494 Address old_reference = rinfo->target_external_reference(); 13495 Address new_reference = old_reference; 13496 VisitExternalReference(&new_reference); 13497 DCHECK_EQ(old_reference, new_reference); 13498 } 13499 13500 13501 void Code::InvalidateRelocation() { 13502 InvalidateEmbeddedObjects(); 13503 set_relocation_info(GetHeap()->empty_byte_array()); 13504 } 13505 13506 13507 void Code::InvalidateEmbeddedObjects() { 13508 Object* undefined = GetHeap()->undefined_value(); 13509 Cell* undefined_cell = GetHeap()->undefined_cell(); 13510 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 13511 RelocInfo::ModeMask(RelocInfo::CELL); 13512 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 13513 RelocInfo::Mode mode = it.rinfo()->rmode(); 13514 if (mode == RelocInfo::EMBEDDED_OBJECT) { 13515 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER); 13516 } else if (mode == RelocInfo::CELL) { 13517 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER); 13518 } 13519 } 13520 } 13521 13522 13523 void Code::Relocate(intptr_t delta) { 13524 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { 13525 it.rinfo()->apply(delta); 13526 } 13527 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size()); 13528 } 13529 13530 13531 void Code::CopyFrom(const CodeDesc& desc) { 13532 // copy code 13533 CopyBytes(instruction_start(), desc.buffer, 13534 static_cast<size_t>(desc.instr_size)); 13535 13536 // copy unwinding info, if any 13537 if (desc.unwinding_info) { 13538 DCHECK_GT(desc.unwinding_info_size, 0); 13539 set_unwinding_info_size(desc.unwinding_info_size); 13540 CopyBytes(unwinding_info_start(), desc.unwinding_info, 13541 static_cast<size_t>(desc.unwinding_info_size)); 13542 } 13543 13544 // copy reloc info 13545 CopyBytes(relocation_start(), 13546 desc.buffer + desc.buffer_size - desc.reloc_size, 13547 static_cast<size_t>(desc.reloc_size)); 13548 13549 // unbox handles and relocate 13550 intptr_t delta = instruction_start() - desc.buffer; 13551 int mode_mask = RelocInfo::kCodeTargetMask | 13552 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 13553 RelocInfo::ModeMask(RelocInfo::CELL) | 13554 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | 13555 RelocInfo::kApplyMask; 13556 // Needed to find target_object and runtime_entry on X64 13557 Assembler* origin = desc.origin; 13558 AllowDeferredHandleDereference embedding_raw_address; 13559 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 13560 RelocInfo::Mode mode = it.rinfo()->rmode(); 13561 if (mode == RelocInfo::EMBEDDED_OBJECT) { 13562 Handle<Object> p = it.rinfo()->target_object_handle(origin); 13563 it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER, 13564 SKIP_ICACHE_FLUSH); 13565 } else if (mode == RelocInfo::CELL) { 13566 Handle<Cell> cell = it.rinfo()->target_cell_handle(); 13567 it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER, 13568 SKIP_ICACHE_FLUSH); 13569 } else if (RelocInfo::IsCodeTarget(mode)) { 13570 // rewrite code handles in inline cache targets to direct 13571 // pointers to the first instruction in the code object 13572 Handle<Object> p = it.rinfo()->target_object_handle(origin); 13573 Code* code = Code::cast(*p); 13574 it.rinfo()->set_target_address(code->instruction_start(), 13575 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); 13576 } else if (RelocInfo::IsRuntimeEntry(mode)) { 13577 Address p = it.rinfo()->target_runtime_entry(origin); 13578 it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER, 13579 SKIP_ICACHE_FLUSH); 13580 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) { 13581 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin); 13582 Code* code = Code::cast(*p); 13583 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH); 13584 } else { 13585 it.rinfo()->apply(delta); 13586 } 13587 } 13588 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size()); 13589 } 13590 13591 // Locate the source position which is closest to the code offset. This is 13592 // using the source position information embedded in the relocation info. 13593 // The position returned is relative to the beginning of the script where the 13594 // source for this function is found. 13595 int Code::SourcePosition(int code_offset) { 13596 // Subtract one because the current PC is one instruction after the call site. 13597 Address pc = instruction_start() + code_offset - 1; 13598 int position = RelocInfo::kNoPosition; // Initially no position found. 13599 // Find the closest position attached to a pc lower or equal to the current. 13600 // Note that the pc of reloc infos grow monotonically. 13601 for (RelocIterator it(this, RelocInfo::kPositionMask); 13602 !it.done() && it.rinfo()->pc() <= pc; it.next()) { 13603 position = static_cast<int>(it.rinfo()->data()); 13604 } 13605 DCHECK(kind() == FUNCTION || (is_optimized_code() && is_turbofanned()) || 13606 is_wasm_code() || position == RelocInfo::kNoPosition); 13607 return position; 13608 } 13609 13610 13611 // Same as Code::SourcePosition above except it only looks for statement 13612 // positions. 13613 int Code::SourceStatementPosition(int code_offset) { 13614 // First find the closest position. 13615 int position = SourcePosition(code_offset); 13616 // Now find the closest statement position before the position. 13617 int statement_position = 0; 13618 for (RelocIterator it(this, RelocInfo::kPositionMask); !it.done(); 13619 it.next()) { 13620 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) { 13621 int p = static_cast<int>(it.rinfo()->data()); 13622 if (statement_position < p && p <= position) { 13623 statement_position = p; 13624 } 13625 } 13626 } 13627 return statement_position; 13628 } 13629 13630 13631 SafepointEntry Code::GetSafepointEntry(Address pc) { 13632 SafepointTable table(this); 13633 return table.FindEntry(pc); 13634 } 13635 13636 13637 Object* Code::FindNthObject(int n, Map* match_map) { 13638 DCHECK(is_inline_cache_stub()); 13639 DisallowHeapAllocation no_allocation; 13640 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 13641 for (RelocIterator it(this, mask); !it.done(); it.next()) { 13642 RelocInfo* info = it.rinfo(); 13643 Object* object = info->target_object(); 13644 if (object->IsWeakCell()) object = WeakCell::cast(object)->value(); 13645 if (object->IsHeapObject()) { 13646 if (HeapObject::cast(object)->map() == match_map) { 13647 if (--n == 0) return object; 13648 } 13649 } 13650 } 13651 return NULL; 13652 } 13653 13654 13655 AllocationSite* Code::FindFirstAllocationSite() { 13656 Object* result = FindNthObject(1, GetHeap()->allocation_site_map()); 13657 return (result != NULL) ? AllocationSite::cast(result) : NULL; 13658 } 13659 13660 13661 Map* Code::FindFirstMap() { 13662 Object* result = FindNthObject(1, GetHeap()->meta_map()); 13663 return (result != NULL) ? Map::cast(result) : NULL; 13664 } 13665 13666 13667 void Code::FindAndReplace(const FindAndReplacePattern& pattern) { 13668 DCHECK(is_inline_cache_stub() || is_handler()); 13669 DisallowHeapAllocation no_allocation; 13670 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 13671 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32); 13672 int current_pattern = 0; 13673 for (RelocIterator it(this, mask); !it.done(); it.next()) { 13674 RelocInfo* info = it.rinfo(); 13675 Object* object = info->target_object(); 13676 if (object->IsHeapObject()) { 13677 if (object->IsWeakCell()) { 13678 object = HeapObject::cast(WeakCell::cast(object)->value()); 13679 } 13680 Map* map = HeapObject::cast(object)->map(); 13681 if (map == *pattern.find_[current_pattern]) { 13682 info->set_target_object(*pattern.replace_[current_pattern]); 13683 if (++current_pattern == pattern.count_) return; 13684 } 13685 } 13686 } 13687 UNREACHABLE(); 13688 } 13689 13690 13691 void Code::ClearInlineCaches() { 13692 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | 13693 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); 13694 for (RelocIterator it(this, mask); !it.done(); it.next()) { 13695 RelocInfo* info = it.rinfo(); 13696 Code* target(Code::GetCodeFromTargetAddress(info->target_address())); 13697 if (target->is_inline_cache_stub()) { 13698 IC::Clear(this->GetIsolate(), info->pc(), info->host()->constant_pool()); 13699 } 13700 } 13701 } 13702 13703 int AbstractCode::SourcePosition(int offset) { 13704 return IsBytecodeArray() ? GetBytecodeArray()->SourcePosition(offset) 13705 : GetCode()->SourcePosition(offset); 13706 } 13707 13708 int AbstractCode::SourceStatementPosition(int offset) { 13709 return IsBytecodeArray() ? GetBytecodeArray()->SourceStatementPosition(offset) 13710 : GetCode()->SourceStatementPosition(offset); 13711 } 13712 13713 void JSFunction::ClearTypeFeedbackInfo() { 13714 feedback_vector()->ClearSlots(shared()); 13715 } 13716 13717 void JSFunction::ClearTypeFeedbackInfoAtGCTime() { 13718 feedback_vector()->ClearSlotsAtGCTime(shared()); 13719 } 13720 13721 BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) { 13722 DisallowHeapAllocation no_gc; 13723 DCHECK(kind() == FUNCTION); 13724 BackEdgeTable back_edges(this, &no_gc); 13725 for (uint32_t i = 0; i < back_edges.length(); i++) { 13726 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i); 13727 } 13728 return BailoutId::None(); 13729 } 13730 13731 13732 uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) { 13733 DisallowHeapAllocation no_gc; 13734 DCHECK(kind() == FUNCTION); 13735 BackEdgeTable back_edges(this, &no_gc); 13736 for (uint32_t i = 0; i < back_edges.length(); i++) { 13737 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i); 13738 } 13739 UNREACHABLE(); // We expect to find the back edge. 13740 return 0; 13741 } 13742 13743 13744 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) { 13745 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY); 13746 } 13747 13748 13749 void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) { 13750 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge, 13751 NO_MARKING_PARITY); 13752 } 13753 13754 13755 // NextAge defines the Code::Age state transitions during a GC cycle. 13756 static Code::Age NextAge(Code::Age age) { 13757 switch (age) { 13758 case Code::kNotExecutedCodeAge: // Keep, until we've been executed. 13759 case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed. 13760 case Code::kLastCodeAge: // Clamp at last Code::Age value. 13761 return age; 13762 case Code::kExecutedOnceCodeAge: 13763 // Pre-age code that has only been executed once. 13764 return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1); 13765 default: 13766 return static_cast<Code::Age>(age + 1); // Default case: Increase age. 13767 } 13768 } 13769 13770 13771 // IsOldAge defines the collection criteria for a Code object. 13772 static bool IsOldAge(Code::Age age) { 13773 return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge; 13774 } 13775 13776 13777 void Code::MakeYoung(Isolate* isolate) { 13778 byte* sequence = FindCodeAgeSequence(); 13779 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate); 13780 } 13781 13782 void Code::PreAge(Isolate* isolate) { 13783 byte* sequence = FindCodeAgeSequence(); 13784 if (sequence != NULL) { 13785 PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge, NO_MARKING_PARITY); 13786 } 13787 } 13788 13789 void Code::MarkToBeExecutedOnce(Isolate* isolate) { 13790 byte* sequence = FindCodeAgeSequence(); 13791 if (sequence != NULL) { 13792 PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge, 13793 NO_MARKING_PARITY); 13794 } 13795 } 13796 13797 void Code::MakeOlder(MarkingParity current_parity) { 13798 byte* sequence = FindCodeAgeSequence(); 13799 if (sequence != NULL) { 13800 Age age; 13801 MarkingParity code_parity; 13802 Isolate* isolate = GetIsolate(); 13803 GetCodeAgeAndParity(isolate, sequence, &age, &code_parity); 13804 Age next_age = NextAge(age); 13805 if (age != next_age && code_parity != current_parity) { 13806 PatchPlatformCodeAge(isolate, sequence, next_age, current_parity); 13807 } 13808 } 13809 } 13810 13811 13812 bool Code::IsOld() { 13813 return IsOldAge(GetAge()); 13814 } 13815 13816 13817 byte* Code::FindCodeAgeSequence() { 13818 return FLAG_age_code && 13819 prologue_offset() != Code::kPrologueOffsetNotSet && 13820 (kind() == OPTIMIZED_FUNCTION || 13821 (kind() == FUNCTION && !has_debug_break_slots())) 13822 ? instruction_start() + prologue_offset() 13823 : NULL; 13824 } 13825 13826 13827 Code::Age Code::GetAge() { 13828 byte* sequence = FindCodeAgeSequence(); 13829 if (sequence == NULL) { 13830 return kNoAgeCodeAge; 13831 } 13832 Age age; 13833 MarkingParity parity; 13834 GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity); 13835 return age; 13836 } 13837 13838 13839 void Code::GetCodeAgeAndParity(Code* code, Age* age, 13840 MarkingParity* parity) { 13841 Isolate* isolate = code->GetIsolate(); 13842 Builtins* builtins = isolate->builtins(); 13843 Code* stub = NULL; 13844 #define HANDLE_CODE_AGE(AGE) \ 13845 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \ 13846 if (code == stub) { \ 13847 *age = k##AGE##CodeAge; \ 13848 *parity = EVEN_MARKING_PARITY; \ 13849 return; \ 13850 } \ 13851 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \ 13852 if (code == stub) { \ 13853 *age = k##AGE##CodeAge; \ 13854 *parity = ODD_MARKING_PARITY; \ 13855 return; \ 13856 } 13857 CODE_AGE_LIST(HANDLE_CODE_AGE) 13858 #undef HANDLE_CODE_AGE 13859 stub = *builtins->MarkCodeAsExecutedOnce(); 13860 if (code == stub) { 13861 *age = kNotExecutedCodeAge; 13862 *parity = NO_MARKING_PARITY; 13863 return; 13864 } 13865 stub = *builtins->MarkCodeAsExecutedTwice(); 13866 if (code == stub) { 13867 *age = kExecutedOnceCodeAge; 13868 *parity = NO_MARKING_PARITY; 13869 return; 13870 } 13871 stub = *builtins->MarkCodeAsToBeExecutedOnce(); 13872 if (code == stub) { 13873 *age = kToBeExecutedOnceCodeAge; 13874 *parity = NO_MARKING_PARITY; 13875 return; 13876 } 13877 UNREACHABLE(); 13878 } 13879 13880 13881 Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) { 13882 Builtins* builtins = isolate->builtins(); 13883 switch (age) { 13884 #define HANDLE_CODE_AGE(AGE) \ 13885 case k##AGE##CodeAge: { \ 13886 Code* stub = parity == EVEN_MARKING_PARITY \ 13887 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \ 13888 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \ 13889 return stub; \ 13890 } 13891 CODE_AGE_LIST(HANDLE_CODE_AGE) 13892 #undef HANDLE_CODE_AGE 13893 case kNotExecutedCodeAge: { 13894 DCHECK(parity == NO_MARKING_PARITY); 13895 return *builtins->MarkCodeAsExecutedOnce(); 13896 } 13897 case kExecutedOnceCodeAge: { 13898 DCHECK(parity == NO_MARKING_PARITY); 13899 return *builtins->MarkCodeAsExecutedTwice(); 13900 } 13901 case kToBeExecutedOnceCodeAge: { 13902 DCHECK(parity == NO_MARKING_PARITY); 13903 return *builtins->MarkCodeAsToBeExecutedOnce(); 13904 } 13905 default: 13906 UNREACHABLE(); 13907 break; 13908 } 13909 return NULL; 13910 } 13911 13912 13913 void Code::PrintDeoptLocation(FILE* out, Address pc) { 13914 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc); 13915 class SourcePosition pos = info.position; 13916 if (info.deopt_reason != Deoptimizer::kNoReason || !pos.IsUnknown()) { 13917 if (FLAG_hydrogen_track_positions) { 13918 PrintF(out, " ;;; deoptimize at %d_%d: %s\n", 13919 pos.inlining_id(), pos.position(), 13920 Deoptimizer::GetDeoptReason(info.deopt_reason)); 13921 } else { 13922 PrintF(out, " ;;; deoptimize at %d: %s\n", pos.raw(), 13923 Deoptimizer::GetDeoptReason(info.deopt_reason)); 13924 } 13925 } 13926 } 13927 13928 13929 bool Code::CanDeoptAt(Address pc) { 13930 DeoptimizationInputData* deopt_data = 13931 DeoptimizationInputData::cast(deoptimization_data()); 13932 Address code_start_address = instruction_start(); 13933 for (int i = 0; i < deopt_data->DeoptCount(); i++) { 13934 if (deopt_data->Pc(i)->value() == -1) continue; 13935 Address address = code_start_address + deopt_data->Pc(i)->value(); 13936 if (address == pc && deopt_data->AstId(i) != BailoutId::None()) { 13937 return true; 13938 } 13939 } 13940 return false; 13941 } 13942 13943 13944 // Identify kind of code. 13945 const char* Code::Kind2String(Kind kind) { 13946 switch (kind) { 13947 #define CASE(name) case name: return #name; 13948 CODE_KIND_LIST(CASE) 13949 #undef CASE 13950 case NUMBER_OF_KINDS: break; 13951 } 13952 UNREACHABLE(); 13953 return NULL; 13954 } 13955 13956 // Identify kind of code. 13957 const char* AbstractCode::Kind2String(Kind kind) { 13958 if (kind < AbstractCode::INTERPRETED_FUNCTION) 13959 return Code::Kind2String((Code::Kind)kind); 13960 if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION"; 13961 UNREACHABLE(); 13962 return NULL; 13963 } 13964 13965 Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) { 13966 DCHECK(code->kind() == OPTIMIZED_FUNCTION); 13967 WeakCell* raw_cell = code->CachedWeakCell(); 13968 if (raw_cell != NULL) return Handle<WeakCell>(raw_cell); 13969 Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code); 13970 DeoptimizationInputData::cast(code->deoptimization_data()) 13971 ->SetWeakCellCache(*cell); 13972 return cell; 13973 } 13974 13975 13976 WeakCell* Code::CachedWeakCell() { 13977 DCHECK(kind() == OPTIMIZED_FUNCTION); 13978 Object* weak_cell_cache = 13979 DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache(); 13980 if (weak_cell_cache->IsWeakCell()) { 13981 DCHECK(this == WeakCell::cast(weak_cell_cache)->value()); 13982 return WeakCell::cast(weak_cell_cache); 13983 } 13984 return NULL; 13985 } 13986 13987 #ifdef ENABLE_DISASSEMBLER 13988 13989 void DeoptimizationInputData::DeoptimizationInputDataPrint( 13990 std::ostream& os) { // NOLINT 13991 disasm::NameConverter converter; 13992 int const inlined_function_count = InlinedFunctionCount()->value(); 13993 os << "Inlined functions (count = " << inlined_function_count << ")\n"; 13994 for (int id = 0; id < inlined_function_count; ++id) { 13995 Object* info = LiteralArray()->get(id); 13996 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n"; 13997 } 13998 os << "\n"; 13999 int deopt_count = DeoptCount(); 14000 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n"; 14001 if (0 != deopt_count) { 14002 os << " index ast id argc pc"; 14003 if (FLAG_print_code_verbose) os << " commands"; 14004 os << "\n"; 14005 } 14006 for (int i = 0; i < deopt_count; i++) { 14007 os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " " 14008 << std::setw(6) << ArgumentsStackHeight(i)->value() << " " 14009 << std::setw(6) << Pc(i)->value(); 14010 14011 if (!FLAG_print_code_verbose) { 14012 os << "\n"; 14013 continue; 14014 } 14015 // Print details of the frame translation. 14016 int translation_index = TranslationIndex(i)->value(); 14017 TranslationIterator iterator(TranslationByteArray(), translation_index); 14018 Translation::Opcode opcode = 14019 static_cast<Translation::Opcode>(iterator.Next()); 14020 DCHECK(Translation::BEGIN == opcode); 14021 int frame_count = iterator.Next(); 14022 int jsframe_count = iterator.Next(); 14023 os << " " << Translation::StringFor(opcode) 14024 << " {frame count=" << frame_count 14025 << ", js frame count=" << jsframe_count << "}\n"; 14026 14027 while (iterator.HasNext() && 14028 Translation::BEGIN != 14029 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) { 14030 os << std::setw(31) << " " << Translation::StringFor(opcode) << " "; 14031 14032 switch (opcode) { 14033 case Translation::BEGIN: 14034 UNREACHABLE(); 14035 break; 14036 14037 case Translation::JS_FRAME: { 14038 int ast_id = iterator.Next(); 14039 int shared_info_id = iterator.Next(); 14040 unsigned height = iterator.Next(); 14041 Object* shared_info = LiteralArray()->get(shared_info_id); 14042 os << "{ast_id=" << ast_id << ", function=" 14043 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14044 << ", height=" << height << "}"; 14045 break; 14046 } 14047 14048 case Translation::INTERPRETED_FRAME: { 14049 int bytecode_offset = iterator.Next(); 14050 int shared_info_id = iterator.Next(); 14051 unsigned height = iterator.Next(); 14052 Object* shared_info = LiteralArray()->get(shared_info_id); 14053 os << "{bytecode_offset=" << bytecode_offset << ", function=" 14054 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14055 << ", height=" << height << "}"; 14056 break; 14057 } 14058 14059 case Translation::COMPILED_STUB_FRAME: { 14060 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next()); 14061 os << "{kind=" << stub_kind << "}"; 14062 break; 14063 } 14064 14065 case Translation::ARGUMENTS_ADAPTOR_FRAME: 14066 case Translation::CONSTRUCT_STUB_FRAME: { 14067 int shared_info_id = iterator.Next(); 14068 Object* shared_info = LiteralArray()->get(shared_info_id); 14069 unsigned height = iterator.Next(); 14070 os << "{function=" 14071 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14072 << ", height=" << height << "}"; 14073 break; 14074 } 14075 14076 case Translation::TAIL_CALLER_FRAME: { 14077 int shared_info_id = iterator.Next(); 14078 Object* shared_info = LiteralArray()->get(shared_info_id); 14079 os << "{function=" 14080 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14081 << "}"; 14082 break; 14083 } 14084 14085 case Translation::GETTER_STUB_FRAME: 14086 case Translation::SETTER_STUB_FRAME: { 14087 int shared_info_id = iterator.Next(); 14088 Object* shared_info = LiteralArray()->get(shared_info_id); 14089 os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info) 14090 ->DebugName()) << "}"; 14091 break; 14092 } 14093 14094 case Translation::REGISTER: { 14095 int reg_code = iterator.Next(); 14096 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}"; 14097 break; 14098 } 14099 14100 case Translation::INT32_REGISTER: { 14101 int reg_code = iterator.Next(); 14102 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}"; 14103 break; 14104 } 14105 14106 case Translation::UINT32_REGISTER: { 14107 int reg_code = iterator.Next(); 14108 os << "{input=" << converter.NameOfCPURegister(reg_code) 14109 << " (unsigned)}"; 14110 break; 14111 } 14112 14113 case Translation::BOOL_REGISTER: { 14114 int reg_code = iterator.Next(); 14115 os << "{input=" << converter.NameOfCPURegister(reg_code) 14116 << " (bool)}"; 14117 break; 14118 } 14119 14120 case Translation::FLOAT_REGISTER: { 14121 int reg_code = iterator.Next(); 14122 os << "{input=" 14123 << RegisterConfiguration::Crankshaft()->GetFloatRegisterName( 14124 reg_code) 14125 << "}"; 14126 break; 14127 } 14128 14129 case Translation::DOUBLE_REGISTER: { 14130 int reg_code = iterator.Next(); 14131 os << "{input=" 14132 << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName( 14133 reg_code) 14134 << "}"; 14135 break; 14136 } 14137 14138 case Translation::STACK_SLOT: { 14139 int input_slot_index = iterator.Next(); 14140 os << "{input=" << input_slot_index << "}"; 14141 break; 14142 } 14143 14144 case Translation::INT32_STACK_SLOT: { 14145 int input_slot_index = iterator.Next(); 14146 os << "{input=" << input_slot_index << "}"; 14147 break; 14148 } 14149 14150 case Translation::UINT32_STACK_SLOT: { 14151 int input_slot_index = iterator.Next(); 14152 os << "{input=" << input_slot_index << " (unsigned)}"; 14153 break; 14154 } 14155 14156 case Translation::BOOL_STACK_SLOT: { 14157 int input_slot_index = iterator.Next(); 14158 os << "{input=" << input_slot_index << " (bool)}"; 14159 break; 14160 } 14161 14162 case Translation::FLOAT_STACK_SLOT: 14163 case Translation::DOUBLE_STACK_SLOT: { 14164 int input_slot_index = iterator.Next(); 14165 os << "{input=" << input_slot_index << "}"; 14166 break; 14167 } 14168 14169 case Translation::LITERAL: { 14170 int literal_index = iterator.Next(); 14171 Object* literal_value = LiteralArray()->get(literal_index); 14172 os << "{literal_id=" << literal_index << " (" << Brief(literal_value) 14173 << ")}"; 14174 break; 14175 } 14176 14177 case Translation::DUPLICATED_OBJECT: { 14178 int object_index = iterator.Next(); 14179 os << "{object_index=" << object_index << "}"; 14180 break; 14181 } 14182 14183 case Translation::ARGUMENTS_OBJECT: 14184 case Translation::CAPTURED_OBJECT: { 14185 int args_length = iterator.Next(); 14186 os << "{length=" << args_length << "}"; 14187 break; 14188 } 14189 } 14190 os << "\n"; 14191 } 14192 } 14193 } 14194 14195 14196 void DeoptimizationOutputData::DeoptimizationOutputDataPrint( 14197 std::ostream& os) { // NOLINT 14198 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints() 14199 << ")\n"; 14200 if (this->DeoptPoints() == 0) return; 14201 14202 os << "ast id pc state\n"; 14203 for (int i = 0; i < this->DeoptPoints(); i++) { 14204 int pc_and_state = this->PcAndState(i)->value(); 14205 os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8) 14206 << FullCodeGenerator::PcField::decode(pc_and_state) << " " 14207 << Deoptimizer::BailoutStateToString( 14208 FullCodeGenerator::BailoutStateField::decode(pc_and_state)) 14209 << "\n"; 14210 } 14211 } 14212 14213 14214 void HandlerTable::HandlerTableRangePrint(std::ostream& os) { 14215 os << " from to hdlr\n"; 14216 for (int i = 0; i < length(); i += kRangeEntrySize) { 14217 int pc_start = Smi::cast(get(i + kRangeStartIndex))->value(); 14218 int pc_end = Smi::cast(get(i + kRangeEndIndex))->value(); 14219 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value(); 14220 int handler_offset = HandlerOffsetField::decode(handler_field); 14221 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 14222 int data = Smi::cast(get(i + kRangeDataIndex))->value(); 14223 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end 14224 << ") -> " << std::setw(4) << handler_offset 14225 << " (prediction=" << prediction << ", data=" << data << ")\n"; 14226 } 14227 } 14228 14229 14230 void HandlerTable::HandlerTableReturnPrint(std::ostream& os) { 14231 os << " off hdlr (c)\n"; 14232 for (int i = 0; i < length(); i += kReturnEntrySize) { 14233 int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value(); 14234 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value(); 14235 int handler_offset = HandlerOffsetField::decode(handler_field); 14236 CatchPrediction prediction = HandlerPredictionField::decode(handler_field); 14237 os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4) 14238 << handler_offset << " (prediction=" << prediction << ")\n"; 14239 } 14240 } 14241 14242 14243 const char* Code::ICState2String(InlineCacheState state) { 14244 switch (state) { 14245 case UNINITIALIZED: return "UNINITIALIZED"; 14246 case PREMONOMORPHIC: return "PREMONOMORPHIC"; 14247 case MONOMORPHIC: return "MONOMORPHIC"; 14248 case RECOMPUTE_HANDLER: 14249 return "RECOMPUTE_HANDLER"; 14250 case POLYMORPHIC: return "POLYMORPHIC"; 14251 case MEGAMORPHIC: return "MEGAMORPHIC"; 14252 case GENERIC: return "GENERIC"; 14253 } 14254 UNREACHABLE(); 14255 return NULL; 14256 } 14257 14258 14259 void Code::PrintExtraICState(std::ostream& os, // NOLINT 14260 Kind kind, ExtraICState extra) { 14261 os << "extra_ic_state = "; 14262 if ((kind == STORE_IC || kind == KEYED_STORE_IC) && 14263 is_strict(static_cast<LanguageMode>(extra))) { 14264 os << "STRICT\n"; 14265 } else { 14266 os << extra << "\n"; 14267 } 14268 } 14269 14270 14271 void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT 14272 os << "kind = " << Kind2String(kind()) << "\n"; 14273 if (IsCodeStubOrIC()) { 14274 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this)); 14275 os << "major_key = " << (n == NULL ? "null" : n) << "\n"; 14276 } 14277 if (is_inline_cache_stub()) { 14278 if (!IC::ICUseVector(kind())) { 14279 InlineCacheState ic_state = IC::StateFromCode(this); 14280 os << "ic_state = " << ICState2String(ic_state) << "\n"; 14281 } 14282 PrintExtraICState(os, kind(), extra_ic_state()); 14283 if (is_compare_ic_stub()) { 14284 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC); 14285 CompareICStub stub(stub_key(), GetIsolate()); 14286 os << "compare_state = " << CompareICState::GetStateName(stub.left()) 14287 << "*" << CompareICState::GetStateName(stub.right()) << " -> " 14288 << CompareICState::GetStateName(stub.state()) << "\n"; 14289 os << "compare_operation = " << Token::Name(stub.op()) << "\n"; 14290 } 14291 } 14292 if ((name != nullptr) && (name[0] != '\0')) { 14293 os << "name = " << name << "\n"; 14294 } else if (kind() == BUILTIN) { 14295 name = GetIsolate()->builtins()->Lookup(instruction_start()); 14296 if (name != nullptr) { 14297 os << "name = " << name << "\n"; 14298 } 14299 } else if (kind() == BYTECODE_HANDLER) { 14300 name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this); 14301 if (name != nullptr) { 14302 os << "name = " << name << "\n"; 14303 } 14304 } 14305 if (kind() == OPTIMIZED_FUNCTION) { 14306 os << "stack_slots = " << stack_slots() << "\n"; 14307 } 14308 os << "compiler = " << (is_turbofanned() 14309 ? "turbofan" 14310 : is_crankshafted() ? "crankshaft" 14311 : kind() == Code::FUNCTION 14312 ? "full-codegen" 14313 : "unknown") << "\n"; 14314 14315 os << "Instructions (size = " << instruction_size() << ")\n"; 14316 { 14317 Isolate* isolate = GetIsolate(); 14318 int size = instruction_size(); 14319 int safepoint_offset = 14320 is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size; 14321 int back_edge_offset = (kind() == Code::FUNCTION) 14322 ? static_cast<int>(back_edge_table_offset()) 14323 : size; 14324 int constant_pool_offset = FLAG_enable_embedded_constant_pool 14325 ? this->constant_pool_offset() 14326 : size; 14327 14328 // Stop before reaching any embedded tables 14329 int code_size = Min(safepoint_offset, back_edge_offset); 14330 code_size = Min(code_size, constant_pool_offset); 14331 byte* begin = instruction_start(); 14332 byte* end = begin + code_size; 14333 Disassembler::Decode(isolate, &os, begin, end, this); 14334 14335 if (constant_pool_offset < size) { 14336 int constant_pool_size = size - constant_pool_offset; 14337 DCHECK((constant_pool_size & kPointerAlignmentMask) == 0); 14338 os << "\nConstant Pool (size = " << constant_pool_size << ")\n"; 14339 Vector<char> buf = Vector<char>::New(50); 14340 intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset); 14341 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) { 14342 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr); 14343 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n"; 14344 } 14345 } 14346 } 14347 os << "\n"; 14348 14349 if (kind() == FUNCTION) { 14350 DeoptimizationOutputData* data = 14351 DeoptimizationOutputData::cast(this->deoptimization_data()); 14352 data->DeoptimizationOutputDataPrint(os); 14353 } else if (kind() == OPTIMIZED_FUNCTION) { 14354 DeoptimizationInputData* data = 14355 DeoptimizationInputData::cast(this->deoptimization_data()); 14356 data->DeoptimizationInputDataPrint(os); 14357 } 14358 os << "\n"; 14359 14360 if (is_crankshafted()) { 14361 SafepointTable table(this); 14362 os << "Safepoints (size = " << table.size() << ")\n"; 14363 for (unsigned i = 0; i < table.length(); i++) { 14364 unsigned pc_offset = table.GetPcOffset(i); 14365 os << static_cast<const void*>(instruction_start() + pc_offset) << " "; 14366 os << std::setw(4) << pc_offset << " "; 14367 table.PrintEntry(i, os); 14368 os << " (sp -> fp) "; 14369 SafepointEntry entry = table.GetEntry(i); 14370 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) { 14371 os << std::setw(6) << entry.deoptimization_index(); 14372 } else { 14373 os << "<none>"; 14374 } 14375 if (entry.argument_count() > 0) { 14376 os << " argc: " << entry.argument_count(); 14377 } 14378 os << "\n"; 14379 } 14380 os << "\n"; 14381 } else if (kind() == FUNCTION) { 14382 unsigned offset = back_edge_table_offset(); 14383 // If there is no back edge table, the "table start" will be at or after 14384 // (due to alignment) the end of the instruction stream. 14385 if (static_cast<int>(offset) < instruction_size()) { 14386 DisallowHeapAllocation no_gc; 14387 BackEdgeTable back_edges(this, &no_gc); 14388 14389 os << "Back edges (size = " << back_edges.length() << ")\n"; 14390 os << "ast_id pc_offset loop_depth\n"; 14391 14392 for (uint32_t i = 0; i < back_edges.length(); i++) { 14393 os << std::setw(6) << back_edges.ast_id(i).ToInt() << " " 14394 << std::setw(9) << back_edges.pc_offset(i) << " " << std::setw(10) 14395 << back_edges.loop_depth(i) << "\n"; 14396 } 14397 14398 os << "\n"; 14399 } 14400 #ifdef OBJECT_PRINT 14401 if (!type_feedback_info()->IsUndefined(GetIsolate())) { 14402 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os); 14403 os << "\n"; 14404 } 14405 #endif 14406 } 14407 14408 if (handler_table()->length() > 0) { 14409 os << "Handler Table (size = " << handler_table()->Size() << ")\n"; 14410 if (kind() == FUNCTION) { 14411 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os); 14412 } else if (kind() == OPTIMIZED_FUNCTION) { 14413 HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os); 14414 } 14415 os << "\n"; 14416 } 14417 14418 os << "RelocInfo (size = " << relocation_size() << ")\n"; 14419 for (RelocIterator it(this); !it.done(); it.next()) { 14420 it.rinfo()->Print(GetIsolate(), os); 14421 } 14422 os << "\n"; 14423 } 14424 #endif // ENABLE_DISASSEMBLER 14425 14426 int BytecodeArray::SourcePosition(int offset) { 14427 int last_position = 0; 14428 for (interpreter::SourcePositionTableIterator iterator( 14429 source_position_table()); 14430 !iterator.done() && iterator.bytecode_offset() <= offset; 14431 iterator.Advance()) { 14432 last_position = iterator.source_position(); 14433 } 14434 return last_position; 14435 } 14436 14437 int BytecodeArray::SourceStatementPosition(int offset) { 14438 // First find the closest position. 14439 int position = SourcePosition(offset); 14440 // Now find the closest statement position before the position. 14441 int statement_position = 0; 14442 for (interpreter::SourcePositionTableIterator it(source_position_table()); 14443 !it.done(); it.Advance()) { 14444 if (it.is_statement()) { 14445 int p = it.source_position(); 14446 if (statement_position < p && p <= position) { 14447 statement_position = p; 14448 } 14449 } 14450 } 14451 return statement_position; 14452 } 14453 14454 void BytecodeArray::Disassemble(std::ostream& os) { 14455 os << "Parameter count " << parameter_count() << "\n"; 14456 os << "Frame size " << frame_size() << "\n"; 14457 14458 const uint8_t* base_address = GetFirstBytecodeAddress(); 14459 interpreter::SourcePositionTableIterator source_positions( 14460 source_position_table()); 14461 14462 interpreter::BytecodeArrayIterator iterator(handle(this)); 14463 while (!iterator.done()) { 14464 if (!source_positions.done() && 14465 iterator.current_offset() == source_positions.bytecode_offset()) { 14466 os << std::setw(5) << source_positions.source_position(); 14467 os << (source_positions.is_statement() ? " S> " : " E> "); 14468 source_positions.Advance(); 14469 } else { 14470 os << " "; 14471 } 14472 const uint8_t* current_address = base_address + iterator.current_offset(); 14473 os << reinterpret_cast<const void*>(current_address) << " @ " 14474 << std::setw(4) << iterator.current_offset() << " : "; 14475 interpreter::Bytecodes::Decode(os, current_address, parameter_count()); 14476 if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) { 14477 const void* jump_target = base_address + iterator.GetJumpTargetOffset(); 14478 os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset() 14479 << ")"; 14480 } 14481 os << std::endl; 14482 iterator.Advance(); 14483 } 14484 14485 if (constant_pool()->length() > 0) { 14486 os << "Constant pool (size = " << constant_pool()->length() << ")\n"; 14487 constant_pool()->Print(); 14488 } 14489 14490 #ifdef ENABLE_DISASSEMBLER 14491 if (handler_table()->length() > 0) { 14492 os << "Handler Table (size = " << handler_table()->Size() << ")\n"; 14493 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os); 14494 } 14495 #endif 14496 } 14497 14498 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) { 14499 BytecodeArray* from = this; 14500 DCHECK_EQ(from->length(), to->length()); 14501 CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(), 14502 from->length()); 14503 } 14504 14505 // static 14506 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { 14507 DCHECK(capacity >= 0); 14508 array->GetIsolate()->factory()->NewJSArrayStorage( 14509 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 14510 } 14511 14512 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) { 14513 // We should never end in here with a pixel or external array. 14514 DCHECK(array->AllowsSetLength()); 14515 if (array->SetLengthWouldNormalize(new_length)) { 14516 JSObject::NormalizeElements(array); 14517 } 14518 array->GetElementsAccessor()->SetLength(array, new_length); 14519 } 14520 14521 14522 // static 14523 void Map::AddDependentCode(Handle<Map> map, 14524 DependentCode::DependencyGroup group, 14525 Handle<Code> code) { 14526 Handle<WeakCell> cell = Code::WeakCellFor(code); 14527 Handle<DependentCode> codes = DependentCode::InsertWeakCode( 14528 Handle<DependentCode>(map->dependent_code()), group, cell); 14529 if (*codes != map->dependent_code()) map->set_dependent_code(*codes); 14530 } 14531 14532 14533 Handle<DependentCode> DependentCode::InsertCompilationDependencies( 14534 Handle<DependentCode> entries, DependencyGroup group, 14535 Handle<Foreign> info) { 14536 return Insert(entries, group, info); 14537 } 14538 14539 14540 Handle<DependentCode> DependentCode::InsertWeakCode( 14541 Handle<DependentCode> entries, DependencyGroup group, 14542 Handle<WeakCell> code_cell) { 14543 return Insert(entries, group, code_cell); 14544 } 14545 14546 14547 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries, 14548 DependencyGroup group, 14549 Handle<Object> object) { 14550 if (entries->length() == 0 || entries->group() > group) { 14551 // There is no such group. 14552 return DependentCode::New(group, object, entries); 14553 } 14554 if (entries->group() < group) { 14555 // The group comes later in the list. 14556 Handle<DependentCode> old_next(entries->next_link()); 14557 Handle<DependentCode> new_next = Insert(old_next, group, object); 14558 if (!old_next.is_identical_to(new_next)) { 14559 entries->set_next_link(*new_next); 14560 } 14561 return entries; 14562 } 14563 DCHECK_EQ(group, entries->group()); 14564 int count = entries->count(); 14565 // Check for existing entry to avoid duplicates. 14566 for (int i = 0; i < count; i++) { 14567 if (entries->object_at(i) == *object) return entries; 14568 } 14569 if (entries->length() < kCodesStartIndex + count + 1) { 14570 entries = EnsureSpace(entries); 14571 // Count could have changed, reload it. 14572 count = entries->count(); 14573 } 14574 entries->set_object_at(count, *object); 14575 entries->set_count(count + 1); 14576 return entries; 14577 } 14578 14579 14580 Handle<DependentCode> DependentCode::New(DependencyGroup group, 14581 Handle<Object> object, 14582 Handle<DependentCode> next) { 14583 Isolate* isolate = next->GetIsolate(); 14584 Handle<DependentCode> result = Handle<DependentCode>::cast( 14585 isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED)); 14586 result->set_next_link(*next); 14587 result->set_flags(GroupField::encode(group) | CountField::encode(1)); 14588 result->set_object_at(0, *object); 14589 return result; 14590 } 14591 14592 14593 Handle<DependentCode> DependentCode::EnsureSpace( 14594 Handle<DependentCode> entries) { 14595 if (entries->Compact()) return entries; 14596 Isolate* isolate = entries->GetIsolate(); 14597 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count()); 14598 int grow_by = capacity - entries->length(); 14599 return Handle<DependentCode>::cast( 14600 isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED)); 14601 } 14602 14603 14604 bool DependentCode::Compact() { 14605 int old_count = count(); 14606 int new_count = 0; 14607 for (int i = 0; i < old_count; i++) { 14608 Object* obj = object_at(i); 14609 if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) { 14610 if (i != new_count) { 14611 copy(i, new_count); 14612 } 14613 new_count++; 14614 } 14615 } 14616 set_count(new_count); 14617 for (int i = new_count; i < old_count; i++) { 14618 clear_at(i); 14619 } 14620 return new_count < old_count; 14621 } 14622 14623 14624 void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info, 14625 WeakCell* code_cell) { 14626 if (this->length() == 0 || this->group() > group) { 14627 // There is no such group. 14628 return; 14629 } 14630 if (this->group() < group) { 14631 // The group comes later in the list. 14632 next_link()->UpdateToFinishedCode(group, info, code_cell); 14633 return; 14634 } 14635 DCHECK_EQ(group, this->group()); 14636 DisallowHeapAllocation no_gc; 14637 int count = this->count(); 14638 for (int i = 0; i < count; i++) { 14639 if (object_at(i) == info) { 14640 set_object_at(i, code_cell); 14641 break; 14642 } 14643 } 14644 #ifdef DEBUG 14645 for (int i = 0; i < count; i++) { 14646 DCHECK(object_at(i) != info); 14647 } 14648 #endif 14649 } 14650 14651 14652 void DependentCode::RemoveCompilationDependencies( 14653 DependentCode::DependencyGroup group, Foreign* info) { 14654 if (this->length() == 0 || this->group() > group) { 14655 // There is no such group. 14656 return; 14657 } 14658 if (this->group() < group) { 14659 // The group comes later in the list. 14660 next_link()->RemoveCompilationDependencies(group, info); 14661 return; 14662 } 14663 DCHECK_EQ(group, this->group()); 14664 DisallowHeapAllocation no_allocation; 14665 int old_count = count(); 14666 // Find compilation info wrapper. 14667 int info_pos = -1; 14668 for (int i = 0; i < old_count; i++) { 14669 if (object_at(i) == info) { 14670 info_pos = i; 14671 break; 14672 } 14673 } 14674 if (info_pos == -1) return; // Not found. 14675 // Use the last code to fill the gap. 14676 if (info_pos < old_count - 1) { 14677 copy(old_count - 1, info_pos); 14678 } 14679 clear_at(old_count - 1); 14680 set_count(old_count - 1); 14681 14682 #ifdef DEBUG 14683 for (int i = 0; i < old_count - 1; i++) { 14684 DCHECK(object_at(i) != info); 14685 } 14686 #endif 14687 } 14688 14689 14690 bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) { 14691 if (this->length() == 0 || this->group() > group) { 14692 // There is no such group. 14693 return false; 14694 } 14695 if (this->group() < group) { 14696 // The group comes later in the list. 14697 return next_link()->Contains(group, code_cell); 14698 } 14699 DCHECK_EQ(group, this->group()); 14700 int count = this->count(); 14701 for (int i = 0; i < count; i++) { 14702 if (object_at(i) == code_cell) return true; 14703 } 14704 return false; 14705 } 14706 14707 14708 bool DependentCode::IsEmpty(DependencyGroup group) { 14709 if (this->length() == 0 || this->group() > group) { 14710 // There is no such group. 14711 return true; 14712 } 14713 if (this->group() < group) { 14714 // The group comes later in the list. 14715 return next_link()->IsEmpty(group); 14716 } 14717 DCHECK_EQ(group, this->group()); 14718 return count() == 0; 14719 } 14720 14721 14722 bool DependentCode::MarkCodeForDeoptimization( 14723 Isolate* isolate, 14724 DependentCode::DependencyGroup group) { 14725 if (this->length() == 0 || this->group() > group) { 14726 // There is no such group. 14727 return false; 14728 } 14729 if (this->group() < group) { 14730 // The group comes later in the list. 14731 return next_link()->MarkCodeForDeoptimization(isolate, group); 14732 } 14733 DCHECK_EQ(group, this->group()); 14734 DisallowHeapAllocation no_allocation_scope; 14735 // Mark all the code that needs to be deoptimized. 14736 bool marked = false; 14737 bool invalidate_embedded_objects = group == kWeakCodeGroup; 14738 int count = this->count(); 14739 for (int i = 0; i < count; i++) { 14740 Object* obj = object_at(i); 14741 if (obj->IsWeakCell()) { 14742 WeakCell* cell = WeakCell::cast(obj); 14743 if (cell->cleared()) continue; 14744 Code* code = Code::cast(cell->value()); 14745 if (!code->marked_for_deoptimization()) { 14746 SetMarkedForDeoptimization(code, group); 14747 if (invalidate_embedded_objects) { 14748 code->InvalidateEmbeddedObjects(); 14749 } 14750 marked = true; 14751 } 14752 } else { 14753 DCHECK(obj->IsForeign()); 14754 CompilationDependencies* info = 14755 reinterpret_cast<CompilationDependencies*>( 14756 Foreign::cast(obj)->foreign_address()); 14757 info->Abort(); 14758 } 14759 } 14760 for (int i = 0; i < count; i++) { 14761 clear_at(i); 14762 } 14763 set_count(0); 14764 return marked; 14765 } 14766 14767 14768 void DependentCode::DeoptimizeDependentCodeGroup( 14769 Isolate* isolate, 14770 DependentCode::DependencyGroup group) { 14771 DCHECK(AllowCodeDependencyChange::IsAllowed()); 14772 DisallowHeapAllocation no_allocation_scope; 14773 bool marked = MarkCodeForDeoptimization(isolate, group); 14774 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate); 14775 } 14776 14777 14778 void DependentCode::SetMarkedForDeoptimization(Code* code, 14779 DependencyGroup group) { 14780 code->set_marked_for_deoptimization(true); 14781 if (FLAG_trace_deopt && 14782 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) { 14783 DeoptimizationInputData* deopt_data = 14784 DeoptimizationInputData::cast(code->deoptimization_data()); 14785 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer()); 14786 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR 14787 " (opt #%d) for deoptimization, reason: %s]\n", 14788 reinterpret_cast<intptr_t>(code), 14789 deopt_data->OptimizationId()->value(), DependencyGroupName(group)); 14790 } 14791 } 14792 14793 14794 const char* DependentCode::DependencyGroupName(DependencyGroup group) { 14795 switch (group) { 14796 case kWeakCodeGroup: 14797 return "weak-code"; 14798 case kTransitionGroup: 14799 return "transition"; 14800 case kPrototypeCheckGroup: 14801 return "prototype-check"; 14802 case kPropertyCellChangedGroup: 14803 return "property-cell-changed"; 14804 case kFieldTypeGroup: 14805 return "field-type"; 14806 case kInitialMapChangedGroup: 14807 return "initial-map-changed"; 14808 case kAllocationSiteTenuringChangedGroup: 14809 return "allocation-site-tenuring-changed"; 14810 case kAllocationSiteTransitionChangedGroup: 14811 return "allocation-site-transition-changed"; 14812 } 14813 UNREACHABLE(); 14814 return "?"; 14815 } 14816 14817 14818 Handle<Map> Map::TransitionToPrototype(Handle<Map> map, 14819 Handle<Object> prototype, 14820 PrototypeOptimizationMode mode) { 14821 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype); 14822 if (new_map.is_null()) { 14823 new_map = Copy(map, "TransitionToPrototype"); 14824 TransitionArray::PutPrototypeTransition(map, prototype, new_map); 14825 Map::SetPrototype(new_map, prototype, mode); 14826 } 14827 return new_map; 14828 } 14829 14830 14831 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object, 14832 Handle<Object> value, bool from_javascript, 14833 ShouldThrow should_throw) { 14834 if (object->IsJSProxy()) { 14835 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value, 14836 from_javascript, should_throw); 14837 } 14838 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value, 14839 from_javascript, should_throw); 14840 } 14841 14842 14843 // ES6: 9.5.2 [[SetPrototypeOf]] (V) 14844 // static 14845 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value, 14846 bool from_javascript, 14847 ShouldThrow should_throw) { 14848 Isolate* isolate = proxy->GetIsolate(); 14849 STACK_CHECK(isolate, Nothing<bool>()); 14850 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string(); 14851 // 1. Assert: Either Type(V) is Object or Type(V) is Null. 14852 DCHECK(value->IsJSReceiver() || value->IsNull(isolate)); 14853 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 14854 Handle<Object> handler(proxy->handler(), isolate); 14855 // 3. If handler is null, throw a TypeError exception. 14856 // 4. Assert: Type(handler) is Object. 14857 if (proxy->IsRevoked()) { 14858 isolate->Throw(*isolate->factory()->NewTypeError( 14859 MessageTemplate::kProxyRevoked, trap_name)); 14860 return Nothing<bool>(); 14861 } 14862 // 5. Let target be the value of the [[ProxyTarget]] internal slot. 14863 Handle<JSReceiver> target(proxy->target(), isolate); 14864 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf"). 14865 Handle<Object> trap; 14866 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 14867 isolate, trap, 14868 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 14869 Nothing<bool>()); 14870 // 7. If trap is undefined, then return target.[[SetPrototypeOf]](). 14871 if (trap->IsUndefined(isolate)) { 14872 return JSReceiver::SetPrototype(target, value, from_javascript, 14873 should_throw); 14874 } 14875 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, target, V)). 14876 Handle<Object> argv[] = {target, value}; 14877 Handle<Object> trap_result; 14878 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 14879 isolate, trap_result, 14880 Execution::Call(isolate, trap, handler, arraysize(argv), argv), 14881 Nothing<bool>()); 14882 bool bool_trap_result = trap_result->BooleanValue(); 14883 // 9. If booleanTrapResult is false, return false. 14884 if (!bool_trap_result) { 14885 RETURN_FAILURE( 14886 isolate, should_throw, 14887 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 14888 } 14889 // 10. Let extensibleTarget be ? IsExtensible(target). 14890 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 14891 if (is_extensible.IsNothing()) return Nothing<bool>(); 14892 // 11. If extensibleTarget is true, return true. 14893 if (is_extensible.FromJust()) { 14894 if (bool_trap_result) return Just(true); 14895 RETURN_FAILURE( 14896 isolate, should_throw, 14897 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 14898 } 14899 // 12. Let targetProto be ? target.[[GetPrototypeOf]](). 14900 Handle<Object> target_proto; 14901 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto, 14902 JSReceiver::GetPrototype(isolate, target), 14903 Nothing<bool>()); 14904 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception. 14905 if (bool_trap_result && !value->SameValue(*target_proto)) { 14906 isolate->Throw(*isolate->factory()->NewTypeError( 14907 MessageTemplate::kProxySetPrototypeOfNonExtensible)); 14908 return Nothing<bool>(); 14909 } 14910 // 14. Return true. 14911 return Just(true); 14912 } 14913 14914 14915 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, 14916 Handle<Object> value, bool from_javascript, 14917 ShouldThrow should_throw) { 14918 Isolate* isolate = object->GetIsolate(); 14919 14920 #ifdef DEBUG 14921 int size = object->Size(); 14922 #endif 14923 14924 if (from_javascript) { 14925 if (object->IsAccessCheckNeeded() && 14926 !isolate->MayAccess(handle(isolate->context()), object)) { 14927 isolate->ReportFailedAccessCheck(object); 14928 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 14929 RETURN_FAILURE(isolate, should_throw, 14930 NewTypeError(MessageTemplate::kNoAccess)); 14931 } 14932 } else { 14933 DCHECK(!object->IsAccessCheckNeeded()); 14934 } 14935 14936 Heap* heap = isolate->heap(); 14937 // Silently ignore the change if value is not a JSObject or null. 14938 // SpiderMonkey behaves this way. 14939 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true); 14940 14941 bool dictionary_elements_in_chain = 14942 object->map()->DictionaryElementsInPrototypeChainOnly(); 14943 14944 bool all_extensible = object->map()->is_extensible(); 14945 Handle<JSObject> real_receiver = object; 14946 if (from_javascript) { 14947 // Find the first object in the chain whose prototype object is not 14948 // hidden. 14949 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, 14950 PrototypeIterator::END_AT_NON_HIDDEN); 14951 while (!iter.IsAtEnd()) { 14952 // Casting to JSObject is fine because hidden prototypes are never 14953 // JSProxies. 14954 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); 14955 iter.Advance(); 14956 all_extensible = all_extensible && real_receiver->map()->is_extensible(); 14957 } 14958 } 14959 Handle<Map> map(real_receiver->map()); 14960 14961 // Nothing to do if prototype is already set. 14962 if (map->prototype() == *value) return Just(true); 14963 14964 // From 8.6.2 Object Internal Methods 14965 // ... 14966 // In addition, if [[Extensible]] is false the value of the [[Class]] and 14967 // [[Prototype]] internal properties of the object may not be modified. 14968 // ... 14969 // Implementation specific extensions that modify [[Class]], [[Prototype]] 14970 // or [[Extensible]] must not violate the invariants defined in the preceding 14971 // paragraph. 14972 if (!all_extensible) { 14973 RETURN_FAILURE(isolate, should_throw, 14974 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); 14975 } 14976 14977 // Before we can set the prototype we need to be sure prototype cycles are 14978 // prevented. It is sufficient to validate that the receiver is not in the 14979 // new prototype chain. 14980 if (value->IsJSReceiver()) { 14981 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value), 14982 kStartAtReceiver); 14983 !iter.IsAtEnd(); iter.Advance()) { 14984 if (iter.GetCurrent<JSReceiver>() == *object) { 14985 // Cycle detected. 14986 RETURN_FAILURE(isolate, should_throw, 14987 NewTypeError(MessageTemplate::kCyclicProto)); 14988 } 14989 } 14990 } 14991 14992 // Set the new prototype of the object. 14993 14994 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); 14995 14996 PrototypeOptimizationMode mode = 14997 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; 14998 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); 14999 DCHECK(new_map->prototype() == *value); 15000 JSObject::MigrateToMap(real_receiver, new_map); 15001 15002 if (from_javascript && !dictionary_elements_in_chain && 15003 new_map->DictionaryElementsInPrototypeChainOnly()) { 15004 // If the prototype chain didn't previously have element callbacks, then 15005 // KeyedStoreICs need to be cleared to ensure any that involve this 15006 // map go generic. 15007 TypeFeedbackVector::ClearAllKeyedStoreICs(isolate); 15008 } 15009 15010 heap->ClearInstanceofCache(); 15011 DCHECK(size == object->Size()); 15012 return Just(true); 15013 } 15014 15015 15016 void JSObject::EnsureCanContainElements(Handle<JSObject> object, 15017 Arguments* args, 15018 uint32_t first_arg, 15019 uint32_t arg_count, 15020 EnsureElementsMode mode) { 15021 // Elements in |Arguments| are ordered backwards (because they're on the 15022 // stack), but the method that's called here iterates over them in forward 15023 // direction. 15024 return EnsureCanContainElements( 15025 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode); 15026 } 15027 15028 15029 ElementsAccessor* JSObject::GetElementsAccessor() { 15030 return ElementsAccessor::ForKind(GetElementsKind()); 15031 } 15032 15033 15034 void JSObject::ValidateElements(Handle<JSObject> object) { 15035 #ifdef ENABLE_SLOW_DCHECKS 15036 if (FLAG_enable_slow_asserts) { 15037 ElementsAccessor* accessor = object->GetElementsAccessor(); 15038 accessor->Validate(object); 15039 } 15040 #endif 15041 } 15042 15043 15044 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity, 15045 uint32_t index, 15046 uint32_t* new_capacity) { 15047 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <= 15048 JSObject::kMaxUncheckedFastElementsLength); 15049 if (index < capacity) { 15050 *new_capacity = capacity; 15051 return false; 15052 } 15053 if (index - capacity >= JSObject::kMaxGap) return true; 15054 *new_capacity = JSObject::NewElementsCapacity(index + 1); 15055 DCHECK_LT(index, *new_capacity); 15056 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength || 15057 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength && 15058 object->GetHeap()->InNewSpace(object))) { 15059 return false; 15060 } 15061 // If the fast-case backing storage takes up roughly three times as 15062 // much space (in machine words) as a dictionary backing storage 15063 // would, the object should have slow elements. 15064 int used_elements = object->GetFastElementsUsage(); 15065 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * 15066 SeededNumberDictionary::kEntrySize; 15067 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; 15068 } 15069 15070 15071 bool JSObject::WouldConvertToSlowElements(uint32_t index) { 15072 if (HasFastElements()) { 15073 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); 15074 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); 15075 uint32_t new_capacity; 15076 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity); 15077 } 15078 return false; 15079 } 15080 15081 15082 static ElementsKind BestFittingFastElementsKind(JSObject* object) { 15083 if (object->HasSloppyArgumentsElements()) { 15084 return FAST_SLOPPY_ARGUMENTS_ELEMENTS; 15085 } 15086 if (object->HasStringWrapperElements()) { 15087 return FAST_STRING_WRAPPER_ELEMENTS; 15088 } 15089 DCHECK(object->HasDictionaryElements()); 15090 SeededNumberDictionary* dictionary = object->element_dictionary(); 15091 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; 15092 for (int i = 0; i < dictionary->Capacity(); i++) { 15093 Object* key = dictionary->KeyAt(i); 15094 if (key->IsNumber()) { 15095 Object* value = dictionary->ValueAt(i); 15096 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; 15097 if (!value->IsSmi()) { 15098 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; 15099 kind = FAST_HOLEY_DOUBLE_ELEMENTS; 15100 } 15101 } 15102 } 15103 return kind; 15104 } 15105 15106 15107 static bool ShouldConvertToFastElements(JSObject* object, 15108 SeededNumberDictionary* dictionary, 15109 uint32_t index, 15110 uint32_t* new_capacity) { 15111 // If properties with non-standard attributes or accessors were added, we 15112 // cannot go back to fast elements. 15113 if (dictionary->requires_slow_elements()) return false; 15114 15115 // Adding a property with this index will require slow elements. 15116 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false; 15117 15118 if (object->IsJSArray()) { 15119 Object* length = JSArray::cast(object)->length(); 15120 if (!length->IsSmi()) return false; 15121 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value()); 15122 } else { 15123 *new_capacity = dictionary->max_number_key() + 1; 15124 } 15125 *new_capacity = Max(index + 1, *new_capacity); 15126 15127 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * 15128 SeededNumberDictionary::kEntrySize; 15129 15130 // Turn fast if the dictionary only saves 50% space. 15131 return 2 * dictionary_size >= *new_capacity; 15132 } 15133 15134 15135 // static 15136 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object, 15137 uint32_t index, 15138 Handle<Object> value, 15139 PropertyAttributes attributes) { 15140 MAYBE_RETURN_NULL( 15141 AddDataElement(object, index, value, attributes, THROW_ON_ERROR)); 15142 return value; 15143 } 15144 15145 15146 // static 15147 Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index, 15148 Handle<Object> value, 15149 PropertyAttributes attributes, 15150 ShouldThrow should_throw) { 15151 DCHECK(object->map()->is_extensible()); 15152 15153 Isolate* isolate = object->GetIsolate(); 15154 15155 uint32_t old_length = 0; 15156 uint32_t new_capacity = 0; 15157 15158 if (object->IsJSArray()) { 15159 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); 15160 } 15161 15162 ElementsKind kind = object->GetElementsKind(); 15163 FixedArrayBase* elements = object->elements(); 15164 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; 15165 if (IsSloppyArgumentsElements(kind)) { 15166 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); 15167 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; 15168 } else if (IsStringWrapperElementsKind(kind)) { 15169 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS; 15170 } 15171 15172 if (attributes != NONE) { 15173 kind = dictionary_kind; 15174 } else if (elements->IsSeededNumberDictionary()) { 15175 kind = ShouldConvertToFastElements(*object, 15176 SeededNumberDictionary::cast(elements), 15177 index, &new_capacity) 15178 ? BestFittingFastElementsKind(*object) 15179 : dictionary_kind; // Overwrite in case of arguments. 15180 } else if (ShouldConvertToSlowElements( 15181 *object, static_cast<uint32_t>(elements->length()), index, 15182 &new_capacity)) { 15183 kind = dictionary_kind; 15184 } 15185 15186 ElementsKind to = value->OptimalElementsKind(); 15187 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) { 15188 to = GetHoleyElementsKind(to); 15189 kind = GetHoleyElementsKind(kind); 15190 } 15191 to = GetMoreGeneralElementsKind(kind, to); 15192 ElementsAccessor* accessor = ElementsAccessor::ForKind(to); 15193 accessor->Add(object, index, value, attributes, new_capacity); 15194 15195 uint32_t new_length = old_length; 15196 Handle<Object> new_length_handle; 15197 if (object->IsJSArray() && index >= old_length) { 15198 new_length = index + 1; 15199 new_length_handle = isolate->factory()->NewNumberFromUint(new_length); 15200 JSArray::cast(*object)->set_length(*new_length_handle); 15201 } 15202 15203 return Just(true); 15204 } 15205 15206 15207 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) { 15208 if (!HasFastElements()) return false; 15209 uint32_t capacity = static_cast<uint32_t>(elements()->length()); 15210 uint32_t new_capacity; 15211 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) && 15212 ShouldConvertToSlowElements(this, capacity, new_length - 1, 15213 &new_capacity); 15214 } 15215 15216 15217 const double AllocationSite::kPretenureRatio = 0.85; 15218 15219 15220 void AllocationSite::ResetPretenureDecision() { 15221 set_pretenure_decision(kUndecided); 15222 set_memento_found_count(0); 15223 set_memento_create_count(0); 15224 } 15225 15226 15227 PretenureFlag AllocationSite::GetPretenureMode() { 15228 PretenureDecision mode = pretenure_decision(); 15229 // Zombie objects "decide" to be untenured. 15230 return mode == kTenure ? TENURED : NOT_TENURED; 15231 } 15232 15233 15234 bool AllocationSite::IsNestedSite() { 15235 DCHECK(FLAG_trace_track_allocation_sites); 15236 Object* current = GetHeap()->allocation_sites_list(); 15237 while (current->IsAllocationSite()) { 15238 AllocationSite* current_site = AllocationSite::cast(current); 15239 if (current_site->nested_site() == this) { 15240 return true; 15241 } 15242 current = current_site->weak_next(); 15243 } 15244 return false; 15245 } 15246 15247 15248 void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site, 15249 ElementsKind to_kind) { 15250 Isolate* isolate = site->GetIsolate(); 15251 15252 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) { 15253 Handle<JSArray> transition_info = 15254 handle(JSArray::cast(site->transition_info())); 15255 ElementsKind kind = transition_info->GetElementsKind(); 15256 // if kind is holey ensure that to_kind is as well. 15257 if (IsHoleyElementsKind(kind)) { 15258 to_kind = GetHoleyElementsKind(to_kind); 15259 } 15260 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { 15261 // If the array is huge, it's not likely to be defined in a local 15262 // function, so we shouldn't make new instances of it very often. 15263 uint32_t length = 0; 15264 CHECK(transition_info->length()->ToArrayLength(&length)); 15265 if (length <= kMaximumArrayBytesToPretransition) { 15266 if (FLAG_trace_track_allocation_sites) { 15267 bool is_nested = site->IsNestedSite(); 15268 PrintF( 15269 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", 15270 reinterpret_cast<void*>(*site), 15271 is_nested ? "(nested)" : "", 15272 ElementsKindToString(kind), 15273 ElementsKindToString(to_kind)); 15274 } 15275 JSObject::TransitionElementsKind(transition_info, to_kind); 15276 site->dependent_code()->DeoptimizeDependentCodeGroup( 15277 isolate, DependentCode::kAllocationSiteTransitionChangedGroup); 15278 } 15279 } 15280 } else { 15281 ElementsKind kind = site->GetElementsKind(); 15282 // if kind is holey ensure that to_kind is as well. 15283 if (IsHoleyElementsKind(kind)) { 15284 to_kind = GetHoleyElementsKind(to_kind); 15285 } 15286 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { 15287 if (FLAG_trace_track_allocation_sites) { 15288 PrintF("AllocationSite: JSArray %p site updated %s->%s\n", 15289 reinterpret_cast<void*>(*site), 15290 ElementsKindToString(kind), 15291 ElementsKindToString(to_kind)); 15292 } 15293 site->SetElementsKind(to_kind); 15294 site->dependent_code()->DeoptimizeDependentCodeGroup( 15295 isolate, DependentCode::kAllocationSiteTransitionChangedGroup); 15296 } 15297 } 15298 } 15299 15300 15301 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) { 15302 switch (decision) { 15303 case kUndecided: return "undecided"; 15304 case kDontTenure: return "don't tenure"; 15305 case kMaybeTenure: return "maybe tenure"; 15306 case kTenure: return "tenure"; 15307 case kZombie: return "zombie"; 15308 default: UNREACHABLE(); 15309 } 15310 return NULL; 15311 } 15312 15313 15314 void JSObject::UpdateAllocationSite(Handle<JSObject> object, 15315 ElementsKind to_kind) { 15316 if (!object->IsJSArray()) return; 15317 15318 Heap* heap = object->GetHeap(); 15319 if (!heap->InNewSpace(*object)) return; 15320 15321 Handle<AllocationSite> site; 15322 { 15323 DisallowHeapAllocation no_allocation; 15324 15325 AllocationMemento* memento = 15326 heap->FindAllocationMemento<Heap::kForRuntime>(*object); 15327 if (memento == NULL) return; 15328 15329 // Walk through to the Allocation Site 15330 site = handle(memento->GetAllocationSite()); 15331 } 15332 AllocationSite::DigestTransitionFeedback(site, to_kind); 15333 } 15334 15335 15336 void JSObject::TransitionElementsKind(Handle<JSObject> object, 15337 ElementsKind to_kind) { 15338 ElementsKind from_kind = object->GetElementsKind(); 15339 15340 if (IsFastHoleyElementsKind(from_kind)) { 15341 to_kind = GetHoleyElementsKind(to_kind); 15342 } 15343 15344 if (from_kind == to_kind) return; 15345 15346 // This method should never be called for any other case. 15347 DCHECK(IsFastElementsKind(from_kind)); 15348 DCHECK(IsFastElementsKind(to_kind)); 15349 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); 15350 15351 UpdateAllocationSite(object, to_kind); 15352 if (object->elements() == object->GetHeap()->empty_fixed_array() || 15353 IsFastDoubleElementsKind(from_kind) == 15354 IsFastDoubleElementsKind(to_kind)) { 15355 // No change is needed to the elements() buffer, the transition 15356 // only requires a map change. 15357 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); 15358 MigrateToMap(object, new_map); 15359 if (FLAG_trace_elements_transitions) { 15360 Handle<FixedArrayBase> elms(object->elements()); 15361 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); 15362 } 15363 } else { 15364 DCHECK((IsFastSmiElementsKind(from_kind) && 15365 IsFastDoubleElementsKind(to_kind)) || 15366 (IsFastDoubleElementsKind(from_kind) && 15367 IsFastObjectElementsKind(to_kind))); 15368 uint32_t c = static_cast<uint32_t>(object->elements()->length()); 15369 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c); 15370 } 15371 } 15372 15373 15374 // static 15375 bool Map::IsValidElementsTransition(ElementsKind from_kind, 15376 ElementsKind to_kind) { 15377 // Transitions can't go backwards. 15378 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { 15379 return false; 15380 } 15381 15382 // Transitions from HOLEY -> PACKED are not allowed. 15383 return !IsFastHoleyElementsKind(from_kind) || 15384 IsFastHoleyElementsKind(to_kind); 15385 } 15386 15387 15388 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { 15389 Map* map = array->map(); 15390 // Fast path: "length" is the first fast property of arrays. Since it's not 15391 // configurable, it's guaranteed to be the first in the descriptor array. 15392 if (!map->is_dictionary_map()) { 15393 DCHECK(map->instance_descriptors()->GetKey(0) == 15394 array->GetHeap()->length_string()); 15395 return map->instance_descriptors()->GetDetails(0).IsReadOnly(); 15396 } 15397 15398 Isolate* isolate = array->GetIsolate(); 15399 LookupIterator it(array, isolate->factory()->length_string(), array, 15400 LookupIterator::OWN_SKIP_INTERCEPTOR); 15401 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); 15402 return it.IsReadOnly(); 15403 } 15404 15405 15406 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, 15407 uint32_t index) { 15408 uint32_t length = 0; 15409 CHECK(array->length()->ToArrayLength(&length)); 15410 if (length <= index) return HasReadOnlyLength(array); 15411 return false; 15412 } 15413 15414 15415 template <typename BackingStore> 15416 static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) { 15417 int limit = object->IsJSArray() 15418 ? Smi::cast(JSArray::cast(object)->length())->value() 15419 : store->length(); 15420 int used = 0; 15421 for (int i = 0; i < limit; ++i) { 15422 if (!store->is_the_hole(i)) ++used; 15423 } 15424 return used; 15425 } 15426 15427 15428 int JSObject::GetFastElementsUsage() { 15429 FixedArrayBase* store = elements(); 15430 switch (GetElementsKind()) { 15431 case FAST_SMI_ELEMENTS: 15432 case FAST_DOUBLE_ELEMENTS: 15433 case FAST_ELEMENTS: 15434 return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value() 15435 : store->length(); 15436 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 15437 store = FixedArray::cast(FixedArray::cast(store)->get(1)); 15438 // Fall through. 15439 case FAST_HOLEY_SMI_ELEMENTS: 15440 case FAST_HOLEY_ELEMENTS: 15441 case FAST_STRING_WRAPPER_ELEMENTS: 15442 return FastHoleyElementsUsage(this, FixedArray::cast(store)); 15443 case FAST_HOLEY_DOUBLE_ELEMENTS: 15444 if (elements()->length() == 0) return 0; 15445 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store)); 15446 15447 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 15448 case SLOW_STRING_WRAPPER_ELEMENTS: 15449 case DICTIONARY_ELEMENTS: 15450 case NO_ELEMENTS: 15451 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 15452 case TYPE##_ELEMENTS: \ 15453 15454 TYPED_ARRAYS(TYPED_ARRAY_CASE) 15455 #undef TYPED_ARRAY_CASE 15456 UNREACHABLE(); 15457 } 15458 return 0; 15459 } 15460 15461 15462 // Certain compilers request function template instantiation when they 15463 // see the definition of the other template functions in the 15464 // class. This requires us to have the template functions put 15465 // together, so even though this function belongs in objects-debug.cc, 15466 // we keep it here instead to satisfy certain compilers. 15467 #ifdef OBJECT_PRINT 15468 template <typename Derived, typename Shape, typename Key> 15469 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT 15470 Isolate* isolate = this->GetIsolate(); 15471 int capacity = this->Capacity(); 15472 for (int i = 0; i < capacity; i++) { 15473 Object* k = this->KeyAt(i); 15474 if (this->IsKey(isolate, k)) { 15475 os << "\n "; 15476 if (k->IsString()) { 15477 String::cast(k)->StringPrint(os); 15478 } else { 15479 os << Brief(k); 15480 } 15481 os << ": " << Brief(this->ValueAt(i)) << " " << this->DetailsAt(i); 15482 } 15483 } 15484 } 15485 template <typename Derived, typename Shape, typename Key> 15486 void Dictionary<Derived, Shape, Key>::Print() { 15487 OFStream os(stdout); 15488 Print(os); 15489 } 15490 #endif 15491 15492 15493 template<typename Derived, typename Shape, typename Key> 15494 void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) { 15495 Isolate* isolate = this->GetIsolate(); 15496 int pos = 0; 15497 int capacity = this->Capacity(); 15498 DisallowHeapAllocation no_gc; 15499 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 15500 for (int i = 0; i < capacity; i++) { 15501 Object* k = this->KeyAt(i); 15502 if (this->IsKey(isolate, k)) { 15503 elements->set(pos++, this->ValueAt(i), mode); 15504 } 15505 } 15506 DCHECK(pos == elements->length()); 15507 } 15508 15509 15510 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it, 15511 bool* done) { 15512 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 15513 return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done); 15514 } 15515 15516 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object, 15517 Handle<Name> name) { 15518 LookupIterator it = LookupIterator::PropertyOrElement( 15519 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 15520 return HasProperty(&it); 15521 } 15522 15523 15524 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object, 15525 uint32_t index) { 15526 Isolate* isolate = object->GetIsolate(); 15527 LookupIterator it(isolate, object, index, object, 15528 LookupIterator::OWN_SKIP_INTERCEPTOR); 15529 return HasProperty(&it); 15530 } 15531 15532 15533 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object, 15534 Handle<Name> name) { 15535 LookupIterator it = LookupIterator::PropertyOrElement( 15536 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 15537 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it); 15538 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR) 15539 : Nothing<bool>(); 15540 } 15541 15542 15543 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) { 15544 Object* temp = get(i); 15545 set(i, get(j)); 15546 set(j, temp); 15547 if (this != numbers) { 15548 temp = numbers->get(i); 15549 numbers->set(i, Smi::cast(numbers->get(j))); 15550 numbers->set(j, Smi::cast(temp)); 15551 } 15552 } 15553 15554 15555 static void InsertionSortPairs(FixedArray* content, 15556 FixedArray* numbers, 15557 int len) { 15558 for (int i = 1; i < len; i++) { 15559 int j = i; 15560 while (j > 0 && 15561 (NumberToUint32(numbers->get(j - 1)) > 15562 NumberToUint32(numbers->get(j)))) { 15563 content->SwapPairs(numbers, j - 1, j); 15564 j--; 15565 } 15566 } 15567 } 15568 15569 15570 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) { 15571 // In-place heap sort. 15572 DCHECK(content->length() == numbers->length()); 15573 15574 // Bottom-up max-heap construction. 15575 for (int i = 1; i < len; ++i) { 15576 int child_index = i; 15577 while (child_index > 0) { 15578 int parent_index = ((child_index + 1) >> 1) - 1; 15579 uint32_t parent_value = NumberToUint32(numbers->get(parent_index)); 15580 uint32_t child_value = NumberToUint32(numbers->get(child_index)); 15581 if (parent_value < child_value) { 15582 content->SwapPairs(numbers, parent_index, child_index); 15583 } else { 15584 break; 15585 } 15586 child_index = parent_index; 15587 } 15588 } 15589 15590 // Extract elements and create sorted array. 15591 for (int i = len - 1; i > 0; --i) { 15592 // Put max element at the back of the array. 15593 content->SwapPairs(numbers, 0, i); 15594 // Sift down the new top element. 15595 int parent_index = 0; 15596 while (true) { 15597 int child_index = ((parent_index + 1) << 1) - 1; 15598 if (child_index >= i) break; 15599 uint32_t child1_value = NumberToUint32(numbers->get(child_index)); 15600 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1)); 15601 uint32_t parent_value = NumberToUint32(numbers->get(parent_index)); 15602 if (child_index + 1 >= i || child1_value > child2_value) { 15603 if (parent_value > child1_value) break; 15604 content->SwapPairs(numbers, parent_index, child_index); 15605 parent_index = child_index; 15606 } else { 15607 if (parent_value > child2_value) break; 15608 content->SwapPairs(numbers, parent_index, child_index + 1); 15609 parent_index = child_index + 1; 15610 } 15611 } 15612 } 15613 } 15614 15615 15616 // Sort this array and the numbers as pairs wrt. the (distinct) numbers. 15617 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) { 15618 DCHECK(this->length() == numbers->length()); 15619 // For small arrays, simply use insertion sort. 15620 if (len <= 10) { 15621 InsertionSortPairs(this, numbers, len); 15622 return; 15623 } 15624 // Check the range of indices. 15625 uint32_t min_index = NumberToUint32(numbers->get(0)); 15626 uint32_t max_index = min_index; 15627 uint32_t i; 15628 for (i = 1; i < len; i++) { 15629 if (NumberToUint32(numbers->get(i)) < min_index) { 15630 min_index = NumberToUint32(numbers->get(i)); 15631 } else if (NumberToUint32(numbers->get(i)) > max_index) { 15632 max_index = NumberToUint32(numbers->get(i)); 15633 } 15634 } 15635 if (max_index - min_index + 1 == len) { 15636 // Indices form a contiguous range, unless there are duplicates. 15637 // Do an in-place linear time sort assuming distinct numbers, but 15638 // avoid hanging in case they are not. 15639 for (i = 0; i < len; i++) { 15640 uint32_t p; 15641 uint32_t j = 0; 15642 // While the current element at i is not at its correct position p, 15643 // swap the elements at these two positions. 15644 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i && 15645 j++ < len) { 15646 SwapPairs(numbers, i, p); 15647 } 15648 } 15649 } else { 15650 HeapSortPairs(this, numbers, len); 15651 return; 15652 } 15653 } 15654 15655 bool JSObject::WasConstructedFromApiFunction() { 15656 auto instance_type = map()->instance_type(); 15657 bool is_api_object = instance_type == JS_API_OBJECT_TYPE || 15658 instance_type == JS_SPECIAL_API_OBJECT_TYPE; 15659 #ifdef ENABLE_SLOW_DCHECKS 15660 if (FLAG_enable_slow_asserts) { 15661 Object* maybe_constructor = map()->GetConstructor(); 15662 if (!maybe_constructor->IsJSFunction()) return false; 15663 JSFunction* constructor = JSFunction::cast(maybe_constructor); 15664 if (constructor->shared()->IsApiFunction()) { 15665 DCHECK(is_api_object); 15666 } else { 15667 DCHECK(!is_api_object); 15668 } 15669 } 15670 #endif 15671 return is_api_object; 15672 } 15673 15674 MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate, 15675 Handle<Object> object) { 15676 if (*object == isolate->heap()->undefined_value()) { 15677 return isolate->factory()->undefined_to_string(); 15678 } 15679 if (*object == isolate->heap()->null_value()) { 15680 return isolate->factory()->null_to_string(); 15681 } 15682 15683 Handle<JSReceiver> receiver = 15684 Object::ToObject(isolate, object).ToHandleChecked(); 15685 15686 // For proxies, we must check IsArray() before get(toStringTag) to comply 15687 // with the specification 15688 Maybe<bool> is_array = Nothing<bool>(); 15689 InstanceType instance_type = receiver->map()->instance_type(); 15690 if (instance_type == JS_PROXY_TYPE) { 15691 is_array = Object::IsArray(receiver); 15692 MAYBE_RETURN(is_array, MaybeHandle<String>()); 15693 } 15694 15695 Handle<String> tag; 15696 Handle<Object> to_string_tag; 15697 ASSIGN_RETURN_ON_EXCEPTION( 15698 isolate, to_string_tag, 15699 JSReceiver::GetProperty(receiver, 15700 isolate->factory()->to_string_tag_symbol()), 15701 String); 15702 if (to_string_tag->IsString()) { 15703 tag = Handle<String>::cast(to_string_tag); 15704 } else { 15705 switch (instance_type) { 15706 case JS_API_OBJECT_TYPE: 15707 case JS_SPECIAL_API_OBJECT_TYPE: 15708 tag = handle(receiver->class_name(), isolate); 15709 break; 15710 case JS_ARGUMENTS_TYPE: 15711 return isolate->factory()->arguments_to_string(); 15712 case JS_ARRAY_TYPE: 15713 return isolate->factory()->array_to_string(); 15714 case JS_BOUND_FUNCTION_TYPE: 15715 case JS_FUNCTION_TYPE: 15716 return isolate->factory()->function_to_string(); 15717 case JS_ERROR_TYPE: 15718 return isolate->factory()->error_to_string(); 15719 case JS_DATE_TYPE: 15720 return isolate->factory()->date_to_string(); 15721 case JS_REGEXP_TYPE: 15722 return isolate->factory()->regexp_to_string(); 15723 case JS_PROXY_TYPE: { 15724 if (is_array.FromJust()) { 15725 return isolate->factory()->array_to_string(); 15726 } 15727 if (receiver->IsCallable()) { 15728 return isolate->factory()->function_to_string(); 15729 } 15730 return isolate->factory()->object_to_string(); 15731 } 15732 case JS_VALUE_TYPE: { 15733 Object* value = JSValue::cast(*receiver)->value(); 15734 if (value->IsString()) { 15735 return isolate->factory()->string_to_string(); 15736 } 15737 if (value->IsNumber()) { 15738 return isolate->factory()->number_to_string(); 15739 } 15740 if (value->IsBoolean()) { 15741 return isolate->factory()->boolean_to_string(); 15742 } 15743 if (value->IsSymbol()) { 15744 return isolate->factory()->object_to_string(); 15745 } 15746 UNREACHABLE(); 15747 tag = handle(receiver->class_name(), isolate); 15748 break; 15749 } 15750 default: 15751 return isolate->factory()->object_to_string(); 15752 } 15753 } 15754 15755 IncrementalStringBuilder builder(isolate); 15756 builder.AppendCString("[object "); 15757 builder.AppendString(tag); 15758 builder.AppendCharacter(']'); 15759 return builder.Finish(); 15760 } 15761 15762 const char* Symbol::PrivateSymbolToName() const { 15763 Heap* heap = GetIsolate()->heap(); 15764 #define SYMBOL_CHECK_AND_PRINT(name) \ 15765 if (this == heap->name()) return #name; 15766 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT) 15767 #undef SYMBOL_CHECK_AND_PRINT 15768 return "UNKNOWN"; 15769 } 15770 15771 15772 void Symbol::SymbolShortPrint(std::ostream& os) { 15773 os << "<Symbol:"; 15774 if (!name()->IsUndefined(GetIsolate())) { 15775 os << " "; 15776 HeapStringAllocator allocator; 15777 StringStream accumulator(&allocator); 15778 String::cast(name())->StringShortPrint(&accumulator, false); 15779 os << accumulator.ToCString().get(); 15780 } else { 15781 os << " (" << PrivateSymbolToName() << ")"; 15782 } 15783 os << ">"; 15784 } 15785 15786 15787 // StringSharedKeys are used as keys in the eval cache. 15788 class StringSharedKey : public HashTableKey { 15789 public: 15790 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared, 15791 LanguageMode language_mode, int scope_position) 15792 : source_(source), 15793 shared_(shared), 15794 language_mode_(language_mode), 15795 scope_position_(scope_position) {} 15796 15797 bool IsMatch(Object* other) override { 15798 DisallowHeapAllocation no_allocation; 15799 if (!other->IsFixedArray()) { 15800 if (!other->IsNumber()) return false; 15801 uint32_t other_hash = static_cast<uint32_t>(other->Number()); 15802 return Hash() == other_hash; 15803 } 15804 FixedArray* other_array = FixedArray::cast(other); 15805 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0)); 15806 if (shared != *shared_) return false; 15807 int language_unchecked = Smi::cast(other_array->get(2))->value(); 15808 DCHECK(is_valid_language_mode(language_unchecked)); 15809 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked); 15810 if (language_mode != language_mode_) return false; 15811 int scope_position = Smi::cast(other_array->get(3))->value(); 15812 if (scope_position != scope_position_) return false; 15813 String* source = String::cast(other_array->get(1)); 15814 return source->Equals(*source_); 15815 } 15816 15817 static uint32_t StringSharedHashHelper(String* source, 15818 SharedFunctionInfo* shared, 15819 LanguageMode language_mode, 15820 int scope_position) { 15821 uint32_t hash = source->Hash(); 15822 if (shared->HasSourceCode()) { 15823 // Instead of using the SharedFunctionInfo pointer in the hash 15824 // code computation, we use a combination of the hash of the 15825 // script source code and the start position of the calling scope. 15826 // We do this to ensure that the cache entries can survive garbage 15827 // collection. 15828 Script* script(Script::cast(shared->script())); 15829 hash ^= String::cast(script->source())->Hash(); 15830 STATIC_ASSERT(LANGUAGE_END == 3); 15831 if (is_strict(language_mode)) hash ^= 0x8000; 15832 hash += scope_position; 15833 } 15834 return hash; 15835 } 15836 15837 uint32_t Hash() override { 15838 return StringSharedHashHelper(*source_, *shared_, language_mode_, 15839 scope_position_); 15840 } 15841 15842 uint32_t HashForObject(Object* obj) override { 15843 DisallowHeapAllocation no_allocation; 15844 if (obj->IsNumber()) { 15845 return static_cast<uint32_t>(obj->Number()); 15846 } 15847 FixedArray* other_array = FixedArray::cast(obj); 15848 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0)); 15849 String* source = String::cast(other_array->get(1)); 15850 int language_unchecked = Smi::cast(other_array->get(2))->value(); 15851 DCHECK(is_valid_language_mode(language_unchecked)); 15852 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked); 15853 int scope_position = Smi::cast(other_array->get(3))->value(); 15854 return StringSharedHashHelper(source, shared, language_mode, 15855 scope_position); 15856 } 15857 15858 15859 Handle<Object> AsHandle(Isolate* isolate) override { 15860 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4); 15861 array->set(0, *shared_); 15862 array->set(1, *source_); 15863 array->set(2, Smi::FromInt(language_mode_)); 15864 array->set(3, Smi::FromInt(scope_position_)); 15865 return array; 15866 } 15867 15868 private: 15869 Handle<String> source_; 15870 Handle<SharedFunctionInfo> shared_; 15871 LanguageMode language_mode_; 15872 int scope_position_; 15873 }; 15874 15875 15876 namespace { 15877 15878 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) { 15879 JSRegExp::Flags value = JSRegExp::kNone; 15880 int length = flags->length(); 15881 // A longer flags string cannot be valid. 15882 if (length > 5) return JSRegExp::Flags(0); 15883 for (int i = 0; i < length; i++) { 15884 JSRegExp::Flag flag = JSRegExp::kNone; 15885 switch (flags->Get(i)) { 15886 case 'g': 15887 flag = JSRegExp::kGlobal; 15888 break; 15889 case 'i': 15890 flag = JSRegExp::kIgnoreCase; 15891 break; 15892 case 'm': 15893 flag = JSRegExp::kMultiline; 15894 break; 15895 case 'u': 15896 flag = JSRegExp::kUnicode; 15897 break; 15898 case 'y': 15899 flag = JSRegExp::kSticky; 15900 break; 15901 default: 15902 return JSRegExp::Flags(0); 15903 } 15904 // Duplicate flag. 15905 if (value & flag) return JSRegExp::Flags(0); 15906 value |= flag; 15907 } 15908 *success = true; 15909 return value; 15910 } 15911 15912 } // namespace 15913 15914 15915 // static 15916 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) { 15917 Isolate* isolate = pattern->GetIsolate(); 15918 Handle<JSFunction> constructor = isolate->regexp_function(); 15919 Handle<JSRegExp> regexp = 15920 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor)); 15921 15922 return JSRegExp::Initialize(regexp, pattern, flags); 15923 } 15924 15925 15926 // static 15927 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) { 15928 Isolate* const isolate = regexp->GetIsolate(); 15929 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp)); 15930 } 15931 15932 15933 template <typename Char> 15934 inline int CountRequiredEscapes(Handle<String> source) { 15935 DisallowHeapAllocation no_gc; 15936 int escapes = 0; 15937 Vector<const Char> src = source->GetCharVector<Char>(); 15938 for (int i = 0; i < src.length(); i++) { 15939 if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++; 15940 } 15941 return escapes; 15942 } 15943 15944 15945 template <typename Char, typename StringType> 15946 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, 15947 Handle<StringType> result) { 15948 DisallowHeapAllocation no_gc; 15949 Vector<const Char> src = source->GetCharVector<Char>(); 15950 Vector<Char> dst(result->GetChars(), result->length()); 15951 int s = 0; 15952 int d = 0; 15953 while (s < src.length()) { 15954 if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\'; 15955 dst[d++] = src[s++]; 15956 } 15957 DCHECK_EQ(result->length(), d); 15958 return result; 15959 } 15960 15961 15962 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate, 15963 Handle<String> source) { 15964 String::Flatten(source); 15965 if (source->length() == 0) return isolate->factory()->query_colon_string(); 15966 bool one_byte = source->IsOneByteRepresentationUnderneath(); 15967 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source) 15968 : CountRequiredEscapes<uc16>(source); 15969 if (escapes == 0) return source; 15970 int length = source->length() + escapes; 15971 if (one_byte) { 15972 Handle<SeqOneByteString> result; 15973 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 15974 isolate->factory()->NewRawOneByteString(length), 15975 String); 15976 return WriteEscapedRegExpSource<uint8_t>(source, result); 15977 } else { 15978 Handle<SeqTwoByteString> result; 15979 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 15980 isolate->factory()->NewRawTwoByteString(length), 15981 String); 15982 return WriteEscapedRegExpSource<uc16>(source, result); 15983 } 15984 } 15985 15986 15987 // static 15988 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, 15989 Handle<String> source, 15990 Handle<String> flags_string) { 15991 Isolate* isolate = source->GetIsolate(); 15992 bool success = false; 15993 Flags flags = RegExpFlagsFromString(flags_string, &success); 15994 if (!success) { 15995 THROW_NEW_ERROR( 15996 isolate, 15997 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string), 15998 JSRegExp); 15999 } 16000 return Initialize(regexp, source, flags); 16001 } 16002 16003 16004 // static 16005 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, 16006 Handle<String> source, Flags flags) { 16007 Isolate* isolate = regexp->GetIsolate(); 16008 Factory* factory = isolate->factory(); 16009 // If source is the empty string we set it to "(?:)" instead as 16010 // suggested by ECMA-262, 5th, section 15.10.4.1. 16011 if (source->length() == 0) source = factory->query_colon_string(); 16012 16013 Handle<String> escaped_source; 16014 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source, 16015 EscapeRegExpSource(isolate, source), JSRegExp); 16016 16017 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags), 16018 JSRegExp); 16019 16020 regexp->set_source(*escaped_source); 16021 regexp->set_flags(Smi::FromInt(flags)); 16022 16023 Map* map = regexp->map(); 16024 Object* constructor = map->GetConstructor(); 16025 if (constructor->IsJSFunction() && 16026 JSFunction::cast(constructor)->initial_map() == map) { 16027 // If we still have the original map, set in-object properties directly. 16028 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, 16029 Smi::FromInt(0), SKIP_WRITE_BARRIER); 16030 } else { 16031 // Map has changed, so use generic, but slower, method. 16032 PropertyAttributes writable = 16033 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); 16034 JSObject::SetOwnPropertyIgnoreAttributes( 16035 regexp, factory->last_index_string(), 16036 Handle<Smi>(Smi::FromInt(0), isolate), writable) 16037 .Check(); 16038 } 16039 16040 return regexp; 16041 } 16042 16043 16044 // RegExpKey carries the source and flags of a regular expression as key. 16045 class RegExpKey : public HashTableKey { 16046 public: 16047 RegExpKey(Handle<String> string, JSRegExp::Flags flags) 16048 : string_(string), flags_(Smi::FromInt(flags)) {} 16049 16050 // Rather than storing the key in the hash table, a pointer to the 16051 // stored value is stored where the key should be. IsMatch then 16052 // compares the search key to the found object, rather than comparing 16053 // a key to a key. 16054 bool IsMatch(Object* obj) override { 16055 FixedArray* val = FixedArray::cast(obj); 16056 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex))) 16057 && (flags_ == val->get(JSRegExp::kFlagsIndex)); 16058 } 16059 16060 uint32_t Hash() override { return RegExpHash(*string_, flags_); } 16061 16062 Handle<Object> AsHandle(Isolate* isolate) override { 16063 // Plain hash maps, which is where regexp keys are used, don't 16064 // use this function. 16065 UNREACHABLE(); 16066 return MaybeHandle<Object>().ToHandleChecked(); 16067 } 16068 16069 uint32_t HashForObject(Object* obj) override { 16070 FixedArray* val = FixedArray::cast(obj); 16071 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)), 16072 Smi::cast(val->get(JSRegExp::kFlagsIndex))); 16073 } 16074 16075 static uint32_t RegExpHash(String* string, Smi* flags) { 16076 return string->Hash() + flags->value(); 16077 } 16078 16079 Handle<String> string_; 16080 Smi* flags_; 16081 }; 16082 16083 16084 Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) { 16085 if (hash_field_ == 0) Hash(); 16086 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_); 16087 } 16088 16089 16090 Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) { 16091 if (hash_field_ == 0) Hash(); 16092 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_); 16093 } 16094 16095 16096 Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) { 16097 if (hash_field_ == 0) Hash(); 16098 return isolate->factory()->NewOneByteInternalizedSubString( 16099 string_, from_, length_, hash_field_); 16100 } 16101 16102 16103 bool SeqOneByteSubStringKey::IsMatch(Object* string) { 16104 Vector<const uint8_t> chars(string_->GetChars() + from_, length_); 16105 return String::cast(string)->IsOneByteEqualTo(chars); 16106 } 16107 16108 16109 // InternalizedStringKey carries a string/internalized-string object as key. 16110 class InternalizedStringKey : public HashTableKey { 16111 public: 16112 explicit InternalizedStringKey(Handle<String> string) 16113 : string_(String::Flatten(string)) {} 16114 16115 bool IsMatch(Object* string) override { 16116 return String::cast(string)->Equals(*string_); 16117 } 16118 16119 uint32_t Hash() override { return string_->Hash(); } 16120 16121 uint32_t HashForObject(Object* other) override { 16122 return String::cast(other)->Hash(); 16123 } 16124 16125 Handle<Object> AsHandle(Isolate* isolate) override { 16126 // Internalize the string if possible. 16127 MaybeHandle<Map> maybe_map = 16128 isolate->factory()->InternalizedStringMapForString(string_); 16129 Handle<Map> map; 16130 if (maybe_map.ToHandle(&map)) { 16131 string_->set_map_no_write_barrier(*map); 16132 DCHECK(string_->IsInternalizedString()); 16133 return string_; 16134 } 16135 // Otherwise allocate a new internalized string. 16136 return isolate->factory()->NewInternalizedStringImpl( 16137 string_, string_->length(), string_->hash_field()); 16138 } 16139 16140 static uint32_t StringHash(Object* obj) { 16141 return String::cast(obj)->Hash(); 16142 } 16143 16144 Handle<String> string_; 16145 }; 16146 16147 16148 template<typename Derived, typename Shape, typename Key> 16149 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { 16150 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); 16151 } 16152 16153 16154 template<typename Derived, typename Shape, typename Key> 16155 void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) { 16156 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset, 16157 kHeaderSize + length() * kPointerSize, v); 16158 } 16159 16160 16161 template<typename Derived, typename Shape, typename Key> 16162 Handle<Derived> HashTable<Derived, Shape, Key>::New( 16163 Isolate* isolate, 16164 int at_least_space_for, 16165 MinimumCapacity capacity_option, 16166 PretenureFlag pretenure) { 16167 DCHECK(0 <= at_least_space_for); 16168 DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for)); 16169 16170 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY) 16171 ? at_least_space_for 16172 : ComputeCapacity(at_least_space_for); 16173 if (capacity > HashTable::kMaxCapacity) { 16174 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true); 16175 } 16176 16177 Factory* factory = isolate->factory(); 16178 int length = EntryToIndex(capacity); 16179 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure); 16180 array->set_map_no_write_barrier(*factory->hash_table_map()); 16181 Handle<Derived> table = Handle<Derived>::cast(array); 16182 16183 table->SetNumberOfElements(0); 16184 table->SetNumberOfDeletedElements(0); 16185 table->SetCapacity(capacity); 16186 return table; 16187 } 16188 16189 16190 // Find entry for key otherwise return kNotFound. 16191 template <typename Derived, typename Shape> 16192 int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) { 16193 if (!key->IsUniqueName()) { 16194 return DerivedDictionary::FindEntry(key); 16195 } 16196 16197 // Optimized for unique names. Knowledge of the key type allows: 16198 // 1. Move the check if the key is unique out of the loop. 16199 // 2. Avoid comparing hash codes in unique-to-unique comparison. 16200 // 3. Detect a case when a dictionary key is not unique but the key is. 16201 // In case of positive result the dictionary key may be replaced by the 16202 // internalized string with minimal performance penalty. It gives a chance 16203 // to perform further lookups in code stubs (and significant performance 16204 // boost a certain style of code). 16205 16206 // EnsureCapacity will guarantee the hash table is never full. 16207 uint32_t capacity = this->Capacity(); 16208 uint32_t entry = Derived::FirstProbe(key->Hash(), capacity); 16209 uint32_t count = 1; 16210 Isolate* isolate = this->GetIsolate(); 16211 while (true) { 16212 Object* element = this->KeyAt(entry); 16213 if (element->IsUndefined(isolate)) break; // Empty entry. 16214 if (*key == element) return entry; 16215 DCHECK(element->IsTheHole(isolate) || element->IsUniqueName()); 16216 entry = Derived::NextProbe(entry, count++, capacity); 16217 } 16218 return Derived::kNotFound; 16219 } 16220 16221 16222 template<typename Derived, typename Shape, typename Key> 16223 void HashTable<Derived, Shape, Key>::Rehash( 16224 Handle<Derived> new_table, 16225 Key key) { 16226 DCHECK(NumberOfElements() < new_table->Capacity()); 16227 16228 DisallowHeapAllocation no_gc; 16229 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc); 16230 16231 // Copy prefix to new array. 16232 for (int i = kPrefixStartIndex; 16233 i < kPrefixStartIndex + Shape::kPrefixSize; 16234 i++) { 16235 new_table->set(i, get(i), mode); 16236 } 16237 16238 // Rehash the elements. 16239 int capacity = this->Capacity(); 16240 Heap* heap = new_table->GetHeap(); 16241 Object* the_hole = heap->the_hole_value(); 16242 Object* undefined = heap->undefined_value(); 16243 for (int i = 0; i < capacity; i++) { 16244 uint32_t from_index = EntryToIndex(i); 16245 Object* k = this->get(from_index); 16246 if (k != the_hole && k != undefined) { 16247 uint32_t hash = this->HashForObject(key, k); 16248 uint32_t insertion_index = 16249 EntryToIndex(new_table->FindInsertionEntry(hash)); 16250 for (int j = 0; j < Shape::kEntrySize; j++) { 16251 new_table->set(insertion_index + j, get(from_index + j), mode); 16252 } 16253 } 16254 } 16255 new_table->SetNumberOfElements(NumberOfElements()); 16256 new_table->SetNumberOfDeletedElements(0); 16257 } 16258 16259 16260 template<typename Derived, typename Shape, typename Key> 16261 uint32_t HashTable<Derived, Shape, Key>::EntryForProbe( 16262 Key key, 16263 Object* k, 16264 int probe, 16265 uint32_t expected) { 16266 uint32_t hash = this->HashForObject(key, k); 16267 uint32_t capacity = this->Capacity(); 16268 uint32_t entry = FirstProbe(hash, capacity); 16269 for (int i = 1; i < probe; i++) { 16270 if (entry == expected) return expected; 16271 entry = NextProbe(entry, i, capacity); 16272 } 16273 return entry; 16274 } 16275 16276 16277 template<typename Derived, typename Shape, typename Key> 16278 void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1, 16279 uint32_t entry2, 16280 WriteBarrierMode mode) { 16281 int index1 = EntryToIndex(entry1); 16282 int index2 = EntryToIndex(entry2); 16283 Object* temp[Shape::kEntrySize]; 16284 for (int j = 0; j < Shape::kEntrySize; j++) { 16285 temp[j] = get(index1 + j); 16286 } 16287 for (int j = 0; j < Shape::kEntrySize; j++) { 16288 set(index1 + j, get(index2 + j), mode); 16289 } 16290 for (int j = 0; j < Shape::kEntrySize; j++) { 16291 set(index2 + j, temp[j], mode); 16292 } 16293 } 16294 16295 16296 template<typename Derived, typename Shape, typename Key> 16297 void HashTable<Derived, Shape, Key>::Rehash(Key key) { 16298 DisallowHeapAllocation no_gc; 16299 WriteBarrierMode mode = GetWriteBarrierMode(no_gc); 16300 Isolate* isolate = GetIsolate(); 16301 uint32_t capacity = Capacity(); 16302 bool done = false; 16303 for (int probe = 1; !done; probe++) { 16304 // All elements at entries given by one of the first _probe_ probes 16305 // are placed correctly. Other elements might need to be moved. 16306 done = true; 16307 for (uint32_t current = 0; current < capacity; current++) { 16308 Object* current_key = KeyAt(current); 16309 if (IsKey(isolate, current_key)) { 16310 uint32_t target = EntryForProbe(key, current_key, probe, current); 16311 if (current == target) continue; 16312 Object* target_key = KeyAt(target); 16313 if (!IsKey(target_key) || 16314 EntryForProbe(key, target_key, probe, target) != target) { 16315 // Put the current element into the correct position. 16316 Swap(current, target, mode); 16317 // The other element will be processed on the next iteration. 16318 current--; 16319 } else { 16320 // The place for the current element is occupied. Leave the element 16321 // for the next probe. 16322 done = false; 16323 } 16324 } 16325 } 16326 } 16327 // Wipe deleted entries. 16328 Object* the_hole = isolate->heap()->the_hole_value(); 16329 Object* undefined = isolate->heap()->undefined_value(); 16330 for (uint32_t current = 0; current < capacity; current++) { 16331 if (KeyAt(current) == the_hole) { 16332 set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined); 16333 } 16334 } 16335 SetNumberOfDeletedElements(0); 16336 } 16337 16338 16339 template<typename Derived, typename Shape, typename Key> 16340 Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity( 16341 Handle<Derived> table, 16342 int n, 16343 Key key, 16344 PretenureFlag pretenure) { 16345 Isolate* isolate = table->GetIsolate(); 16346 int capacity = table->Capacity(); 16347 int nof = table->NumberOfElements() + n; 16348 16349 if (table->HasSufficientCapacityToAdd(n)) return table; 16350 16351 const int kMinCapacityForPretenure = 256; 16352 bool should_pretenure = pretenure == TENURED || 16353 ((capacity > kMinCapacityForPretenure) && 16354 !isolate->heap()->InNewSpace(*table)); 16355 Handle<Derived> new_table = HashTable::New( 16356 isolate, 16357 nof * 2, 16358 USE_DEFAULT_MINIMUM_CAPACITY, 16359 should_pretenure ? TENURED : NOT_TENURED); 16360 16361 table->Rehash(new_table, key); 16362 return new_table; 16363 } 16364 16365 template <typename Derived, typename Shape, typename Key> 16366 bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd( 16367 int number_of_additional_elements) { 16368 int capacity = Capacity(); 16369 int nof = NumberOfElements() + number_of_additional_elements; 16370 int nod = NumberOfDeletedElements(); 16371 // Return true if: 16372 // 50% is still free after adding number_of_additional_elements elements and 16373 // at most 50% of the free elements are deleted elements. 16374 if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) { 16375 int needed_free = nof >> 1; 16376 if (nof + needed_free <= capacity) return true; 16377 } 16378 return false; 16379 } 16380 16381 16382 template<typename Derived, typename Shape, typename Key> 16383 Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table, 16384 Key key) { 16385 int capacity = table->Capacity(); 16386 int nof = table->NumberOfElements(); 16387 16388 // Shrink to fit the number of elements if only a quarter of the 16389 // capacity is filled with elements. 16390 if (nof > (capacity >> 2)) return table; 16391 // Allocate a new dictionary with room for at least the current 16392 // number of elements. The allocation method will make sure that 16393 // there is extra room in the dictionary for additions. Don't go 16394 // lower than room for 16 elements. 16395 int at_least_room_for = nof; 16396 if (at_least_room_for < 16) return table; 16397 16398 Isolate* isolate = table->GetIsolate(); 16399 const int kMinCapacityForPretenure = 256; 16400 bool pretenure = 16401 (at_least_room_for > kMinCapacityForPretenure) && 16402 !isolate->heap()->InNewSpace(*table); 16403 Handle<Derived> new_table = HashTable::New( 16404 isolate, 16405 at_least_room_for, 16406 USE_DEFAULT_MINIMUM_CAPACITY, 16407 pretenure ? TENURED : NOT_TENURED); 16408 16409 table->Rehash(new_table, key); 16410 return new_table; 16411 } 16412 16413 16414 template<typename Derived, typename Shape, typename Key> 16415 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) { 16416 uint32_t capacity = Capacity(); 16417 uint32_t entry = FirstProbe(hash, capacity); 16418 uint32_t count = 1; 16419 // EnsureCapacity will guarantee the hash table is never full. 16420 Isolate* isolate = GetIsolate(); 16421 while (true) { 16422 Object* element = KeyAt(entry); 16423 if (!IsKey(isolate, element)) break; 16424 entry = NextProbe(entry, count++, capacity); 16425 } 16426 return entry; 16427 } 16428 16429 16430 // Force instantiation of template instances class. 16431 // Please note this list is compiler dependent. 16432 16433 template class HashTable<StringTable, StringTableShape, HashTableKey*>; 16434 16435 template class HashTable<CompilationCacheTable, 16436 CompilationCacheShape, 16437 HashTableKey*>; 16438 16439 template class HashTable<ObjectHashTable, 16440 ObjectHashTableShape, 16441 Handle<Object> >; 16442 16443 template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >; 16444 16445 template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >; 16446 16447 template class Dictionary<GlobalDictionary, GlobalDictionaryShape, 16448 Handle<Name> >; 16449 16450 template class Dictionary<SeededNumberDictionary, 16451 SeededNumberDictionaryShape, 16452 uint32_t>; 16453 16454 template class Dictionary<UnseededNumberDictionary, 16455 UnseededNumberDictionaryShape, 16456 uint32_t>; 16457 16458 template Handle<SeededNumberDictionary> 16459 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16460 New(Isolate*, int at_least_space_for, PretenureFlag pretenure); 16461 16462 template Handle<UnseededNumberDictionary> 16463 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>:: 16464 New(Isolate*, int at_least_space_for, PretenureFlag pretenure); 16465 16466 template Handle<NameDictionary> 16467 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16468 New(Isolate*, int n, PretenureFlag pretenure); 16469 16470 template Handle<GlobalDictionary> 16471 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::New( 16472 Isolate*, int n, PretenureFlag pretenure); 16473 16474 template Handle<SeededNumberDictionary> 16475 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16476 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>); 16477 16478 template Handle<UnseededNumberDictionary> 16479 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>:: 16480 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>); 16481 16482 template Object* 16483 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16484 SlowReverseLookup(Object* value); 16485 16486 template Object* 16487 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16488 SlowReverseLookup(Object* value); 16489 16490 template Handle<Object> 16491 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty( 16492 Handle<NameDictionary>, int); 16493 16494 template Handle<Object> 16495 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, 16496 uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int); 16497 16498 template Handle<Object> 16499 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, 16500 uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int); 16501 16502 template Handle<NameDictionary> 16503 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16504 New(Isolate*, int, MinimumCapacity, PretenureFlag); 16505 16506 template Handle<NameDictionary> 16507 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16508 Shrink(Handle<NameDictionary>, Handle<Name>); 16509 16510 template Handle<SeededNumberDictionary> 16511 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16512 Shrink(Handle<SeededNumberDictionary>, uint32_t); 16513 16514 template Handle<UnseededNumberDictionary> 16515 HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape, 16516 uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t); 16517 16518 template Handle<NameDictionary> 16519 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add( 16520 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails); 16521 16522 template Handle<GlobalDictionary> 16523 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Add( 16524 Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, 16525 PropertyDetails); 16526 16527 template Handle<FixedArray> Dictionary< 16528 NameDictionary, NameDictionaryShape, 16529 Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>); 16530 16531 template Handle<FixedArray> Dictionary< 16532 NameDictionary, NameDictionaryShape, 16533 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>); 16534 16535 template Handle<SeededNumberDictionary> 16536 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16537 Add(Handle<SeededNumberDictionary>, 16538 uint32_t, 16539 Handle<Object>, 16540 PropertyDetails); 16541 16542 template Handle<UnseededNumberDictionary> 16543 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>:: 16544 Add(Handle<UnseededNumberDictionary>, 16545 uint32_t, 16546 Handle<Object>, 16547 PropertyDetails); 16548 16549 template Handle<SeededNumberDictionary> 16550 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>:: 16551 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t); 16552 16553 template Handle<UnseededNumberDictionary> 16554 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>:: 16555 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t); 16556 16557 template void Dictionary<NameDictionary, NameDictionaryShape, 16558 Handle<Name> >::SetRequiresCopyOnCapacityChange(); 16559 16560 template Handle<NameDictionary> 16561 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >:: 16562 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>); 16563 16564 template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, 16565 uint32_t>::FindEntry(uint32_t); 16566 16567 template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry( 16568 Handle<Name>); 16569 16570 template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 16571 NumberOfElementsFilterAttributes(PropertyFilter filter); 16572 16573 template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>:: 16574 NumberOfElementsFilterAttributes(PropertyFilter filter); 16575 16576 template void Dictionary<GlobalDictionary, GlobalDictionaryShape, 16577 Handle<Name>>::CopyEnumKeysTo(FixedArray* storage); 16578 16579 template void Dictionary<NameDictionary, NameDictionaryShape, 16580 Handle<Name>>::CopyEnumKeysTo(FixedArray* storage); 16581 16582 template void 16583 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>:: 16584 CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape, 16585 Handle<Name>>> 16586 dictionary, 16587 KeyAccumulator* keys, PropertyFilter filter); 16588 16589 template void 16590 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo( 16591 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>> 16592 dictionary, 16593 KeyAccumulator* keys, PropertyFilter filter); 16594 16595 Handle<Object> JSObject::PrepareSlowElementsForSort( 16596 Handle<JSObject> object, uint32_t limit) { 16597 DCHECK(object->HasDictionaryElements()); 16598 Isolate* isolate = object->GetIsolate(); 16599 // Must stay in dictionary mode, either because of requires_slow_elements, 16600 // or because we are not going to sort (and therefore compact) all of the 16601 // elements. 16602 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate); 16603 Handle<SeededNumberDictionary> new_dict = 16604 SeededNumberDictionary::New(isolate, dict->NumberOfElements()); 16605 16606 uint32_t pos = 0; 16607 uint32_t undefs = 0; 16608 int capacity = dict->Capacity(); 16609 Handle<Smi> bailout(Smi::FromInt(-1), isolate); 16610 // Entry to the new dictionary does not cause it to grow, as we have 16611 // allocated one that is large enough for all entries. 16612 DisallowHeapAllocation no_gc; 16613 for (int i = 0; i < capacity; i++) { 16614 Object* k = dict->KeyAt(i); 16615 if (!dict->IsKey(isolate, k)) continue; 16616 16617 DCHECK(k->IsNumber()); 16618 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0); 16619 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0); 16620 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32); 16621 16622 HandleScope scope(isolate); 16623 Handle<Object> value(dict->ValueAt(i), isolate); 16624 PropertyDetails details = dict->DetailsAt(i); 16625 if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) { 16626 // Bail out and do the sorting of undefineds and array holes in JS. 16627 // Also bail out if the element is not supposed to be moved. 16628 return bailout; 16629 } 16630 16631 uint32_t key = NumberToUint32(k); 16632 if (key < limit) { 16633 if (value->IsUndefined(isolate)) { 16634 undefs++; 16635 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { 16636 // Adding an entry with the key beyond smi-range requires 16637 // allocation. Bailout. 16638 return bailout; 16639 } else { 16640 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 16641 new_dict, pos, value, details, object->map()->is_prototype_map()); 16642 DCHECK(result.is_identical_to(new_dict)); 16643 USE(result); 16644 pos++; 16645 } 16646 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) { 16647 // Adding an entry with the key beyond smi-range requires 16648 // allocation. Bailout. 16649 return bailout; 16650 } else { 16651 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 16652 new_dict, key, value, details, object->map()->is_prototype_map()); 16653 DCHECK(result.is_identical_to(new_dict)); 16654 USE(result); 16655 } 16656 } 16657 16658 uint32_t result = pos; 16659 PropertyDetails no_details = PropertyDetails::Empty(); 16660 while (undefs > 0) { 16661 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { 16662 // Adding an entry with the key beyond smi-range requires 16663 // allocation. Bailout. 16664 return bailout; 16665 } 16666 HandleScope scope(isolate); 16667 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( 16668 new_dict, pos, isolate->factory()->undefined_value(), no_details, 16669 object->map()->is_prototype_map()); 16670 DCHECK(result.is_identical_to(new_dict)); 16671 USE(result); 16672 pos++; 16673 undefs--; 16674 } 16675 16676 object->set_elements(*new_dict); 16677 16678 AllowHeapAllocation allocate_return_value; 16679 return isolate->factory()->NewNumberFromUint(result); 16680 } 16681 16682 16683 // Collects all defined (non-hole) and non-undefined (array) elements at 16684 // the start of the elements array. 16685 // If the object is in dictionary mode, it is converted to fast elements 16686 // mode. 16687 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object, 16688 uint32_t limit) { 16689 Isolate* isolate = object->GetIsolate(); 16690 if (object->HasSloppyArgumentsElements()) { 16691 return handle(Smi::FromInt(-1), isolate); 16692 } 16693 16694 if (object->HasStringWrapperElements()) { 16695 int len = String::cast(Handle<JSValue>::cast(object)->value())->length(); 16696 return handle(Smi::FromInt(len), isolate); 16697 } 16698 16699 if (object->HasDictionaryElements()) { 16700 // Convert to fast elements containing only the existing properties. 16701 // Ordering is irrelevant, since we are going to sort anyway. 16702 Handle<SeededNumberDictionary> dict(object->element_dictionary()); 16703 if (object->IsJSArray() || dict->requires_slow_elements() || 16704 dict->max_number_key() >= limit) { 16705 return JSObject::PrepareSlowElementsForSort(object, limit); 16706 } 16707 // Convert to fast elements. 16708 16709 Handle<Map> new_map = 16710 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS); 16711 16712 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ? 16713 NOT_TENURED: TENURED; 16714 Handle<FixedArray> fast_elements = 16715 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure); 16716 dict->CopyValuesTo(*fast_elements); 16717 JSObject::ValidateElements(object); 16718 16719 JSObject::SetMapAndElements(object, new_map, fast_elements); 16720 } else if (object->HasFixedTypedArrayElements()) { 16721 // Typed arrays cannot have holes or undefined elements. 16722 return handle(Smi::FromInt( 16723 FixedArrayBase::cast(object->elements())->length()), isolate); 16724 } else if (!object->HasFastDoubleElements()) { 16725 EnsureWritableFastElements(object); 16726 } 16727 DCHECK(object->HasFastSmiOrObjectElements() || 16728 object->HasFastDoubleElements()); 16729 16730 // Collect holes at the end, undefined before that and the rest at the 16731 // start, and return the number of non-hole, non-undefined values. 16732 16733 Handle<FixedArrayBase> elements_base(object->elements()); 16734 uint32_t elements_length = static_cast<uint32_t>(elements_base->length()); 16735 if (limit > elements_length) { 16736 limit = elements_length; 16737 } 16738 if (limit == 0) { 16739 return handle(Smi::FromInt(0), isolate); 16740 } 16741 16742 uint32_t result = 0; 16743 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) { 16744 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base); 16745 // Split elements into defined and the_hole, in that order. 16746 unsigned int holes = limit; 16747 // Assume most arrays contain no holes and undefined values, so minimize the 16748 // number of stores of non-undefined, non-the-hole values. 16749 for (unsigned int i = 0; i < holes; i++) { 16750 if (elements->is_the_hole(i)) { 16751 holes--; 16752 } else { 16753 continue; 16754 } 16755 // Position i needs to be filled. 16756 while (holes > i) { 16757 if (elements->is_the_hole(holes)) { 16758 holes--; 16759 } else { 16760 elements->set(i, elements->get_scalar(holes)); 16761 break; 16762 } 16763 } 16764 } 16765 result = holes; 16766 while (holes < limit) { 16767 elements->set_the_hole(holes); 16768 holes++; 16769 } 16770 } else { 16771 FixedArray* elements = FixedArray::cast(*elements_base); 16772 DisallowHeapAllocation no_gc; 16773 16774 // Split elements into defined, undefined and the_hole, in that order. Only 16775 // count locations for undefined and the hole, and fill them afterwards. 16776 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc); 16777 unsigned int undefs = limit; 16778 unsigned int holes = limit; 16779 // Assume most arrays contain no holes and undefined values, so minimize the 16780 // number of stores of non-undefined, non-the-hole values. 16781 for (unsigned int i = 0; i < undefs; i++) { 16782 Object* current = elements->get(i); 16783 if (current->IsTheHole(isolate)) { 16784 holes--; 16785 undefs--; 16786 } else if (current->IsUndefined(isolate)) { 16787 undefs--; 16788 } else { 16789 continue; 16790 } 16791 // Position i needs to be filled. 16792 while (undefs > i) { 16793 current = elements->get(undefs); 16794 if (current->IsTheHole(isolate)) { 16795 holes--; 16796 undefs--; 16797 } else if (current->IsUndefined(isolate)) { 16798 undefs--; 16799 } else { 16800 elements->set(i, current, write_barrier); 16801 break; 16802 } 16803 } 16804 } 16805 result = undefs; 16806 while (undefs < holes) { 16807 elements->set_undefined(undefs); 16808 undefs++; 16809 } 16810 while (holes < limit) { 16811 elements->set_the_hole(holes); 16812 holes++; 16813 } 16814 } 16815 16816 return isolate->factory()->NewNumberFromUint(result); 16817 } 16818 16819 16820 ExternalArrayType JSTypedArray::type() { 16821 switch (elements()->map()->instance_type()) { 16822 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \ 16823 case FIXED_##TYPE##_ARRAY_TYPE: \ 16824 return kExternal##Type##Array; 16825 16826 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE) 16827 #undef INSTANCE_TYPE_TO_ARRAY_TYPE 16828 16829 default: 16830 UNREACHABLE(); 16831 return static_cast<ExternalArrayType>(-1); 16832 } 16833 } 16834 16835 16836 size_t JSTypedArray::element_size() { 16837 switch (elements()->map()->instance_type()) { 16838 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \ 16839 case FIXED_##TYPE##_ARRAY_TYPE: \ 16840 return size; 16841 16842 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE) 16843 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE 16844 16845 default: 16846 UNREACHABLE(); 16847 return 0; 16848 } 16849 } 16850 16851 16852 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global, 16853 Handle<Name> name) { 16854 DCHECK(!global->HasFastProperties()); 16855 auto dictionary = handle(global->global_dictionary()); 16856 int entry = dictionary->FindEntry(name); 16857 if (entry == GlobalDictionary::kNotFound) return; 16858 PropertyCell::InvalidateEntry(dictionary, entry); 16859 } 16860 16861 16862 // TODO(ishell): rename to EnsureEmptyPropertyCell or something. 16863 Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell( 16864 Handle<JSGlobalObject> global, Handle<Name> name) { 16865 Isolate* isolate = global->GetIsolate(); 16866 DCHECK(!global->HasFastProperties()); 16867 auto dictionary = handle(global->global_dictionary(), isolate); 16868 int entry = dictionary->FindEntry(name); 16869 Handle<PropertyCell> cell; 16870 if (entry != GlobalDictionary::kNotFound) { 16871 // This call should be idempotent. 16872 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 16873 cell = handle(PropertyCell::cast(dictionary->ValueAt(entry))); 16874 DCHECK(cell->property_details().cell_type() == 16875 PropertyCellType::kUninitialized || 16876 cell->property_details().cell_type() == 16877 PropertyCellType::kInvalidated); 16878 DCHECK(cell->value()->IsTheHole(isolate)); 16879 return cell; 16880 } 16881 cell = isolate->factory()->NewPropertyCell(); 16882 PropertyDetails details(NONE, DATA, 0, PropertyCellType::kUninitialized); 16883 dictionary = GlobalDictionary::Add(dictionary, name, cell, details); 16884 global->set_properties(*dictionary); 16885 return cell; 16886 } 16887 16888 16889 // This class is used for looking up two character strings in the string table. 16890 // If we don't have a hit we don't want to waste much time so we unroll the 16891 // string hash calculation loop here for speed. Doesn't work if the two 16892 // characters form a decimal integer, since such strings have a different hash 16893 // algorithm. 16894 class TwoCharHashTableKey : public HashTableKey { 16895 public: 16896 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed) 16897 : c1_(c1), c2_(c2) { 16898 // Char 1. 16899 uint32_t hash = seed; 16900 hash += c1; 16901 hash += hash << 10; 16902 hash ^= hash >> 6; 16903 // Char 2. 16904 hash += c2; 16905 hash += hash << 10; 16906 hash ^= hash >> 6; 16907 // GetHash. 16908 hash += hash << 3; 16909 hash ^= hash >> 11; 16910 hash += hash << 15; 16911 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash; 16912 hash_ = hash; 16913 #ifdef DEBUG 16914 // If this assert fails then we failed to reproduce the two-character 16915 // version of the string hashing algorithm above. One reason could be 16916 // that we were passed two digits as characters, since the hash 16917 // algorithm is different in that case. 16918 uint16_t chars[2] = {c1, c2}; 16919 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed); 16920 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask; 16921 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash)); 16922 #endif 16923 } 16924 16925 bool IsMatch(Object* o) override { 16926 if (!o->IsString()) return false; 16927 String* other = String::cast(o); 16928 if (other->length() != 2) return false; 16929 if (other->Get(0) != c1_) return false; 16930 return other->Get(1) == c2_; 16931 } 16932 16933 uint32_t Hash() override { return hash_; } 16934 uint32_t HashForObject(Object* key) override { 16935 if (!key->IsString()) return 0; 16936 return String::cast(key)->Hash(); 16937 } 16938 16939 Handle<Object> AsHandle(Isolate* isolate) override { 16940 // The TwoCharHashTableKey is only used for looking in the string 16941 // table, not for adding to it. 16942 UNREACHABLE(); 16943 return MaybeHandle<Object>().ToHandleChecked(); 16944 } 16945 16946 private: 16947 uint16_t c1_; 16948 uint16_t c2_; 16949 uint32_t hash_; 16950 }; 16951 16952 16953 MaybeHandle<String> StringTable::InternalizeStringIfExists( 16954 Isolate* isolate, 16955 Handle<String> string) { 16956 if (string->IsInternalizedString()) { 16957 return string; 16958 } 16959 return LookupStringIfExists(isolate, string); 16960 } 16961 16962 16963 MaybeHandle<String> StringTable::LookupStringIfExists( 16964 Isolate* isolate, 16965 Handle<String> string) { 16966 Handle<StringTable> string_table = isolate->factory()->string_table(); 16967 InternalizedStringKey key(string); 16968 int entry = string_table->FindEntry(&key); 16969 if (entry == kNotFound) { 16970 return MaybeHandle<String>(); 16971 } else { 16972 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate); 16973 DCHECK(StringShape(*result).IsInternalized()); 16974 return result; 16975 } 16976 } 16977 16978 16979 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists( 16980 Isolate* isolate, 16981 uint16_t c1, 16982 uint16_t c2) { 16983 Handle<StringTable> string_table = isolate->factory()->string_table(); 16984 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed()); 16985 int entry = string_table->FindEntry(&key); 16986 if (entry == kNotFound) { 16987 return MaybeHandle<String>(); 16988 } else { 16989 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate); 16990 DCHECK(StringShape(*result).IsInternalized()); 16991 return result; 16992 } 16993 } 16994 16995 16996 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, 16997 int expected) { 16998 Handle<StringTable> table = isolate->factory()->string_table(); 16999 // We need a key instance for the virtual hash function. 17000 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); 17001 table = StringTable::EnsureCapacity(table, expected, &dummy_key); 17002 isolate->heap()->SetRootStringTable(*table); 17003 } 17004 17005 17006 Handle<String> StringTable::LookupString(Isolate* isolate, 17007 Handle<String> string) { 17008 if (string->IsConsString() && string->IsFlat()) { 17009 string = String::Flatten(string); 17010 if (string->IsInternalizedString()) return string; 17011 } 17012 17013 InternalizedStringKey key(string); 17014 Handle<String> result = LookupKey(isolate, &key); 17015 17016 if (string->IsConsString()) { 17017 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17018 cons->set_first(*result); 17019 cons->set_second(isolate->heap()->empty_string()); 17020 } else if (string->IsSlicedString()) { 17021 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); 17022 DisallowHeapAllocation no_gc; 17023 bool one_byte = result->IsOneByteRepresentation(); 17024 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map() 17025 : isolate->factory()->cons_string_map(); 17026 string->set_map(*map); 17027 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17028 cons->set_first(*result); 17029 cons->set_second(isolate->heap()->empty_string()); 17030 } 17031 return result; 17032 } 17033 17034 17035 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { 17036 Handle<StringTable> table = isolate->factory()->string_table(); 17037 int entry = table->FindEntry(key); 17038 17039 // String already in table. 17040 if (entry != kNotFound) { 17041 return handle(String::cast(table->KeyAt(entry)), isolate); 17042 } 17043 17044 // Adding new string. Grow table if needed. 17045 table = StringTable::EnsureCapacity(table, 1, key); 17046 17047 // Create string object. 17048 Handle<Object> string = key->AsHandle(isolate); 17049 // There must be no attempts to internalize strings that could throw 17050 // InvalidStringLength error. 17051 CHECK(!string.is_null()); 17052 17053 // Add the new string and return it along with the string table. 17054 entry = table->FindInsertionEntry(key->Hash()); 17055 table->set(EntryToIndex(entry), *string); 17056 table->ElementAdded(); 17057 17058 isolate->heap()->SetRootStringTable(*table); 17059 return Handle<String>::cast(string); 17060 } 17061 17062 17063 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) { 17064 Handle<StringTable> table = isolate->factory()->string_table(); 17065 int entry = table->FindEntry(key); 17066 if (entry != kNotFound) return String::cast(table->KeyAt(entry)); 17067 return NULL; 17068 } 17069 17070 Handle<StringSet> StringSet::New(Isolate* isolate) { 17071 return HashTable::New(isolate, 0); 17072 } 17073 17074 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset, 17075 Handle<String> name) { 17076 if (!stringset->Has(name)) { 17077 stringset = EnsureCapacity(stringset, 1, *name); 17078 uint32_t hash = StringSetShape::Hash(*name); 17079 int entry = stringset->FindInsertionEntry(hash); 17080 stringset->set(EntryToIndex(entry), *name); 17081 stringset->ElementAdded(); 17082 } 17083 return stringset; 17084 } 17085 17086 bool StringSet::Has(Handle<String> name) { 17087 return FindEntry(*name) != kNotFound; 17088 } 17089 17090 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src, 17091 Handle<Context> context, 17092 LanguageMode language_mode) { 17093 Isolate* isolate = GetIsolate(); 17094 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 17095 StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition); 17096 int entry = FindEntry(&key); 17097 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17098 int index = EntryToIndex(entry); 17099 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value(); 17100 return Handle<Object>(get(index + 1), isolate); 17101 } 17102 17103 17104 Handle<Object> CompilationCacheTable::LookupEval( 17105 Handle<String> src, Handle<SharedFunctionInfo> outer_info, 17106 LanguageMode language_mode, int scope_position) { 17107 Isolate* isolate = GetIsolate(); 17108 // Cache key is the tuple (source, outer shared function info, scope position) 17109 // to unambiguously identify the context chain the cached eval code assumes. 17110 StringSharedKey key(src, outer_info, language_mode, scope_position); 17111 int entry = FindEntry(&key); 17112 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17113 int index = EntryToIndex(entry); 17114 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value(); 17115 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate); 17116 } 17117 17118 17119 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src, 17120 JSRegExp::Flags flags) { 17121 Isolate* isolate = GetIsolate(); 17122 DisallowHeapAllocation no_allocation; 17123 RegExpKey key(src, flags); 17124 int entry = FindEntry(&key); 17125 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17126 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate); 17127 } 17128 17129 17130 Handle<CompilationCacheTable> CompilationCacheTable::Put( 17131 Handle<CompilationCacheTable> cache, Handle<String> src, 17132 Handle<Context> context, LanguageMode language_mode, Handle<Object> value) { 17133 Isolate* isolate = cache->GetIsolate(); 17134 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 17135 StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition); 17136 Handle<Object> k = key.AsHandle(isolate); 17137 cache = EnsureCapacity(cache, 1, &key); 17138 int entry = cache->FindInsertionEntry(key.Hash()); 17139 cache->set(EntryToIndex(entry), *k); 17140 cache->set(EntryToIndex(entry) + 1, *value); 17141 cache->ElementAdded(); 17142 return cache; 17143 } 17144 17145 17146 Handle<CompilationCacheTable> CompilationCacheTable::PutEval( 17147 Handle<CompilationCacheTable> cache, Handle<String> src, 17148 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value, 17149 int scope_position) { 17150 Isolate* isolate = cache->GetIsolate(); 17151 StringSharedKey key(src, outer_info, value->language_mode(), scope_position); 17152 { 17153 Handle<Object> k = key.AsHandle(isolate); 17154 DisallowHeapAllocation no_allocation_scope; 17155 int entry = cache->FindEntry(&key); 17156 if (entry != kNotFound) { 17157 cache->set(EntryToIndex(entry), *k); 17158 cache->set(EntryToIndex(entry) + 1, *value); 17159 return cache; 17160 } 17161 } 17162 17163 cache = EnsureCapacity(cache, 1, &key); 17164 int entry = cache->FindInsertionEntry(key.Hash()); 17165 Handle<Object> k = 17166 isolate->factory()->NewNumber(static_cast<double>(key.Hash())); 17167 cache->set(EntryToIndex(entry), *k); 17168 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations)); 17169 cache->ElementAdded(); 17170 return cache; 17171 } 17172 17173 17174 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp( 17175 Handle<CompilationCacheTable> cache, Handle<String> src, 17176 JSRegExp::Flags flags, Handle<FixedArray> value) { 17177 RegExpKey key(src, flags); 17178 cache = EnsureCapacity(cache, 1, &key); 17179 int entry = cache->FindInsertionEntry(key.Hash()); 17180 // We store the value in the key slot, and compare the search key 17181 // to the stored value with a custon IsMatch function during lookups. 17182 cache->set(EntryToIndex(entry), *value); 17183 cache->set(EntryToIndex(entry) + 1, *value); 17184 cache->ElementAdded(); 17185 return cache; 17186 } 17187 17188 17189 void CompilationCacheTable::Age() { 17190 DisallowHeapAllocation no_allocation; 17191 Object* the_hole_value = GetHeap()->the_hole_value(); 17192 uint32_t capacity = Capacity(); 17193 for (int entry = 0, size = capacity; entry < size; entry++) { 17194 int entry_index = EntryToIndex(entry); 17195 int value_index = entry_index + 1; 17196 17197 if (get(entry_index)->IsNumber()) { 17198 Smi* count = Smi::cast(get(value_index)); 17199 count = Smi::FromInt(count->value() - 1); 17200 if (count->value() == 0) { 17201 NoWriteBarrierSet(this, entry_index, the_hole_value); 17202 NoWriteBarrierSet(this, value_index, the_hole_value); 17203 ElementRemoved(); 17204 } else { 17205 NoWriteBarrierSet(this, value_index, count); 17206 } 17207 } else if (get(entry_index)->IsFixedArray()) { 17208 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index)); 17209 if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) { 17210 NoWriteBarrierSet(this, entry_index, the_hole_value); 17211 NoWriteBarrierSet(this, value_index, the_hole_value); 17212 ElementRemoved(); 17213 } 17214 } 17215 } 17216 // Wipe deleted entries. 17217 Heap* heap = GetHeap(); 17218 Object* the_hole = heap->the_hole_value(); 17219 Object* undefined = heap->undefined_value(); 17220 for (uint32_t current = 0; current < capacity; current++) { 17221 if (get(EntryToIndex(current)) == the_hole) { 17222 set(EntryToIndex(current), undefined); 17223 } 17224 } 17225 SetNumberOfDeletedElements(0); 17226 } 17227 17228 17229 void CompilationCacheTable::Remove(Object* value) { 17230 DisallowHeapAllocation no_allocation; 17231 Object* the_hole_value = GetHeap()->the_hole_value(); 17232 for (int entry = 0, size = Capacity(); entry < size; entry++) { 17233 int entry_index = EntryToIndex(entry); 17234 int value_index = entry_index + 1; 17235 if (get(value_index) == value) { 17236 NoWriteBarrierSet(this, entry_index, the_hole_value); 17237 NoWriteBarrierSet(this, value_index, the_hole_value); 17238 ElementRemoved(); 17239 } 17240 } 17241 return; 17242 } 17243 17244 17245 template<typename Derived, typename Shape, typename Key> 17246 Handle<Derived> Dictionary<Derived, Shape, Key>::New( 17247 Isolate* isolate, 17248 int at_least_space_for, 17249 PretenureFlag pretenure) { 17250 DCHECK(0 <= at_least_space_for); 17251 Handle<Derived> dict = DerivedHashTable::New(isolate, 17252 at_least_space_for, 17253 USE_DEFAULT_MINIMUM_CAPACITY, 17254 pretenure); 17255 17256 // Initialize the next enumeration index. 17257 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex); 17258 return dict; 17259 } 17260 17261 17262 template <typename Derived, typename Shape, typename Key> 17263 Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray( 17264 Handle<Derived> dictionary) { 17265 Isolate* isolate = dictionary->GetIsolate(); 17266 Factory* factory = isolate->factory(); 17267 int length = dictionary->NumberOfElements(); 17268 17269 Handle<FixedArray> iteration_order = factory->NewFixedArray(length); 17270 Handle<FixedArray> enumeration_order = factory->NewFixedArray(length); 17271 17272 // Fill both the iteration order array and the enumeration order array 17273 // with property details. 17274 int capacity = dictionary->Capacity(); 17275 int pos = 0; 17276 for (int i = 0; i < capacity; i++) { 17277 if (dictionary->IsKey(isolate, dictionary->KeyAt(i))) { 17278 int index = dictionary->DetailsAt(i).dictionary_index(); 17279 iteration_order->set(pos, Smi::FromInt(i)); 17280 enumeration_order->set(pos, Smi::FromInt(index)); 17281 pos++; 17282 } 17283 } 17284 DCHECK(pos == length); 17285 17286 // Sort the arrays wrt. enumeration order. 17287 iteration_order->SortPairs(*enumeration_order, enumeration_order->length()); 17288 return iteration_order; 17289 } 17290 17291 17292 template <typename Derived, typename Shape, typename Key> 17293 Handle<FixedArray> 17294 Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices( 17295 Handle<Derived> dictionary) { 17296 int length = dictionary->NumberOfElements(); 17297 17298 Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary); 17299 DCHECK(iteration_order->length() == length); 17300 17301 // Iterate over the dictionary using the enumeration order and update 17302 // the dictionary with new enumeration indices. 17303 for (int i = 0; i < length; i++) { 17304 int index = Smi::cast(iteration_order->get(i))->value(); 17305 DCHECK(dictionary->IsKey(dictionary->KeyAt(index))); 17306 17307 int enum_index = PropertyDetails::kInitialIndex + i; 17308 17309 PropertyDetails details = dictionary->DetailsAt(index); 17310 PropertyDetails new_details = details.set_index(enum_index); 17311 dictionary->DetailsAtPut(index, new_details); 17312 } 17313 17314 // Set the next enumeration index. 17315 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length); 17316 return iteration_order; 17317 } 17318 17319 17320 template <typename Derived, typename Shape, typename Key> 17321 void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() { 17322 DCHECK_EQ(0, DerivedHashTable::NumberOfElements()); 17323 DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements()); 17324 // Make sure that HashTable::EnsureCapacity will create a copy. 17325 DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity()); 17326 DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1)); 17327 } 17328 17329 17330 template <typename Derived, typename Shape, typename Key> 17331 Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity( 17332 Handle<Derived> dictionary, int n, Key key) { 17333 // Check whether there are enough enumeration indices to add n elements. 17334 if (Shape::kIsEnumerable && 17335 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) { 17336 // If not, we generate new indices for the properties. 17337 GenerateNewEnumerationIndices(dictionary); 17338 } 17339 return DerivedHashTable::EnsureCapacity(dictionary, n, key); 17340 } 17341 17342 17343 template <typename Derived, typename Shape, typename Key> 17344 Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty( 17345 Handle<Derived> dictionary, int entry) { 17346 Factory* factory = dictionary->GetIsolate()->factory(); 17347 PropertyDetails details = dictionary->DetailsAt(entry); 17348 if (!details.IsConfigurable()) return factory->false_value(); 17349 17350 dictionary->SetEntry( 17351 entry, factory->the_hole_value(), factory->the_hole_value()); 17352 dictionary->ElementRemoved(); 17353 return factory->true_value(); 17354 } 17355 17356 17357 template<typename Derived, typename Shape, typename Key> 17358 Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut( 17359 Handle<Derived> dictionary, Key key, Handle<Object> value) { 17360 int entry = dictionary->FindEntry(key); 17361 17362 // If the entry is present set the value; 17363 if (entry != Dictionary::kNotFound) { 17364 dictionary->ValueAtPut(entry, *value); 17365 return dictionary; 17366 } 17367 17368 // Check whether the dictionary should be extended. 17369 dictionary = EnsureCapacity(dictionary, 1, key); 17370 #ifdef DEBUG 17371 USE(Shape::AsHandle(dictionary->GetIsolate(), key)); 17372 #endif 17373 PropertyDetails details = PropertyDetails::Empty(); 17374 17375 AddEntry(dictionary, key, value, details, dictionary->Hash(key)); 17376 return dictionary; 17377 } 17378 17379 17380 template<typename Derived, typename Shape, typename Key> 17381 Handle<Derived> Dictionary<Derived, Shape, Key>::Add( 17382 Handle<Derived> dictionary, 17383 Key key, 17384 Handle<Object> value, 17385 PropertyDetails details) { 17386 // Valdate key is absent. 17387 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound)); 17388 // Check whether the dictionary should be extended. 17389 dictionary = EnsureCapacity(dictionary, 1, key); 17390 17391 AddEntry(dictionary, key, value, details, dictionary->Hash(key)); 17392 return dictionary; 17393 } 17394 17395 17396 // Add a key, value pair to the dictionary. 17397 template<typename Derived, typename Shape, typename Key> 17398 void Dictionary<Derived, Shape, Key>::AddEntry( 17399 Handle<Derived> dictionary, 17400 Key key, 17401 Handle<Object> value, 17402 PropertyDetails details, 17403 uint32_t hash) { 17404 // Compute the key object. 17405 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key); 17406 17407 uint32_t entry = dictionary->FindInsertionEntry(hash); 17408 // Insert element at empty or deleted entry 17409 if (details.dictionary_index() == 0 && Shape::kIsEnumerable) { 17410 // Assign an enumeration index to the property and update 17411 // SetNextEnumerationIndex. 17412 int index = dictionary->NextEnumerationIndex(); 17413 details = details.set_index(index); 17414 dictionary->SetNextEnumerationIndex(index + 1); 17415 } 17416 dictionary->SetEntry(entry, k, value, details); 17417 DCHECK((dictionary->KeyAt(entry)->IsNumber() || 17418 dictionary->KeyAt(entry)->IsName())); 17419 dictionary->ElementAdded(); 17420 } 17421 17422 bool SeededNumberDictionary::HasComplexElements() { 17423 if (!requires_slow_elements()) return false; 17424 Isolate* isolate = this->GetIsolate(); 17425 int capacity = this->Capacity(); 17426 for (int i = 0; i < capacity; i++) { 17427 Object* k = this->KeyAt(i); 17428 if (!this->IsKey(isolate, k)) continue; 17429 DCHECK(!IsDeleted(i)); 17430 PropertyDetails details = this->DetailsAt(i); 17431 if (details.type() == ACCESSOR_CONSTANT) return true; 17432 PropertyAttributes attr = details.attributes(); 17433 if (attr & ALL_ATTRIBUTES_MASK) return true; 17434 } 17435 return false; 17436 } 17437 17438 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key, 17439 bool used_as_prototype) { 17440 DisallowHeapAllocation no_allocation; 17441 // If the dictionary requires slow elements an element has already 17442 // been added at a high index. 17443 if (requires_slow_elements()) return; 17444 // Check if this index is high enough that we should require slow 17445 // elements. 17446 if (key > kRequiresSlowElementsLimit) { 17447 if (used_as_prototype) { 17448 // TODO(verwaest): Remove this hack. 17449 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate()); 17450 } 17451 set_requires_slow_elements(); 17452 return; 17453 } 17454 // Update max key value. 17455 Object* max_index_object = get(kMaxNumberKeyIndex); 17456 if (!max_index_object->IsSmi() || max_number_key() < key) { 17457 FixedArray::set(kMaxNumberKeyIndex, 17458 Smi::FromInt(key << kRequiresSlowElementsTagSize)); 17459 } 17460 } 17461 17462 17463 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry( 17464 Handle<SeededNumberDictionary> dictionary, uint32_t key, 17465 Handle<Object> value, PropertyDetails details, bool used_as_prototype) { 17466 dictionary->UpdateMaxNumberKey(key, used_as_prototype); 17467 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); 17468 return Add(dictionary, key, value, details); 17469 } 17470 17471 17472 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry( 17473 Handle<UnseededNumberDictionary> dictionary, 17474 uint32_t key, 17475 Handle<Object> value) { 17476 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); 17477 return Add(dictionary, key, value, PropertyDetails::Empty()); 17478 } 17479 17480 17481 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut( 17482 Handle<SeededNumberDictionary> dictionary, uint32_t key, 17483 Handle<Object> value, bool used_as_prototype) { 17484 dictionary->UpdateMaxNumberKey(key, used_as_prototype); 17485 return AtPut(dictionary, key, value); 17486 } 17487 17488 17489 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut( 17490 Handle<UnseededNumberDictionary> dictionary, 17491 uint32_t key, 17492 Handle<Object> value) { 17493 return AtPut(dictionary, key, value); 17494 } 17495 17496 17497 Handle<SeededNumberDictionary> SeededNumberDictionary::Set( 17498 Handle<SeededNumberDictionary> dictionary, uint32_t key, 17499 Handle<Object> value, PropertyDetails details, bool used_as_prototype) { 17500 int entry = dictionary->FindEntry(key); 17501 if (entry == kNotFound) { 17502 return AddNumberEntry(dictionary, key, value, details, used_as_prototype); 17503 } 17504 // Preserve enumeration index. 17505 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index()); 17506 Handle<Object> object_key = 17507 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); 17508 dictionary->SetEntry(entry, object_key, value, details); 17509 return dictionary; 17510 } 17511 17512 17513 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set( 17514 Handle<UnseededNumberDictionary> dictionary, 17515 uint32_t key, 17516 Handle<Object> value) { 17517 int entry = dictionary->FindEntry(key); 17518 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value); 17519 Handle<Object> object_key = 17520 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); 17521 dictionary->SetEntry(entry, object_key, value); 17522 return dictionary; 17523 } 17524 17525 17526 template <typename Derived, typename Shape, typename Key> 17527 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes( 17528 PropertyFilter filter) { 17529 Isolate* isolate = this->GetIsolate(); 17530 int capacity = this->Capacity(); 17531 int result = 0; 17532 for (int i = 0; i < capacity; i++) { 17533 Object* k = this->KeyAt(i); 17534 if (this->IsKey(isolate, k) && !k->FilterKey(filter)) { 17535 if (this->IsDeleted(i)) continue; 17536 PropertyDetails details = this->DetailsAt(i); 17537 PropertyAttributes attr = details.attributes(); 17538 if ((attr & filter) == 0) result++; 17539 } 17540 } 17541 return result; 17542 } 17543 17544 17545 template <typename Dictionary> 17546 struct EnumIndexComparator { 17547 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {} 17548 bool operator() (Smi* a, Smi* b) { 17549 PropertyDetails da(dict->DetailsAt(a->value())); 17550 PropertyDetails db(dict->DetailsAt(b->value())); 17551 return da.dictionary_index() < db.dictionary_index(); 17552 } 17553 Dictionary* dict; 17554 }; 17555 17556 17557 template <typename Derived, typename Shape, typename Key> 17558 void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(FixedArray* storage) { 17559 Isolate* isolate = this->GetIsolate(); 17560 int length = storage->length(); 17561 int capacity = this->Capacity(); 17562 int properties = 0; 17563 for (int i = 0; i < capacity; i++) { 17564 Object* k = this->KeyAt(i); 17565 if (this->IsKey(isolate, k) && !k->IsSymbol()) { 17566 PropertyDetails details = this->DetailsAt(i); 17567 if (details.IsDontEnum() || this->IsDeleted(i)) continue; 17568 storage->set(properties, Smi::FromInt(i)); 17569 properties++; 17570 if (properties == length) break; 17571 } 17572 } 17573 CHECK_EQ(length, properties); 17574 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(this)); 17575 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress()); 17576 std::sort(start, start + length, cmp); 17577 for (int i = 0; i < length; i++) { 17578 int index = Smi::cast(storage->get(i))->value(); 17579 storage->set(i, this->KeyAt(index)); 17580 } 17581 } 17582 17583 template <typename Derived, typename Shape, typename Key> 17584 void Dictionary<Derived, Shape, Key>::CollectKeysTo( 17585 Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys, 17586 PropertyFilter filter) { 17587 Isolate* isolate = keys->isolate(); 17588 int capacity = dictionary->Capacity(); 17589 Handle<FixedArray> array = 17590 isolate->factory()->NewFixedArray(dictionary->NumberOfElements()); 17591 int array_size = 0; 17592 17593 { 17594 DisallowHeapAllocation no_gc; 17595 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary; 17596 for (int i = 0; i < capacity; i++) { 17597 Object* k = raw_dict->KeyAt(i); 17598 if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue; 17599 if (raw_dict->IsDeleted(i)) continue; 17600 PropertyDetails details = raw_dict->DetailsAt(i); 17601 if ((details.attributes() & filter) != 0) continue; 17602 if (filter & ONLY_ALL_CAN_READ) { 17603 if (details.kind() != kAccessor) continue; 17604 Object* accessors = raw_dict->ValueAt(i); 17605 if (accessors->IsPropertyCell()) { 17606 accessors = PropertyCell::cast(accessors)->value(); 17607 } 17608 if (!accessors->IsAccessorInfo()) continue; 17609 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; 17610 } 17611 array->set(array_size++, Smi::FromInt(i)); 17612 } 17613 17614 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict)); 17615 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress()); 17616 std::sort(start, start + array_size, cmp); 17617 } 17618 17619 bool has_seen_symbol = false; 17620 for (int i = 0; i < array_size; i++) { 17621 int index = Smi::cast(array->get(i))->value(); 17622 Object* key = dictionary->KeyAt(index); 17623 if (key->IsSymbol()) { 17624 has_seen_symbol = true; 17625 continue; 17626 } 17627 keys->AddKey(key, DO_NOT_CONVERT); 17628 } 17629 if (has_seen_symbol) { 17630 for (int i = 0; i < array_size; i++) { 17631 int index = Smi::cast(array->get(i))->value(); 17632 Object* key = dictionary->KeyAt(index); 17633 if (!key->IsSymbol()) continue; 17634 keys->AddKey(key, DO_NOT_CONVERT); 17635 } 17636 } 17637 } 17638 17639 17640 // Backwards lookup (slow). 17641 template<typename Derived, typename Shape, typename Key> 17642 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { 17643 Isolate* isolate = this->GetIsolate(); 17644 int capacity = this->Capacity(); 17645 for (int i = 0; i < capacity; i++) { 17646 Object* k = this->KeyAt(i); 17647 if (!this->IsKey(isolate, k)) continue; 17648 Object* e = this->ValueAt(i); 17649 // TODO(dcarney): this should be templatized. 17650 if (e->IsPropertyCell()) { 17651 e = PropertyCell::cast(e)->value(); 17652 } 17653 if (e == value) return k; 17654 } 17655 return isolate->heap()->undefined_value(); 17656 } 17657 17658 17659 Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key, 17660 int32_t hash) { 17661 DisallowHeapAllocation no_gc; 17662 DCHECK(IsKey(isolate, *key)); 17663 17664 int entry = FindEntry(isolate, key, hash); 17665 if (entry == kNotFound) return isolate->heap()->the_hole_value(); 17666 return get(EntryToIndex(entry) + 1); 17667 } 17668 17669 17670 Object* ObjectHashTable::Lookup(Handle<Object> key) { 17671 DisallowHeapAllocation no_gc; 17672 17673 Isolate* isolate = GetIsolate(); 17674 DCHECK(IsKey(isolate, *key)); 17675 17676 // If the object does not have an identity hash, it was never used as a key. 17677 Object* hash = key->GetHash(); 17678 if (hash->IsUndefined(isolate)) { 17679 return isolate->heap()->the_hole_value(); 17680 } 17681 return Lookup(isolate, key, Smi::cast(hash)->value()); 17682 } 17683 17684 17685 Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) { 17686 return Lookup(GetIsolate(), key, hash); 17687 } 17688 17689 17690 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table, 17691 Handle<Object> key, 17692 Handle<Object> value) { 17693 Isolate* isolate = table->GetIsolate(); 17694 DCHECK(table->IsKey(isolate, *key)); 17695 DCHECK(!value->IsTheHole(isolate)); 17696 17697 // Make sure the key object has an identity hash code. 17698 int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); 17699 17700 return Put(table, key, value, hash); 17701 } 17702 17703 17704 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table, 17705 Handle<Object> key, 17706 Handle<Object> value, 17707 int32_t hash) { 17708 Isolate* isolate = table->GetIsolate(); 17709 DCHECK(table->IsKey(isolate, *key)); 17710 DCHECK(!value->IsTheHole(isolate)); 17711 17712 int entry = table->FindEntry(isolate, key, hash); 17713 17714 // Key is already in table, just overwrite value. 17715 if (entry != kNotFound) { 17716 table->set(EntryToIndex(entry) + 1, *value); 17717 return table; 17718 } 17719 17720 // Rehash if more than 25% of the entries are deleted entries. 17721 // TODO(jochen): Consider to shrink the fixed array in place. 17722 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) { 17723 table->Rehash(isolate->factory()->undefined_value()); 17724 } 17725 // If we're out of luck, we didn't get a GC recently, and so rehashing 17726 // isn't enough to avoid a crash. 17727 if (!table->HasSufficientCapacityToAdd(1)) { 17728 int nof = table->NumberOfElements() + 1; 17729 int capacity = ObjectHashTable::ComputeCapacity(nof * 2); 17730 if (capacity > ObjectHashTable::kMaxCapacity) { 17731 for (size_t i = 0; i < 2; ++i) { 17732 isolate->heap()->CollectAllGarbage( 17733 Heap::kFinalizeIncrementalMarkingMask, "full object hash table"); 17734 } 17735 table->Rehash(isolate->factory()->undefined_value()); 17736 } 17737 } 17738 17739 // Check whether the hash table should be extended. 17740 table = EnsureCapacity(table, 1, key); 17741 table->AddEntry(table->FindInsertionEntry(hash), *key, *value); 17742 return table; 17743 } 17744 17745 17746 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table, 17747 Handle<Object> key, 17748 bool* was_present) { 17749 DCHECK(table->IsKey(table->GetIsolate(), *key)); 17750 17751 Object* hash = key->GetHash(); 17752 if (hash->IsUndefined(table->GetIsolate())) { 17753 *was_present = false; 17754 return table; 17755 } 17756 17757 return Remove(table, key, was_present, Smi::cast(hash)->value()); 17758 } 17759 17760 17761 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table, 17762 Handle<Object> key, 17763 bool* was_present, 17764 int32_t hash) { 17765 Isolate* isolate = table->GetIsolate(); 17766 DCHECK(table->IsKey(isolate, *key)); 17767 17768 int entry = table->FindEntry(isolate, key, hash); 17769 if (entry == kNotFound) { 17770 *was_present = false; 17771 return table; 17772 } 17773 17774 *was_present = true; 17775 table->RemoveEntry(entry); 17776 return Shrink(table, key); 17777 } 17778 17779 17780 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) { 17781 set(EntryToIndex(entry), key); 17782 set(EntryToIndex(entry) + 1, value); 17783 ElementAdded(); 17784 } 17785 17786 17787 void ObjectHashTable::RemoveEntry(int entry) { 17788 set_the_hole(EntryToIndex(entry)); 17789 set_the_hole(EntryToIndex(entry) + 1); 17790 ElementRemoved(); 17791 } 17792 17793 17794 Object* WeakHashTable::Lookup(Handle<HeapObject> key) { 17795 DisallowHeapAllocation no_gc; 17796 Isolate* isolate = GetIsolate(); 17797 DCHECK(IsKey(isolate, *key)); 17798 int entry = FindEntry(key); 17799 if (entry == kNotFound) return isolate->heap()->the_hole_value(); 17800 return get(EntryToValueIndex(entry)); 17801 } 17802 17803 17804 Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table, 17805 Handle<HeapObject> key, 17806 Handle<HeapObject> value) { 17807 Isolate* isolate = key->GetIsolate(); 17808 DCHECK(table->IsKey(isolate, *key)); 17809 int entry = table->FindEntry(key); 17810 // Key is already in table, just overwrite value. 17811 if (entry != kNotFound) { 17812 table->set(EntryToValueIndex(entry), *value); 17813 return table; 17814 } 17815 17816 Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key); 17817 17818 // Check whether the hash table should be extended. 17819 table = EnsureCapacity(table, 1, key, TENURED); 17820 17821 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value); 17822 return table; 17823 } 17824 17825 17826 void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell, 17827 Handle<HeapObject> value) { 17828 DisallowHeapAllocation no_allocation; 17829 set(EntryToIndex(entry), *key_cell); 17830 set(EntryToValueIndex(entry), *value); 17831 ElementAdded(); 17832 } 17833 17834 17835 template<class Derived, class Iterator, int entrysize> 17836 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate( 17837 Isolate* isolate, int capacity, PretenureFlag pretenure) { 17838 // Capacity must be a power of two, since we depend on being able 17839 // to divide and multiple by 2 (kLoadFactor) to derive capacity 17840 // from number of buckets. If we decide to change kLoadFactor 17841 // to something other than 2, capacity should be stored as another 17842 // field of this object. 17843 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity)); 17844 if (capacity > kMaxCapacity) { 17845 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true); 17846 } 17847 int num_buckets = capacity / kLoadFactor; 17848 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray( 17849 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure); 17850 backing_store->set_map_no_write_barrier( 17851 isolate->heap()->ordered_hash_table_map()); 17852 Handle<Derived> table = Handle<Derived>::cast(backing_store); 17853 for (int i = 0; i < num_buckets; ++i) { 17854 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound)); 17855 } 17856 table->SetNumberOfBuckets(num_buckets); 17857 table->SetNumberOfElements(0); 17858 table->SetNumberOfDeletedElements(0); 17859 return table; 17860 } 17861 17862 17863 template<class Derived, class Iterator, int entrysize> 17864 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable( 17865 Handle<Derived> table) { 17866 DCHECK(!table->IsObsolete()); 17867 17868 int nof = table->NumberOfElements(); 17869 int nod = table->NumberOfDeletedElements(); 17870 int capacity = table->Capacity(); 17871 if ((nof + nod) < capacity) return table; 17872 // Don't need to grow if we can simply clear out deleted entries instead. 17873 // Note that we can't compact in place, though, so we always allocate 17874 // a new table. 17875 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity); 17876 } 17877 17878 17879 template<class Derived, class Iterator, int entrysize> 17880 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink( 17881 Handle<Derived> table) { 17882 DCHECK(!table->IsObsolete()); 17883 17884 int nof = table->NumberOfElements(); 17885 int capacity = table->Capacity(); 17886 if (nof >= (capacity >> 2)) return table; 17887 return Rehash(table, capacity / 2); 17888 } 17889 17890 17891 template<class Derived, class Iterator, int entrysize> 17892 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear( 17893 Handle<Derived> table) { 17894 DCHECK(!table->IsObsolete()); 17895 17896 Handle<Derived> new_table = 17897 Allocate(table->GetIsolate(), 17898 kMinCapacity, 17899 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED); 17900 17901 table->SetNextTable(*new_table); 17902 table->SetNumberOfDeletedElements(kClearedTableSentinel); 17903 17904 return new_table; 17905 } 17906 17907 template <class Derived, class Iterator, int entrysize> 17908 bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey( 17909 Handle<Derived> table, Handle<Object> key) { 17910 DisallowHeapAllocation no_gc; 17911 Isolate* isolate = table->GetIsolate(); 17912 Object* raw_key = *key; 17913 int entry = table->KeyToFirstEntry(isolate, raw_key); 17914 // Walk the chain in the bucket to find the key. 17915 while (entry != kNotFound) { 17916 Object* candidate_key = table->KeyAt(entry); 17917 if (candidate_key->SameValueZero(raw_key)) return true; 17918 entry = table->NextChainEntry(entry); 17919 } 17920 return false; 17921 } 17922 17923 17924 Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table, 17925 Handle<Object> key) { 17926 int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value(); 17927 int entry = table->HashToEntry(hash); 17928 // Walk the chain of the bucket and try finding the key. 17929 while (entry != kNotFound) { 17930 Object* candidate_key = table->KeyAt(entry); 17931 // Do not add if we have the key already 17932 if (candidate_key->SameValueZero(*key)) return table; 17933 entry = table->NextChainEntry(entry); 17934 } 17935 17936 table = OrderedHashSet::EnsureGrowable(table); 17937 // Read the existing bucket values. 17938 int bucket = table->HashToBucket(hash); 17939 int previous_entry = table->HashToEntry(hash); 17940 int nof = table->NumberOfElements(); 17941 // Insert a new entry at the end, 17942 int new_entry = nof + table->NumberOfDeletedElements(); 17943 int new_index = table->EntryToIndex(new_entry); 17944 table->set(new_index, *key); 17945 table->set(new_index + kChainOffset, Smi::FromInt(previous_entry)); 17946 // and point the bucket to the new entry. 17947 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); 17948 table->SetNumberOfElements(nof + 1); 17949 return table; 17950 } 17951 17952 Handle<FixedArray> OrderedHashSet::ConvertToKeysArray( 17953 Handle<OrderedHashSet> table, GetKeysConversion convert) { 17954 Isolate* isolate = table->GetIsolate(); 17955 int length = table->NumberOfElements(); 17956 int nof_buckets = table->NumberOfBuckets(); 17957 // Convert the dictionary to a linear list. 17958 Handle<FixedArray> result = Handle<FixedArray>::cast(table); 17959 // From this point on table is no longer a valid OrderedHashSet. 17960 result->set_map(isolate->heap()->fixed_array_map()); 17961 for (int i = 0; i < length; i++) { 17962 int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize); 17963 Object* key = table->get(index); 17964 if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) { 17965 key = *isolate->factory()->NumberToString(handle(key, isolate)); 17966 } 17967 result->set(i, key); 17968 } 17969 result->Shrink(length); 17970 return result; 17971 } 17972 17973 template<class Derived, class Iterator, int entrysize> 17974 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash( 17975 Handle<Derived> table, int new_capacity) { 17976 Isolate* isolate = table->GetIsolate(); 17977 DCHECK(!table->IsObsolete()); 17978 17979 Handle<Derived> new_table = 17980 Allocate(isolate, new_capacity, 17981 isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED); 17982 int nof = table->NumberOfElements(); 17983 int nod = table->NumberOfDeletedElements(); 17984 int new_buckets = new_table->NumberOfBuckets(); 17985 int new_entry = 0; 17986 int removed_holes_index = 0; 17987 17988 DisallowHeapAllocation no_gc; 17989 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) { 17990 Object* key = table->KeyAt(old_entry); 17991 if (key->IsTheHole(isolate)) { 17992 table->SetRemovedIndexAt(removed_holes_index++, old_entry); 17993 continue; 17994 } 17995 17996 Object* hash = key->GetHash(); 17997 int bucket = Smi::cast(hash)->value() & (new_buckets - 1); 17998 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket); 17999 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); 18000 int new_index = new_table->EntryToIndex(new_entry); 18001 int old_index = table->EntryToIndex(old_entry); 18002 for (int i = 0; i < entrysize; ++i) { 18003 Object* value = table->get(old_index + i); 18004 new_table->set(new_index + i, value); 18005 } 18006 new_table->set(new_index + kChainOffset, chain_entry); 18007 ++new_entry; 18008 } 18009 18010 DCHECK_EQ(nod, removed_holes_index); 18011 18012 new_table->SetNumberOfElements(nof); 18013 table->SetNextTable(*new_table); 18014 18015 return new_table; 18016 } 18017 18018 18019 template Handle<OrderedHashSet> 18020 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate( 18021 Isolate* isolate, int capacity, PretenureFlag pretenure); 18022 18023 template Handle<OrderedHashSet> 18024 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable( 18025 Handle<OrderedHashSet> table); 18026 18027 template Handle<OrderedHashSet> 18028 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink( 18029 Handle<OrderedHashSet> table); 18030 18031 template Handle<OrderedHashSet> 18032 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear( 18033 Handle<OrderedHashSet> table); 18034 18035 template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey( 18036 Handle<OrderedHashSet> table, Handle<Object> key); 18037 18038 18039 template Handle<OrderedHashMap> 18040 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate( 18041 Isolate* isolate, int capacity, PretenureFlag pretenure); 18042 18043 template Handle<OrderedHashMap> 18044 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable( 18045 Handle<OrderedHashMap> table); 18046 18047 template Handle<OrderedHashMap> 18048 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink( 18049 Handle<OrderedHashMap> table); 18050 18051 template Handle<OrderedHashMap> 18052 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear( 18053 Handle<OrderedHashMap> table); 18054 18055 template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey( 18056 Handle<OrderedHashMap> table, Handle<Object> key); 18057 18058 18059 template<class Derived, class TableType> 18060 void OrderedHashTableIterator<Derived, TableType>::Transition() { 18061 DisallowHeapAllocation no_allocation; 18062 TableType* table = TableType::cast(this->table()); 18063 if (!table->IsObsolete()) return; 18064 18065 int index = Smi::cast(this->index())->value(); 18066 while (table->IsObsolete()) { 18067 TableType* next_table = table->NextTable(); 18068 18069 if (index > 0) { 18070 int nod = table->NumberOfDeletedElements(); 18071 18072 if (nod == TableType::kClearedTableSentinel) { 18073 index = 0; 18074 } else { 18075 int old_index = index; 18076 for (int i = 0; i < nod; ++i) { 18077 int removed_index = table->RemovedIndexAt(i); 18078 if (removed_index >= old_index) break; 18079 --index; 18080 } 18081 } 18082 } 18083 18084 table = next_table; 18085 } 18086 18087 set_table(table); 18088 set_index(Smi::FromInt(index)); 18089 } 18090 18091 18092 template<class Derived, class TableType> 18093 bool OrderedHashTableIterator<Derived, TableType>::HasMore() { 18094 DisallowHeapAllocation no_allocation; 18095 Isolate* isolate = this->GetIsolate(); 18096 if (this->table()->IsUndefined(isolate)) return false; 18097 18098 Transition(); 18099 18100 TableType* table = TableType::cast(this->table()); 18101 int index = Smi::cast(this->index())->value(); 18102 int used_capacity = table->UsedCapacity(); 18103 18104 while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) { 18105 index++; 18106 } 18107 18108 set_index(Smi::FromInt(index)); 18109 18110 if (index < used_capacity) return true; 18111 18112 set_table(isolate->heap()->undefined_value()); 18113 return false; 18114 } 18115 18116 18117 template<class Derived, class TableType> 18118 Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) { 18119 DisallowHeapAllocation no_allocation; 18120 if (HasMore()) { 18121 FixedArray* array = FixedArray::cast(value_array->elements()); 18122 static_cast<Derived*>(this)->PopulateValueArray(array); 18123 MoveNext(); 18124 return Smi::cast(kind()); 18125 } 18126 return Smi::FromInt(0); 18127 } 18128 18129 18130 template Smi* 18131 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next( 18132 JSArray* value_array); 18133 18134 template bool 18135 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore(); 18136 18137 template void 18138 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext(); 18139 18140 template Object* 18141 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey(); 18142 18143 template void 18144 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition(); 18145 18146 18147 template Smi* 18148 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next( 18149 JSArray* value_array); 18150 18151 template bool 18152 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore(); 18153 18154 template void 18155 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext(); 18156 18157 template Object* 18158 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey(); 18159 18160 template void 18161 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition(); 18162 18163 18164 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) { 18165 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet(); 18166 set->set_table(*table); 18167 } 18168 18169 18170 void JSSet::Clear(Handle<JSSet> set) { 18171 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); 18172 table = OrderedHashSet::Clear(table); 18173 set->set_table(*table); 18174 } 18175 18176 18177 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) { 18178 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap(); 18179 map->set_table(*table); 18180 } 18181 18182 18183 void JSMap::Clear(Handle<JSMap> map) { 18184 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); 18185 table = OrderedHashMap::Clear(table); 18186 map->set_table(*table); 18187 } 18188 18189 18190 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection, 18191 Isolate* isolate) { 18192 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0); 18193 weak_collection->set_table(*table); 18194 } 18195 18196 18197 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection, 18198 Handle<Object> key, Handle<Object> value, 18199 int32_t hash) { 18200 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 18201 Handle<ObjectHashTable> table( 18202 ObjectHashTable::cast(weak_collection->table())); 18203 DCHECK(table->IsKey(*key)); 18204 Handle<ObjectHashTable> new_table = 18205 ObjectHashTable::Put(table, key, value, hash); 18206 weak_collection->set_table(*new_table); 18207 if (*table != *new_table) { 18208 // Zap the old table since we didn't record slots for its elements. 18209 table->FillWithHoles(0, table->length()); 18210 } 18211 } 18212 18213 18214 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection, 18215 Handle<Object> key, int32_t hash) { 18216 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 18217 Handle<ObjectHashTable> table( 18218 ObjectHashTable::cast(weak_collection->table())); 18219 DCHECK(table->IsKey(*key)); 18220 bool was_present = false; 18221 Handle<ObjectHashTable> new_table = 18222 ObjectHashTable::Remove(table, key, &was_present, hash); 18223 weak_collection->set_table(*new_table); 18224 if (*table != *new_table) { 18225 // Zap the old table since we didn't record slots for its elements. 18226 table->FillWithHoles(0, table->length()); 18227 } 18228 return was_present; 18229 } 18230 18231 // Check if there is a break point at this code offset. 18232 bool DebugInfo::HasBreakPoint(int code_offset) { 18233 // Get the break point info object for this code offset. 18234 Object* break_point_info = GetBreakPointInfo(code_offset); 18235 18236 // If there is no break point info object or no break points in the break 18237 // point info object there is no break point at this code offset. 18238 if (break_point_info->IsUndefined(GetIsolate())) return false; 18239 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0; 18240 } 18241 18242 // Get the break point info object for this code offset. 18243 Object* DebugInfo::GetBreakPointInfo(int code_offset) { 18244 // Find the index of the break point info object for this code offset. 18245 int index = GetBreakPointInfoIndex(code_offset); 18246 18247 // Return the break point info object if any. 18248 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value(); 18249 return BreakPointInfo::cast(break_points()->get(index)); 18250 } 18251 18252 // Clear a break point at the specified code offset. 18253 void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, int code_offset, 18254 Handle<Object> break_point_object) { 18255 Isolate* isolate = debug_info->GetIsolate(); 18256 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset), 18257 isolate); 18258 if (break_point_info->IsUndefined(isolate)) return; 18259 BreakPointInfo::ClearBreakPoint( 18260 Handle<BreakPointInfo>::cast(break_point_info), 18261 break_point_object); 18262 } 18263 18264 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int code_offset, 18265 int source_position, int statement_position, 18266 Handle<Object> break_point_object) { 18267 Isolate* isolate = debug_info->GetIsolate(); 18268 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset), 18269 isolate); 18270 if (!break_point_info->IsUndefined(isolate)) { 18271 BreakPointInfo::SetBreakPoint( 18272 Handle<BreakPointInfo>::cast(break_point_info), 18273 break_point_object); 18274 return; 18275 } 18276 18277 // Adding a new break point for a code offset which did not have any 18278 // break points before. Try to find a free slot. 18279 int index = kNoBreakPointInfo; 18280 for (int i = 0; i < debug_info->break_points()->length(); i++) { 18281 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) { 18282 index = i; 18283 break; 18284 } 18285 } 18286 if (index == kNoBreakPointInfo) { 18287 // No free slot - extend break point info array. 18288 Handle<FixedArray> old_break_points = Handle<FixedArray>( 18289 FixedArray::cast(debug_info->break_points()), isolate); 18290 Handle<FixedArray> new_break_points = 18291 isolate->factory()->NewFixedArray( 18292 old_break_points->length() + 18293 DebugInfo::kEstimatedNofBreakPointsInFunction); 18294 18295 debug_info->set_break_points(*new_break_points); 18296 for (int i = 0; i < old_break_points->length(); i++) { 18297 new_break_points->set(i, old_break_points->get(i)); 18298 } 18299 index = old_break_points->length(); 18300 } 18301 DCHECK(index != kNoBreakPointInfo); 18302 18303 // Allocate new BreakPointInfo object and set the break point. 18304 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast( 18305 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE)); 18306 new_break_point_info->set_code_offset(code_offset); 18307 new_break_point_info->set_source_position(source_position); 18308 new_break_point_info->set_statement_position(statement_position); 18309 new_break_point_info->set_break_point_objects( 18310 isolate->heap()->undefined_value()); 18311 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object); 18312 debug_info->break_points()->set(index, *new_break_point_info); 18313 } 18314 18315 // Get the break point objects for a code offset. 18316 Handle<Object> DebugInfo::GetBreakPointObjects(int code_offset) { 18317 Object* break_point_info = GetBreakPointInfo(code_offset); 18318 Isolate* isolate = GetIsolate(); 18319 if (break_point_info->IsUndefined(isolate)) { 18320 return isolate->factory()->undefined_value(); 18321 } 18322 return Handle<Object>( 18323 BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate); 18324 } 18325 18326 18327 // Get the total number of break points. 18328 int DebugInfo::GetBreakPointCount() { 18329 Isolate* isolate = GetIsolate(); 18330 if (break_points()->IsUndefined(isolate)) return 0; 18331 int count = 0; 18332 for (int i = 0; i < break_points()->length(); i++) { 18333 if (!break_points()->get(i)->IsUndefined(isolate)) { 18334 BreakPointInfo* break_point_info = 18335 BreakPointInfo::cast(break_points()->get(i)); 18336 count += break_point_info->GetBreakPointCount(); 18337 } 18338 } 18339 return count; 18340 } 18341 18342 18343 Handle<Object> DebugInfo::FindBreakPointInfo( 18344 Handle<DebugInfo> debug_info, Handle<Object> break_point_object) { 18345 Isolate* isolate = debug_info->GetIsolate(); 18346 if (!debug_info->break_points()->IsUndefined(isolate)) { 18347 for (int i = 0; i < debug_info->break_points()->length(); i++) { 18348 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { 18349 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>( 18350 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate); 18351 if (BreakPointInfo::HasBreakPointObject(break_point_info, 18352 break_point_object)) { 18353 return break_point_info; 18354 } 18355 } 18356 } 18357 } 18358 return isolate->factory()->undefined_value(); 18359 } 18360 18361 18362 // Find the index of the break point info object for the specified code 18363 // position. 18364 int DebugInfo::GetBreakPointInfoIndex(int code_offset) { 18365 Isolate* isolate = GetIsolate(); 18366 if (break_points()->IsUndefined(isolate)) return kNoBreakPointInfo; 18367 for (int i = 0; i < break_points()->length(); i++) { 18368 if (!break_points()->get(i)->IsUndefined(isolate)) { 18369 BreakPointInfo* break_point_info = 18370 BreakPointInfo::cast(break_points()->get(i)); 18371 if (break_point_info->code_offset() == code_offset) { 18372 return i; 18373 } 18374 } 18375 } 18376 return kNoBreakPointInfo; 18377 } 18378 18379 18380 // Remove the specified break point object. 18381 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, 18382 Handle<Object> break_point_object) { 18383 Isolate* isolate = break_point_info->GetIsolate(); 18384 // If there are no break points just ignore. 18385 if (break_point_info->break_point_objects()->IsUndefined(isolate)) return; 18386 // If there is a single break point clear it if it is the same. 18387 if (!break_point_info->break_point_objects()->IsFixedArray()) { 18388 if (break_point_info->break_point_objects() == *break_point_object) { 18389 break_point_info->set_break_point_objects( 18390 isolate->heap()->undefined_value()); 18391 } 18392 return; 18393 } 18394 // If there are multiple break points shrink the array 18395 DCHECK(break_point_info->break_point_objects()->IsFixedArray()); 18396 Handle<FixedArray> old_array = 18397 Handle<FixedArray>( 18398 FixedArray::cast(break_point_info->break_point_objects())); 18399 Handle<FixedArray> new_array = 18400 isolate->factory()->NewFixedArray(old_array->length() - 1); 18401 int found_count = 0; 18402 for (int i = 0; i < old_array->length(); i++) { 18403 if (old_array->get(i) == *break_point_object) { 18404 DCHECK(found_count == 0); 18405 found_count++; 18406 } else { 18407 new_array->set(i - found_count, old_array->get(i)); 18408 } 18409 } 18410 // If the break point was found in the list change it. 18411 if (found_count > 0) break_point_info->set_break_point_objects(*new_array); 18412 } 18413 18414 18415 // Add the specified break point object. 18416 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info, 18417 Handle<Object> break_point_object) { 18418 Isolate* isolate = break_point_info->GetIsolate(); 18419 18420 // If there was no break point objects before just set it. 18421 if (break_point_info->break_point_objects()->IsUndefined(isolate)) { 18422 break_point_info->set_break_point_objects(*break_point_object); 18423 return; 18424 } 18425 // If the break point object is the same as before just ignore. 18426 if (break_point_info->break_point_objects() == *break_point_object) return; 18427 // If there was one break point object before replace with array. 18428 if (!break_point_info->break_point_objects()->IsFixedArray()) { 18429 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2); 18430 array->set(0, break_point_info->break_point_objects()); 18431 array->set(1, *break_point_object); 18432 break_point_info->set_break_point_objects(*array); 18433 return; 18434 } 18435 // If there was more than one break point before extend array. 18436 Handle<FixedArray> old_array = 18437 Handle<FixedArray>( 18438 FixedArray::cast(break_point_info->break_point_objects())); 18439 Handle<FixedArray> new_array = 18440 isolate->factory()->NewFixedArray(old_array->length() + 1); 18441 for (int i = 0; i < old_array->length(); i++) { 18442 // If the break point was there before just ignore. 18443 if (old_array->get(i) == *break_point_object) return; 18444 new_array->set(i, old_array->get(i)); 18445 } 18446 // Add the new break point. 18447 new_array->set(old_array->length(), *break_point_object); 18448 break_point_info->set_break_point_objects(*new_array); 18449 } 18450 18451 18452 bool BreakPointInfo::HasBreakPointObject( 18453 Handle<BreakPointInfo> break_point_info, 18454 Handle<Object> break_point_object) { 18455 // No break point. 18456 Isolate* isolate = break_point_info->GetIsolate(); 18457 if (break_point_info->break_point_objects()->IsUndefined(isolate)) { 18458 return false; 18459 } 18460 // Single break point. 18461 if (!break_point_info->break_point_objects()->IsFixedArray()) { 18462 return break_point_info->break_point_objects() == *break_point_object; 18463 } 18464 // Multiple break points. 18465 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects()); 18466 for (int i = 0; i < array->length(); i++) { 18467 if (array->get(i) == *break_point_object) { 18468 return true; 18469 } 18470 } 18471 return false; 18472 } 18473 18474 18475 // Get the number of break points. 18476 int BreakPointInfo::GetBreakPointCount() { 18477 // No break point. 18478 if (break_point_objects()->IsUndefined(GetIsolate())) return 0; 18479 // Single break point. 18480 if (!break_point_objects()->IsFixedArray()) return 1; 18481 // Multiple break points. 18482 return FixedArray::cast(break_point_objects())->length(); 18483 } 18484 18485 18486 // static 18487 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor, 18488 Handle<JSReceiver> new_target, double tv) { 18489 Isolate* const isolate = constructor->GetIsolate(); 18490 Handle<JSObject> result; 18491 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 18492 JSObject::New(constructor, new_target), JSDate); 18493 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) { 18494 tv = DoubleToInteger(tv) + 0.0; 18495 } else { 18496 tv = std::numeric_limits<double>::quiet_NaN(); 18497 } 18498 Handle<Object> value = isolate->factory()->NewNumber(tv); 18499 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv)); 18500 return Handle<JSDate>::cast(result); 18501 } 18502 18503 18504 // static 18505 double JSDate::CurrentTimeValue(Isolate* isolate) { 18506 if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent()); 18507 18508 // According to ECMA-262, section 15.9.1, page 117, the precision of 18509 // the number in a Date object representing a particular instant in 18510 // time is milliseconds. Therefore, we floor the result of getting 18511 // the OS time. 18512 return Floor(FLAG_verify_predictable 18513 ? isolate->heap()->MonotonicallyIncreasingTimeInMs() 18514 : base::OS::TimeCurrentMillis()); 18515 } 18516 18517 18518 // static 18519 Object* JSDate::GetField(Object* object, Smi* index) { 18520 return JSDate::cast(object)->DoGetField( 18521 static_cast<FieldIndex>(index->value())); 18522 } 18523 18524 18525 Object* JSDate::DoGetField(FieldIndex index) { 18526 DCHECK(index != kDateValue); 18527 18528 DateCache* date_cache = GetIsolate()->date_cache(); 18529 18530 if (index < kFirstUncachedField) { 18531 Object* stamp = cache_stamp(); 18532 if (stamp != date_cache->stamp() && stamp->IsSmi()) { 18533 // Since the stamp is not NaN, the value is also not NaN. 18534 int64_t local_time_ms = 18535 date_cache->ToLocal(static_cast<int64_t>(value()->Number())); 18536 SetCachedFields(local_time_ms, date_cache); 18537 } 18538 switch (index) { 18539 case kYear: return year(); 18540 case kMonth: return month(); 18541 case kDay: return day(); 18542 case kWeekday: return weekday(); 18543 case kHour: return hour(); 18544 case kMinute: return min(); 18545 case kSecond: return sec(); 18546 default: UNREACHABLE(); 18547 } 18548 } 18549 18550 if (index >= kFirstUTCField) { 18551 return GetUTCField(index, value()->Number(), date_cache); 18552 } 18553 18554 double time = value()->Number(); 18555 if (std::isnan(time)) return GetIsolate()->heap()->nan_value(); 18556 18557 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time)); 18558 int days = DateCache::DaysFromTime(local_time_ms); 18559 18560 if (index == kDays) return Smi::FromInt(days); 18561 18562 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days); 18563 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000); 18564 DCHECK(index == kTimeInDay); 18565 return Smi::FromInt(time_in_day_ms); 18566 } 18567 18568 18569 Object* JSDate::GetUTCField(FieldIndex index, 18570 double value, 18571 DateCache* date_cache) { 18572 DCHECK(index >= kFirstUTCField); 18573 18574 if (std::isnan(value)) return GetIsolate()->heap()->nan_value(); 18575 18576 int64_t time_ms = static_cast<int64_t>(value); 18577 18578 if (index == kTimezoneOffset) { 18579 return Smi::FromInt(date_cache->TimezoneOffset(time_ms)); 18580 } 18581 18582 int days = DateCache::DaysFromTime(time_ms); 18583 18584 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days)); 18585 18586 if (index <= kDayUTC) { 18587 int year, month, day; 18588 date_cache->YearMonthDayFromDays(days, &year, &month, &day); 18589 if (index == kYearUTC) return Smi::FromInt(year); 18590 if (index == kMonthUTC) return Smi::FromInt(month); 18591 DCHECK(index == kDayUTC); 18592 return Smi::FromInt(day); 18593 } 18594 18595 int time_in_day_ms = DateCache::TimeInDay(time_ms, days); 18596 switch (index) { 18597 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000)); 18598 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60); 18599 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60); 18600 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000); 18601 case kDaysUTC: return Smi::FromInt(days); 18602 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms); 18603 default: UNREACHABLE(); 18604 } 18605 18606 UNREACHABLE(); 18607 return NULL; 18608 } 18609 18610 18611 // static 18612 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) { 18613 Isolate* const isolate = date->GetIsolate(); 18614 Handle<Object> value = isolate->factory()->NewNumber(v); 18615 bool value_is_nan = std::isnan(v); 18616 date->SetValue(*value, value_is_nan); 18617 return value; 18618 } 18619 18620 18621 void JSDate::SetValue(Object* value, bool is_value_nan) { 18622 set_value(value); 18623 if (is_value_nan) { 18624 HeapNumber* nan = GetIsolate()->heap()->nan_value(); 18625 set_cache_stamp(nan, SKIP_WRITE_BARRIER); 18626 set_year(nan, SKIP_WRITE_BARRIER); 18627 set_month(nan, SKIP_WRITE_BARRIER); 18628 set_day(nan, SKIP_WRITE_BARRIER); 18629 set_hour(nan, SKIP_WRITE_BARRIER); 18630 set_min(nan, SKIP_WRITE_BARRIER); 18631 set_sec(nan, SKIP_WRITE_BARRIER); 18632 set_weekday(nan, SKIP_WRITE_BARRIER); 18633 } else { 18634 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER); 18635 } 18636 } 18637 18638 18639 // static 18640 MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver, 18641 Handle<Object> hint) { 18642 Isolate* const isolate = receiver->GetIsolate(); 18643 if (hint->IsString()) { 18644 Handle<String> hint_string = Handle<String>::cast(hint); 18645 if (hint_string->Equals(isolate->heap()->number_string())) { 18646 return JSReceiver::OrdinaryToPrimitive(receiver, 18647 OrdinaryToPrimitiveHint::kNumber); 18648 } 18649 if (hint_string->Equals(isolate->heap()->default_string()) || 18650 hint_string->Equals(isolate->heap()->string_string())) { 18651 return JSReceiver::OrdinaryToPrimitive(receiver, 18652 OrdinaryToPrimitiveHint::kString); 18653 } 18654 } 18655 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint), 18656 Object); 18657 } 18658 18659 18660 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) { 18661 int days = DateCache::DaysFromTime(local_time_ms); 18662 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days); 18663 int year, month, day; 18664 date_cache->YearMonthDayFromDays(days, &year, &month, &day); 18665 int weekday = date_cache->Weekday(days); 18666 int hour = time_in_day_ms / (60 * 60 * 1000); 18667 int min = (time_in_day_ms / (60 * 1000)) % 60; 18668 int sec = (time_in_day_ms / 1000) % 60; 18669 set_cache_stamp(date_cache->stamp()); 18670 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 18671 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 18672 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 18673 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 18674 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 18675 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 18676 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 18677 } 18678 18679 18680 void JSArrayBuffer::Neuter() { 18681 CHECK(is_neuterable()); 18682 CHECK(is_external()); 18683 set_backing_store(NULL); 18684 set_byte_length(Smi::FromInt(0)); 18685 set_was_neutered(true); 18686 } 18687 18688 18689 void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate, 18690 bool is_external, void* data, size_t allocated_length, 18691 SharedFlag shared) { 18692 DCHECK(array_buffer->GetInternalFieldCount() == 18693 v8::ArrayBuffer::kInternalFieldCount); 18694 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { 18695 array_buffer->SetInternalField(i, Smi::FromInt(0)); 18696 } 18697 array_buffer->set_bit_field(0); 18698 array_buffer->set_is_external(is_external); 18699 array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared); 18700 array_buffer->set_is_shared(shared == SharedFlag::kShared); 18701 18702 Handle<Object> byte_length = 18703 isolate->factory()->NewNumberFromSize(allocated_length); 18704 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); 18705 array_buffer->set_byte_length(*byte_length); 18706 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that 18707 // are currently being constructed in the |ArrayBufferTracker|. The 18708 // registration method below handles the case of registering a buffer that has 18709 // already been promoted. 18710 array_buffer->set_backing_store(data); 18711 18712 if (data && !is_external) { 18713 isolate->heap()->RegisterNewArrayBuffer(*array_buffer); 18714 } 18715 } 18716 18717 18718 bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer, 18719 Isolate* isolate, 18720 size_t allocated_length, 18721 bool initialize, SharedFlag shared) { 18722 void* data; 18723 CHECK(isolate->array_buffer_allocator() != NULL); 18724 // Prevent creating array buffers when serializing. 18725 DCHECK(!isolate->serializer_enabled()); 18726 if (allocated_length != 0) { 18727 if (initialize) { 18728 data = isolate->array_buffer_allocator()->Allocate(allocated_length); 18729 } else { 18730 data = isolate->array_buffer_allocator()->AllocateUninitialized( 18731 allocated_length); 18732 } 18733 if (data == NULL) return false; 18734 } else { 18735 data = NULL; 18736 } 18737 18738 JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length, 18739 shared); 18740 return true; 18741 } 18742 18743 18744 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer( 18745 Handle<JSTypedArray> typed_array) { 18746 18747 Handle<Map> map(typed_array->map()); 18748 Isolate* isolate = typed_array->GetIsolate(); 18749 18750 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind())); 18751 18752 Handle<FixedTypedArrayBase> fixed_typed_array( 18753 FixedTypedArrayBase::cast(typed_array->elements())); 18754 18755 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()), 18756 isolate); 18757 void* backing_store = 18758 isolate->array_buffer_allocator()->AllocateUninitialized( 18759 fixed_typed_array->DataSize()); 18760 buffer->set_is_external(false); 18761 DCHECK(buffer->byte_length()->IsSmi() || 18762 buffer->byte_length()->IsHeapNumber()); 18763 DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize()); 18764 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that 18765 // are currently being constructed in the |ArrayBufferTracker|. The 18766 // registration method below handles the case of registering a buffer that has 18767 // already been promoted. 18768 buffer->set_backing_store(backing_store); 18769 isolate->heap()->RegisterNewArrayBuffer(*buffer); 18770 memcpy(buffer->backing_store(), 18771 fixed_typed_array->DataPtr(), 18772 fixed_typed_array->DataSize()); 18773 Handle<FixedTypedArrayBase> new_elements = 18774 isolate->factory()->NewFixedTypedArrayWithExternalPointer( 18775 fixed_typed_array->length(), typed_array->type(), 18776 static_cast<uint8_t*>(buffer->backing_store())); 18777 18778 typed_array->set_elements(*new_elements); 18779 18780 return buffer; 18781 } 18782 18783 18784 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() { 18785 Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()), 18786 GetIsolate()); 18787 if (array_buffer->was_neutered() || 18788 array_buffer->backing_store() != nullptr) { 18789 return array_buffer; 18790 } 18791 Handle<JSTypedArray> self(this); 18792 return MaterializeArrayBuffer(self); 18793 } 18794 18795 18796 Handle<PropertyCell> PropertyCell::InvalidateEntry( 18797 Handle<GlobalDictionary> dictionary, int entry) { 18798 Isolate* isolate = dictionary->GetIsolate(); 18799 // Swap with a copy. 18800 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 18801 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry))); 18802 auto new_cell = isolate->factory()->NewPropertyCell(); 18803 new_cell->set_value(cell->value()); 18804 dictionary->ValueAtPut(entry, *new_cell); 18805 bool is_the_hole = cell->value()->IsTheHole(isolate); 18806 // Cell is officially mutable henceforth. 18807 PropertyDetails details = cell->property_details(); 18808 details = details.set_cell_type(is_the_hole ? PropertyCellType::kInvalidated 18809 : PropertyCellType::kMutable); 18810 new_cell->set_property_details(details); 18811 // Old cell is ready for invalidation. 18812 if (is_the_hole) { 18813 cell->set_value(isolate->heap()->undefined_value()); 18814 } else { 18815 cell->set_value(isolate->heap()->the_hole_value()); 18816 } 18817 details = details.set_cell_type(PropertyCellType::kInvalidated); 18818 cell->set_property_details(details); 18819 cell->dependent_code()->DeoptimizeDependentCodeGroup( 18820 isolate, DependentCode::kPropertyCellChangedGroup); 18821 return new_cell; 18822 } 18823 18824 18825 PropertyCellConstantType PropertyCell::GetConstantType() { 18826 if (value()->IsSmi()) return PropertyCellConstantType::kSmi; 18827 return PropertyCellConstantType::kStableMap; 18828 } 18829 18830 18831 static bool RemainsConstantType(Handle<PropertyCell> cell, 18832 Handle<Object> value) { 18833 // TODO(dcarney): double->smi and smi->double transition from kConstant 18834 if (cell->value()->IsSmi() && value->IsSmi()) { 18835 return true; 18836 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) { 18837 return HeapObject::cast(cell->value())->map() == 18838 HeapObject::cast(*value)->map() && 18839 HeapObject::cast(*value)->map()->is_stable(); 18840 } 18841 return false; 18842 } 18843 18844 18845 PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell, 18846 Handle<Object> value, 18847 PropertyDetails details) { 18848 PropertyCellType type = details.cell_type(); 18849 Isolate* isolate = cell->GetIsolate(); 18850 DCHECK(!value->IsTheHole(isolate)); 18851 if (cell->value()->IsTheHole(isolate)) { 18852 switch (type) { 18853 // Only allow a cell to transition once into constant state. 18854 case PropertyCellType::kUninitialized: 18855 if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined; 18856 return PropertyCellType::kConstant; 18857 case PropertyCellType::kInvalidated: 18858 return PropertyCellType::kMutable; 18859 default: 18860 UNREACHABLE(); 18861 return PropertyCellType::kMutable; 18862 } 18863 } 18864 switch (type) { 18865 case PropertyCellType::kUndefined: 18866 return PropertyCellType::kConstant; 18867 case PropertyCellType::kConstant: 18868 if (*value == cell->value()) return PropertyCellType::kConstant; 18869 // Fall through. 18870 case PropertyCellType::kConstantType: 18871 if (RemainsConstantType(cell, value)) { 18872 return PropertyCellType::kConstantType; 18873 } 18874 // Fall through. 18875 case PropertyCellType::kMutable: 18876 return PropertyCellType::kMutable; 18877 } 18878 UNREACHABLE(); 18879 return PropertyCellType::kMutable; 18880 } 18881 18882 18883 void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry, 18884 Handle<Object> value, PropertyDetails details) { 18885 Isolate* isolate = dictionary->GetIsolate(); 18886 DCHECK(!value->IsTheHole(isolate)); 18887 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 18888 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry))); 18889 const PropertyDetails original_details = cell->property_details(); 18890 // Data accesses could be cached in ics or optimized code. 18891 bool invalidate = 18892 original_details.kind() == kData && details.kind() == kAccessor; 18893 int index = original_details.dictionary_index(); 18894 PropertyCellType old_type = original_details.cell_type(); 18895 // Preserve the enumeration index unless the property was deleted or never 18896 // initialized. 18897 if (cell->value()->IsTheHole(isolate)) { 18898 index = dictionary->NextEnumerationIndex(); 18899 dictionary->SetNextEnumerationIndex(index + 1); 18900 // Negative lookup cells must be invalidated. 18901 invalidate = true; 18902 } 18903 DCHECK(index > 0); 18904 details = details.set_index(index); 18905 18906 PropertyCellType new_type = UpdatedType(cell, value, original_details); 18907 if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry); 18908 18909 // Install new property details and cell value. 18910 details = details.set_cell_type(new_type); 18911 cell->set_property_details(details); 18912 cell->set_value(*value); 18913 18914 // Deopt when transitioning from a constant type. 18915 if (!invalidate && (old_type != new_type || 18916 original_details.IsReadOnly() != details.IsReadOnly())) { 18917 cell->dependent_code()->DeoptimizeDependentCodeGroup( 18918 isolate, DependentCode::kPropertyCellChangedGroup); 18919 } 18920 } 18921 18922 18923 // static 18924 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, 18925 Handle<Object> new_value) { 18926 if (cell->value() != *new_value) { 18927 cell->set_value(*new_value); 18928 Isolate* isolate = cell->GetIsolate(); 18929 cell->dependent_code()->DeoptimizeDependentCodeGroup( 18930 isolate, DependentCode::kPropertyCellChangedGroup); 18931 } 18932 } 18933 18934 int JSGeneratorObject::source_position() const { 18935 CHECK(is_suspended()); 18936 if (function()->shared()->HasBytecodeArray()) { 18937 // New-style generators. 18938 int offset = Smi::cast(input_or_debug_pos())->value(); 18939 // The stored bytecode offset is relative to a different base than what 18940 // is used in the source position table, hence the subtraction. 18941 offset -= BytecodeArray::kHeaderSize - kHeapObjectTag; 18942 return function()->shared()->bytecode_array()->SourcePosition(offset); 18943 } else { 18944 // Old-style generators. 18945 int offset = continuation(); 18946 CHECK(0 <= offset && offset < function()->code()->instruction_size()); 18947 return function()->code()->SourcePosition(offset); 18948 } 18949 } 18950 18951 // static 18952 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate, 18953 Handle<JSObject> receiver) { 18954 DisallowHeapAllocation no_gc; 18955 DCHECK(receiver->map()->is_access_check_needed()); 18956 Object* maybe_constructor = receiver->map()->GetConstructor(); 18957 // Might happen for a detached context. 18958 if (!maybe_constructor->IsJSFunction()) return nullptr; 18959 JSFunction* constructor = JSFunction::cast(maybe_constructor); 18960 // Might happen for the debug context. 18961 if (!constructor->shared()->IsApiFunction()) return nullptr; 18962 18963 Object* data_obj = 18964 constructor->shared()->get_api_func_data()->access_check_info(); 18965 if (data_obj->IsUndefined(isolate)) return nullptr; 18966 18967 return AccessCheckInfo::cast(data_obj); 18968 } 18969 18970 } // namespace internal 18971 } // namespace v8 18972