diff options
Diffstat (limited to 'src/3rdparty/v8/src/objects.h')
-rw-r--r-- | src/3rdparty/v8/src/objects.h | 1747 |
1 files changed, 1065 insertions, 682 deletions
diff --git a/src/3rdparty/v8/src/objects.h b/src/3rdparty/v8/src/objects.h index 59458da..fe9655a 100644 --- a/src/3rdparty/v8/src/objects.h +++ b/src/3rdparty/v8/src/objects.h @@ -30,9 +30,10 @@ #include "allocation.h" #include "builtins.h" +#include "elements-kind.h" #include "list.h" #include "property-details.h" -#include "smart-array-pointer.h" +#include "smart-pointers.h" #include "unicode-inl.h" #if V8_TARGET_ARCH_ARM #include "arm/constants-arm.h" @@ -40,6 +41,7 @@ #include "mips/constants-mips.h" #endif #include "v8checks.h" +#include "zone.h" // @@ -82,6 +84,7 @@ // - Context // - JSFunctionResultCache // - ScopeInfo +// - TransitionArray // - FixedDoubleArray // - ExternalArray // - ExternalPixelArray @@ -131,40 +134,6 @@ namespace v8 { namespace internal { -enum ElementsKind { - // The "fast" kind for elements that only contain SMI values. Must be first - // to make it possible to efficiently check maps for this kind. - FAST_SMI_ONLY_ELEMENTS, - - // The "fast" kind for tagged values. Must be second to make it possible to - // efficiently check maps for this and the FAST_SMI_ONLY_ELEMENTS kind - // together at once. - FAST_ELEMENTS, - - // The "fast" kind for unwrapped, non-tagged double values. - FAST_DOUBLE_ELEMENTS, - - // The "slow" kind. - DICTIONARY_ELEMENTS, - NON_STRICT_ARGUMENTS_ELEMENTS, - // The "fast" kind for external arrays - EXTERNAL_BYTE_ELEMENTS, - EXTERNAL_UNSIGNED_BYTE_ELEMENTS, - EXTERNAL_SHORT_ELEMENTS, - EXTERNAL_UNSIGNED_SHORT_ELEMENTS, - EXTERNAL_INT_ELEMENTS, - EXTERNAL_UNSIGNED_INT_ELEMENTS, - EXTERNAL_FLOAT_ELEMENTS, - EXTERNAL_DOUBLE_ELEMENTS, - EXTERNAL_PIXEL_ELEMENTS, - - // Derived constants from ElementsKind - FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS, - LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS, - FIRST_ELEMENTS_KIND = FAST_SMI_ONLY_ELEMENTS, - LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS -}; - enum CompareMapMode { REQUIRE_EXACT_MAP, ALLOW_ELEMENT_TRANSITION_MAPS @@ -175,13 +144,6 @@ enum KeyedAccessGrowMode { ALLOW_JSARRAY_GROWTH }; -const int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1; - -void PrintElementsKind(FILE* out, ElementsKind kind); - -inline bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind, - ElementsKind to_kind); - // Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER. enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER }; @@ -209,9 +171,47 @@ enum CreationFlag { }; +// Indicates whether transitions can be added to a source map or not. +enum TransitionFlag { + INSERT_TRANSITION, + OMIT_TRANSITION +}; + + +// Indicates whether the transition is simple: the target map of the transition +// either extends the current map with a new property, or it modifies the +// property that was added last to the current map. +enum SimpleTransitionFlag { + SIMPLE_TRANSITION, + FULL_TRANSITION +}; + + +// Indicates whether we are only interested in the descriptors of a particular +// map, or in all descriptors in the descriptor array. +enum DescriptorFlag { + ALL_DESCRIPTORS, + OWN_DESCRIPTORS +}; + +// The GC maintains a bit of information, the MarkingParity, which toggles +// from odd to even and back every time marking is completed. Incremental +// marking can visit an object twice during a marking phase, so algorithms that +// that piggy-back on marking can use the parity to ensure that they only +// perform an operation on an object once per marking phase: they record the +// MarkingParity when they visit an object, and only re-visit the object when it +// is marked again and the MarkingParity changes. +enum MarkingParity { + NO_MARKING_PARITY, + ODD_MARKING_PARITY, + EVEN_MARKING_PARITY +}; + // Instance size sentinel for objects of variable size. const int kVariableSizeSentinel = 0; +const int kStubMajorKeyBits = 6; +const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; // All Maps have a field instance_type containing a InstanceType. // It describes the type of the instances. @@ -479,7 +479,7 @@ const uint32_t kSymbolTag = 0x40; // two-byte characters or one-byte characters. const uint32_t kStringEncodingMask = 0x4; const uint32_t kTwoByteStringTag = 0x0; -const uint32_t kAsciiStringTag = 0x4; +const uint32_t kOneByteStringTag = 0x4; // If bit 7 is clear, the low-order 2 bits indicate the representation // of the string. @@ -530,39 +530,39 @@ const uint32_t kShortcutTypeTag = kConsStringTag; enum InstanceType { // String types. SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kSeqStringTag, - ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag, + ASCII_SYMBOL_TYPE = kOneByteStringTag | kSymbolTag | kSeqStringTag, CONS_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kConsStringTag, - CONS_ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kConsStringTag, + CONS_ASCII_SYMBOL_TYPE = kOneByteStringTag | kSymbolTag | kConsStringTag, SHORT_EXTERNAL_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag | kShortExternalStringTag, SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag | kAsciiDataHintTag | kShortExternalStringTag, - SHORT_EXTERNAL_ASCII_SYMBOL_TYPE = kAsciiStringTag | kExternalStringTag | + SHORT_EXTERNAL_ASCII_SYMBOL_TYPE = kOneByteStringTag | kExternalStringTag | kSymbolTag | kShortExternalStringTag, EXTERNAL_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag, EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag | kAsciiDataHintTag, EXTERNAL_ASCII_SYMBOL_TYPE = - kAsciiStringTag | kSymbolTag | kExternalStringTag, + kOneByteStringTag | kSymbolTag | kExternalStringTag, STRING_TYPE = kTwoByteStringTag | kSeqStringTag, - ASCII_STRING_TYPE = kAsciiStringTag | kSeqStringTag, + ASCII_STRING_TYPE = kOneByteStringTag | kSeqStringTag, CONS_STRING_TYPE = kTwoByteStringTag | kConsStringTag, - CONS_ASCII_STRING_TYPE = kAsciiStringTag | kConsStringTag, + CONS_ASCII_STRING_TYPE = kOneByteStringTag | kConsStringTag, SLICED_STRING_TYPE = kTwoByteStringTag | kSlicedStringTag, - SLICED_ASCII_STRING_TYPE = kAsciiStringTag | kSlicedStringTag, + SLICED_ASCII_STRING_TYPE = kOneByteStringTag | kSlicedStringTag, SHORT_EXTERNAL_STRING_TYPE = kTwoByteStringTag | kExternalStringTag | kShortExternalStringTag, SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE = kTwoByteStringTag | kExternalStringTag | kAsciiDataHintTag | kShortExternalStringTag, SHORT_EXTERNAL_ASCII_STRING_TYPE = - kAsciiStringTag | kExternalStringTag | kShortExternalStringTag, + kOneByteStringTag | kExternalStringTag | kShortExternalStringTag, EXTERNAL_STRING_TYPE = kTwoByteStringTag | kExternalStringTag, EXTERNAL_STRING_WITH_ASCII_DATA_TYPE = kTwoByteStringTag | kExternalStringTag | kAsciiDataHintTag, // LAST_STRING_TYPE - EXTERNAL_ASCII_STRING_TYPE = kAsciiStringTag | kExternalStringTag, + EXTERNAL_ASCII_STRING_TYPE = kOneByteStringTag | kExternalStringTag, PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE, // Objects allocated in their own spaces (never in new space). @@ -684,6 +684,25 @@ STATIC_CHECK(ODDBALL_TYPE == Internals::kOddballType); STATIC_CHECK(FOREIGN_TYPE == Internals::kForeignType); +#define FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(V) \ + V(FAST_ELEMENTS_SUB_TYPE) \ + V(DICTIONARY_ELEMENTS_SUB_TYPE) \ + V(FAST_PROPERTIES_SUB_TYPE) \ + V(DICTIONARY_PROPERTIES_SUB_TYPE) \ + V(MAP_CODE_CACHE_SUB_TYPE) \ + V(SCOPE_INFO_SUB_TYPE) \ + V(SYMBOL_TABLE_SUB_TYPE) \ + V(DESCRIPTOR_ARRAY_SUB_TYPE) \ + V(TRANSITION_ARRAY_SUB_TYPE) + +enum FixedArraySubInstanceType { +#define DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE(name) name, + FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE) +#undef DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE + LAST_FIXED_ARRAY_SUB_TYPE = TRANSITION_ARRAY_SUB_TYPE +}; + + enum CompareResult { LESS = -1, EQUAL = 0, @@ -704,12 +723,13 @@ enum CompareResult { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \ +class AccessorPair; class DictionaryElementsAccessor; class ElementsAccessor; +class Failure; class FixedArrayBase; class ObjectVisitor; class StringStream; -class Failure; struct ValueInfo : public Malloced { ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { } @@ -723,6 +743,11 @@ struct ValueInfo : public Malloced { // A template-ized version of the IsXXX functions. template <class C> static inline bool Is(Object* obj); +#ifdef VERIFY_HEAP +#define DECLARE_VERIFIER(Name) void Name##Verify(); +#else +#define DECLARE_VERIFIER(Name) +#endif class MaybeObject BASE_EMBEDDED { public: @@ -756,6 +781,13 @@ class MaybeObject BASE_EMBEDDED { return true; } + template<typename T> + inline bool ToHandle(Handle<T>* obj) { + if (IsFailure()) return false; + *obj = handle(T::cast(reinterpret_cast<Object*>(this))); + return true; + } + #ifdef OBJECT_PRINT // Prints this object with details. inline void Print() { @@ -767,7 +799,7 @@ class MaybeObject BASE_EMBEDDED { void Print(FILE* out); void PrintLn(FILE* out); #endif -#ifdef DEBUG +#ifdef VERIFY_HEAP // Verifies the object. void Verify(); #endif @@ -810,14 +842,14 @@ class MaybeObject BASE_EMBEDDED { V(JSModule) \ V(Map) \ V(DescriptorArray) \ + V(TransitionArray) \ V(DeoptimizationInputData) \ V(DeoptimizationOutputData) \ V(TypeFeedbackCells) \ V(FixedArray) \ V(FixedDoubleArray) \ V(Context) \ - V(GlobalContext) \ - V(ModuleContext) \ + V(NativeContext) \ V(ScopeInfo) \ V(JSFunction) \ V(Code) \ @@ -853,6 +885,7 @@ class MaybeObject BASE_EMBEDDED { V(UndetectableObject) \ V(AccessCheckNeeded) \ V(JSGlobalPropertyCell) \ + V(ObjectHashTable) \ class JSReceiver; @@ -913,8 +946,8 @@ class Object : public MaybeObject { Object* ToBoolean(); // ECMA-262 9.2. // Convert to a JSObject if needed. - // global_context is used when creating wrapper object. - MUST_USE_RESULT MaybeObject* ToObject(Context* global_context); + // native_context is used when creating wrapper object. + MUST_USE_RESULT MaybeObject* ToObject(Context* native_context); // Converts this to a Smi if possible. // Failure is returned otherwise. @@ -974,11 +1007,13 @@ class Object : public MaybeObject { // < the length of the string. Used to implement [] on strings. inline bool IsStringObjectWithCharacterAt(uint32_t index); -#ifdef DEBUG +#ifdef VERIFY_HEAP // Verify a pointer is a valid object pointer. static void VerifyPointer(Object* p); #endif + inline void VerifyApiCallResultType(); + // Prints this object without details. inline void ShortPrint() { ShortPrint(stdout); @@ -1027,9 +1062,8 @@ class Smi: public Object { } void SmiPrint(FILE* out); void SmiPrint(StringStream* accumulator); -#ifdef DEBUG - void SmiVerify(); -#endif + + DECLARE_VERIFIER(Smi) static const int kMinValue = (static_cast<unsigned int>(-1)) << (kSmiValueSize - 1); @@ -1100,9 +1134,8 @@ class Failure: public MaybeObject { } void FailurePrint(FILE* out); void FailurePrint(StringStream* accumulator); -#ifdef DEBUG - void FailureVerify(); -#endif + + DECLARE_VERIFIER(Failure) private: inline intptr_t value() const; @@ -1233,9 +1266,8 @@ class HeapObject: public Object { void HeapObjectPrint(FILE* out); void PrintHeader(FILE* out, const char* id); #endif - -#ifdef DEBUG - void HeapObjectVerify(); + DECLARE_VERIFIER(HeapObject) +#ifdef VERIFY_HEAP inline void VerifyObjectField(int offset); inline void VerifySmiField(int offset); @@ -1263,9 +1295,6 @@ class HeapObject: public Object { }; -#define SLOT_ADDR(obj, offset) \ - reinterpret_cast<Object**>((obj)->address() + offset) - // This class describes a body of an object of a fixed size // in which all pointer fields are located in the [start_offset, end_offset) // interval. @@ -1280,8 +1309,8 @@ class FixedBodyDescriptor { template<typename StaticVisitor> static inline void IterateBody(HeapObject* obj) { - StaticVisitor::VisitPointers(SLOT_ADDR(obj, start_offset), - SLOT_ADDR(obj, end_offset)); + StaticVisitor::VisitPointers(HeapObject::RawField(obj, start_offset), + HeapObject::RawField(obj, end_offset)); } }; @@ -1300,13 +1329,11 @@ class FlexibleBodyDescriptor { template<typename StaticVisitor> static inline void IterateBody(HeapObject* obj, int object_size) { - StaticVisitor::VisitPointers(SLOT_ADDR(obj, start_offset), - SLOT_ADDR(obj, object_size)); + StaticVisitor::VisitPointers(HeapObject::RawField(obj, start_offset), + HeapObject::RawField(obj, object_size)); } }; -#undef SLOT_ADDR - // The HeapNumber class describes heap allocated numbers that cannot be // represented in a Smi (small integer) @@ -1326,9 +1353,7 @@ class HeapNumber: public HeapObject { } void HeapNumberPrint(FILE* out); void HeapNumberPrint(StringStream* accumulator); -#ifdef DEBUG - void HeapNumberVerify(); -#endif + DECLARE_VERIFIER(HeapNumber) inline int get_exponent(); inline int get_sign(); @@ -1392,6 +1417,20 @@ class JSReceiver: public HeapObject { FORCE_DELETION }; + // A non-keyed store is of the form a.x = foo or a["x"] = foo whereas + // a keyed store is of the form a[expression] = foo. + enum StoreFromKeyed { + MAY_BE_STORE_FROM_KEYED, + CERTAINLY_NOT_STORE_FROM_KEYED + }; + + // Internal properties (e.g. the hidden properties dictionary) might + // be added even though the receiver is non-extensible. + enum ExtensibilityCheck { + PERFORM_EXTENSIBILITY_CHECK, + OMIT_EXTENSIBILITY_CHECK + }; + // Casting. static inline JSReceiver* cast(Object* obj); @@ -1402,16 +1441,20 @@ class JSReceiver: public HeapObject { StrictModeFlag strict_mode, bool skip_fallback_interceptor = false); // Can cause GC. - MUST_USE_RESULT MaybeObject* SetProperty(String* key, - Object* value, - PropertyAttributes attributes, - StrictModeFlag strict_mode, - bool skip_fallback_interceptor = false); - MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result, - String* key, - Object* value, - PropertyAttributes attributes, - StrictModeFlag strict_mode); + MUST_USE_RESULT MaybeObject* SetProperty( + String* key, + Object* value, + PropertyAttributes attributes, + StrictModeFlag strict_mode, + StoreFromKeyed store_from_keyed = MAY_BE_STORE_FROM_KEYED, + bool skip_fallback_interceptor = false); + MUST_USE_RESULT MaybeObject* SetProperty( + LookupResult* result, + String* key, + Object* value, + PropertyAttributes attributes, + StrictModeFlag strict_mode, + StoreFromKeyed store_from_keyed = MAY_BE_STORE_FROM_KEYED); MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSReceiver* setter, Object* value); @@ -1441,14 +1484,21 @@ class JSReceiver: public HeapObject { String* name); PropertyAttributes GetLocalPropertyAttribute(String* name); + inline PropertyAttributes GetElementAttribute(uint32_t index); + inline PropertyAttributes GetLocalElementAttribute(uint32_t index); + // Can cause a GC. inline bool HasProperty(String* name); inline bool HasLocalProperty(String* name); inline bool HasElement(uint32_t index); + inline bool HasLocalElement(uint32_t index); // Return the object's prototype (might be Heap::null_value()). inline Object* GetPrototype(); + // Return the constructor function (may be Heap::null_value()). + inline Object* GetConstructor(); + // Set the object's prototype (only JSReceiver and null are allowed). MUST_USE_RESULT MaybeObject* SetPrototype(Object* value, bool skip_hidden_prototypes); @@ -1470,10 +1520,10 @@ class JSReceiver: public HeapObject { Smi* GenerateIdentityHash(); private: - PropertyAttributes GetPropertyAttribute(JSReceiver* receiver, - LookupResult* result, - String* name, - bool continue_search); + PropertyAttributes GetPropertyAttributeForResult(JSReceiver* receiver, + LookupResult* result, + String* name, + bool continue_search); DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver); }; @@ -1515,13 +1565,19 @@ class JSObject: public JSReceiver { MUST_USE_RESULT inline MaybeObject* ResetElements(); inline ElementsKind GetElementsKind(); inline ElementsAccessor* GetElementsAccessor(); - inline bool HasFastSmiOnlyElements(); - inline bool HasFastElements(); - // Returns if an object has either FAST_ELEMENT or FAST_SMI_ONLY_ELEMENT - // elements. TODO(danno): Rename HasFastTypeElements to HasFastElements() and - // HasFastElements to HasFastObjectElements. - inline bool HasFastTypeElements(); + // Returns true if an object has elements of FAST_SMI_ELEMENTS ElementsKind. + inline bool HasFastSmiElements(); + // Returns true if an object has elements of FAST_ELEMENTS ElementsKind. + inline bool HasFastObjectElements(); + // Returns true if an object has elements of FAST_ELEMENTS or + // FAST_SMI_ONLY_ELEMENTS. + inline bool HasFastSmiOrObjectElements(); + // Returns true if an object has elements of FAST_DOUBLE_ELEMENTS + // ElementsKind. inline bool HasFastDoubleElements(); + // Returns true if an object has elements of FAST_HOLEY_*_ELEMENTS + // ElementsKind. + inline bool HasFastHoleyElements(); inline bool HasNonStrictArgumentsElements(); inline bool HasDictionaryElements(); inline bool HasExternalPixelElements(); @@ -1563,7 +1619,8 @@ class JSObject: public JSReceiver { String* key, Object* value, PropertyAttributes attributes, - StrictModeFlag strict_mode); + StrictModeFlag strict_mode, + StoreFromKeyed store_mode); MUST_USE_RESULT MaybeObject* SetPropertyWithFailedAccessCheck( LookupResult* result, String* name, @@ -1585,7 +1642,8 @@ class JSObject: public JSReceiver { String* name, Object* value, PropertyAttributes attributes, - StrictModeFlag strict_mode); + StrictModeFlag strict_mode, + ExtensibilityCheck extensibility_check); static Handle<Object> SetLocalPropertyIgnoreAttributes( Handle<JSObject> object, @@ -1593,6 +1651,18 @@ class JSObject: public JSReceiver { Handle<Object> value, PropertyAttributes attributes); + // Try to follow an existing transition to a field with attributes NONE. The + // return value indicates whether the transition was successful. + static inline bool TryTransitionToField(Handle<JSObject> object, + Handle<String> key); + + inline int LastAddedFieldIndex(); + + // Extend the receiver with a single fast property appeared first in the + // passed map. This also extends the property backing store if necessary. + static void AddFastPropertyUsingMap(Handle<JSObject> object, Handle<Map> map); + inline MUST_USE_RESULT MaybeObject* AddFastPropertyUsingMap(Map* map); + // Can cause GC. MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes( String* key, @@ -1622,6 +1692,8 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* DeleteNormalizedProperty(String* name, DeleteMode mode); + MUST_USE_RESULT MaybeObject* OptimizeAsPrototype(); + // Retrieve interceptors. InterceptorInfo* GetNamedInterceptor(); InterceptorInfo* GetIndexedInterceptor(); @@ -1638,16 +1710,28 @@ class JSObject: public JSReceiver { LookupResult* result, String* name, bool continue_search); + PropertyAttributes GetElementAttributeWithReceiver(JSReceiver* receiver, + uint32_t index, + bool continue_search); static void DefineAccessor(Handle<JSObject> object, Handle<String> name, Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes); + // Can cause GC. MUST_USE_RESULT MaybeObject* DefineAccessor(String* name, Object* getter, Object* setter, PropertyAttributes attributes); + // Try to define a single accessor paying attention to map transitions. + // Returns a JavaScript null if this was not possible and we have to use the + // slow case. Note that we can fail due to allocations, too. + MUST_USE_RESULT MaybeObject* DefineFastAccessor( + String* name, + AccessorComponent component, + Object* accessor, + PropertyAttributes attributes); Object* LookupAccessor(String* name, AccessorComponent component); MUST_USE_RESULT MaybeObject* DefineAccessor(AccessorInfo* info); @@ -1659,15 +1743,15 @@ class JSObject: public JSReceiver { String* name, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetPropertyWithInterceptor( - JSReceiver* receiver, + Object* receiver, String* name, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetPropertyPostInterceptor( - JSReceiver* receiver, + Object* receiver, String* name, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetLocalPropertyPostInterceptor( - JSReceiver* receiver, + Object* receiver, String* name, PropertyAttributes* attributes); @@ -1707,16 +1791,17 @@ class JSObject: public JSReceiver { static int GetIdentityHash(Handle<JSObject> obj); MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag); - MUST_USE_RESULT MaybeObject* SetIdentityHash(Object* hash, CreationFlag flag); + MUST_USE_RESULT MaybeObject* SetIdentityHash(Smi* hash, CreationFlag flag); static Handle<Object> DeleteProperty(Handle<JSObject> obj, Handle<String> name); + // Can cause GC. MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode); static Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index); MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode); - inline void ValidateSmiOnlyElements(); + inline void ValidateElements(); // Makes sure that this object can contain HeapObject as elements. MUST_USE_RESULT inline MaybeObject* EnsureCanContainHeapObjectElements(); @@ -1728,6 +1813,7 @@ class JSObject: public JSReceiver { EnsureElementsMode mode); MUST_USE_RESULT inline MaybeObject* EnsureCanContainElements( FixedArrayBase* elements, + uint32_t length, EnsureElementsMode mode); MUST_USE_RESULT MaybeObject* EnsureCanContainElements( Arguments* arguments, @@ -1748,9 +1834,6 @@ class JSObject: public JSReceiver { // be represented as a double and not a Smi. bool ShouldConvertToFastDoubleElements(bool* has_smi_only_elements); - // Tells whether the index'th element is present. - bool HasElementWithReceiver(JSReceiver* receiver, uint32_t index); - // Computes the new capacity when expanding the elements of a JSObject. static int NewElementsCapacity(int old_capacity) { // (old_capacity + 50%) + 16 @@ -1775,9 +1858,7 @@ class JSObject: public JSReceiver { DICTIONARY_ELEMENT }; - LocalElementType HasLocalElement(uint32_t index); - - bool HasElementWithInterceptor(JSReceiver* receiver, uint32_t index); + LocalElementType GetLocalElementType(uint32_t index); MUST_USE_RESULT MaybeObject* SetFastElement(uint32_t index, Object* value, @@ -1826,10 +1907,10 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* GetElementWithInterceptor(Object* receiver, uint32_t index); - enum SetFastElementsCapacityMode { - kAllowSmiOnlyElements, - kForceSmiOnlyElements, - kDontAllowSmiOnlyElements + enum SetFastElementsCapacitySmiMode { + kAllowSmiElements, + kForceSmiElements, + kDontAllowSmiElements }; // Replace the elements' backing store with fast elements of the given @@ -1838,7 +1919,7 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* SetFastElementsCapacityAndLength( int capacity, int length, - SetFastElementsCapacityMode set_capacity_mode); + SetFastElementsCapacitySmiMode smi_mode); MUST_USE_RESULT MaybeObject* SetFastDoubleElementsCapacityAndLength( int capacity, int length); @@ -1870,10 +1951,9 @@ class JSObject: public JSReceiver { void LocalLookupRealNamedProperty(String* name, LookupResult* result); void LookupRealNamedProperty(String* name, LookupResult* result); void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result); - void LookupCallbackSetterInPrototypes(String* name, LookupResult* result); MUST_USE_RESULT MaybeObject* SetElementWithCallbackSetterInPrototypes( uint32_t index, Object* value, bool* found, StrictModeFlag strict_mode); - void LookupCallback(String* name, LookupResult* result); + void LookupCallbackProperty(String* name, LookupResult* result); // Returns the number of properties on this object filtering out properties // with the specified attributes (ignoring interceptors). @@ -1901,7 +1981,8 @@ class JSObject: public JSReceiver { // new_map. MUST_USE_RESULT MaybeObject* AddFastPropertyUsingMap(Map* new_map, String* name, - Object* value); + Object* value, + int field_index); // Add a constant function property to a fast-case object. // This leaves a CONSTANT_TRANSITION in the old map, and @@ -1934,39 +2015,40 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind); - // Converts a descriptor of any other type to a real field, - // backed by the properties array. Descriptors of visible - // types, such as CONSTANT_FUNCTION, keep their enumeration order. - // Converts the descriptor on the original object's map to a - // map transition, and the the new field is on the object's new map. - MUST_USE_RESULT MaybeObject* ConvertDescriptorToFieldAndMapTransition( + // Replaces an existing transition with a transition to a map with a FIELD. + MUST_USE_RESULT MaybeObject* ConvertTransitionToMapTransition( + int transition_index, String* name, Object* new_value, PropertyAttributes attributes); - // Converts a descriptor of any other type to a real field, - // backed by the properties array. Descriptors of visible - // types, such as CONSTANT_FUNCTION, keep their enumeration order. + // Converts a descriptor of any other type to a real field, backed by the + // properties array. MUST_USE_RESULT MaybeObject* ConvertDescriptorToField( String* name, Object* new_value, PropertyAttributes attributes); // Add a property to a fast-case object. - MUST_USE_RESULT MaybeObject* AddFastProperty(String* name, - Object* value, - PropertyAttributes attributes); + MUST_USE_RESULT MaybeObject* AddFastProperty( + String* name, + Object* value, + PropertyAttributes attributes, + StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED); // Add a property to a slow-case object. MUST_USE_RESULT MaybeObject* AddSlowProperty(String* name, Object* value, PropertyAttributes attributes); - // Add a property to an object. - MUST_USE_RESULT MaybeObject* AddProperty(String* name, - Object* value, - PropertyAttributes attributes, - StrictModeFlag strict_mode); + // Add a property to an object. May cause GC. + MUST_USE_RESULT MaybeObject* AddProperty( + String* name, + Object* value, + PropertyAttributes attributes, + StrictModeFlag strict_mode, + StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED, + ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK); // Convert the object to use the canonical dictionary // representation. If the object is expected to have additional properties @@ -2041,9 +2123,7 @@ class JSObject: public JSReceiver { } void JSObjectPrint(FILE* out); #endif -#ifdef DEBUG - void JSObjectVerify(); -#endif + DECLARE_VERIFIER(JSObject) #ifdef OBJECT_PRINT inline void PrintProperties() { PrintProperties(stdout); @@ -2054,6 +2134,10 @@ class JSObject: public JSReceiver { PrintElements(stdout); } void PrintElements(FILE* out); + inline void PrintTransitions() { + PrintTransitions(stdout); + } + void PrintTransitions(FILE* out); #endif void PrintElementsTransition( @@ -2086,7 +2170,7 @@ class JSObject: public JSReceiver { // Maximal number of fast properties for the JSObject. Used to // restrict the number of map transitions to avoid an explosion in // the number of maps for objects used as dictionaries. - inline int MaxFastProperties(); + inline bool TooManyFastProperties(int properties, StoreFromKeyed store_mode); // Maximal number of elements (numbered 0 .. kMaxElementCount - 1). // Also maximal value of JSArray's length property. @@ -2108,7 +2192,8 @@ class JSObject: public JSReceiver { static const int kMaxUncheckedOldFastElementsLength = 500; static const int kInitialMaxFastElementArray = 100000; - static const int kMaxFastProperties = 12; + static const int kFastPropertiesSoftLimit = 12; + static const int kMaxFastProperties = 64; static const int kMaxInstanceSize = 255 * kPointerSize; // When extending the backing storage for property values, we increase // its size by more than the 1 entry necessary, so sequentially adding fields @@ -2127,6 +2212,15 @@ class JSObject: public JSReceiver { static inline int SizeOf(Map* map, HeapObject* object); }; + // Enqueue change record for Object.observe. May cause GC. + static void EnqueueChangeRecord(Handle<JSObject> object, + const char* type, + Handle<String> name, + Handle<Object> old_value); + + // Deliver change records to observers. May cause GC. + static void DeliverChangeRecords(Isolate* isolate); + private: friend class DictionaryElementsAccessor; @@ -2134,6 +2228,14 @@ class JSObject: public JSReceiver { Object* structure, uint32_t index, Object* holder); + MUST_USE_RESULT PropertyAttributes GetElementAttributeWithInterceptor( + JSReceiver* receiver, + uint32_t index, + bool continue_search); + MUST_USE_RESULT PropertyAttributes GetElementAttributeWithoutInterceptor( + JSReceiver* receiver, + uint32_t index, + bool continue_search); MUST_USE_RESULT MaybeObject* SetElementWithCallback( Object* structure, uint32_t index, @@ -2155,17 +2257,16 @@ class JSObject: public JSReceiver { bool check_prototype, SetPropertyMode set_mode); - // Searches the prototype chain for a callback setter and sets the property - // with the setter if it finds one. The '*found' flag indicates whether - // a setter was found or not. - // This function can cause GC and can return a failure result with - // '*found==true'. - MUST_USE_RESULT MaybeObject* SetPropertyWithCallbackSetterInPrototypes( + // Searches the prototype chain for property 'name'. If it is found and + // has a setter, invoke it and set '*done' to true. If it is found and is + // read-only, reject and set '*done' to true. Otherwise, set '*done' to + // false. Can cause GC and can return a failure result with '*done==true'. + MUST_USE_RESULT MaybeObject* SetPropertyViaPrototypes( String* name, Object* value, PropertyAttributes attributes, - bool* found, - StrictModeFlag strict_mode); + StrictModeFlag strict_mode, + bool* done); MUST_USE_RESULT MaybeObject* DeletePropertyPostInterceptor(String* name, DeleteMode mode); @@ -2207,18 +2308,23 @@ class JSObject: public JSReceiver { Object* getter, Object* setter, PropertyAttributes attributes); - void LookupInDescriptor(String* name, LookupResult* result); - - // Returns the hidden properties backing store object, currently - // a StringDictionary, stored on this object. - // If no hidden properties object has been put on this object, - // return undefined, unless create_if_absent is true, in which case - // a new dictionary is created, added to this object, and returned. - MUST_USE_RESULT MaybeObject* GetHiddenPropertiesDictionary( - bool create_if_absent); - // Updates the existing hidden properties dictionary. - MUST_USE_RESULT MaybeObject* SetHiddenPropertiesDictionary( - StringDictionary* dictionary); + + + enum InitializeHiddenProperties { + CREATE_NEW_IF_ABSENT, + ONLY_RETURN_INLINE_VALUE + }; + + // If create_if_absent is true, return the hash table backing store + // for hidden properties. If there is no backing store, allocate one. + // If create_if_absent is false, return the hash table backing store + // or the inline stored identity hash, whatever is found. + MUST_USE_RESULT MaybeObject* GetHiddenPropertiesHashTable( + InitializeHiddenProperties init_option); + // Set the hidden property backing store to either a hash table or + // the inline-stored identity hash. + MUST_USE_RESULT MaybeObject* SetHiddenPropertiesHashTable( + Object* value); DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject); }; @@ -2242,6 +2348,8 @@ class FixedArrayBase: public HeapObject { class FixedDoubleArray; +class IncrementalMarking; + // FixedArray describes fixed-sized arrays with element type Object*. class FixedArray: public FixedArrayBase { @@ -2314,8 +2422,8 @@ class FixedArray: public FixedArrayBase { } void FixedArrayPrint(FILE* out); #endif + DECLARE_VERIFIER(FixedArray) #ifdef DEBUG - void FixedArrayVerify(); // Checks if two FixedArrays have identical contents. bool IsEqualTo(FixedArray* other); #endif @@ -2401,34 +2509,40 @@ class FixedDoubleArray: public FixedArrayBase { } void FixedDoubleArrayPrint(FILE* out); #endif - -#ifdef DEBUG - void FixedDoubleArrayVerify(); -#endif + DECLARE_VERIFIER(FixedDoubleArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(FixedDoubleArray); }; -class IncrementalMarking; - - // DescriptorArrays are fixed arrays used to hold instance descriptors. // The format of the these objects is: -// TODO(1399): It should be possible to make room for bit_field3 in the map -// without overloading the instance descriptors field in the map -// (and storing it in the DescriptorArray when the map has one). -// [0]: storage for bit_field3 for Map owning this object (Smi) -// [1]: point to a fixed array with (value, detail) pairs. -// [2]: next enumeration index (Smi), or pointer to small fixed array: -// [0]: next enumeration index (Smi) -// [1]: pointer to fixed array with enum cache -// [3]: first key -// [length() - 1]: last key -// +// [0]: Number of descriptors +// [1]: Either Smi(0) if uninitialized, or a pointer to small fixed array: +// [0]: pointer to fixed array with enum cache +// [1]: either Smi(0) or pointer to fixed array with indices +// [2]: first key +// [2 + number of descriptors * kDescriptorSize]: start of slack class DescriptorArray: public FixedArray { public: + // WhitenessWitness is used to prove that a descriptor array is white + // (unmarked), so incremental write barriers can be skipped because the + // marking invariant cannot be broken and slots pointing into evacuation + // candidates will be discovered when the object is scanned. A witness is + // always stack-allocated right after creating an array. By allocating a + // witness, incremental marking is globally disabled. The witness is then + // passed along wherever needed to statically prove that the array is known to + // be white. + class WhitenessWitness { + public: + inline explicit WhitenessWitness(FixedArray* array); + inline ~WhitenessWitness(); + + private: + IncrementalMarking* marking_; + }; + // Returns true for both shared empty_descriptor_array and for smis, which the // map uses to encode additional bit fields when the descriptor array is not // yet used. @@ -2436,43 +2550,58 @@ class DescriptorArray: public FixedArray { // Returns the number of descriptors in the array. int number_of_descriptors() { - ASSERT(length() > kFirstIndex || IsEmpty()); + ASSERT(length() >= kFirstIndex || IsEmpty()); int len = length(); - return len <= kFirstIndex ? 0 : len - kFirstIndex; + return len == 0 ? 0 : Smi::cast(get(kDescriptorLengthIndex))->value(); } - int NextEnumerationIndex() { - if (IsEmpty()) return PropertyDetails::kInitialIndex; - Object* obj = get(kEnumerationIndexIndex); - if (obj->IsSmi()) { - return Smi::cast(obj)->value(); - } else { - Object* index = FixedArray::cast(obj)->get(kEnumCacheBridgeEnumIndex); - return Smi::cast(index)->value(); - } + int number_of_descriptors_storage() { + int len = length(); + return len == 0 ? 0 : (len - kFirstIndex) / kDescriptorSize; } - // Set next enumeration index and flush any enum cache. - void SetNextEnumerationIndex(int value) { - if (!IsEmpty()) { - set(kEnumerationIndexIndex, Smi::FromInt(value)); - } + int NumberOfSlackDescriptors() { + return number_of_descriptors_storage() - number_of_descriptors(); } + + inline void SetNumberOfDescriptors(int number_of_descriptors); + inline int number_of_entries() { return number_of_descriptors(); } + bool HasEnumCache() { - return !IsEmpty() && !get(kEnumerationIndexIndex)->IsSmi(); + return !IsEmpty() && !get(kEnumCacheIndex)->IsSmi(); + } + + void CopyEnumCacheFrom(DescriptorArray* array) { + set(kEnumCacheIndex, array->get(kEnumCacheIndex)); + } + + FixedArray* GetEnumCache() { + ASSERT(HasEnumCache()); + FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex)); + return FixedArray::cast(bridge->get(kEnumCacheBridgeCacheIndex)); + } + + bool HasEnumIndicesCache() { + if (IsEmpty()) return false; + Object* object = get(kEnumCacheIndex); + if (object->IsSmi()) return false; + FixedArray* bridge = FixedArray::cast(object); + return !bridge->get(kEnumCacheBridgeIndicesCacheIndex)->IsSmi(); + } + + FixedArray* GetEnumIndicesCache() { + ASSERT(HasEnumIndicesCache()); + FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex)); + return FixedArray::cast(bridge->get(kEnumCacheBridgeIndicesCacheIndex)); } - Object* GetEnumCache() { + Object** GetEnumCacheSlot() { ASSERT(HasEnumCache()); - FixedArray* bridge = FixedArray::cast(get(kEnumerationIndexIndex)); - return bridge->get(kEnumCacheBridgeCacheIndex); + return HeapObject::RawField(reinterpret_cast<HeapObject*>(this), + kEnumCacheOffset); } - // TODO(1399): It should be possible to make room for bit_field3 in the map - // without overloading the instance descriptors field in the map - // (and storing it in the DescriptorArray when the map has one). - inline int bit_field3_storage(); - inline void set_bit_field3_storage(int value); + void ClearEnumCache(); // Initialize or change the enum cache, // using the supplied storage for the small "bridge". @@ -2482,92 +2611,56 @@ class DescriptorArray: public FixedArray { // Accessors for fetching instance descriptor at descriptor number. inline String* GetKey(int descriptor_number); + inline Object** GetKeySlot(int descriptor_number); inline Object* GetValue(int descriptor_number); + inline Object** GetValueSlot(int descriptor_number); inline PropertyDetails GetDetails(int descriptor_number); inline PropertyType GetType(int descriptor_number); inline int GetFieldIndex(int descriptor_number); inline JSFunction* GetConstantFunction(int descriptor_number); inline Object* GetCallbacksObject(int descriptor_number); inline AccessorDescriptor* GetCallbacks(int descriptor_number); - inline bool IsProperty(int descriptor_number); - inline bool IsTransitionOnly(int descriptor_number); - inline bool IsNullDescriptor(int descriptor_number); - class WhitenessWitness { - public: - inline explicit WhitenessWitness(DescriptorArray* array); - inline ~WhitenessWitness(); - - private: - IncrementalMarking* marking_; - }; + inline String* GetSortedKey(int descriptor_number); + inline int GetSortedKeyIndex(int descriptor_number); + inline void SetSortedKey(int pointer, int descriptor_number); // Accessor for complete descriptor. inline void Get(int descriptor_number, Descriptor* desc); inline void Set(int descriptor_number, Descriptor* desc, const WhitenessWitness&); + inline void Set(int descriptor_number, Descriptor* desc); - // Transfer a complete descriptor from the src descriptor array to the dst - // one, dropping map transitions in CALLBACKS. - static void CopyFrom(Handle<DescriptorArray> dst, - int dst_index, - Handle<DescriptorArray> src, - int src_index, - const WhitenessWitness& witness); + // Append automatically sets the enumeration index. This should only be used + // to add descriptors in bulk at the end, followed by sorting the descriptor + // array. + inline void Append(Descriptor* desc, const WhitenessWitness&); + inline void Append(Descriptor* desc); // Transfer a complete descriptor from the src descriptor array to this - // descriptor array, dropping map transitions in CALLBACKS. - MUST_USE_RESULT MaybeObject* CopyFrom(int dst_index, - DescriptorArray* src, - int src_index, - const WhitenessWitness&); - - // Copy the descriptor array, insert a new descriptor and optionally - // remove map transitions. If the descriptor is already present, it is - // replaced. If a replaced descriptor is a real property (not a transition - // or null), its enumeration index is kept as is. - // If adding a real property, map transitions must be removed. If adding - // a transition, they must not be removed. All null descriptors are removed. - MUST_USE_RESULT MaybeObject* CopyInsert(Descriptor* descriptor, - TransitionFlag transition_flag); - - // Return a copy of the array with all transitions and null descriptors - // removed. Return a Failure object in case of an allocation failure. - MUST_USE_RESULT MaybeObject* RemoveTransitions(); + // descriptor array. + void CopyFrom(int dst_index, + DescriptorArray* src, + int src_index, + const WhitenessWitness&); - // Sort the instance descriptors by the hash codes of their keys. - // Does not check for duplicates. - void SortUnchecked(const WhitenessWitness&); + MUST_USE_RESULT MaybeObject* CopyUpTo(int enumeration_index); // Sort the instance descriptors by the hash codes of their keys. - // Checks the result for duplicates. - void Sort(const WhitenessWitness&); + void Sort(); // Search the instance descriptors for given name. - inline int Search(String* name); + INLINE(int Search(String* name, int number_of_own_descriptors)); // As the above, but uses DescriptorLookupCache and updates it when // necessary. - inline int SearchWithCache(String* name); - - // Tells whether the name is present int the array. - bool Contains(String* name) { return kNotFound != Search(name); } - - // Perform a binary search in the instance descriptors represented - // by this fixed array. low and high are descriptor indices. If there - // are three instance descriptors in this array it should be called - // with low=0 and high=2. - int BinarySearch(String* name, int low, int high); - - // Perform a linear search in the instance descriptors represented - // by this fixed array. len is the number of descriptor indices that are - // valid. Does not require the descriptors to be sorted. - int LinearSearch(String* name, int len); + INLINE(int SearchWithCache(String* name, Map* map)); // Allocates a DescriptorArray, but returns the singleton // empty descriptor array object if number_of_descriptors is 0. - MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors); + MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors, + int slack = 0); // Casting. static inline DescriptorArray* cast(Object* obj); @@ -2575,27 +2668,28 @@ class DescriptorArray: public FixedArray { // Constant for denoting key was not found. static const int kNotFound = -1; - static const int kBitField3StorageIndex = 0; - static const int kContentArrayIndex = 1; - static const int kEnumerationIndexIndex = 2; - static const int kFirstIndex = 3; + static const int kDescriptorLengthIndex = 0; + static const int kEnumCacheIndex = 1; + static const int kFirstIndex = 2; // The length of the "bridge" to the enum cache. - static const int kEnumCacheBridgeLength = 3; - static const int kEnumCacheBridgeEnumIndex = 0; - static const int kEnumCacheBridgeCacheIndex = 1; - static const int kEnumCacheBridgeIndicesCacheIndex = 2; + static const int kEnumCacheBridgeLength = 2; + static const int kEnumCacheBridgeCacheIndex = 0; + static const int kEnumCacheBridgeIndicesCacheIndex = 1; // Layout description. - static const int kBitField3StorageOffset = FixedArray::kHeaderSize; - static const int kContentArrayOffset = kBitField3StorageOffset + kPointerSize; - static const int kEnumerationIndexOffset = kContentArrayOffset + kPointerSize; - static const int kFirstOffset = kEnumerationIndexOffset + kPointerSize; + static const int kDescriptorLengthOffset = FixedArray::kHeaderSize; + static const int kEnumCacheOffset = kDescriptorLengthOffset + kPointerSize; + static const int kFirstOffset = kEnumCacheOffset + kPointerSize; // Layout description for the bridge array. - static const int kEnumCacheBridgeEnumOffset = FixedArray::kHeaderSize; - static const int kEnumCacheBridgeCacheOffset = - kEnumCacheBridgeEnumOffset + kPointerSize; + static const int kEnumCacheBridgeCacheOffset = FixedArray::kHeaderSize; + + // Layout of descriptor. + static const int kDescriptorKey = 0; + static const int kDescriptorDetails = 1; + static const int kDescriptorValue = 2; + static const int kDescriptorSize = 3; #ifdef OBJECT_PRINT // Print all the descriptors. @@ -2607,7 +2701,7 @@ class DescriptorArray: public FixedArray { #ifdef DEBUG // Is the descriptor array sorted and without duplicates? - bool IsSortedNoDuplicates(); + bool IsSortedNoDuplicates(int valid_descriptors = -1); // Is the descriptor array consistent with the back pointers in targets? bool IsConsistentWithBackPointers(Map* current_map); @@ -2620,6 +2714,12 @@ class DescriptorArray: public FixedArray { // fit in a page). static const int kMaxNumberOfDescriptors = 1024 + 512; + // Returns the fixed array length required to hold number_of_descriptors + // descriptors. + static int LengthFor(int number_of_descriptors) { + return ToKeyIndex(number_of_descriptors); + } + private: // An entry in a DescriptorArray, represented as an (array, index) pair. class Entry { @@ -2637,32 +2737,40 @@ class DescriptorArray: public FixedArray { // Conversion from descriptor number to array indices. static int ToKeyIndex(int descriptor_number) { - return descriptor_number+kFirstIndex; + return kFirstIndex + + (descriptor_number * kDescriptorSize) + + kDescriptorKey; } static int ToDetailsIndex(int descriptor_number) { - return (descriptor_number << 1) + 1; + return kFirstIndex + + (descriptor_number * kDescriptorSize) + + kDescriptorDetails; } static int ToValueIndex(int descriptor_number) { - return descriptor_number << 1; + return kFirstIndex + + (descriptor_number * kDescriptorSize) + + kDescriptorValue; } - // Swap operation on FixedArray without using write barriers. - static inline void NoIncrementalWriteBarrierSwap( - FixedArray* array, int first, int second); - - // Swap descriptor first and second. - inline void NoIncrementalWriteBarrierSwapDescriptors( - int first, int second); + // Swap first and second descriptor. + inline void SwapSortedKeys(int first, int second); - FixedArray* GetContentArray() { - return FixedArray::cast(get(kContentArrayIndex)); - } DISALLOW_IMPLICIT_CONSTRUCTORS(DescriptorArray); }; +enum SearchMode { ALL_ENTRIES, VALID_ENTRIES }; + +template<SearchMode search_mode, typename T> +inline int LinearSearch(T* array, String* name, int len, int valid_entries); + + +template<SearchMode search_mode, typename T> +inline int Search(T* array, String* name, int valid_entries = 0); + + // HashTable is a subclass of FixedArray that implements a hash table // that uses open addressing and quadratic probing. // @@ -2715,6 +2823,11 @@ class BaseShape { template<typename Shape, typename Key> class HashTable: public FixedArray { public: + enum MinimumCapacity { + USE_DEFAULT_MINIMUM_CAPACITY, + USE_CUSTOM_MINIMUM_CAPACITY + }; + // Wrapper methods inline uint32_t Hash(Key key) { if (Shape::UsesSeed) { @@ -2767,6 +2880,7 @@ class HashTable: public FixedArray { // Returns a new HashTable object. Might return Failure. MUST_USE_RESULT static MaybeObject* Allocate( int at_least_space_for, + MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY, PretenureFlag pretenure = NOT_TENURED); // Computes the required capacity for a table holding the given @@ -2856,11 +2970,12 @@ class HashTable: public FixedArray { return (hash + GetProbeOffset(number)) & (size - 1); } - static uint32_t FirstProbe(uint32_t hash, uint32_t size) { + inline static uint32_t FirstProbe(uint32_t hash, uint32_t size) { return hash & (size - 1); } - static uint32_t NextProbe(uint32_t last, uint32_t number, uint32_t size) { + inline static uint32_t NextProbe( + uint32_t last, uint32_t number, uint32_t size) { return (last + number) & (size - 1); } @@ -2947,6 +3062,8 @@ class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> { private: MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s); + template <bool seq_ascii> friend class JsonParser; + DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable); }; @@ -3044,6 +3161,7 @@ class Dictionary: public HashTable<Shape, Key> { // Accessors for next enumeration index. void SetNextEnumerationIndex(int index) { + ASSERT(index != 0); this->set(kNextEnumerationIndexIndex, Smi::FromInt(index)); } @@ -3117,7 +3235,9 @@ class StringDictionary: public Dictionary<StringDictionaryShape, String*> { } // Copies enumerable keys to preallocated fixed array. - void CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array); + FixedArray* CopyEnumKeysTo(FixedArray* storage); + static void DoGenerateNewEnumerationIndices( + Handle<StringDictionary> dictionary); // For transforming properties of a JSObject. MUST_USE_RESULT MaybeObject* TransformPropertiesToFastFor( @@ -3127,8 +3247,6 @@ class StringDictionary: public Dictionary<StringDictionaryShape, String*> { // Find entry for key, otherwise return kNotFound. Optimized version of // HashTable::FindEntry. int FindEntry(String* key); - - bool ContainsTransition(int entry); }; @@ -3274,12 +3392,12 @@ class ObjectHashTable: public HashTable<ObjectHashTableShape<2>, Object*> { return reinterpret_cast<ObjectHashTable*>(obj); } - // Looks up the value associated with the given key. The undefined value is + // Looks up the value associated with the given key. The hole value is // returned in case the key is not present. Object* Lookup(Object* key); // Adds (or overwrites) the value associated with the given key. Mapping a - // key to the undefined value causes removal of the whole entry. + // key to the hole value causes removal of the whole entry. MUST_USE_RESULT MaybeObject* Put(Object* key, Object* value); private: @@ -3327,9 +3445,7 @@ class JSFunctionResultCache: public FixedArray { // Casting static inline JSFunctionResultCache* cast(Object* obj); -#ifdef DEBUG - void JSFunctionResultCacheVerify(); -#endif + DECLARE_VERIFIER(JSFunctionResultCache) }; @@ -3436,7 +3552,7 @@ class ScopeInfo : public FixedArray { // must be a symbol (canonicalized). int FunctionContextSlotIndex(String* name, VariableMode* mode); - static Handle<ScopeInfo> Create(Scope* scope); + static Handle<ScopeInfo> Create(Scope* scope, Zone* zone); // Serializes empty scope info. static ScopeInfo* Empty(); @@ -3482,7 +3598,7 @@ class ScopeInfo : public FixedArray { FOR_EACH_NUMERIC_FIELD(DECL_INDEX) #undef DECL_INDEX #undef FOR_EACH_NUMERIC_FIELD - kVariablePartIndex + kVariablePartIndex }; // The layout of the variable part of a ScopeInfo is as follows: @@ -3556,9 +3672,7 @@ class NormalizedMapCache: public FixedArray { // Casting static inline NormalizedMapCache* cast(Object* obj); -#ifdef DEBUG - void NormalizedMapCacheVerify(); -#endif + DECLARE_VERIFIER(NormalizedMapCache) }; @@ -3607,9 +3721,7 @@ class ByteArray: public FixedArrayBase { } void ByteArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ByteArrayVerify(); -#endif + DECLARE_VERIFIER(ByteArray) // Layout description. static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize); @@ -3643,9 +3755,7 @@ class FreeSpace: public HeapObject { } void FreeSpacePrint(FILE* out); #endif -#ifdef DEBUG - void FreeSpaceVerify(); -#endif + DECLARE_VERIFIER(FreeSpace) // Layout description. // Size is smi tagged when it is stored. @@ -3725,9 +3835,7 @@ class ExternalPixelArray: public ExternalArray { } void ExternalPixelArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalPixelArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalPixelArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalPixelArray); @@ -3754,9 +3862,7 @@ class ExternalByteArray: public ExternalArray { } void ExternalByteArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalByteArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalByteArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalByteArray); @@ -3783,9 +3889,7 @@ class ExternalUnsignedByteArray: public ExternalArray { } void ExternalUnsignedByteArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalUnsignedByteArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalUnsignedByteArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedByteArray); @@ -3812,9 +3916,7 @@ class ExternalShortArray: public ExternalArray { } void ExternalShortArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalShortArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalShortArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalShortArray); @@ -3841,9 +3943,7 @@ class ExternalUnsignedShortArray: public ExternalArray { } void ExternalUnsignedShortArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalUnsignedShortArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalUnsignedShortArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedShortArray); @@ -3870,9 +3970,7 @@ class ExternalIntArray: public ExternalArray { } void ExternalIntArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalIntArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalIntArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalIntArray); @@ -3899,9 +3997,7 @@ class ExternalUnsignedIntArray: public ExternalArray { } void ExternalUnsignedIntArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalUnsignedIntArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalUnsignedIntArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedIntArray); @@ -3928,9 +4024,7 @@ class ExternalFloatArray: public ExternalArray { } void ExternalFloatArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalFloatArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalFloatArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloatArray); @@ -3957,9 +4051,7 @@ class ExternalDoubleArray: public ExternalArray { } void ExternalDoubleArrayPrint(FILE* out); #endif // OBJECT_PRINT -#ifdef DEBUG - void ExternalDoubleArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalDoubleArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalDoubleArray); @@ -3984,7 +4076,7 @@ class DeoptimizationInputData: public FixedArray { static const int kFirstDeoptEntryIndex = 5; // Offsets of deopt entry elements relative to the start of the entry. - static const int kAstIdOffset = 0; + static const int kAstIdRawOffset = 0; static const int kTranslationIndexOffset = 1; static const int kArgumentsStackHeightOffset = 2; static const int kPcOffset = 3; @@ -4016,13 +4108,21 @@ class DeoptimizationInputData: public FixedArray { set(IndexForEntry(i) + k##name##Offset, value); \ } - DEFINE_ENTRY_ACCESSORS(AstId, Smi) + DEFINE_ENTRY_ACCESSORS(AstIdRaw, Smi) DEFINE_ENTRY_ACCESSORS(TranslationIndex, Smi) DEFINE_ENTRY_ACCESSORS(ArgumentsStackHeight, Smi) DEFINE_ENTRY_ACCESSORS(Pc, Smi) #undef DEFINE_ENTRY_ACCESSORS + BailoutId AstId(int i) { + return BailoutId(AstIdRaw(i)->value()); + } + + void SetAstId(int i, BailoutId value) { + SetAstIdRaw(i, Smi::FromInt(value.ToInt())); + } + int DeoptCount() { return (length() - kFirstDeoptEntryIndex) / kDeoptEntrySize; } @@ -4057,8 +4157,15 @@ class DeoptimizationInputData: public FixedArray { class DeoptimizationOutputData: public FixedArray { public: int DeoptPoints() { return length() / 2; } - Smi* AstId(int index) { return Smi::cast(get(index * 2)); } - void SetAstId(int index, Smi* id) { set(index * 2, id); } + + BailoutId AstId(int index) { + return BailoutId(Smi::cast(get(index * 2))->value()); + } + + void SetAstId(int index, BailoutId id) { + set(index * 2, Smi::FromInt(id.ToInt())); + } + Smi* PcAndState(int index) { return Smi::cast(get(1 + index * 2)); } void SetPcAndState(int index, Smi* offset) { set(1 + index * 2, offset); } @@ -4093,8 +4200,8 @@ class TypeFeedbackCells: public FixedArray { static int LengthOfFixedArray(int cell_count) { return cell_count * 2; } // Accessors for AST ids associated with cache values. - inline Smi* AstId(int index); - inline void SetAstId(int index, Smi* id); + inline TypeFeedbackId AstId(int index); + inline void SetAstId(int index, TypeFeedbackId id); // Accessors for global property cells holding the cache values. inline JSGlobalPropertyCell* Cell(int index); @@ -4134,30 +4241,49 @@ class Code: public HeapObject { FLAGS_MAX_VALUE = kMaxInt }; +#define CODE_KIND_LIST(V) \ + V(FUNCTION) \ + V(OPTIMIZED_FUNCTION) \ + V(STUB) \ + V(BUILTIN) \ + V(LOAD_IC) \ + V(KEYED_LOAD_IC) \ + V(CALL_IC) \ + V(KEYED_CALL_IC) \ + V(STORE_IC) \ + V(KEYED_STORE_IC) \ + V(UNARY_OP_IC) \ + V(BINARY_OP_IC) \ + V(COMPARE_IC) \ + V(TO_BOOLEAN_IC) + enum Kind { - FUNCTION, - OPTIMIZED_FUNCTION, - STUB, - BUILTIN, - LOAD_IC, - KEYED_LOAD_IC, - CALL_IC, - KEYED_CALL_IC, - STORE_IC, - KEYED_STORE_IC, - UNARY_OP_IC, - BINARY_OP_IC, - COMPARE_IC, - TO_BOOLEAN_IC, - // No more than 16 kinds. The value currently encoded in four bits in - // Flags. +#define DEFINE_CODE_KIND_ENUM(name) name, + CODE_KIND_LIST(DEFINE_CODE_KIND_ENUM) +#undef DEFINE_CODE_KIND_ENUM // Pseudo-kinds. + LAST_CODE_KIND = TO_BOOLEAN_IC, REGEXP = BUILTIN, FIRST_IC_KIND = LOAD_IC, LAST_IC_KIND = TO_BOOLEAN_IC }; + // No more than 16 kinds. The value is currently encoded in four bits in + // Flags. + STATIC_ASSERT(LAST_CODE_KIND < 16); + + // Types of stubs. + enum StubType { + NORMAL, + FIELD, + CONSTANT_FUNCTION, + CALLBACKS, + INTERCEPTOR, + MAP_TRANSITION, + NONEXISTENT + }; + enum { NUMBER_OF_KINDS = LAST_IC_KIND + 1 }; @@ -4170,7 +4296,7 @@ class Code: public HeapObject { // Printing static const char* Kind2String(Kind kind); static const char* ICState2String(InlineCacheState state); - static const char* PropertyType2String(PropertyType type); + static const char* StubType2String(StubType type); static void PrintExtraICState(FILE* out, Kind kind, ExtraICState extra); inline void Disassemble(const char* name) { Disassemble(name, stdout); @@ -4220,7 +4346,7 @@ class Code: public HeapObject { inline Kind kind(); inline InlineCacheState ic_state(); // Only valid for IC stubs. inline ExtraICState extra_ic_state(); // Only valid for IC stubs. - inline PropertyType type(); // Only valid for monomorphic IC stubs. + inline StubType type(); // Only valid for monomorphic IC stubs. inline int arguments_count(); // Only valid for call IC stubs. // Testers for IC stub kinds. @@ -4324,6 +4450,8 @@ class Code: public HeapObject { inline bool has_function_cache(); inline void set_has_function_cache(bool flag); + bool allowed_in_shared_map_code_cache(); + // Get the safepoint entry for the given pc. SafepointEntry GetSafepointEntry(Address pc); @@ -4361,19 +4489,19 @@ class Code: public HeapObject { Kind kind, InlineCacheState ic_state = UNINITIALIZED, ExtraICState extra_ic_state = kNoExtraICState, - PropertyType type = NORMAL, + StubType type = NORMAL, int argc = -1, InlineCacheHolderFlag holder = OWN_MAP); static inline Flags ComputeMonomorphicFlags( Kind kind, - PropertyType type, + StubType type, ExtraICState extra_ic_state = kNoExtraICState, InlineCacheHolderFlag holder = OWN_MAP, int argc = -1); static inline InlineCacheState ExtractICStateFromFlags(Flags flags); - static inline PropertyType ExtractTypeFromFlags(Flags flags); + static inline StubType ExtractTypeFromFlags(Flags flags); static inline Kind ExtractKindFromFlags(Flags flags); static inline InlineCacheHolderFlag ExtractCacheHolderFromFlags(Flags flags); static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags); @@ -4446,12 +4574,28 @@ class Code: public HeapObject { } void CodePrint(FILE* out); #endif -#ifdef DEBUG - void CodeVerify(); -#endif + DECLARE_VERIFIER(Code) + void ClearInlineCaches(); void ClearTypeFeedbackCells(Heap* heap); +#define DECLARE_CODE_AGE_ENUM(X) k##X##CodeAge, + enum Age { + kNoAge = 0, + CODE_AGE_LIST(DECLARE_CODE_AGE_ENUM) + kAfterLastCodeAge, + kLastCodeAge = kAfterLastCodeAge - 1, + kCodeAgeCount = kAfterLastCodeAge - 1 + }; +#undef DECLARE_CODE_AGE_ENUM + + // Code aging + static void MakeCodeAgeSequenceYoung(byte* sequence); + void MakeYoung(); + void MakeOlder(MarkingParity); + static bool IsYoungSequence(byte* sequence); + bool IsOld(); + // Max loop nesting marker used to postpose OSR. We don't take loop // nesting that is deeper than 5 levels into account. static const int kMaxLoopNestingMarker = 6; @@ -4468,28 +4612,20 @@ class Code: public HeapObject { static const int kICAgeOffset = kGCMetadataOffset + kPointerSize; static const int kFlagsOffset = kICAgeOffset + kIntSize; - static const int kKindSpecificFlagsOffset = kFlagsOffset + kIntSize; - static const int kKindSpecificFlagsSize = 2 * kIntSize; + static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize; + static const int kKindSpecificFlags2Offset = + kKindSpecificFlags1Offset + kIntSize; - static const int kHeaderPaddingStart = kKindSpecificFlagsOffset + - kKindSpecificFlagsSize; + static const int kHeaderPaddingStart = kKindSpecificFlags2Offset + kIntSize; // Add padding to align the instruction start following right after // the Code object header. static const int kHeaderSize = (kHeaderPaddingStart + kCodeAlignmentMask) & ~kCodeAlignmentMask; - // Byte offsets within kKindSpecificFlagsOffset. - static const int kStubMajorKeyOffset = kKindSpecificFlagsOffset; - static const int kOptimizableOffset = kKindSpecificFlagsOffset; - static const int kStackSlotsOffset = kKindSpecificFlagsOffset; - static const int kCheckTypeOffset = kKindSpecificFlagsOffset; - - static const int kUnaryOpTypeOffset = kStubMajorKeyOffset + 1; - static const int kBinaryOpTypeOffset = kStubMajorKeyOffset + 1; - static const int kCompareStateOffset = kStubMajorKeyOffset + 1; - static const int kToBooleanTypeOffset = kStubMajorKeyOffset + 1; - static const int kHasFunctionCacheOffset = kStubMajorKeyOffset + 1; + // Byte offsets within kKindSpecificFlags1Offset. + static const int kOptimizableOffset = kKindSpecificFlags1Offset; + static const int kCheckTypeOffset = kKindSpecificFlags1Offset; static const int kFullCodeFlags = kOptimizableOffset + 1; class FullCodeFlagsHasDeoptimizationSupportField: @@ -4497,26 +4633,90 @@ class Code: public HeapObject { class FullCodeFlagsHasDebugBreakSlotsField: public BitField<bool, 1, 1> {}; class FullCodeFlagsIsCompiledOptimizable: public BitField<bool, 2, 1> {}; - static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1; - - static const int kCompareOperationOffset = kCompareStateOffset + 1; - static const int kAllowOSRAtLoopNestingLevelOffset = kFullCodeFlags + 1; static const int kProfilerTicksOffset = kAllowOSRAtLoopNestingLevelOffset + 1; - static const int kSafepointTableOffsetOffset = kStackSlotsOffset + kIntSize; - static const int kStackCheckTableOffsetOffset = kStackSlotsOffset + kIntSize; - // Flags layout. BitField<type, shift, size>. class ICStateField: public BitField<InlineCacheState, 0, 3> {}; - class TypeField: public BitField<PropertyType, 3, 4> {}; - class CacheHolderField: public BitField<InlineCacheHolderFlag, 7, 1> {}; - class KindField: public BitField<Kind, 8, 4> {}; - class ExtraICStateField: public BitField<ExtraICState, 12, 2> {}; - class IsPregeneratedField: public BitField<bool, 14, 1> {}; + class TypeField: public BitField<StubType, 3, 3> {}; + class CacheHolderField: public BitField<InlineCacheHolderFlag, 6, 1> {}; + class KindField: public BitField<Kind, 7, 4> {}; + class ExtraICStateField: public BitField<ExtraICState, 11, 2> {}; + class IsPregeneratedField: public BitField<bool, 13, 1> {}; + + // KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION) + static const int kStackSlotsFirstBit = 0; + static const int kStackSlotsBitCount = 24; + static const int kUnaryOpTypeFirstBit = + kStackSlotsFirstBit + kStackSlotsBitCount; + static const int kUnaryOpTypeBitCount = 3; + static const int kBinaryOpTypeFirstBit = + kStackSlotsFirstBit + kStackSlotsBitCount; + static const int kBinaryOpTypeBitCount = 3; + static const int kBinaryOpResultTypeFirstBit = + kBinaryOpTypeFirstBit + kBinaryOpTypeBitCount; + static const int kBinaryOpResultTypeBitCount = 3; + static const int kCompareStateFirstBit = + kStackSlotsFirstBit + kStackSlotsBitCount; + static const int kCompareStateBitCount = 3; + static const int kCompareOperationFirstBit = + kCompareStateFirstBit + kCompareStateBitCount; + static const int kCompareOperationBitCount = 4; + static const int kToBooleanStateFirstBit = + kStackSlotsFirstBit + kStackSlotsBitCount; + static const int kToBooleanStateBitCount = 8; + static const int kHasFunctionCacheFirstBit = + kStackSlotsFirstBit + kStackSlotsBitCount; + static const int kHasFunctionCacheBitCount = 1; + + STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32); + STATIC_ASSERT(kUnaryOpTypeFirstBit + kUnaryOpTypeBitCount <= 32); + STATIC_ASSERT(kBinaryOpTypeFirstBit + kBinaryOpTypeBitCount <= 32); + STATIC_ASSERT(kBinaryOpResultTypeFirstBit + + kBinaryOpResultTypeBitCount <= 32); + STATIC_ASSERT(kCompareStateFirstBit + kCompareStateBitCount <= 32); + STATIC_ASSERT(kCompareOperationFirstBit + kCompareOperationBitCount <= 32); + STATIC_ASSERT(kToBooleanStateFirstBit + kToBooleanStateBitCount <= 32); + STATIC_ASSERT(kHasFunctionCacheFirstBit + kHasFunctionCacheBitCount <= 32); + + class StackSlotsField: public BitField<int, + kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT + class UnaryOpTypeField: public BitField<int, + kUnaryOpTypeFirstBit, kUnaryOpTypeBitCount> {}; // NOLINT + class BinaryOpTypeField: public BitField<int, + kBinaryOpTypeFirstBit, kBinaryOpTypeBitCount> {}; // NOLINT + class BinaryOpResultTypeField: public BitField<int, + kBinaryOpResultTypeFirstBit, kBinaryOpResultTypeBitCount> {}; // NOLINT + class CompareStateField: public BitField<int, + kCompareStateFirstBit, kCompareStateBitCount> {}; // NOLINT + class CompareOperationField: public BitField<int, + kCompareOperationFirstBit, kCompareOperationBitCount> {}; // NOLINT + class ToBooleanStateField: public BitField<int, + kToBooleanStateFirstBit, kToBooleanStateBitCount> {}; // NOLINT + class HasFunctionCacheField: public BitField<bool, + kHasFunctionCacheFirstBit, kHasFunctionCacheBitCount> {}; // NOLINT + + // KindSpecificFlags2 layout (STUB and OPTIMIZED_FUNCTION) + static const int kStubMajorKeyFirstBit = 0; + static const int kSafepointTableOffsetFirstBit = + kStubMajorKeyFirstBit + kStubMajorKeyBits; + static const int kSafepointTableOffsetBitCount = 26; + + STATIC_ASSERT(kStubMajorKeyFirstBit + kStubMajorKeyBits <= 32); + STATIC_ASSERT(kSafepointTableOffsetFirstBit + + kSafepointTableOffsetBitCount <= 32); + + class SafepointTableOffsetField: public BitField<int, + kSafepointTableOffsetFirstBit, + kSafepointTableOffsetBitCount> {}; // NOLINT + class StubMajorKeyField: public BitField<int, + kStubMajorKeyFirstBit, kStubMajorKeyBits> {}; // NOLINT + + // KindSpecificFlags2 layout (FUNCTION) + class StackCheckTableOffsetField: public BitField<int, 0, 31> {}; // Signed field cannot be encoded using the BitField class. - static const int kArgumentsCountShift = 15; + static const int kArgumentsCountShift = 14; static const int kArgumentsCountMask = ~((1 << kArgumentsCountShift) - 1); // This constant should be encodable in an ARM instruction. @@ -4524,6 +4724,21 @@ class Code: public HeapObject { TypeField::kMask | CacheHolderField::kMask; private: + friend class RelocIterator; + + // Code aging + byte* FindCodeAgeSequence(); + static void GetCodeAgeAndParity(Code* code, Age* age, + MarkingParity* parity); + static void GetCodeAgeAndParity(byte* sequence, Age* age, + MarkingParity* parity); + static Code* GetCodeAgeStub(Age age, MarkingParity parity); + + // Code aging -- platform-specific + byte* FindPlatformCodeAgeSequence(); + static void PatchPlatformCodeAge(byte* sequence, Age age, + MarkingParity parity); + DISALLOW_IMPLICIT_CONSTRUCTORS(Code); }; @@ -4566,12 +4781,20 @@ class Map: public HeapObject { inline void set_bit_field2(byte value); // Bit field 3. - // TODO(1399): It should be possible to make room for bit_field3 in the map - // without overloading the instance descriptors field (and storing it in the - // DescriptorArray when the map has one). inline int bit_field3(); inline void set_bit_field3(int value); + class EnumLengthBits: public BitField<int, 0, 11> {}; + class NumberOfOwnDescriptorsBits: public BitField<int, 11, 11> {}; + class IsShared: public BitField<bool, 22, 1> {}; + class FunctionWithPrototype: public BitField<bool, 23, 1> {}; + class DictionaryMap: public BitField<bool, 24, 1> {}; + class OwnsDescriptors: public BitField<bool, 25, 1> {}; + class IsObserved: public BitField<bool, 26, 1> {}; + class NamedInterceptorIsFallback: public BitField<bool, 27, 1> {}; + class HasInstanceCallHandler: public BitField<bool, 28, 1> {}; + class AttachedToSharedFunctionInfo: public BitField<bool, 29, 1> {}; + // Tells whether the object in the prototype property will be used // for instances created from this function. If the prototype // property is set to a value that is not a JSObject, the prototype @@ -4630,11 +4853,11 @@ class Map: public HeapObject { // Tells whether the instance has a call-as-function handler. inline void set_has_instance_call_handler() { - set_bit_field3(bit_field3() | (1 << kHasInstanceCallHandler)); + set_bit_field3(HasInstanceCallHandler::update(bit_field3(), true)); } inline bool has_instance_call_handler() { - return ((1 << kHasInstanceCallHandler) & bit_field3()) != 0; + return HasInstanceCallHandler::decode(bit_field3()); } inline void set_is_extensible(bool value); @@ -4654,17 +4877,21 @@ class Map: public HeapObject { } // Tells whether the instance has fast elements that are only Smis. - inline bool has_fast_smi_only_elements() { - return elements_kind() == FAST_SMI_ONLY_ELEMENTS; + inline bool has_fast_smi_elements() { + return IsFastSmiElementsKind(elements_kind()); } // Tells whether the instance has fast elements. - inline bool has_fast_elements() { - return elements_kind() == FAST_ELEMENTS; + inline bool has_fast_object_elements() { + return IsFastObjectElementsKind(elements_kind()); + } + + inline bool has_fast_smi_or_object_elements() { + return IsFastSmiOrObjectElementsKind(elements_kind()); } inline bool has_fast_double_elements() { - return elements_kind() == FAST_DOUBLE_ELEMENTS; + return IsFastDoubleElementsKind(elements_kind()); } inline bool has_non_strict_arguments_elements() { @@ -4672,13 +4899,11 @@ class Map: public HeapObject { } inline bool has_external_array_elements() { - ElementsKind kind(elements_kind()); - return kind >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && - kind <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND; + return IsExternalArrayElementsKind(elements_kind()); } inline bool has_dictionary_elements() { - return elements_kind() == DICTIONARY_ELEMENTS; + return IsDictionaryElementsKind(elements_kind()); } inline bool has_slow_elements_kind() { @@ -4689,6 +4914,20 @@ class Map: public HeapObject { static bool IsValidElementsTransition(ElementsKind from_kind, ElementsKind to_kind); + inline bool HasTransitionArray(); + inline bool HasElementsTransition(); + inline Map* elements_transition_map(); + MUST_USE_RESULT inline MaybeObject* set_elements_transition_map( + Map* transitioned_map); + inline void SetTransition(int transition_index, Map* target); + inline Map* GetTransition(int transition_index); + MUST_USE_RESULT inline MaybeObject* AddTransition(String* key, + Map* target, + SimpleTransitionFlag flag); + DECL_ACCESSORS(transitions, TransitionArray) + inline void ClearTransitions(Heap* heap, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + // Tells whether the map is attached to SharedFunctionInfo // (for inobject slack tracking). inline void set_attached_to_shared_function_info(bool value); @@ -4699,9 +4938,15 @@ class Map: public HeapObject { // behavior. If true, the map should never be modified, instead a clone // should be created and modified. inline void set_is_shared(bool value); - inline bool is_shared(); + // Tells whether the map is used for JSObjects in dictionary mode (ie + // normalized objects, ie objects for which HasFastProperties returns false). + // A map can never be used for both dictionary mode and fast mode JSObjects. + // False by default and for HeapObjects that are not JSObjects. + inline void set_dictionary_map(bool value); + inline bool is_dictionary_map(); + // Tells whether the instance needs security checks when accessing its // properties. inline void set_is_access_check_needed(bool access_check_needed); @@ -4720,7 +4965,7 @@ class Map: public HeapObject { // comparisons involving this object inline void set_use_user_object_comparison(bool value); inline bool use_user_object_comparison(); - + // [prototype]: implicit prototype object. DECL_ACCESSORS(prototype, Object) @@ -4729,16 +4974,9 @@ class Map: public HeapObject { inline JSFunction* unchecked_constructor(); - // Should only be called by the code that initializes map to set initial valid - // value of the instance descriptor member. - inline void init_instance_descriptors(); - // [instance descriptors]: describes the object. DECL_ACCESSORS(instance_descriptors, DescriptorArray) - - // Sets the instance descriptor array for the map to be an empty descriptor - // array. - inline void clear_instance_descriptors(); + inline void InitializeDescriptors(DescriptorArray* descriptors); // [stub cache]: contains stubs compiled for this map. DECL_ACCESSORS(code_cache, Object) @@ -4750,6 +4988,7 @@ class Map: public HeapObject { inline Object* GetBackPointer(); inline void SetBackPointer(Object* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline void init_back_pointer(Object* undefined); // [prototype transitions]: cache of prototype transitions. // Prototype transition is a transition that happens @@ -4759,27 +4998,29 @@ class Map: public HeapObject { // 1: back pointer that overlaps with prototype transitions field. // 2 + 2 * i: prototype // 3 + 2 * i: target map - DECL_ACCESSORS(prototype_transitions, FixedArray) + inline FixedArray* GetPrototypeTransitions(); + MUST_USE_RESULT inline MaybeObject* SetPrototypeTransitions( + FixedArray* prototype_transitions); + inline bool HasPrototypeTransitions(); - inline void init_prototype_transitions(Object* undefined); - inline HeapObject* unchecked_prototype_transitions(); + inline HeapObject* UncheckedPrototypeTransitions(); + inline TransitionArray* unchecked_transition_array(); - static const int kProtoTransitionHeaderSize = 2; + static const int kProtoTransitionHeaderSize = 1; static const int kProtoTransitionNumberOfEntriesOffset = 0; - static const int kProtoTransitionBackPointerOffset = 1; static const int kProtoTransitionElementsPerEntry = 2; static const int kProtoTransitionPrototypeOffset = 0; static const int kProtoTransitionMapOffset = 1; inline int NumberOfProtoTransitions() { - FixedArray* cache = prototype_transitions(); + FixedArray* cache = GetPrototypeTransitions(); if (cache->length() == 0) return 0; return Smi::cast(cache->get(kProtoTransitionNumberOfEntriesOffset))->value(); } inline void SetNumberOfProtoTransitions(int value) { - FixedArray* cache = prototype_transitions(); + FixedArray* cache = GetPrototypeTransitions(); ASSERT(cache->length() != 0); cache->set_unchecked(kProtoTransitionNumberOfEntriesOffset, Smi::FromInt(value)); @@ -4788,18 +5029,86 @@ class Map: public HeapObject { // Lookup in the map's instance descriptors and fill out the result // with the given holder if the name is found. The holder may be // NULL when this function is used from the compiler. - void LookupInDescriptors(JSObject* holder, - String* name, - LookupResult* result); + inline void LookupDescriptor(JSObject* holder, + String* name, + LookupResult* result); + + inline void LookupTransition(JSObject* holder, + String* name, + LookupResult* result); + + // The size of transition arrays are limited so they do not end up in large + // object space. Otherwise ClearNonLiveTransitions would leak memory while + // applying in-place right trimming. + inline bool CanHaveMoreTransitions(); + + int LastAdded() { + int number_of_own_descriptors = NumberOfOwnDescriptors(); + ASSERT(number_of_own_descriptors > 0); + return number_of_own_descriptors - 1; + } + + int NumberOfOwnDescriptors() { + return NumberOfOwnDescriptorsBits::decode(bit_field3()); + } + + void SetNumberOfOwnDescriptors(int number) { + ASSERT(number <= instance_descriptors()->number_of_descriptors()); + set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(), number)); + } + + inline JSGlobalPropertyCell* RetrieveDescriptorsPointer(); + + int EnumLength() { + return EnumLengthBits::decode(bit_field3()); + } + + void SetEnumLength(int length) { + if (length != kInvalidEnumCache) { + ASSERT(length >= 0); + ASSERT(length == 0 || instance_descriptors()->HasEnumCache()); + ASSERT(length <= NumberOfOwnDescriptors()); + } + set_bit_field3(EnumLengthBits::update(bit_field3(), length)); + } + + inline bool owns_descriptors(); + inline void set_owns_descriptors(bool is_shared); + inline bool is_observed(); + inline void set_is_observed(bool is_observed); + + MUST_USE_RESULT MaybeObject* RawCopy(int instance_size); + MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors(); MUST_USE_RESULT MaybeObject* CopyDropDescriptors(); + MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors( + DescriptorArray* descriptors, + String* name, + TransitionFlag flag, + int descriptor_index); + MUST_USE_RESULT MaybeObject* ShareDescriptor(DescriptorArray* descriptors, + Descriptor* descriptor); + MUST_USE_RESULT MaybeObject* CopyAddDescriptor(Descriptor* descriptor, + TransitionFlag flag); + MUST_USE_RESULT MaybeObject* CopyInsertDescriptor(Descriptor* descriptor, + TransitionFlag flag); + MUST_USE_RESULT MaybeObject* CopyReplaceDescriptor( + DescriptorArray* descriptors, + Descriptor* descriptor, + int index, + TransitionFlag flag); + MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind, + TransitionFlag flag); MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode, NormalizedMapSharingMode sharing); + inline void AppendDescriptor(Descriptor* desc, + const DescriptorArray::WhitenessWitness&); + // Returns a copy of the map, with all transitions dropped from the // instance descriptors. - MUST_USE_RESULT MaybeObject* CopyDropTransitions(); + MUST_USE_RESULT MaybeObject* Copy(); // Returns the property index for name (only valid for FAST MODE). int PropertyIndexFor(String* name); @@ -4809,7 +5118,8 @@ class Map: public HeapObject { // Returns the number of properties described in instance_descriptors // filtering out properties with the specified attributes. - int NumberOfDescribedProperties(PropertyAttributes filter = NONE); + int NumberOfDescribedProperties(DescriptorFlag which = OWN_DESCRIPTORS, + PropertyAttributes filter = NONE); // Casting. static inline Map* cast(Object* obj); @@ -4828,6 +5138,13 @@ class Map: public HeapObject { Handle<Code> code); MUST_USE_RESULT MaybeObject* UpdateCodeCache(String* name, Code* code); + // Extend the descriptor array of the map with the list of descriptors. + // In case of duplicates, the latest descriptor is used. + static void AppendCallbackDescriptors(Handle<Map> map, + Handle<Object> descriptors); + + static void EnsureDescriptorSlack(Handle<Map> map, int slack); + // Returns the found code or undefined if absent. Object* FindInCodeCache(String* name, Code::Flags flags); @@ -4852,23 +5169,11 @@ class Map: public HeapObject { // The "shared" flags of both this map and |other| are ignored. bool EquivalentToForNormalization(Map* other, PropertyNormalizationMode mode); - // Returns the contents of this map's descriptor array for the given string. - // May return NULL. |safe_to_add_transition| is set to false and NULL - // is returned if adding transitions is not allowed. - Object* GetDescriptorContents(String* sentinel_name, - bool* safe_to_add_transitions); - // Returns the map that this map transitions to if its elements_kind // is changed to |elements_kind|, or NULL if no such map is cached yet. // |safe_to_add_transitions| is set to false if adding transitions is not // allowed. - Map* LookupElementsTransitionMap(ElementsKind elements_kind, - bool* safe_to_add_transition); - - // Adds an entry to this map's descriptor array for a transition to - // |transitioned_map| when its elements_kind is changed to |elements_kind|. - MUST_USE_RESULT MaybeObject* AddElementsTransition( - ElementsKind elements_kind, Map* transitioned_map); + Map* LookupElementsTransitionMap(ElementsKind elements_kind); // Returns the transitioned map for this map with the most generic // elements_kind that's found in |candidates|, or null handle if no match is @@ -4876,14 +5181,14 @@ class Map: public HeapObject { Handle<Map> FindTransitionedMap(MapHandleList* candidates); Map* FindTransitionedMap(MapList* candidates); - // Zaps the contents of backing data structures in debug mode. Note that the + // Zaps the contents of backing data structures. Note that the // heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects // holding weak references when incremental marking is used, because it also // iterates over objects that are otherwise unreachable. -#ifdef DEBUG - void ZapInstanceDescriptors(); + // In general we only want to call these functions in release mode when + // heap verification is turned on. void ZapPrototypeTransitions(); -#endif + void ZapTransitions(); // Dispatched behavior. #ifdef OBJECT_PRINT @@ -4892,8 +5197,9 @@ class Map: public HeapObject { } void MapPrint(FILE* out); #endif -#ifdef DEBUG - void MapVerify(); + DECLARE_VERIFIER(Map) + +#ifdef VERIFY_HEAP void SharedMapVerify(); #endif @@ -4904,44 +5210,47 @@ class Map: public HeapObject { void TraverseTransitionTree(TraverseCallback callback, void* data); + // When you set the prototype of an object using the __proto__ accessor you + // need a new map for the object (the prototype is stored in the map). In + // order not to multiply maps unnecessarily we store these as transitions in + // the original map. That way we can transition to the same map if the same + // prototype is set, rather than creating a new map every time. The + // transitions are in the form of a map where the keys are prototype objects + // and the values are the maps the are transitioned to. static const int kMaxCachedPrototypeTransitions = 256; - Object* GetPrototypeTransition(Object* prototype); + Map* GetPrototypeTransition(Object* prototype); MUST_USE_RESULT MaybeObject* PutPrototypeTransition(Object* prototype, Map* map); static const int kMaxPreAllocatedPropertyFields = 255; + // Constant for denoting that the enum cache is not yet initialized. + static const int kInvalidEnumCache = EnumLengthBits::kMax; + // Layout description. static const int kInstanceSizesOffset = HeapObject::kHeaderSize; static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize; static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize; static const int kConstructorOffset = kPrototypeOffset + kPointerSize; - // Storage for instance descriptors is overloaded to also contain additional - // map flags when unused (bit_field3). When the map has instance descriptors, - // the flags are transferred to the instance descriptor array and accessed - // through an extra indirection. - // TODO(1399): It should be possible to make room for bit_field3 in the map - // without overloading the instance descriptors field, but the map is - // currently perfectly aligned to 32 bytes and extending it at all would - // double its size. After the increment GC work lands, this size restriction - // could be loosened and bit_field3 moved directly back in the map. - static const int kInstanceDescriptorsOrBitField3Offset = + // Storage for the transition array is overloaded to directly contain a back + // pointer if unused. When the map has transitions, the back pointer is + // transferred to the transition array and accessed through an extra + // indirection. + static const int kTransitionsOrBackPointerOffset = kConstructorOffset + kPointerSize; + static const int kDescriptorsOffset = + kTransitionsOrBackPointerOffset + kPointerSize; static const int kCodeCacheOffset = - kInstanceDescriptorsOrBitField3Offset + kPointerSize; - static const int kPrototypeTransitionsOrBackPointerOffset = - kCodeCacheOffset + kPointerSize; - static const int kPadStart = - kPrototypeTransitionsOrBackPointerOffset + kPointerSize; - static const int kSize = MAP_POINTER_ALIGN(kPadStart); + kDescriptorsOffset + kPointerSize; + static const int kBitField3Offset = kCodeCacheOffset + kPointerSize; + static const int kSize = kBitField3Offset + kPointerSize; // Layout of pointer fields. Heap iteration code relies on them // being continuously allocated. static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset; - static const int kPointerFieldsEndOffset = - kPrototypeTransitionsOrBackPointerOffset + kPointerSize; + static const int kPointerFieldsEndOffset = kBitField3Offset + kPointerSize; // Byte offsets within kInstanceSizesOffset. static const int kInstanceSizeOffset = kInstanceSizesOffset + 0; @@ -4974,40 +5283,33 @@ class Map: public HeapObject { // Bit positions for bit field 2 static const int kIsExtensible = 0; - static const int kFunctionWithPrototype = 1; - static const int kStringWrapperSafeForDefaultValueOf = 2; - static const int kUseUserObjectComparison = 3; + static const int kStringWrapperSafeForDefaultValueOf = 1; + static const int kUseUserObjectComparison = 2; // No bits can be used after kElementsKindFirstBit, they are all reserved for // storing ElementKind. - static const int kElementsKindShift = 4; - static const int kElementsKindBitCount = 4; + static const int kElementsKindShift = 3; + static const int kElementsKindBitCount = 5; // Derived values from bit field 2 static const int kElementsKindMask = (-1 << kElementsKindShift) & ((1 << (kElementsKindShift + kElementsKindBitCount)) - 1); static const int8_t kMaximumBitField2FastElementValue = static_cast<int8_t>( (FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1; - static const int8_t kMaximumBitField2FastSmiOnlyElementValue = - static_cast<int8_t>((FAST_SMI_ONLY_ELEMENTS + 1) << + static const int8_t kMaximumBitField2FastSmiElementValue = + static_cast<int8_t>((FAST_SMI_ELEMENTS + 1) << + Map::kElementsKindShift) - 1; + static const int8_t kMaximumBitField2FastHoleyElementValue = + static_cast<int8_t>((FAST_HOLEY_ELEMENTS + 1) << + Map::kElementsKindShift) - 1; + static const int8_t kMaximumBitField2FastHoleySmiElementValue = + static_cast<int8_t>((FAST_HOLEY_SMI_ELEMENTS + 1) << Map::kElementsKindShift) - 1; - - // Bit positions for bit field 3 - static const int kIsShared = 0; - static const int kNamedInterceptorIsFallback = 1; - static const int kHasInstanceCallHandler = 2; - static const int kAttachedToSharedFunctionInfo = 3; - - // Layout of the default cache. It holds alternating name and code objects. - static const int kCodeCacheEntrySize = 2; - static const int kCodeCacheEntryNameOffset = 0; - static const int kCodeCacheEntryCodeOffset = 1; typedef FixedBodyDescriptor<kPointerFieldsBeginOffset, kPointerFieldsEndOffset, kSize> BodyDescriptor; private: - String* elements_transition_sentinel_name(); DISALLOW_IMPLICIT_CONSTRUCTORS(Map); }; @@ -5101,9 +5403,7 @@ class Script: public Struct { } void ScriptPrint(FILE* out); #endif -#ifdef DEBUG - void ScriptVerify(); -#endif + DECLARE_VERIFIER(Script) static const int kSourceOffset = HeapObject::kHeaderSize; static const int kNameOffset = kSourceOffset + kPointerSize; @@ -5188,6 +5488,29 @@ class SharedFunctionInfo: public HeapObject { // [code]: Function code. DECL_ACCESSORS(code, Code) + // [optimized_code_map]: Map from native context to optimized code + // and a shared literals array or Smi 0 if none. + DECL_ACCESSORS(optimized_code_map, Object) + + // Returns index i of the entry with the specified context. At position + // i - 1 is the context, position i the code, and i + 1 the literals array. + // Returns -1 when no matching entry is found. + int SearchOptimizedCodeMap(Context* native_context); + + // Installs optimized code from the code map on the given closure. The + // index has to be consistent with a search result as defined above. + void InstallFromOptimizedCodeMap(JSFunction* function, int index); + + // Clear optimized code map. + void ClearOptimizedCodeMap(); + + // Add a new entry to the optimized code map. + static void AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared, + Handle<Context> native_context, + Handle<Code> code, + Handle<FixedArray> literals); + static const int kEntryLength = 3; + // [scope_info]: Scope info. DECL_ACCESSORS(scope_info, ScopeInfo) @@ -5295,6 +5618,10 @@ class SharedFunctionInfo: public HeapObject { // IsInobjectSlackTrackingInProgress is false after this call. void CompleteInobjectSlackTracking(); + // Invoked before pointers in SharedFunctionInfo are being marked. + // Also clears the optimized code map. + inline void BeforeVisitingPointers(); + // Clears the initial_map before the GC marking phase to ensure the reference // is weak. IsInobjectSlackTrackingInProgress is false after this call. void DetachInitialMap(); @@ -5380,8 +5707,8 @@ class SharedFunctionInfo: public HeapObject { // A counter used to determine when to stress the deoptimizer with a // deopt. - inline int deopt_counter(); - inline void set_deopt_counter(int counter); + inline int stress_deopt_counter(); + inline void set_stress_deopt_counter(int counter); inline int profiler_ticks(); @@ -5407,6 +5734,12 @@ class SharedFunctionInfo: public HeapObject { // when doing GC if we expect that the function will no longer be used. DECL_BOOLEAN_ACCESSORS(allows_lazy_compilation) + // Indicates if this function can be lazy compiled without a context. + // This is used to determine if we can force compilation without reaching + // the function through program execution but through other means (e.g. heap + // iteration by the debugger). + DECL_BOOLEAN_ACCESSORS(allows_lazy_compilation_without_context) + // Indicates how many full GCs this function has survived with assigned // code object. Used to determine when it is relatively safe to flush // this code object and replace it with lazy compilation stub. @@ -5474,6 +5807,9 @@ class SharedFunctionInfo: public HeapObject { // Indicates that the function cannot be inlined. DECL_BOOLEAN_ACCESSORS(dont_inline) + // Indicates that code for this function cannot be cached. + DECL_BOOLEAN_ACCESSORS(dont_cache) + // Indicates whether or not the code in the shared function support // deoptimization. inline bool has_deoptimization_support(); @@ -5483,12 +5819,12 @@ class SharedFunctionInfo: public HeapObject { // Disable (further) attempted optimization of all functions sharing this // shared function info. - void DisableOptimization(); + void DisableOptimization(const char* reason); // Lookup the bailout ID and ASSERT that it exists in the non-optimized // code, returns whether it asserted (i.e., always true if assertions are // disabled). - bool VerifyBailoutId(int id); + bool VerifyBailoutId(BailoutId id); // Check whether a inlined constructor can be generated with the given // prototype. @@ -5512,9 +5848,26 @@ class SharedFunctionInfo: public HeapObject { bool HasSourceCode(); Handle<Object> GetSourceCode(); + // Number of times the function was optimized. inline int opt_count(); inline void set_opt_count(int opt_count); + // Number of times the function was deoptimized. + inline void set_deopt_count(int value); + inline int deopt_count(); + inline void increment_deopt_count(); + + // Number of time we tried to re-enable optimization after it + // was disabled due to high number of deoptimizations. + inline void set_opt_reenable_tries(int value); + inline int opt_reenable_tries(); + + inline void TryReenableOptimization(); + + // Stores deopt_count, opt_reenable_tries and ic_age as bit-fields. + inline void set_counters(int value); + inline int counters(); + // Source size of this function. int SourceSize(); @@ -5533,21 +5886,16 @@ class SharedFunctionInfo: public HeapObject { } void SharedFunctionInfoPrint(FILE* out); #endif -#ifdef DEBUG - void SharedFunctionInfoVerify(); -#endif + DECLARE_VERIFIER(SharedFunctionInfo) void ResetForNewContext(int new_ic_age); - // Helpers to compile the shared code. Returns true on success, false on - // failure (e.g., stack overflow during compilation). - static bool EnsureCompiled(Handle<SharedFunctionInfo> shared, - ClearExceptionFlag flag); + // Helper to compile the shared code. Returns true on success, false on + // failure (e.g., stack overflow during compilation). This is only used by + // the debugger, it is not possible to compile without a context otherwise. static bool CompileLazy(Handle<SharedFunctionInfo> shared, ClearExceptionFlag flag); - void SharedFunctionInfoIterateBody(ObjectVisitor* v); - // Casting. static inline SharedFunctionInfo* cast(Object* obj); @@ -5558,7 +5906,8 @@ class SharedFunctionInfo: public HeapObject { // Pointer fields. static const int kNameOffset = HeapObject::kHeaderSize; static const int kCodeOffset = kNameOffset + kPointerSize; - static const int kScopeInfoOffset = kCodeOffset + kPointerSize; + static const int kOptimizedCodeMapOffset = kCodeOffset + kPointerSize; + static const int kScopeInfoOffset = kOptimizedCodeMapOffset + kPointerSize; static const int kConstructStubOffset = kScopeInfoOffset + kPointerSize; static const int kInstanceClassNameOffset = kConstructStubOffset + kPointerSize; @@ -5571,13 +5920,14 @@ class SharedFunctionInfo: public HeapObject { kInferredNameOffset + kPointerSize; static const int kThisPropertyAssignmentsOffset = kInitialMapOffset + kPointerSize; - // ic_age is a Smi field. It could be grouped with another Smi field into a - // PSEUDO_SMI_ACCESSORS pair (on x64), if one becomes available. - static const int kICAgeOffset = kThisPropertyAssignmentsOffset + kPointerSize; + // ast_node_count is a Smi field. It could be grouped with another Smi field + // into a PSEUDO_SMI_ACCESSORS pair (on x64), if one becomes available. + static const int kAstNodeCountOffset = + kThisPropertyAssignmentsOffset + kPointerSize; #if V8_HOST_ARCH_32_BIT // Smi fields. static const int kLengthOffset = - kICAgeOffset + kPointerSize; + kAstNodeCountOffset + kPointerSize; static const int kFormalParameterCountOffset = kLengthOffset + kPointerSize; static const int kExpectedNofPropertiesOffset = kFormalParameterCountOffset + kPointerSize; @@ -5595,12 +5945,11 @@ class SharedFunctionInfo: public HeapObject { kCompilerHintsOffset + kPointerSize; static const int kOptCountOffset = kThisPropertyAssignmentsCountOffset + kPointerSize; - static const int kAstNodeCountOffset = kOptCountOffset + kPointerSize; - static const int kDeoptCounterOffset = kAstNodeCountOffset + kPointerSize; - + static const int kCountersOffset = kOptCountOffset + kPointerSize; + static const int kStressDeoptCounterOffset = kCountersOffset + kPointerSize; // Total size. - static const int kSize = kDeoptCounterOffset + kPointerSize; + static const int kSize = kStressDeoptCounterOffset + kPointerSize; #else // The only reason to use smi fields instead of int fields // is to allow iteration without maps decoding during @@ -5612,7 +5961,7 @@ class SharedFunctionInfo: public HeapObject { // word is not set and thus this word cannot be treated as pointer // to HeapObject during old space traversal. static const int kLengthOffset = - kICAgeOffset + kPointerSize; + kAstNodeCountOffset + kPointerSize; static const int kFormalParameterCountOffset = kLengthOffset + kIntSize; @@ -5636,11 +5985,11 @@ class SharedFunctionInfo: public HeapObject { static const int kOptCountOffset = kThisPropertyAssignmentsCountOffset + kIntSize; - static const int kAstNodeCountOffset = kOptCountOffset + kIntSize; - static const int kDeoptCounterOffset = kAstNodeCountOffset + kIntSize; + static const int kCountersOffset = kOptCountOffset + kIntSize; + static const int kStressDeoptCounterOffset = kCountersOffset + kIntSize; // Total size. - static const int kSize = kDeoptCounterOffset + kIntSize; + static const int kSize = kStressDeoptCounterOffset + kIntSize; #endif @@ -5676,6 +6025,7 @@ class SharedFunctionInfo: public HeapObject { enum CompilerHints { kHasOnlySimpleThisPropertyAssignments, kAllowLazyCompilation, + kAllowLazyCompilationWithoutContext, kLiveObjectsMayExist, kCodeAgeShift, kOptimizationDisabled = kCodeAgeShift + kCodeAgeSize, @@ -5691,9 +6041,14 @@ class SharedFunctionInfo: public HeapObject { kIsFunction, kDontOptimize, kDontInline, + kDontCache, kCompilerHintsCount // Pseudo entry }; + class DeoptCountBits: public BitField<int, 0, 4> {}; + class OptReenableTriesBits: public BitField<int, 4, 18> {}; + class ICAgeBits: public BitField<int, 22, 8> {}; + private: #if V8_HOST_ARCH_32_BIT // On 32 bit platforms, compiler hints is a smi. @@ -5753,6 +6108,9 @@ class JSModule: public JSObject { // [context]: the context holding the module's locals, or undefined if none. DECL_ACCESSORS(context, Object) + // [scope_info]: Scope info. + DECL_ACCESSORS(scope_info, ScopeInfo) + // Casting. static inline JSModule* cast(Object* obj); @@ -5763,13 +6121,12 @@ class JSModule: public JSObject { } void JSModulePrint(FILE* out); #endif -#ifdef DEBUG - void JSModuleVerify(); -#endif + DECLARE_VERIFIER(JSModule) // Layout description. static const int kContextOffset = JSObject::kHeaderSize; - static const int kSize = kContextOffset + kPointerSize; + static const int kScopeInfoOffset = kContextOffset + kPointerSize; + static const int kSize = kScopeInfoOffset + kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSModule); @@ -5818,18 +6175,26 @@ class JSFunction: public JSObject { // Mark this function for lazy recompilation. The function will be // recompiled the next time it is executed. void MarkForLazyRecompilation(); + void MarkForParallelRecompilation(); // Helpers to compile this function. Returns true on success, false on // failure (e.g., stack overflow during compilation). + static bool EnsureCompiled(Handle<JSFunction> function, + ClearExceptionFlag flag); static bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag); static bool CompileOptimized(Handle<JSFunction> function, - int osr_ast_id, + BailoutId osr_ast_id, ClearExceptionFlag flag); // Tells whether or not the function is already marked for lazy // recompilation. inline bool IsMarkedForLazyRecompilation(); + inline bool IsMarkedForParallelRecompilation(); + + // Tells whether or not the function is on the parallel + // recompilation queue. + inline bool IsInRecompileQueue(); // Check whether or not this function is inlineable. bool IsInlineable(); @@ -5859,8 +6224,6 @@ class JSFunction: public JSObject { // The initial map for an object created by this constructor. inline Map* initial_map(); inline void set_initial_map(Map* value); - MUST_USE_RESULT inline MaybeObject* set_initial_map_and_cache_transitions( - Map* value); inline bool has_initial_map(); // Get and set the prototype property on a JSFunction. If the @@ -5876,7 +6239,7 @@ class JSFunction: public JSObject { // After prototype is removed, it will not be created when accessed, and // [[Construct]] from this function will not be allowed. - Object* RemovePrototype(); + void RemovePrototype(); inline bool should_have_prototype(); // Accessor for this function's initial map's [[class]] @@ -5888,7 +6251,7 @@ class JSFunction: public JSObject { // Instances created afterwards will have a map whose [[class]] is // set to 'value', but there is no guarantees on instances created // before. - Object* SetInstanceClassName(String* name); + void SetInstanceClassName(String* name); // Returns if this function has been compiled to native code yet. inline bool is_compiled(); @@ -5917,15 +6280,13 @@ class JSFunction: public JSObject { } void JSFunctionPrint(FILE* out); #endif -#ifdef DEBUG - void JSFunctionVerify(); -#endif + DECLARE_VERIFIER(JSFunction) // Returns the number of allocated literals. inline int NumberOfLiterals(); - // Retrieve the global context from a function's literal array. - static Context* GlobalContextFromLiterals(FixedArray* literals); + // Retrieve the native context from a function's literal array. + static Context* NativeContextFromLiterals(FixedArray* literals); // Layout descriptors. The last property (from kNonWeakFieldsEndOffset to // kSize) is weak and has special handling during garbage collection. @@ -5942,7 +6303,7 @@ class JSFunction: public JSObject { // Layout of the literals array. static const int kLiteralsPrefixSize = 1; - static const int kLiteralGlobalContextIndex = 0; + static const int kLiteralNativeContextIndex = 0; // Layout of the bound-function binding array. static const int kBoundFunctionIndex = 0; @@ -5964,9 +6325,9 @@ class JSFunction: public JSObject { class JSGlobalProxy : public JSObject { public: - // [context]: the owner global context of this global proxy object. + // [native_context]: the owner native context of this global proxy object. // It is null value if this object is not used by any context. - DECL_ACCESSORS(context, Object) + DECL_ACCESSORS(native_context, Object) // Casting. static inline JSGlobalProxy* cast(Object* obj); @@ -5978,13 +6339,11 @@ class JSGlobalProxy : public JSObject { } void JSGlobalProxyPrint(FILE* out); #endif -#ifdef DEBUG - void JSGlobalProxyVerify(); -#endif + DECLARE_VERIFIER(JSGlobalProxy) // Layout description. - static const int kContextOffset = JSObject::kHeaderSize; - static const int kSize = kContextOffset + kPointerSize; + static const int kNativeContextOffset = JSObject::kHeaderSize; + static const int kSize = kNativeContextOffset + kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalProxy); @@ -6001,7 +6360,10 @@ class GlobalObject: public JSObject { // [builtins]: the object holding the runtime routines written in JS. DECL_ACCESSORS(builtins, JSBuiltinsObject) - // [global context]: the global context corresponding to this global object. + // [native context]: the natives corresponding to this global object. + DECL_ACCESSORS(native_context, Context) + + // [global context]: the most recent (i.e. innermost) global context. DECL_ACCESSORS(global_context, Context) // [global receiver]: the global receiver object of the context @@ -6032,7 +6394,8 @@ class GlobalObject: public JSObject { // Layout description. static const int kBuiltinsOffset = JSObject::kHeaderSize; - static const int kGlobalContextOffset = kBuiltinsOffset + kPointerSize; + static const int kNativeContextOffset = kBuiltinsOffset + kPointerSize; + static const int kGlobalContextOffset = kNativeContextOffset + kPointerSize; static const int kGlobalReceiverOffset = kGlobalContextOffset + kPointerSize; static const int kHeaderSize = kGlobalReceiverOffset + kPointerSize; @@ -6054,9 +6417,7 @@ class JSGlobalObject: public GlobalObject { } void JSGlobalObjectPrint(FILE* out); #endif -#ifdef DEBUG - void JSGlobalObjectVerify(); -#endif + DECLARE_VERIFIER(JSGlobalObject) // Layout description. static const int kSize = GlobalObject::kHeaderSize; @@ -6088,9 +6449,7 @@ class JSBuiltinsObject: public GlobalObject { } void JSBuiltinsObjectPrint(FILE* out); #endif -#ifdef DEBUG - void JSBuiltinsObjectVerify(); -#endif + DECLARE_VERIFIER(JSBuiltinsObject) // Layout description. The size of the builtins object includes // room for two pointers per runtime routine written in javascript @@ -6131,9 +6490,7 @@ class JSValue: public JSObject { } void JSValuePrint(FILE* out); #endif -#ifdef DEBUG - void JSValueVerify(); -#endif + DECLARE_VERIFIER(JSValue) // Layout description. static const int kValueOffset = JSObject::kHeaderSize; @@ -6187,9 +6544,8 @@ class JSDate: public JSObject { } void JSDatePrint(FILE* out); #endif -#ifdef DEBUG - void JSDateVerify(); -#endif + DECLARE_VERIFIER(JSDate) + // The order is important. It must be kept in sync with date macros // in macros.py. enum FieldIndex { @@ -6285,9 +6641,7 @@ class JSMessageObject: public JSObject { } void JSMessageObjectPrint(FILE* out); #endif -#ifdef DEBUG - void JSMessageObjectVerify(); -#endif + DECLARE_VERIFIER(JSMessageObject) // Layout description. static const int kTypeOffset = JSObject::kHeaderSize; @@ -6376,9 +6730,7 @@ class JSRegExp: public JSObject { static inline JSRegExp* cast(Object* obj); // Dispatched behavior. -#ifdef DEBUG - void JSRegExpVerify(); -#endif + DECLARE_VERIFIER(JSRegExp) static const int kDataOffset = JSObject::kHeaderSize; static const int kSize = kDataOffset + kPointerSize; @@ -6478,13 +6830,15 @@ class CompilationCacheTable: public HashTable<CompilationCacheShape, HashTableKey*> { public: // Find cached value for a string key, otherwise return null. - Object* Lookup(String* src); + Object* Lookup(String* src, Context* context); Object* LookupEval(String* src, Context* context, LanguageMode language_mode, int scope_position); Object* LookupRegExp(String* source, JSRegExp::Flags flags); - MUST_USE_RESULT MaybeObject* Put(String* src, Object* value); + MUST_USE_RESULT MaybeObject* Put(String* src, + Context* context, + Object* value); MUST_USE_RESULT MaybeObject* PutEval(String* src, Context* context, SharedFunctionInfo* value, @@ -6532,9 +6886,7 @@ class CodeCache: public Struct { } void CodeCachePrint(FILE* out); #endif -#ifdef DEBUG - void CodeCacheVerify(); -#endif + DECLARE_VERIFIER(CodeCache) static const int kDefaultCacheOffset = HeapObject::kHeaderSize; static const int kNormalTypeCacheOffset = @@ -6623,9 +6975,7 @@ class PolymorphicCodeCache: public Struct { } void PolymorphicCodeCachePrint(FILE* out); #endif -#ifdef DEBUG - void PolymorphicCodeCacheVerify(); -#endif + DECLARE_VERIFIER(PolymorphicCodeCache) static const int kCacheOffset = HeapObject::kHeaderSize; static const int kSize = kCacheOffset + kPointerSize; @@ -6658,7 +7008,15 @@ class TypeFeedbackInfo: public Struct { inline void set_ic_total_count(int count); inline int ic_with_type_info_count(); - inline void set_ic_with_type_info_count(int count); + inline void change_ic_with_type_info_count(int count); + + inline void initialize_storage(); + + inline void change_own_type_change_checksum(); + inline int own_type_change_checksum(); + + inline void set_inlined_type_change_checksum(int checksum); + inline bool matches_inlined_type_change_checksum(int checksum); DECL_ACCESSORS(type_feedback_cells, TypeFeedbackCells) @@ -6670,18 +7028,27 @@ class TypeFeedbackInfo: public Struct { } void TypeFeedbackInfoPrint(FILE* out); #endif -#ifdef DEBUG - void TypeFeedbackInfoVerify(); -#endif + DECLARE_VERIFIER(TypeFeedbackInfo) - static const int kIcTotalCountOffset = HeapObject::kHeaderSize; - static const int kIcWithTypeinfoCountOffset = - kIcTotalCountOffset + kPointerSize; - static const int kTypeFeedbackCellsOffset = - kIcWithTypeinfoCountOffset + kPointerSize; + static const int kStorage1Offset = HeapObject::kHeaderSize; + static const int kStorage2Offset = kStorage1Offset + kPointerSize; + static const int kTypeFeedbackCellsOffset = kStorage2Offset + kPointerSize; static const int kSize = kTypeFeedbackCellsOffset + kPointerSize; private: + static const int kTypeChangeChecksumBits = 7; + + class ICTotalCountField: public BitField<int, 0, + kSmiValueSize - kTypeChangeChecksumBits> {}; // NOLINT + class OwnTypeChangeChecksum: public BitField<int, + kSmiValueSize - kTypeChangeChecksumBits, + kTypeChangeChecksumBits> {}; // NOLINT + class ICsWithTypeInfoCountField: public BitField<int, 0, + kSmiValueSize - kTypeChangeChecksumBits> {}; // NOLINT + class InlinedTypeChangeChecksum: public BitField<int, + kSmiValueSize - kTypeChangeChecksumBits, + kTypeChangeChecksumBits> {}; // NOLINT + DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackInfo); }; @@ -6707,9 +7074,7 @@ class AliasedArgumentsEntry: public Struct { } void AliasedArgumentsEntryPrint(FILE* out); #endif -#ifdef DEBUG - void AliasedArgumentsEntryVerify(); -#endif + DECLARE_VERIFIER(AliasedArgumentsEntry) static const int kAliasedContextSlot = HeapObject::kHeaderSize; static const int kSize = kAliasedContextSlot + kPointerSize; @@ -6752,10 +7117,6 @@ class StringHasher { // index. bool is_array_index() { return is_array_index_; } - bool is_valid() { return is_valid_; } - - void invalidate() { is_valid_ = false; } - // Calculated hash value for a string consisting of 1 to // String::kMaxArrayIndexSize digits with no leading zeros (except "0"). // value is represented decimal value. @@ -6774,13 +7135,33 @@ class StringHasher { inline uint32_t GetHash(); + // Reusable parts of the hashing algorithm. + INLINE(static uint32_t AddCharacterCore(uint32_t running_hash, uint32_t c)); + INLINE(static uint32_t GetHashCore(uint32_t running_hash)); + int length_; uint32_t raw_running_hash_; uint32_t array_index_; bool is_array_index_; bool is_first_char_; - bool is_valid_; friend class TwoCharHashTableKey; + + template <bool seq_ascii> friend class JsonParser; +}; + + +class IncrementalAsciiStringHasher { + public: + explicit inline IncrementalAsciiStringHasher(uint32_t seed, char first_char); + inline void AddCharacter(uc32 c); + inline uint32_t GetHash(); + + private: + int length_; + uint32_t raw_running_hash_; + uint32_t array_index_; + bool is_array_index_; + char first_char_; }; @@ -6974,9 +7355,6 @@ class String: public HeapObject { bool IsAsciiEqualTo(Vector<const char> str); bool IsTwoByteEqualTo(Vector<const uc16> str); - bool SlowEqualsExternal(uc16 *string, int length); - bool SlowEqualsExternal(char *string, int length); - // Return a UTF8 representation of the string. The string is null // terminated but may optionally contain nulls. Length is returned // in length_output if length_output is not a null pointer The string @@ -7043,9 +7421,8 @@ class String: public HeapObject { char* ToAsciiArray(); #endif -#ifdef DEBUG - void StringVerify(); -#endif + DECLARE_VERIFIER(String) + inline bool IsFlat(); // Layout description. @@ -7114,7 +7491,7 @@ class String: public HeapObject { kIsNotArrayIndexMask | kHashNotComputedMask; // Value of hash field containing computed hash equal to zero. - static const int kZeroHash = kIsNotArrayIndexMask; + static const int kEmptyStringHash = kIsNotArrayIndexMask; // Maximal string length. static const int kMaxLength = (1 << (32 - 2)) - 1; @@ -7149,32 +7526,47 @@ class String: public HeapObject { int from, int to); - static inline bool IsAscii(const char* chars, int length) { + // The return value may point to the first aligned word containing the + // first non-ascii character, rather than directly to the non-ascii character. + // If the return value is >= the passed length, the entire string was ASCII. + static inline int NonAsciiStart(const char* chars, int length) { + const char* start = chars; const char* limit = chars + length; #ifdef V8_HOST_CAN_READ_UNALIGNED ASSERT(kMaxAsciiCharCode == 0x7F); const uintptr_t non_ascii_mask = kUintptrAllBitsSet / 0xFF * 0x80; - while (chars <= limit - sizeof(uintptr_t)) { + while (chars + sizeof(uintptr_t) <= limit) { if (*reinterpret_cast<const uintptr_t*>(chars) & non_ascii_mask) { - return false; + return static_cast<int>(chars - start); } chars += sizeof(uintptr_t); } #endif while (chars < limit) { - if (static_cast<uint8_t>(*chars) > kMaxAsciiCharCodeU) return false; + if (static_cast<uint8_t>(*chars) > kMaxAsciiCharCodeU) { + return static_cast<int>(chars - start); + } ++chars; } - return true; + return static_cast<int>(chars - start); } - static inline bool IsAscii(const uc16* chars, int length) { + static inline bool IsAscii(const char* chars, int length) { + return NonAsciiStart(chars, length) >= length; + } + + static inline int NonAsciiStart(const uc16* chars, int length) { const uc16* limit = chars + length; + const uc16* start = chars; while (chars < limit) { - if (*chars > kMaxAsciiCharCodeU) return false; + if (*chars > kMaxAsciiCharCodeU) return static_cast<int>(chars - start); ++chars; } - return true; + return static_cast<int>(chars - start); + } + + static inline bool IsAscii(const uc16* chars, int length) { + return NonAsciiStart(chars, length) >= length; } protected: @@ -7287,6 +7679,8 @@ class SeqAsciiString: public SeqString { unsigned* offset, unsigned chars); + DECLARE_VERIFIER(SeqAsciiString) + private: DISALLOW_IMPLICIT_CONSTRUCTORS(SeqAsciiString); }; @@ -7390,9 +7784,7 @@ class ConsString: public String { typedef FixedBodyDescriptor<kFirstOffset, kSecondOffset + kPointerSize, kSize> BodyDescriptor; -#ifdef DEBUG - void ConsStringVerify(); -#endif + DECLARE_VERIFIER(ConsString) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ConsString); @@ -7414,7 +7806,8 @@ class ConsString: public String { class SlicedString: public String { public: inline String* parent(); - inline void set_parent(String* parent); + inline void set_parent(String* parent, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline int offset(); inline void set_offset(int offset); @@ -7443,9 +7836,7 @@ class SlicedString: public String { kOffsetOffset + kPointerSize, kSize> BodyDescriptor; -#ifdef DEBUG - void SlicedStringVerify(); -#endif + DECLARE_VERIFIER(SlicedString) private: DISALLOW_IMPLICIT_CONSTRUCTORS(SlicedString); @@ -7672,9 +8063,7 @@ class Oddball: public HeapObject { static inline Oddball* cast(Object* obj); // Dispatched behavior. -#ifdef DEBUG - void OddballVerify(); -#endif + DECLARE_VERIFIER(Oddball) // Initialize the fields. MUST_USE_RESULT MaybeObject* Initialize(const char* to_string, @@ -7717,9 +8106,16 @@ class JSGlobalPropertyCell: public HeapObject { // Casting. static inline JSGlobalPropertyCell* cast(Object* obj); -#ifdef DEBUG - void JSGlobalPropertyCellVerify(); -#endif + static inline JSGlobalPropertyCell* FromValueAddress(Address value) { + return cast(FromAddress(value - kValueOffset)); + } + + inline Address ValueAddress() { + return address() + kValueOffset; + } + + DECLARE_VERIFIER(JSGlobalPropertyCell) + #ifdef OBJECT_PRINT inline void JSGlobalPropertyCellPrint() { JSGlobalPropertyCellPrint(stdout); @@ -7763,23 +8159,28 @@ class JSProxy: public JSReceiver { uint32_t index); MUST_USE_RESULT MaybeObject* SetPropertyWithHandler( + JSReceiver* receiver, String* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode); MUST_USE_RESULT MaybeObject* SetElementWithHandler( + JSReceiver* receiver, uint32_t index, Object* value, StrictModeFlag strict_mode); - // If the handler defines an accessor property, invoke its setter - // (or throw if only a getter exists) and set *found to true. Otherwise false. - MUST_USE_RESULT MaybeObject* SetPropertyWithHandlerIfDefiningSetter( + // If the handler defines an accessor property with a setter, invoke it. + // If it defines an accessor property without a setter, or a data property + // that is read-only, throw. In all these cases set '*done' to true, + // otherwise set it to false. + MUST_USE_RESULT MaybeObject* SetPropertyViaPrototypesWithHandler( + JSReceiver* receiver, String* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, - bool* found); + bool* done); MUST_USE_RESULT MaybeObject* DeletePropertyWithHandler( String* name, @@ -7817,9 +8218,7 @@ class JSProxy: public JSReceiver { } void JSProxyPrint(FILE* out); #endif -#ifdef DEBUG - void JSProxyVerify(); -#endif + DECLARE_VERIFIER(JSProxy) // Layout description. We add padding so that a proxy has the same // size as a virgin JSObject. This is essential for becoming a JSObject @@ -7860,9 +8259,7 @@ class JSFunctionProxy: public JSProxy { } void JSFunctionProxyPrint(FILE* out); #endif -#ifdef DEBUG - void JSFunctionProxyVerify(); -#endif + DECLARE_VERIFIER(JSFunctionProxy) // Layout description. static const int kCallTrapOffset = JSProxy::kPaddingOffset; @@ -7897,9 +8294,7 @@ class JSSet: public JSObject { } void JSSetPrint(FILE* out); #endif -#ifdef DEBUG - void JSSetVerify(); -#endif + DECLARE_VERIFIER(JSSet) static const int kTableOffset = JSObject::kHeaderSize; static const int kSize = kTableOffset + kPointerSize; @@ -7924,9 +8319,7 @@ class JSMap: public JSObject { } void JSMapPrint(FILE* out); #endif -#ifdef DEBUG - void JSMapVerify(); -#endif + DECLARE_VERIFIER(JSMap) static const int kTableOffset = JSObject::kHeaderSize; static const int kSize = kTableOffset + kPointerSize; @@ -7954,9 +8347,7 @@ class JSWeakMap: public JSObject { } void JSWeakMapPrint(FILE* out); #endif -#ifdef DEBUG - void JSWeakMapVerify(); -#endif + DECLARE_VERIFIER(JSWeakMap) static const int kTableOffset = JSObject::kHeaderSize; static const int kNextOffset = kTableOffset + kPointerSize; @@ -7991,9 +8382,7 @@ class Foreign: public HeapObject { } void ForeignPrint(FILE* out); #endif -#ifdef DEBUG - void ForeignVerify(); -#endif + DECLARE_VERIFIER(Foreign) // Layout description. @@ -8050,9 +8439,7 @@ class JSArray: public JSObject { } void JSArrayPrint(FILE* out); #endif -#ifdef DEBUG - void JSArrayVerify(); -#endif + DECLARE_VERIFIER(JSArray) // Number of element slots to pre-allocate for an empty array. static const int kPreallocatedArrayElements = 4; @@ -8106,6 +8493,7 @@ class AccessorInfo: public Struct { DECL_ACCESSORS(data, Object) DECL_ACCESSORS(name, Object) DECL_ACCESSORS(flag, Smi) + DECL_ACCESSORS(expected_receiver_type, Object) inline bool all_can_read(); inline void set_all_can_read(bool value); @@ -8119,6 +8507,9 @@ class AccessorInfo: public Struct { inline PropertyAttributes property_attributes(); inline void set_property_attributes(PropertyAttributes attributes); + // Checks whether the given receiver is compatible with this accessor. + inline bool IsCompatibleReceiver(Object* receiver); + static inline AccessorInfo* cast(Object* obj); #ifdef OBJECT_PRINT @@ -8127,16 +8518,15 @@ class AccessorInfo: public Struct { } void AccessorInfoPrint(FILE* out); #endif -#ifdef DEBUG - void AccessorInfoVerify(); -#endif + DECLARE_VERIFIER(AccessorInfo) static const int kGetterOffset = HeapObject::kHeaderSize; static const int kSetterOffset = kGetterOffset + kPointerSize; static const int kDataOffset = kSetterOffset + kPointerSize; static const int kNameOffset = kDataOffset + kPointerSize; static const int kFlagOffset = kNameOffset + kPointerSize; - static const int kSize = kFlagOffset + kPointerSize; + static const int kExpectedReceiverTypeOffset = kFlagOffset + kPointerSize; + static const int kSize = kExpectedReceiverTypeOffset + kPointerSize; private: // Bit positions in flag. @@ -8162,7 +8552,19 @@ class AccessorPair: public Struct { static inline AccessorPair* cast(Object* obj); - MUST_USE_RESULT MaybeObject* CopyWithoutTransitions(); + MUST_USE_RESULT MaybeObject* Copy(); + + Object* get(AccessorComponent component) { + return component == ACCESSOR_GETTER ? getter() : setter(); + } + + void set(AccessorComponent component, Object* value) { + if (component == ACCESSOR_GETTER) { + set_getter(value); + } else { + set_setter(value); + } + } // Note: Returns undefined instead in case of a hole. Object* GetComponent(AccessorComponent component); @@ -8180,9 +8582,7 @@ class AccessorPair: public Struct { #ifdef OBJECT_PRINT void AccessorPairPrint(FILE* out = stdout); #endif -#ifdef DEBUG - void AccessorPairVerify(); -#endif + DECLARE_VERIFIER(AccessorPair) static const int kGetterOffset = HeapObject::kHeaderSize; static const int kSetterOffset = kGetterOffset + kPointerSize; @@ -8216,9 +8616,7 @@ class AccessCheckInfo: public Struct { } void AccessCheckInfoPrint(FILE* out); #endif -#ifdef DEBUG - void AccessCheckInfoVerify(); -#endif + DECLARE_VERIFIER(AccessCheckInfo) static const int kNamedCallbackOffset = HeapObject::kHeaderSize; static const int kIndexedCallbackOffset = kNamedCallbackOffset + kPointerSize; @@ -8248,9 +8646,7 @@ class InterceptorInfo: public Struct { } void InterceptorInfoPrint(FILE* out); #endif -#ifdef DEBUG - void InterceptorInfoVerify(); -#endif + DECLARE_VERIFIER(InterceptorInfo) static const int kGetterOffset = HeapObject::kHeaderSize; static const int kSetterOffset = kGetterOffset + kPointerSize; @@ -8279,9 +8675,7 @@ class CallHandlerInfo: public Struct { } void CallHandlerInfoPrint(FILE* out); #endif -#ifdef DEBUG - void CallHandlerInfoVerify(); -#endif + DECLARE_VERIFIER(CallHandlerInfo) static const int kCallbackOffset = HeapObject::kHeaderSize; static const int kDataOffset = kCallbackOffset + kPointerSize; @@ -8297,9 +8691,7 @@ class TemplateInfo: public Struct { DECL_ACCESSORS(tag, Object) DECL_ACCESSORS(property_list, Object) -#ifdef DEBUG - void TemplateInfoVerify(); -#endif + DECLARE_VERIFIER(TemplateInfo) static const int kTagOffset = HeapObject::kHeaderSize; static const int kPropertyListOffset = kTagOffset + kPointerSize; @@ -8342,9 +8734,7 @@ class FunctionTemplateInfo: public TemplateInfo { } void FunctionTemplateInfoPrint(FILE* out); #endif -#ifdef DEBUG - void FunctionTemplateInfoVerify(); -#endif + DECLARE_VERIFIER(FunctionTemplateInfo) static const int kSerialNumberOffset = TemplateInfo::kHeaderSize; static const int kCallCodeOffset = kSerialNumberOffset + kPointerSize; @@ -8393,9 +8783,7 @@ class ObjectTemplateInfo: public TemplateInfo { } void ObjectTemplateInfoPrint(FILE* out); #endif -#ifdef DEBUG - void ObjectTemplateInfoVerify(); -#endif + DECLARE_VERIFIER(ObjectTemplateInfo) static const int kConstructorOffset = TemplateInfo::kHeaderSize; static const int kInternalFieldCountOffset = @@ -8419,9 +8807,7 @@ class SignatureInfo: public Struct { } void SignatureInfoPrint(FILE* out); #endif -#ifdef DEBUG - void SignatureInfoVerify(); -#endif + DECLARE_VERIFIER(SignatureInfo) static const int kReceiverOffset = Struct::kHeaderSize; static const int kArgsOffset = kReceiverOffset + kPointerSize; @@ -8444,9 +8830,7 @@ class TypeSwitchInfo: public Struct { } void TypeSwitchInfoPrint(FILE* out); #endif -#ifdef DEBUG - void TypeSwitchInfoVerify(); -#endif + DECLARE_VERIFIER(TypeSwitchInfo) static const int kTypesOffset = Struct::kHeaderSize; static const int kSize = kTypesOffset + kPointerSize; @@ -8496,9 +8880,7 @@ class DebugInfo: public Struct { } void DebugInfoPrint(FILE* out); #endif -#ifdef DEBUG - void DebugInfoVerify(); -#endif + DECLARE_VERIFIER(DebugInfo) static const int kSharedFunctionInfoIndex = Struct::kHeaderSize; static const int kOriginalCodeIndex = kSharedFunctionInfoIndex + kPointerSize; @@ -8554,9 +8936,7 @@ class BreakPointInfo: public Struct { } void BreakPointInfoPrint(FILE* out); #endif -#ifdef DEBUG - void BreakPointInfoVerify(); -#endif + DECLARE_VERIFIER(BreakPointInfo) static const int kCodePositionIndex = Struct::kHeaderSize; static const int kSourcePositionIndex = kCodePositionIndex + kPointerSize; @@ -8574,6 +8954,7 @@ class BreakPointInfo: public Struct { #undef DECL_BOOLEAN_ACCESSORS #undef DECL_ACCESSORS +#undef DECLARE_VERIFIER #define VISITOR_SYNCHRONIZATION_TAGS_LIST(V) \ V(kSymbolTable, "symbol_table", "(Symbols)") \ @@ -8638,14 +9019,16 @@ class ObjectVisitor BASE_EMBEDDED { // Visits a debug call target in the instruction stream. virtual void VisitDebugTarget(RelocInfo* rinfo); + // Visits the byte sequence in a function's prologue that contains information + // about the code's age. + virtual void VisitCodeAgeSequence(RelocInfo* rinfo); + // Handy shorthand for visiting a single pointer. virtual void VisitPointer(Object** p) { VisitPointers(p, p + 1); } // Visit pointer embedded into a code object. virtual void VisitEmbeddedPointer(RelocInfo* rinfo); - virtual void VisitSharedFunctionInfo(SharedFunctionInfo* shared) {} - // Visits a contiguous arrays of external references (references to the C++ // heap) in the half-open range [start, end). Any or all of the values // may be modified on return. |