objects-inl.h revision e46be819fca9468a0cd4e74859ce0f778eb8ca60
1// Copyright 2006-2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27// 28// Review notes: 29// 30// - The use of macros in these inline functions may seem superfluous 31// but it is absolutely needed to make sure gcc generates optimal 32// code. gcc is not happy when attempting to inline too deep. 33// 34 35#ifndef V8_OBJECTS_INL_H_ 36#define V8_OBJECTS_INL_H_ 37 38#include "objects.h" 39#include "contexts.h" 40#include "conversions-inl.h" 41#include "property.h" 42 43namespace v8 { 44namespace internal { 45 46PropertyDetails::PropertyDetails(Smi* smi) { 47 value_ = smi->value(); 48} 49 50 51Smi* PropertyDetails::AsSmi() { 52 return Smi::FromInt(value_); 53} 54 55 56PropertyDetails PropertyDetails::AsDeleted() { 57 PropertyDetails d(DONT_ENUM, NORMAL); 58 Smi* smi = Smi::FromInt(AsSmi()->value() | DeletedField::encode(1)); 59 return PropertyDetails(smi); 60} 61 62 63#define CAST_ACCESSOR(type) \ 64 type* type::cast(Object* object) { \ 65 ASSERT(object->Is##type()); \ 66 return reinterpret_cast<type*>(object); \ 67 } 68 69 70#define INT_ACCESSORS(holder, name, offset) \ 71 int holder::name() { return READ_INT_FIELD(this, offset); } \ 72 void holder::set_##name(int value) { WRITE_INT_FIELD(this, offset, value); } 73 74 75#define ACCESSORS(holder, name, type, offset) \ 76 type* holder::name() { return type::cast(READ_FIELD(this, offset)); } \ 77 void holder::set_##name(type* value, WriteBarrierMode mode) { \ 78 WRITE_FIELD(this, offset, value); \ 79 CONDITIONAL_WRITE_BARRIER(this, offset, mode); \ 80 } 81 82 83 84#define SMI_ACCESSORS(holder, name, offset) \ 85 int holder::name() { \ 86 Object* value = READ_FIELD(this, offset); \ 87 return Smi::cast(value)->value(); \ 88 } \ 89 void holder::set_##name(int value) { \ 90 WRITE_FIELD(this, offset, Smi::FromInt(value)); \ 91 } 92 93 94#define BOOL_GETTER(holder, field, name, offset) \ 95 bool holder::name() { \ 96 return BooleanBit::get(field(), offset); \ 97 } \ 98 99 100#define BOOL_ACCESSORS(holder, field, name, offset) \ 101 bool holder::name() { \ 102 return BooleanBit::get(field(), offset); \ 103 } \ 104 void holder::set_##name(bool value) { \ 105 set_##field(BooleanBit::set(field(), offset, value)); \ 106 } 107 108 109bool Object::IsInstanceOf(FunctionTemplateInfo* expected) { 110 // There is a constraint on the object; check. 111 if (!this->IsJSObject()) return false; 112 // Fetch the constructor function of the object. 113 Object* cons_obj = JSObject::cast(this)->map()->constructor(); 114 if (!cons_obj->IsJSFunction()) return false; 115 JSFunction* fun = JSFunction::cast(cons_obj); 116 // Iterate through the chain of inheriting function templates to 117 // see if the required one occurs. 118 for (Object* type = fun->shared()->function_data(); 119 type->IsFunctionTemplateInfo(); 120 type = FunctionTemplateInfo::cast(type)->parent_template()) { 121 if (type == expected) return true; 122 } 123 // Didn't find the required type in the inheritance chain. 124 return false; 125} 126 127 128bool Object::IsSmi() { 129 return HAS_SMI_TAG(this); 130} 131 132 133bool Object::IsHeapObject() { 134 return Internals::HasHeapObjectTag(this); 135} 136 137 138bool Object::IsHeapNumber() { 139 return Object::IsHeapObject() 140 && HeapObject::cast(this)->map()->instance_type() == HEAP_NUMBER_TYPE; 141} 142 143 144bool Object::IsString() { 145 return Object::IsHeapObject() 146 && HeapObject::cast(this)->map()->instance_type() < FIRST_NONSTRING_TYPE; 147} 148 149 150bool Object::IsSymbol() { 151 if (!this->IsHeapObject()) return false; 152 uint32_t type = HeapObject::cast(this)->map()->instance_type(); 153 // Because the symbol tag is non-zero and no non-string types have the 154 // symbol bit set we can test for symbols with a very simple test 155 // operation. 156 ASSERT(kSymbolTag != 0); 157 ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); 158 return (type & kIsSymbolMask) != 0; 159} 160 161 162bool Object::IsConsString() { 163 if (!this->IsHeapObject()) return false; 164 uint32_t type = HeapObject::cast(this)->map()->instance_type(); 165 return (type & (kIsNotStringMask | kStringRepresentationMask)) == 166 (kStringTag | kConsStringTag); 167} 168 169 170bool Object::IsSeqString() { 171 if (!IsString()) return false; 172 return StringShape(String::cast(this)).IsSequential(); 173} 174 175 176bool Object::IsSeqAsciiString() { 177 if (!IsString()) return false; 178 return StringShape(String::cast(this)).IsSequential() && 179 String::cast(this)->IsAsciiRepresentation(); 180} 181 182 183bool Object::IsSeqTwoByteString() { 184 if (!IsString()) return false; 185 return StringShape(String::cast(this)).IsSequential() && 186 String::cast(this)->IsTwoByteRepresentation(); 187} 188 189 190bool Object::IsExternalString() { 191 if (!IsString()) return false; 192 return StringShape(String::cast(this)).IsExternal(); 193} 194 195 196bool Object::IsExternalAsciiString() { 197 if (!IsString()) return false; 198 return StringShape(String::cast(this)).IsExternal() && 199 String::cast(this)->IsAsciiRepresentation(); 200} 201 202 203bool Object::IsExternalTwoByteString() { 204 if (!IsString()) return false; 205 return StringShape(String::cast(this)).IsExternal() && 206 String::cast(this)->IsTwoByteRepresentation(); 207} 208 209 210StringShape::StringShape(String* str) 211 : type_(str->map()->instance_type()) { 212 set_valid(); 213 ASSERT((type_ & kIsNotStringMask) == kStringTag); 214} 215 216 217StringShape::StringShape(Map* map) 218 : type_(map->instance_type()) { 219 set_valid(); 220 ASSERT((type_ & kIsNotStringMask) == kStringTag); 221} 222 223 224StringShape::StringShape(InstanceType t) 225 : type_(static_cast<uint32_t>(t)) { 226 set_valid(); 227 ASSERT((type_ & kIsNotStringMask) == kStringTag); 228} 229 230 231bool StringShape::IsSymbol() { 232 ASSERT(valid()); 233 ASSERT(kSymbolTag != 0); 234 return (type_ & kIsSymbolMask) != 0; 235} 236 237 238bool String::IsAsciiRepresentation() { 239 uint32_t type = map()->instance_type(); 240 if ((type & kStringRepresentationMask) == kConsStringTag && 241 ConsString::cast(this)->second()->length() == 0) { 242 return ConsString::cast(this)->first()->IsAsciiRepresentation(); 243 } 244 return (type & kStringEncodingMask) == kAsciiStringTag; 245} 246 247 248bool String::IsTwoByteRepresentation() { 249 uint32_t type = map()->instance_type(); 250 if ((type & kStringRepresentationMask) == kConsStringTag && 251 ConsString::cast(this)->second()->length() == 0) { 252 return ConsString::cast(this)->first()->IsTwoByteRepresentation(); 253 } 254 return (type & kStringEncodingMask) == kTwoByteStringTag; 255} 256 257 258bool StringShape::IsCons() { 259 return (type_ & kStringRepresentationMask) == kConsStringTag; 260} 261 262 263bool StringShape::IsExternal() { 264 return (type_ & kStringRepresentationMask) == kExternalStringTag; 265} 266 267 268bool StringShape::IsSequential() { 269 return (type_ & kStringRepresentationMask) == kSeqStringTag; 270} 271 272 273StringRepresentationTag StringShape::representation_tag() { 274 uint32_t tag = (type_ & kStringRepresentationMask); 275 return static_cast<StringRepresentationTag>(tag); 276} 277 278 279uint32_t StringShape::full_representation_tag() { 280 return (type_ & (kStringRepresentationMask | kStringEncodingMask)); 281} 282 283 284STATIC_CHECK((kStringRepresentationMask | kStringEncodingMask) == 285 Internals::kFullStringRepresentationMask); 286 287 288bool StringShape::IsSequentialAscii() { 289 return full_representation_tag() == (kSeqStringTag | kAsciiStringTag); 290} 291 292 293bool StringShape::IsSequentialTwoByte() { 294 return full_representation_tag() == (kSeqStringTag | kTwoByteStringTag); 295} 296 297 298bool StringShape::IsExternalAscii() { 299 return full_representation_tag() == (kExternalStringTag | kAsciiStringTag); 300} 301 302 303bool StringShape::IsExternalTwoByte() { 304 return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag); 305} 306 307 308STATIC_CHECK((kExternalStringTag | kTwoByteStringTag) == 309 Internals::kExternalTwoByteRepresentationTag); 310 311 312uc32 FlatStringReader::Get(int index) { 313 ASSERT(0 <= index && index <= length_); 314 if (is_ascii_) { 315 return static_cast<const byte*>(start_)[index]; 316 } else { 317 return static_cast<const uc16*>(start_)[index]; 318 } 319} 320 321 322bool Object::IsNumber() { 323 return IsSmi() || IsHeapNumber(); 324} 325 326 327bool Object::IsByteArray() { 328 return Object::IsHeapObject() 329 && HeapObject::cast(this)->map()->instance_type() == BYTE_ARRAY_TYPE; 330} 331 332 333bool Object::IsPixelArray() { 334 return Object::IsHeapObject() && 335 HeapObject::cast(this)->map()->instance_type() == PIXEL_ARRAY_TYPE; 336} 337 338 339bool Object::IsExternalArray() { 340 if (!Object::IsHeapObject()) 341 return false; 342 InstanceType instance_type = 343 HeapObject::cast(this)->map()->instance_type(); 344 return (instance_type >= FIRST_EXTERNAL_ARRAY_TYPE && 345 instance_type <= LAST_EXTERNAL_ARRAY_TYPE); 346} 347 348 349bool Object::IsExternalByteArray() { 350 return Object::IsHeapObject() && 351 HeapObject::cast(this)->map()->instance_type() == 352 EXTERNAL_BYTE_ARRAY_TYPE; 353} 354 355 356bool Object::IsExternalUnsignedByteArray() { 357 return Object::IsHeapObject() && 358 HeapObject::cast(this)->map()->instance_type() == 359 EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE; 360} 361 362 363bool Object::IsExternalShortArray() { 364 return Object::IsHeapObject() && 365 HeapObject::cast(this)->map()->instance_type() == 366 EXTERNAL_SHORT_ARRAY_TYPE; 367} 368 369 370bool Object::IsExternalUnsignedShortArray() { 371 return Object::IsHeapObject() && 372 HeapObject::cast(this)->map()->instance_type() == 373 EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE; 374} 375 376 377bool Object::IsExternalIntArray() { 378 return Object::IsHeapObject() && 379 HeapObject::cast(this)->map()->instance_type() == 380 EXTERNAL_INT_ARRAY_TYPE; 381} 382 383 384bool Object::IsExternalUnsignedIntArray() { 385 return Object::IsHeapObject() && 386 HeapObject::cast(this)->map()->instance_type() == 387 EXTERNAL_UNSIGNED_INT_ARRAY_TYPE; 388} 389 390 391bool Object::IsExternalFloatArray() { 392 return Object::IsHeapObject() && 393 HeapObject::cast(this)->map()->instance_type() == 394 EXTERNAL_FLOAT_ARRAY_TYPE; 395} 396 397 398bool Object::IsFailure() { 399 return HAS_FAILURE_TAG(this); 400} 401 402 403bool Object::IsRetryAfterGC() { 404 return HAS_FAILURE_TAG(this) 405 && Failure::cast(this)->type() == Failure::RETRY_AFTER_GC; 406} 407 408 409bool Object::IsOutOfMemoryFailure() { 410 return HAS_FAILURE_TAG(this) 411 && Failure::cast(this)->IsOutOfMemoryException(); 412} 413 414 415bool Object::IsException() { 416 return this == Failure::Exception(); 417} 418 419 420bool Object::IsJSObject() { 421 return IsHeapObject() 422 && HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_OBJECT_TYPE; 423} 424 425 426bool Object::IsJSContextExtensionObject() { 427 return IsHeapObject() 428 && (HeapObject::cast(this)->map()->instance_type() == 429 JS_CONTEXT_EXTENSION_OBJECT_TYPE); 430} 431 432 433bool Object::IsMap() { 434 return Object::IsHeapObject() 435 && HeapObject::cast(this)->map()->instance_type() == MAP_TYPE; 436} 437 438 439bool Object::IsFixedArray() { 440 return Object::IsHeapObject() 441 && HeapObject::cast(this)->map()->instance_type() == FIXED_ARRAY_TYPE; 442} 443 444 445bool Object::IsDescriptorArray() { 446 return IsFixedArray(); 447} 448 449 450bool Object::IsContext() { 451 return Object::IsHeapObject() 452 && (HeapObject::cast(this)->map() == Heap::context_map() || 453 HeapObject::cast(this)->map() == Heap::catch_context_map() || 454 HeapObject::cast(this)->map() == Heap::global_context_map()); 455} 456 457 458bool Object::IsCatchContext() { 459 return Object::IsHeapObject() 460 && HeapObject::cast(this)->map() == Heap::catch_context_map(); 461} 462 463 464bool Object::IsGlobalContext() { 465 return Object::IsHeapObject() 466 && HeapObject::cast(this)->map() == Heap::global_context_map(); 467} 468 469 470bool Object::IsJSFunction() { 471 return Object::IsHeapObject() 472 && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE; 473} 474 475 476template <> inline bool Is<JSFunction>(Object* obj) { 477 return obj->IsJSFunction(); 478} 479 480 481bool Object::IsCode() { 482 return Object::IsHeapObject() 483 && HeapObject::cast(this)->map()->instance_type() == CODE_TYPE; 484} 485 486 487bool Object::IsOddball() { 488 return Object::IsHeapObject() 489 && HeapObject::cast(this)->map()->instance_type() == ODDBALL_TYPE; 490} 491 492 493bool Object::IsJSGlobalPropertyCell() { 494 return Object::IsHeapObject() 495 && HeapObject::cast(this)->map()->instance_type() 496 == JS_GLOBAL_PROPERTY_CELL_TYPE; 497} 498 499 500bool Object::IsSharedFunctionInfo() { 501 return Object::IsHeapObject() && 502 (HeapObject::cast(this)->map()->instance_type() == 503 SHARED_FUNCTION_INFO_TYPE); 504} 505 506 507bool Object::IsJSValue() { 508 return Object::IsHeapObject() 509 && HeapObject::cast(this)->map()->instance_type() == JS_VALUE_TYPE; 510} 511 512 513bool Object::IsStringWrapper() { 514 return IsJSValue() && JSValue::cast(this)->value()->IsString(); 515} 516 517 518bool Object::IsProxy() { 519 return Object::IsHeapObject() 520 && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE; 521} 522 523 524bool Object::IsBoolean() { 525 return IsTrue() || IsFalse(); 526} 527 528 529bool Object::IsJSArray() { 530 return Object::IsHeapObject() 531 && HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE; 532} 533 534 535bool Object::IsJSRegExp() { 536 return Object::IsHeapObject() 537 && HeapObject::cast(this)->map()->instance_type() == JS_REGEXP_TYPE; 538} 539 540 541template <> inline bool Is<JSArray>(Object* obj) { 542 return obj->IsJSArray(); 543} 544 545 546bool Object::IsHashTable() { 547 return Object::IsHeapObject() 548 && HeapObject::cast(this)->map() == Heap::hash_table_map(); 549} 550 551 552bool Object::IsDictionary() { 553 return IsHashTable() && this != Heap::symbol_table(); 554} 555 556 557bool Object::IsSymbolTable() { 558 return IsHashTable() && this == Heap::raw_unchecked_symbol_table(); 559} 560 561 562bool Object::IsCompilationCacheTable() { 563 return IsHashTable(); 564} 565 566 567bool Object::IsMapCache() { 568 return IsHashTable(); 569} 570 571 572bool Object::IsPrimitive() { 573 return IsOddball() || IsNumber() || IsString(); 574} 575 576 577bool Object::IsJSGlobalProxy() { 578 bool result = IsHeapObject() && 579 (HeapObject::cast(this)->map()->instance_type() == 580 JS_GLOBAL_PROXY_TYPE); 581 ASSERT(!result || IsAccessCheckNeeded()); 582 return result; 583} 584 585 586bool Object::IsGlobalObject() { 587 if (!IsHeapObject()) return false; 588 589 InstanceType type = HeapObject::cast(this)->map()->instance_type(); 590 return type == JS_GLOBAL_OBJECT_TYPE || 591 type == JS_BUILTINS_OBJECT_TYPE; 592} 593 594 595bool Object::IsJSGlobalObject() { 596 return IsHeapObject() && 597 (HeapObject::cast(this)->map()->instance_type() == 598 JS_GLOBAL_OBJECT_TYPE); 599} 600 601 602bool Object::IsJSBuiltinsObject() { 603 return IsHeapObject() && 604 (HeapObject::cast(this)->map()->instance_type() == 605 JS_BUILTINS_OBJECT_TYPE); 606} 607 608 609bool Object::IsUndetectableObject() { 610 return IsHeapObject() 611 && HeapObject::cast(this)->map()->is_undetectable(); 612} 613 614 615bool Object::IsAccessCheckNeeded() { 616 return IsHeapObject() 617 && HeapObject::cast(this)->map()->is_access_check_needed(); 618} 619 620 621bool Object::IsStruct() { 622 if (!IsHeapObject()) return false; 623 switch (HeapObject::cast(this)->map()->instance_type()) { 624#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return true; 625 STRUCT_LIST(MAKE_STRUCT_CASE) 626#undef MAKE_STRUCT_CASE 627 default: return false; 628 } 629} 630 631 632#define MAKE_STRUCT_PREDICATE(NAME, Name, name) \ 633 bool Object::Is##Name() { \ 634 return Object::IsHeapObject() \ 635 && HeapObject::cast(this)->map()->instance_type() == NAME##_TYPE; \ 636 } 637 STRUCT_LIST(MAKE_STRUCT_PREDICATE) 638#undef MAKE_STRUCT_PREDICATE 639 640 641bool Object::IsUndefined() { 642 return this == Heap::undefined_value(); 643} 644 645 646bool Object::IsTheHole() { 647 return this == Heap::the_hole_value(); 648} 649 650 651bool Object::IsNull() { 652 return this == Heap::null_value(); 653} 654 655 656bool Object::IsTrue() { 657 return this == Heap::true_value(); 658} 659 660 661bool Object::IsFalse() { 662 return this == Heap::false_value(); 663} 664 665 666double Object::Number() { 667 ASSERT(IsNumber()); 668 return IsSmi() 669 ? static_cast<double>(reinterpret_cast<Smi*>(this)->value()) 670 : reinterpret_cast<HeapNumber*>(this)->value(); 671} 672 673 674 675Object* Object::ToSmi() { 676 if (IsSmi()) return this; 677 if (IsHeapNumber()) { 678 double value = HeapNumber::cast(this)->value(); 679 int int_value = FastD2I(value); 680 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { 681 return Smi::FromInt(int_value); 682 } 683 } 684 return Failure::Exception(); 685} 686 687 688bool Object::HasSpecificClassOf(String* name) { 689 return this->IsJSObject() && (JSObject::cast(this)->class_name() == name); 690} 691 692 693Object* Object::GetElement(uint32_t index) { 694 return GetElementWithReceiver(this, index); 695} 696 697 698Object* Object::GetProperty(String* key) { 699 PropertyAttributes attributes; 700 return GetPropertyWithReceiver(this, key, &attributes); 701} 702 703 704Object* Object::GetProperty(String* key, PropertyAttributes* attributes) { 705 return GetPropertyWithReceiver(this, key, attributes); 706} 707 708 709#define FIELD_ADDR(p, offset) \ 710 (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag) 711 712#define READ_FIELD(p, offset) \ 713 (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset))) 714 715#define WRITE_FIELD(p, offset, value) \ 716 (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value) 717 718 719#define WRITE_BARRIER(object, offset) \ 720 Heap::RecordWrite(object->address(), offset); 721 722// CONDITIONAL_WRITE_BARRIER must be issued after the actual 723// write due to the assert validating the written value. 724#define CONDITIONAL_WRITE_BARRIER(object, offset, mode) \ 725 if (mode == UPDATE_WRITE_BARRIER) { \ 726 Heap::RecordWrite(object->address(), offset); \ 727 } else { \ 728 ASSERT(mode == SKIP_WRITE_BARRIER); \ 729 ASSERT(Heap::InNewSpace(object) || \ 730 !Heap::InNewSpace(READ_FIELD(object, offset))); \ 731 } 732 733#define READ_DOUBLE_FIELD(p, offset) \ 734 (*reinterpret_cast<double*>(FIELD_ADDR(p, offset))) 735 736#define WRITE_DOUBLE_FIELD(p, offset, value) \ 737 (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)) = value) 738 739#define READ_INT_FIELD(p, offset) \ 740 (*reinterpret_cast<int*>(FIELD_ADDR(p, offset))) 741 742#define WRITE_INT_FIELD(p, offset, value) \ 743 (*reinterpret_cast<int*>(FIELD_ADDR(p, offset)) = value) 744 745#define READ_INTPTR_FIELD(p, offset) \ 746 (*reinterpret_cast<intptr_t*>(FIELD_ADDR(p, offset))) 747 748#define WRITE_INTPTR_FIELD(p, offset, value) \ 749 (*reinterpret_cast<intptr_t*>(FIELD_ADDR(p, offset)) = value) 750 751#define READ_UINT32_FIELD(p, offset) \ 752 (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset))) 753 754#define WRITE_UINT32_FIELD(p, offset, value) \ 755 (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset)) = value) 756 757#define READ_SHORT_FIELD(p, offset) \ 758 (*reinterpret_cast<uint16_t*>(FIELD_ADDR(p, offset))) 759 760#define WRITE_SHORT_FIELD(p, offset, value) \ 761 (*reinterpret_cast<uint16_t*>(FIELD_ADDR(p, offset)) = value) 762 763#define READ_BYTE_FIELD(p, offset) \ 764 (*reinterpret_cast<byte*>(FIELD_ADDR(p, offset))) 765 766#define WRITE_BYTE_FIELD(p, offset, value) \ 767 (*reinterpret_cast<byte*>(FIELD_ADDR(p, offset)) = value) 768 769 770Object** HeapObject::RawField(HeapObject* obj, int byte_offset) { 771 return &READ_FIELD(obj, byte_offset); 772} 773 774 775int Smi::value() { 776 return Internals::SmiValue(this); 777} 778 779 780Smi* Smi::FromInt(int value) { 781 ASSERT(Smi::IsValid(value)); 782 int smi_shift_bits = kSmiTagSize + kSmiShiftSize; 783 intptr_t tagged_value = 784 (static_cast<intptr_t>(value) << smi_shift_bits) | kSmiTag; 785 return reinterpret_cast<Smi*>(tagged_value); 786} 787 788 789Smi* Smi::FromIntptr(intptr_t value) { 790 ASSERT(Smi::IsValid(value)); 791 int smi_shift_bits = kSmiTagSize + kSmiShiftSize; 792 return reinterpret_cast<Smi*>((value << smi_shift_bits) | kSmiTag); 793} 794 795 796Failure::Type Failure::type() const { 797 return static_cast<Type>(value() & kFailureTypeTagMask); 798} 799 800 801bool Failure::IsInternalError() const { 802 return type() == INTERNAL_ERROR; 803} 804 805 806bool Failure::IsOutOfMemoryException() const { 807 return type() == OUT_OF_MEMORY_EXCEPTION; 808} 809 810 811int Failure::requested() const { 812 const int kShiftBits = 813 kFailureTypeTagSize + kSpaceTagSize - kObjectAlignmentBits; 814 STATIC_ASSERT(kShiftBits >= 0); 815 ASSERT(type() == RETRY_AFTER_GC); 816 return static_cast<int>(value() >> kShiftBits); 817} 818 819 820AllocationSpace Failure::allocation_space() const { 821 ASSERT_EQ(RETRY_AFTER_GC, type()); 822 return static_cast<AllocationSpace>((value() >> kFailureTypeTagSize) 823 & kSpaceTagMask); 824} 825 826 827Failure* Failure::InternalError() { 828 return Construct(INTERNAL_ERROR); 829} 830 831 832Failure* Failure::Exception() { 833 return Construct(EXCEPTION); 834} 835 836 837Failure* Failure::OutOfMemoryException() { 838 return Construct(OUT_OF_MEMORY_EXCEPTION); 839} 840 841 842intptr_t Failure::value() const { 843 return reinterpret_cast<intptr_t>(this) >> kFailureTagSize; 844} 845 846 847Failure* Failure::RetryAfterGC(int requested_bytes) { 848 // Assert that the space encoding fits in the three bytes allotted for it. 849 ASSERT((LAST_SPACE & ~kSpaceTagMask) == 0); 850 intptr_t requested = requested_bytes >> kObjectAlignmentBits; 851 int tag_bits = kSpaceTagSize + kFailureTypeTagSize; 852 if (((requested << tag_bits) >> tag_bits) != requested) { 853 // No room for entire requested size in the bits. Round down to 854 // maximally representable size. 855 requested = static_cast<intptr_t>( 856 (~static_cast<uintptr_t>(0)) >> (tag_bits + 1)); 857 } 858 int value = static_cast<int>(requested << kSpaceTagSize) | NEW_SPACE; 859 return Construct(RETRY_AFTER_GC, value); 860} 861 862 863Failure* Failure::Construct(Type type, intptr_t value) { 864 intptr_t info = (static_cast<intptr_t>(value) << kFailureTypeTagSize) | type; 865 ASSERT(((info << kFailureTagSize) >> kFailureTagSize) == info); 866 return reinterpret_cast<Failure*>((info << kFailureTagSize) | kFailureTag); 867} 868 869 870bool Smi::IsValid(intptr_t value) { 871#ifdef DEBUG 872 bool in_range = (value >= kMinValue) && (value <= kMaxValue); 873#endif 874 875#ifdef V8_TARGET_ARCH_X64 876 // To be representable as a long smi, the value must be a 32-bit integer. 877 bool result = (value == static_cast<int32_t>(value)); 878#else 879 // To be representable as an tagged small integer, the two 880 // most-significant bits of 'value' must be either 00 or 11 due to 881 // sign-extension. To check this we add 01 to the two 882 // most-significant bits, and check if the most-significant bit is 0 883 // 884 // CAUTION: The original code below: 885 // bool result = ((value + 0x40000000) & 0x80000000) == 0; 886 // may lead to incorrect results according to the C language spec, and 887 // in fact doesn't work correctly with gcc4.1.1 in some cases: The 888 // compiler may produce undefined results in case of signed integer 889 // overflow. The computation must be done w/ unsigned ints. 890 bool result = (static_cast<uintptr_t>(value + 0x40000000U) < 0x80000000U); 891#endif 892 ASSERT(result == in_range); 893 return result; 894} 895 896 897MapWord MapWord::FromMap(Map* map) { 898 return MapWord(reinterpret_cast<uintptr_t>(map)); 899} 900 901 902Map* MapWord::ToMap() { 903 return reinterpret_cast<Map*>(value_); 904} 905 906 907bool MapWord::IsForwardingAddress() { 908 return HAS_SMI_TAG(reinterpret_cast<Object*>(value_)); 909} 910 911 912MapWord MapWord::FromForwardingAddress(HeapObject* object) { 913 Address raw = reinterpret_cast<Address>(object) - kHeapObjectTag; 914 return MapWord(reinterpret_cast<uintptr_t>(raw)); 915} 916 917 918HeapObject* MapWord::ToForwardingAddress() { 919 ASSERT(IsForwardingAddress()); 920 return HeapObject::FromAddress(reinterpret_cast<Address>(value_)); 921} 922 923 924bool MapWord::IsMarked() { 925 return (value_ & kMarkingMask) == 0; 926} 927 928 929void MapWord::SetMark() { 930 value_ &= ~kMarkingMask; 931} 932 933 934void MapWord::ClearMark() { 935 value_ |= kMarkingMask; 936} 937 938 939bool MapWord::IsOverflowed() { 940 return (value_ & kOverflowMask) != 0; 941} 942 943 944void MapWord::SetOverflow() { 945 value_ |= kOverflowMask; 946} 947 948 949void MapWord::ClearOverflow() { 950 value_ &= ~kOverflowMask; 951} 952 953 954MapWord MapWord::EncodeAddress(Address map_address, int offset) { 955 // Offset is the distance in live bytes from the first live object in the 956 // same page. The offset between two objects in the same page should not 957 // exceed the object area size of a page. 958 ASSERT(0 <= offset && offset < Page::kObjectAreaSize); 959 960 uintptr_t compact_offset = offset >> kObjectAlignmentBits; 961 ASSERT(compact_offset < (1 << kForwardingOffsetBits)); 962 963 Page* map_page = Page::FromAddress(map_address); 964 ASSERT_MAP_PAGE_INDEX(map_page->mc_page_index); 965 966 uintptr_t map_page_offset = 967 map_page->Offset(map_address) >> kMapAlignmentBits; 968 969 uintptr_t encoding = 970 (compact_offset << kForwardingOffsetShift) | 971 (map_page_offset << kMapPageOffsetShift) | 972 (map_page->mc_page_index << kMapPageIndexShift); 973 return MapWord(encoding); 974} 975 976 977Address MapWord::DecodeMapAddress(MapSpace* map_space) { 978 int map_page_index = 979 static_cast<int>((value_ & kMapPageIndexMask) >> kMapPageIndexShift); 980 ASSERT_MAP_PAGE_INDEX(map_page_index); 981 982 int map_page_offset = static_cast<int>( 983 ((value_ & kMapPageOffsetMask) >> kMapPageOffsetShift) << 984 kMapAlignmentBits); 985 986 return (map_space->PageAddress(map_page_index) + map_page_offset); 987} 988 989 990int MapWord::DecodeOffset() { 991 // The offset field is represented in the kForwardingOffsetBits 992 // most-significant bits. 993 uintptr_t offset = (value_ >> kForwardingOffsetShift) << kObjectAlignmentBits; 994 ASSERT(offset < static_cast<uintptr_t>(Page::kObjectAreaSize)); 995 return static_cast<int>(offset); 996} 997 998 999MapWord MapWord::FromEncodedAddress(Address address) { 1000 return MapWord(reinterpret_cast<uintptr_t>(address)); 1001} 1002 1003 1004Address MapWord::ToEncodedAddress() { 1005 return reinterpret_cast<Address>(value_); 1006} 1007 1008 1009#ifdef DEBUG 1010void HeapObject::VerifyObjectField(int offset) { 1011 VerifyPointer(READ_FIELD(this, offset)); 1012} 1013#endif 1014 1015 1016Map* HeapObject::map() { 1017 return map_word().ToMap(); 1018} 1019 1020 1021void HeapObject::set_map(Map* value) { 1022 set_map_word(MapWord::FromMap(value)); 1023} 1024 1025 1026MapWord HeapObject::map_word() { 1027 return MapWord(reinterpret_cast<uintptr_t>(READ_FIELD(this, kMapOffset))); 1028} 1029 1030 1031void HeapObject::set_map_word(MapWord map_word) { 1032 // WRITE_FIELD does not update the remembered set, but there is no need 1033 // here. 1034 WRITE_FIELD(this, kMapOffset, reinterpret_cast<Object*>(map_word.value_)); 1035} 1036 1037 1038HeapObject* HeapObject::FromAddress(Address address) { 1039 ASSERT_TAG_ALIGNED(address); 1040 return reinterpret_cast<HeapObject*>(address + kHeapObjectTag); 1041} 1042 1043 1044Address HeapObject::address() { 1045 return reinterpret_cast<Address>(this) - kHeapObjectTag; 1046} 1047 1048 1049int HeapObject::Size() { 1050 return SizeFromMap(map()); 1051} 1052 1053 1054void HeapObject::IteratePointers(ObjectVisitor* v, int start, int end) { 1055 v->VisitPointers(reinterpret_cast<Object**>(FIELD_ADDR(this, start)), 1056 reinterpret_cast<Object**>(FIELD_ADDR(this, end))); 1057} 1058 1059 1060void HeapObject::IteratePointer(ObjectVisitor* v, int offset) { 1061 v->VisitPointer(reinterpret_cast<Object**>(FIELD_ADDR(this, offset))); 1062} 1063 1064 1065bool HeapObject::IsMarked() { 1066 return map_word().IsMarked(); 1067} 1068 1069 1070void HeapObject::SetMark() { 1071 ASSERT(!IsMarked()); 1072 MapWord first_word = map_word(); 1073 first_word.SetMark(); 1074 set_map_word(first_word); 1075} 1076 1077 1078void HeapObject::ClearMark() { 1079 ASSERT(IsMarked()); 1080 MapWord first_word = map_word(); 1081 first_word.ClearMark(); 1082 set_map_word(first_word); 1083} 1084 1085 1086bool HeapObject::IsOverflowed() { 1087 return map_word().IsOverflowed(); 1088} 1089 1090 1091void HeapObject::SetOverflow() { 1092 MapWord first_word = map_word(); 1093 first_word.SetOverflow(); 1094 set_map_word(first_word); 1095} 1096 1097 1098void HeapObject::ClearOverflow() { 1099 ASSERT(IsOverflowed()); 1100 MapWord first_word = map_word(); 1101 first_word.ClearOverflow(); 1102 set_map_word(first_word); 1103} 1104 1105 1106double HeapNumber::value() { 1107 return READ_DOUBLE_FIELD(this, kValueOffset); 1108} 1109 1110 1111void HeapNumber::set_value(double value) { 1112 WRITE_DOUBLE_FIELD(this, kValueOffset, value); 1113} 1114 1115 1116ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset) 1117 1118 1119Array* JSObject::elements() { 1120 Object* array = READ_FIELD(this, kElementsOffset); 1121 // In the assert below Dictionary is covered under FixedArray. 1122 ASSERT(array->IsFixedArray() || array->IsPixelArray() || 1123 array->IsExternalArray()); 1124 return reinterpret_cast<Array*>(array); 1125} 1126 1127 1128void JSObject::set_elements(Array* value, WriteBarrierMode mode) { 1129 // In the assert below Dictionary is covered under FixedArray. 1130 ASSERT(value->IsFixedArray() || value->IsPixelArray() || 1131 value->IsExternalArray()); 1132 WRITE_FIELD(this, kElementsOffset, value); 1133 CONDITIONAL_WRITE_BARRIER(this, kElementsOffset, mode); 1134} 1135 1136 1137void JSObject::initialize_properties() { 1138 ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); 1139 WRITE_FIELD(this, kPropertiesOffset, Heap::empty_fixed_array()); 1140} 1141 1142 1143void JSObject::initialize_elements() { 1144 ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); 1145 WRITE_FIELD(this, kElementsOffset, Heap::empty_fixed_array()); 1146} 1147 1148 1149ACCESSORS(Oddball, to_string, String, kToStringOffset) 1150ACCESSORS(Oddball, to_number, Object, kToNumberOffset) 1151 1152 1153Object* JSGlobalPropertyCell::value() { 1154 return READ_FIELD(this, kValueOffset); 1155} 1156 1157 1158void JSGlobalPropertyCell::set_value(Object* val, WriteBarrierMode ignored) { 1159 // The write barrier is not used for global property cells. 1160 ASSERT(!val->IsJSGlobalPropertyCell()); 1161 WRITE_FIELD(this, kValueOffset, val); 1162} 1163 1164 1165int JSObject::GetHeaderSize() { 1166 InstanceType type = map()->instance_type(); 1167 // Check for the most common kind of JavaScript object before 1168 // falling into the generic switch. This speeds up the internal 1169 // field operations considerably on average. 1170 if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize; 1171 switch (type) { 1172 case JS_GLOBAL_PROXY_TYPE: 1173 return JSGlobalProxy::kSize; 1174 case JS_GLOBAL_OBJECT_TYPE: 1175 return JSGlobalObject::kSize; 1176 case JS_BUILTINS_OBJECT_TYPE: 1177 return JSBuiltinsObject::kSize; 1178 case JS_FUNCTION_TYPE: 1179 return JSFunction::kSize; 1180 case JS_VALUE_TYPE: 1181 return JSValue::kSize; 1182 case JS_ARRAY_TYPE: 1183 return JSValue::kSize; 1184 case JS_REGEXP_TYPE: 1185 return JSValue::kSize; 1186 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 1187 return JSObject::kHeaderSize; 1188 default: 1189 UNREACHABLE(); 1190 return 0; 1191 } 1192} 1193 1194 1195int JSObject::GetInternalFieldCount() { 1196 ASSERT(1 << kPointerSizeLog2 == kPointerSize); 1197 // Make sure to adjust for the number of in-object properties. These 1198 // properties do contribute to the size, but are not internal fields. 1199 return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) - 1200 map()->inobject_properties(); 1201} 1202 1203 1204Object* JSObject::GetInternalField(int index) { 1205 ASSERT(index < GetInternalFieldCount() && index >= 0); 1206 // Internal objects do follow immediately after the header, whereas in-object 1207 // properties are at the end of the object. Therefore there is no need 1208 // to adjust the index here. 1209 return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index)); 1210} 1211 1212 1213void JSObject::SetInternalField(int index, Object* value) { 1214 ASSERT(index < GetInternalFieldCount() && index >= 0); 1215 // Internal objects do follow immediately after the header, whereas in-object 1216 // properties are at the end of the object. Therefore there is no need 1217 // to adjust the index here. 1218 int offset = GetHeaderSize() + (kPointerSize * index); 1219 WRITE_FIELD(this, offset, value); 1220 WRITE_BARRIER(this, offset); 1221} 1222 1223 1224// Access fast-case object properties at index. The use of these routines 1225// is needed to correctly distinguish between properties stored in-object and 1226// properties stored in the properties array. 1227Object* JSObject::FastPropertyAt(int index) { 1228 // Adjust for the number of properties stored in the object. 1229 index -= map()->inobject_properties(); 1230 if (index < 0) { 1231 int offset = map()->instance_size() + (index * kPointerSize); 1232 return READ_FIELD(this, offset); 1233 } else { 1234 ASSERT(index < properties()->length()); 1235 return properties()->get(index); 1236 } 1237} 1238 1239 1240Object* JSObject::FastPropertyAtPut(int index, Object* value) { 1241 // Adjust for the number of properties stored in the object. 1242 index -= map()->inobject_properties(); 1243 if (index < 0) { 1244 int offset = map()->instance_size() + (index * kPointerSize); 1245 WRITE_FIELD(this, offset, value); 1246 WRITE_BARRIER(this, offset); 1247 } else { 1248 ASSERT(index < properties()->length()); 1249 properties()->set(index, value); 1250 } 1251 return value; 1252} 1253 1254 1255Object* JSObject::InObjectPropertyAt(int index) { 1256 // Adjust for the number of properties stored in the object. 1257 index -= map()->inobject_properties(); 1258 ASSERT(index < 0); 1259 int offset = map()->instance_size() + (index * kPointerSize); 1260 return READ_FIELD(this, offset); 1261} 1262 1263 1264Object* JSObject::InObjectPropertyAtPut(int index, 1265 Object* value, 1266 WriteBarrierMode mode) { 1267 // Adjust for the number of properties stored in the object. 1268 index -= map()->inobject_properties(); 1269 ASSERT(index < 0); 1270 int offset = map()->instance_size() + (index * kPointerSize); 1271 WRITE_FIELD(this, offset, value); 1272 CONDITIONAL_WRITE_BARRIER(this, offset, mode); 1273 return value; 1274} 1275 1276 1277 1278void JSObject::InitializeBody(int object_size) { 1279 Object* value = Heap::undefined_value(); 1280 for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) { 1281 WRITE_FIELD(this, offset, value); 1282 } 1283} 1284 1285 1286void Struct::InitializeBody(int object_size) { 1287 Object* value = Heap::undefined_value(); 1288 for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) { 1289 WRITE_FIELD(this, offset, value); 1290 } 1291} 1292 1293 1294bool JSObject::HasFastProperties() { 1295 return !properties()->IsDictionary(); 1296} 1297 1298 1299bool Array::IndexFromObject(Object* object, uint32_t* index) { 1300 if (object->IsSmi()) { 1301 int value = Smi::cast(object)->value(); 1302 if (value < 0) return false; 1303 *index = value; 1304 return true; 1305 } 1306 if (object->IsHeapNumber()) { 1307 double value = HeapNumber::cast(object)->value(); 1308 uint32_t uint_value = static_cast<uint32_t>(value); 1309 if (value == static_cast<double>(uint_value)) { 1310 *index = uint_value; 1311 return true; 1312 } 1313 } 1314 return false; 1315} 1316 1317 1318bool Object::IsStringObjectWithCharacterAt(uint32_t index) { 1319 if (!this->IsJSValue()) return false; 1320 1321 JSValue* js_value = JSValue::cast(this); 1322 if (!js_value->value()->IsString()) return false; 1323 1324 String* str = String::cast(js_value->value()); 1325 if (index >= (uint32_t)str->length()) return false; 1326 1327 return true; 1328} 1329 1330 1331Object* FixedArray::get(int index) { 1332 ASSERT(index >= 0 && index < this->length()); 1333 return READ_FIELD(this, kHeaderSize + index * kPointerSize); 1334} 1335 1336 1337void FixedArray::set(int index, Smi* value) { 1338 ASSERT(reinterpret_cast<Object*>(value)->IsSmi()); 1339 int offset = kHeaderSize + index * kPointerSize; 1340 WRITE_FIELD(this, offset, value); 1341} 1342 1343 1344void FixedArray::set(int index, Object* value) { 1345 ASSERT(index >= 0 && index < this->length()); 1346 int offset = kHeaderSize + index * kPointerSize; 1347 WRITE_FIELD(this, offset, value); 1348 WRITE_BARRIER(this, offset); 1349} 1350 1351 1352WriteBarrierMode HeapObject::GetWriteBarrierMode() { 1353 if (Heap::InNewSpace(this)) return SKIP_WRITE_BARRIER; 1354 return UPDATE_WRITE_BARRIER; 1355} 1356 1357 1358void FixedArray::set(int index, 1359 Object* value, 1360 WriteBarrierMode mode) { 1361 ASSERT(index >= 0 && index < this->length()); 1362 int offset = kHeaderSize + index * kPointerSize; 1363 WRITE_FIELD(this, offset, value); 1364 CONDITIONAL_WRITE_BARRIER(this, offset, mode); 1365} 1366 1367 1368void FixedArray::fast_set(FixedArray* array, int index, Object* value) { 1369 ASSERT(index >= 0 && index < array->length()); 1370 WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value); 1371} 1372 1373 1374void FixedArray::set_undefined(int index) { 1375 ASSERT(index >= 0 && index < this->length()); 1376 ASSERT(!Heap::InNewSpace(Heap::undefined_value())); 1377 WRITE_FIELD(this, kHeaderSize + index * kPointerSize, 1378 Heap::undefined_value()); 1379} 1380 1381 1382void FixedArray::set_null(int index) { 1383 ASSERT(index >= 0 && index < this->length()); 1384 ASSERT(!Heap::InNewSpace(Heap::null_value())); 1385 WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::null_value()); 1386} 1387 1388 1389void FixedArray::set_the_hole(int index) { 1390 ASSERT(index >= 0 && index < this->length()); 1391 ASSERT(!Heap::InNewSpace(Heap::the_hole_value())); 1392 WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::the_hole_value()); 1393} 1394 1395 1396bool DescriptorArray::IsEmpty() { 1397 ASSERT(this == Heap::empty_descriptor_array() || 1398 this->length() > 2); 1399 return this == Heap::empty_descriptor_array(); 1400} 1401 1402 1403void DescriptorArray::fast_swap(FixedArray* array, int first, int second) { 1404 Object* tmp = array->get(first); 1405 fast_set(array, first, array->get(second)); 1406 fast_set(array, second, tmp); 1407} 1408 1409 1410int DescriptorArray::Search(String* name) { 1411 SLOW_ASSERT(IsSortedNoDuplicates()); 1412 1413 // Check for empty descriptor array. 1414 int nof = number_of_descriptors(); 1415 if (nof == 0) return kNotFound; 1416 1417 // Fast case: do linear search for small arrays. 1418 const int kMaxElementsForLinearSearch = 8; 1419 if (StringShape(name).IsSymbol() && nof < kMaxElementsForLinearSearch) { 1420 return LinearSearch(name, nof); 1421 } 1422 1423 // Slow case: perform binary search. 1424 return BinarySearch(name, 0, nof - 1); 1425} 1426 1427 1428String* DescriptorArray::GetKey(int descriptor_number) { 1429 ASSERT(descriptor_number < number_of_descriptors()); 1430 return String::cast(get(ToKeyIndex(descriptor_number))); 1431} 1432 1433 1434Object* DescriptorArray::GetValue(int descriptor_number) { 1435 ASSERT(descriptor_number < number_of_descriptors()); 1436 return GetContentArray()->get(ToValueIndex(descriptor_number)); 1437} 1438 1439 1440Smi* DescriptorArray::GetDetails(int descriptor_number) { 1441 ASSERT(descriptor_number < number_of_descriptors()); 1442 return Smi::cast(GetContentArray()->get(ToDetailsIndex(descriptor_number))); 1443} 1444 1445 1446PropertyType DescriptorArray::GetType(int descriptor_number) { 1447 ASSERT(descriptor_number < number_of_descriptors()); 1448 return PropertyDetails(GetDetails(descriptor_number)).type(); 1449} 1450 1451 1452int DescriptorArray::GetFieldIndex(int descriptor_number) { 1453 return Descriptor::IndexFromValue(GetValue(descriptor_number)); 1454} 1455 1456 1457JSFunction* DescriptorArray::GetConstantFunction(int descriptor_number) { 1458 return JSFunction::cast(GetValue(descriptor_number)); 1459} 1460 1461 1462Object* DescriptorArray::GetCallbacksObject(int descriptor_number) { 1463 ASSERT(GetType(descriptor_number) == CALLBACKS); 1464 return GetValue(descriptor_number); 1465} 1466 1467 1468AccessorDescriptor* DescriptorArray::GetCallbacks(int descriptor_number) { 1469 ASSERT(GetType(descriptor_number) == CALLBACKS); 1470 Proxy* p = Proxy::cast(GetCallbacksObject(descriptor_number)); 1471 return reinterpret_cast<AccessorDescriptor*>(p->proxy()); 1472} 1473 1474 1475bool DescriptorArray::IsProperty(int descriptor_number) { 1476 return GetType(descriptor_number) < FIRST_PHANTOM_PROPERTY_TYPE; 1477} 1478 1479 1480bool DescriptorArray::IsTransition(int descriptor_number) { 1481 PropertyType t = GetType(descriptor_number); 1482 return t == MAP_TRANSITION || t == CONSTANT_TRANSITION; 1483} 1484 1485 1486bool DescriptorArray::IsNullDescriptor(int descriptor_number) { 1487 return GetType(descriptor_number) == NULL_DESCRIPTOR; 1488} 1489 1490 1491bool DescriptorArray::IsDontEnum(int descriptor_number) { 1492 return PropertyDetails(GetDetails(descriptor_number)).IsDontEnum(); 1493} 1494 1495 1496void DescriptorArray::Get(int descriptor_number, Descriptor* desc) { 1497 desc->Init(GetKey(descriptor_number), 1498 GetValue(descriptor_number), 1499 GetDetails(descriptor_number)); 1500} 1501 1502 1503void DescriptorArray::Set(int descriptor_number, Descriptor* desc) { 1504 // Range check. 1505 ASSERT(descriptor_number < number_of_descriptors()); 1506 1507 // Make sure none of the elements in desc are in new space. 1508 ASSERT(!Heap::InNewSpace(desc->GetKey())); 1509 ASSERT(!Heap::InNewSpace(desc->GetValue())); 1510 1511 fast_set(this, ToKeyIndex(descriptor_number), desc->GetKey()); 1512 FixedArray* content_array = GetContentArray(); 1513 fast_set(content_array, ToValueIndex(descriptor_number), desc->GetValue()); 1514 fast_set(content_array, ToDetailsIndex(descriptor_number), 1515 desc->GetDetails().AsSmi()); 1516} 1517 1518 1519void DescriptorArray::CopyFrom(int index, DescriptorArray* src, int src_index) { 1520 Descriptor desc; 1521 src->Get(src_index, &desc); 1522 Set(index, &desc); 1523} 1524 1525 1526void DescriptorArray::Swap(int first, int second) { 1527 fast_swap(this, ToKeyIndex(first), ToKeyIndex(second)); 1528 FixedArray* content_array = GetContentArray(); 1529 fast_swap(content_array, ToValueIndex(first), ToValueIndex(second)); 1530 fast_swap(content_array, ToDetailsIndex(first), ToDetailsIndex(second)); 1531} 1532 1533 1534bool NumberDictionary::requires_slow_elements() { 1535 Object* max_index_object = get(kMaxNumberKeyIndex); 1536 if (!max_index_object->IsSmi()) return false; 1537 return 0 != 1538 (Smi::cast(max_index_object)->value() & kRequiresSlowElementsMask); 1539} 1540 1541uint32_t NumberDictionary::max_number_key() { 1542 ASSERT(!requires_slow_elements()); 1543 Object* max_index_object = get(kMaxNumberKeyIndex); 1544 if (!max_index_object->IsSmi()) return 0; 1545 uint32_t value = static_cast<uint32_t>(Smi::cast(max_index_object)->value()); 1546 return value >> kRequiresSlowElementsTagSize; 1547} 1548 1549void NumberDictionary::set_requires_slow_elements() { 1550 set(kMaxNumberKeyIndex, 1551 Smi::FromInt(kRequiresSlowElementsMask), 1552 SKIP_WRITE_BARRIER); 1553} 1554 1555 1556// ------------------------------------ 1557// Cast operations 1558 1559 1560CAST_ACCESSOR(FixedArray) 1561CAST_ACCESSOR(DescriptorArray) 1562CAST_ACCESSOR(SymbolTable) 1563CAST_ACCESSOR(CompilationCacheTable) 1564CAST_ACCESSOR(MapCache) 1565CAST_ACCESSOR(String) 1566CAST_ACCESSOR(SeqString) 1567CAST_ACCESSOR(SeqAsciiString) 1568CAST_ACCESSOR(SeqTwoByteString) 1569CAST_ACCESSOR(ConsString) 1570CAST_ACCESSOR(ExternalString) 1571CAST_ACCESSOR(ExternalAsciiString) 1572CAST_ACCESSOR(ExternalTwoByteString) 1573CAST_ACCESSOR(JSObject) 1574CAST_ACCESSOR(Smi) 1575CAST_ACCESSOR(Failure) 1576CAST_ACCESSOR(HeapObject) 1577CAST_ACCESSOR(HeapNumber) 1578CAST_ACCESSOR(Oddball) 1579CAST_ACCESSOR(JSGlobalPropertyCell) 1580CAST_ACCESSOR(SharedFunctionInfo) 1581CAST_ACCESSOR(Map) 1582CAST_ACCESSOR(JSFunction) 1583CAST_ACCESSOR(GlobalObject) 1584CAST_ACCESSOR(JSGlobalProxy) 1585CAST_ACCESSOR(JSGlobalObject) 1586CAST_ACCESSOR(JSBuiltinsObject) 1587CAST_ACCESSOR(Code) 1588CAST_ACCESSOR(JSArray) 1589CAST_ACCESSOR(JSRegExp) 1590CAST_ACCESSOR(Proxy) 1591CAST_ACCESSOR(ByteArray) 1592CAST_ACCESSOR(PixelArray) 1593CAST_ACCESSOR(ExternalArray) 1594CAST_ACCESSOR(ExternalByteArray) 1595CAST_ACCESSOR(ExternalUnsignedByteArray) 1596CAST_ACCESSOR(ExternalShortArray) 1597CAST_ACCESSOR(ExternalUnsignedShortArray) 1598CAST_ACCESSOR(ExternalIntArray) 1599CAST_ACCESSOR(ExternalUnsignedIntArray) 1600CAST_ACCESSOR(ExternalFloatArray) 1601CAST_ACCESSOR(Struct) 1602 1603 1604#define MAKE_STRUCT_CAST(NAME, Name, name) CAST_ACCESSOR(Name) 1605 STRUCT_LIST(MAKE_STRUCT_CAST) 1606#undef MAKE_STRUCT_CAST 1607 1608 1609template <typename Shape, typename Key> 1610HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) { 1611 ASSERT(obj->IsHashTable()); 1612 return reinterpret_cast<HashTable*>(obj); 1613} 1614 1615 1616INT_ACCESSORS(Array, length, kLengthOffset) 1617 1618 1619INT_ACCESSORS(String, length, kLengthOffset) 1620 1621 1622uint32_t String::hash_field() { 1623 return READ_UINT32_FIELD(this, kHashFieldOffset); 1624} 1625 1626 1627void String::set_hash_field(uint32_t value) { 1628 WRITE_UINT32_FIELD(this, kHashFieldOffset, value); 1629} 1630 1631 1632bool String::Equals(String* other) { 1633 if (other == this) return true; 1634 if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) { 1635 return false; 1636 } 1637 return SlowEquals(other); 1638} 1639 1640 1641Object* String::TryFlattenIfNotFlat() { 1642 // We don't need to flatten strings that are already flat. Since this code 1643 // is inlined, it can be helpful in the flat case to not call out to Flatten. 1644 if (!IsFlat()) { 1645 return TryFlatten(); 1646 } 1647 return this; 1648} 1649 1650 1651uint16_t String::Get(int index) { 1652 ASSERT(index >= 0 && index < length()); 1653 switch (StringShape(this).full_representation_tag()) { 1654 case kSeqStringTag | kAsciiStringTag: 1655 return SeqAsciiString::cast(this)->SeqAsciiStringGet(index); 1656 case kSeqStringTag | kTwoByteStringTag: 1657 return SeqTwoByteString::cast(this)->SeqTwoByteStringGet(index); 1658 case kConsStringTag | kAsciiStringTag: 1659 case kConsStringTag | kTwoByteStringTag: 1660 return ConsString::cast(this)->ConsStringGet(index); 1661 case kExternalStringTag | kAsciiStringTag: 1662 return ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index); 1663 case kExternalStringTag | kTwoByteStringTag: 1664 return ExternalTwoByteString::cast(this)->ExternalTwoByteStringGet(index); 1665 default: 1666 break; 1667 } 1668 1669 UNREACHABLE(); 1670 return 0; 1671} 1672 1673 1674void String::Set(int index, uint16_t value) { 1675 ASSERT(index >= 0 && index < length()); 1676 ASSERT(StringShape(this).IsSequential()); 1677 1678 return this->IsAsciiRepresentation() 1679 ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value) 1680 : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value); 1681} 1682 1683 1684bool String::IsFlat() { 1685 switch (StringShape(this).representation_tag()) { 1686 case kConsStringTag: { 1687 String* second = ConsString::cast(this)->second(); 1688 // Only flattened strings have second part empty. 1689 return second->length() == 0; 1690 } 1691 default: 1692 return true; 1693 } 1694} 1695 1696 1697uint16_t SeqAsciiString::SeqAsciiStringGet(int index) { 1698 ASSERT(index >= 0 && index < length()); 1699 return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); 1700} 1701 1702 1703void SeqAsciiString::SeqAsciiStringSet(int index, uint16_t value) { 1704 ASSERT(index >= 0 && index < length() && value <= kMaxAsciiCharCode); 1705 WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, 1706 static_cast<byte>(value)); 1707} 1708 1709 1710Address SeqAsciiString::GetCharsAddress() { 1711 return FIELD_ADDR(this, kHeaderSize); 1712} 1713 1714 1715char* SeqAsciiString::GetChars() { 1716 return reinterpret_cast<char*>(GetCharsAddress()); 1717} 1718 1719 1720Address SeqTwoByteString::GetCharsAddress() { 1721 return FIELD_ADDR(this, kHeaderSize); 1722} 1723 1724 1725uc16* SeqTwoByteString::GetChars() { 1726 return reinterpret_cast<uc16*>(FIELD_ADDR(this, kHeaderSize)); 1727} 1728 1729 1730uint16_t SeqTwoByteString::SeqTwoByteStringGet(int index) { 1731 ASSERT(index >= 0 && index < length()); 1732 return READ_SHORT_FIELD(this, kHeaderSize + index * kShortSize); 1733} 1734 1735 1736void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) { 1737 ASSERT(index >= 0 && index < length()); 1738 WRITE_SHORT_FIELD(this, kHeaderSize + index * kShortSize, value); 1739} 1740 1741 1742int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) { 1743 uint32_t length = READ_INT_FIELD(this, kLengthOffset); 1744 return SizeFor(length); 1745} 1746 1747 1748int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) { 1749 uint32_t length = READ_INT_FIELD(this, kLengthOffset); 1750 return SizeFor(length); 1751} 1752 1753 1754String* ConsString::first() { 1755 return String::cast(READ_FIELD(this, kFirstOffset)); 1756} 1757 1758 1759Object* ConsString::unchecked_first() { 1760 return READ_FIELD(this, kFirstOffset); 1761} 1762 1763 1764void ConsString::set_first(String* value, WriteBarrierMode mode) { 1765 WRITE_FIELD(this, kFirstOffset, value); 1766 CONDITIONAL_WRITE_BARRIER(this, kFirstOffset, mode); 1767} 1768 1769 1770String* ConsString::second() { 1771 return String::cast(READ_FIELD(this, kSecondOffset)); 1772} 1773 1774 1775Object* ConsString::unchecked_second() { 1776 return READ_FIELD(this, kSecondOffset); 1777} 1778 1779 1780void ConsString::set_second(String* value, WriteBarrierMode mode) { 1781 WRITE_FIELD(this, kSecondOffset, value); 1782 CONDITIONAL_WRITE_BARRIER(this, kSecondOffset, mode); 1783} 1784 1785 1786ExternalAsciiString::Resource* ExternalAsciiString::resource() { 1787 return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)); 1788} 1789 1790 1791void ExternalAsciiString::set_resource( 1792 ExternalAsciiString::Resource* resource) { 1793 *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)) = resource; 1794} 1795 1796 1797ExternalTwoByteString::Resource* ExternalTwoByteString::resource() { 1798 return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)); 1799} 1800 1801 1802void ExternalTwoByteString::set_resource( 1803 ExternalTwoByteString::Resource* resource) { 1804 *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)) = resource; 1805} 1806 1807 1808byte ByteArray::get(int index) { 1809 ASSERT(index >= 0 && index < this->length()); 1810 return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); 1811} 1812 1813 1814void ByteArray::set(int index, byte value) { 1815 ASSERT(index >= 0 && index < this->length()); 1816 WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value); 1817} 1818 1819 1820int ByteArray::get_int(int index) { 1821 ASSERT(index >= 0 && (index * kIntSize) < this->length()); 1822 return READ_INT_FIELD(this, kHeaderSize + index * kIntSize); 1823} 1824 1825 1826ByteArray* ByteArray::FromDataStartAddress(Address address) { 1827 ASSERT_TAG_ALIGNED(address); 1828 return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag); 1829} 1830 1831 1832Address ByteArray::GetDataStartAddress() { 1833 return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize; 1834} 1835 1836 1837uint8_t* PixelArray::external_pointer() { 1838 intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset); 1839 return reinterpret_cast<uint8_t*>(ptr); 1840} 1841 1842 1843void PixelArray::set_external_pointer(uint8_t* value, WriteBarrierMode mode) { 1844 intptr_t ptr = reinterpret_cast<intptr_t>(value); 1845 WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr); 1846} 1847 1848 1849uint8_t PixelArray::get(int index) { 1850 ASSERT((index >= 0) && (index < this->length())); 1851 uint8_t* ptr = external_pointer(); 1852 return ptr[index]; 1853} 1854 1855 1856void PixelArray::set(int index, uint8_t value) { 1857 ASSERT((index >= 0) && (index < this->length())); 1858 uint8_t* ptr = external_pointer(); 1859 ptr[index] = value; 1860} 1861 1862 1863void* ExternalArray::external_pointer() { 1864 intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset); 1865 return reinterpret_cast<void*>(ptr); 1866} 1867 1868 1869void ExternalArray::set_external_pointer(void* value, WriteBarrierMode mode) { 1870 intptr_t ptr = reinterpret_cast<intptr_t>(value); 1871 WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr); 1872} 1873 1874 1875int8_t ExternalByteArray::get(int index) { 1876 ASSERT((index >= 0) && (index < this->length())); 1877 int8_t* ptr = static_cast<int8_t*>(external_pointer()); 1878 return ptr[index]; 1879} 1880 1881 1882void ExternalByteArray::set(int index, int8_t value) { 1883 ASSERT((index >= 0) && (index < this->length())); 1884 int8_t* ptr = static_cast<int8_t*>(external_pointer()); 1885 ptr[index] = value; 1886} 1887 1888 1889uint8_t ExternalUnsignedByteArray::get(int index) { 1890 ASSERT((index >= 0) && (index < this->length())); 1891 uint8_t* ptr = static_cast<uint8_t*>(external_pointer()); 1892 return ptr[index]; 1893} 1894 1895 1896void ExternalUnsignedByteArray::set(int index, uint8_t value) { 1897 ASSERT((index >= 0) && (index < this->length())); 1898 uint8_t* ptr = static_cast<uint8_t*>(external_pointer()); 1899 ptr[index] = value; 1900} 1901 1902 1903int16_t ExternalShortArray::get(int index) { 1904 ASSERT((index >= 0) && (index < this->length())); 1905 int16_t* ptr = static_cast<int16_t*>(external_pointer()); 1906 return ptr[index]; 1907} 1908 1909 1910void ExternalShortArray::set(int index, int16_t value) { 1911 ASSERT((index >= 0) && (index < this->length())); 1912 int16_t* ptr = static_cast<int16_t*>(external_pointer()); 1913 ptr[index] = value; 1914} 1915 1916 1917uint16_t ExternalUnsignedShortArray::get(int index) { 1918 ASSERT((index >= 0) && (index < this->length())); 1919 uint16_t* ptr = static_cast<uint16_t*>(external_pointer()); 1920 return ptr[index]; 1921} 1922 1923 1924void ExternalUnsignedShortArray::set(int index, uint16_t value) { 1925 ASSERT((index >= 0) && (index < this->length())); 1926 uint16_t* ptr = static_cast<uint16_t*>(external_pointer()); 1927 ptr[index] = value; 1928} 1929 1930 1931int32_t ExternalIntArray::get(int index) { 1932 ASSERT((index >= 0) && (index < this->length())); 1933 int32_t* ptr = static_cast<int32_t*>(external_pointer()); 1934 return ptr[index]; 1935} 1936 1937 1938void ExternalIntArray::set(int index, int32_t value) { 1939 ASSERT((index >= 0) && (index < this->length())); 1940 int32_t* ptr = static_cast<int32_t*>(external_pointer()); 1941 ptr[index] = value; 1942} 1943 1944 1945uint32_t ExternalUnsignedIntArray::get(int index) { 1946 ASSERT((index >= 0) && (index < this->length())); 1947 uint32_t* ptr = static_cast<uint32_t*>(external_pointer()); 1948 return ptr[index]; 1949} 1950 1951 1952void ExternalUnsignedIntArray::set(int index, uint32_t value) { 1953 ASSERT((index >= 0) && (index < this->length())); 1954 uint32_t* ptr = static_cast<uint32_t*>(external_pointer()); 1955 ptr[index] = value; 1956} 1957 1958 1959float ExternalFloatArray::get(int index) { 1960 ASSERT((index >= 0) && (index < this->length())); 1961 float* ptr = static_cast<float*>(external_pointer()); 1962 return ptr[index]; 1963} 1964 1965 1966void ExternalFloatArray::set(int index, float value) { 1967 ASSERT((index >= 0) && (index < this->length())); 1968 float* ptr = static_cast<float*>(external_pointer()); 1969 ptr[index] = value; 1970} 1971 1972 1973int Map::instance_size() { 1974 return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2; 1975} 1976 1977 1978int Map::inobject_properties() { 1979 return READ_BYTE_FIELD(this, kInObjectPropertiesOffset); 1980} 1981 1982 1983int Map::pre_allocated_property_fields() { 1984 return READ_BYTE_FIELD(this, kPreAllocatedPropertyFieldsOffset); 1985} 1986 1987 1988int HeapObject::SizeFromMap(Map* map) { 1989 InstanceType instance_type = map->instance_type(); 1990 // Only inline the most frequent cases. 1991 if (instance_type == JS_OBJECT_TYPE || 1992 (instance_type & (kIsNotStringMask | kStringRepresentationMask)) == 1993 (kStringTag | kConsStringTag) || 1994 instance_type == JS_ARRAY_TYPE) return map->instance_size(); 1995 if (instance_type == FIXED_ARRAY_TYPE) { 1996 return reinterpret_cast<FixedArray*>(this)->FixedArraySize(); 1997 } 1998 if (instance_type == BYTE_ARRAY_TYPE) { 1999 return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); 2000 } 2001 // Otherwise do the general size computation. 2002 return SlowSizeFromMap(map); 2003} 2004 2005 2006void Map::set_instance_size(int value) { 2007 ASSERT_EQ(0, value & (kPointerSize - 1)); 2008 value >>= kPointerSizeLog2; 2009 ASSERT(0 <= value && value < 256); 2010 WRITE_BYTE_FIELD(this, kInstanceSizeOffset, static_cast<byte>(value)); 2011} 2012 2013 2014void Map::set_inobject_properties(int value) { 2015 ASSERT(0 <= value && value < 256); 2016 WRITE_BYTE_FIELD(this, kInObjectPropertiesOffset, static_cast<byte>(value)); 2017} 2018 2019 2020void Map::set_pre_allocated_property_fields(int value) { 2021 ASSERT(0 <= value && value < 256); 2022 WRITE_BYTE_FIELD(this, 2023 kPreAllocatedPropertyFieldsOffset, 2024 static_cast<byte>(value)); 2025} 2026 2027 2028InstanceType Map::instance_type() { 2029 return static_cast<InstanceType>(READ_BYTE_FIELD(this, kInstanceTypeOffset)); 2030} 2031 2032 2033void Map::set_instance_type(InstanceType value) { 2034 ASSERT(0 <= value && value < 256); 2035 WRITE_BYTE_FIELD(this, kInstanceTypeOffset, value); 2036} 2037 2038 2039int Map::unused_property_fields() { 2040 return READ_BYTE_FIELD(this, kUnusedPropertyFieldsOffset); 2041} 2042 2043 2044void Map::set_unused_property_fields(int value) { 2045 WRITE_BYTE_FIELD(this, kUnusedPropertyFieldsOffset, Min(value, 255)); 2046} 2047 2048 2049byte Map::bit_field() { 2050 return READ_BYTE_FIELD(this, kBitFieldOffset); 2051} 2052 2053 2054void Map::set_bit_field(byte value) { 2055 WRITE_BYTE_FIELD(this, kBitFieldOffset, value); 2056} 2057 2058 2059byte Map::bit_field2() { 2060 return READ_BYTE_FIELD(this, kBitField2Offset); 2061} 2062 2063 2064void Map::set_bit_field2(byte value) { 2065 WRITE_BYTE_FIELD(this, kBitField2Offset, value); 2066} 2067 2068 2069void Map::set_non_instance_prototype(bool value) { 2070 if (value) { 2071 set_bit_field(bit_field() | (1 << kHasNonInstancePrototype)); 2072 } else { 2073 set_bit_field(bit_field() & ~(1 << kHasNonInstancePrototype)); 2074 } 2075} 2076 2077 2078bool Map::has_non_instance_prototype() { 2079 return ((1 << kHasNonInstancePrototype) & bit_field()) != 0; 2080} 2081 2082 2083void Map::set_is_access_check_needed(bool access_check_needed) { 2084 if (access_check_needed) { 2085 set_bit_field(bit_field() | (1 << kIsAccessCheckNeeded)); 2086 } else { 2087 set_bit_field(bit_field() & ~(1 << kIsAccessCheckNeeded)); 2088 } 2089} 2090 2091 2092bool Map::is_access_check_needed() { 2093 return ((1 << kIsAccessCheckNeeded) & bit_field()) != 0; 2094} 2095 2096 2097Code::Flags Code::flags() { 2098 return static_cast<Flags>(READ_INT_FIELD(this, kFlagsOffset)); 2099} 2100 2101 2102void Code::set_flags(Code::Flags flags) { 2103 STATIC_ASSERT(Code::NUMBER_OF_KINDS <= (kFlagsKindMask >> kFlagsKindShift)+1); 2104 // Make sure that all call stubs have an arguments count. 2105 ASSERT(ExtractKindFromFlags(flags) != CALL_IC || 2106 ExtractArgumentsCountFromFlags(flags) >= 0); 2107 WRITE_INT_FIELD(this, kFlagsOffset, flags); 2108} 2109 2110 2111Code::Kind Code::kind() { 2112 return ExtractKindFromFlags(flags()); 2113} 2114 2115 2116InLoopFlag Code::ic_in_loop() { 2117 return ExtractICInLoopFromFlags(flags()); 2118} 2119 2120 2121InlineCacheState Code::ic_state() { 2122 InlineCacheState result = ExtractICStateFromFlags(flags()); 2123 // Only allow uninitialized or debugger states for non-IC code 2124 // objects. This is used in the debugger to determine whether or not 2125 // a call to code object has been replaced with a debug break call. 2126 ASSERT(is_inline_cache_stub() || 2127 result == UNINITIALIZED || 2128 result == DEBUG_BREAK || 2129 result == DEBUG_PREPARE_STEP_IN); 2130 return result; 2131} 2132 2133 2134PropertyType Code::type() { 2135 ASSERT(ic_state() == MONOMORPHIC); 2136 return ExtractTypeFromFlags(flags()); 2137} 2138 2139 2140int Code::arguments_count() { 2141 ASSERT(is_call_stub() || kind() == STUB); 2142 return ExtractArgumentsCountFromFlags(flags()); 2143} 2144 2145 2146CodeStub::Major Code::major_key() { 2147 ASSERT(kind() == STUB); 2148 return static_cast<CodeStub::Major>(READ_BYTE_FIELD(this, 2149 kStubMajorKeyOffset)); 2150} 2151 2152 2153void Code::set_major_key(CodeStub::Major major) { 2154 ASSERT(kind() == STUB); 2155 ASSERT(0 <= major && major < 256); 2156 WRITE_BYTE_FIELD(this, kStubMajorKeyOffset, major); 2157} 2158 2159 2160bool Code::is_inline_cache_stub() { 2161 Kind kind = this->kind(); 2162 return kind >= FIRST_IC_KIND && kind <= LAST_IC_KIND; 2163} 2164 2165 2166Code::Flags Code::ComputeFlags(Kind kind, 2167 InLoopFlag in_loop, 2168 InlineCacheState ic_state, 2169 PropertyType type, 2170 int argc) { 2171 // Compute the bit mask. 2172 int bits = kind << kFlagsKindShift; 2173 if (in_loop) bits |= kFlagsICInLoopMask; 2174 bits |= ic_state << kFlagsICStateShift; 2175 bits |= type << kFlagsTypeShift; 2176 bits |= argc << kFlagsArgumentsCountShift; 2177 // Cast to flags and validate result before returning it. 2178 Flags result = static_cast<Flags>(bits); 2179 ASSERT(ExtractKindFromFlags(result) == kind); 2180 ASSERT(ExtractICStateFromFlags(result) == ic_state); 2181 ASSERT(ExtractICInLoopFromFlags(result) == in_loop); 2182 ASSERT(ExtractTypeFromFlags(result) == type); 2183 ASSERT(ExtractArgumentsCountFromFlags(result) == argc); 2184 return result; 2185} 2186 2187 2188Code::Flags Code::ComputeMonomorphicFlags(Kind kind, 2189 PropertyType type, 2190 InLoopFlag in_loop, 2191 int argc) { 2192 return ComputeFlags(kind, in_loop, MONOMORPHIC, type, argc); 2193} 2194 2195 2196Code::Kind Code::ExtractKindFromFlags(Flags flags) { 2197 int bits = (flags & kFlagsKindMask) >> kFlagsKindShift; 2198 return static_cast<Kind>(bits); 2199} 2200 2201 2202InlineCacheState Code::ExtractICStateFromFlags(Flags flags) { 2203 int bits = (flags & kFlagsICStateMask) >> kFlagsICStateShift; 2204 return static_cast<InlineCacheState>(bits); 2205} 2206 2207 2208InLoopFlag Code::ExtractICInLoopFromFlags(Flags flags) { 2209 int bits = (flags & kFlagsICInLoopMask); 2210 return bits != 0 ? IN_LOOP : NOT_IN_LOOP; 2211} 2212 2213 2214PropertyType Code::ExtractTypeFromFlags(Flags flags) { 2215 int bits = (flags & kFlagsTypeMask) >> kFlagsTypeShift; 2216 return static_cast<PropertyType>(bits); 2217} 2218 2219 2220int Code::ExtractArgumentsCountFromFlags(Flags flags) { 2221 return (flags & kFlagsArgumentsCountMask) >> kFlagsArgumentsCountShift; 2222} 2223 2224 2225Code::Flags Code::RemoveTypeFromFlags(Flags flags) { 2226 int bits = flags & ~kFlagsTypeMask; 2227 return static_cast<Flags>(bits); 2228} 2229 2230 2231Code* Code::GetCodeFromTargetAddress(Address address) { 2232 HeapObject* code = HeapObject::FromAddress(address - Code::kHeaderSize); 2233 // GetCodeFromTargetAddress might be called when marking objects during mark 2234 // sweep. reinterpret_cast is therefore used instead of the more appropriate 2235 // Code::cast. Code::cast does not work when the object's map is 2236 // marked. 2237 Code* result = reinterpret_cast<Code*>(code); 2238 return result; 2239} 2240 2241 2242Object* Map::prototype() { 2243 return READ_FIELD(this, kPrototypeOffset); 2244} 2245 2246 2247void Map::set_prototype(Object* value, WriteBarrierMode mode) { 2248 ASSERT(value->IsNull() || value->IsJSObject()); 2249 WRITE_FIELD(this, kPrototypeOffset, value); 2250 CONDITIONAL_WRITE_BARRIER(this, kPrototypeOffset, mode); 2251} 2252 2253 2254ACCESSORS(Map, instance_descriptors, DescriptorArray, 2255 kInstanceDescriptorsOffset) 2256ACCESSORS(Map, code_cache, FixedArray, kCodeCacheOffset) 2257ACCESSORS(Map, constructor, Object, kConstructorOffset) 2258 2259ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset) 2260ACCESSORS(JSFunction, literals, FixedArray, kLiteralsOffset) 2261 2262ACCESSORS(GlobalObject, builtins, JSBuiltinsObject, kBuiltinsOffset) 2263ACCESSORS(GlobalObject, global_context, Context, kGlobalContextOffset) 2264ACCESSORS(GlobalObject, global_receiver, JSObject, kGlobalReceiverOffset) 2265 2266ACCESSORS(JSGlobalProxy, context, Object, kContextOffset) 2267 2268ACCESSORS(AccessorInfo, getter, Object, kGetterOffset) 2269ACCESSORS(AccessorInfo, setter, Object, kSetterOffset) 2270ACCESSORS(AccessorInfo, data, Object, kDataOffset) 2271ACCESSORS(AccessorInfo, name, Object, kNameOffset) 2272ACCESSORS(AccessorInfo, flag, Smi, kFlagOffset) 2273ACCESSORS(AccessorInfo, load_stub_cache, Object, kLoadStubCacheOffset) 2274 2275ACCESSORS(AccessCheckInfo, named_callback, Object, kNamedCallbackOffset) 2276ACCESSORS(AccessCheckInfo, indexed_callback, Object, kIndexedCallbackOffset) 2277ACCESSORS(AccessCheckInfo, data, Object, kDataOffset) 2278 2279ACCESSORS(InterceptorInfo, getter, Object, kGetterOffset) 2280ACCESSORS(InterceptorInfo, setter, Object, kSetterOffset) 2281ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) 2282ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset) 2283ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset) 2284ACCESSORS(InterceptorInfo, data, Object, kDataOffset) 2285 2286ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) 2287ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) 2288 2289ACCESSORS(TemplateInfo, tag, Object, kTagOffset) 2290ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset) 2291 2292ACCESSORS(FunctionTemplateInfo, serial_number, Object, kSerialNumberOffset) 2293ACCESSORS(FunctionTemplateInfo, call_code, Object, kCallCodeOffset) 2294ACCESSORS(FunctionTemplateInfo, property_accessors, Object, 2295 kPropertyAccessorsOffset) 2296ACCESSORS(FunctionTemplateInfo, prototype_template, Object, 2297 kPrototypeTemplateOffset) 2298ACCESSORS(FunctionTemplateInfo, parent_template, Object, kParentTemplateOffset) 2299ACCESSORS(FunctionTemplateInfo, named_property_handler, Object, 2300 kNamedPropertyHandlerOffset) 2301ACCESSORS(FunctionTemplateInfo, indexed_property_handler, Object, 2302 kIndexedPropertyHandlerOffset) 2303ACCESSORS(FunctionTemplateInfo, instance_template, Object, 2304 kInstanceTemplateOffset) 2305ACCESSORS(FunctionTemplateInfo, class_name, Object, kClassNameOffset) 2306ACCESSORS(FunctionTemplateInfo, signature, Object, kSignatureOffset) 2307ACCESSORS(FunctionTemplateInfo, instance_call_handler, Object, 2308 kInstanceCallHandlerOffset) 2309ACCESSORS(FunctionTemplateInfo, access_check_info, Object, 2310 kAccessCheckInfoOffset) 2311ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset) 2312 2313ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset) 2314ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, 2315 kInternalFieldCountOffset) 2316 2317ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) 2318ACCESSORS(SignatureInfo, args, Object, kArgsOffset) 2319 2320ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset) 2321 2322ACCESSORS(Script, source, Object, kSourceOffset) 2323ACCESSORS(Script, name, Object, kNameOffset) 2324ACCESSORS(Script, id, Object, kIdOffset) 2325ACCESSORS(Script, line_offset, Smi, kLineOffsetOffset) 2326ACCESSORS(Script, column_offset, Smi, kColumnOffsetOffset) 2327ACCESSORS(Script, data, Object, kDataOffset) 2328ACCESSORS(Script, context_data, Object, kContextOffset) 2329ACCESSORS(Script, wrapper, Proxy, kWrapperOffset) 2330ACCESSORS(Script, type, Smi, kTypeOffset) 2331ACCESSORS(Script, compilation_type, Smi, kCompilationTypeOffset) 2332ACCESSORS(Script, line_ends, Object, kLineEndsOffset) 2333ACCESSORS(Script, eval_from_shared, Object, kEvalFromSharedOffset) 2334ACCESSORS(Script, eval_from_instructions_offset, Smi, 2335 kEvalFrominstructionsOffsetOffset) 2336 2337#ifdef ENABLE_DEBUGGER_SUPPORT 2338ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoIndex) 2339ACCESSORS(DebugInfo, original_code, Code, kOriginalCodeIndex) 2340ACCESSORS(DebugInfo, code, Code, kPatchedCodeIndex) 2341ACCESSORS(DebugInfo, break_points, FixedArray, kBreakPointsStateIndex) 2342 2343ACCESSORS(BreakPointInfo, code_position, Smi, kCodePositionIndex) 2344ACCESSORS(BreakPointInfo, source_position, Smi, kSourcePositionIndex) 2345ACCESSORS(BreakPointInfo, statement_position, Smi, kStatementPositionIndex) 2346ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsIndex) 2347#endif 2348 2349ACCESSORS(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset) 2350ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset) 2351ACCESSORS(SharedFunctionInfo, instance_class_name, Object, 2352 kInstanceClassNameOffset) 2353ACCESSORS(SharedFunctionInfo, function_data, Object, 2354 kExternalReferenceDataOffset) 2355ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset) 2356ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset) 2357ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset) 2358ACCESSORS(SharedFunctionInfo, this_property_assignments, Object, 2359 kThisPropertyAssignmentsOffset) 2360 2361BOOL_ACCESSORS(FunctionTemplateInfo, flag, hidden_prototype, 2362 kHiddenPrototypeBit) 2363BOOL_ACCESSORS(FunctionTemplateInfo, flag, undetectable, kUndetectableBit) 2364BOOL_ACCESSORS(FunctionTemplateInfo, flag, needs_access_check, 2365 kNeedsAccessCheckBit) 2366BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_expression, 2367 kIsExpressionBit) 2368BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_toplevel, 2369 kIsTopLevelBit) 2370BOOL_GETTER(SharedFunctionInfo, compiler_hints, 2371 has_only_simple_this_property_assignments, 2372 kHasOnlySimpleThisPropertyAssignments) 2373BOOL_ACCESSORS(SharedFunctionInfo, 2374 compiler_hints, 2375 try_fast_codegen, 2376 kTryFastCodegen) 2377 2378INT_ACCESSORS(SharedFunctionInfo, length, kLengthOffset) 2379INT_ACCESSORS(SharedFunctionInfo, formal_parameter_count, 2380 kFormalParameterCountOffset) 2381INT_ACCESSORS(SharedFunctionInfo, expected_nof_properties, 2382 kExpectedNofPropertiesOffset) 2383INT_ACCESSORS(SharedFunctionInfo, start_position_and_type, 2384 kStartPositionAndTypeOffset) 2385INT_ACCESSORS(SharedFunctionInfo, end_position, kEndPositionOffset) 2386INT_ACCESSORS(SharedFunctionInfo, function_token_position, 2387 kFunctionTokenPositionOffset) 2388INT_ACCESSORS(SharedFunctionInfo, compiler_hints, 2389 kCompilerHintsOffset) 2390INT_ACCESSORS(SharedFunctionInfo, this_property_assignments_count, 2391 kThisPropertyAssignmentsCountOffset) 2392 2393 2394bool Script::HasValidSource() { 2395 Object* src = this->source(); 2396 if (!src->IsString()) return true; 2397 String* src_str = String::cast(src); 2398 if (!StringShape(src_str).IsExternal()) return true; 2399 if (src_str->IsAsciiRepresentation()) { 2400 return ExternalAsciiString::cast(src)->resource() != NULL; 2401 } else if (src_str->IsTwoByteRepresentation()) { 2402 return ExternalTwoByteString::cast(src)->resource() != NULL; 2403 } 2404 return true; 2405} 2406 2407 2408void SharedFunctionInfo::DontAdaptArguments() { 2409 ASSERT(code()->kind() == Code::BUILTIN); 2410 set_formal_parameter_count(kDontAdaptArgumentsSentinel); 2411} 2412 2413 2414int SharedFunctionInfo::start_position() { 2415 return start_position_and_type() >> kStartPositionShift; 2416} 2417 2418 2419void SharedFunctionInfo::set_start_position(int start_position) { 2420 set_start_position_and_type((start_position << kStartPositionShift) 2421 | (start_position_and_type() & ~kStartPositionMask)); 2422} 2423 2424 2425Code* SharedFunctionInfo::code() { 2426 return Code::cast(READ_FIELD(this, kCodeOffset)); 2427} 2428 2429 2430void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) { 2431 WRITE_FIELD(this, kCodeOffset, value); 2432 CONDITIONAL_WRITE_BARRIER(this, kCodeOffset, mode); 2433} 2434 2435 2436bool SharedFunctionInfo::is_compiled() { 2437 // TODO(1242782): Create a code kind for uncompiled code. 2438 return code()->kind() != Code::STUB; 2439} 2440 2441 2442bool JSFunction::IsBoilerplate() { 2443 return map() == Heap::boilerplate_function_map(); 2444} 2445 2446 2447bool JSFunction::IsBuiltin() { 2448 return context()->global()->IsJSBuiltinsObject(); 2449} 2450 2451 2452bool JSObject::IsLoaded() { 2453 return !map()->needs_loading(); 2454} 2455 2456 2457Code* JSFunction::code() { 2458 return shared()->code(); 2459} 2460 2461 2462void JSFunction::set_code(Code* value) { 2463 shared()->set_code(value); 2464} 2465 2466 2467Context* JSFunction::context() { 2468 return Context::cast(READ_FIELD(this, kContextOffset)); 2469} 2470 2471 2472Object* JSFunction::unchecked_context() { 2473 return READ_FIELD(this, kContextOffset); 2474} 2475 2476 2477void JSFunction::set_context(Object* value) { 2478 ASSERT(value == Heap::undefined_value() || value->IsContext()); 2479 WRITE_FIELD(this, kContextOffset, value); 2480 WRITE_BARRIER(this, kContextOffset); 2481} 2482 2483ACCESSORS(JSFunction, prototype_or_initial_map, Object, 2484 kPrototypeOrInitialMapOffset) 2485 2486 2487Map* JSFunction::initial_map() { 2488 return Map::cast(prototype_or_initial_map()); 2489} 2490 2491 2492void JSFunction::set_initial_map(Map* value) { 2493 set_prototype_or_initial_map(value); 2494} 2495 2496 2497bool JSFunction::has_initial_map() { 2498 return prototype_or_initial_map()->IsMap(); 2499} 2500 2501 2502bool JSFunction::has_instance_prototype() { 2503 return has_initial_map() || !prototype_or_initial_map()->IsTheHole(); 2504} 2505 2506 2507bool JSFunction::has_prototype() { 2508 return map()->has_non_instance_prototype() || has_instance_prototype(); 2509} 2510 2511 2512Object* JSFunction::instance_prototype() { 2513 ASSERT(has_instance_prototype()); 2514 if (has_initial_map()) return initial_map()->prototype(); 2515 // When there is no initial map and the prototype is a JSObject, the 2516 // initial map field is used for the prototype field. 2517 return prototype_or_initial_map(); 2518} 2519 2520 2521Object* JSFunction::prototype() { 2522 ASSERT(has_prototype()); 2523 // If the function's prototype property has been set to a non-JSObject 2524 // value, that value is stored in the constructor field of the map. 2525 if (map()->has_non_instance_prototype()) return map()->constructor(); 2526 return instance_prototype(); 2527} 2528 2529 2530bool JSFunction::is_compiled() { 2531 return shared()->is_compiled(); 2532} 2533 2534 2535int JSFunction::NumberOfLiterals() { 2536 return literals()->length(); 2537} 2538 2539 2540Object* JSBuiltinsObject::javascript_builtin(Builtins::JavaScript id) { 2541 ASSERT(0 <= id && id < kJSBuiltinsCount); 2542 return READ_FIELD(this, kJSBuiltinsOffset + (id * kPointerSize)); 2543} 2544 2545 2546void JSBuiltinsObject::set_javascript_builtin(Builtins::JavaScript id, 2547 Object* value) { 2548 ASSERT(0 <= id && id < kJSBuiltinsCount); 2549 WRITE_FIELD(this, kJSBuiltinsOffset + (id * kPointerSize), value); 2550 WRITE_BARRIER(this, kJSBuiltinsOffset + (id * kPointerSize)); 2551} 2552 2553 2554Address Proxy::proxy() { 2555 return AddressFrom<Address>(READ_INTPTR_FIELD(this, kProxyOffset)); 2556} 2557 2558 2559void Proxy::set_proxy(Address value) { 2560 WRITE_INTPTR_FIELD(this, kProxyOffset, OffsetFrom(value)); 2561} 2562 2563 2564void Proxy::ProxyIterateBody(ObjectVisitor* visitor) { 2565 visitor->VisitExternalReference( 2566 reinterpret_cast<Address *>(FIELD_ADDR(this, kProxyOffset))); 2567} 2568 2569 2570ACCESSORS(JSValue, value, Object, kValueOffset) 2571 2572 2573JSValue* JSValue::cast(Object* obj) { 2574 ASSERT(obj->IsJSValue()); 2575 ASSERT(HeapObject::cast(obj)->Size() == JSValue::kSize); 2576 return reinterpret_cast<JSValue*>(obj); 2577} 2578 2579 2580INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset) 2581INT_ACCESSORS(Code, relocation_size, kRelocationSizeOffset) 2582INT_ACCESSORS(Code, sinfo_size, kSInfoSizeOffset) 2583 2584 2585byte* Code::instruction_start() { 2586 return FIELD_ADDR(this, kHeaderSize); 2587} 2588 2589 2590int Code::body_size() { 2591 return RoundUp(instruction_size() + relocation_size(), kObjectAlignment); 2592} 2593 2594 2595byte* Code::relocation_start() { 2596 return FIELD_ADDR(this, kHeaderSize + instruction_size()); 2597} 2598 2599 2600byte* Code::entry() { 2601 return instruction_start(); 2602} 2603 2604 2605bool Code::contains(byte* pc) { 2606 return (instruction_start() <= pc) && 2607 (pc < instruction_start() + instruction_size()); 2608} 2609 2610 2611byte* Code::sinfo_start() { 2612 return FIELD_ADDR(this, kHeaderSize + body_size()); 2613} 2614 2615 2616ACCESSORS(JSArray, length, Object, kLengthOffset) 2617 2618 2619ACCESSORS(JSRegExp, data, Object, kDataOffset) 2620 2621 2622JSRegExp::Type JSRegExp::TypeTag() { 2623 Object* data = this->data(); 2624 if (data->IsUndefined()) return JSRegExp::NOT_COMPILED; 2625 Smi* smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex)); 2626 return static_cast<JSRegExp::Type>(smi->value()); 2627} 2628 2629 2630int JSRegExp::CaptureCount() { 2631 switch (TypeTag()) { 2632 case ATOM: 2633 return 0; 2634 case IRREGEXP: 2635 return Smi::cast(DataAt(kIrregexpCaptureCountIndex))->value(); 2636 default: 2637 UNREACHABLE(); 2638 return -1; 2639 } 2640} 2641 2642 2643JSRegExp::Flags JSRegExp::GetFlags() { 2644 ASSERT(this->data()->IsFixedArray()); 2645 Object* data = this->data(); 2646 Smi* smi = Smi::cast(FixedArray::cast(data)->get(kFlagsIndex)); 2647 return Flags(smi->value()); 2648} 2649 2650 2651String* JSRegExp::Pattern() { 2652 ASSERT(this->data()->IsFixedArray()); 2653 Object* data = this->data(); 2654 String* pattern= String::cast(FixedArray::cast(data)->get(kSourceIndex)); 2655 return pattern; 2656} 2657 2658 2659Object* JSRegExp::DataAt(int index) { 2660 ASSERT(TypeTag() != NOT_COMPILED); 2661 return FixedArray::cast(data())->get(index); 2662} 2663 2664 2665void JSRegExp::SetDataAt(int index, Object* value) { 2666 ASSERT(TypeTag() != NOT_COMPILED); 2667 ASSERT(index >= kDataIndex); // Only implementation data can be set this way. 2668 FixedArray::cast(data())->set(index, value); 2669} 2670 2671 2672JSObject::ElementsKind JSObject::GetElementsKind() { 2673 Array* array = elements(); 2674 if (array->IsFixedArray()) { 2675 // FAST_ELEMENTS or DICTIONARY_ELEMENTS are both stored in a FixedArray. 2676 if (array->map() == Heap::fixed_array_map()) { 2677 return FAST_ELEMENTS; 2678 } 2679 ASSERT(array->IsDictionary()); 2680 return DICTIONARY_ELEMENTS; 2681 } 2682 if (array->IsExternalArray()) { 2683 switch (array->map()->instance_type()) { 2684 case EXTERNAL_BYTE_ARRAY_TYPE: 2685 return EXTERNAL_BYTE_ELEMENTS; 2686 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: 2687 return EXTERNAL_UNSIGNED_BYTE_ELEMENTS; 2688 case EXTERNAL_SHORT_ARRAY_TYPE: 2689 return EXTERNAL_SHORT_ELEMENTS; 2690 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: 2691 return EXTERNAL_UNSIGNED_SHORT_ELEMENTS; 2692 case EXTERNAL_INT_ARRAY_TYPE: 2693 return EXTERNAL_INT_ELEMENTS; 2694 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: 2695 return EXTERNAL_UNSIGNED_INT_ELEMENTS; 2696 default: 2697 ASSERT(array->map()->instance_type() == EXTERNAL_FLOAT_ARRAY_TYPE); 2698 return EXTERNAL_FLOAT_ELEMENTS; 2699 } 2700 } 2701 ASSERT(array->IsPixelArray()); 2702 return PIXEL_ELEMENTS; 2703} 2704 2705 2706bool JSObject::HasFastElements() { 2707 return GetElementsKind() == FAST_ELEMENTS; 2708} 2709 2710 2711bool JSObject::HasDictionaryElements() { 2712 return GetElementsKind() == DICTIONARY_ELEMENTS; 2713} 2714 2715 2716bool JSObject::HasPixelElements() { 2717 return GetElementsKind() == PIXEL_ELEMENTS; 2718} 2719 2720 2721bool JSObject::HasExternalArrayElements() { 2722 return (HasExternalByteElements() || 2723 HasExternalUnsignedByteElements() || 2724 HasExternalShortElements() || 2725 HasExternalUnsignedShortElements() || 2726 HasExternalIntElements() || 2727 HasExternalUnsignedIntElements() || 2728 HasExternalFloatElements()); 2729} 2730 2731 2732bool JSObject::HasExternalByteElements() { 2733 return GetElementsKind() == EXTERNAL_BYTE_ELEMENTS; 2734} 2735 2736 2737bool JSObject::HasExternalUnsignedByteElements() { 2738 return GetElementsKind() == EXTERNAL_UNSIGNED_BYTE_ELEMENTS; 2739} 2740 2741 2742bool JSObject::HasExternalShortElements() { 2743 return GetElementsKind() == EXTERNAL_SHORT_ELEMENTS; 2744} 2745 2746 2747bool JSObject::HasExternalUnsignedShortElements() { 2748 return GetElementsKind() == EXTERNAL_UNSIGNED_SHORT_ELEMENTS; 2749} 2750 2751 2752bool JSObject::HasExternalIntElements() { 2753 return GetElementsKind() == EXTERNAL_INT_ELEMENTS; 2754} 2755 2756 2757bool JSObject::HasExternalUnsignedIntElements() { 2758 return GetElementsKind() == EXTERNAL_UNSIGNED_INT_ELEMENTS; 2759} 2760 2761 2762bool JSObject::HasExternalFloatElements() { 2763 return GetElementsKind() == EXTERNAL_FLOAT_ELEMENTS; 2764} 2765 2766 2767bool JSObject::HasNamedInterceptor() { 2768 return map()->has_named_interceptor(); 2769} 2770 2771 2772bool JSObject::HasIndexedInterceptor() { 2773 return map()->has_indexed_interceptor(); 2774} 2775 2776 2777StringDictionary* JSObject::property_dictionary() { 2778 ASSERT(!HasFastProperties()); 2779 return StringDictionary::cast(properties()); 2780} 2781 2782 2783NumberDictionary* JSObject::element_dictionary() { 2784 ASSERT(HasDictionaryElements()); 2785 return NumberDictionary::cast(elements()); 2786} 2787 2788 2789bool String::HasHashCode() { 2790 return (hash_field() & kHashComputedMask) != 0; 2791} 2792 2793 2794uint32_t String::Hash() { 2795 // Fast case: has hash code already been computed? 2796 uint32_t field = hash_field(); 2797 if (field & kHashComputedMask) return field >> kHashShift; 2798 // Slow case: compute hash code and set it. 2799 return ComputeAndSetHash(); 2800} 2801 2802 2803StringHasher::StringHasher(int length) 2804 : length_(length), 2805 raw_running_hash_(0), 2806 array_index_(0), 2807 is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize), 2808 is_first_char_(true), 2809 is_valid_(true) { } 2810 2811 2812bool StringHasher::has_trivial_hash() { 2813 return length_ > String::kMaxHashCalcLength; 2814} 2815 2816 2817void StringHasher::AddCharacter(uc32 c) { 2818 // Use the Jenkins one-at-a-time hash function to update the hash 2819 // for the given character. 2820 raw_running_hash_ += c; 2821 raw_running_hash_ += (raw_running_hash_ << 10); 2822 raw_running_hash_ ^= (raw_running_hash_ >> 6); 2823 // Incremental array index computation. 2824 if (is_array_index_) { 2825 if (c < '0' || c > '9') { 2826 is_array_index_ = false; 2827 } else { 2828 int d = c - '0'; 2829 if (is_first_char_) { 2830 is_first_char_ = false; 2831 if (c == '0' && length_ > 1) { 2832 is_array_index_ = false; 2833 return; 2834 } 2835 } 2836 if (array_index_ > 429496729U - ((d + 2) >> 3)) { 2837 is_array_index_ = false; 2838 } else { 2839 array_index_ = array_index_ * 10 + d; 2840 } 2841 } 2842 } 2843} 2844 2845 2846void StringHasher::AddCharacterNoIndex(uc32 c) { 2847 ASSERT(!is_array_index()); 2848 raw_running_hash_ += c; 2849 raw_running_hash_ += (raw_running_hash_ << 10); 2850 raw_running_hash_ ^= (raw_running_hash_ >> 6); 2851} 2852 2853 2854uint32_t StringHasher::GetHash() { 2855 // Get the calculated raw hash value and do some more bit ops to distribute 2856 // the hash further. Ensure that we never return zero as the hash value. 2857 uint32_t result = raw_running_hash_; 2858 result += (result << 3); 2859 result ^= (result >> 11); 2860 result += (result << 15); 2861 if (result == 0) { 2862 result = 27; 2863 } 2864 return result; 2865} 2866 2867 2868bool String::AsArrayIndex(uint32_t* index) { 2869 uint32_t field = hash_field(); 2870 if ((field & kHashComputedMask) && !(field & kIsArrayIndexMask)) return false; 2871 return SlowAsArrayIndex(index); 2872} 2873 2874 2875Object* JSObject::GetPrototype() { 2876 return JSObject::cast(this)->map()->prototype(); 2877} 2878 2879 2880PropertyAttributes JSObject::GetPropertyAttribute(String* key) { 2881 return GetPropertyAttributeWithReceiver(this, key); 2882} 2883 2884// TODO(504): this may be useful in other places too where JSGlobalProxy 2885// is used. 2886Object* JSObject::BypassGlobalProxy() { 2887 if (IsJSGlobalProxy()) { 2888 Object* proto = GetPrototype(); 2889 if (proto->IsNull()) return Heap::undefined_value(); 2890 ASSERT(proto->IsJSGlobalObject()); 2891 return proto; 2892 } 2893 return this; 2894} 2895 2896 2897bool JSObject::HasHiddenPropertiesObject() { 2898 ASSERT(!IsJSGlobalProxy()); 2899 return GetPropertyAttributePostInterceptor(this, 2900 Heap::hidden_symbol(), 2901 false) != ABSENT; 2902} 2903 2904 2905Object* JSObject::GetHiddenPropertiesObject() { 2906 ASSERT(!IsJSGlobalProxy()); 2907 PropertyAttributes attributes; 2908 return GetLocalPropertyPostInterceptor(this, 2909 Heap::hidden_symbol(), 2910 &attributes); 2911} 2912 2913 2914Object* JSObject::SetHiddenPropertiesObject(Object* hidden_obj) { 2915 ASSERT(!IsJSGlobalProxy()); 2916 return SetPropertyPostInterceptor(Heap::hidden_symbol(), 2917 hidden_obj, 2918 DONT_ENUM); 2919} 2920 2921 2922bool JSObject::HasElement(uint32_t index) { 2923 return HasElementWithReceiver(this, index); 2924} 2925 2926 2927bool AccessorInfo::all_can_read() { 2928 return BooleanBit::get(flag(), kAllCanReadBit); 2929} 2930 2931 2932void AccessorInfo::set_all_can_read(bool value) { 2933 set_flag(BooleanBit::set(flag(), kAllCanReadBit, value)); 2934} 2935 2936 2937bool AccessorInfo::all_can_write() { 2938 return BooleanBit::get(flag(), kAllCanWriteBit); 2939} 2940 2941 2942void AccessorInfo::set_all_can_write(bool value) { 2943 set_flag(BooleanBit::set(flag(), kAllCanWriteBit, value)); 2944} 2945 2946 2947bool AccessorInfo::prohibits_overwriting() { 2948 return BooleanBit::get(flag(), kProhibitsOverwritingBit); 2949} 2950 2951 2952void AccessorInfo::set_prohibits_overwriting(bool value) { 2953 set_flag(BooleanBit::set(flag(), kProhibitsOverwritingBit, value)); 2954} 2955 2956 2957PropertyAttributes AccessorInfo::property_attributes() { 2958 return AttributesField::decode(static_cast<uint32_t>(flag()->value())); 2959} 2960 2961 2962void AccessorInfo::set_property_attributes(PropertyAttributes attributes) { 2963 ASSERT(AttributesField::is_valid(attributes)); 2964 int rest_value = flag()->value() & ~AttributesField::mask(); 2965 set_flag(Smi::FromInt(rest_value | AttributesField::encode(attributes))); 2966} 2967 2968template<typename Shape, typename Key> 2969void Dictionary<Shape, Key>::SetEntry(int entry, 2970 Object* key, 2971 Object* value, 2972 PropertyDetails details) { 2973 ASSERT(!key->IsString() || details.IsDeleted() || details.index() > 0); 2974 int index = HashTable<Shape, Key>::EntryToIndex(entry); 2975 WriteBarrierMode mode = FixedArray::GetWriteBarrierMode(); 2976 FixedArray::set(index, key, mode); 2977 FixedArray::set(index+1, value, mode); 2978 FixedArray::fast_set(this, index+2, details.AsSmi()); 2979} 2980 2981 2982void Map::ClearCodeCache() { 2983 // No write barrier is needed since empty_fixed_array is not in new space. 2984 // Please note this function is used during marking: 2985 // - MarkCompactCollector::MarkUnmarkedObject 2986 ASSERT(!Heap::InNewSpace(Heap::raw_unchecked_empty_fixed_array())); 2987 WRITE_FIELD(this, kCodeCacheOffset, Heap::raw_unchecked_empty_fixed_array()); 2988} 2989 2990 2991void JSArray::EnsureSize(int required_size) { 2992 ASSERT(HasFastElements()); 2993 Array* elts = elements(); 2994 const int kArraySizeThatFitsComfortablyInNewSpace = 128; 2995 if (elts->length() < required_size) { 2996 // Doubling in size would be overkill, but leave some slack to avoid 2997 // constantly growing. 2998 Expand(required_size + (required_size >> 3)); 2999 // It's a performance benefit to keep a frequently used array in new-space. 3000 } else if (!Heap::new_space()->Contains(elts) && 3001 required_size < kArraySizeThatFitsComfortablyInNewSpace) { 3002 // Expand will allocate a new backing store in new space even if the size 3003 // we asked for isn't larger than what we had before. 3004 Expand(required_size); 3005 } 3006} 3007 3008 3009void JSArray::SetContent(FixedArray* storage) { 3010 set_length(Smi::FromInt(storage->length()), SKIP_WRITE_BARRIER); 3011 set_elements(storage); 3012} 3013 3014 3015Object* FixedArray::Copy() { 3016 if (length() == 0) return this; 3017 return Heap::CopyFixedArray(this); 3018} 3019 3020 3021#undef CAST_ACCESSOR 3022#undef INT_ACCESSORS 3023#undef SMI_ACCESSORS 3024#undef ACCESSORS 3025#undef FIELD_ADDR 3026#undef READ_FIELD 3027#undef WRITE_FIELD 3028#undef WRITE_BARRIER 3029#undef CONDITIONAL_WRITE_BARRIER 3030#undef READ_MEMADDR_FIELD 3031#undef WRITE_MEMADDR_FIELD 3032#undef READ_DOUBLE_FIELD 3033#undef WRITE_DOUBLE_FIELD 3034#undef READ_INT_FIELD 3035#undef WRITE_INT_FIELD 3036#undef READ_SHORT_FIELD 3037#undef WRITE_SHORT_FIELD 3038#undef READ_BYTE_FIELD 3039#undef WRITE_BYTE_FIELD 3040 3041 3042} } // namespace v8::internal 3043 3044#endif // V8_OBJECTS_INL_H_ 3045