diff options
Diffstat (limited to 'deps/v8/src/objects.h')
-rw-r--r-- | deps/v8/src/objects.h | 2244 |
1 files changed, 1276 insertions, 968 deletions
diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 755dd42d9e..933a07599a 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -77,7 +77,7 @@ // - DescriptorArray // - HashTable // - Dictionary -// - SymbolTable +// - StringTable // - CompilationCacheTable // - CodeCacheHashTable // - MapCache @@ -95,15 +95,25 @@ // - ExternalIntArray // - ExternalUnsignedIntArray // - ExternalFloatArray -// - String -// - SeqString -// - SeqAsciiString -// - SeqTwoByteString -// - SlicedString -// - ConsString -// - ExternalString -// - ExternalAsciiString -// - ExternalTwoByteString +// - Name +// - String +// - SeqString +// - SeqOneByteString +// - SeqTwoByteString +// - SlicedString +// - ConsString +// - ExternalString +// - ExternalAsciiString +// - ExternalTwoByteString +// - InternalizedString +// - SeqInternalizedString +// - SeqOneByteInternalizedString +// - SeqTwoByteInternalizedString +// - ConsInternalizedString +// - ExternalInternalizedString +// - ExternalAsciiInternalizedString +// - ExternalTwoByteInternalizedString +// - Symbol // - HeapNumber // - Code // - Map @@ -111,7 +121,10 @@ // - Foreign // - SharedFunctionInfo // - Struct +// - DeclaredAccessorDescriptor // - AccessorInfo +// - DeclaredAccessorInfo +// - ExecutableAccessorInfo // - AccessorPair // - AccessCheckInfo // - InterceptorInfo @@ -139,11 +152,75 @@ enum CompareMapMode { ALLOW_ELEMENT_TRANSITION_MAPS }; -enum KeyedAccessGrowMode { - DO_NOT_ALLOW_JSARRAY_GROWTH, - ALLOW_JSARRAY_GROWTH +enum KeyedAccessStoreMode { + STANDARD_STORE, + STORE_TRANSITION_SMI_TO_OBJECT, + STORE_TRANSITION_SMI_TO_DOUBLE, + STORE_TRANSITION_DOUBLE_TO_OBJECT, + STORE_TRANSITION_HOLEY_SMI_TO_OBJECT, + STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE, + STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT, + STORE_AND_GROW_NO_TRANSITION, + STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT, + STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE, + STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT, + STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT, + STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE, + STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT, + STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS, + STORE_NO_TRANSITION_HANDLE_COW }; + +static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION - + STANDARD_STORE; +STATIC_ASSERT(STANDARD_STORE == 0); +STATIC_ASSERT(kGrowICDelta == + STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT - + STORE_TRANSITION_SMI_TO_OBJECT); +STATIC_ASSERT(kGrowICDelta == + STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE - + STORE_TRANSITION_SMI_TO_DOUBLE); +STATIC_ASSERT(kGrowICDelta == + STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT - + STORE_TRANSITION_DOUBLE_TO_OBJECT); + + +static inline KeyedAccessStoreMode GetGrowStoreMode( + KeyedAccessStoreMode store_mode) { + if (store_mode < STORE_AND_GROW_NO_TRANSITION) { + store_mode = static_cast<KeyedAccessStoreMode>( + static_cast<int>(store_mode) + kGrowICDelta); + } + return store_mode; +} + + +static inline bool IsTransitionStoreMode(KeyedAccessStoreMode store_mode) { + return store_mode > STANDARD_STORE && + store_mode <= STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT && + store_mode != STORE_AND_GROW_NO_TRANSITION; +} + + +static inline KeyedAccessStoreMode GetNonTransitioningStoreMode( + KeyedAccessStoreMode store_mode) { + if (store_mode >= STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { + return store_mode; + } + if (store_mode >= STORE_AND_GROW_NO_TRANSITION) { + return STORE_AND_GROW_NO_TRANSITION; + } + return STANDARD_STORE; +} + + +static inline bool IsGrowStoreMode(KeyedAccessStoreMode store_mode) { + return store_mode >= STORE_AND_GROW_NO_TRANSITION && + store_mode <= STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT; +} + + // Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER. enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER }; @@ -178,6 +255,12 @@ enum TransitionFlag { }; +enum DebugExtraICState { + DEBUG_BREAK, + DEBUG_PREPARE_STEP_IN +}; + + // 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. @@ -194,6 +277,18 @@ enum DescriptorFlag { 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; @@ -213,8 +308,8 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; // encoding is mentioned explicitly in the name. Likewise, the default // representation is considered sequential. It is not mentioned in the // name. The other representations (e.g. CONS, EXTERNAL) are explicitly -// mentioned. Finally, the string is either a SYMBOL_TYPE (if it is a -// symbol) or a STRING_TYPE (if it is not a symbol). +// mentioned. Finally, the string is either a STRING_TYPE (if it is a normal +// string) or a INTERNALIZED_STRING_TYPE (if it is a internalized string). // // NOTE: The following things are some that depend on the string types having // instance_types that are less than those of all other types: @@ -225,29 +320,30 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; // JSObject for GC purposes. The first four entries here have typeof // 'object', whereas JS_FUNCTION_TYPE has typeof 'function'. #define INSTANCE_TYPE_LIST_ALL(V) \ - V(SYMBOL_TYPE) \ - V(ASCII_SYMBOL_TYPE) \ - V(CONS_SYMBOL_TYPE) \ - V(CONS_ASCII_SYMBOL_TYPE) \ - V(EXTERNAL_SYMBOL_TYPE) \ - V(EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE) \ - V(EXTERNAL_ASCII_SYMBOL_TYPE) \ - V(SHORT_EXTERNAL_SYMBOL_TYPE) \ - V(SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE) \ - V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE) \ V(STRING_TYPE) \ V(ASCII_STRING_TYPE) \ V(CONS_STRING_TYPE) \ V(CONS_ASCII_STRING_TYPE) \ V(SLICED_STRING_TYPE) \ V(EXTERNAL_STRING_TYPE) \ - V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \ V(EXTERNAL_ASCII_STRING_TYPE) \ + V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \ V(SHORT_EXTERNAL_STRING_TYPE) \ - V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \ V(SHORT_EXTERNAL_ASCII_STRING_TYPE) \ - V(PRIVATE_EXTERNAL_ASCII_STRING_TYPE) \ + V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \ + \ + V(INTERNALIZED_STRING_TYPE) \ + V(ASCII_INTERNALIZED_STRING_TYPE) \ + V(CONS_INTERNALIZED_STRING_TYPE) \ + V(CONS_ASCII_INTERNALIZED_STRING_TYPE) \ + V(EXTERNAL_INTERNALIZED_STRING_TYPE) \ + V(EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE) \ + V(EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE) \ + V(SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE) \ + V(SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE) \ + V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE) \ \ + V(SYMBOL_TYPE) \ V(MAP_TYPE) \ V(CODE_TYPE) \ V(ODDBALL_TYPE) \ @@ -270,7 +366,9 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(EXTERNAL_PIXEL_ARRAY_TYPE) \ V(FILLER_TYPE) \ \ - V(ACCESSOR_INFO_TYPE) \ + V(DECLARED_ACCESSOR_DESCRIPTOR_TYPE) \ + V(DECLARED_ACCESSOR_INFO_TYPE) \ + V(EXECUTABLE_ACCESSOR_INFO_TYPE) \ V(ACCESSOR_PAIR_TYPE) \ V(ACCESS_CHECK_INFO_TYPE) \ V(INTERCEPTOR_INFO_TYPE) \ @@ -279,6 +377,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(OBJECT_TEMPLATE_INFO_TYPE) \ V(SIGNATURE_INFO_TYPE) \ V(TYPE_SWITCH_INFO_TYPE) \ + V(ALLOCATION_SITE_INFO_TYPE) \ V(SCRIPT_TYPE) \ V(CODE_CACHE_TYPE) \ V(POLYMORPHIC_CODE_CACHE_TYPE) \ @@ -323,46 +422,6 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; // Since string types are not consecutive, this macro is used to // iterate over them. #define STRING_TYPE_LIST(V) \ - V(SYMBOL_TYPE, \ - kVariableSizeSentinel, \ - symbol, \ - Symbol) \ - V(ASCII_SYMBOL_TYPE, \ - kVariableSizeSentinel, \ - ascii_symbol, \ - AsciiSymbol) \ - V(CONS_SYMBOL_TYPE, \ - ConsString::kSize, \ - cons_symbol, \ - ConsSymbol) \ - V(CONS_ASCII_SYMBOL_TYPE, \ - ConsString::kSize, \ - cons_ascii_symbol, \ - ConsAsciiSymbol) \ - V(EXTERNAL_SYMBOL_TYPE, \ - ExternalTwoByteString::kSize, \ - external_symbol, \ - ExternalSymbol) \ - V(EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE, \ - ExternalTwoByteString::kSize, \ - external_symbol_with_ascii_data, \ - ExternalSymbolWithAsciiData) \ - V(EXTERNAL_ASCII_SYMBOL_TYPE, \ - ExternalAsciiString::kSize, \ - external_ascii_symbol, \ - ExternalAsciiSymbol) \ - V(SHORT_EXTERNAL_SYMBOL_TYPE, \ - ExternalTwoByteString::kShortSize, \ - short_external_symbol, \ - ShortExternalSymbol) \ - V(SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE, \ - ExternalTwoByteString::kShortSize, \ - short_external_symbol_with_ascii_data, \ - ShortExternalSymbolWithAsciiData) \ - V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE, \ - ExternalAsciiString::kShortSize, \ - short_external_ascii_symbol, \ - ShortExternalAsciiSymbol) \ V(STRING_TYPE, \ kVariableSizeSentinel, \ string, \ @@ -391,26 +450,67 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; ExternalTwoByteString::kSize, \ external_string, \ ExternalString) \ - V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \ - ExternalTwoByteString::kSize, \ - external_string_with_ascii_data, \ - ExternalStringWithAsciiData) \ V(EXTERNAL_ASCII_STRING_TYPE, \ ExternalAsciiString::kSize, \ external_ascii_string, \ ExternalAsciiString) \ + V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \ + ExternalTwoByteString::kSize, \ + external_string_with_ascii_data, \ + ExternalStringWithAsciiData) \ V(SHORT_EXTERNAL_STRING_TYPE, \ ExternalTwoByteString::kShortSize, \ short_external_string, \ ShortExternalString) \ + V(SHORT_EXTERNAL_ASCII_STRING_TYPE, \ + ExternalAsciiString::kShortSize, \ + short_external_ascii_string, \ + ShortExternalAsciiString) \ V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \ ExternalTwoByteString::kShortSize, \ short_external_string_with_ascii_data, \ ShortExternalStringWithAsciiData) \ - V(SHORT_EXTERNAL_ASCII_STRING_TYPE, \ + \ + V(INTERNALIZED_STRING_TYPE, \ + kVariableSizeSentinel, \ + internalized_string, \ + InternalizedString) \ + V(ASCII_INTERNALIZED_STRING_TYPE, \ + kVariableSizeSentinel, \ + ascii_internalized_string, \ + AsciiInternalizedString) \ + V(CONS_INTERNALIZED_STRING_TYPE, \ + ConsString::kSize, \ + cons_internalized_string, \ + ConsInternalizedString) \ + V(CONS_ASCII_INTERNALIZED_STRING_TYPE, \ + ConsString::kSize, \ + cons_ascii_internalized_string, \ + ConsAsciiInternalizedString) \ + V(EXTERNAL_INTERNALIZED_STRING_TYPE, \ + ExternalTwoByteString::kSize, \ + external_internalized_string, \ + ExternalInternalizedString) \ + V(EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE, \ + ExternalAsciiString::kSize, \ + external_ascii_internalized_string, \ + ExternalAsciiInternalizedString) \ + V(EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE, \ + ExternalTwoByteString::kSize, \ + external_internalized_string_with_ascii_data, \ + ExternalInternalizedStringWithAsciiData) \ + V(SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE, \ + ExternalTwoByteString::kShortSize, \ + short_external_internalized_string, \ + ShortExternalInternalizedString) \ + V(SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE, \ ExternalAsciiString::kShortSize, \ - short_external_ascii_string, \ - ShortExternalAsciiString) + short_external_ascii_internalized_string, \ + ShortExternalAsciiInternalizedString) \ + V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE, \ + ExternalTwoByteString::kShortSize, \ + short_external_internalized_string_with_ascii_data, \ + ShortExternalInternalizedStringWithAsciiData) \ // A struct is a simple object a set of object-valued fields. Including an // object type in this causes the compiler to generate most of the boilerplate @@ -422,7 +522,11 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; // type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST // manually. #define STRUCT_LIST_ALL(V) \ - V(ACCESSOR_INFO, AccessorInfo, accessor_info) \ + V(DECLARED_ACCESSOR_DESCRIPTOR, \ + DeclaredAccessorDescriptor, \ + declared_accessor_descriptor) \ + V(DECLARED_ACCESSOR_INFO, DeclaredAccessorInfo, declared_accessor_info) \ + V(EXECUTABLE_ACCESSOR_INFO, ExecutableAccessorInfo, executable_accessor_info)\ V(ACCESSOR_PAIR, AccessorPair, accessor_pair) \ V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info) \ V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info) \ @@ -432,6 +536,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(SIGNATURE_INFO, SignatureInfo, signature_info) \ V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \ V(SCRIPT, Script, script) \ + V(ALLOCATION_SITE_INFO, AllocationSiteInfo, allocation_site_info) \ V(CODE_CACHE, CodeCache, code_cache) \ V(POLYMORPHIC_CODE_CACHE, PolymorphicCodeCache, polymorphic_code_cache) \ V(TYPE_FEEDBACK_INFO, TypeFeedbackInfo, type_feedback_info) \ @@ -456,18 +561,18 @@ const uint32_t kIsNotStringMask = 0x80; const uint32_t kStringTag = 0x0; const uint32_t kNotStringTag = 0x80; -// Bit 6 indicates that the object is a symbol (if set) or not (if cleared). +// Bit 6 indicates that the object is an internalized string (if set) or not. // There are not enough types that the non-string types (with bit 7 set) can // have bit 6 set too. -const uint32_t kIsSymbolMask = 0x40; -const uint32_t kNotSymbolTag = 0x0; -const uint32_t kSymbolTag = 0x40; +const uint32_t kIsInternalizedMask = 0x40; +const uint32_t kNotInternalizedTag = 0x0; +const uint32_t kInternalizedTag = 0x40; // If bit 7 is clear then bit 2 indicates whether the string consists of // 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. @@ -504,57 +609,57 @@ const uint32_t kShortExternalStringTag = 0x10; // A ConsString with an empty string as the right side is a candidate -// for being shortcut by the garbage collector unless it is a -// symbol. It's not common to have non-flat symbols, so we do not -// shortcut them thereby avoiding turning symbols into strings. See -// heap.cc and mark-compact.cc. +// for being shortcut by the garbage collector unless it is internalized. +// It's not common to have non-flat internalized strings, so we do not +// shortcut them thereby avoiding turning internalized strings into strings. +// See heap.cc and mark-compact.cc. const uint32_t kShortcutTypeMask = kIsNotStringMask | - kIsSymbolMask | + kIsInternalizedMask | kStringRepresentationMask; const uint32_t kShortcutTypeTag = kConsStringTag; enum InstanceType { // String types. - SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kSeqStringTag, - ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag, - CONS_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kConsStringTag, - CONS_ASCII_SYMBOL_TYPE = kAsciiStringTag | 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 | - 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, 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, - 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, + SLICED_ASCII_STRING_TYPE = kOneByteStringTag | kSlicedStringTag, EXTERNAL_STRING_TYPE = kTwoByteStringTag | kExternalStringTag, + EXTERNAL_ASCII_STRING_TYPE = kOneByteStringTag | kExternalStringTag, EXTERNAL_STRING_WITH_ASCII_DATA_TYPE = - kTwoByteStringTag | kExternalStringTag | kAsciiDataHintTag, - // LAST_STRING_TYPE - EXTERNAL_ASCII_STRING_TYPE = kAsciiStringTag | kExternalStringTag, - PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE, + EXTERNAL_STRING_TYPE | kAsciiDataHintTag, + SHORT_EXTERNAL_STRING_TYPE = EXTERNAL_STRING_TYPE | kShortExternalStringTag, + SHORT_EXTERNAL_ASCII_STRING_TYPE = + EXTERNAL_ASCII_STRING_TYPE | kShortExternalStringTag, + SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE = + EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kShortExternalStringTag, + + INTERNALIZED_STRING_TYPE = STRING_TYPE | kInternalizedTag, + ASCII_INTERNALIZED_STRING_TYPE = ASCII_STRING_TYPE | kInternalizedTag, + CONS_INTERNALIZED_STRING_TYPE = CONS_STRING_TYPE | kInternalizedTag, + CONS_ASCII_INTERNALIZED_STRING_TYPE = + CONS_ASCII_STRING_TYPE | kInternalizedTag, + EXTERNAL_INTERNALIZED_STRING_TYPE = EXTERNAL_STRING_TYPE | kInternalizedTag, + EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE = + EXTERNAL_ASCII_STRING_TYPE | kInternalizedTag, + EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE = + EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kInternalizedTag, + SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE = + SHORT_EXTERNAL_STRING_TYPE | kInternalizedTag, + SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE = + SHORT_EXTERNAL_ASCII_STRING_TYPE | kInternalizedTag, + SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE = + SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kInternalizedTag, + + // Non-string names + SYMBOL_TYPE = kNotStringTag, // LAST_NAME_TYPE, FIRST_NONSTRING_TYPE // Objects allocated in their own spaces (never in new space). - MAP_TYPE = kNotStringTag, // FIRST_NONSTRING_TYPE + MAP_TYPE, CODE_TYPE, ODDBALL_TYPE, JS_GLOBAL_PROPERTY_CELL_TYPE, @@ -578,7 +683,9 @@ enum InstanceType { FILLER_TYPE, // LAST_DATA_TYPE // Structs. - ACCESSOR_INFO_TYPE, + DECLARED_ACCESSOR_DESCRIPTOR_TYPE, + DECLARED_ACCESSOR_INFO_TYPE, + EXECUTABLE_ACCESSOR_INFO_TYPE, ACCESSOR_PAIR_TYPE, ACCESS_CHECK_INFO_TYPE, INTERCEPTOR_INFO_TYPE, @@ -587,6 +694,7 @@ enum InstanceType { OBJECT_TEMPLATE_INFO_TYPE, SIGNATURE_INFO_TYPE, TYPE_SWITCH_INFO_TYPE, + ALLOCATION_SITE_INFO_TYPE, SCRIPT_TYPE, CODE_CACHE_TYPE, POLYMORPHIC_CODE_CACHE_TYPE, @@ -633,7 +741,11 @@ enum InstanceType { FIRST_TYPE = 0x0, LAST_TYPE = JS_FUNCTION_TYPE, INVALID_TYPE = FIRST_TYPE - 1, - FIRST_NONSTRING_TYPE = MAP_TYPE, + FIRST_NAME_TYPE = FIRST_TYPE, + LAST_NAME_TYPE = SYMBOL_TYPE, + FIRST_UNIQUE_NAME_TYPE = INTERNALIZED_STRING_TYPE, + LAST_UNIQUE_NAME_TYPE = SYMBOL_TYPE, + FIRST_NONSTRING_TYPE = SYMBOL_TYPE, // Boundaries for testing for an external array. FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_BYTE_ARRAY_TYPE, LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_PIXEL_ARRAY_TYPE, @@ -679,7 +791,7 @@ STATIC_CHECK(FOREIGN_TYPE == Internals::kForeignType); V(DICTIONARY_PROPERTIES_SUB_TYPE) \ V(MAP_CODE_CACHE_SUB_TYPE) \ V(SCOPE_INFO_SUB_TYPE) \ - V(SYMBOL_TABLE_SUB_TYPE) \ + V(STRING_TABLE_SUB_TYPE) \ V(DESCRIPTOR_ARRAY_SUB_TYPE) \ V(TRANSITION_ARRAY_SUB_TYPE) @@ -737,6 +849,12 @@ template <class C> static inline bool Is(Object* obj); #define DECLARE_VERIFIER(Name) #endif +#ifdef OBJECT_PRINT +#define DECLARE_PRINTER(Name) void Name##Print(FILE* out = stdout); +#else +#define DECLARE_PRINTER(Name) +#endif + class MaybeObject BASE_EMBEDDED { public: inline bool IsFailure(); @@ -754,7 +872,9 @@ class MaybeObject BASE_EMBEDDED { return reinterpret_cast<Failure*>(this); } inline Object* ToObjectUnchecked() { - ASSERT(!IsFailure()); + // TODO(jkummerow): Turn this back into an ASSERT when we can be certain + // that it never fires in Release mode in the wild. + CHECK(!IsFailure()); return reinterpret_cast<Object*>(this); } inline Object* ToObjectChecked() { @@ -769,6 +889,13 @@ class MaybeObject BASE_EMBEDDED { return true; } + template<typename T> + inline bool ToHandle(Handle<T>* obj, Isolate* isolate) { + if (IsFailure()) return false; + *obj = handle(T::cast(reinterpret_cast<Object*>(this)), isolate); + return true; + } + #ifdef OBJECT_PRINT // Prints this object with details. inline void Print() { @@ -794,8 +921,9 @@ class MaybeObject BASE_EMBEDDED { #define HEAP_OBJECT_TYPE_LIST(V) \ V(HeapNumber) \ + V(Name) \ + V(UniqueName) \ V(String) \ - V(Symbol) \ V(SeqString) \ V(ExternalString) \ V(ConsString) \ @@ -803,7 +931,9 @@ class MaybeObject BASE_EMBEDDED { V(ExternalTwoByteString) \ V(ExternalAsciiString) \ V(SeqTwoByteString) \ - V(SeqAsciiString) \ + V(SeqOneByteString) \ + V(InternalizedString) \ + V(Symbol) \ \ V(ExternalArray) \ V(ExternalByteArray) \ @@ -826,6 +956,7 @@ class MaybeObject BASE_EMBEDDED { V(TransitionArray) \ V(DeoptimizationInputData) \ V(DeoptimizationOutputData) \ + V(DependentCode) \ V(TypeFeedbackCells) \ V(FixedArray) \ V(FixedDoubleArray) \ @@ -851,7 +982,7 @@ class MaybeObject BASE_EMBEDDED { V(JSRegExp) \ V(HashTable) \ V(Dictionary) \ - V(SymbolTable) \ + V(StringTable) \ V(JSFunctionResultCache) \ V(NormalizedMapCache) \ V(CompilationCacheTable) \ @@ -866,10 +997,9 @@ class MaybeObject BASE_EMBEDDED { V(UndetectableObject) \ V(AccessCheckNeeded) \ V(JSGlobalPropertyCell) \ + V(ObjectHashTable) \ -class JSReceiver; - // Object is the abstract superclass for all classes in the // object hierarchy. // Object does not use any virtual functions to avoid the @@ -887,6 +1017,8 @@ class Object : public MaybeObject { #undef IS_TYPE_FUNCTION_DECL inline bool IsFixedArrayBase(); + inline bool IsExternal(); + inline bool IsAccessorInfo(); // Returns true if this object is an instance of the specified // function template. @@ -923,7 +1055,7 @@ class Object : public MaybeObject { inline bool HasSpecificClassOf(String* name); MUST_USE_RESULT MaybeObject* ToObject(); // ECMA-262 9.9. - Object* ToBoolean(); // ECMA-262 9.2. + bool BooleanValue(); // ECMA-262 9.2. // Convert to a JSObject if needed. // native_context is used when creating wrapper object. @@ -933,27 +1065,28 @@ class Object : public MaybeObject { // Failure is returned otherwise. MUST_USE_RESULT inline MaybeObject* ToSmi(); - void Lookup(String* name, LookupResult* result); + void Lookup(Name* name, LookupResult* result); // Property access. - MUST_USE_RESULT inline MaybeObject* GetProperty(String* key); + MUST_USE_RESULT inline MaybeObject* GetProperty(Name* key); MUST_USE_RESULT inline MaybeObject* GetProperty( - String* key, + Name* key, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetPropertyWithReceiver( Object* receiver, - String* key, + Name* key, PropertyAttributes* attributes); + static Handle<Object> GetProperty(Handle<Object> object, Handle<Name> key); static Handle<Object> GetProperty(Handle<Object> object, Handle<Object> receiver, LookupResult* result, - Handle<String> key, + Handle<Name> key, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetProperty(Object* receiver, LookupResult* result, - String* key, + Name* key, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetPropertyWithDefinedGetter(Object* receiver, @@ -967,7 +1100,10 @@ class Object : public MaybeObject { uint32_t index); // Return the object's prototype (might be Heap::null_value()). - Object* GetPrototype(); + Object* GetPrototype(Isolate* isolate); + + // Return the prototype, or the method holder for a value-like object. + Object* GetDelegate(Isolate* isolate); // Returns the permanent hash code associated with this object depending on // the actual object type. Might return a failure in case no hash was @@ -1104,7 +1240,9 @@ class Failure: public MaybeObject { static inline Failure* RetryAfterGC(); // NEW_SPACE static inline Failure* Exception(); static inline Failure* InternalError(); - static inline Failure* OutOfMemoryException(); + // TODO(jkummerow): The value is temporary instrumentation. Remove it + // when it has served its purpose. + static inline Failure* OutOfMemoryException(intptr_t value); // Casting. static inline Failure* cast(MaybeObject* object); @@ -1327,7 +1465,8 @@ class HeapNumber: public HeapObject { static inline HeapNumber* cast(Object* obj); // Dispatched behavior. - Object* HeapNumberToBoolean(); + bool HeapNumberBooleanValue(); + inline void HeapNumberPrint() { HeapNumberPrint(stdout); } @@ -1415,20 +1554,20 @@ class JSReceiver: public HeapObject { static inline JSReceiver* cast(Object* obj); static Handle<Object> SetProperty(Handle<JSReceiver> object, - Handle<String> key, + Handle<Name> key, Handle<Object> value, PropertyAttributes attributes, StrictModeFlag strict_mode); // Can cause GC. MUST_USE_RESULT MaybeObject* SetProperty( - String* key, + Name* key, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, StoreFromKeyed store_from_keyed = MAY_BE_STORE_FROM_KEYED); MUST_USE_RESULT MaybeObject* SetProperty( LookupResult* result, - String* key, + Name* key, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, @@ -1436,7 +1575,7 @@ class JSReceiver: public HeapObject { MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSReceiver* setter, Object* value); - MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode); + MUST_USE_RESULT MaybeObject* DeleteProperty(Name* name, DeleteMode mode); MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode); // Set the index'th array element. @@ -1457,15 +1596,19 @@ class JSReceiver: public HeapObject { // function that was used to instantiate the object). String* constructor_name(); - inline PropertyAttributes GetPropertyAttribute(String* name); + inline PropertyAttributes GetPropertyAttribute(Name* name); PropertyAttributes GetPropertyAttributeWithReceiver(JSReceiver* receiver, - String* name); - PropertyAttributes GetLocalPropertyAttribute(String* name); + Name* name); + PropertyAttributes GetLocalPropertyAttribute(Name* 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 HasProperty(Name* name); + inline bool HasLocalProperty(Name* 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(); @@ -1483,17 +1626,18 @@ class JSReceiver: public HeapObject { // Lookup a property. If found, the result is valid and has // detailed information. - void LocalLookup(String* name, LookupResult* result); - void Lookup(String* name, LookupResult* result); + void LocalLookup(Name* name, LookupResult* result, + bool search_hidden_prototypes = false); + void Lookup(Name* name, LookupResult* result); protected: Smi* GenerateIdentityHash(); private: - PropertyAttributes GetPropertyAttribute(JSReceiver* receiver, - LookupResult* result, - String* name, - bool continue_search); + PropertyAttributes GetPropertyAttributeForResult(JSReceiver* receiver, + LookupResult* result, + Name* name, + bool continue_search); DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver); }; @@ -1510,7 +1654,7 @@ class JSObject: public JSReceiver { DECL_ACCESSORS(properties, FixedArray) // Get and set fast properties. inline void initialize_properties(); inline bool HasFastProperties(); - inline StringDictionary* property_dictionary(); // Gets slow properties. + inline NameDictionary* property_dictionary(); // Gets slow properties. // [elements]: The elements (properties with names that are integers). // @@ -1542,6 +1686,8 @@ class JSObject: public JSReceiver { // Returns true if an object has elements of FAST_ELEMENTS or // FAST_SMI_ONLY_ELEMENTS. inline bool HasFastSmiOrObjectElements(); + // Returns true if an object has any of the fast elements kinds. + inline bool HasFastElements(); // Returns true if an object has elements of FAST_DOUBLE_ELEMENTS // ElementsKind. inline bool HasFastDoubleElements(); @@ -1582,34 +1728,34 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* GetPropertyWithCallback(Object* receiver, Object* structure, - String* name); + Name* name); // Can cause GC. MUST_USE_RESULT MaybeObject* SetPropertyForResult(LookupResult* result, - String* key, + Name* key, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, StoreFromKeyed store_mode); MUST_USE_RESULT MaybeObject* SetPropertyWithFailedAccessCheck( LookupResult* result, - String* name, + Name* name, Object* value, bool check_prototype, StrictModeFlag strict_mode); MUST_USE_RESULT MaybeObject* SetPropertyWithCallback( Object* structure, - String* name, + Name* name, Object* value, JSObject* holder, StrictModeFlag strict_mode); MUST_USE_RESULT MaybeObject* SetPropertyWithInterceptor( - String* name, + Name* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode); MUST_USE_RESULT MaybeObject* SetPropertyPostInterceptor( - String* name, + Name* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, @@ -1617,14 +1763,14 @@ class JSObject: public JSReceiver { static Handle<Object> SetLocalPropertyIgnoreAttributes( Handle<JSObject> object, - Handle<String> key, + Handle<Name> key, 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); + Handle<Name> key); inline int LastAddedFieldIndex(); @@ -1635,7 +1781,7 @@ class JSObject: public JSReceiver { // Can cause GC. MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes( - String* key, + Name* key, Object* value, PropertyAttributes attributes); @@ -1650,16 +1796,16 @@ class JSObject: public JSReceiver { // Sets the property value in a normalized object given (key, value, details). // Handles the special representation of JS global objects. static Handle<Object> SetNormalizedProperty(Handle<JSObject> object, - Handle<String> key, + Handle<Name> key, Handle<Object> value, PropertyDetails details); - MUST_USE_RESULT MaybeObject* SetNormalizedProperty(String* name, + MUST_USE_RESULT MaybeObject* SetNormalizedProperty(Name* name, Object* value, PropertyDetails details); // Deletes the named property in a normalized object. - MUST_USE_RESULT MaybeObject* DeleteNormalizedProperty(String* name, + MUST_USE_RESULT MaybeObject* DeleteNormalizedProperty(Name* name, DeleteMode mode); MUST_USE_RESULT MaybeObject* OptimizeAsPrototype(); @@ -1670,23 +1816,27 @@ class JSObject: public JSReceiver { // Used from JSReceiver. PropertyAttributes GetPropertyAttributePostInterceptor(JSObject* receiver, - String* name, + Name* name, bool continue_search); PropertyAttributes GetPropertyAttributeWithInterceptor(JSObject* receiver, - String* name, + Name* name, bool continue_search); PropertyAttributes GetPropertyAttributeWithFailedAccessCheck( Object* receiver, LookupResult* result, - String* name, + Name* name, bool continue_search); + PropertyAttributes GetElementAttributeWithReceiver(JSReceiver* receiver, + uint32_t index, + bool continue_search); static void DefineAccessor(Handle<JSObject> object, - Handle<String> name, + Handle<Name> name, Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes); - MUST_USE_RESULT MaybeObject* DefineAccessor(String* name, + // Can cause GC. + MUST_USE_RESULT MaybeObject* DefineAccessor(Name* name, Object* getter, Object* setter, PropertyAttributes attributes); @@ -1694,11 +1844,11 @@ class JSObject: public JSReceiver { // 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, + Name* name, AccessorComponent component, Object* accessor, PropertyAttributes attributes); - Object* LookupAccessor(String* name, AccessorComponent component); + Object* LookupAccessor(Name* name, AccessorComponent component); MUST_USE_RESULT MaybeObject* DefineAccessor(AccessorInfo* info); @@ -1706,19 +1856,19 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* GetPropertyWithFailedAccessCheck( Object* receiver, LookupResult* result, - String* name, + Name* name, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetPropertyWithInterceptor( Object* receiver, - String* name, + Name* name, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetPropertyPostInterceptor( Object* receiver, - String* name, + Name* name, PropertyAttributes* attributes); MUST_USE_RESULT MaybeObject* GetLocalPropertyPostInterceptor( Object* receiver, - String* name, + Name* name, PropertyAttributes* attributes); // Returns true if this is an instance of an api function and has @@ -1733,7 +1883,7 @@ class JSObject: public JSReceiver { // // Hidden properties are not local properties of the object itself. // Instead they are stored in an auxiliary structure kept as a local - // property with a special name Heap::hidden_symbol(). But if the + // property with a special name Heap::hidden_string(). But if the // receiver is a JSGlobalProxy then the auxiliary object is a property // of its prototype, and if it's a detached proxy, then you can't have // hidden properties. @@ -1741,18 +1891,18 @@ class JSObject: public JSReceiver { // Sets a hidden property on this object. Returns this object if successful, // undefined if called on a detached proxy. static Handle<Object> SetHiddenProperty(Handle<JSObject> obj, - Handle<String> key, + Handle<Name> key, Handle<Object> value); // Returns a failure if a GC is required. - MUST_USE_RESULT MaybeObject* SetHiddenProperty(String* key, Object* value); + MUST_USE_RESULT MaybeObject* SetHiddenProperty(Name* key, Object* value); // Gets the value of a hidden property with the given key. Returns undefined // if the property doesn't exist (or if called on a detached proxy), // otherwise returns the value set for the key. - Object* GetHiddenProperty(String* key); + Object* GetHiddenProperty(Name* key); // Deletes a hidden property. Deleting a non-existing property is // considered successful. - void DeleteHiddenProperty(String* key); - // Returns true if the object has a property with the hidden symbol as name. + void DeleteHiddenProperty(Name* key); + // Returns true if the object has a property with the hidden string as name. bool HasHiddenProperties(); static int GetIdentityHash(Handle<JSObject> obj); @@ -1760,8 +1910,9 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* SetIdentityHash(Smi* hash, CreationFlag flag); static Handle<Object> DeleteProperty(Handle<JSObject> obj, - Handle<String> name); - MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode); + Handle<Name> name); + // Can cause GC. + MUST_USE_RESULT MaybeObject* DeleteProperty(Name* name, DeleteMode mode); static Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index); MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode); @@ -1799,36 +1950,18 @@ 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 return old_capacity + (old_capacity >> 1) + 16; } - // Tells whether the index'th element is present and how it is stored. - enum LocalElementType { - // There is no element with given index. - UNDEFINED_ELEMENT, - - // Element with given index is handled by interceptor. - INTERCEPTED_ELEMENT, - - // Element with given index is character in string. - STRING_CHARACTER_ELEMENT, - - // Element with given index is stored in fast backing store. - FAST_ELEMENT, + PropertyType GetLocalPropertyType(Name* name); + PropertyType GetLocalElementType(uint32_t index); - // Element with given index is stored in slow backing store. - DICTIONARY_ELEMENT - }; - - LocalElementType HasLocalElement(uint32_t index); - - bool HasElementWithInterceptor(JSReceiver* receiver, uint32_t index); + // These methods do not perform access checks! + AccessorPair* GetLocalPropertyAccessorPair(Name* name); + AccessorPair* GetLocalElementAccessorPair(uint32_t index); MUST_USE_RESULT MaybeObject* SetFastElement(uint32_t index, Object* value, @@ -1855,7 +1988,7 @@ class JSObject: public JSReceiver { StrictModeFlag strict_mode); // Empty handle is returned if the element cannot be set to the given value. - static MUST_USE_RESULT Handle<Object> SetElement( + static Handle<Object> SetElement( Handle<JSObject> object, uint32_t index, Handle<Object> value, @@ -1900,9 +2033,9 @@ class JSObject: public JSReceiver { inline bool HasIndexedInterceptor(); // Support functions for v8 api (needed for correct interceptor behavior). - bool HasRealNamedProperty(String* key); + bool HasRealNamedProperty(Name* key); bool HasRealElementProperty(uint32_t index); - bool HasRealNamedCallbackProperty(String* key); + bool HasRealNamedCallbackProperty(Name* key); // Get the header size for a JSObject. Used to compute the index of // internal fields as well as the number of internal fields. @@ -1915,12 +2048,12 @@ class JSObject: public JSReceiver { inline void SetInternalField(int index, Smi* value); // The following lookup functions skip interceptors. - void LocalLookupRealNamedProperty(String* name, LookupResult* result); - void LookupRealNamedProperty(String* name, LookupResult* result); - void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result); + void LocalLookupRealNamedProperty(Name* name, LookupResult* result); + void LookupRealNamedProperty(Name* name, LookupResult* result); + void LookupRealNamedPropertyInPrototypes(Name* name, LookupResult* result); MUST_USE_RESULT MaybeObject* SetElementWithCallbackSetterInPrototypes( uint32_t index, Object* value, bool* found, StrictModeFlag strict_mode); - void LookupCallbackProperty(String* name, LookupResult* result); + void LookupCallbackProperty(Name* name, LookupResult* result); // Returns the number of properties on this object filtering out properties // with the specified attributes (ignoring interceptors). @@ -1947,7 +2080,7 @@ class JSObject: public JSReceiver { // Add a property to a fast-case object using a map transition to // new_map. MUST_USE_RESULT MaybeObject* AddFastPropertyUsingMap(Map* new_map, - String* name, + Name* name, Object* value, int field_index); @@ -1958,12 +2091,12 @@ class JSObject: public JSReceiver { // This avoids the creation of many maps with the same constant // function, all orphaned. MUST_USE_RESULT MaybeObject* AddConstantFunctionProperty( - String* name, + Name* name, JSFunction* function, PropertyAttributes attributes); MUST_USE_RESULT MaybeObject* ReplaceSlowProperty( - String* name, + Name* name, Object* value, PropertyAttributes attributes); @@ -1981,36 +2114,38 @@ class JSObject: public JSReceiver { ElementsKind to_kind); MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind); + MUST_USE_RESULT MaybeObject* UpdateAllocationSiteInfo( + ElementsKind to_kind); // Replaces an existing transition with a transition to a map with a FIELD. MUST_USE_RESULT MaybeObject* ConvertTransitionToMapTransition( int transition_index, - String* name, + Name* name, Object* new_value, PropertyAttributes attributes); // Converts a descriptor of any other type to a real field, backed by the // properties array. MUST_USE_RESULT MaybeObject* ConvertDescriptorToField( - String* name, + Name* name, Object* new_value, PropertyAttributes attributes); // Add a property to a fast-case object. MUST_USE_RESULT MaybeObject* AddFastProperty( - String* name, + Name* 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, + MUST_USE_RESULT MaybeObject* AddSlowProperty(Name* name, Object* value, PropertyAttributes attributes); - // Add a property to an object. + // Add a property to an object. May cause GC. MUST_USE_RESULT MaybeObject* AddProperty( - String* name, + Name* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, @@ -2037,10 +2172,10 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* NormalizeElements(); static void UpdateMapCodeCache(Handle<JSObject> object, - Handle<String> name, + Handle<Name> name, Handle<Code> code); - MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(String* name, Code* code); + MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(Name* name, Code* code); // Transform slow named properties to fast variants. // Returns failure if allocation failed. @@ -2084,12 +2219,7 @@ class JSObject: public JSReceiver { // Dispatched behavior. void JSObjectShortPrint(StringStream* accumulator); -#ifdef OBJECT_PRINT - inline void JSObjectPrint() { - JSObjectPrint(stdout); - } - void JSObjectPrint(FILE* out); -#endif + DECLARE_PRINTER(JSObject) DECLARE_VERIFIER(JSObject) #ifdef OBJECT_PRINT inline void PrintProperties() { @@ -2179,6 +2309,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<Name> name, + Handle<Object> old_value); + + // Deliver change records to observers. May cause GC. + static void DeliverChangeRecords(Isolate* isolate); + private: friend class DictionaryElementsAccessor; @@ -2186,6 +2325,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, @@ -2212,15 +2359,15 @@ class JSObject: public JSReceiver { // 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, + Name* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, bool* done); - MUST_USE_RESULT MaybeObject* DeletePropertyPostInterceptor(String* name, + MUST_USE_RESULT MaybeObject* DeletePropertyPostInterceptor(Name* name, DeleteMode mode); - MUST_USE_RESULT MaybeObject* DeletePropertyWithInterceptor(String* name); + MUST_USE_RESULT MaybeObject* DeletePropertyWithInterceptor(Name* name); MUST_USE_RESULT MaybeObject* DeleteElementWithInterceptor(uint32_t index); @@ -2238,13 +2385,13 @@ class JSObject: public JSReceiver { // Gets the current elements capacity and the number of used elements. void GetElementsCapacityAndUsage(int* capacity, int* used); - bool CanSetCallback(String* name); + bool CanSetCallback(Name* name); MUST_USE_RESULT MaybeObject* SetElementCallback( uint32_t index, Object* structure, PropertyAttributes attributes); MUST_USE_RESULT MaybeObject* SetPropertyCallback( - String* name, + Name* name, Object* structure, PropertyAttributes attributes); MUST_USE_RESULT MaybeObject* DefineElementAccessor( @@ -2252,9 +2399,9 @@ class JSObject: public JSReceiver { Object* getter, Object* setter, PropertyAttributes attributes); - MUST_USE_RESULT MaybeObject* CreateAccessorPairFor(String* name); + MUST_USE_RESULT MaybeObject* CreateAccessorPairFor(Name* name); MUST_USE_RESULT MaybeObject* DefinePropertyAccessor( - String* name, + Name* name, Object* getter, Object* setter, PropertyAttributes attributes); @@ -2330,12 +2477,12 @@ class FixedArray: public FixedArrayBase { inline void set_unchecked(Heap* heap, int index, Object* value, WriteBarrierMode mode); - // Gives access to raw memory which stores the array's data. - inline Object** data_start(); - inline Object** GetFirstElementAddress(); inline bool ContainsOnlySmisOrHoles(); + // Gives access to raw memory which stores the array's data. + inline Object** data_start(); + // Copy operations. MUST_USE_RESULT inline MaybeObject* Copy(); MUST_USE_RESULT MaybeObject* CopySize(int new_length); @@ -2366,12 +2513,7 @@ class FixedArray: public FixedArrayBase { static const int kMaxLength = (kMaxSize - kHeaderSize) / kPointerSize; // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void FixedArrayPrint() { - FixedArrayPrint(stdout); - } - void FixedArrayPrint(FILE* out); -#endif + DECLARE_PRINTER(FixedArray) DECLARE_VERIFIER(FixedArray) #ifdef DEBUG // Checks if two FixedArrays have identical contents. @@ -2410,6 +2552,8 @@ class FixedArray: public FixedArrayBase { Object* value); private: + STATIC_CHECK(kHeaderSize == Internals::kFixedArrayHeaderSize); + DISALLOW_IMPLICIT_CONSTRUCTORS(FixedArray); }; @@ -2435,6 +2579,9 @@ class FixedDoubleArray: public FixedArrayBase { return kHeaderSize + length * kDoubleSize; } + // Gives access to raw memory which stores the array's data. + inline double* data_start(); + // Code Generation support. static int OffsetOfElementAt(int index) { return SizeFor(index); } @@ -2453,12 +2600,7 @@ class FixedDoubleArray: public FixedArrayBase { static const int kMaxLength = (kMaxSize - kHeaderSize) / kDoubleSize; // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void FixedDoubleArrayPrint() { - FixedDoubleArrayPrint(stdout); - } - void FixedDoubleArrayPrint(FILE* out); -#endif + DECLARE_PRINTER(FixedDoubleArray) DECLARE_VERIFIER(FixedDoubleArray) private: @@ -2560,10 +2702,12 @@ class DescriptorArray: public FixedArray { Object* new_index_cache); // Accessors for fetching instance descriptor at descriptor number. - inline String* GetKey(int descriptor_number); + inline Name* GetKey(int descriptor_number); inline Object** GetKeySlot(int descriptor_number); inline Object* GetValue(int descriptor_number); inline Object** GetValueSlot(int descriptor_number); + inline Object** GetDescriptorStartSlot(int descriptor_number); + inline Object** GetDescriptorEndSlot(int descriptor_number); inline PropertyDetails GetDetails(int descriptor_number); inline PropertyType GetType(int descriptor_number); inline int GetFieldIndex(int descriptor_number); @@ -2571,7 +2715,7 @@ class DescriptorArray: public FixedArray { inline Object* GetCallbacksObject(int descriptor_number); inline AccessorDescriptor* GetCallbacks(int descriptor_number); - inline String* GetSortedKey(int descriptor_number); + inline Name* GetSortedKey(int descriptor_number); inline int GetSortedKeyIndex(int descriptor_number); inline void SetSortedKey(int pointer, int descriptor_number); @@ -2601,11 +2745,11 @@ class DescriptorArray: public FixedArray { void Sort(); // Search the instance descriptors for given name. - INLINE(int Search(String* name, int number_of_own_descriptors)); + INLINE(int Search(Name* name, int number_of_own_descriptors)); // As the above, but uses DescriptorLookupCache and updates it when // necessary. - INLINE(int SearchWithCache(String* name, Map* map)); + INLINE(int SearchWithCache(Name* name, Map* map)); // Allocates a DescriptorArray, but returns the singleton // empty descriptor array object if number_of_descriptors is 0. @@ -2714,11 +2858,11 @@ class DescriptorArray: public FixedArray { enum SearchMode { ALL_ENTRIES, VALID_ENTRIES }; template<SearchMode search_mode, typename T> -inline int LinearSearch(T* array, String* name, int len, int valid_entries); +inline int LinearSearch(T* array, Name* name, int len, int valid_entries); template<SearchMode search_mode, typename T> -inline int Search(T* array, String* name, int valid_entries = 0); +inline int Search(T* array, Name* name, int valid_entries = 0); // HashTable is a subclass of FixedArray that implements a hash table @@ -2743,7 +2887,7 @@ inline int Search(T* array, String* name, int valid_entries = 0); // // Returns the hash value for object. // static uint32_t HashForObject(Key key, Object* object); // // Convert key to an object. -// static inline Object* AsObject(Key key); +// static inline Object* AsObject(Heap* heap, Key key); // // The prefix size indicates number of elements in the beginning // // of the backing storage. // static const int kPrefixSize = ..; @@ -2829,6 +2973,7 @@ class HashTable: public FixedArray { // Returns a new HashTable object. Might return Failure. MUST_USE_RESULT static MaybeObject* Allocate( + Heap* heap, int at_least_space_for, MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY, PretenureFlag pretenure = NOT_TENURED); @@ -2951,13 +3096,13 @@ class HashTableKey { virtual uint32_t HashForObject(Object* key) = 0; // Returns the key object for storing into the hash table. // If allocations fails a failure object is returned. - MUST_USE_RESULT virtual MaybeObject* AsObject() = 0; + MUST_USE_RESULT virtual MaybeObject* AsObject(Heap* heap) = 0; // Required. virtual ~HashTableKey() {} }; -class SymbolTableShape : public BaseShape<HashTableKey*> { +class StringTableShape : public BaseShape<HashTableKey*> { public: static inline bool IsMatch(HashTableKey* key, Object* value) { return key->IsMatch(value); @@ -2968,53 +3113,58 @@ class SymbolTableShape : public BaseShape<HashTableKey*> { static inline uint32_t HashForObject(HashTableKey* key, Object* object) { return key->HashForObject(object); } - MUST_USE_RESULT static inline MaybeObject* AsObject(HashTableKey* key) { - return key->AsObject(); + MUST_USE_RESULT static inline MaybeObject* AsObject(Heap* heap, + HashTableKey* key) { + return key->AsObject(heap); } static const int kPrefixSize = 0; static const int kEntrySize = 1; }; -class SeqAsciiString; +class SeqOneByteString; -// SymbolTable. +// StringTable. // // No special elements in the prefix and the element size is 1 -// because only the symbol itself (the key) needs to be stored. -class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> { +// because only the string itself (the key) needs to be stored. +class StringTable: public HashTable<StringTableShape, HashTableKey*> { public: - // Find symbol in the symbol table. If it is not there yet, it is - // added. The return value is the symbol table which might have - // been enlarged. If the return value is not a failure, the symbol - // pointer *s is set to the symbol found. - MUST_USE_RESULT MaybeObject* LookupSymbol(Vector<const char> str, Object** s); - MUST_USE_RESULT MaybeObject* LookupAsciiSymbol(Vector<const char> str, - Object** s); - MUST_USE_RESULT MaybeObject* LookupSubStringAsciiSymbol( - Handle<SeqAsciiString> str, + // Find string in the string table. If it is not there yet, it is + // added. The return value is the string table which might have + // been enlarged. If the return value is not a failure, the string + // pointer *s is set to the string found. + MUST_USE_RESULT MaybeObject* LookupUtf8String( + Vector<const char> str, + Object** s); + MUST_USE_RESULT MaybeObject* LookupOneByteString( + Vector<const uint8_t> str, + Object** s); + MUST_USE_RESULT MaybeObject* LookupSubStringOneByteString( + Handle<SeqOneByteString> str, int from, int length, Object** s); - MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol(Vector<const uc16> str, - Object** s); + MUST_USE_RESULT MaybeObject* LookupTwoByteString( + Vector<const uc16> str, + Object** s); MUST_USE_RESULT MaybeObject* LookupString(String* key, Object** s); - // Looks up a symbol that is equal to the given string and returns - // true if it is found, assigning the symbol to the given output + // Looks up a string that is equal to the given string and returns + // true if it is found, assigning the string to the given output // parameter. - bool LookupSymbolIfExists(String* str, String** symbol); - bool LookupTwoCharsSymbolIfExists(uint32_t c1, uint32_t c2, String** symbol); + bool LookupStringIfExists(String* str, String** result); + bool LookupTwoCharsStringIfExists(uint16_t c1, uint16_t c2, String** result); // Casting. - static inline SymbolTable* cast(Object* obj); + static inline StringTable* cast(Object* obj); private: MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s); template <bool seq_ascii> friend class JsonParser; - DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable); + DISALLOW_IMPLICIT_CONSTRUCTORS(StringTable); }; @@ -3031,8 +3181,9 @@ class MapCacheShape : public BaseShape<HashTableKey*> { return key->HashForObject(object); } - MUST_USE_RESULT static inline MaybeObject* AsObject(HashTableKey* key) { - return key->AsObject(); + MUST_USE_RESULT static inline MaybeObject* AsObject(Heap* heap, + HashTableKey* key) { + return key->AsObject(heap); } static const int kPrefixSize = 0; @@ -3042,11 +3193,11 @@ class MapCacheShape : public BaseShape<HashTableKey*> { // MapCache. // -// Maps keys that are a fixed array of symbols to a map. +// Maps keys that are a fixed array of unique names to a map. // Used for canonicalize maps for object literals. class MapCache: public HashTable<MapCacheShape, HashTableKey*> { public: - // Find cached value for a string key, otherwise return null. + // Find cached value for a name key, otherwise return null. Object* Lookup(FixedArray* key); MUST_USE_RESULT MaybeObject* Put(FixedArray* key, Map* value); static inline MapCache* cast(Object* obj); @@ -3120,7 +3271,8 @@ class Dictionary: public HashTable<Shape, Key> { } // Returns a new array for dictionary usage. Might return Failure. - MUST_USE_RESULT static MaybeObject* Allocate(int at_least_space_for); + MUST_USE_RESULT static MaybeObject* Allocate(Heap* heap, + int at_least_space_for); // Ensure enough space for n additional elements. MUST_USE_RESULT MaybeObject* EnsureCapacity(int n, Key key); @@ -3165,29 +3317,30 @@ class Dictionary: public HashTable<Shape, Key> { }; -class StringDictionaryShape : public BaseShape<String*> { +class NameDictionaryShape : public BaseShape<Name*> { public: - static inline bool IsMatch(String* key, Object* other); - static inline uint32_t Hash(String* key); - static inline uint32_t HashForObject(String* key, Object* object); - MUST_USE_RESULT static inline MaybeObject* AsObject(String* key); + static inline bool IsMatch(Name* key, Object* other); + static inline uint32_t Hash(Name* key); + static inline uint32_t HashForObject(Name* key, Object* object); + MUST_USE_RESULT static inline MaybeObject* AsObject(Heap* heap, + Name* key); static const int kPrefixSize = 2; static const int kEntrySize = 3; static const bool kIsEnumerable = true; }; -class StringDictionary: public Dictionary<StringDictionaryShape, String*> { +class NameDictionary: public Dictionary<NameDictionaryShape, Name*> { public: - static inline StringDictionary* cast(Object* obj) { + static inline NameDictionary* cast(Object* obj) { ASSERT(obj->IsDictionary()); - return reinterpret_cast<StringDictionary*>(obj); + return reinterpret_cast<NameDictionary*>(obj); } // Copies enumerable keys to preallocated fixed array. FixedArray* CopyEnumKeysTo(FixedArray* storage); static void DoGenerateNewEnumerationIndices( - Handle<StringDictionary> dictionary); + Handle<NameDictionary> dictionary); // For transforming properties of a JSObject. MUST_USE_RESULT MaybeObject* TransformPropertiesToFastFor( @@ -3196,14 +3349,15 @@ class StringDictionary: public Dictionary<StringDictionaryShape, String*> { // Find entry for key, otherwise return kNotFound. Optimized version of // HashTable::FindEntry. - int FindEntry(String* key); + int FindEntry(Name* key); }; class NumberDictionaryShape : public BaseShape<uint32_t> { public: static inline bool IsMatch(uint32_t key, Object* other); - MUST_USE_RESULT static inline MaybeObject* AsObject(uint32_t key); + MUST_USE_RESULT static inline MaybeObject* AsObject(Heap* heap, + uint32_t key); static const int kEntrySize = 3; static const bool kIsEnumerable = false; }; @@ -3307,7 +3461,8 @@ class ObjectHashTableShape : public BaseShape<Object*> { static inline bool IsMatch(Object* key, Object* other); static inline uint32_t Hash(Object* key); static inline uint32_t HashForObject(Object* key, Object* object); - MUST_USE_RESULT static inline MaybeObject* AsObject(Object* key); + MUST_USE_RESULT static inline MaybeObject* AsObject(Heap* heap, + Object* key); static const int kPrefixSize = 0; static const int kEntrySize = entrysize; }; @@ -3475,13 +3630,13 @@ class ScopeInfo : public FixedArray { // Lookup support for serialized scope info. Returns the // the stack slot index for a given slot name if the slot is - // present; otherwise returns a value < 0. The name must be a symbol - // (canonicalized). + // present; otherwise returns a value < 0. The name must be an internalized + // string. int StackSlotIndex(String* name); // Lookup support for serialized scope info. Returns the // context slot index for a given slot name if the slot is present; otherwise - // returns a value < 0. The name must be a symbol (canonicalized). + // returns a value < 0. The name must be an internalized string. // If the slot is present and mode != NULL, sets *mode to the corresponding // mode for that variable. int ContextSlotIndex(String* name, @@ -3490,19 +3645,26 @@ class ScopeInfo : public FixedArray { // Lookup support for serialized scope info. Returns the // parameter index for a given parameter name if the parameter is present; - // otherwise returns a value < 0. The name must be a symbol (canonicalized). + // otherwise returns a value < 0. The name must be an internalized string. int ParameterIndex(String* name); // Lookup support for serialized scope info. Returns the function context // slot index if the function name is present and context-allocated (named // function expressions, only), otherwise returns a value < 0. The name - // must be a symbol (canonicalized). + // must be an internalized string. int FunctionContextSlotIndex(String* name, VariableMode* mode); + + // Copies all the context locals into an object used to materialize a scope. + bool CopyContextLocalsToScopeObject(Isolate* isolate, + Handle<Context> context, + Handle<JSObject> scope_object); + + static Handle<ScopeInfo> Create(Scope* scope, Zone* zone); // Serializes empty scope info. - static ScopeInfo* Empty(); + static ScopeInfo* Empty(Isolate* isolate); #ifdef DEBUG void Print(); @@ -3658,12 +3820,7 @@ class ByteArray: public FixedArrayBase { inline int ByteArraySize() { return SizeFor(this->length()); } -#ifdef OBJECT_PRINT - inline void ByteArrayPrint() { - ByteArrayPrint(stdout); - } - void ByteArrayPrint(FILE* out); -#endif + DECLARE_PRINTER(ByteArray) DECLARE_VERIFIER(ByteArray) // Layout description. @@ -3692,12 +3849,8 @@ class FreeSpace: public HeapObject { // Casting. static inline FreeSpace* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void FreeSpacePrint() { - FreeSpacePrint(stdout); - } - void FreeSpacePrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(FreeSpace) DECLARE_VERIFIER(FreeSpace) // Layout description. @@ -3772,12 +3925,8 @@ class ExternalPixelArray: public ExternalArray { // Casting. static inline ExternalPixelArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalPixelArrayPrint() { - ExternalPixelArrayPrint(stdout); - } - void ExternalPixelArrayPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ExternalPixelArray) DECLARE_VERIFIER(ExternalPixelArray) private: @@ -3799,12 +3948,8 @@ class ExternalByteArray: public ExternalArray { // Casting. static inline ExternalByteArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalByteArrayPrint() { - ExternalByteArrayPrint(stdout); - } - void ExternalByteArrayPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ExternalByteArray) DECLARE_VERIFIER(ExternalByteArray) private: @@ -3826,12 +3971,8 @@ class ExternalUnsignedByteArray: public ExternalArray { // Casting. static inline ExternalUnsignedByteArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalUnsignedByteArrayPrint() { - ExternalUnsignedByteArrayPrint(stdout); - } - void ExternalUnsignedByteArrayPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ExternalUnsignedByteArray) DECLARE_VERIFIER(ExternalUnsignedByteArray) private: @@ -3853,12 +3994,8 @@ class ExternalShortArray: public ExternalArray { // Casting. static inline ExternalShortArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalShortArrayPrint() { - ExternalShortArrayPrint(stdout); - } - void ExternalShortArrayPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ExternalShortArray) DECLARE_VERIFIER(ExternalShortArray) private: @@ -3880,12 +4017,8 @@ class ExternalUnsignedShortArray: public ExternalArray { // Casting. static inline ExternalUnsignedShortArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalUnsignedShortArrayPrint() { - ExternalUnsignedShortArrayPrint(stdout); - } - void ExternalUnsignedShortArrayPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ExternalUnsignedShortArray) DECLARE_VERIFIER(ExternalUnsignedShortArray) private: @@ -3907,12 +4040,8 @@ class ExternalIntArray: public ExternalArray { // Casting. static inline ExternalIntArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalIntArrayPrint() { - ExternalIntArrayPrint(stdout); - } - void ExternalIntArrayPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ExternalIntArray) DECLARE_VERIFIER(ExternalIntArray) private: @@ -3934,12 +4063,8 @@ class ExternalUnsignedIntArray: public ExternalArray { // Casting. static inline ExternalUnsignedIntArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalUnsignedIntArrayPrint() { - ExternalUnsignedIntArrayPrint(stdout); - } - void ExternalUnsignedIntArrayPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ExternalUnsignedIntArray) DECLARE_VERIFIER(ExternalUnsignedIntArray) private: @@ -3961,12 +4086,8 @@ class ExternalFloatArray: public ExternalArray { // Casting. static inline ExternalFloatArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalFloatArrayPrint() { - ExternalFloatArrayPrint(stdout); - } - void ExternalFloatArrayPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ExternalFloatArray) DECLARE_VERIFIER(ExternalFloatArray) private: @@ -3988,12 +4109,8 @@ class ExternalDoubleArray: public ExternalArray { // Casting. static inline ExternalDoubleArray* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ExternalDoubleArrayPrint() { - ExternalDoubleArrayPrint(stdout); - } - void ExternalDoubleArrayPrint(FILE* out); -#endif // OBJECT_PRINT + // Dispatched behavior. + DECLARE_PRINTER(ExternalDoubleArray) DECLARE_VERIFIER(ExternalDoubleArray) private: @@ -4156,6 +4273,11 @@ class TypeFeedbackCells: public FixedArray { // The object that indicates a megamorphic state. static inline Handle<Object> MegamorphicSentinel(Isolate* isolate); + // The object that indicates a monomorphic state of Array with + // ElementsKind + static inline Handle<Object> MonomorphicArraySentinel(Isolate* isolate, + ElementsKind elements_kind); + // A raw version of the uninitialized sentinel that's safe to read during // garbage collection (e.g., for patching the cache). static inline Object* RawUninitializedSentinel(Heap* heap); @@ -4177,17 +4299,13 @@ class Code: public HeapObject { public: // Opaque data type for encapsulating code flags like kind, inline // cache state, and arguments count. - // FLAGS_MIN_VALUE and FLAGS_MAX_VALUE are specified to ensure that - // enumeration type has correct value range (see Issue 830 for more details). - enum Flags { - FLAGS_MIN_VALUE = kMinInt, - FLAGS_MAX_VALUE = kMaxInt - }; + typedef uint32_t Flags; #define CODE_KIND_LIST(V) \ V(FUNCTION) \ V(OPTIMIZED_FUNCTION) \ V(STUB) \ + V(COMPILED_STUB) \ V(BUILTIN) \ V(LOAD_IC) \ V(KEYED_LOAD_IC) \ @@ -4216,6 +4334,8 @@ class Code: public HeapObject { // Flags. STATIC_ASSERT(LAST_CODE_KIND < 16); + static const char* Kind2String(Kind kind); + // Types of stubs. enum StubType { NORMAL, @@ -4237,7 +4357,6 @@ class Code: public HeapObject { #ifdef ENABLE_DISASSEMBLER // Printing - static const char* Kind2String(Kind kind); static const char* ICState2String(InlineCacheState state); static const char* StubType2String(StubType type); static void PrintExtraICState(FILE* out, Kind kind, ExtraICState extra); @@ -4261,9 +4380,18 @@ class Code: public HeapObject { // [deoptimization_data]: Array containing data for deopt. DECL_ACCESSORS(deoptimization_data, FixedArray) - // [type_feedback_info]: Struct containing type feedback information. - // Will contain either a TypeFeedbackInfo object, or undefined. + // [type_feedback_info]: Struct containing type feedback information for + // unoptimized code. Optimized code can temporarily store the head of + // the list of the dependent optimized functions during deoptimization. + // STUBs can use this slot to store arbitrary information as a Smi. + // Will contain either a TypeFeedbackInfo object, or JSFunction object, + // or undefined, or a Smi. DECL_ACCESSORS(type_feedback_info, Object) + inline void InitializeTypeFeedbackInfoNoWriteBarrier(Object* value); + inline int stub_info(); + inline void set_stub_info(int info); + inline Object* deoptimizing_functions(); + inline void set_deoptimizing_functions(Object* value); // [gc_metadata]: Field used to hold GC related metadata. The contents of this // field does not have to be traced during garbage collection since @@ -4275,6 +4403,11 @@ class Code: public HeapObject { inline void set_ic_age(int count); inline int ic_age(); + // [prologue_offset]: Offset of the function prologue, used for aging + // FUNCTIONs and OPTIMIZED_FUNCTIONs. + inline int prologue_offset(); + inline void set_prologue_offset(int offset); + // Unchecked accessors to be used during GC. inline ByteArray* unchecked_relocation_info(); inline FixedArray* unchecked_deoptimization_data(); @@ -4294,6 +4427,7 @@ class Code: public HeapObject { // Testers for IC stub kinds. inline bool is_inline_cache_stub(); + inline bool is_debug_break(); inline bool is_load_stub() { return kind() == LOAD_IC; } inline bool is_keyed_load_stub() { return kind() == KEYED_LOAD_IC; } inline bool is_store_stub() { return kind() == STORE_IC; } @@ -4360,6 +4494,9 @@ class Code: public HeapObject { inline unsigned stack_check_table_offset(); inline void set_stack_check_table_offset(unsigned offset); + inline bool stack_check_patched_for_osr(); + inline void set_stack_check_patched_for_osr(bool value); + // [check type]: For kind CALL_IC, tells how to check if the // receiver is valid for the given call. inline CheckType check_type(); @@ -4369,21 +4506,6 @@ class Code: public HeapObject { inline byte unary_op_type(); inline void set_unary_op_type(byte value); - // [type-recording binary op type]: For kind BINARY_OP_IC. - inline byte binary_op_type(); - inline void set_binary_op_type(byte value); - inline byte binary_op_result_type(); - inline void set_binary_op_result_type(byte value); - - // [compare state]: For kind COMPARE_IC, tells what state the stub is in. - inline byte compare_state(); - inline void set_compare_state(byte value); - - // [compare_operation]: For kind COMPARE_IC tells what compare operation the - // stub was generated for. - inline byte compare_operation(); - inline void set_compare_operation(byte value); - // [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in. inline byte to_boolean_state(); inline void set_to_boolean_state(byte value); @@ -4393,6 +4515,12 @@ class Code: public HeapObject { inline bool has_function_cache(); inline void set_has_function_cache(bool flag); + + // [marked_for_deoptimization]: For kind OPTIMIZED_FUNCTION tells whether + // the code is going to be deoptimized because of dead embedded maps. + inline bool marked_for_deoptimization(); + inline void set_marked_for_deoptimization(bool flag); + bool allowed_in_shared_map_code_cache(); // Get the safepoint entry for the given pc. @@ -4404,26 +4532,29 @@ class Code: public HeapObject { // Find the first map in an IC stub. Map* FindFirstMap(); + void FindAllMaps(MapHandleList* maps); - class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {}; - class ExtraICStateKeyedAccessGrowMode: - public BitField<KeyedAccessGrowMode, 1, 1> {}; // NOLINT + // Find the first code in an IC stub. + Code* FindFirstCode(); + void FindAllCode(CodeHandleList* code_list, int length); - static const int kExtraICStateGrowModeShift = 1; + class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {}; + class ExtraICStateKeyedAccessStoreMode: + public BitField<KeyedAccessStoreMode, 1, 4> {}; // NOLINT static inline StrictModeFlag GetStrictMode(ExtraICState extra_ic_state) { return ExtraICStateStrictMode::decode(extra_ic_state); } - static inline KeyedAccessGrowMode GetKeyedAccessGrowMode( + static inline KeyedAccessStoreMode GetKeyedAccessStoreMode( ExtraICState extra_ic_state) { - return ExtraICStateKeyedAccessGrowMode::decode(extra_ic_state); + return ExtraICStateKeyedAccessStoreMode::decode(extra_ic_state); } static inline ExtraICState ComputeExtraICState( - KeyedAccessGrowMode grow_mode, + KeyedAccessStoreMode store_mode, StrictModeFlag strict_mode) { - return ExtraICStateKeyedAccessGrowMode::encode(grow_mode) | + return ExtraICStateKeyedAccessStoreMode::encode(store_mode) | ExtraICStateStrictMode::encode(strict_mode); } @@ -4438,10 +4569,10 @@ class Code: public HeapObject { static inline Flags ComputeMonomorphicFlags( Kind kind, - StubType type, ExtraICState extra_ic_state = kNoExtraICState, - InlineCacheHolderFlag holder = OWN_MAP, - int argc = -1); + StubType type = NORMAL, + int argc = -1, + InlineCacheHolderFlag holder = OWN_MAP); static inline InlineCacheState ExtractICStateFromFlags(Flags flags); static inline StubType ExtractTypeFromFlags(Flags flags); @@ -4511,17 +4642,35 @@ class Code: public HeapObject { template<typename StaticVisitor> inline void CodeIterateBody(Heap* heap); -#ifdef OBJECT_PRINT - inline void CodePrint() { - CodePrint(stdout); - } - void CodePrint(FILE* out); -#endif + + DECLARE_PRINTER(Code) 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 MakeOlder(MarkingParity); + static bool IsYoungSequence(byte* sequence); + bool IsOld(); + + void PrintDeoptLocation(int bailout_id); + +#ifdef VERIFY_HEAP + void VerifyEmbeddedMapsDependency(); +#endif + // 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; @@ -4541,8 +4690,10 @@ class Code: public HeapObject { static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize; static const int kKindSpecificFlags2Offset = kKindSpecificFlags1Offset + kIntSize; + // Note: We might be able to squeeze this into the flags above. + static const int kPrologueOffset = kKindSpecificFlags2Offset + kIntSize; - static const int kHeaderPaddingStart = kKindSpecificFlags2Offset + kIntSize; + static const int kHeaderPaddingStart = kPrologueOffset + kIntSize; // Add padding to align the instruction start following right after // the Code object header. @@ -4567,8 +4718,8 @@ class Code: public HeapObject { 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> {}; + class ExtraICStateField: public BitField<ExtraICState, 11, 5> {}; + class IsPregeneratedField: public BitField<bool, 16, 1> {}; // KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION) static const int kStackSlotsFirstBit = 0; @@ -4576,51 +4727,34 @@ class Code: public HeapObject { 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 const int kMarkedForDeoptimizationFirstBit = + kStackSlotsFirstBit + kStackSlotsBitCount + 1; + static const int kMarkedForDeoptimizationBitCount = 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); + STATIC_ASSERT(kMarkedForDeoptimizationFirstBit + + kMarkedForDeoptimizationBitCount <= 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 + class MarkedForDeoptimizationField: public BitField<bool, + kMarkedForDeoptimizationFirstBit, + kMarkedForDeoptimizationBitCount> {}; // NOLINT // KindSpecificFlags2 layout (STUB and OPTIMIZED_FUNCTION) static const int kStubMajorKeyFirstBit = 0; @@ -4640,20 +4774,108 @@ class Code: public HeapObject { // KindSpecificFlags2 layout (FUNCTION) class StackCheckTableOffsetField: public BitField<int, 0, 31> {}; + class StackCheckPatchedForOSRField: public BitField<bool, 31, 1> {}; // Signed field cannot be encoded using the BitField class. - static const int kArgumentsCountShift = 14; + static const int kArgumentsCountShift = 17; static const int kArgumentsCountMask = ~((1 << kArgumentsCountShift) - 1); + static const int kArgumentsBits = + PlatformSmiTagging::kSmiValueSize - Code::kArgumentsCountShift + 1; + static const int kMaxArguments = (1 << kArgumentsBits) - 1; // This constant should be encodable in an ARM instruction. static const int kFlagsNotUsedInLookup = 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 + static void PatchPlatformCodeAge(byte* sequence, Age age, + MarkingParity parity); + DISALLOW_IMPLICIT_CONSTRUCTORS(Code); }; +// This class describes the layout of dependent codes array of a map. The +// array is partitioned into several groups of dependent codes. Each group +// contains codes with the same dependency on the map. The array has the +// following layout for n dependency groups: +// +// +----+----+-----+----+---------+----------+-----+---------+-----------+ +// | C1 | C2 | ... | Cn | group 1 | group 2 | ... | group n | undefined | +// +----+----+-----+----+---------+----------+-----+---------+-----------+ +// +// The first n elements are Smis, each of them specifies the number of codes +// in the corresponding group. The subsequent elements contain grouped code +// objects. The suffix of the array can be filled with the undefined value if +// the number of codes is less than the length of the array. The order of the +// code objects within a group is not preserved. +// +// All code indexes used in the class are counted starting from the first +// code object of the first group. In other words, code index 0 corresponds +// to array index n = kCodesStartIndex. + +class DependentCode: public FixedArray { + public: + enum DependencyGroup { + // Group of code that weakly embed this map and depend on being + // deoptimized when the map is garbage collected. + kWeaklyEmbeddedGroup, + // Group of code that omit run-time prototype checks for prototypes + // described by this map. The group is deoptimized whenever an object + // described by this map changes shape (and transitions to a new map), + // possibly invalidating the assumptions embedded in the code. + kPrototypeCheckGroup, + kGroupCount = kPrototypeCheckGroup + 1 + }; + + // Array for holding the index of the first code object of each group. + // The last element stores the total number of code objects. + class GroupStartIndexes { + public: + explicit GroupStartIndexes(DependentCode* entries); + void Recompute(DependentCode* entries); + int at(int i) { return start_indexes_[i]; } + int number_of_entries() { return start_indexes_[kGroupCount]; } + private: + int start_indexes_[kGroupCount + 1]; + }; + + bool Contains(DependencyGroup group, Code* code); + static Handle<DependentCode> Insert(Handle<DependentCode> entries, + DependencyGroup group, + Handle<Code> value); + void DeoptimizeDependentCodeGroup(Isolate* isolate, + DependentCode::DependencyGroup group); + + // The following low-level accessors should only be used by this class + // and the mark compact collector. + inline int number_of_entries(DependencyGroup group); + inline void set_number_of_entries(DependencyGroup group, int value); + inline Code* code_at(int i); + inline void set_code_at(int i, Code* value); + inline Object** code_slot_at(int i); + inline void clear_code_at(int i); + static inline DependentCode* cast(Object* object); + + private: + // Make a room at the end of the given group by moving out the first + // code objects of the subsequent groups. + inline void ExtendGroup(DependencyGroup group); + static const int kCodesStartIndex = kGroupCount; +}; + + // All heap objects have a Map that describes their structure. // A Map contains information about: // - Size information about the object @@ -4701,6 +4923,7 @@ class Map: public HeapObject { 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> {}; // Tells whether the object in the prototype property will be used // for instances created from this function. If the prototype @@ -4717,7 +4940,7 @@ class Map: public HeapObject { inline bool function_with_prototype(); // Tells whether the instance with this map should be ignored by the - // __proto__ accessor. + // Object.getPrototypeOf() function and the __proto__ accessor. inline void set_is_hidden_prototype() { set_bit_field(bit_field() | (1 << kIsHiddenPrototype)); } @@ -4773,6 +4996,10 @@ class Map: public HeapObject { inline void set_elements_kind(ElementsKind elements_kind) { ASSERT(elements_kind < kElementsKindCount); ASSERT(kElementsKindCount <= (1 << kElementsKindBitCount)); + ASSERT(!is_observed() || + elements_kind == DICTIONARY_ELEMENTS || + elements_kind == NON_STRICT_ARGUMENTS_ELEMENTS || + IsExternalArrayElementsKind(elements_kind)); set_bit_field2((bit_field2() & ~kElementsKindMask) | (elements_kind << kElementsKindShift)); ASSERT(this->elements_kind() == elements_kind); @@ -4801,6 +5028,10 @@ class Map: public HeapObject { return IsFastDoubleElementsKind(elements_kind()); } + inline bool has_fast_elements() { + return IsFastElementsKind(elements_kind()); + } + inline bool has_non_strict_arguments_elements() { return elements_kind() == NON_STRICT_ARGUMENTS_ELEMENTS; } @@ -4828,7 +5059,7 @@ class Map: public HeapObject { 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, + MUST_USE_RESULT inline MaybeObject* AddTransition(Name* key, Map* target, SimpleTransitionFlag flag); DECL_ACCESSORS(transitions, TransitionArray) @@ -4874,6 +5105,9 @@ class Map: public HeapObject { // [stub cache]: contains stubs compiled for this map. DECL_ACCESSORS(code_cache, Object) + // [dependent code]: list of optimized codes that have this map embedded. + DECL_ACCESSORS(dependent_code, DependentCode) + // [back pointer]: points back to the parent map from which a transition // leads to this map. The field overlaps with prototype transitions and the // back pointer will be moved into the prototype transitions array if @@ -4923,11 +5157,11 @@ class Map: public HeapObject { // with the given holder if the name is found. The holder may be // NULL when this function is used from the compiler. inline void LookupDescriptor(JSObject* holder, - String* name, + Name* name, LookupResult* result); inline void LookupTransition(JSObject* holder, - String* name, + Name* name, LookupResult* result); // The size of transition arrays are limited so they do not end up in large @@ -4965,16 +5199,18 @@ class Map: public HeapObject { set_bit_field3(EnumLengthBits::update(bit_field3(), length)); } - + inline bool CanTrackAllocationSite(); 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, + Name* name, TransitionFlag flag, int descriptor_index); MUST_USE_RESULT MaybeObject* ShareDescriptor(DescriptorArray* descriptors, @@ -5002,7 +5238,7 @@ class Map: public HeapObject { MUST_USE_RESULT MaybeObject* Copy(); // Returns the property index for name (only valid for FAST MODE). - int PropertyIndexFor(String* name); + int PropertyIndexFor(Name* name); // Returns the next free property index (only valid for FAST MODE). int NextFreePropertyIndex(); @@ -5016,7 +5252,7 @@ class Map: public HeapObject { static inline Map* cast(Object* obj); // Locate an accessor in the instance descriptor. - AccessorDescriptor* FindAccessor(String* name); + AccessorDescriptor* FindAccessor(Name* name); // Code cache operations. @@ -5025,9 +5261,9 @@ class Map: public HeapObject { // Update code cache. static void UpdateCodeCache(Handle<Map> map, - Handle<String> name, + Handle<Name> name, Handle<Code> code); - MUST_USE_RESULT MaybeObject* UpdateCodeCache(String* name, Code* code); + MUST_USE_RESULT MaybeObject* UpdateCodeCache(Name* name, Code* code); // Extend the descriptor array of the map with the list of descriptors. // In case of duplicates, the latest descriptor is used. @@ -5037,14 +5273,14 @@ class Map: public HeapObject { static void EnsureDescriptorSlack(Handle<Map> map, int slack); // Returns the found code or undefined if absent. - Object* FindInCodeCache(String* name, Code::Flags flags); + Object* FindInCodeCache(Name* name, Code::Flags flags); // Returns the non-negative index of the code object if it is in the // cache and -1 otherwise. int IndexInCodeCache(Object* name, Code* code); // Removes a code object from the code cache at the given index. - void RemoveFromCodeCache(String* name, Code* code, int index); + void RemoveFromCodeCache(Name* name, Code* code, int index); // Set all map transitions from this map to dead maps to null. Also clear // back pointers in transition targets so that we do not process this map @@ -5081,17 +5317,29 @@ class Map: public HeapObject { void ZapPrototypeTransitions(); void ZapTransitions(); - // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void MapPrint() { - MapPrint(stdout); + bool CanTransition() { + // Only JSObject and subtypes have map transitions and back pointers. + STATIC_ASSERT(LAST_TYPE == LAST_JS_OBJECT_TYPE); + return instance_type() >= FIRST_JS_OBJECT_TYPE; } - void MapPrint(FILE* out); -#endif + + // Fires when the layout of an object with a leaf map changes. + // This includes adding transitions to the leaf map or changing + // the descriptor array. + inline void NotifyLeafMapLayoutChange(); + + inline bool CanOmitPrototypeChecks(); + + inline void AddDependentCode(DependentCode::DependencyGroup group, + Handle<Code> code); + + // Dispatched behavior. + DECLARE_PRINTER(Map) DECLARE_VERIFIER(Map) #ifdef VERIFY_HEAP void SharedMapVerify(); + void VerifyOmittedPrototypeChecks(); #endif inline int visitor_id(); @@ -5133,9 +5381,9 @@ class Map: public HeapObject { kConstructorOffset + kPointerSize; static const int kDescriptorsOffset = kTransitionsOrBackPointerOffset + kPointerSize; - static const int kCodeCacheOffset = - kDescriptorsOffset + kPointerSize; - static const int kBitField3Offset = kCodeCacheOffset + kPointerSize; + static const int kCodeCacheOffset = kDescriptorsOffset + kPointerSize; + static const int kDependentCodeOffset = kCodeCacheOffset + kPointerSize; + static const int kBitField3Offset = kDependentCodeOffset + kPointerSize; static const int kSize = kBitField3Offset + kPointerSize; // Layout of pointer fields. Heap iteration code relies on them @@ -5288,12 +5536,8 @@ class Script: public Struct { // resource is accessible. Otherwise, always return true. inline bool HasValidSource(); -#ifdef OBJECT_PRINT - inline void ScriptPrint() { - ScriptPrint(stdout); - } - void ScriptPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(Script) DECLARE_VERIFIER(Script) static const int kSourceOffset = HeapObject::kHeaderSize; @@ -5378,6 +5622,7 @@ class SharedFunctionInfo: public HeapObject { // [code]: Function code. DECL_ACCESSORS(code, Code) + inline void ReplaceCode(Code* code); // [optimized_code_map]: Map from native context to optimized code // and a shared literals array or Smi 0 if none. @@ -5393,7 +5638,7 @@ class SharedFunctionInfo: public HeapObject { void InstallFromOptimizedCodeMap(JSFunction* function, int index); // Clear optimized code map. - void ClearOptimizedCodeMap(); + inline void ClearOptimizedCodeMap(); // Add a new entry to the optimized code map. static void AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared, @@ -5768,12 +6013,7 @@ class SharedFunctionInfo: public HeapObject { // Dispatched behavior. // Set max_length to -1 for unlimited length. void SourceCodePrint(StringStream* accumulator, int max_length); -#ifdef OBJECT_PRINT - inline void SharedFunctionInfoPrint() { - SharedFunctionInfoPrint(stdout); - } - void SharedFunctionInfoPrint(FILE* out); -#endif + DECLARE_PRINTER(SharedFunctionInfo) DECLARE_VERIFIER(SharedFunctionInfo) void ResetForNewContext(int new_ic_age); @@ -5901,10 +6141,10 @@ class SharedFunctionInfo: public HeapObject { // Bit positions in start_position_and_type. // The source code start position is in the 30 most significant bits of // the start_position_and_type field. - static const int kIsExpressionBit = 0; - static const int kIsTopLevelBit = 1; + static const int kIsExpressionBit = 0; + static const int kIsTopLevelBit = 1; static const int kStartPositionShift = 2; - static const int kStartPositionMask = ~((1 << kStartPositionShift) - 1); + static const int kStartPositionMask = ~((1 << kStartPositionShift) - 1); // Bit positions in compiler_hints. static const int kCodeAgeSize = 3; @@ -6002,12 +6242,7 @@ class JSModule: public JSObject { static inline JSModule* cast(Object* obj); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSModulePrint() { - JSModulePrint(stdout); - } - void JSModulePrint(FILE* out); -#endif + DECLARE_PRINTER(JSModule) DECLARE_VERIFIER(JSModule) // Layout description. @@ -6043,6 +6278,7 @@ class JSFunction: public JSObject { // 8.6.2, page 27. inline Code* code(); inline void set_code(Code* code); + inline void set_code_no_write_barrier(Code* code); inline void ReplaceCode(Code* code); inline Code* unchecked_code(); @@ -6063,6 +6299,8 @@ class JSFunction: public JSObject { // recompiled the next time it is executed. void MarkForLazyRecompilation(); void MarkForParallelRecompilation(); + void MarkForInstallingRecompiledCode(); + void MarkInRecompileQueue(); // Helpers to compile this function. Returns true on success, false on // failure (e.g., stack overflow during compilation). @@ -6078,6 +6316,7 @@ class JSFunction: public JSObject { // recompilation. inline bool IsMarkedForLazyRecompilation(); inline bool IsMarkedForParallelRecompilation(); + inline bool IsMarkedForInstallingRecompiledCode(); // Tells whether or not the function is on the parallel // recompilation queue. @@ -6161,12 +6400,7 @@ class JSFunction: public JSObject { void JSFunctionIterateBody(int object_size, ObjectVisitor* v); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSFunctionPrint() { - JSFunctionPrint(stdout); - } - void JSFunctionPrint(FILE* out); -#endif + DECLARE_PRINTER(JSFunction) DECLARE_VERIFIER(JSFunction) // Returns the number of allocated literals. @@ -6175,6 +6409,18 @@ class JSFunction: public JSObject { // Retrieve the native context from a function's literal array. static Context* NativeContextFromLiterals(FixedArray* literals); +#ifdef DEBUG + bool FunctionsInFunctionListShareSameCode() { + Object* current = this; + while (!current->IsUndefined()) { + JSFunction* function = JSFunction::cast(current); + current = function->next_function_link(); + if (function->code() != this->code()) return false; + } + return true; + } +#endif + // Layout descriptors. The last property (from kNonWeakFieldsEndOffset to // kSize) is weak and has special handling during garbage collection. static const int kCodeEntryOffset = JSObject::kHeaderSize; @@ -6220,12 +6466,7 @@ class JSGlobalProxy : public JSObject { static inline JSGlobalProxy* cast(Object* obj); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSGlobalProxyPrint() { - JSGlobalProxyPrint(stdout); - } - void JSGlobalProxyPrint(FILE* out); -#endif + DECLARE_PRINTER(JSGlobalProxy) DECLARE_VERIFIER(JSGlobalProxy) // Layout description. @@ -6263,7 +6504,7 @@ class GlobalObject: public JSObject { // by throwing an exception. This is for the debug and builtins global // objects, where it is known which properties can be expected to be present // on the object. - Object* GetPropertyNoExceptionThrown(String* key) { + Object* GetPropertyNoExceptionThrown(Name* key) { Object* answer = GetProperty(key)->ToObjectUnchecked(); return answer; } @@ -6271,10 +6512,10 @@ class GlobalObject: public JSObject { // Ensure that the global object has a cell for the given property name. static Handle<JSGlobalPropertyCell> EnsurePropertyCell( Handle<GlobalObject> global, - Handle<String> name); + Handle<Name> name); // TODO(kmillikin): This function can be eliminated once the stub cache is - // full handlified (and the static helper can be written directly). - MUST_USE_RESULT MaybeObject* EnsurePropertyCell(String* name); + // fully handlified (and the static helper can be written directly). + MUST_USE_RESULT MaybeObject* EnsurePropertyCell(Name* name); // Casting. static inline GlobalObject* cast(Object* obj); @@ -6298,12 +6539,7 @@ class JSGlobalObject: public GlobalObject { static inline JSGlobalObject* cast(Object* obj); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSGlobalObjectPrint() { - JSGlobalObjectPrint(stdout); - } - void JSGlobalObjectPrint(FILE* out); -#endif + DECLARE_PRINTER(JSGlobalObject) DECLARE_VERIFIER(JSGlobalObject) // Layout description. @@ -6330,12 +6566,7 @@ class JSBuiltinsObject: public GlobalObject { static inline JSBuiltinsObject* cast(Object* obj); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSBuiltinsObjectPrint() { - JSBuiltinsObjectPrint(stdout); - } - void JSBuiltinsObjectPrint(FILE* out); -#endif + DECLARE_PRINTER(JSBuiltinsObject) DECLARE_VERIFIER(JSBuiltinsObject) // Layout description. The size of the builtins object includes @@ -6371,12 +6602,7 @@ class JSValue: public JSObject { static inline JSValue* cast(Object* obj); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSValuePrint() { - JSValuePrint(stdout); - } - void JSValuePrint(FILE* out); -#endif + DECLARE_PRINTER(JSValue) DECLARE_VERIFIER(JSValue) // Layout description. @@ -6425,12 +6651,7 @@ class JSDate: public JSObject { // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSDatePrint() { - JSDatePrint(stdout); - } - void JSDatePrint(FILE* out); -#endif + DECLARE_PRINTER(JSDate) DECLARE_VERIFIER(JSDate) // The order is important. It must be kept in sync with date macros @@ -6522,12 +6743,7 @@ class JSMessageObject: public JSObject { static inline JSMessageObject* cast(Object* obj); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSMessageObjectPrint() { - JSMessageObjectPrint(stdout); - } - void JSMessageObjectPrint(FILE* out); -#endif + DECLARE_PRINTER(JSMessageObject) DECLARE_VERIFIER(JSMessageObject) // Layout description. @@ -6704,8 +6920,9 @@ class CompilationCacheShape : public BaseShape<HashTableKey*> { return key->HashForObject(object); } - MUST_USE_RESULT static MaybeObject* AsObject(HashTableKey* key) { - return key->AsObject(); + MUST_USE_RESULT static MaybeObject* AsObject(Heap* heap, + HashTableKey* key) { + return key->AsObject(heap); } static const int kPrefixSize = 0; @@ -6750,11 +6967,11 @@ class CodeCache: public Struct { DECL_ACCESSORS(normal_type_cache, Object) // Add the code object to the cache. - MUST_USE_RESULT MaybeObject* Update(String* name, Code* code); + MUST_USE_RESULT MaybeObject* Update(Name* name, Code* code); // Lookup code object in the cache. Returns code object if found and undefined // if not. - Object* Lookup(String* name, Code::Flags flags); + Object* Lookup(Name* name, Code::Flags flags); // Get the internal index of a code object in the cache. Returns -1 if the // code object is not in that cache. This index can be used to later call @@ -6767,12 +6984,8 @@ class CodeCache: public Struct { static inline CodeCache* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void CodeCachePrint() { - CodeCachePrint(stdout); - } - void CodeCachePrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(CodeCache) DECLARE_VERIFIER(CodeCache) static const int kDefaultCacheOffset = HeapObject::kHeaderSize; @@ -6781,10 +6994,10 @@ class CodeCache: public Struct { static const int kSize = kNormalTypeCacheOffset + kPointerSize; private: - MUST_USE_RESULT MaybeObject* UpdateDefaultCache(String* name, Code* code); - MUST_USE_RESULT MaybeObject* UpdateNormalTypeCache(String* name, Code* code); - Object* LookupDefaultCache(String* name, Code::Flags flags); - Object* LookupNormalTypeCache(String* name, Code::Flags flags); + MUST_USE_RESULT MaybeObject* UpdateDefaultCache(Name* name, Code* code); + MUST_USE_RESULT MaybeObject* UpdateNormalTypeCache(Name* name, Code* code); + Object* LookupDefaultCache(Name* name, Code::Flags flags); + Object* LookupNormalTypeCache(Name* name, Code::Flags flags); // Code cache layout of the default cache. Elements are alternating name and // code objects for non normal load/store/call IC's. @@ -6810,8 +7023,9 @@ class CodeCacheHashTableShape : public BaseShape<HashTableKey*> { return key->HashForObject(object); } - MUST_USE_RESULT static MaybeObject* AsObject(HashTableKey* key) { - return key->AsObject(); + MUST_USE_RESULT static MaybeObject* AsObject(Heap* heap, + HashTableKey* key) { + return key->AsObject(heap); } static const int kPrefixSize = 0; @@ -6822,10 +7036,10 @@ class CodeCacheHashTableShape : public BaseShape<HashTableKey*> { class CodeCacheHashTable: public HashTable<CodeCacheHashTableShape, HashTableKey*> { public: - Object* Lookup(String* name, Code::Flags flags); - MUST_USE_RESULT MaybeObject* Put(String* name, Code* code); + Object* Lookup(Name* name, Code::Flags flags); + MUST_USE_RESULT MaybeObject* Put(Name* name, Code* code); - int GetIndex(String* name, Code::Flags flags); + int GetIndex(Name* name, Code::Flags flags); void RemoveByIndex(int index); static inline CodeCacheHashTable* cast(Object* obj); @@ -6856,12 +7070,8 @@ class PolymorphicCodeCache: public Struct { static inline PolymorphicCodeCache* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void PolymorphicCodeCachePrint() { - PolymorphicCodeCachePrint(stdout); - } - void PolymorphicCodeCachePrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(PolymorphicCodeCache) DECLARE_VERIFIER(PolymorphicCodeCache) static const int kCacheOffset = HeapObject::kHeaderSize; @@ -6909,12 +7119,8 @@ class TypeFeedbackInfo: public Struct { static inline TypeFeedbackInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void TypeFeedbackInfoPrint() { - TypeFeedbackInfoPrint(stdout); - } - void TypeFeedbackInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(TypeFeedbackInfo) DECLARE_VERIFIER(TypeFeedbackInfo) static const int kStorage1Offset = HeapObject::kHeaderSize; @@ -6940,6 +7146,38 @@ class TypeFeedbackInfo: public Struct { }; +enum AllocationSiteMode { + DONT_TRACK_ALLOCATION_SITE, + TRACK_ALLOCATION_SITE, + LAST_ALLOCATION_SITE_MODE = TRACK_ALLOCATION_SITE +}; + + +class AllocationSiteInfo: public Struct { + public: + DECL_ACCESSORS(payload, Object) + + static inline AllocationSiteInfo* cast(Object* obj); + + DECLARE_PRINTER(AllocationSiteInfo) + DECLARE_VERIFIER(AllocationSiteInfo) + + // Returns NULL if no AllocationSiteInfo is available for object. + static AllocationSiteInfo* FindForJSObject(JSObject* object); + + static AllocationSiteMode GetMode(ElementsKind boilerplate_elements_kind); + static AllocationSiteMode GetMode(ElementsKind from, ElementsKind to); + + static const int kPayloadOffset = HeapObject::kHeaderSize; + static const int kSize = kPayloadOffset + kPointerSize; + static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024; + + bool GetElementsKindPayload(ElementsKind* kind); + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSiteInfo); +}; + + // Representation of a slow alias as part of a non-strict arguments objects. // For fast aliases (if HasNonStrictArgumentsElements()): // - the parameter map contains an index into the context @@ -6955,12 +7193,8 @@ class AliasedArgumentsEntry: public Struct { static inline AliasedArgumentsEntry* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void AliasedArgumentsEntryPrint() { - AliasedArgumentsEntryPrint(stdout); - } - void AliasedArgumentsEntryPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(AliasedArgumentsEntry) DECLARE_VERIFIER(AliasedArgumentsEntry) static const int kAliasedContextSlot = HeapObject::kHeaderSize; @@ -6979,30 +7213,15 @@ class StringHasher { public: explicit inline StringHasher(int length, uint32_t seed); - // Returns true if the hash of this string can be computed without - // looking at the contents. - inline bool has_trivial_hash(); - - // Add a character to the hash and update the array index calculation. - inline void AddCharacter(uint32_t c); + template <typename schar> + static inline uint32_t HashSequentialString(const schar* chars, + int length, + uint32_t seed); - // Adds a character to the hash but does not update the array index - // calculation. This can only be called when it has been verified - // that the input is not an array index. - inline void AddCharacterNoIndex(uint32_t c); - - // Add a character above 0xffff as a surrogate pair. These can get into - // the hasher through the routines that take a UTF-8 string and make a symbol. - void AddSurrogatePair(uc32 c); - void AddSurrogatePairNoIndex(uc32 c); - - // Returns the value to store in the hash field of a string with - // the given length and contents. - uint32_t GetHashField(); - - // Returns true if the characters seen so far make up a legal array - // index. - bool is_array_index() { return is_array_index_; } + // Reads all the data, even for long strings and computes the utf16 length. + static uint32_t ComputeUtf8Hash(Vector<const char> chars, + uint32_t seed, + int* utf16_length_out); // Calculated hash value for a string consisting of 1 to // String::kMaxArrayIndexSize digits with no leading zeros (except "0"). @@ -7014,51 +7233,36 @@ class StringHasher { // use 27 instead. static const int kZeroHash = 27; - private: - uint32_t array_index() { - ASSERT(is_array_index()); - return array_index_; - } - - 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 AddCharacterCore(uint32_t running_hash, uint16_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_; - 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(); + protected: + // Returns the value to store in the hash field of a string with + // the given length and contents. + uint32_t GetHashField(); + // Returns true if the hash of this string can be computed without + // looking at the contents. + inline bool has_trivial_hash(); + // Adds a block of characters to the hash. + template<typename Char> + inline void AddCharacters(const Char* chars, int len); private: + // Add a character to the hash. + inline void AddCharacter(uint16_t c); + // Update index. Returns true if string is still an index. + inline bool UpdateIndex(uint16_t c); + int length_; uint32_t raw_running_hash_; uint32_t array_index_; bool is_array_index_; - char first_char_; + bool is_first_char_; + DISALLOW_COPY_AND_ASSIGN(StringHasher); }; -// Calculates string hash. -template <typename schar> -inline uint32_t HashSequentialString(const schar* chars, - int length, - uint32_t seed); - - // The characteristics of a string are stored in its map. Retrieving these // few bits of information is moderately expensive, involving two memory // loads where the second is dependent on the first. To improve efficiency @@ -7084,7 +7288,7 @@ class StringShape BASE_EMBEDDED { inline bool IsExternalTwoByte(); inline bool IsSequentialAscii(); inline bool IsSequentialTwoByte(); - inline bool IsSymbol(); + inline bool IsInternalized(); inline StringRepresentationTag representation_tag(); inline uint32_t encoding_tag(); inline uint32_t full_representation_tag(); @@ -7108,6 +7312,112 @@ class StringShape BASE_EMBEDDED { }; +// The Name abstract class captures anything that can be used as a property +// name, i.e., strings and symbols. All names store a hash value. +class Name: public HeapObject { + public: + // Get and set the hash field of the name. + inline uint32_t hash_field(); + inline void set_hash_field(uint32_t value); + + // Tells whether the hash code has been computed. + inline bool HasHashCode(); + + // Returns a hash value used for the property table + inline uint32_t Hash(); + + // Equality operations. + inline bool Equals(Name* other); + + // Conversion. + inline bool AsArrayIndex(uint32_t* index); + + // Casting. + static inline Name* cast(Object* obj); + + DECLARE_PRINTER(Name) + + // Layout description. + static const int kHashFieldOffset = HeapObject::kHeaderSize; + static const int kSize = kHashFieldOffset + kPointerSize; + + // Mask constant for checking if a name has a computed hash code + // and if it is a string that is an array index. The least significant bit + // indicates whether a hash code has been computed. If the hash code has + // been computed the 2nd bit tells whether the string can be used as an + // array index. + static const int kHashNotComputedMask = 1; + static const int kIsNotArrayIndexMask = 1 << 1; + static const int kNofHashBitFields = 2; + + // Shift constant retrieving hash code from hash field. + static const int kHashShift = kNofHashBitFields; + + // Only these bits are relevant in the hash, since the top two are shifted + // out. + static const uint32_t kHashBitMask = 0xffffffffu >> kHashShift; + + // Array index strings this short can keep their index in the hash field. + static const int kMaxCachedArrayIndexLength = 7; + + // For strings which are array indexes the hash value has the string length + // mixed into the hash, mainly to avoid a hash value of zero which would be + // the case for the string '0'. 24 bits are used for the array index value. + static const int kArrayIndexValueBits = 24; + static const int kArrayIndexLengthBits = + kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields; + + STATIC_CHECK((kArrayIndexLengthBits > 0)); + + static const int kArrayIndexHashLengthShift = + kArrayIndexValueBits + kNofHashBitFields; + + static const int kArrayIndexHashMask = (1 << kArrayIndexHashLengthShift) - 1; + + static const int kArrayIndexValueMask = + ((1 << kArrayIndexValueBits) - 1) << kHashShift; + + // Check that kMaxCachedArrayIndexLength + 1 is a power of two so we + // could use a mask to test if the length of string is less than or equal to + // kMaxCachedArrayIndexLength. + STATIC_CHECK(IS_POWER_OF_TWO(kMaxCachedArrayIndexLength + 1)); + + static const int kContainsCachedArrayIndexMask = + (~kMaxCachedArrayIndexLength << kArrayIndexHashLengthShift) | + kIsNotArrayIndexMask; + + // Value of empty hash field indicating that the hash is not computed. + static const int kEmptyHashField = + kIsNotArrayIndexMask | kHashNotComputedMask; + + protected: + static inline bool IsHashFieldComputed(uint32_t field); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Name); +}; + + +// ES6 symbols. +class Symbol: public Name { + public: + // Casting. + static inline Symbol* cast(Object* obj); + + // Dispatched behavior. + DECLARE_PRINTER(Symbol) + DECLARE_VERIFIER(Symbol) + + // Layout description. + static const int kSize = Name::kSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol); +}; + + +class ConsString; + // The String abstract class captures JavaScript string values: // // Ecma-262: @@ -7116,8 +7426,10 @@ class StringShape BASE_EMBEDDED { // ordered sequence of zero or more 16-bit unsigned integer values. // // All string values have a length field. -class String: public HeapObject { +class String: public Name { public: + enum Encoding { ONE_BYTE_ENCODING, TWO_BYTE_ENCODING }; + // Representation of the flat content of a String. // A non-flat string doesn't have flat content. // A flat string has content that's encoded as a sequence of either @@ -7132,11 +7444,11 @@ class String: public HeapObject { // Returns true if the structure contains two-byte content. bool IsTwoByte() { return state_ == TWO_BYTE; } - // Return the ASCII content of the string. Only use if IsAscii() returns + // Return the one byte content of the string. Only use if IsAscii() returns // true. - Vector<const char> ToAsciiVector() { + Vector<const uint8_t> ToOneByteVector() { ASSERT_EQ(ASCII, state_); - return Vector<const char>::cast(buffer_); + return buffer_; } // Return the two-byte content of the string. Only use if IsTwoByte() // returns true. @@ -7149,15 +7461,15 @@ class String: public HeapObject { enum State { NON_FLAT, ASCII, TWO_BYTE }; // Constructors only used by String::GetFlatContent(). - explicit FlatContent(Vector<const char> chars) - : buffer_(Vector<const byte>::cast(chars)), + explicit FlatContent(Vector<const uint8_t> chars) + : buffer_(chars), state_(ASCII) { } explicit FlatContent(Vector<const uc16> chars) : buffer_(Vector<const byte>::cast(chars)), state_(TWO_BYTE) { } FlatContent() : buffer_(), state_(NON_FLAT) { } - Vector<const byte> buffer_; + Vector<const uint8_t> buffer_; State state_; friend class String; @@ -7167,27 +7479,25 @@ class String: public HeapObject { inline int length(); inline void set_length(int value); - // Get and set the hash field of the string. - inline uint32_t hash_field(); - inline void set_hash_field(uint32_t value); - // Returns whether this string has only ASCII chars, i.e. all of them can // be ASCII encoded. This might be the case even if the string is // two-byte. Such strings may appear when the embedder prefers // two-byte external representations even for ASCII data. - inline bool IsAsciiRepresentation(); + inline bool IsOneByteRepresentation(); inline bool IsTwoByteRepresentation(); // Cons and slices have an encoding flag that may not represent the actual // encoding of the underlying string. This is taken into account here. // Requires: this->IsFlat() - inline bool IsAsciiRepresentationUnderneath(); + inline bool IsOneByteRepresentationUnderneath(); inline bool IsTwoByteRepresentationUnderneath(); // NOTE: this should be considered only a hint. False negatives are // possible. inline bool HasOnlyAsciiChars(); + inline bool IsOneByteConvertible(); + // Get and set individual two byte chars in the string. inline void Set(int index, uint16_t value); // Get individual two byte char in the string. Repeated calls @@ -7238,8 +7548,8 @@ class String: public HeapObject { // String equality operations. inline bool Equals(String* other); - bool IsEqualTo(Vector<const char> str); - bool IsAsciiEqualTo(Vector<const char> str); + bool IsUtf8EqualTo(Vector<const char> str); + bool IsOneByteEqualTo(Vector<const uint8_t> str); bool IsTwoByteEqualTo(Vector<const uc16> str); // Return a UTF8 representation of the string. The string is null @@ -7269,19 +7579,7 @@ class String: public HeapObject { SmartArrayPointer<uc16> ToWideCString( RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL); - // Tells whether the hash code has been computed. - inline bool HasHashCode(); - - // Returns a hash value used for the property table - inline uint32_t Hash(); - - static uint32_t ComputeHashField(unibrow::CharacterStream* buffer, - int length, - uint32_t seed); - - static bool ComputeArrayIndex(unibrow::CharacterStream* buffer, - uint32_t* index, - int length); + bool ComputeArrayIndex(uint32_t* index); // Externalization. bool MakeExternal(v8::String::ExternalStringResource* resource); @@ -7313,69 +7611,18 @@ class String: public HeapObject { inline bool IsFlat(); // Layout description. - static const int kLengthOffset = HeapObject::kHeaderSize; - static const int kHashFieldOffset = kLengthOffset + kPointerSize; - static const int kSize = kHashFieldOffset + kPointerSize; + static const int kLengthOffset = Name::kSize; + static const int kSize = kLengthOffset + kPointerSize; // Maximum number of characters to consider when trying to convert a string // value into an array index. static const int kMaxArrayIndexSize = 10; - - // Max ASCII char code. - static const int kMaxAsciiCharCode = unibrow::Utf8::kMaxOneByteChar; - static const unsigned kMaxAsciiCharCodeU = unibrow::Utf8::kMaxOneByteChar; - static const int kMaxUtf16CodeUnit = 0xffff; - - // Mask constant for checking if a string has a computed hash code - // and if it is an array index. The least significant bit indicates - // whether a hash code has been computed. If the hash code has been - // computed the 2nd bit tells whether the string can be used as an - // array index. - static const int kHashNotComputedMask = 1; - static const int kIsNotArrayIndexMask = 1 << 1; - static const int kNofHashBitFields = 2; - - // Shift constant retrieving hash code from hash field. - static const int kHashShift = kNofHashBitFields; - - // Only these bits are relevant in the hash, since the top two are shifted - // out. - static const uint32_t kHashBitMask = 0xffffffffu >> kHashShift; - - // Array index strings this short can keep their index in the hash - // field. - static const int kMaxCachedArrayIndexLength = 7; - - // For strings which are array indexes the hash value has the string length - // mixed into the hash, mainly to avoid a hash value of zero which would be - // the case for the string '0'. 24 bits are used for the array index value. - static const int kArrayIndexValueBits = 24; - static const int kArrayIndexLengthBits = - kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields; - - STATIC_CHECK((kArrayIndexLengthBits > 0)); STATIC_CHECK(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits)); - static const int kArrayIndexHashLengthShift = - kArrayIndexValueBits + kNofHashBitFields; - - static const int kArrayIndexHashMask = (1 << kArrayIndexHashLengthShift) - 1; - - static const int kArrayIndexValueMask = - ((1 << kArrayIndexValueBits) - 1) << kHashShift; - - // Check that kMaxCachedArrayIndexLength + 1 is a power of two so we - // could use a mask to test if the length of string is less than or equal to - // kMaxCachedArrayIndexLength. - STATIC_CHECK(IS_POWER_OF_TWO(kMaxCachedArrayIndexLength + 1)); - - static const int kContainsCachedArrayIndexMask = - (~kMaxCachedArrayIndexLength << kArrayIndexHashLengthShift) | - kIsNotArrayIndexMask; - - // Value of empty hash field indicating that the hash is not computed. - static const int kEmptyHashField = - kIsNotArrayIndexMask | kHashNotComputedMask; + // Max char codes. + static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar; + static const uint32_t kMaxOneByteCharCodeU = unibrow::Latin1::kMaxChar; + static const int kMaxUtf16CodeUnit = 0xffff; // Value of hash field containing computed hash equal to zero. static const int kEmptyStringHash = kIsNotArrayIndexMask; @@ -7394,18 +7641,6 @@ class String: public HeapObject { const uc16* GetTwoByteData(); const uc16* GetTwoByteData(unsigned start); - // Support for StringInputBuffer - static const unibrow::byte* ReadBlock(String* input, - unibrow::byte* util_buffer, - unsigned capacity, - unsigned* remaining, - unsigned* offset); - static const unibrow::byte* ReadBlock(String** input, - unibrow::byte* util_buffer, - unsigned capacity, - unsigned* remaining, - unsigned* offset); - // Helper function for flattening strings. template <typename sinkchar> static void WriteToFlat(String* source, @@ -7420,7 +7655,7 @@ class String: public HeapObject { const char* start = chars; const char* limit = chars + length; #ifdef V8_HOST_CAN_READ_UNALIGNED - ASSERT(kMaxAsciiCharCode == 0x7F); + ASSERT(unibrow::Utf8::kMaxOneByteChar == 0x7F); const uintptr_t non_ascii_mask = kUintptrAllBitsSet / 0xFF * 0x80; while (chars + sizeof(uintptr_t) <= limit) { if (*reinterpret_cast<const uintptr_t*>(chars) & non_ascii_mask) { @@ -7430,7 +7665,7 @@ class String: public HeapObject { } #endif while (chars < limit) { - if (static_cast<uint8_t>(*chars) > kMaxAsciiCharCodeU) { + if (static_cast<uint8_t>(*chars) > unibrow::Utf8::kMaxOneByteChar) { return static_cast<int>(chars - start); } ++chars; @@ -7442,55 +7677,57 @@ class String: public HeapObject { return NonAsciiStart(chars, length) >= length; } - static inline int NonAsciiStart(const uc16* chars, int length) { + static inline bool IsAscii(const uint8_t* chars, int length) { + return + NonAsciiStart(reinterpret_cast<const char*>(chars), length) >= length; + } + + static inline int NonOneByteStart(const uc16* chars, int length) { const uc16* limit = chars + length; const uc16* start = chars; while (chars < limit) { - if (*chars > kMaxAsciiCharCodeU) return static_cast<int>(chars - start); + if (*chars > kMaxOneByteCharCodeU) return static_cast<int>(chars - start); ++chars; } return static_cast<int>(chars - start); } - static inline bool IsAscii(const uc16* chars, int length) { - return NonAsciiStart(chars, length) >= length; + static inline bool IsOneByte(const uc16* chars, int length) { + return NonOneByteStart(chars, length) >= length; } - protected: - class ReadBlockBuffer { - public: - ReadBlockBuffer(unibrow::byte* util_buffer_, - unsigned cursor_, - unsigned capacity_, - unsigned remaining_) : - util_buffer(util_buffer_), - cursor(cursor_), - capacity(capacity_), - remaining(remaining_) { - } - unibrow::byte* util_buffer; - unsigned cursor; - unsigned capacity; - unsigned remaining; - }; + // TODO(dcarney): Replace all instances of this with VisitFlat. + template<class Visitor, class ConsOp> + static inline void Visit(String* string, + unsigned offset, + Visitor& visitor, + ConsOp& cons_op, + int32_t type, + unsigned length); + + template<class Visitor> + static inline ConsString* VisitFlat(Visitor* visitor, + String* string, + int offset, + int length, + int32_t type); - static inline const unibrow::byte* ReadBlock(String* input, - ReadBlockBuffer* buffer, - unsigned* offset, - unsigned max_chars); - static void ReadBlockIntoBuffer(String* input, - ReadBlockBuffer* buffer, - unsigned* offset_ptr, - unsigned max_chars); + template<class Visitor> + static inline ConsString* VisitFlat(Visitor* visitor, + String* string, + int offset = 0) { + int32_t type = string->map()->instance_type(); + return VisitFlat(visitor, string, offset, string->length(), type); + } private: + friend class Name; + // Try to flatten the top level ConsString that is hiding behind this // string. This is a no-op unless the string is a ConsString. Flatten // mutates the ConsString and might return a failure. MUST_USE_RESULT MaybeObject* SlowTryFlatten(PretenureFlag pretenure); - static inline bool IsHashFieldComputed(uint32_t field); - // Slow case of String::Equals. This implementation works on any strings // but it is most efficient on strings that are almost flat. bool SlowEquals(String* other); @@ -7514,6 +7751,11 @@ class SeqString: public String { // Layout description. static const int kHeaderSize = String::kSize; + // Truncate the string in-place if possible and return the result. + // In case of new_length == 0, the empty string is returned without + // truncating the original string. + MUST_USE_RESULT String* Truncate(int new_length); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString); }; @@ -7521,26 +7763,26 @@ class SeqString: public String { // The AsciiString class captures sequential ASCII string objects. // Each character in the AsciiString is an ASCII character. -class SeqAsciiString: public SeqString { +class SeqOneByteString: public SeqString { public: static const bool kHasAsciiEncoding = true; // Dispatched behavior. - inline uint16_t SeqAsciiStringGet(int index); - inline void SeqAsciiStringSet(int index, uint16_t value); + inline uint16_t SeqOneByteStringGet(int index); + inline void SeqOneByteStringSet(int index, uint16_t value); // Get the address of the characters in this string. inline Address GetCharsAddress(); - inline char* GetChars(); + inline uint8_t* GetChars(); // Casting - static inline SeqAsciiString* cast(Object* obj); + static inline SeqOneByteString* cast(Object* obj); // Garbage collection support. This method is called by the // garbage collector to compute the actual size of an AsciiString // instance. - inline int SeqAsciiStringSize(InstanceType instance_type); + inline int SeqOneByteStringSize(InstanceType instance_type); // Computes the size for an AsciiString instance of a given length. static int SizeFor(int length) { @@ -7553,18 +7795,8 @@ class SeqAsciiString: public SeqString { // Q.v. String::kMaxLength which is the maximal size of concatenated strings. static const int kMaxLength = (kMaxSize - kHeaderSize); - // Support for StringInputBuffer. - inline void SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, - unsigned* offset, - unsigned chars); - inline const unibrow::byte* SeqAsciiStringReadBlock(unsigned* remaining, - unsigned* offset, - unsigned chars); - - DECLARE_VERIFIER(SeqAsciiString) - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(SeqAsciiString); + DISALLOW_IMPLICIT_CONSTRUCTORS(SeqOneByteString); }; @@ -7605,11 +7837,6 @@ class SeqTwoByteString: public SeqString { // Q.v. String::kMaxLength which is the maximal size of concatenated strings. static const int kMaxLength = (kMaxSize - kHeaderSize) / sizeof(uint16_t); - // Support for StringInputBuffer. - inline void SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, - unsigned* offset_ptr, - unsigned chars); - private: DISALLOW_IMPLICIT_CONSTRUCTORS(SeqTwoByteString); }; @@ -7652,14 +7879,6 @@ class ConsString: public String { static const int kSecondOffset = kFirstOffset + kPointerSize; static const int kSize = kSecondOffset + kPointerSize; - // Support for StringInputBuffer. - inline const unibrow::byte* ConsStringReadBlock(ReadBlockBuffer* buffer, - unsigned* offset_ptr, - unsigned chars); - inline void ConsStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, - unsigned* offset_ptr, - unsigned chars); - // Minimum length for a cons string. static const int kMinLength = 13; @@ -7704,13 +7923,6 @@ class SlicedString: public String { static const int kOffsetOffset = kParentOffset + kPointerSize; static const int kSize = kOffsetOffset + kPointerSize; - // Support for StringInputBuffer - inline const unibrow::byte* SlicedStringReadBlock(ReadBlockBuffer* buffer, - unsigned* offset_ptr, - unsigned chars); - inline void SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, - unsigned* offset_ptr, - unsigned chars); // Minimum length for a sliced string. static const int kMinLength = 13; @@ -7745,6 +7957,9 @@ class ExternalString: public String { static const int kResourceDataOffset = kResourceOffset + kPointerSize; static const int kSize = kResourceDataOffset + kPointerSize; + static const int kMaxShortLength = + (kShortSize - SeqString::kHeaderSize) / kCharSize; + // Return whether external string is short (data pointer is not cached). inline bool is_short(); @@ -7773,7 +7988,7 @@ class ExternalAsciiString: public ExternalString { // which the pointer cache has to be refreshed. inline void update_data_cache(); - inline const char* GetChars(); + inline const uint8_t* GetChars(); // Dispatched behavior. inline uint16_t ExternalAsciiStringGet(int index); @@ -7787,14 +8002,6 @@ class ExternalAsciiString: public ExternalString { template<typename StaticVisitor> inline void ExternalAsciiStringIterateBody(); - // Support for StringInputBuffer. - const unibrow::byte* ExternalAsciiStringReadBlock(unsigned* remaining, - unsigned* offset, - unsigned chars); - inline void ExternalAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, - unsigned* offset, - unsigned chars); - private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalAsciiString); }; @@ -7835,12 +8042,6 @@ class ExternalTwoByteString: public ExternalString { template<typename StaticVisitor> inline void ExternalTwoByteStringIterateBody(); - - // Support for StringInputBuffer. - void ExternalTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, - unsigned* offset_ptr, - unsigned chars); - private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString); }; @@ -7887,32 +8088,82 @@ class FlatStringReader : public Relocatable { }; -// Note that StringInputBuffers are not valid across a GC! To fix this -// it would have to store a String Handle instead of a String* and -// AsciiStringReadBlock would have to be modified to use memcpy. -// -// StringInputBuffer is able to traverse any string regardless of how -// deeply nested a sequence of ConsStrings it is made of. However, -// performance will be better if deep strings are flattened before they -// are traversed. Since flattening requires memory allocation this is -// not always desirable, however (esp. in debugging situations). -class StringInputBuffer: public unibrow::InputBuffer<String, String*, 1024> { +// A ConsStringOp that returns null. +// Useful when the operation to apply on a ConsString +// requires an expensive data structure. +class ConsStringNullOp { public: - virtual void Seek(unsigned pos); - inline StringInputBuffer(): unibrow::InputBuffer<String, String*, 1024>() {} - explicit inline StringInputBuffer(String* backing): - unibrow::InputBuffer<String, String*, 1024>(backing) {} + inline ConsStringNullOp() {} + static inline String* Operate(String*, unsigned*, int32_t*, unsigned*); + private: + DISALLOW_COPY_AND_ASSIGN(ConsStringNullOp); }; -class SafeStringInputBuffer - : public unibrow::InputBuffer<String, String**, 256> { +// This maintains an off-stack representation of the stack frames required +// to traverse a ConsString, allowing an entirely iterative and restartable +// traversal of the entire string +// Note: this class is not GC-safe. +class ConsStringIteratorOp { public: - virtual void Seek(unsigned pos); - inline SafeStringInputBuffer() - : unibrow::InputBuffer<String, String**, 256>() {} - explicit inline SafeStringInputBuffer(String** backing) - : unibrow::InputBuffer<String, String**, 256>(backing) {} + inline ConsStringIteratorOp() {} + String* Operate(String* string, + unsigned* offset_out, + int32_t* type_out, + unsigned* length_out); + inline String* ContinueOperation(int32_t* type_out, unsigned* length_out); + inline void Reset(); + inline bool HasMore(); + + private: + // TODO(dcarney): Templatize this out for different stack sizes. + static const unsigned kStackSize = 32; + // Use a mask instead of doing modulo operations for stack wrapping. + static const unsigned kDepthMask = kStackSize-1; + STATIC_ASSERT(IS_POWER_OF_TWO(kStackSize)); + static inline unsigned OffsetForDepth(unsigned depth); + + inline void PushLeft(ConsString* string); + inline void PushRight(ConsString* string); + inline void AdjustMaximumDepth(); + inline void Pop(); + String* NextLeaf(bool* blew_stack, int32_t* type_out, unsigned* length_out); + String* Search(unsigned* offset_out, + int32_t* type_out, + unsigned* length_out); + + unsigned depth_; + unsigned maximum_depth_; + // Stack must always contain only frames for which right traversal + // has not yet been performed. + ConsString* frames_[kStackSize]; + unsigned consumed_; + ConsString* root_; + DISALLOW_COPY_AND_ASSIGN(ConsStringIteratorOp); +}; + + +// Note: this class is not GC-safe. +class StringCharacterStream { + public: + inline StringCharacterStream(String* string, + ConsStringIteratorOp* op, + unsigned offset = 0); + inline uint16_t GetNext(); + inline bool HasMore(); + inline void Reset(String* string, unsigned offset = 0); + inline void VisitOneByteString(const uint8_t* chars, unsigned length); + inline void VisitTwoByteString(const uint16_t* chars, unsigned length); + + private: + bool is_one_byte_; + union { + const uint8_t* buffer8_; + const uint16_t* buffer16_; + }; + const uint8_t* end_; + ConsStringIteratorOp* op_; + DISALLOW_COPY_AND_ASSIGN(StringCharacterStream); }; @@ -7996,15 +8247,10 @@ class JSGlobalPropertyCell: public HeapObject { return address() + kValueOffset; } + // Dispatched behavior. + DECLARE_PRINTER(JSGlobalPropertyCell) DECLARE_VERIFIER(JSGlobalPropertyCell) -#ifdef OBJECT_PRINT - inline void JSGlobalPropertyCellPrint() { - JSGlobalPropertyCellPrint(stdout); - } - void JSGlobalPropertyCellPrint(FILE* out); -#endif - // Layout description. static const int kValueOffset = HeapObject::kHeaderSize; static const int kSize = kValueOffset + kPointerSize; @@ -8030,19 +8276,19 @@ class JSProxy: public JSReceiver { // Casting. static inline JSProxy* cast(Object* obj); - bool HasPropertyWithHandler(String* name); + bool HasPropertyWithHandler(Name* name); bool HasElementWithHandler(uint32_t index); MUST_USE_RESULT MaybeObject* GetPropertyWithHandler( Object* receiver, - String* name); + Name* name); MUST_USE_RESULT MaybeObject* GetElementWithHandler( Object* receiver, uint32_t index); MUST_USE_RESULT MaybeObject* SetPropertyWithHandler( JSReceiver* receiver, - String* name, + Name* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode); @@ -8058,14 +8304,14 @@ class JSProxy: public JSReceiver { // otherwise set it to false. MUST_USE_RESULT MaybeObject* SetPropertyViaPrototypesWithHandler( JSReceiver* receiver, - String* name, + Name* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, bool* done); MUST_USE_RESULT MaybeObject* DeletePropertyWithHandler( - String* name, + Name* name, DeleteMode mode); MUST_USE_RESULT MaybeObject* DeleteElementWithHandler( uint32_t index, @@ -8073,7 +8319,7 @@ class JSProxy: public JSReceiver { MUST_USE_RESULT PropertyAttributes GetPropertyAttributeWithHandler( JSReceiver* receiver, - String* name); + Name* name); MUST_USE_RESULT PropertyAttributes GetElementAttributeWithHandler( JSReceiver* receiver, uint32_t index); @@ -8094,12 +8340,7 @@ class JSProxy: public JSReceiver { Handle<Object> args[]); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSProxyPrint() { - JSProxyPrint(stdout); - } - void JSProxyPrint(FILE* out); -#endif + DECLARE_PRINTER(JSProxy) DECLARE_VERIFIER(JSProxy) // Layout description. We add padding so that a proxy has the same @@ -8135,12 +8376,7 @@ class JSFunctionProxy: public JSProxy { static inline JSFunctionProxy* cast(Object* obj); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSFunctionProxyPrint() { - JSFunctionProxyPrint(stdout); - } - void JSFunctionProxyPrint(FILE* out); -#endif + DECLARE_PRINTER(JSFunctionProxy) DECLARE_VERIFIER(JSFunctionProxy) // Layout description. @@ -8170,12 +8406,8 @@ class JSSet: public JSObject { // Casting. static inline JSSet* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void JSSetPrint() { - JSSetPrint(stdout); - } - void JSSetPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(JSSet) DECLARE_VERIFIER(JSSet) static const int kTableOffset = JSObject::kHeaderSize; @@ -8195,12 +8427,8 @@ class JSMap: public JSObject { // Casting. static inline JSMap* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void JSMapPrint() { - JSMapPrint(stdout); - } - void JSMapPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(JSMap) DECLARE_VERIFIER(JSMap) static const int kTableOffset = JSObject::kHeaderSize; @@ -8223,12 +8451,8 @@ class JSWeakMap: public JSObject { // Casting. static inline JSWeakMap* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void JSWeakMapPrint() { - JSWeakMapPrint(stdout); - } - void JSWeakMapPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(JSWeakMap) DECLARE_VERIFIER(JSWeakMap) static const int kTableOffset = JSObject::kHeaderSize; @@ -8258,12 +8482,8 @@ class Foreign: public HeapObject { template<typename StaticVisitor> inline void ForeignIterateBody(); -#ifdef OBJECT_PRINT - inline void ForeignPrint() { - ForeignPrint(stdout); - } - void ForeignPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(Foreign) DECLARE_VERIFIER(Foreign) // Layout description. @@ -8298,10 +8518,11 @@ class JSArray: public JSObject { // Initialize the array with the given capacity. The function may // fail due to out-of-memory situations, but only if the requested // capacity is non-zero. - MUST_USE_RESULT MaybeObject* Initialize(int capacity); + MUST_USE_RESULT MaybeObject* Initialize(int capacity, int length = 0); // Initializes the array to a certain length. inline bool AllowsSetElementsLength(); + // Can cause GC. MUST_USE_RESULT MaybeObject* SetElementsLength(Object* length); // Set the content of the array to the content of storage. @@ -8315,12 +8536,7 @@ class JSArray: public JSObject { inline void EnsureSize(int minimum_size_of_backing_fixed_array); // Dispatched behavior. -#ifdef OBJECT_PRINT - inline void JSArrayPrint() { - JSArrayPrint(stdout); - } - void JSArrayPrint(FILE* out); -#endif + DECLARE_PRINTER(JSArray) DECLARE_VERIFIER(JSArray) // Number of element slots to pre-allocate for an empty array. @@ -8359,20 +8575,8 @@ class JSRegExpResult: public JSArray { }; -// An accessor must have a getter, but can have no setter. -// -// When setting a property, V8 searches accessors in prototypes. -// If an accessor was found and it does not have a setter, -// the request is ignored. -// -// If the accessor in the prototype has the READ_ONLY property attribute, then -// a new value is added to the local object when the property is set. -// This shadows the accessor in the prototype. class AccessorInfo: public Struct { public: - DECL_ACCESSORS(getter, Object) - DECL_ACCESSORS(setter, Object) - DECL_ACCESSORS(data, Object) DECL_ACCESSORS(name, Object) DECL_ACCESSORS(flag, Smi) DECL_ACCESSORS(expected_receiver_type, Object) @@ -8394,18 +8598,11 @@ class AccessorInfo: public Struct { static inline AccessorInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void AccessorInfoPrint() { - AccessorInfoPrint(stdout); - } - void AccessorInfoPrint(FILE* out); -#endif + // Dispatched behavior. 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 kNameOffset = HeapObject::kHeaderSize; static const int kFlagOffset = kNameOffset + kPointerSize; static const int kExpectedReceiverTypeOffset = kFlagOffset + kPointerSize; static const int kSize = kExpectedReceiverTypeOffset + kPointerSize; @@ -8421,6 +8618,146 @@ class AccessorInfo: public Struct { }; +enum AccessorDescriptorType { + kDescriptorBitmaskCompare, + kDescriptorPointerCompare, + kDescriptorPrimitiveValue, + kDescriptorObjectDereference, + kDescriptorPointerDereference, + kDescriptorPointerShift, + kDescriptorReturnObject +}; + + +struct BitmaskCompareDescriptor { + uint32_t bitmask; + uint32_t compare_value; + uint8_t size; // Must be in {1,2,4}. +}; + + +struct PointerCompareDescriptor { + void* compare_value; +}; + + +struct PrimitiveValueDescriptor { + v8::DeclaredAccessorDescriptorDataType data_type; + uint8_t bool_offset; // Must be in [0,7], used for kDescriptorBoolType. +}; + + +struct ObjectDerefenceDescriptor { + uint8_t internal_field; +}; + + +struct PointerShiftDescriptor { + int16_t byte_offset; +}; + + +struct DeclaredAccessorDescriptorData { + AccessorDescriptorType type; + union { + struct BitmaskCompareDescriptor bitmask_compare_descriptor; + struct PointerCompareDescriptor pointer_compare_descriptor; + struct PrimitiveValueDescriptor primitive_value_descriptor; + struct ObjectDerefenceDescriptor object_dereference_descriptor; + struct PointerShiftDescriptor pointer_shift_descriptor; + }; +}; + + +class DeclaredAccessorDescriptor; + + +class DeclaredAccessorDescriptorIterator { + public: + explicit DeclaredAccessorDescriptorIterator( + DeclaredAccessorDescriptor* descriptor); + const DeclaredAccessorDescriptorData* Next(); + bool Complete() const { return length_ == offset_; } + private: + uint8_t* array_; + const int length_; + int offset_; + DISALLOW_IMPLICIT_CONSTRUCTORS(DeclaredAccessorDescriptorIterator); +}; + + +class DeclaredAccessorDescriptor: public Struct { + public: + DECL_ACCESSORS(serialized_data, ByteArray) + + static inline DeclaredAccessorDescriptor* cast(Object* obj); + + static Handle<DeclaredAccessorDescriptor> Create( + Isolate* isolate, + const DeclaredAccessorDescriptorData& data, + Handle<DeclaredAccessorDescriptor> previous); + + // Dispatched behavior. + DECLARE_PRINTER(DeclaredAccessorDescriptor) + DECLARE_VERIFIER(DeclaredAccessorDescriptor) + + static const int kSerializedDataOffset = HeapObject::kHeaderSize; + static const int kSize = kSerializedDataOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DeclaredAccessorDescriptor); +}; + + +class DeclaredAccessorInfo: public AccessorInfo { + public: + DECL_ACCESSORS(descriptor, DeclaredAccessorDescriptor) + + static inline DeclaredAccessorInfo* cast(Object* obj); + + // Dispatched behavior. + DECLARE_PRINTER(DeclaredAccessorInfo) + DECLARE_VERIFIER(DeclaredAccessorInfo) + + static const int kDescriptorOffset = AccessorInfo::kSize; + static const int kSize = kDescriptorOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DeclaredAccessorInfo); +}; + + +// An accessor must have a getter, but can have no setter. +// +// When setting a property, V8 searches accessors in prototypes. +// If an accessor was found and it does not have a setter, +// the request is ignored. +// +// If the accessor in the prototype has the READ_ONLY property attribute, then +// a new value is added to the local object when the property is set. +// This shadows the accessor in the prototype. +class ExecutableAccessorInfo: public AccessorInfo { + public: + DECL_ACCESSORS(getter, Object) + DECL_ACCESSORS(setter, Object) + DECL_ACCESSORS(data, Object) + + static inline ExecutableAccessorInfo* cast(Object* obj); + + // Dispatched behavior. + DECLARE_PRINTER(ExecutableAccessorInfo) + DECLARE_VERIFIER(ExecutableAccessorInfo) + + static const int kGetterOffset = AccessorInfo::kSize; + static const int kSetterOffset = kGetterOffset + kPointerSize; + static const int kDataOffset = kSetterOffset + kPointerSize; + static const int kSize = kDataOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExecutableAccessorInfo); +}; + + // Support for JavaScript accessors: A pair of a getter and a setter. Each // accessor can either be // * a pointer to a JavaScript function or proxy: a real accessor @@ -8461,9 +8798,8 @@ class AccessorPair: public Struct { return IsJSAccessor(getter()) || IsJSAccessor(setter()); } -#ifdef OBJECT_PRINT - void AccessorPairPrint(FILE* out = stdout); -#endif + // Dispatched behavior. + DECLARE_PRINTER(AccessorPair) DECLARE_VERIFIER(AccessorPair) static const int kGetterOffset = HeapObject::kHeaderSize; @@ -8492,12 +8828,8 @@ class AccessCheckInfo: public Struct { static inline AccessCheckInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void AccessCheckInfoPrint() { - AccessCheckInfoPrint(stdout); - } - void AccessCheckInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(AccessCheckInfo) DECLARE_VERIFIER(AccessCheckInfo) static const int kNamedCallbackOffset = HeapObject::kHeaderSize; @@ -8521,12 +8853,8 @@ class InterceptorInfo: public Struct { static inline InterceptorInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void InterceptorInfoPrint() { - InterceptorInfoPrint(stdout); - } - void InterceptorInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(InterceptorInfo) DECLARE_VERIFIER(InterceptorInfo) static const int kGetterOffset = HeapObject::kHeaderSize; @@ -8549,12 +8877,8 @@ class CallHandlerInfo: public Struct { static inline CallHandlerInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void CallHandlerInfoPrint() { - CallHandlerInfoPrint(stdout); - } - void CallHandlerInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(CallHandlerInfo) DECLARE_VERIFIER(CallHandlerInfo) static const int kCallbackOffset = HeapObject::kHeaderSize; @@ -8598,6 +8922,9 @@ class FunctionTemplateInfo: public TemplateInfo { DECL_ACCESSORS(access_check_info, Object) DECL_ACCESSORS(flag, Smi) + inline int length(); + inline void set_length(int value); + // Following properties use flag bits. DECL_BOOLEAN_ACCESSORS(hidden_prototype) DECL_BOOLEAN_ACCESSORS(undetectable) @@ -8608,12 +8935,8 @@ class FunctionTemplateInfo: public TemplateInfo { static inline FunctionTemplateInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void FunctionTemplateInfoPrint() { - FunctionTemplateInfoPrint(stdout); - } - void FunctionTemplateInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(FunctionTemplateInfo) DECLARE_VERIFIER(FunctionTemplateInfo) static const int kSerialNumberOffset = TemplateInfo::kHeaderSize; @@ -8635,7 +8958,8 @@ class FunctionTemplateInfo: public TemplateInfo { static const int kAccessCheckInfoOffset = kInstanceCallHandlerOffset + kPointerSize; static const int kFlagOffset = kAccessCheckInfoOffset + kPointerSize; - static const int kSize = kFlagOffset + kPointerSize; + static const int kLengthOffset = kFlagOffset + kPointerSize; + static const int kSize = kLengthOffset + kPointerSize; private: // Bit position in the flag, from least significant bit position. @@ -8655,12 +8979,8 @@ class ObjectTemplateInfo: public TemplateInfo { static inline ObjectTemplateInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void ObjectTemplateInfoPrint() { - ObjectTemplateInfoPrint(stdout); - } - void ObjectTemplateInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(ObjectTemplateInfo) DECLARE_VERIFIER(ObjectTemplateInfo) static const int kConstructorOffset = TemplateInfo::kHeaderSize; @@ -8677,12 +8997,8 @@ class SignatureInfo: public Struct { static inline SignatureInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void SignatureInfoPrint() { - SignatureInfoPrint(stdout); - } - void SignatureInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(SignatureInfo) DECLARE_VERIFIER(SignatureInfo) static const int kReceiverOffset = Struct::kHeaderSize; @@ -8700,12 +9016,8 @@ class TypeSwitchInfo: public Struct { static inline TypeSwitchInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void TypeSwitchInfoPrint() { - TypeSwitchInfoPrint(stdout); - } - void TypeSwitchInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(TypeSwitchInfo) DECLARE_VERIFIER(TypeSwitchInfo) static const int kTypesOffset = Struct::kHeaderSize; @@ -8750,12 +9062,8 @@ class DebugInfo: public Struct { static inline DebugInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void DebugInfoPrint() { - DebugInfoPrint(stdout); - } - void DebugInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(DebugInfo) DECLARE_VERIFIER(DebugInfo) static const int kSharedFunctionInfoIndex = Struct::kHeaderSize; @@ -8806,12 +9114,8 @@ class BreakPointInfo: public Struct { static inline BreakPointInfo* cast(Object* obj); -#ifdef OBJECT_PRINT - inline void BreakPointInfoPrint() { - BreakPointInfoPrint(stdout); - } - void BreakPointInfoPrint(FILE* out); -#endif + // Dispatched behavior. + DECLARE_PRINTER(BreakPointInfo) DECLARE_VERIFIER(BreakPointInfo) static const int kCodePositionIndex = Struct::kHeaderSize; @@ -8833,10 +9137,10 @@ class BreakPointInfo: public Struct { #undef DECLARE_VERIFIER #define VISITOR_SYNCHRONIZATION_TAGS_LIST(V) \ - V(kSymbolTable, "symbol_table", "(Symbols)") \ + V(kStringTable, "string_table", "(Internalized strings)") \ V(kExternalStringsTable, "external_strings_table", "(External strings)") \ V(kStrongRootList, "strong_root_list", "(Strong roots)") \ - V(kSymbol, "symbol", "(Symbol)") \ + V(kInternalizedString, "internalized_string", "(Internal string)") \ V(kBootstrapper, "bootstrapper", "(Bootstrapper)") \ V(kTop, "top", "(Isolate)") \ V(kRelocatable, "relocatable", "(Relocatable)") \ @@ -8895,6 +9199,10 @@ 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); } |