diff options
author | Ryan <ry@tinyclouds.org> | 2009-04-22 19:35:47 +0200 |
---|---|---|
committer | Ryan <ry@tinyclouds.org> | 2009-04-22 19:35:47 +0200 |
commit | 40c0f755c998d2615fe8466aab20c6d81bd463e7 (patch) | |
tree | 51fcb08ba1bd3f745ceb43fd5f814a5700079881 /deps/v8/src/objects-inl.h | |
parent | a93cf503073ba0258c55dec4dc325bdc1509b739 (diff) | |
download | node-new-40c0f755c998d2615fe8466aab20c6d81bd463e7.tar.gz |
import full versions of dependency libraries!
Diffstat (limited to 'deps/v8/src/objects-inl.h')
-rw-r--r-- | deps/v8/src/objects-inl.h | 2597 |
1 files changed, 2597 insertions, 0 deletions
diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h new file mode 100644 index 0000000000..c2143ea026 --- /dev/null +++ b/deps/v8/src/objects-inl.h @@ -0,0 +1,2597 @@ +// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Review notes: +// +// - The use of macros in these inline functions may seem superfluous +// but it is absolutely needed to make sure gcc generates optimal +// code. gcc is not happy when attempting to inline too deep. +// + +#ifndef V8_OBJECTS_INL_H_ +#define V8_OBJECTS_INL_H_ + +#include "objects.h" +#include "contexts.h" +#include "conversions-inl.h" +#include "property.h" + +namespace v8 { namespace internal { + +PropertyDetails::PropertyDetails(Smi* smi) { + value_ = smi->value(); +} + + +Smi* PropertyDetails::AsSmi() { + return Smi::FromInt(value_); +} + + +#define CAST_ACCESSOR(type) \ + type* type::cast(Object* object) { \ + ASSERT(object->Is##type()); \ + return reinterpret_cast<type*>(object); \ + } + + +#define INT_ACCESSORS(holder, name, offset) \ + int holder::name() { return READ_INT_FIELD(this, offset); } \ + void holder::set_##name(int value) { WRITE_INT_FIELD(this, offset, value); } + + +#define ACCESSORS(holder, name, type, offset) \ + type* holder::name() { return type::cast(READ_FIELD(this, offset)); } \ + void holder::set_##name(type* value, WriteBarrierMode mode) { \ + WRITE_FIELD(this, offset, value); \ + CONDITIONAL_WRITE_BARRIER(this, offset, mode); \ + } + + + +#define SMI_ACCESSORS(holder, name, offset) \ + int holder::name() { \ + Object* value = READ_FIELD(this, offset); \ + return Smi::cast(value)->value(); \ + } \ + void holder::set_##name(int value) { \ + WRITE_FIELD(this, offset, Smi::FromInt(value)); \ + } + + +#define BOOL_ACCESSORS(holder, field, name, offset) \ + bool holder::name() { \ + return BooleanBit::get(field(), offset); \ + } \ + void holder::set_##name(bool value) { \ + set_##field(BooleanBit::set(field(), offset, value)); \ + } + + +bool Object::IsSmi() { + return HAS_SMI_TAG(this); +} + + +bool Object::IsHeapObject() { + return HAS_HEAP_OBJECT_TAG(this); +} + + +bool Object::IsHeapNumber() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == HEAP_NUMBER_TYPE; +} + + +bool Object::IsString() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() < FIRST_NONSTRING_TYPE; +} + + +bool Object::IsSymbol() { + if (!this->IsHeapObject()) return false; + uint32_t type = HeapObject::cast(this)->map()->instance_type(); + return (type & (kIsNotStringMask | kIsSymbolMask)) == + (kStringTag | kSymbolTag); +} + + +bool Object::IsConsString() { + if (!this->IsHeapObject()) return false; + uint32_t type = HeapObject::cast(this)->map()->instance_type(); + return (type & (kIsNotStringMask | kStringRepresentationMask)) == + (kStringTag | kConsStringTag); +} + + +#ifdef DEBUG +// These are for cast checks. If you need one of these in release +// mode you should consider using a StringShape before moving it out +// of the ifdef + +bool Object::IsSeqString() { + if (!IsString()) return false; + return StringShape(String::cast(this)).IsSequential(); +} + + +bool Object::IsSeqAsciiString() { + if (!IsString()) return false; + return StringShape(String::cast(this)).IsSequential() && + StringShape(String::cast(this)).IsAsciiRepresentation(); +} + + +bool Object::IsSeqTwoByteString() { + if (!IsString()) return false; + return StringShape(String::cast(this)).IsSequential() && + StringShape(String::cast(this)).IsTwoByteRepresentation(); +} + + +bool Object::IsExternalString() { + if (!IsString()) return false; + return StringShape(String::cast(this)).IsExternal(); +} + + +bool Object::IsExternalAsciiString() { + if (!IsString()) return false; + return StringShape(String::cast(this)).IsExternal() && + StringShape(String::cast(this)).IsAsciiRepresentation(); +} + + +bool Object::IsExternalTwoByteString() { + if (!IsString()) return false; + return StringShape(String::cast(this)).IsExternal() && + StringShape(String::cast(this)).IsTwoByteRepresentation(); +} + + +bool Object::IsSlicedString() { + if (!IsString()) return false; + return StringShape(String::cast(this)).IsSliced(); +} + + +#endif // DEBUG + + +StringShape::StringShape(String* str) + : type_(str->map()->instance_type()) { + set_valid(); + ASSERT((type_ & kIsNotStringMask) == kStringTag); +} + + +StringShape::StringShape(Map* map) + : type_(map->instance_type()) { + set_valid(); + ASSERT((type_ & kIsNotStringMask) == kStringTag); +} + + +StringShape::StringShape(InstanceType t) + : type_(static_cast<uint32_t>(t)) { + set_valid(); + ASSERT((type_ & kIsNotStringMask) == kStringTag); +} + + +bool StringShape::IsSymbol() { + ASSERT(valid()); + return (type_ & kIsSymbolMask) == kSymbolTag; +} + + +bool StringShape::IsAsciiRepresentation() { + return (type_ & kStringEncodingMask) == kAsciiStringTag; +} + + +bool StringShape::IsTwoByteRepresentation() { + return (type_ & kStringEncodingMask) == kTwoByteStringTag; +} + + +bool StringShape::IsCons() { + return (type_ & kStringRepresentationMask) == kConsStringTag; +} + + +bool StringShape::IsSliced() { + return (type_ & kStringRepresentationMask) == kSlicedStringTag; +} + + +bool StringShape::IsExternal() { + return (type_ & kStringRepresentationMask) == kExternalStringTag; +} + + +bool StringShape::IsSequential() { + return (type_ & kStringRepresentationMask) == kSeqStringTag; +} + + +StringRepresentationTag StringShape::representation_tag() { + uint32_t tag = (type_ & kStringRepresentationMask); + return static_cast<StringRepresentationTag>(tag); +} + + +uint32_t StringShape::full_representation_tag() { + return (type_ & (kStringRepresentationMask | kStringEncodingMask)); +} + + +uint32_t StringShape::size_tag() { + return (type_ & kStringSizeMask); +} + + +bool StringShape::IsSequentialAscii() { + return full_representation_tag() == (kSeqStringTag | kAsciiStringTag); +} + + +bool StringShape::IsSequentialTwoByte() { + return full_representation_tag() == (kSeqStringTag | kTwoByteStringTag); +} + + +bool StringShape::IsExternalAscii() { + return full_representation_tag() == (kExternalStringTag | kAsciiStringTag); +} + + +bool StringShape::IsExternalTwoByte() { + return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag); +} + + +uc32 FlatStringReader::Get(int index) { + ASSERT(0 <= index && index <= length_); + if (is_ascii_) { + return static_cast<const byte*>(start_)[index]; + } else { + return static_cast<const uc16*>(start_)[index]; + } +} + + +bool Object::IsNumber() { + return IsSmi() || IsHeapNumber(); +} + + +bool Object::IsByteArray() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == BYTE_ARRAY_TYPE; +} + + +bool Object::IsFailure() { + return HAS_FAILURE_TAG(this); +} + + +bool Object::IsRetryAfterGC() { + return HAS_FAILURE_TAG(this) + && Failure::cast(this)->type() == Failure::RETRY_AFTER_GC; +} + + +bool Object::IsOutOfMemoryFailure() { + return HAS_FAILURE_TAG(this) + && Failure::cast(this)->IsOutOfMemoryException(); +} + + +bool Object::IsException() { + return this == Failure::Exception(); +} + + +bool Object::IsJSObject() { + return IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_OBJECT_TYPE; +} + + +bool Object::IsJSContextExtensionObject() { + return IsHeapObject() + && (HeapObject::cast(this)->map()->instance_type() == + JS_CONTEXT_EXTENSION_OBJECT_TYPE); +} + + +bool Object::IsMap() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == MAP_TYPE; +} + + +bool Object::IsFixedArray() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == FIXED_ARRAY_TYPE; +} + + +bool Object::IsDescriptorArray() { + return IsFixedArray(); +} + + +bool Object::IsContext() { + return Object::IsHeapObject() + && (HeapObject::cast(this)->map() == Heap::context_map() || + HeapObject::cast(this)->map() == Heap::catch_context_map() || + HeapObject::cast(this)->map() == Heap::global_context_map()); +} + + +bool Object::IsCatchContext() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map() == Heap::catch_context_map(); +} + + +bool Object::IsGlobalContext() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map() == Heap::global_context_map(); +} + + +bool Object::IsJSFunction() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE; +} + + +template <> inline bool Is<JSFunction>(Object* obj) { + return obj->IsJSFunction(); +} + + +bool Object::IsCode() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == CODE_TYPE; +} + + +bool Object::IsOddball() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == ODDBALL_TYPE; +} + + +bool Object::IsSharedFunctionInfo() { + return Object::IsHeapObject() && + (HeapObject::cast(this)->map()->instance_type() == + SHARED_FUNCTION_INFO_TYPE); +} + + +bool Object::IsJSValue() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == JS_VALUE_TYPE; +} + + +bool Object::IsStringWrapper() { + return IsJSValue() && JSValue::cast(this)->value()->IsString(); +} + + +bool Object::IsProxy() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE; +} + + +bool Object::IsBoolean() { + return IsTrue() || IsFalse(); +} + + +bool Object::IsJSArray() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE; +} + + +bool Object::IsJSRegExp() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map()->instance_type() == JS_REGEXP_TYPE; +} + + +template <> inline bool Is<JSArray>(Object* obj) { + return obj->IsJSArray(); +} + + +bool Object::IsHashTable() { + return Object::IsHeapObject() + && HeapObject::cast(this)->map() == Heap::hash_table_map(); +} + + +bool Object::IsDictionary() { + return IsHashTable() && this != Heap::symbol_table(); +} + + +bool Object::IsSymbolTable() { + return IsHashTable() && this == Heap::symbol_table(); +} + + +bool Object::IsCompilationCacheTable() { + return IsHashTable(); +} + + +bool Object::IsMapCache() { + return IsHashTable(); +} + + +bool Object::IsLookupCache() { + return IsHashTable(); +} + + +bool Object::IsPrimitive() { + return IsOddball() || IsNumber() || IsString(); +} + + +bool Object::IsJSGlobalProxy() { + bool result = IsHeapObject() && + (HeapObject::cast(this)->map()->instance_type() == + JS_GLOBAL_PROXY_TYPE); + ASSERT(!result || IsAccessCheckNeeded()); + return result; +} + + +bool Object::IsGlobalObject() { + if (!IsHeapObject()) return false; + + InstanceType type = HeapObject::cast(this)->map()->instance_type(); + return type == JS_GLOBAL_OBJECT_TYPE || + type == JS_BUILTINS_OBJECT_TYPE; +} + + +bool Object::IsJSGlobalObject() { + return IsHeapObject() && + (HeapObject::cast(this)->map()->instance_type() == + JS_GLOBAL_OBJECT_TYPE); +} + + +bool Object::IsJSBuiltinsObject() { + return IsHeapObject() && + (HeapObject::cast(this)->map()->instance_type() == + JS_BUILTINS_OBJECT_TYPE); +} + + +bool Object::IsUndetectableObject() { + return IsHeapObject() + && HeapObject::cast(this)->map()->is_undetectable(); +} + + +bool Object::IsAccessCheckNeeded() { + return IsHeapObject() + && HeapObject::cast(this)->map()->is_access_check_needed(); +} + + +bool Object::IsStruct() { + if (!IsHeapObject()) return false; + switch (HeapObject::cast(this)->map()->instance_type()) { +#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return true; + STRUCT_LIST(MAKE_STRUCT_CASE) +#undef MAKE_STRUCT_CASE + default: return false; + } +} + + +#define MAKE_STRUCT_PREDICATE(NAME, Name, name) \ + bool Object::Is##Name() { \ + return Object::IsHeapObject() \ + && HeapObject::cast(this)->map()->instance_type() == NAME##_TYPE; \ + } + STRUCT_LIST(MAKE_STRUCT_PREDICATE) +#undef MAKE_STRUCT_PREDICATE + + +bool Object::IsUndefined() { + return this == Heap::undefined_value(); +} + + +bool Object::IsTheHole() { + return this == Heap::the_hole_value(); +} + + +bool Object::IsNull() { + return this == Heap::null_value(); +} + + +bool Object::IsTrue() { + return this == Heap::true_value(); +} + + +bool Object::IsFalse() { + return this == Heap::false_value(); +} + + +double Object::Number() { + ASSERT(IsNumber()); + return IsSmi() + ? static_cast<double>(reinterpret_cast<Smi*>(this)->value()) + : reinterpret_cast<HeapNumber*>(this)->value(); +} + + + +Object* Object::ToSmi() { + if (IsSmi()) return this; + if (IsHeapNumber()) { + double value = HeapNumber::cast(this)->value(); + int int_value = FastD2I(value); + if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { + return Smi::FromInt(int_value); + } + } + return Failure::Exception(); +} + + +bool Object::HasSpecificClassOf(String* name) { + return this->IsJSObject() && (JSObject::cast(this)->class_name() == name); +} + + +Object* Object::GetElement(uint32_t index) { + return GetElementWithReceiver(this, index); +} + + +Object* Object::GetProperty(String* key) { + PropertyAttributes attributes; + return GetPropertyWithReceiver(this, key, &attributes); +} + + +Object* Object::GetProperty(String* key, PropertyAttributes* attributes) { + return GetPropertyWithReceiver(this, key, attributes); +} + + +#define FIELD_ADDR(p, offset) \ + (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag) + +#define READ_FIELD(p, offset) \ + (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset))) + +#define WRITE_FIELD(p, offset, value) \ + (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value) + + +#define WRITE_BARRIER(object, offset) \ + Heap::RecordWrite(object->address(), offset); + +// CONDITIONAL_WRITE_BARRIER must be issued after the actual +// write due to the assert validating the written value. +#define CONDITIONAL_WRITE_BARRIER(object, offset, mode) \ + if (mode == UPDATE_WRITE_BARRIER) { \ + Heap::RecordWrite(object->address(), offset); \ + } else { \ + ASSERT(mode == SKIP_WRITE_BARRIER); \ + ASSERT(Heap::InNewSpace(object) || \ + !Heap::InNewSpace(READ_FIELD(object, offset))); \ + } + +#define READ_DOUBLE_FIELD(p, offset) \ + (*reinterpret_cast<double*>(FIELD_ADDR(p, offset))) + +#define WRITE_DOUBLE_FIELD(p, offset, value) \ + (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)) = value) + +#define READ_INT_FIELD(p, offset) \ + (*reinterpret_cast<int*>(FIELD_ADDR(p, offset))) + +#define WRITE_INT_FIELD(p, offset, value) \ + (*reinterpret_cast<int*>(FIELD_ADDR(p, offset)) = value) + +#define READ_UINT32_FIELD(p, offset) \ + (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset))) + +#define WRITE_UINT32_FIELD(p, offset, value) \ + (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset)) = value) + +#define READ_SHORT_FIELD(p, offset) \ + (*reinterpret_cast<uint16_t*>(FIELD_ADDR(p, offset))) + +#define WRITE_SHORT_FIELD(p, offset, value) \ + (*reinterpret_cast<uint16_t*>(FIELD_ADDR(p, offset)) = value) + +#define READ_BYTE_FIELD(p, offset) \ + (*reinterpret_cast<byte*>(FIELD_ADDR(p, offset))) + +#define WRITE_BYTE_FIELD(p, offset, value) \ + (*reinterpret_cast<byte*>(FIELD_ADDR(p, offset)) = value) + + +Object** HeapObject::RawField(HeapObject* obj, int byte_offset) { + return &READ_FIELD(obj, byte_offset); +} + + +int Smi::value() { + return reinterpret_cast<int>(this) >> kSmiTagSize; +} + + +Smi* Smi::FromInt(int value) { + ASSERT(Smi::IsValid(value)); + return reinterpret_cast<Smi*>((value << kSmiTagSize) | kSmiTag); +} + + +Failure::Type Failure::type() const { + return static_cast<Type>(value() & kFailureTypeTagMask); +} + + +bool Failure::IsInternalError() const { + return type() == INTERNAL_ERROR; +} + + +bool Failure::IsOutOfMemoryException() const { + return type() == OUT_OF_MEMORY_EXCEPTION; +} + + +int Failure::requested() const { + const int kShiftBits = + kFailureTypeTagSize + kSpaceTagSize - kObjectAlignmentBits; + STATIC_ASSERT(kShiftBits >= 0); + ASSERT(type() == RETRY_AFTER_GC); + return value() >> kShiftBits; +} + + +AllocationSpace Failure::allocation_space() const { + ASSERT_EQ(RETRY_AFTER_GC, type()); + return static_cast<AllocationSpace>((value() >> kFailureTypeTagSize) + & kSpaceTagMask); +} + + +Failure* Failure::InternalError() { + return Construct(INTERNAL_ERROR); +} + + +Failure* Failure::Exception() { + return Construct(EXCEPTION); +} + +Failure* Failure::OutOfMemoryException() { + return Construct(OUT_OF_MEMORY_EXCEPTION); +} + + +int Failure::value() const { + return reinterpret_cast<int>(this) >> kFailureTagSize; +} + + +Failure* Failure::RetryAfterGC(int requested_bytes) { + int requested = requested_bytes >> kObjectAlignmentBits; + int value = (requested << kSpaceTagSize) | NEW_SPACE; + ASSERT(value >> kSpaceTagSize == requested); + ASSERT(Smi::IsValid(value)); + ASSERT(value == ((value << kFailureTypeTagSize) >> kFailureTypeTagSize)); + ASSERT(Smi::IsValid(value << kFailureTypeTagSize)); + return Construct(RETRY_AFTER_GC, value); +} + + +Failure* Failure::Construct(Type type, int value) { + int info = (value << kFailureTypeTagSize) | type; + ASSERT(Smi::IsValid(info)); // Same validation check as in Smi + return reinterpret_cast<Failure*>((info << kFailureTagSize) | kFailureTag); +} + + +bool Smi::IsValid(int value) { +#ifdef DEBUG + bool in_range = (value >= kMinValue) && (value <= kMaxValue); +#endif + // To be representable as an tagged small integer, the two + // most-significant bits of 'value' must be either 00 or 11 due to + // sign-extension. To check this we add 01 to the two + // most-significant bits, and check if the most-significant bit is 0 + // + // CAUTION: The original code below: + // bool result = ((value + 0x40000000) & 0x80000000) == 0; + // may lead to incorrect results according to the C language spec, and + // in fact doesn't work correctly with gcc4.1.1 in some cases: The + // compiler may produce undefined results in case of signed integer + // overflow. The computation must be done w/ unsigned ints. + bool result = + ((static_cast<unsigned int>(value) + 0x40000000U) & 0x80000000U) == 0; + ASSERT(result == in_range); + return result; +} + + +MapWord MapWord::FromMap(Map* map) { + return MapWord(reinterpret_cast<uintptr_t>(map)); +} + + +Map* MapWord::ToMap() { + return reinterpret_cast<Map*>(value_); +} + + +bool MapWord::IsForwardingAddress() { + return HAS_SMI_TAG(reinterpret_cast<Object*>(value_)); +} + + +MapWord MapWord::FromForwardingAddress(HeapObject* object) { + Address raw = reinterpret_cast<Address>(object) - kHeapObjectTag; + return MapWord(reinterpret_cast<uintptr_t>(raw)); +} + + +HeapObject* MapWord::ToForwardingAddress() { + ASSERT(IsForwardingAddress()); + return HeapObject::FromAddress(reinterpret_cast<Address>(value_)); +} + + +bool MapWord::IsMarked() { + return (value_ & kMarkingMask) == 0; +} + + +void MapWord::SetMark() { + value_ &= ~kMarkingMask; +} + + +void MapWord::ClearMark() { + value_ |= kMarkingMask; +} + + +bool MapWord::IsOverflowed() { + return (value_ & kOverflowMask) != 0; +} + + +void MapWord::SetOverflow() { + value_ |= kOverflowMask; +} + + +void MapWord::ClearOverflow() { + value_ &= ~kOverflowMask; +} + + +MapWord MapWord::EncodeAddress(Address map_address, int offset) { + // Offset is the distance in live bytes from the first live object in the + // same page. The offset between two objects in the same page should not + // exceed the object area size of a page. + ASSERT(0 <= offset && offset < Page::kObjectAreaSize); + + int compact_offset = offset >> kObjectAlignmentBits; + ASSERT(compact_offset < (1 << kForwardingOffsetBits)); + + Page* map_page = Page::FromAddress(map_address); + ASSERT_MAP_PAGE_INDEX(map_page->mc_page_index); + + int map_page_offset = + map_page->Offset(map_address) >> kObjectAlignmentBits; + + uintptr_t encoding = + (compact_offset << kForwardingOffsetShift) | + (map_page_offset << kMapPageOffsetShift) | + (map_page->mc_page_index << kMapPageIndexShift); + return MapWord(encoding); +} + + +Address MapWord::DecodeMapAddress(MapSpace* map_space) { + int map_page_index = (value_ & kMapPageIndexMask) >> kMapPageIndexShift; + ASSERT_MAP_PAGE_INDEX(map_page_index); + + int map_page_offset = + ((value_ & kMapPageOffsetMask) >> kMapPageOffsetShift) + << kObjectAlignmentBits; + + return (map_space->PageAddress(map_page_index) + map_page_offset); +} + + +int MapWord::DecodeOffset() { + // The offset field is represented in the kForwardingOffsetBits + // most-significant bits. + int offset = (value_ >> kForwardingOffsetShift) << kObjectAlignmentBits; + ASSERT(0 <= offset && offset < Page::kObjectAreaSize); + return offset; +} + + +MapWord MapWord::FromEncodedAddress(Address address) { + return MapWord(reinterpret_cast<uintptr_t>(address)); +} + + +Address MapWord::ToEncodedAddress() { + return reinterpret_cast<Address>(value_); +} + + +#ifdef DEBUG +void HeapObject::VerifyObjectField(int offset) { + VerifyPointer(READ_FIELD(this, offset)); +} +#endif + + +Map* HeapObject::map() { + return map_word().ToMap(); +} + + +void HeapObject::set_map(Map* value) { + set_map_word(MapWord::FromMap(value)); +} + + +MapWord HeapObject::map_word() { + return MapWord(reinterpret_cast<uintptr_t>(READ_FIELD(this, kMapOffset))); +} + + +void HeapObject::set_map_word(MapWord map_word) { + // WRITE_FIELD does not update the remembered set, but there is no need + // here. + WRITE_FIELD(this, kMapOffset, reinterpret_cast<Object*>(map_word.value_)); +} + + +HeapObject* HeapObject::FromAddress(Address address) { + ASSERT_TAG_ALIGNED(address); + return reinterpret_cast<HeapObject*>(address + kHeapObjectTag); +} + + +Address HeapObject::address() { + return reinterpret_cast<Address>(this) - kHeapObjectTag; +} + + +int HeapObject::Size() { + return SizeFromMap(map()); +} + + +void HeapObject::IteratePointers(ObjectVisitor* v, int start, int end) { + v->VisitPointers(reinterpret_cast<Object**>(FIELD_ADDR(this, start)), + reinterpret_cast<Object**>(FIELD_ADDR(this, end))); +} + + +void HeapObject::IteratePointer(ObjectVisitor* v, int offset) { + v->VisitPointer(reinterpret_cast<Object**>(FIELD_ADDR(this, offset))); +} + + +bool HeapObject::IsMarked() { + return map_word().IsMarked(); +} + + +void HeapObject::SetMark() { + ASSERT(!IsMarked()); + MapWord first_word = map_word(); + first_word.SetMark(); + set_map_word(first_word); +} + + +void HeapObject::ClearMark() { + ASSERT(IsMarked()); + MapWord first_word = map_word(); + first_word.ClearMark(); + set_map_word(first_word); +} + + +bool HeapObject::IsOverflowed() { + return map_word().IsOverflowed(); +} + + +void HeapObject::SetOverflow() { + MapWord first_word = map_word(); + first_word.SetOverflow(); + set_map_word(first_word); +} + + +void HeapObject::ClearOverflow() { + ASSERT(IsOverflowed()); + MapWord first_word = map_word(); + first_word.ClearOverflow(); + set_map_word(first_word); +} + + +double HeapNumber::value() { + return READ_DOUBLE_FIELD(this, kValueOffset); +} + + +void HeapNumber::set_value(double value) { + WRITE_DOUBLE_FIELD(this, kValueOffset, value); +} + + +ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset) +ACCESSORS(JSObject, elements, FixedArray, kElementsOffset) + + +void JSObject::initialize_properties() { + ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); + WRITE_FIELD(this, kPropertiesOffset, Heap::empty_fixed_array()); +} + + +void JSObject::initialize_elements() { + ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); + WRITE_FIELD(this, kElementsOffset, Heap::empty_fixed_array()); +} + + +ACCESSORS(Oddball, to_string, String, kToStringOffset) +ACCESSORS(Oddball, to_number, Object, kToNumberOffset) + + +int JSObject::GetHeaderSize() { + switch (map()->instance_type()) { + case JS_GLOBAL_PROXY_TYPE: + return JSGlobalProxy::kSize; + case JS_GLOBAL_OBJECT_TYPE: + return JSGlobalObject::kSize; + case JS_BUILTINS_OBJECT_TYPE: + return JSBuiltinsObject::kSize; + case JS_FUNCTION_TYPE: + return JSFunction::kSize; + case JS_VALUE_TYPE: + return JSValue::kSize; + case JS_ARRAY_TYPE: + return JSValue::kSize; + case JS_REGEXP_TYPE: + return JSValue::kSize; + case JS_OBJECT_TYPE: + case JS_CONTEXT_EXTENSION_OBJECT_TYPE: + return JSObject::kHeaderSize; + default: + UNREACHABLE(); + return 0; + } +} + + +int JSObject::GetInternalFieldCount() { + ASSERT(1 << kPointerSizeLog2 == kPointerSize); + // Make sure to adjust for the number of in-object properties. These + // properties do contribute to the size, but are not internal fields. + return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) - + map()->inobject_properties(); +} + + +Object* JSObject::GetInternalField(int index) { + ASSERT(index < GetInternalFieldCount() && index >= 0); + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. + return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index)); +} + + +void JSObject::SetInternalField(int index, Object* value) { + ASSERT(index < GetInternalFieldCount() && index >= 0); + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. + int offset = GetHeaderSize() + (kPointerSize * index); + WRITE_FIELD(this, offset, value); + WRITE_BARRIER(this, offset); +} + + +// Access fast-case object properties at index. The use of these routines +// is needed to correctly distinguish between properties stored in-object and +// properties stored in the properties array. +Object* JSObject::FastPropertyAt(int index) { + // Adjust for the number of properties stored in the object. + index -= map()->inobject_properties(); + if (index < 0) { + int offset = map()->instance_size() + (index * kPointerSize); + return READ_FIELD(this, offset); + } else { + ASSERT(index < properties()->length()); + return properties()->get(index); + } +} + + +Object* JSObject::FastPropertyAtPut(int index, Object* value) { + // Adjust for the number of properties stored in the object. + index -= map()->inobject_properties(); + if (index < 0) { + int offset = map()->instance_size() + (index * kPointerSize); + WRITE_FIELD(this, offset, value); + WRITE_BARRIER(this, offset); + } else { + ASSERT(index < properties()->length()); + properties()->set(index, value); + } + return value; +} + + +Object* JSObject::InObjectPropertyAt(int index) { + // Adjust for the number of properties stored in the object. + index -= map()->inobject_properties(); + ASSERT(index < 0); + int offset = map()->instance_size() + (index * kPointerSize); + return READ_FIELD(this, offset); +} + + +Object* JSObject::InObjectPropertyAtPut(int index, + Object* value, + WriteBarrierMode mode) { + // Adjust for the number of properties stored in the object. + index -= map()->inobject_properties(); + ASSERT(index < 0); + int offset = map()->instance_size() + (index * kPointerSize); + WRITE_FIELD(this, offset, value); + CONDITIONAL_WRITE_BARRIER(this, offset, mode); + return value; +} + + + +void JSObject::InitializeBody(int object_size) { + Object* value = Heap::undefined_value(); + for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) { + WRITE_FIELD(this, offset, value); + } +} + + +void Struct::InitializeBody(int object_size) { + Object* value = Heap::undefined_value(); + for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) { + WRITE_FIELD(this, offset, value); + } +} + + +bool JSObject::HasFastProperties() { + return !properties()->IsDictionary(); +} + + +bool Array::IndexFromObject(Object* object, uint32_t* index) { + if (object->IsSmi()) { + int value = Smi::cast(object)->value(); + if (value < 0) return false; + *index = value; + return true; + } + if (object->IsHeapNumber()) { + double value = HeapNumber::cast(object)->value(); + uint32_t uint_value = static_cast<uint32_t>(value); + if (value == static_cast<double>(uint_value)) { + *index = uint_value; + return true; + } + } + return false; +} + + +bool Object::IsStringObjectWithCharacterAt(uint32_t index) { + if (!this->IsJSValue()) return false; + + JSValue* js_value = JSValue::cast(this); + if (!js_value->value()->IsString()) return false; + + String* str = String::cast(js_value->value()); + if (index >= (uint32_t)str->length()) return false; + + return true; +} + + +Object* FixedArray::get(int index) { + ASSERT(index >= 0 && index < this->length()); + return READ_FIELD(this, kHeaderSize + index * kPointerSize); +} + + +void FixedArray::set(int index, Smi* value) { + ASSERT(reinterpret_cast<Object*>(value)->IsSmi()); + int offset = kHeaderSize + index * kPointerSize; + WRITE_FIELD(this, offset, value); +} + + +void FixedArray::set(int index, Object* value) { + ASSERT(index >= 0 && index < this->length()); + int offset = kHeaderSize + index * kPointerSize; + WRITE_FIELD(this, offset, value); + WRITE_BARRIER(this, offset); +} + + +WriteBarrierMode HeapObject::GetWriteBarrierMode() { + if (Heap::InNewSpace(this)) return SKIP_WRITE_BARRIER; + return UPDATE_WRITE_BARRIER; +} + + +void FixedArray::set(int index, + Object* value, + WriteBarrierMode mode) { + ASSERT(index >= 0 && index < this->length()); + int offset = kHeaderSize + index * kPointerSize; + WRITE_FIELD(this, offset, value); + CONDITIONAL_WRITE_BARRIER(this, offset, mode); +} + + +void FixedArray::fast_set(FixedArray* array, int index, Object* value) { + ASSERT(index >= 0 && index < array->length()); + WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value); +} + + +void FixedArray::set_undefined(int index) { + ASSERT(index >= 0 && index < this->length()); + ASSERT(!Heap::InNewSpace(Heap::undefined_value())); + WRITE_FIELD(this, kHeaderSize + index * kPointerSize, + Heap::undefined_value()); +} + + +void FixedArray::set_null(int index) { + ASSERT(index >= 0 && index < this->length()); + ASSERT(!Heap::InNewSpace(Heap::null_value())); + WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::null_value()); +} + + +void FixedArray::set_the_hole(int index) { + ASSERT(index >= 0 && index < this->length()); + ASSERT(!Heap::InNewSpace(Heap::the_hole_value())); + WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::the_hole_value()); +} + + +bool DescriptorArray::IsEmpty() { + ASSERT(this == Heap::empty_descriptor_array() || + this->length() > 2); + return this == Heap::empty_descriptor_array(); +} + + +void DescriptorArray::fast_swap(FixedArray* array, int first, int second) { + Object* tmp = array->get(first); + fast_set(array, first, array->get(second)); + fast_set(array, second, tmp); +} + + +int DescriptorArray::Search(String* name) { + SLOW_ASSERT(IsSortedNoDuplicates()); + + // Check for empty descriptor array. + int nof = number_of_descriptors(); + if (nof == 0) return kNotFound; + + // Fast case: do linear search for small arrays. + const int kMaxElementsForLinearSearch = 8; + if (StringShape(name).IsSymbol() && nof < kMaxElementsForLinearSearch) { + return LinearSearch(name, nof); + } + + // Slow case: perform binary search. + return BinarySearch(name, 0, nof - 1); +} + + + +String* DescriptorArray::GetKey(int descriptor_number) { + ASSERT(descriptor_number < number_of_descriptors()); + return String::cast(get(ToKeyIndex(descriptor_number))); +} + + +Object* DescriptorArray::GetValue(int descriptor_number) { + ASSERT(descriptor_number < number_of_descriptors()); + return GetContentArray()->get(ToValueIndex(descriptor_number)); +} + + +Smi* DescriptorArray::GetDetails(int descriptor_number) { + ASSERT(descriptor_number < number_of_descriptors()); + return Smi::cast(GetContentArray()->get(ToDetailsIndex(descriptor_number))); +} + + +void DescriptorArray::Get(int descriptor_number, Descriptor* desc) { + desc->Init(GetKey(descriptor_number), + GetValue(descriptor_number), + GetDetails(descriptor_number)); +} + + +void DescriptorArray::Set(int descriptor_number, Descriptor* desc) { + // Range check. + ASSERT(descriptor_number < number_of_descriptors()); + + // Make sure non of the elements in desc are in new space. + ASSERT(!Heap::InNewSpace(desc->GetKey())); + ASSERT(!Heap::InNewSpace(desc->GetValue())); + + fast_set(this, ToKeyIndex(descriptor_number), desc->GetKey()); + FixedArray* content_array = GetContentArray(); + fast_set(content_array, ToValueIndex(descriptor_number), desc->GetValue()); + fast_set(content_array, ToDetailsIndex(descriptor_number), + desc->GetDetails().AsSmi()); +} + + +void DescriptorArray::Swap(int first, int second) { + fast_swap(this, ToKeyIndex(first), ToKeyIndex(second)); + FixedArray* content_array = GetContentArray(); + fast_swap(content_array, ToValueIndex(first), ToValueIndex(second)); + fast_swap(content_array, ToDetailsIndex(first), ToDetailsIndex(second)); +} + + +bool Dictionary::requires_slow_elements() { + Object* max_index_object = get(kMaxNumberKeyIndex); + if (!max_index_object->IsSmi()) return false; + return 0 != + (Smi::cast(max_index_object)->value() & kRequiresSlowElementsMask); +} + + +uint32_t Dictionary::max_number_key() { + ASSERT(!requires_slow_elements()); + Object* max_index_object = get(kMaxNumberKeyIndex); + if (!max_index_object->IsSmi()) return 0; + uint32_t value = static_cast<uint32_t>(Smi::cast(max_index_object)->value()); + return value >> kRequiresSlowElementsTagSize; +} + + +void Dictionary::set_requires_slow_elements() { + set(kMaxNumberKeyIndex, + Smi::FromInt(kRequiresSlowElementsMask), + SKIP_WRITE_BARRIER); +} + + +// ------------------------------------ +// Cast operations + + +CAST_ACCESSOR(FixedArray) +CAST_ACCESSOR(DescriptorArray) +CAST_ACCESSOR(Dictionary) +CAST_ACCESSOR(SymbolTable) +CAST_ACCESSOR(CompilationCacheTable) +CAST_ACCESSOR(MapCache) +CAST_ACCESSOR(LookupCache) +CAST_ACCESSOR(String) +CAST_ACCESSOR(SeqString) +CAST_ACCESSOR(SeqAsciiString) +CAST_ACCESSOR(SeqTwoByteString) +CAST_ACCESSOR(ConsString) +CAST_ACCESSOR(SlicedString) +CAST_ACCESSOR(ExternalString) +CAST_ACCESSOR(ExternalAsciiString) +CAST_ACCESSOR(ExternalTwoByteString) +CAST_ACCESSOR(JSObject) +CAST_ACCESSOR(Smi) +CAST_ACCESSOR(Failure) +CAST_ACCESSOR(HeapObject) +CAST_ACCESSOR(HeapNumber) +CAST_ACCESSOR(Oddball) +CAST_ACCESSOR(SharedFunctionInfo) +CAST_ACCESSOR(Map) +CAST_ACCESSOR(JSFunction) +CAST_ACCESSOR(GlobalObject) +CAST_ACCESSOR(JSGlobalProxy) +CAST_ACCESSOR(JSGlobalObject) +CAST_ACCESSOR(JSBuiltinsObject) +CAST_ACCESSOR(Code) +CAST_ACCESSOR(JSArray) +CAST_ACCESSOR(JSRegExp) +CAST_ACCESSOR(Proxy) +CAST_ACCESSOR(ByteArray) +CAST_ACCESSOR(Struct) + + +#define MAKE_STRUCT_CAST(NAME, Name, name) CAST_ACCESSOR(Name) + STRUCT_LIST(MAKE_STRUCT_CAST) +#undef MAKE_STRUCT_CAST + +template <int prefix_size, int elem_size> +HashTable<prefix_size, elem_size>* HashTable<prefix_size, elem_size>::cast( + Object* obj) { + ASSERT(obj->IsHashTable()); + return reinterpret_cast<HashTable*>(obj); +} + + +INT_ACCESSORS(Array, length, kLengthOffset) + + +bool String::Equals(String* other) { + if (other == this) return true; + if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) { + return false; + } + return SlowEquals(other); +} + + +int String::length() { + uint32_t len = READ_INT_FIELD(this, kLengthOffset); + + ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); + ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift); + ASSERT(kLongStringTag == 0); + + return len >> (StringShape(this).size_tag() + kLongLengthShift); +} + + +void String::set_length(int value) { + ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); + ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift); + ASSERT(kLongStringTag == 0); + + WRITE_INT_FIELD(this, + kLengthOffset, + value << (StringShape(this).size_tag() + kLongLengthShift)); +} + + +uint32_t String::length_field() { + return READ_UINT32_FIELD(this, kLengthOffset); +} + + +void String::set_length_field(uint32_t value) { + WRITE_UINT32_FIELD(this, kLengthOffset, value); +} + + +Object* String::TryFlattenIfNotFlat() { + // We don't need to flatten strings that are already flat. Since this code + // is inlined, it can be helpful in the flat case to not call out to Flatten. + if (!IsFlat()) { + return TryFlatten(); + } + return this; +} + + +uint16_t String::Get(int index) { + ASSERT(index >= 0 && index < length()); + switch (StringShape(this).full_representation_tag()) { + case kSeqStringTag | kAsciiStringTag: + return SeqAsciiString::cast(this)->SeqAsciiStringGet(index); + case kSeqStringTag | kTwoByteStringTag: + return SeqTwoByteString::cast(this)->SeqTwoByteStringGet(index); + case kConsStringTag | kAsciiStringTag: + case kConsStringTag | kTwoByteStringTag: + return ConsString::cast(this)->ConsStringGet(index); + case kSlicedStringTag | kAsciiStringTag: + case kSlicedStringTag | kTwoByteStringTag: + return SlicedString::cast(this)->SlicedStringGet(index); + case kExternalStringTag | kAsciiStringTag: + return ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index); + case kExternalStringTag | kTwoByteStringTag: + return ExternalTwoByteString::cast(this)->ExternalTwoByteStringGet(index); + default: + break; + } + + UNREACHABLE(); + return 0; +} + + +void String::Set(int index, uint16_t value) { + ASSERT(index >= 0 && index < length()); + ASSERT(StringShape(this).IsSequential()); + + return StringShape(this).IsAsciiRepresentation() + ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value) + : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value); +} + + +bool String::IsFlat() { + switch (StringShape(this).representation_tag()) { + case kConsStringTag: { + String* second = ConsString::cast(this)->second(); + // Only flattened strings have second part empty. + return second->length() == 0; + } + case kSlicedStringTag: { + StringRepresentationTag tag = + StringShape(SlicedString::cast(this)->buffer()).representation_tag(); + return tag == kSeqStringTag || tag == kExternalStringTag; + } + default: + return true; + } +} + + +uint16_t SeqAsciiString::SeqAsciiStringGet(int index) { + ASSERT(index >= 0 && index < length()); + return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); +} + + +void SeqAsciiString::SeqAsciiStringSet(int index, uint16_t value) { + ASSERT(index >= 0 && index < length() && value <= kMaxAsciiCharCode); + WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, + static_cast<byte>(value)); +} + + +Address SeqAsciiString::GetCharsAddress() { + return FIELD_ADDR(this, kHeaderSize); +} + + +char* SeqAsciiString::GetChars() { + return reinterpret_cast<char*>(GetCharsAddress()); +} + + +Address SeqTwoByteString::GetCharsAddress() { + return FIELD_ADDR(this, kHeaderSize); +} + + +uc16* SeqTwoByteString::GetChars() { + return reinterpret_cast<uc16*>(FIELD_ADDR(this, kHeaderSize)); +} + + +uint16_t SeqTwoByteString::SeqTwoByteStringGet(int index) { + ASSERT(index >= 0 && index < length()); + return READ_SHORT_FIELD(this, kHeaderSize + index * kShortSize); +} + + +void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) { + ASSERT(index >= 0 && index < length()); + WRITE_SHORT_FIELD(this, kHeaderSize + index * kShortSize, value); +} + + +int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) { + uint32_t length = READ_INT_FIELD(this, kLengthOffset); + + ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); + ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift); + ASSERT(kLongStringTag == 0); + + // Use the map (and not 'this') to compute the size tag, since + // TwoByteStringSize is called during GC when maps are encoded. + length >>= StringShape(instance_type).size_tag() + kLongLengthShift; + + return SizeFor(length); +} + + +int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) { + uint32_t length = READ_INT_FIELD(this, kLengthOffset); + + ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); + ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift); + ASSERT(kLongStringTag == 0); + + // Use the map (and not 'this') to compute the size tag, since + // AsciiStringSize is called during GC when maps are encoded. + length >>= StringShape(instance_type).size_tag() + kLongLengthShift; + + return SizeFor(length); +} + + +String* ConsString::first() { + ASSERT(String::cast(READ_FIELD(this, kSecondOffset))->length() != 0 || + StringShape( + String::cast( + READ_FIELD(this, kFirstOffset))).IsAsciiRepresentation() + == StringShape(this).IsAsciiRepresentation()); + return String::cast(READ_FIELD(this, kFirstOffset)); +} + + +Object* ConsString::unchecked_first() { + return READ_FIELD(this, kFirstOffset); +} + + +void ConsString::set_first(String* value, WriteBarrierMode mode) { + WRITE_FIELD(this, kFirstOffset, value); + CONDITIONAL_WRITE_BARRIER(this, kFirstOffset, mode); +} + + +String* ConsString::second() { + return String::cast(READ_FIELD(this, kSecondOffset)); +} + + +Object* ConsString::unchecked_second() { + return READ_FIELD(this, kSecondOffset); +} + + +void ConsString::set_second(String* value, WriteBarrierMode mode) { + WRITE_FIELD(this, kSecondOffset, value); + CONDITIONAL_WRITE_BARRIER(this, kSecondOffset, mode); +} + + +String* SlicedString::buffer() { + ASSERT( + StringShape( + String::cast(READ_FIELD(this, kBufferOffset))).IsAsciiRepresentation() + == StringShape(this).IsAsciiRepresentation()); + return String::cast(READ_FIELD(this, kBufferOffset)); +} + + +void SlicedString::set_buffer(String* buffer) { + WRITE_FIELD(this, kBufferOffset, buffer); + WRITE_BARRIER(this, kBufferOffset); +} + + +int SlicedString::start() { + return READ_INT_FIELD(this, kStartOffset); +} + + +void SlicedString::set_start(int start) { + WRITE_INT_FIELD(this, kStartOffset, start); +} + + +ExternalAsciiString::Resource* ExternalAsciiString::resource() { + return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)); +} + + +void ExternalAsciiString::set_resource( + ExternalAsciiString::Resource* resource) { + *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)) = resource; +} + + +Map* ExternalAsciiString::StringMap(int length) { + Map* map; + // Number of characters: determines the map. + if (length <= String::kMaxShortStringSize) { + map = Heap::short_external_ascii_string_map(); + } else if (length <= String::kMaxMediumStringSize) { + map = Heap::medium_external_ascii_string_map(); + } else { + map = Heap::long_external_ascii_string_map(); + } + return map; +} + + +Map* ExternalAsciiString::SymbolMap(int length) { + Map* map; + // Number of characters: determines the map. + if (length <= String::kMaxShortStringSize) { + map = Heap::short_external_ascii_symbol_map(); + } else if (length <= String::kMaxMediumStringSize) { + map = Heap::medium_external_ascii_symbol_map(); + } else { + map = Heap::long_external_ascii_symbol_map(); + } + return map; +} + + +ExternalTwoByteString::Resource* ExternalTwoByteString::resource() { + return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)); +} + + +void ExternalTwoByteString::set_resource( + ExternalTwoByteString::Resource* resource) { + *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)) = resource; +} + + +Map* ExternalTwoByteString::StringMap(int length) { + Map* map; + // Number of characters: determines the map. + if (length <= String::kMaxShortStringSize) { + map = Heap::short_external_string_map(); + } else if (length <= String::kMaxMediumStringSize) { + map = Heap::medium_external_string_map(); + } else { + map = Heap::long_external_string_map(); + } + return map; +} + + +Map* ExternalTwoByteString::SymbolMap(int length) { + Map* map; + // Number of characters: determines the map. + if (length <= String::kMaxShortStringSize) { + map = Heap::short_external_symbol_map(); + } else if (length <= String::kMaxMediumStringSize) { + map = Heap::medium_external_symbol_map(); + } else { + map = Heap::long_external_symbol_map(); + } + return map; +} + + +byte ByteArray::get(int index) { + ASSERT(index >= 0 && index < this->length()); + return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); +} + + +void ByteArray::set(int index, byte value) { + ASSERT(index >= 0 && index < this->length()); + WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value); +} + + +int ByteArray::get_int(int index) { + ASSERT(index >= 0 && (index * kIntSize) < this->length()); + return READ_INT_FIELD(this, kHeaderSize + index * kIntSize); +} + + +ByteArray* ByteArray::FromDataStartAddress(Address address) { + ASSERT_TAG_ALIGNED(address); + return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag); +} + + +Address ByteArray::GetDataStartAddress() { + return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize; +} + + +int Map::instance_size() { + return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2; +} + + +int Map::inobject_properties() { + return READ_BYTE_FIELD(this, kInObjectPropertiesOffset); +} + + +int HeapObject::SizeFromMap(Map* map) { + InstanceType instance_type = map->instance_type(); + // Only inline the two most frequent cases. + if (instance_type == JS_OBJECT_TYPE) return map->instance_size(); + if (instance_type == FIXED_ARRAY_TYPE) { + return reinterpret_cast<FixedArray*>(this)->FixedArraySize(); + } + // Otherwise do the general size computation. + return SlowSizeFromMap(map); +} + + +void Map::set_instance_size(int value) { + ASSERT((value & ~(kPointerSize - 1)) == value); + value >>= kPointerSizeLog2; + ASSERT(0 <= value && value < 256); + WRITE_BYTE_FIELD(this, kInstanceSizeOffset, static_cast<byte>(value)); +} + + +void Map::set_inobject_properties(int value) { + ASSERT(0 <= value && value < 256); + WRITE_BYTE_FIELD(this, kInObjectPropertiesOffset, static_cast<byte>(value)); +} + + +InstanceType Map::instance_type() { + return static_cast<InstanceType>(READ_BYTE_FIELD(this, kInstanceTypeOffset)); +} + + +void Map::set_instance_type(InstanceType value) { + ASSERT(0 <= value && value < 256); + WRITE_BYTE_FIELD(this, kInstanceTypeOffset, value); +} + + +int Map::unused_property_fields() { + return READ_BYTE_FIELD(this, kUnusedPropertyFieldsOffset); +} + + +void Map::set_unused_property_fields(int value) { + WRITE_BYTE_FIELD(this, kUnusedPropertyFieldsOffset, Min(value, 255)); +} + + +byte Map::bit_field() { + return READ_BYTE_FIELD(this, kBitFieldOffset); +} + + +void Map::set_bit_field(byte value) { + WRITE_BYTE_FIELD(this, kBitFieldOffset, value); +} + + +void Map::set_non_instance_prototype(bool value) { + if (value) { + set_bit_field(bit_field() | (1 << kHasNonInstancePrototype)); + } else { + set_bit_field(bit_field() & ~(1 << kHasNonInstancePrototype)); + } +} + + +bool Map::has_non_instance_prototype() { + return ((1 << kHasNonInstancePrototype) & bit_field()) != 0; +} + + +void Map::set_is_access_check_needed(bool access_check_needed) { + if (access_check_needed) { + set_bit_field(bit_field() | (1 << kIsAccessCheckNeeded)); + } else { + set_bit_field(bit_field() & ~(1 << kIsAccessCheckNeeded)); + } +} + + +bool Map::is_access_check_needed() { + return ((1 << kIsAccessCheckNeeded) & bit_field()) != 0; +} + + +Code::Flags Code::flags() { + return static_cast<Flags>(READ_INT_FIELD(this, kFlagsOffset)); +} + + +void Code::set_flags(Code::Flags flags) { + STATIC_ASSERT(Code::NUMBER_OF_KINDS <= (kFlagsKindMask >> kFlagsKindShift)+1); + // Make sure that all call stubs have an arguments count. + ASSERT(ExtractKindFromFlags(flags) != CALL_IC || + ExtractArgumentsCountFromFlags(flags) >= 0); + WRITE_INT_FIELD(this, kFlagsOffset, flags); +} + + +Code::Kind Code::kind() { + return ExtractKindFromFlags(flags()); +} + + +InlineCacheState Code::ic_state() { + InlineCacheState result = ExtractICStateFromFlags(flags()); + // Only allow uninitialized or debugger states for non-IC code + // objects. This is used in the debugger to determine whether or not + // a call to code object has been replaced with a debug break call. + ASSERT(is_inline_cache_stub() || + result == UNINITIALIZED || + result == DEBUG_BREAK || + result == DEBUG_PREPARE_STEP_IN); + return result; +} + + +PropertyType Code::type() { + ASSERT(ic_state() == MONOMORPHIC); + return ExtractTypeFromFlags(flags()); +} + + +int Code::arguments_count() { + ASSERT(is_call_stub() || kind() == STUB); + return ExtractArgumentsCountFromFlags(flags()); +} + + +CodeStub::Major Code::major_key() { + ASSERT(kind() == STUB); + return static_cast<CodeStub::Major>(READ_BYTE_FIELD(this, + kStubMajorKeyOffset)); +} + + +void Code::set_major_key(CodeStub::Major major) { + ASSERT(kind() == STUB); + ASSERT(0 <= major && major < 256); + WRITE_BYTE_FIELD(this, kStubMajorKeyOffset, major); +} + + +bool Code::is_inline_cache_stub() { + Kind kind = this->kind(); + return kind >= FIRST_IC_KIND && kind <= LAST_IC_KIND; +} + + +Code::Flags Code::ComputeFlags(Kind kind, + InlineCacheState ic_state, + PropertyType type, + int argc) { + // Compute the bit mask. + int bits = kind << kFlagsKindShift; + bits |= ic_state << kFlagsICStateShift; + bits |= type << kFlagsTypeShift; + bits |= argc << kFlagsArgumentsCountShift; + // Cast to flags and validate result before returning it. + Flags result = static_cast<Flags>(bits); + ASSERT(ExtractKindFromFlags(result) == kind); + ASSERT(ExtractICStateFromFlags(result) == ic_state); + ASSERT(ExtractTypeFromFlags(result) == type); + ASSERT(ExtractArgumentsCountFromFlags(result) == argc); + return result; +} + + +Code::Flags Code::ComputeMonomorphicFlags(Kind kind, + PropertyType type, + int argc) { + return ComputeFlags(kind, MONOMORPHIC, type, argc); +} + + +Code::Kind Code::ExtractKindFromFlags(Flags flags) { + int bits = (flags & kFlagsKindMask) >> kFlagsKindShift; + return static_cast<Kind>(bits); +} + + +InlineCacheState Code::ExtractICStateFromFlags(Flags flags) { + int bits = (flags & kFlagsICStateMask) >> kFlagsICStateShift; + return static_cast<InlineCacheState>(bits); +} + + +PropertyType Code::ExtractTypeFromFlags(Flags flags) { + int bits = (flags & kFlagsTypeMask) >> kFlagsTypeShift; + return static_cast<PropertyType>(bits); +} + + +int Code::ExtractArgumentsCountFromFlags(Flags flags) { + return (flags & kFlagsArgumentsCountMask) >> kFlagsArgumentsCountShift; +} + + +Code::Flags Code::RemoveTypeFromFlags(Flags flags) { + int bits = flags & ~kFlagsTypeMask; + return static_cast<Flags>(bits); +} + + +Code* Code::GetCodeFromTargetAddress(Address address) { + HeapObject* code = HeapObject::FromAddress(address - Code::kHeaderSize); + // GetCodeFromTargetAddress might be called when marking objects during mark + // sweep. reinterpret_cast is therefore used instead of the more appropriate + // Code::cast. Code::cast does not work when the object's map is + // marked. + Code* result = reinterpret_cast<Code*>(code); + return result; +} + + +Object* Map::prototype() { + return READ_FIELD(this, kPrototypeOffset); +} + + +void Map::set_prototype(Object* value, WriteBarrierMode mode) { + ASSERT(value->IsNull() || value->IsJSObject()); + WRITE_FIELD(this, kPrototypeOffset, value); + CONDITIONAL_WRITE_BARRIER(this, kPrototypeOffset, mode); +} + + +ACCESSORS(Map, instance_descriptors, DescriptorArray, + kInstanceDescriptorsOffset) +ACCESSORS(Map, code_cache, FixedArray, kCodeCacheOffset) +ACCESSORS(Map, constructor, Object, kConstructorOffset) + +ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset) +ACCESSORS(JSFunction, literals, FixedArray, kLiteralsOffset) + +ACCESSORS(GlobalObject, builtins, JSBuiltinsObject, kBuiltinsOffset) +ACCESSORS(GlobalObject, global_context, Context, kGlobalContextOffset) +ACCESSORS(GlobalObject, global_receiver, JSObject, kGlobalReceiverOffset) + +ACCESSORS(JSGlobalProxy, context, Object, kContextOffset) + +ACCESSORS(AccessorInfo, getter, Object, kGetterOffset) +ACCESSORS(AccessorInfo, setter, Object, kSetterOffset) +ACCESSORS(AccessorInfo, data, Object, kDataOffset) +ACCESSORS(AccessorInfo, name, Object, kNameOffset) +ACCESSORS(AccessorInfo, flag, Smi, kFlagOffset) + +ACCESSORS(AccessCheckInfo, named_callback, Object, kNamedCallbackOffset) +ACCESSORS(AccessCheckInfo, indexed_callback, Object, kIndexedCallbackOffset) +ACCESSORS(AccessCheckInfo, data, Object, kDataOffset) + +ACCESSORS(InterceptorInfo, getter, Object, kGetterOffset) +ACCESSORS(InterceptorInfo, setter, Object, kSetterOffset) +ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) +ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset) +ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset) +ACCESSORS(InterceptorInfo, data, Object, kDataOffset) + +ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) +ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) + +ACCESSORS(TemplateInfo, tag, Object, kTagOffset) +ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset) + +ACCESSORS(FunctionTemplateInfo, serial_number, Object, kSerialNumberOffset) +ACCESSORS(FunctionTemplateInfo, call_code, Object, kCallCodeOffset) +ACCESSORS(FunctionTemplateInfo, property_accessors, Object, + kPropertyAccessorsOffset) +ACCESSORS(FunctionTemplateInfo, prototype_template, Object, + kPrototypeTemplateOffset) +ACCESSORS(FunctionTemplateInfo, parent_template, Object, kParentTemplateOffset) +ACCESSORS(FunctionTemplateInfo, named_property_handler, Object, + kNamedPropertyHandlerOffset) +ACCESSORS(FunctionTemplateInfo, indexed_property_handler, Object, + kIndexedPropertyHandlerOffset) +ACCESSORS(FunctionTemplateInfo, instance_template, Object, + kInstanceTemplateOffset) +ACCESSORS(FunctionTemplateInfo, class_name, Object, kClassNameOffset) +ACCESSORS(FunctionTemplateInfo, signature, Object, kSignatureOffset) +ACCESSORS(FunctionTemplateInfo, instance_call_handler, Object, + kInstanceCallHandlerOffset) +ACCESSORS(FunctionTemplateInfo, access_check_info, Object, + kAccessCheckInfoOffset) +ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset) + +ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset) +ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, + kInternalFieldCountOffset) + +ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) +ACCESSORS(SignatureInfo, args, Object, kArgsOffset) + +ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset) + +ACCESSORS(Script, source, Object, kSourceOffset) +ACCESSORS(Script, name, Object, kNameOffset) +ACCESSORS(Script, id, Object, kIdOffset) +ACCESSORS(Script, line_offset, Smi, kLineOffsetOffset) +ACCESSORS(Script, column_offset, Smi, kColumnOffsetOffset) +ACCESSORS(Script, wrapper, Proxy, kWrapperOffset) +ACCESSORS(Script, type, Smi, kTypeOffset) +ACCESSORS(Script, line_ends, Object, kLineEndsOffset) + +ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoIndex) +ACCESSORS(DebugInfo, original_code, Code, kOriginalCodeIndex) +ACCESSORS(DebugInfo, code, Code, kPatchedCodeIndex) +ACCESSORS(DebugInfo, break_points, FixedArray, kBreakPointsStateIndex) + +ACCESSORS(BreakPointInfo, code_position, Smi, kCodePositionIndex) +ACCESSORS(BreakPointInfo, source_position, Smi, kSourcePositionIndex) +ACCESSORS(BreakPointInfo, statement_position, Smi, kStatementPositionIndex) +ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsIndex) + +ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset) +ACCESSORS(SharedFunctionInfo, instance_class_name, Object, + kInstanceClassNameOffset) +ACCESSORS(SharedFunctionInfo, function_data, Object, + kExternalReferenceDataOffset) +ACCESSORS(SharedFunctionInfo, lazy_load_data, Object, kLazyLoadDataOffset) +ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset) +ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset) +ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset) + +BOOL_ACCESSORS(FunctionTemplateInfo, flag, hidden_prototype, + kHiddenPrototypeBit) +BOOL_ACCESSORS(FunctionTemplateInfo, flag, undetectable, kUndetectableBit) +BOOL_ACCESSORS(FunctionTemplateInfo, flag, needs_access_check, + kNeedsAccessCheckBit) +BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_expression, + kIsExpressionBit) +BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_toplevel, + kIsTopLevelBit) + +INT_ACCESSORS(SharedFunctionInfo, length, kLengthOffset) +INT_ACCESSORS(SharedFunctionInfo, formal_parameter_count, + kFormalParameterCountOffset) +INT_ACCESSORS(SharedFunctionInfo, expected_nof_properties, + kExpectedNofPropertiesOffset) +INT_ACCESSORS(SharedFunctionInfo, start_position_and_type, + kStartPositionAndTypeOffset) +INT_ACCESSORS(SharedFunctionInfo, end_position, kEndPositionOffset) +INT_ACCESSORS(SharedFunctionInfo, function_token_position, + kFunctionTokenPositionOffset) + + +void SharedFunctionInfo::DontAdaptArguments() { + ASSERT(code()->kind() == Code::BUILTIN); + set_formal_parameter_count(kDontAdaptArgumentsSentinel); +} + + +int SharedFunctionInfo::start_position() { + return start_position_and_type() >> kStartPositionShift; +} + + +void SharedFunctionInfo::set_start_position(int start_position) { + set_start_position_and_type((start_position << kStartPositionShift) + | (start_position_and_type() & ~kStartPositionMask)); +} + + +Code* SharedFunctionInfo::code() { + return Code::cast(READ_FIELD(this, kCodeOffset)); +} + + +void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) { + WRITE_FIELD(this, kCodeOffset, value); + CONDITIONAL_WRITE_BARRIER(this, kCodeOffset, mode); +} + + +bool SharedFunctionInfo::is_compiled() { + // TODO(1242782): Create a code kind for uncompiled code. + return code()->kind() != Code::STUB; +} + + +bool JSFunction::IsBoilerplate() { + return map() == Heap::boilerplate_function_map(); +} + + +bool JSFunction::IsLoaded() { + return shared()->lazy_load_data() == Heap::undefined_value(); +} + + +Code* JSFunction::code() { + return shared()->code(); +} + + +void JSFunction::set_code(Code* value) { + shared()->set_code(value); +} + + +Context* JSFunction::context() { + return Context::cast(READ_FIELD(this, kContextOffset)); +} + + +Object* JSFunction::unchecked_context() { + return READ_FIELD(this, kContextOffset); +} + + +void JSFunction::set_context(Object* value) { + ASSERT(value == Heap::undefined_value() || value->IsContext()); + WRITE_FIELD(this, kContextOffset, value); + WRITE_BARRIER(this, kContextOffset); +} + +ACCESSORS(JSFunction, prototype_or_initial_map, Object, + kPrototypeOrInitialMapOffset) + + +Map* JSFunction::initial_map() { + return Map::cast(prototype_or_initial_map()); +} + + +void JSFunction::set_initial_map(Map* value) { + set_prototype_or_initial_map(value); +} + + +bool JSFunction::has_initial_map() { + return prototype_or_initial_map()->IsMap(); +} + + +bool JSFunction::has_instance_prototype() { + return has_initial_map() || !prototype_or_initial_map()->IsTheHole(); +} + + +bool JSFunction::has_prototype() { + return map()->has_non_instance_prototype() || has_instance_prototype(); +} + + +Object* JSFunction::instance_prototype() { + ASSERT(has_instance_prototype()); + if (has_initial_map()) return initial_map()->prototype(); + // When there is no initial map and the prototype is a JSObject, the + // initial map field is used for the prototype field. + return prototype_or_initial_map(); +} + + +Object* JSFunction::prototype() { + ASSERT(has_prototype()); + // If the function's prototype property has been set to a non-JSObject + // value, that value is stored in the constructor field of the map. + if (map()->has_non_instance_prototype()) return map()->constructor(); + return instance_prototype(); +} + + +bool JSFunction::is_compiled() { + return shared()->is_compiled(); +} + + +int JSFunction::NumberOfLiterals() { + return literals()->length(); +} + + +Object* JSBuiltinsObject::javascript_builtin(Builtins::JavaScript id) { + ASSERT(0 <= id && id < kJSBuiltinsCount); + return READ_FIELD(this, kJSBuiltinsOffset + (id * kPointerSize)); +} + + +void JSBuiltinsObject::set_javascript_builtin(Builtins::JavaScript id, + Object* value) { + ASSERT(0 <= id && id < kJSBuiltinsCount); + WRITE_FIELD(this, kJSBuiltinsOffset + (id * kPointerSize), value); + WRITE_BARRIER(this, kJSBuiltinsOffset + (id * kPointerSize)); +} + + +Address Proxy::proxy() { + return AddressFrom<Address>(READ_INT_FIELD(this, kProxyOffset)); +} + + +void Proxy::set_proxy(Address value) { + WRITE_INT_FIELD(this, kProxyOffset, OffsetFrom(value)); +} + + +void Proxy::ProxyIterateBody(ObjectVisitor* visitor) { + visitor->VisitExternalReference( + reinterpret_cast<Address *>(FIELD_ADDR(this, kProxyOffset))); +} + + +ACCESSORS(JSValue, value, Object, kValueOffset) + + +JSValue* JSValue::cast(Object* obj) { + ASSERT(obj->IsJSValue()); + ASSERT(HeapObject::cast(obj)->Size() == JSValue::kSize); + return reinterpret_cast<JSValue*>(obj); +} + + +INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset) +INT_ACCESSORS(Code, relocation_size, kRelocationSizeOffset) +INT_ACCESSORS(Code, sinfo_size, kSInfoSizeOffset) + + +Code::ICTargetState Code::ic_flag() { + return static_cast<ICTargetState>(READ_BYTE_FIELD(this, kICFlagOffset)); +} + + +void Code::set_ic_flag(ICTargetState value) { + WRITE_BYTE_FIELD(this, kICFlagOffset, value); +} + + +byte* Code::instruction_start() { + return FIELD_ADDR(this, kHeaderSize); +} + + +int Code::body_size() { + return RoundUp(instruction_size() + relocation_size(), kObjectAlignment); +} + + +byte* Code::relocation_start() { + return FIELD_ADDR(this, kHeaderSize + instruction_size()); +} + + +byte* Code::entry() { + return instruction_start(); +} + + +bool Code::contains(byte* pc) { + return (instruction_start() <= pc) && + (pc < instruction_start() + instruction_size()); +} + + +byte* Code::sinfo_start() { + return FIELD_ADDR(this, kHeaderSize + body_size()); +} + + +ACCESSORS(JSArray, length, Object, kLengthOffset) + + +ACCESSORS(JSRegExp, data, Object, kDataOffset) + + +JSRegExp::Type JSRegExp::TypeTag() { + Object* data = this->data(); + if (data->IsUndefined()) return JSRegExp::NOT_COMPILED; + Smi* smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex)); + return static_cast<JSRegExp::Type>(smi->value()); +} + + +int JSRegExp::CaptureCount() { + switch (TypeTag()) { + case ATOM: + return 0; + case IRREGEXP: + return Smi::cast(DataAt(kIrregexpCaptureCountIndex))->value(); + default: + UNREACHABLE(); + return -1; + } +} + + +JSRegExp::Flags JSRegExp::GetFlags() { + ASSERT(this->data()->IsFixedArray()); + Object* data = this->data(); + Smi* smi = Smi::cast(FixedArray::cast(data)->get(kFlagsIndex)); + return Flags(smi->value()); +} + + +String* JSRegExp::Pattern() { + ASSERT(this->data()->IsFixedArray()); + Object* data = this->data(); + String* pattern= String::cast(FixedArray::cast(data)->get(kSourceIndex)); + return pattern; +} + + +Object* JSRegExp::DataAt(int index) { + ASSERT(TypeTag() != NOT_COMPILED); + return FixedArray::cast(data())->get(index); +} + + +void JSRegExp::SetDataAt(int index, Object* value) { + ASSERT(TypeTag() != NOT_COMPILED); + ASSERT(index >= kDataIndex); // Only implementation data can be set this way. + FixedArray::cast(data())->set(index, value); +} + + +bool JSObject::HasFastElements() { + return !elements()->IsDictionary(); +} + + +bool JSObject::HasNamedInterceptor() { + return map()->has_named_interceptor(); +} + + +bool JSObject::HasIndexedInterceptor() { + return map()->has_indexed_interceptor(); +} + + +Dictionary* JSObject::property_dictionary() { + ASSERT(!HasFastProperties()); + return Dictionary::cast(properties()); +} + + +Dictionary* JSObject::element_dictionary() { + ASSERT(!HasFastElements()); + return Dictionary::cast(elements()); +} + + +bool String::HasHashCode() { + return (length_field() & kHashComputedMask) != 0; +} + + +uint32_t String::Hash() { + // Fast case: has hash code already been computed? + uint32_t field = length_field(); + if (field & kHashComputedMask) return field >> kHashShift; + // Slow case: compute hash code and set it. + return ComputeAndSetHash(); +} + + +StringHasher::StringHasher(int length) + : length_(length), + raw_running_hash_(0), + array_index_(0), + is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize), + is_first_char_(true), + is_valid_(true) { } + + +bool StringHasher::has_trivial_hash() { + return length_ > String::kMaxMediumStringSize; +} + + +void StringHasher::AddCharacter(uc32 c) { + // Use the Jenkins one-at-a-time hash function to update the hash + // for the given character. + raw_running_hash_ += c; + raw_running_hash_ += (raw_running_hash_ << 10); + raw_running_hash_ ^= (raw_running_hash_ >> 6); + // Incremental array index computation. + if (is_array_index_) { + if (c < '0' || c > '9') { + is_array_index_ = false; + } else { + int d = c - '0'; + if (is_first_char_) { + is_first_char_ = false; + if (c == '0' && length_ > 1) { + is_array_index_ = false; + return; + } + } + if (array_index_ > 429496729U - ((d + 2) >> 3)) { + is_array_index_ = false; + } else { + array_index_ = array_index_ * 10 + d; + } + } + } +} + + +void StringHasher::AddCharacterNoIndex(uc32 c) { + ASSERT(!is_array_index()); + raw_running_hash_ += c; + raw_running_hash_ += (raw_running_hash_ << 10); + raw_running_hash_ ^= (raw_running_hash_ >> 6); +} + + +uint32_t StringHasher::GetHash() { + // Get the calculated raw hash value and do some more bit ops to distribute + // the hash further. Ensure that we never return zero as the hash value. + uint32_t result = raw_running_hash_; + result += (result << 3); + result ^= (result >> 11); + result += (result << 15); + if (result == 0) { + result = 27; + } + return result; +} + + +bool String::AsArrayIndex(uint32_t* index) { + uint32_t field = length_field(); + if ((field & kHashComputedMask) && !(field & kIsArrayIndexMask)) return false; + return SlowAsArrayIndex(index); +} + + +Object* JSObject::GetPrototype() { + return JSObject::cast(this)->map()->prototype(); +} + + +PropertyAttributes JSObject::GetPropertyAttribute(String* key) { + return GetPropertyAttributeWithReceiver(this, key); +} + + +bool JSObject::HasElement(uint32_t index) { + return HasElementWithReceiver(this, index); +} + + +bool AccessorInfo::all_can_read() { + return BooleanBit::get(flag(), kAllCanReadBit); +} + + +void AccessorInfo::set_all_can_read(bool value) { + set_flag(BooleanBit::set(flag(), kAllCanReadBit, value)); +} + + +bool AccessorInfo::all_can_write() { + return BooleanBit::get(flag(), kAllCanWriteBit); +} + + +void AccessorInfo::set_all_can_write(bool value) { + set_flag(BooleanBit::set(flag(), kAllCanWriteBit, value)); +} + + +bool AccessorInfo::prohibits_overwriting() { + return BooleanBit::get(flag(), kProhibitsOverwritingBit); +} + + +void AccessorInfo::set_prohibits_overwriting(bool value) { + set_flag(BooleanBit::set(flag(), kProhibitsOverwritingBit, value)); +} + + +PropertyAttributes AccessorInfo::property_attributes() { + return AttributesField::decode(static_cast<uint32_t>(flag()->value())); +} + + +void AccessorInfo::set_property_attributes(PropertyAttributes attributes) { + ASSERT(AttributesField::is_valid(attributes)); + int rest_value = flag()->value() & ~AttributesField::mask(); + set_flag(Smi::FromInt(rest_value | AttributesField::encode(attributes))); +} + +void Dictionary::SetEntry(int entry, + Object* key, + Object* value, + PropertyDetails details) { + ASSERT(!key->IsString() || details.index() > 0); + int index = EntryToIndex(entry); + WriteBarrierMode mode = GetWriteBarrierMode(); + set(index, key, mode); + set(index+1, value, mode); + fast_set(this, index+2, details.AsSmi()); +} + + +void Map::ClearCodeCache() { + // No write barrier is needed since empty_fixed_array is not in new space. + // Please note this function is used during marking: + // - MarkCompactCollector::MarkUnmarkedObject + ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); + WRITE_FIELD(this, kCodeCacheOffset, Heap::empty_fixed_array()); +} + + +void JSArray::SetContent(FixedArray* storage) { + set_length(Smi::FromInt(storage->length()), SKIP_WRITE_BARRIER); + set_elements(storage); +} + + +Object* FixedArray::Copy() { + if (length() == 0) return this; + return Heap::CopyFixedArray(this); +} + + +#undef CAST_ACCESSOR +#undef INT_ACCESSORS +#undef SMI_ACCESSORS +#undef ACCESSORS +#undef FIELD_ADDR +#undef READ_FIELD +#undef WRITE_FIELD +#undef WRITE_BARRIER +#undef CONDITIONAL_WRITE_BARRIER +#undef READ_MEMADDR_FIELD +#undef WRITE_MEMADDR_FIELD +#undef READ_DOUBLE_FIELD +#undef WRITE_DOUBLE_FIELD +#undef READ_INT_FIELD +#undef WRITE_INT_FIELD +#undef READ_SHORT_FIELD +#undef WRITE_SHORT_FIELD +#undef READ_BYTE_FIELD +#undef WRITE_BYTE_FIELD + + +} } // namespace v8::internal + +#endif // V8_OBJECTS_INL_H_ |