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