Upgrade to 3.29
Update V8 to 3.29.88.17 and update makefiles to support building on
all the relevant platforms.
Bug: 17370214
Change-Id: Ia3407c157fd8d72a93e23d8318ccaf6ecf77fa4e
diff --git a/src/objects.h b/src/objects.h
index ccd07ff..3340350 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1,190 +1,247 @@
// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#ifndef V8_OBJECTS_H_
#define V8_OBJECTS_H_
-#include "allocation.h"
-#include "builtins.h"
-#include "list.h"
-#include "property-details.h"
-#include "smart-array-pointer.h"
-#include "unicode-inl.h"
+#include "src/allocation.h"
+#include "src/assert-scope.h"
+#include "src/bailout-reason.h"
+#include "src/base/bits.h"
+#include "src/builtins.h"
+#include "src/checks.h"
+#include "src/elements-kind.h"
+#include "src/field-index.h"
+#include "src/flags.h"
+#include "src/list.h"
+#include "src/property-details.h"
+#include "src/smart-pointers.h"
+#include "src/unicode-inl.h"
+#include "src/zone.h"
+
#if V8_TARGET_ARCH_ARM
-#include "arm/constants-arm.h"
+#include "src/arm/constants-arm.h" // NOLINT
+#elif V8_TARGET_ARCH_ARM64
+#include "src/arm64/constants-arm64.h" // NOLINT
#elif V8_TARGET_ARCH_MIPS
-#include "mips/constants-mips.h"
+#include "src/mips/constants-mips.h" // NOLINT
+#elif V8_TARGET_ARCH_MIPS64
+#include "src/mips64/constants-mips64.h" // NOLINT
#endif
-#include "v8checks.h"
//
// Most object types in the V8 JavaScript are described in this file.
//
// Inheritance hierarchy:
-// - MaybeObject (an object or a failure)
-// - Failure (immediate for marking failed operation)
-// - Object
-// - Smi (immediate small integer)
-// - HeapObject (superclass for everything allocated in the heap)
-// - JSReceiver (suitable for property access)
-// - JSObject
-// - JSArray
+// - Object
+// - Smi (immediate small integer)
+// - HeapObject (superclass for everything allocated in the heap)
+// - JSReceiver (suitable for property access)
+// - JSObject
+// - JSArray
+// - JSArrayBuffer
+// - JSArrayBufferView
+// - JSTypedArray
+// - JSDataView
+// - JSCollection
// - JSSet
// - JSMap
+// - JSSetIterator
+// - JSMapIterator
+// - JSWeakCollection
// - JSWeakMap
-// - JSRegExp
-// - JSFunction
-// - GlobalObject
-// - JSGlobalObject
-// - JSBuiltinsObject
-// - JSGlobalProxy
-// - JSValue
-// - JSDate
-// - JSMessageObject
-// - JSProxy
-// - JSFunctionProxy
-// - FixedArrayBase
-// - ByteArray
-// - FixedArray
-// - DescriptorArray
-// - HashTable
-// - Dictionary
-// - SymbolTable
-// - CompilationCacheTable
-// - CodeCacheHashTable
-// - MapCache
-// - Context
-// - JSFunctionResultCache
-// - ScopeInfo
-// - FixedDoubleArray
-// - ExternalArray
-// - ExternalPixelArray
-// - ExternalByteArray
-// - ExternalUnsignedByteArray
-// - ExternalShortArray
-// - ExternalUnsignedShortArray
-// - ExternalIntArray
-// - ExternalUnsignedIntArray
-// - ExternalFloatArray
+// - JSWeakSet
+// - JSRegExp
+// - JSFunction
+// - JSGeneratorObject
+// - JSModule
+// - GlobalObject
+// - JSGlobalObject
+// - JSBuiltinsObject
+// - JSGlobalProxy
+// - JSValue
+// - JSDate
+// - JSMessageObject
+// - JSProxy
+// - JSFunctionProxy
+// - FixedArrayBase
+// - ByteArray
+// - FixedArray
+// - DescriptorArray
+// - HashTable
+// - Dictionary
+// - StringTable
+// - CompilationCacheTable
+// - CodeCacheHashTable
+// - MapCache
+// - OrderedHashTable
+// - OrderedHashSet
+// - OrderedHashMap
+// - Context
+// - TypeFeedbackVector
+// - JSFunctionResultCache
+// - ScopeInfo
+// - TransitionArray
+// - FixedDoubleArray
+// - ExternalArray
+// - ExternalUint8ClampedArray
+// - ExternalInt8Array
+// - ExternalUint8Array
+// - ExternalInt16Array
+// - ExternalUint16Array
+// - ExternalInt32Array
+// - ExternalUint32Array
+// - ExternalFloat32Array
+// - Name
// - String
// - SeqString
-// - SeqAsciiString
+// - SeqOneByteString
// - SeqTwoByteString
// - SlicedString
// - ConsString
// - ExternalString
-// - ExternalAsciiString
+// - ExternalOneByteString
// - ExternalTwoByteString
-// - HeapNumber
-// - Code
-// - Map
-// - Oddball
-// - Foreign
-// - SharedFunctionInfo
-// - Struct
-// - AccessorInfo
-// - AccessorPair
-// - AccessCheckInfo
-// - InterceptorInfo
-// - CallHandlerInfo
-// - TemplateInfo
-// - FunctionTemplateInfo
-// - ObjectTemplateInfo
-// - Script
-// - SignatureInfo
-// - TypeSwitchInfo
-// - DebugInfo
-// - BreakPointInfo
-// - CodeCache
+// - InternalizedString
+// - SeqInternalizedString
+// - SeqOneByteInternalizedString
+// - SeqTwoByteInternalizedString
+// - ConsInternalizedString
+// - ExternalInternalizedString
+// - ExternalOneByteInternalizedString
+// - ExternalTwoByteInternalizedString
+// - Symbol
+// - HeapNumber
+// - Cell
+// - PropertyCell
+// - Code
+// - Map
+// - Oddball
+// - Foreign
+// - SharedFunctionInfo
+// - Struct
+// - Box
+// - DeclaredAccessorDescriptor
+// - AccessorInfo
+// - DeclaredAccessorInfo
+// - ExecutableAccessorInfo
+// - AccessorPair
+// - AccessCheckInfo
+// - InterceptorInfo
+// - CallHandlerInfo
+// - TemplateInfo
+// - FunctionTemplateInfo
+// - ObjectTemplateInfo
+// - Script
+// - SignatureInfo
+// - TypeSwitchInfo
+// - DebugInfo
+// - BreakPointInfo
+// - CodeCache
//
// Formats of Object*:
// Smi: [31 bit signed int] 0
// HeapObject: [32 bit direct pointer] (4 byte aligned) | 01
-// Failure: [30 bit signed int] 11
namespace v8 {
namespace internal {
-enum ElementsKind {
- // The "fast" kind for elements that only contain SMI values. Must be first
- // to make it possible to efficiently check maps for this kind.
- FAST_SMI_ONLY_ELEMENTS,
+class OStream;
- // The "fast" kind for tagged values. Must be second to make it possible to
- // efficiently check maps for this and the FAST_SMI_ONLY_ELEMENTS kind
- // together at once.
- FAST_ELEMENTS,
-
- // The "fast" kind for unwrapped, non-tagged double values.
- FAST_DOUBLE_ELEMENTS,
-
- // The "slow" kind.
- DICTIONARY_ELEMENTS,
- NON_STRICT_ARGUMENTS_ELEMENTS,
- // The "fast" kind for external arrays
- EXTERNAL_BYTE_ELEMENTS,
- EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
- EXTERNAL_SHORT_ELEMENTS,
- EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
- EXTERNAL_INT_ELEMENTS,
- EXTERNAL_UNSIGNED_INT_ELEMENTS,
- EXTERNAL_FLOAT_ELEMENTS,
- EXTERNAL_DOUBLE_ELEMENTS,
- EXTERNAL_PIXEL_ELEMENTS,
-
- // Derived constants from ElementsKind
- FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS,
- LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
- FIRST_ELEMENTS_KIND = FAST_SMI_ONLY_ELEMENTS,
- LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS
+enum 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
};
-enum CompareMapMode {
- REQUIRE_EXACT_MAP,
- ALLOW_ELEMENT_TRANSITION_MAPS
+
+enum ContextualMode {
+ NOT_CONTEXTUAL,
+ CONTEXTUAL
};
-enum KeyedAccessGrowMode {
- DO_NOT_ALLOW_JSARRAY_GROWTH,
- ALLOW_JSARRAY_GROWTH
+
+enum MutableMode {
+ MUTABLE,
+ IMMUTABLE
};
-const int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
-void PrintElementsKind(FILE* out, ElementsKind kind);
+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);
-inline bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
- ElementsKind to_kind);
+
+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 };
+// Indicates whether a value can be loaded as a constant.
+enum StoreMode {
+ ALLOW_AS_CONSTANT,
+ FORCE_FIELD
+};
+
+
// PropertyNormalizationMode is used to specify whether to keep
// inobject properties when normalizing properties of a JSObject.
enum PropertyNormalizationMode {
@@ -193,24 +250,68 @@
};
-// NormalizedMapSharingMode is used to specify whether a map may be shared
-// by different objects with normalized properties.
-enum NormalizedMapSharingMode {
- UNIQUE_NORMALIZED_MAP,
- SHARED_NORMALIZED_MAP
+// Indicates how aggressively the prototype should be optimized. FAST_PROTOTYPE
+// will give the fastest result by tailoring the map to the prototype, but that
+// will cause polymorphism with other objects. REGULAR_PROTOTYPE is to be used
+// (at least for now) when dynamically modifying the prototype chain of an
+// object using __proto__ or Object.setPrototypeOf.
+enum PrototypeOptimizationMode { REGULAR_PROTOTYPE, FAST_PROTOTYPE };
+
+
+// Indicates whether transitions can be added to a source map or not.
+enum TransitionFlag {
+ INSERT_TRANSITION,
+ OMIT_TRANSITION
};
-// Indicates whether a get method should implicitly create the object looked up.
-enum CreationFlag {
- ALLOW_CREATION,
- OMIT_CREATION
+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.
+enum SimpleTransitionFlag {
+ SIMPLE_TRANSITION,
+ FULL_TRANSITION
+};
+
+
+// Indicates whether we are only interested in the descriptors of a particular
+// map, or in all descriptors in the descriptor array.
+enum DescriptorFlag {
+ ALL_DESCRIPTORS,
+ OWN_DESCRIPTORS
+};
+
+// The GC maintains a bit of information, the MarkingParity, which toggles
+// from odd to even and back every time marking is completed. Incremental
+// marking can visit an object twice during a marking phase, so algorithms that
+// that piggy-back on marking can use the parity to ensure that they only
+// perform an operation on an object once per marking phase: they record the
+// MarkingParity when they visit an object, and only re-visit the object when it
+// is marked again and the MarkingParity changes.
+enum MarkingParity {
+ NO_MARKING_PARITY,
+ ODD_MARKING_PARITY,
+ EVEN_MARKING_PARITY
+};
+
+// ICs store extra state in a Code object. The default extra state is
+// kNoExtraICState.
+typedef int ExtraICState;
+static const ExtraICState kNoExtraICState = 0;
+
// Instance size sentinel for objects of variable size.
const int kVariableSizeSentinel = 0;
+// We may store the unsigned bit field as signed Smi value and do not
+// use the sign bit.
+const int kStubMajorKeyBits = 7;
+const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
// All Maps have a field instance_type containing a InstanceType.
// It describes the type of the instances.
@@ -220,12 +321,12 @@
//
// The names of the string instance types are intended to systematically
// mirror their encoding in the instance_type field of the map. The default
-// encoding is considered TWO_BYTE. It is not mentioned in the name. ASCII
+// encoding is considered TWO_BYTE. It is not mentioned in the name. ONE_BYTE
// 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:
@@ -235,192 +336,172 @@
// NOTE: Everything following JS_VALUE_TYPE is considered a
// 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(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(MAP_TYPE) \
- V(CODE_TYPE) \
- V(ODDBALL_TYPE) \
- V(JS_GLOBAL_PROPERTY_CELL_TYPE) \
- \
- V(HEAP_NUMBER_TYPE) \
- V(FOREIGN_TYPE) \
- V(BYTE_ARRAY_TYPE) \
- V(FREE_SPACE_TYPE) \
- /* Note: the order of these external array */ \
- /* types is relied upon in */ \
- /* Object::IsExternalArray(). */ \
- V(EXTERNAL_BYTE_ARRAY_TYPE) \
- V(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE) \
- V(EXTERNAL_SHORT_ARRAY_TYPE) \
- V(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE) \
- V(EXTERNAL_INT_ARRAY_TYPE) \
- V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE) \
- V(EXTERNAL_FLOAT_ARRAY_TYPE) \
- V(EXTERNAL_PIXEL_ARRAY_TYPE) \
- V(FILLER_TYPE) \
- \
- V(ACCESSOR_INFO_TYPE) \
- V(ACCESSOR_PAIR_TYPE) \
- V(ACCESS_CHECK_INFO_TYPE) \
- V(INTERCEPTOR_INFO_TYPE) \
- V(CALL_HANDLER_INFO_TYPE) \
- V(FUNCTION_TEMPLATE_INFO_TYPE) \
- V(OBJECT_TEMPLATE_INFO_TYPE) \
- V(SIGNATURE_INFO_TYPE) \
- V(TYPE_SWITCH_INFO_TYPE) \
- V(SCRIPT_TYPE) \
- V(CODE_CACHE_TYPE) \
- V(POLYMORPHIC_CODE_CACHE_TYPE) \
- V(TYPE_FEEDBACK_INFO_TYPE) \
- V(ALIASED_ARGUMENTS_ENTRY_TYPE) \
- \
- V(FIXED_ARRAY_TYPE) \
- V(FIXED_DOUBLE_ARRAY_TYPE) \
- V(SHARED_FUNCTION_INFO_TYPE) \
- \
- V(JS_MESSAGE_OBJECT_TYPE) \
- \
- V(JS_VALUE_TYPE) \
- V(JS_DATE_TYPE) \
- V(JS_OBJECT_TYPE) \
- V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
- V(JS_GLOBAL_OBJECT_TYPE) \
- V(JS_BUILTINS_OBJECT_TYPE) \
- V(JS_GLOBAL_PROXY_TYPE) \
- V(JS_ARRAY_TYPE) \
- V(JS_PROXY_TYPE) \
- V(JS_WEAK_MAP_TYPE) \
- V(JS_REGEXP_TYPE) \
- \
- V(JS_FUNCTION_TYPE) \
- V(JS_FUNCTION_PROXY_TYPE) \
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
-#define INSTANCE_TYPE_LIST_DEBUGGER(V) \
- V(DEBUG_INFO_TYPE) \
+#define INSTANCE_TYPE_LIST(V) \
+ V(STRING_TYPE) \
+ V(ONE_BYTE_STRING_TYPE) \
+ V(CONS_STRING_TYPE) \
+ V(CONS_ONE_BYTE_STRING_TYPE) \
+ V(SLICED_STRING_TYPE) \
+ V(SLICED_ONE_BYTE_STRING_TYPE) \
+ V(EXTERNAL_STRING_TYPE) \
+ V(EXTERNAL_ONE_BYTE_STRING_TYPE) \
+ V(EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE) \
+ V(SHORT_EXTERNAL_STRING_TYPE) \
+ V(SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE) \
+ V(SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE) \
+ \
+ V(INTERNALIZED_STRING_TYPE) \
+ V(ONE_BYTE_INTERNALIZED_STRING_TYPE) \
+ V(EXTERNAL_INTERNALIZED_STRING_TYPE) \
+ V(EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE) \
+ V(EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE) \
+ V(SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE) \
+ V(SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE) \
+ V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE) \
+ \
+ V(SYMBOL_TYPE) \
+ \
+ V(MAP_TYPE) \
+ V(CODE_TYPE) \
+ V(ODDBALL_TYPE) \
+ V(CELL_TYPE) \
+ V(PROPERTY_CELL_TYPE) \
+ \
+ V(HEAP_NUMBER_TYPE) \
+ V(MUTABLE_HEAP_NUMBER_TYPE) \
+ V(FOREIGN_TYPE) \
+ V(BYTE_ARRAY_TYPE) \
+ V(FREE_SPACE_TYPE) \
+ /* Note: the order of these external array */ \
+ /* types is relied upon in */ \
+ /* Object::IsExternalArray(). */ \
+ V(EXTERNAL_INT8_ARRAY_TYPE) \
+ V(EXTERNAL_UINT8_ARRAY_TYPE) \
+ V(EXTERNAL_INT16_ARRAY_TYPE) \
+ V(EXTERNAL_UINT16_ARRAY_TYPE) \
+ V(EXTERNAL_INT32_ARRAY_TYPE) \
+ V(EXTERNAL_UINT32_ARRAY_TYPE) \
+ V(EXTERNAL_FLOAT32_ARRAY_TYPE) \
+ V(EXTERNAL_FLOAT64_ARRAY_TYPE) \
+ V(EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE) \
+ \
+ V(FIXED_INT8_ARRAY_TYPE) \
+ V(FIXED_UINT8_ARRAY_TYPE) \
+ V(FIXED_INT16_ARRAY_TYPE) \
+ V(FIXED_UINT16_ARRAY_TYPE) \
+ V(FIXED_INT32_ARRAY_TYPE) \
+ V(FIXED_UINT32_ARRAY_TYPE) \
+ V(FIXED_FLOAT32_ARRAY_TYPE) \
+ V(FIXED_FLOAT64_ARRAY_TYPE) \
+ V(FIXED_UINT8_CLAMPED_ARRAY_TYPE) \
+ \
+ V(FILLER_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) \
+ V(CALL_HANDLER_INFO_TYPE) \
+ V(FUNCTION_TEMPLATE_INFO_TYPE) \
+ V(OBJECT_TEMPLATE_INFO_TYPE) \
+ V(SIGNATURE_INFO_TYPE) \
+ V(TYPE_SWITCH_INFO_TYPE) \
+ V(ALLOCATION_MEMENTO_TYPE) \
+ V(ALLOCATION_SITE_TYPE) \
+ V(SCRIPT_TYPE) \
+ V(CODE_CACHE_TYPE) \
+ V(POLYMORPHIC_CODE_CACHE_TYPE) \
+ V(TYPE_FEEDBACK_INFO_TYPE) \
+ V(ALIASED_ARGUMENTS_ENTRY_TYPE) \
+ V(BOX_TYPE) \
+ \
+ V(FIXED_ARRAY_TYPE) \
+ V(FIXED_DOUBLE_ARRAY_TYPE) \
+ V(CONSTANT_POOL_ARRAY_TYPE) \
+ V(SHARED_FUNCTION_INFO_TYPE) \
+ \
+ V(JS_MESSAGE_OBJECT_TYPE) \
+ \
+ V(JS_VALUE_TYPE) \
+ V(JS_DATE_TYPE) \
+ V(JS_OBJECT_TYPE) \
+ V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
+ V(JS_GENERATOR_OBJECT_TYPE) \
+ V(JS_MODULE_TYPE) \
+ V(JS_GLOBAL_OBJECT_TYPE) \
+ V(JS_BUILTINS_OBJECT_TYPE) \
+ V(JS_GLOBAL_PROXY_TYPE) \
+ V(JS_ARRAY_TYPE) \
+ V(JS_ARRAY_BUFFER_TYPE) \
+ V(JS_TYPED_ARRAY_TYPE) \
+ V(JS_DATA_VIEW_TYPE) \
+ V(JS_PROXY_TYPE) \
+ V(JS_SET_TYPE) \
+ V(JS_MAP_TYPE) \
+ V(JS_SET_ITERATOR_TYPE) \
+ V(JS_MAP_ITERATOR_TYPE) \
+ V(JS_WEAK_MAP_TYPE) \
+ V(JS_WEAK_SET_TYPE) \
+ V(JS_REGEXP_TYPE) \
+ \
+ V(JS_FUNCTION_TYPE) \
+ V(JS_FUNCTION_PROXY_TYPE) \
+ V(DEBUG_INFO_TYPE) \
V(BREAK_POINT_INFO_TYPE)
-#else
-#define INSTANCE_TYPE_LIST_DEBUGGER(V)
-#endif
-
-#define INSTANCE_TYPE_LIST(V) \
- INSTANCE_TYPE_LIST_ALL(V) \
- INSTANCE_TYPE_LIST_DEBUGGER(V)
// 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, \
- String) \
- V(ASCII_STRING_TYPE, \
- kVariableSizeSentinel, \
- ascii_string, \
- AsciiString) \
- V(CONS_STRING_TYPE, \
- ConsString::kSize, \
- cons_string, \
- ConsString) \
- V(CONS_ASCII_STRING_TYPE, \
- ConsString::kSize, \
- cons_ascii_string, \
- ConsAsciiString) \
- V(SLICED_STRING_TYPE, \
- SlicedString::kSize, \
- sliced_string, \
- SlicedString) \
- V(SLICED_ASCII_STRING_TYPE, \
- SlicedString::kSize, \
- sliced_ascii_string, \
- SlicedAsciiString) \
- V(EXTERNAL_STRING_TYPE, \
- 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(SHORT_EXTERNAL_STRING_TYPE, \
- ExternalTwoByteString::kShortSize, \
- short_external_string, \
- ShortExternalString) \
- V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \
- ExternalTwoByteString::kShortSize, \
- short_external_string_with_ascii_data, \
- ShortExternalStringWithAsciiData) \
- V(SHORT_EXTERNAL_ASCII_STRING_TYPE, \
- ExternalAsciiString::kShortSize, \
- short_external_ascii_string, \
- ShortExternalAsciiString)
+#define STRING_TYPE_LIST(V) \
+ V(STRING_TYPE, kVariableSizeSentinel, string, String) \
+ V(ONE_BYTE_STRING_TYPE, kVariableSizeSentinel, one_byte_string, \
+ OneByteString) \
+ V(CONS_STRING_TYPE, ConsString::kSize, cons_string, ConsString) \
+ V(CONS_ONE_BYTE_STRING_TYPE, ConsString::kSize, cons_one_byte_string, \
+ ConsOneByteString) \
+ V(SLICED_STRING_TYPE, SlicedString::kSize, sliced_string, SlicedString) \
+ V(SLICED_ONE_BYTE_STRING_TYPE, SlicedString::kSize, sliced_one_byte_string, \
+ SlicedOneByteString) \
+ V(EXTERNAL_STRING_TYPE, ExternalTwoByteString::kSize, external_string, \
+ ExternalString) \
+ V(EXTERNAL_ONE_BYTE_STRING_TYPE, ExternalOneByteString::kSize, \
+ external_one_byte_string, ExternalOneByteString) \
+ V(EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE, ExternalTwoByteString::kSize, \
+ external_string_with_one_byte_data, ExternalStringWithOneByteData) \
+ V(SHORT_EXTERNAL_STRING_TYPE, ExternalTwoByteString::kShortSize, \
+ short_external_string, ShortExternalString) \
+ V(SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE, ExternalOneByteString::kShortSize, \
+ short_external_one_byte_string, ShortExternalOneByteString) \
+ V(SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE, \
+ ExternalTwoByteString::kShortSize, \
+ short_external_string_with_one_byte_data, \
+ ShortExternalStringWithOneByteData) \
+ \
+ V(INTERNALIZED_STRING_TYPE, kVariableSizeSentinel, internalized_string, \
+ InternalizedString) \
+ V(ONE_BYTE_INTERNALIZED_STRING_TYPE, kVariableSizeSentinel, \
+ one_byte_internalized_string, OneByteInternalizedString) \
+ V(EXTERNAL_INTERNALIZED_STRING_TYPE, ExternalTwoByteString::kSize, \
+ external_internalized_string, ExternalInternalizedString) \
+ V(EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE, ExternalOneByteString::kSize, \
+ external_one_byte_internalized_string, ExternalOneByteInternalizedString) \
+ V(EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE, \
+ ExternalTwoByteString::kSize, \
+ external_internalized_string_with_one_byte_data, \
+ ExternalInternalizedStringWithOneByteData) \
+ V(SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE, \
+ ExternalTwoByteString::kShortSize, short_external_internalized_string, \
+ ShortExternalInternalizedString) \
+ V(SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE, \
+ ExternalOneByteString::kShortSize, \
+ short_external_one_byte_internalized_string, \
+ ShortExternalOneByteInternalizedString) \
+ V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE, \
+ ExternalTwoByteString::kShortSize, \
+ short_external_internalized_string_with_one_byte_data, \
+ ShortExternalInternalizedStringWithOneByteData)
// 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
@@ -431,8 +512,13 @@
// Note that for subtle reasons related to the ordering or numerical values of
// 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) \
+#define STRUCT_LIST(V) \
+ V(BOX, Box, box) \
+ 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) \
@@ -442,22 +528,14 @@
V(SIGNATURE_INFO, SignatureInfo, signature_info) \
V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \
V(SCRIPT, Script, script) \
+ V(ALLOCATION_SITE, AllocationSite, allocation_site) \
+ V(ALLOCATION_MEMENTO, AllocationMemento, allocation_memento) \
V(CODE_CACHE, CodeCache, code_cache) \
V(POLYMORPHIC_CODE_CACHE, PolymorphicCodeCache, polymorphic_code_cache) \
V(TYPE_FEEDBACK_INFO, TypeFeedbackInfo, type_feedback_info) \
- V(ALIASED_ARGUMENTS_ENTRY, AliasedArgumentsEntry, aliased_arguments_entry)
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
-#define STRUCT_LIST_DEBUGGER(V) \
+ V(ALIASED_ARGUMENTS_ENTRY, AliasedArgumentsEntry, aliased_arguments_entry) \
V(DEBUG_INFO, DebugInfo, debug_info) \
V(BREAK_POINT_INFO, BreakPointInfo, break_point_info)
-#else
-#define STRUCT_LIST_DEBUGGER(V)
-#endif
-
-#define STRUCT_LIST(V) \
- STRUCT_LIST_ALL(V) \
- STRUCT_LIST_DEBUGGER(V)
// We use the full 8 bits of the instance_type field to encode heap object
// instance types. The high-order bit (bit 7) is set if the object is not a
@@ -466,18 +544,17 @@
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).
-// 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;
+// Bit 6 indicates that the object is an internalized string (if set) or not.
+// Bit 7 has to be clear as well.
+const uint32_t kIsNotInternalizedMask = 0x40;
+const uint32_t kNotInternalizedTag = 0x40;
+const uint32_t kInternalizedTag = 0x0;
// 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.
@@ -490,22 +567,22 @@
};
const uint32_t kIsIndirectStringMask = 0x1;
const uint32_t kIsIndirectStringTag = 0x1;
-STATIC_ASSERT((kSeqStringTag & kIsIndirectStringMask) == 0);
-STATIC_ASSERT((kExternalStringTag & kIsIndirectStringMask) == 0);
-STATIC_ASSERT(
- (kConsStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);
-STATIC_ASSERT(
- (kSlicedStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);
+STATIC_ASSERT((kSeqStringTag & kIsIndirectStringMask) == 0); // NOLINT
+STATIC_ASSERT((kExternalStringTag & kIsIndirectStringMask) == 0); // NOLINT
+STATIC_ASSERT((kConsStringTag &
+ kIsIndirectStringMask) == kIsIndirectStringTag); // NOLINT
+STATIC_ASSERT((kSlicedStringTag &
+ kIsIndirectStringMask) == kIsIndirectStringTag); // NOLINT
// Use this mask to distinguish between cons and slice only after making
// sure that the string is one of the two (an indirect string).
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
-STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
+STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask));
// If bit 7 is clear, then bit 3 indicates whether this two-byte
-// string actually contains ASCII data.
-const uint32_t kAsciiDataHintMask = 0x08;
-const uint32_t kAsciiDataHintTag = 0x08;
+// string actually contains one byte data.
+const uint32_t kOneByteDataHintMask = 0x08;
+const uint32_t kOneByteDataHintTag = 0x08;
// If bit 7 is clear and string representation indicates an external string,
// then bit 4 indicates whether the data pointer is cached.
@@ -514,81 +591,111 @@
// 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. We don't allocate any
+// non-flat internalized strings, so we do not shortcut them thereby
+// avoiding turning internalized strings into strings. The bit-masks
+// below contain the internalized bit as additional safety.
+// See heap.cc, mark-compact.cc and objects-visiting.cc.
const uint32_t kShortcutTypeMask =
kIsNotStringMask |
- kIsSymbolMask |
+ kIsNotInternalizedMask |
kStringRepresentationMask;
-const uint32_t kShortcutTypeTag = kConsStringTag;
+const uint32_t kShortcutTypeTag = kConsStringTag | kNotInternalizedTag;
+
+static inline bool IsShortcutCandidate(int type) {
+ return ((type & kShortcutTypeMask) == kShortcutTypeTag);
+}
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,
- CONS_STRING_TYPE = kTwoByteStringTag | kConsStringTag,
- CONS_ASCII_STRING_TYPE = kAsciiStringTag | kConsStringTag,
- SLICED_STRING_TYPE = kTwoByteStringTag | kSlicedStringTag,
- SLICED_ASCII_STRING_TYPE = kAsciiStringTag | kSlicedStringTag,
+ INTERNALIZED_STRING_TYPE =
+ kTwoByteStringTag | kSeqStringTag | kInternalizedTag,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE =
+ kOneByteStringTag | kSeqStringTag | kInternalizedTag,
+ EXTERNAL_INTERNALIZED_STRING_TYPE =
+ kTwoByteStringTag | kExternalStringTag | kInternalizedTag,
+ EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE =
+ kOneByteStringTag | kExternalStringTag | kInternalizedTag,
+ EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE =
+ EXTERNAL_INTERNALIZED_STRING_TYPE | kOneByteDataHintTag |
+ kInternalizedTag,
+ SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE = EXTERNAL_INTERNALIZED_STRING_TYPE |
+ kShortExternalStringTag |
+ kInternalizedTag,
+ SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE =
+ EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kShortExternalStringTag |
+ kInternalizedTag,
+ SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE =
+ EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE |
+ kShortExternalStringTag | kInternalizedTag,
+ STRING_TYPE = INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
+ ONE_BYTE_STRING_TYPE =
+ ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
+ CONS_STRING_TYPE = kTwoByteStringTag | kConsStringTag | kNotInternalizedTag,
+ CONS_ONE_BYTE_STRING_TYPE =
+ kOneByteStringTag | kConsStringTag | kNotInternalizedTag,
+ SLICED_STRING_TYPE =
+ kTwoByteStringTag | kSlicedStringTag | kNotInternalizedTag,
+ SLICED_ONE_BYTE_STRING_TYPE =
+ kOneByteStringTag | kSlicedStringTag | kNotInternalizedTag,
+ EXTERNAL_STRING_TYPE =
+ EXTERNAL_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
+ EXTERNAL_ONE_BYTE_STRING_TYPE =
+ EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
+ EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE =
+ EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE |
+ kNotInternalizedTag,
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,
- EXTERNAL_STRING_TYPE = kTwoByteStringTag | 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,
+ SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
+ SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE =
+ SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
+ SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE =
+ SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE |
+ kNotInternalizedTag,
+
+ // Non-string names
+ SYMBOL_TYPE = kNotStringTag, // FIRST_NONSTRING_TYPE, LAST_NAME_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,
+ CELL_TYPE,
+ PROPERTY_CELL_TYPE,
// "Data", objects that cannot contain non-map-word pointers to heap
// objects.
HEAP_NUMBER_TYPE,
+ MUTABLE_HEAP_NUMBER_TYPE,
FOREIGN_TYPE,
BYTE_ARRAY_TYPE,
FREE_SPACE_TYPE,
- EXTERNAL_BYTE_ARRAY_TYPE, // FIRST_EXTERNAL_ARRAY_TYPE
- EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
- EXTERNAL_SHORT_ARRAY_TYPE,
- EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
- EXTERNAL_INT_ARRAY_TYPE,
- EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
- EXTERNAL_FLOAT_ARRAY_TYPE,
- EXTERNAL_DOUBLE_ARRAY_TYPE,
- EXTERNAL_PIXEL_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE
+ EXTERNAL_INT8_ARRAY_TYPE, // FIRST_EXTERNAL_ARRAY_TYPE
+ EXTERNAL_UINT8_ARRAY_TYPE,
+ EXTERNAL_INT16_ARRAY_TYPE,
+ EXTERNAL_UINT16_ARRAY_TYPE,
+ EXTERNAL_INT32_ARRAY_TYPE,
+ EXTERNAL_UINT32_ARRAY_TYPE,
+ EXTERNAL_FLOAT32_ARRAY_TYPE,
+ EXTERNAL_FLOAT64_ARRAY_TYPE,
+ EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE
+ FIXED_INT8_ARRAY_TYPE, // FIRST_FIXED_TYPED_ARRAY_TYPE
+ FIXED_UINT8_ARRAY_TYPE,
+ FIXED_INT16_ARRAY_TYPE,
+ FIXED_UINT16_ARRAY_TYPE,
+ FIXED_INT32_ARRAY_TYPE,
+ FIXED_UINT32_ARRAY_TYPE,
+ FIXED_FLOAT32_ARRAY_TYPE,
+ FIXED_FLOAT64_ARRAY_TYPE,
+ FIXED_UINT8_CLAMPED_ARRAY_TYPE, // LAST_FIXED_TYPED_ARRAY_TYPE
FIXED_DOUBLE_ARRAY_TYPE,
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,
@@ -597,55 +704,64 @@
OBJECT_TEMPLATE_INFO_TYPE,
SIGNATURE_INFO_TYPE,
TYPE_SWITCH_INFO_TYPE,
+ ALLOCATION_SITE_TYPE,
+ ALLOCATION_MEMENTO_TYPE,
SCRIPT_TYPE,
CODE_CACHE_TYPE,
POLYMORPHIC_CODE_CACHE_TYPE,
TYPE_FEEDBACK_INFO_TYPE,
ALIASED_ARGUMENTS_ENTRY_TYPE,
- // The following two instance types are only used when ENABLE_DEBUGGER_SUPPORT
- // is defined. However as include/v8.h contain some of the instance type
- // constants always having them avoids them getting different numbers
- // depending on whether ENABLE_DEBUGGER_SUPPORT is defined or not.
+ BOX_TYPE,
DEBUG_INFO_TYPE,
BREAK_POINT_INFO_TYPE,
-
FIXED_ARRAY_TYPE,
+ CONSTANT_POOL_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
- JS_MESSAGE_OBJECT_TYPE,
-
// All the following types are subtypes of JSReceiver, which corresponds to
// objects in the JS sense. The first and the last type in this range are
// the two forms of function. This organization enables using the same
// compares for checking the JS_RECEIVER/SPEC_OBJECT range and the
// NONCALLABLE_JS_OBJECT range.
JS_FUNCTION_PROXY_TYPE, // FIRST_JS_RECEIVER_TYPE, FIRST_JS_PROXY_TYPE
- JS_PROXY_TYPE, // LAST_JS_PROXY_TYPE
-
- JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE
+ JS_PROXY_TYPE, // LAST_JS_PROXY_TYPE
+ JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE
+ JS_MESSAGE_OBJECT_TYPE,
JS_DATE_TYPE,
JS_OBJECT_TYPE,
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
+ JS_GENERATOR_OBJECT_TYPE,
+ JS_MODULE_TYPE,
JS_GLOBAL_OBJECT_TYPE,
JS_BUILTINS_OBJECT_TYPE,
JS_GLOBAL_PROXY_TYPE,
JS_ARRAY_TYPE,
+ JS_ARRAY_BUFFER_TYPE,
+ JS_TYPED_ARRAY_TYPE,
+ JS_DATA_VIEW_TYPE,
JS_SET_TYPE,
JS_MAP_TYPE,
+ JS_SET_ITERATOR_TYPE,
+ JS_MAP_ITERATOR_TYPE,
JS_WEAK_MAP_TYPE,
-
+ JS_WEAK_SET_TYPE,
JS_REGEXP_TYPE,
-
JS_FUNCTION_TYPE, // LAST_JS_OBJECT_TYPE, LAST_JS_RECEIVER_TYPE
// Pseudo-types
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,
+ FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_INT8_ARRAY_TYPE,
+ LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE,
+ // Boundaries for testing for a fixed typed array.
+ FIRST_FIXED_TYPED_ARRAY_TYPE = FIXED_INT8_ARRAY_TYPE,
+ LAST_FIXED_TYPED_ARRAY_TYPE = FIXED_UINT8_CLAMPED_ARRAY_TYPE,
// Boundary for promotion to old data space/old pointer space.
LAST_DATA_TYPE = FILLER_TYPE,
// Boundary for objects represented as JSReceiver (i.e. JSObject or JSProxy).
@@ -675,9 +791,29 @@
const int kExternalArrayTypeCount =
LAST_EXTERNAL_ARRAY_TYPE - FIRST_EXTERNAL_ARRAY_TYPE + 1;
-STATIC_CHECK(JS_OBJECT_TYPE == Internals::kJSObjectType);
-STATIC_CHECK(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);
-STATIC_CHECK(FOREIGN_TYPE == Internals::kForeignType);
+STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);
+STATIC_ASSERT(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);
+STATIC_ASSERT(ODDBALL_TYPE == Internals::kOddballType);
+STATIC_ASSERT(FOREIGN_TYPE == Internals::kForeignType);
+
+
+#define FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(V) \
+ V(FAST_ELEMENTS_SUB_TYPE) \
+ V(DICTIONARY_ELEMENTS_SUB_TYPE) \
+ V(FAST_PROPERTIES_SUB_TYPE) \
+ V(DICTIONARY_PROPERTIES_SUB_TYPE) \
+ V(MAP_CODE_CACHE_SUB_TYPE) \
+ V(SCOPE_INFO_SUB_TYPE) \
+ V(STRING_TABLE_SUB_TYPE) \
+ V(DESCRIPTOR_ARRAY_SUB_TYPE) \
+ V(TRANSITION_ARRAY_SUB_TYPE)
+
+enum FixedArraySubInstanceType {
+#define DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE(name) name,
+ FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE)
+#undef DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE
+ LAST_FIXED_ARRAY_SUB_TYPE = TRANSITION_ARRAY_SUB_TYPE
+};
enum CompareResult {
@@ -690,212 +826,265 @@
#define DECL_BOOLEAN_ACCESSORS(name) \
- inline bool name(); \
+ inline bool name() const; \
inline void set_##name(bool value); \
#define DECL_ACCESSORS(name, type) \
- inline type* name(); \
+ inline type* name() const; \
inline void set_##name(type* value, \
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
+#define DECLARE_CAST(type) \
+ INLINE(static type* cast(Object* object)); \
+ INLINE(static const type* cast(const Object* object));
+
+
+class AccessorPair;
+class AllocationSite;
+class AllocationSiteCreationContext;
+class AllocationSiteUsageContext;
class DictionaryElementsAccessor;
class ElementsAccessor;
class FixedArrayBase;
+class GlobalObject;
class ObjectVisitor;
+class LookupIterator;
class StringStream;
-class Failure;
-
-struct ValueInfo : public Malloced {
- ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { }
- InstanceType type;
- Object* ptr;
- const char* str;
- double number;
-};
+class TypeFeedbackVector;
+// We cannot just say "class HeapType;" if it is created from a template... =8-?
+template<class> class TypeImpl;
+struct HeapTypeConfig;
+typedef TypeImpl<HeapTypeConfig> HeapType;
// A template-ized version of the IsXXX functions.
-template <class C> static inline bool Is(Object* obj);
+template <class C> inline bool Is(Object* obj);
-
-class MaybeObject BASE_EMBEDDED {
- public:
- inline bool IsFailure();
- inline bool IsRetryAfterGC();
- inline bool IsOutOfMemory();
- inline bool IsException();
- INLINE(bool IsTheHole());
- inline bool ToObject(Object** obj) {
- if (IsFailure()) return false;
- *obj = reinterpret_cast<Object*>(this);
- return true;
- }
- inline Failure* ToFailureUnchecked() {
- ASSERT(IsFailure());
- return reinterpret_cast<Failure*>(this);
- }
- inline Object* ToObjectUnchecked() {
- ASSERT(!IsFailure());
- return reinterpret_cast<Object*>(this);
- }
- inline Object* ToObjectChecked() {
- CHECK(!IsFailure());
- return reinterpret_cast<Object*>(this);
- }
-
- template<typename T>
- inline bool To(T** obj) {
- if (IsFailure()) return false;
- *obj = T::cast(reinterpret_cast<Object*>(this));
- return true;
- }
+#ifdef VERIFY_HEAP
+#define DECLARE_VERIFIER(Name) void Name##Verify();
+#else
+#define DECLARE_VERIFIER(Name)
+#endif
#ifdef OBJECT_PRINT
- // Prints this object with details.
- inline void Print() {
- Print(stdout);
- }
- inline void PrintLn() {
- PrintLn(stdout);
- }
- void Print(FILE* out);
- void PrintLn(FILE* out);
+#define DECLARE_PRINTER(Name) void Name##Print(OStream& os); // NOLINT
+#else
+#define DECLARE_PRINTER(Name)
#endif
-#ifdef DEBUG
- // Verifies the object.
- void Verify();
-#endif
-};
-#define OBJECT_TYPE_LIST(V) \
- V(Smi) \
- V(HeapObject) \
- V(Number) \
+#define OBJECT_TYPE_LIST(V) \
+ V(Smi) \
+ V(HeapObject) \
+ V(Number)
-#define HEAP_OBJECT_TYPE_LIST(V) \
- V(HeapNumber) \
- V(String) \
- V(Symbol) \
- V(SeqString) \
- V(ExternalString) \
- V(ConsString) \
- V(SlicedString) \
- V(ExternalTwoByteString) \
- V(ExternalAsciiString) \
- V(SeqTwoByteString) \
- V(SeqAsciiString) \
- \
- V(ExternalArray) \
- V(ExternalByteArray) \
- V(ExternalUnsignedByteArray) \
- V(ExternalShortArray) \
- V(ExternalUnsignedShortArray) \
- V(ExternalIntArray) \
- V(ExternalUnsignedIntArray) \
- V(ExternalFloatArray) \
- V(ExternalDoubleArray) \
- V(ExternalPixelArray) \
- V(ByteArray) \
- V(FreeSpace) \
- V(JSReceiver) \
- V(JSObject) \
- V(JSContextExtensionObject) \
- V(Map) \
- V(DescriptorArray) \
- V(DeoptimizationInputData) \
- V(DeoptimizationOutputData) \
- V(TypeFeedbackCells) \
- V(FixedArray) \
- V(FixedDoubleArray) \
- V(Context) \
- V(GlobalContext) \
- V(ScopeInfo) \
- V(JSFunction) \
- V(Code) \
- V(Oddball) \
- V(SharedFunctionInfo) \
- V(JSValue) \
- V(JSDate) \
- V(JSMessageObject) \
- V(StringWrapper) \
- V(Foreign) \
- V(Boolean) \
- V(JSArray) \
- V(JSProxy) \
- V(JSFunctionProxy) \
- V(JSSet) \
- V(JSMap) \
- V(JSWeakMap) \
- V(JSRegExp) \
- V(HashTable) \
- V(Dictionary) \
- V(SymbolTable) \
- V(JSFunctionResultCache) \
- V(NormalizedMapCache) \
- V(CompilationCacheTable) \
- V(CodeCacheHashTable) \
- V(PolymorphicCodeCacheHashTable) \
- V(MapCache) \
- V(Primitive) \
- V(GlobalObject) \
- V(JSGlobalObject) \
- V(JSBuiltinsObject) \
- V(JSGlobalProxy) \
- V(UndetectableObject) \
- V(AccessCheckNeeded) \
- V(JSGlobalPropertyCell) \
-
-
-class JSReceiver;
+#define HEAP_OBJECT_TYPE_LIST(V) \
+ V(HeapNumber) \
+ V(MutableHeapNumber) \
+ V(Name) \
+ V(UniqueName) \
+ V(String) \
+ V(SeqString) \
+ V(ExternalString) \
+ V(ConsString) \
+ V(SlicedString) \
+ V(ExternalTwoByteString) \
+ V(ExternalOneByteString) \
+ V(SeqTwoByteString) \
+ V(SeqOneByteString) \
+ V(InternalizedString) \
+ V(Symbol) \
+ \
+ V(ExternalArray) \
+ V(ExternalInt8Array) \
+ V(ExternalUint8Array) \
+ V(ExternalInt16Array) \
+ V(ExternalUint16Array) \
+ V(ExternalInt32Array) \
+ V(ExternalUint32Array) \
+ V(ExternalFloat32Array) \
+ V(ExternalFloat64Array) \
+ V(ExternalUint8ClampedArray) \
+ V(FixedTypedArrayBase) \
+ V(FixedUint8Array) \
+ V(FixedInt8Array) \
+ V(FixedUint16Array) \
+ V(FixedInt16Array) \
+ V(FixedUint32Array) \
+ V(FixedInt32Array) \
+ V(FixedFloat32Array) \
+ V(FixedFloat64Array) \
+ V(FixedUint8ClampedArray) \
+ V(ByteArray) \
+ V(FreeSpace) \
+ V(JSReceiver) \
+ V(JSObject) \
+ V(JSContextExtensionObject) \
+ V(JSGeneratorObject) \
+ V(JSModule) \
+ V(Map) \
+ V(DescriptorArray) \
+ V(TransitionArray) \
+ V(TypeFeedbackVector) \
+ V(DeoptimizationInputData) \
+ V(DeoptimizationOutputData) \
+ V(DependentCode) \
+ V(FixedArray) \
+ V(FixedDoubleArray) \
+ V(ConstantPoolArray) \
+ V(Context) \
+ V(NativeContext) \
+ V(ScopeInfo) \
+ V(JSFunction) \
+ V(Code) \
+ V(Oddball) \
+ V(SharedFunctionInfo) \
+ V(JSValue) \
+ V(JSDate) \
+ V(JSMessageObject) \
+ V(StringWrapper) \
+ V(Foreign) \
+ V(Boolean) \
+ V(JSArray) \
+ V(JSArrayBuffer) \
+ V(JSArrayBufferView) \
+ V(JSTypedArray) \
+ V(JSDataView) \
+ V(JSProxy) \
+ V(JSFunctionProxy) \
+ V(JSSet) \
+ V(JSMap) \
+ V(JSSetIterator) \
+ V(JSMapIterator) \
+ V(JSWeakCollection) \
+ V(JSWeakMap) \
+ V(JSWeakSet) \
+ V(JSRegExp) \
+ V(HashTable) \
+ V(Dictionary) \
+ V(StringTable) \
+ V(JSFunctionResultCache) \
+ V(NormalizedMapCache) \
+ V(CompilationCacheTable) \
+ V(CodeCacheHashTable) \
+ V(PolymorphicCodeCacheHashTable) \
+ V(MapCache) \
+ V(Primitive) \
+ V(GlobalObject) \
+ V(JSGlobalObject) \
+ V(JSBuiltinsObject) \
+ V(JSGlobalProxy) \
+ V(UndetectableObject) \
+ V(AccessCheckNeeded) \
+ V(Cell) \
+ V(PropertyCell) \
+ V(ObjectHashTable) \
+ V(WeakHashTable) \
+ V(OrderedHashTable)
// Object is the abstract superclass for all classes in the
// object hierarchy.
// Object does not use any virtual functions to avoid the
// allocation of the C++ vtable.
-// Since Smi and Failure are subclasses of Object no
+// Since both Smi and HeapObject are subclasses of Object no
// data members can be present in Object.
-class Object : public MaybeObject {
+class Object {
public:
// Type testing.
- bool IsObject() { return true; }
+ bool IsObject() const { return true; }
-#define IS_TYPE_FUNCTION_DECL(type_) inline bool Is##type_();
+#define IS_TYPE_FUNCTION_DECL(type_) INLINE(bool Is##type_() const);
OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL)
HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL)
#undef IS_TYPE_FUNCTION_DECL
- inline bool IsFixedArrayBase();
+ // A non-keyed store is of the form a.x = foo or a["x"] = foo whereas
+ // a keyed store is of the form a[expression] = foo.
+ enum StoreFromKeyed {
+ MAY_BE_STORE_FROM_KEYED,
+ CERTAINLY_NOT_STORE_FROM_KEYED
+ };
- // Returns true if this object is an instance of the specified
- // function template.
- inline bool IsInstanceOf(FunctionTemplateInfo* type);
+ INLINE(bool IsFixedArrayBase() const);
+ INLINE(bool IsExternal() const);
+ INLINE(bool IsAccessorInfo() const);
- inline bool IsStruct();
-#define DECLARE_STRUCT_PREDICATE(NAME, Name, name) inline bool Is##Name();
+ INLINE(bool IsStruct() const);
+#define DECLARE_STRUCT_PREDICATE(NAME, Name, name) \
+ INLINE(bool Is##Name() const);
STRUCT_LIST(DECLARE_STRUCT_PREDICATE)
#undef DECLARE_STRUCT_PREDICATE
- INLINE(bool IsSpecObject());
- INLINE(bool IsSpecFunction());
+ INLINE(bool IsSpecObject()) const;
+ INLINE(bool IsSpecFunction()) const;
+ INLINE(bool IsTemplateInfo()) const;
+ INLINE(bool IsNameDictionary() const);
+ INLINE(bool IsSeededNumberDictionary() const);
+ INLINE(bool IsUnseededNumberDictionary() const);
+ INLINE(bool IsOrderedHashSet() const);
+ INLINE(bool IsOrderedHashMap() const);
+ bool IsCallable() const;
// Oddball testing.
- INLINE(bool IsUndefined());
- INLINE(bool IsNull());
- INLINE(bool IsTheHole()); // Shadows MaybeObject's implementation.
- INLINE(bool IsTrue());
- INLINE(bool IsFalse());
- inline bool IsArgumentsMarker();
- inline bool NonFailureIsHeapObject();
+ INLINE(bool IsUndefined() const);
+ INLINE(bool IsNull() const);
+ INLINE(bool IsTheHole() const);
+ INLINE(bool IsException() const);
+ INLINE(bool IsUninitialized() const);
+ INLINE(bool IsTrue() const);
+ INLINE(bool IsFalse() const);
+ INLINE(bool IsArgumentsMarker() const);
// Filler objects (fillers and free space objects).
- inline bool IsFiller();
+ INLINE(bool IsFiller() const);
// Extract the number.
inline double Number();
- inline bool IsNaN();
+ INLINE(bool IsNaN() const);
+ INLINE(bool IsMinusZero() const);
+ bool ToInt32(int32_t* value);
+ bool ToUint32(uint32_t* value);
+
+ inline Representation OptimalRepresentation() {
+ if (!FLAG_track_fields) return Representation::Tagged();
+ if (IsSmi()) {
+ return Representation::Smi();
+ } else if (FLAG_track_double_fields && IsHeapNumber()) {
+ return Representation::Double();
+ } else if (FLAG_track_computed_fields && IsUninitialized()) {
+ return Representation::None();
+ } else if (FLAG_track_heap_object_fields) {
+ DCHECK(IsHeapObject());
+ return Representation::HeapObject();
+ } else {
+ return Representation::Tagged();
+ }
+ }
+
+ inline bool FitsRepresentation(Representation representation) {
+ if (FLAG_track_fields && representation.IsNone()) {
+ return false;
+ } else if (FLAG_track_fields && representation.IsSmi()) {
+ return IsSmi();
+ } else if (FLAG_track_double_fields && representation.IsDouble()) {
+ return IsMutableHeapNumber() || IsNumber();
+ } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
+ return IsHeapObject();
+ }
+ return true;
+ }
+
+ Handle<HeapType> OptimalType(Isolate* isolate, Representation representation);
+
+ inline static Handle<Object> NewStorageFor(Isolate* isolate,
+ Handle<Object> object,
+ Representation representation);
+
+ inline static Handle<Object> WrapForRead(Isolate* isolate,
+ Handle<Object> object,
+ Representation representation);
// Returns true if the object is of the correct type to be used as a
// implementation of a JSObject's elements.
@@ -903,63 +1092,98 @@
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.
- // global_context is used when creating wrapper object.
- MUST_USE_RESULT MaybeObject* ToObject(Context* global_context);
+ // native_context is used when creating wrapper object.
+ static inline MaybeHandle<JSReceiver> ToObject(Isolate* isolate,
+ Handle<Object> object);
+ static MaybeHandle<JSReceiver> ToObject(Isolate* isolate,
+ Handle<Object> object,
+ Handle<Context> context);
// Converts this to a Smi if possible.
- // Failure is returned otherwise.
- MUST_USE_RESULT inline MaybeObject* ToSmi();
+ static MUST_USE_RESULT inline MaybeHandle<Smi> ToSmi(Isolate* isolate,
+ Handle<Object> object);
- void Lookup(String* name, LookupResult* result);
+ MUST_USE_RESULT static MaybeHandle<Object> GetProperty(LookupIterator* it);
- // Property access.
- MUST_USE_RESULT inline MaybeObject* GetProperty(String* key);
- MUST_USE_RESULT inline MaybeObject* GetProperty(
- String* key,
- PropertyAttributes* attributes);
- MUST_USE_RESULT MaybeObject* GetPropertyWithReceiver(
- Object* receiver,
- String* key,
- PropertyAttributes* attributes);
+ // Implementation of [[Put]], ECMA-262 5th edition, section 8.12.5.
+ MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
+ Handle<Object> object, Handle<Name> key, Handle<Object> value,
+ StrictMode strict_mode,
+ StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED);
- static Handle<Object> GetProperty(Handle<Object> object,
- Handle<Object> receiver,
- LookupResult* result,
- Handle<String> key,
- PropertyAttributes* attributes);
+ MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
+ LookupIterator* it, Handle<Object> value, StrictMode strict_mode,
+ StoreFromKeyed store_mode);
+ MUST_USE_RESULT static MaybeHandle<Object> WriteToReadOnlyProperty(
+ LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
+ static Handle<Object> SetDataProperty(LookupIterator* it,
+ Handle<Object> value);
+ MUST_USE_RESULT static MaybeHandle<Object> AddDataProperty(
+ LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
+ StrictMode strict_mode, StoreFromKeyed store_mode);
+ MUST_USE_RESULT static inline MaybeHandle<Object> GetPropertyOrElement(
+ Handle<Object> object,
+ Handle<Name> key);
+ MUST_USE_RESULT static inline MaybeHandle<Object> GetProperty(
+ Isolate* isolate,
+ Handle<Object> object,
+ const char* key);
+ MUST_USE_RESULT static inline MaybeHandle<Object> GetProperty(
+ Handle<Object> object,
+ Handle<Name> key);
- MUST_USE_RESULT MaybeObject* GetProperty(Object* receiver,
- LookupResult* result,
- String* key,
- PropertyAttributes* attributes);
+ MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithAccessor(
+ Handle<Object> receiver,
+ Handle<Name> name,
+ Handle<JSObject> holder,
+ Handle<Object> structure);
+ MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithAccessor(
+ Handle<Object> receiver, Handle<Name> name, Handle<Object> value,
+ Handle<JSObject> holder, Handle<Object> structure,
+ StrictMode strict_mode);
- MUST_USE_RESULT MaybeObject* GetPropertyWithDefinedGetter(Object* receiver,
- JSReceiver* getter);
+ MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithDefinedGetter(
+ Handle<Object> receiver,
+ Handle<JSReceiver> getter);
+ MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithDefinedSetter(
+ Handle<Object> receiver,
+ Handle<JSReceiver> setter,
+ Handle<Object> value);
- static Handle<Object> GetElement(Handle<Object> object, uint32_t index);
- MUST_USE_RESULT inline MaybeObject* GetElement(uint32_t index);
- // For use when we know that no exception can be thrown.
- inline Object* GetElementNoExceptionThrown(uint32_t index);
- MUST_USE_RESULT MaybeObject* GetElementWithReceiver(Object* receiver,
- uint32_t index);
+ MUST_USE_RESULT static inline MaybeHandle<Object> GetElement(
+ Isolate* isolate,
+ Handle<Object> object,
+ uint32_t index);
- // Return the object's prototype (might be Heap::null_value()).
- Object* GetPrototype();
+ MUST_USE_RESULT static MaybeHandle<Object> GetElementWithReceiver(
+ Isolate* isolate,
+ Handle<Object> object,
+ Handle<Object> receiver,
+ uint32_t index);
+
+ // Returns the permanent hash code associated with this object. May return
+ // undefined if not yet created.
+ Object* GetHash();
// Returns the permanent hash code associated with this object depending on
- // the actual object type. Might return a failure in case no hash was
- // created yet or GC was caused by creation.
- MUST_USE_RESULT MaybeObject* GetHash(CreationFlag flag);
+ // the actual object type. May create and store a hash code if needed and none
+ // exists.
+ static Handle<Smi> GetOrCreateHash(Isolate* isolate, Handle<Object> object);
// Checks whether this object has the same value as the given one. This
// function is implemented according to ES5, section 9.12 and can be used
// to implement the Harmony "egal" function.
bool SameValue(Object* other);
+ // Checks whether this object has the same value as the given one.
+ // +0 and -0 are treated equal. Everything else is the same as SameValue.
+ // This function is implemented according to ES6, section 7.2.4 and is used
+ // by ES6 Map and Set.
+ bool SameValueZero(Object* other);
+
// Tries to convert an object to an array index. Returns true and sets
// the output parameter if it succeeds.
inline bool ToArrayIndex(uint32_t* index);
@@ -968,31 +1192,53 @@
// < the length of the string. Used to implement [] on strings.
inline bool IsStringObjectWithCharacterAt(uint32_t index);
-#ifdef DEBUG
+ DECLARE_VERIFIER(Object)
+#ifdef VERIFY_HEAP
// Verify a pointer is a valid object pointer.
static void VerifyPointer(Object* p);
#endif
+ inline void VerifyApiCallResultType();
+
// Prints this object without details.
- inline void ShortPrint() {
- ShortPrint(stdout);
- }
- void ShortPrint(FILE* out);
+ void ShortPrint(FILE* out = stdout);
// Prints this object without details to a message accumulator.
void ShortPrint(StringStream* accumulator);
- // Casting: This cast is only needed to satisfy macros in objects-inl.h.
- static Object* cast(Object* value) { return value; }
+ DECLARE_CAST(Object)
// Layout description.
static const int kHeaderSize = 0; // Object does not take up any space.
+#ifdef OBJECT_PRINT
+ // For our gdb macros, we should perhaps change these in the future.
+ void Print();
+
+ // Prints this object with details.
+ void Print(OStream& os); // NOLINT
+#endif
+
private:
+ friend class LookupIterator;
+ friend class PrototypeIterator;
+
+ // Return the map of the root of object's prototype chain.
+ Map* GetRootMap(Isolate* isolate);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
};
+struct Brief {
+ explicit Brief(const Object* const v) : value(v) {}
+ const Object* value;
+};
+
+
+OStream& operator<<(OStream& os, const Brief& v);
+
+
// Smi represents integer Numbers that can be stored in 31 bits.
// Smis are immediate which means they are NOT allocated in the heap.
// The this pointer has the following format: [31 bit signed int] 0
@@ -1002,7 +1248,7 @@
class Smi: public Object {
public:
// Returns the integer value.
- inline int value();
+ inline int value() const;
// Convert a value to a Smi object.
static inline Smi* FromInt(int value);
@@ -1012,18 +1258,11 @@
// Returns whether value can be represented in a Smi.
static inline bool IsValid(intptr_t value);
- // Casting.
- static inline Smi* cast(Object* object);
+ DECLARE_CAST(Smi)
// Dispatched behavior.
- inline void SmiPrint() {
- SmiPrint(stdout);
- }
- void SmiPrint(FILE* out);
- void SmiPrint(StringStream* accumulator);
-#ifdef DEBUG
- void SmiVerify();
-#endif
+ void SmiPrint(OStream& os) const; // NOLINT
+ DECLARE_VERIFIER(Smi)
static const int kMinValue =
(static_cast<unsigned int>(-1)) << (kSmiValueSize - 1);
@@ -1034,78 +1273,6 @@
};
-// Failure is used for reporting out of memory situations and
-// propagating exceptions through the runtime system. Failure objects
-// are transient and cannot occur as part of the object graph.
-//
-// Failures are a single word, encoded as follows:
-// +-------------------------+---+--+--+
-// |.........unused..........|sss|tt|11|
-// +-------------------------+---+--+--+
-// 7 6 4 32 10
-//
-//
-// The low two bits, 0-1, are the failure tag, 11. The next two bits,
-// 2-3, are a failure type tag 'tt' with possible values:
-// 00 RETRY_AFTER_GC
-// 01 EXCEPTION
-// 10 INTERNAL_ERROR
-// 11 OUT_OF_MEMORY_EXCEPTION
-//
-// The next three bits, 4-6, are an allocation space tag 'sss'. The
-// allocation space tag is 000 for all failure types except
-// RETRY_AFTER_GC. For RETRY_AFTER_GC, the possible values are the
-// allocation spaces (the encoding is found in globals.h).
-
-// Failure type tag info.
-const int kFailureTypeTagSize = 2;
-const int kFailureTypeTagMask = (1 << kFailureTypeTagSize) - 1;
-
-class Failure: public MaybeObject {
- public:
- // RuntimeStubs assumes EXCEPTION = 1 in the compiler-generated code.
- enum Type {
- RETRY_AFTER_GC = 0,
- EXCEPTION = 1, // Returning this marker tells the real exception
- // is in Isolate::pending_exception.
- INTERNAL_ERROR = 2,
- OUT_OF_MEMORY_EXCEPTION = 3
- };
-
- inline Type type() const;
-
- // Returns the space that needs to be collected for RetryAfterGC failures.
- inline AllocationSpace allocation_space() const;
-
- inline bool IsInternalError() const;
- inline bool IsOutOfMemoryException() const;
-
- static inline Failure* RetryAfterGC(AllocationSpace space);
- static inline Failure* RetryAfterGC(); // NEW_SPACE
- static inline Failure* Exception();
- static inline Failure* InternalError();
- static inline Failure* OutOfMemoryException();
- // Casting.
- static inline Failure* cast(MaybeObject* object);
-
- // Dispatched behavior.
- inline void FailurePrint() {
- FailurePrint(stdout);
- }
- void FailurePrint(FILE* out);
- void FailurePrint(StringStream* accumulator);
-#ifdef DEBUG
- void FailureVerify();
-#endif
-
- private:
- inline intptr_t value() const;
- static inline Failure* Construct(Type type, intptr_t value = 0);
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(Failure);
-};
-
-
// Heap objects typically have a map pointer in their first word. However,
// during GC other data (e.g. mark bits, forwarding addresses) is sometimes
// encoded in the first word. The class MapWord is an abstraction of the
@@ -1115,7 +1282,7 @@
// Normal state: the map word contains a map pointer.
// Create a map word from a map pointer.
- static inline MapWord FromMap(Map* map);
+ static inline MapWord FromMap(const Map* map);
// View this map word as a map pointer.
inline Map* ToMap();
@@ -1159,25 +1326,32 @@
public:
// [map]: Contains a map which contains the object's reflective
// information.
- inline Map* map();
+ inline Map* map() const;
inline void set_map(Map* value);
// The no-write-barrier version. This is OK if the object is white and in
// new space, or if the value is an immortal immutable object, like the maps
// of primitive (non-JS) objects like strings, heap numbers etc.
inline void set_map_no_write_barrier(Map* value);
+ // Get the map using acquire load.
+ inline Map* synchronized_map();
+ inline MapWord synchronized_map_word() const;
+
+ // Set the map using release store
+ inline void synchronized_set_map(Map* value);
+ inline void synchronized_set_map_no_write_barrier(Map* value);
+ inline void synchronized_set_map_word(MapWord map_word);
+
// During garbage collection, the map word of a heap object does not
// necessarily contain a map pointer.
- inline MapWord map_word();
+ inline MapWord map_word() const;
inline void set_map_word(MapWord map_word);
// The Heap the object was allocated in. Used also to access Isolate.
- inline Heap* GetHeap();
+ inline Heap* GetHeap() const;
- // Convenience method to get current isolate. This method can be
- // accessed only when its result is the same as
- // Isolate::Current(), it ASSERTs this. See also comment for GetHeap.
- inline Isolate* GetIsolate();
+ // Convenience method to get current isolate.
+ inline Isolate* GetIsolate() const;
// Converts an address to a HeapObject pointer.
static inline HeapObject* FromAddress(Address address);
@@ -1197,6 +1371,10 @@
// Returns the heap object's size in bytes
inline int Size();
+ // Returns true if this heap object may contain raw values, i.e., values that
+ // look like pointers to heap objects.
+ inline bool MayContainRawValues();
+
// Given a heap object's map pointer, returns the heap size in bytes
// Useful when the map pointer field is used for other purposes.
// GC internal.
@@ -1208,28 +1386,31 @@
// during marking GC.
static inline Object** RawField(HeapObject* obj, int offset);
- // Casting.
- static inline HeapObject* cast(Object* obj);
+ // Adds the |code| object related to |name| to the code cache of this map. If
+ // this map is a dictionary map that is shared, the map copied and installed
+ // onto the object.
+ static void UpdateMapCodeCache(Handle<HeapObject> object,
+ Handle<Name> name,
+ Handle<Code> code);
+
+ DECLARE_CAST(HeapObject)
// Return the write barrier mode for this. Callers of this function
- // must be able to present a reference to an AssertNoAllocation
+ // must be able to present a reference to an DisallowHeapAllocation
// object as a sign that they are not going to use this function
// from code that allocates and thus invalidates the returned write
// barrier mode.
- inline WriteBarrierMode GetWriteBarrierMode(const AssertNoAllocation&);
+ inline WriteBarrierMode GetWriteBarrierMode(
+ const DisallowHeapAllocation& promise);
// Dispatched behavior.
- void HeapObjectShortPrint(StringStream* accumulator);
+ void HeapObjectShortPrint(OStream& os); // NOLINT
#ifdef OBJECT_PRINT
- inline void HeapObjectPrint() {
- HeapObjectPrint(stdout);
- }
- void HeapObjectPrint(FILE* out);
- void PrintHeader(FILE* out, const char* id);
+ void PrintHeader(OStream& os, const char* id); // NOLINT
#endif
-
-#ifdef DEBUG
- void HeapObjectVerify();
+ DECLARE_PRINTER(HeapObject)
+ DECLARE_VERIFIER(HeapObject)
+#ifdef VERIFY_HEAP
inline void VerifyObjectField(int offset);
inline void VerifySmiField(int offset);
@@ -1243,7 +1424,7 @@
static const int kMapOffset = Object::kHeaderSize;
static const int kHeaderSize = kMapOffset + kPointerSize;
- STATIC_CHECK(kMapOffset == Internals::kHeapObjectMapOffset);
+ STATIC_ASSERT(kMapOffset == Internals::kHeapObjectMapOffset);
protected:
// helpers for calling an ObjectVisitor to iterate over pointers in the
@@ -1251,15 +1432,14 @@
inline void IteratePointers(ObjectVisitor* v, int start, int end);
// as above, for the single element at "offset"
inline void IteratePointer(ObjectVisitor* v, int offset);
+ // as above, for the next code link of a code object.
+ inline void IterateNextCodeLink(ObjectVisitor* v, int offset);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(HeapObject);
};
-#define SLOT_ADDR(obj, offset) \
- reinterpret_cast<Object**>((obj)->address() + offset)
-
// This class describes a body of an object of a fixed size
// in which all pointer fields are located in the [start_offset, end_offset)
// interval.
@@ -1274,8 +1454,8 @@
template<typename StaticVisitor>
static inline void IterateBody(HeapObject* obj) {
- StaticVisitor::VisitPointers(SLOT_ADDR(obj, start_offset),
- SLOT_ADDR(obj, end_offset));
+ StaticVisitor::VisitPointers(HeapObject::RawField(obj, start_offset),
+ HeapObject::RawField(obj, end_offset));
}
};
@@ -1294,35 +1474,27 @@
template<typename StaticVisitor>
static inline void IterateBody(HeapObject* obj, int object_size) {
- StaticVisitor::VisitPointers(SLOT_ADDR(obj, start_offset),
- SLOT_ADDR(obj, object_size));
+ StaticVisitor::VisitPointers(HeapObject::RawField(obj, start_offset),
+ HeapObject::RawField(obj, object_size));
}
};
-#undef SLOT_ADDR
-
// The HeapNumber class describes heap allocated numbers that cannot be
// represented in a Smi (small integer)
class HeapNumber: public HeapObject {
public:
// [value]: number value.
- inline double value();
+ inline double value() const;
inline void set_value(double value);
- // Casting.
- static inline HeapNumber* cast(Object* obj);
+ DECLARE_CAST(HeapNumber)
// Dispatched behavior.
- Object* HeapNumberToBoolean();
- inline void HeapNumberPrint() {
- HeapNumberPrint(stdout);
- }
- void HeapNumberPrint(FILE* out);
- void HeapNumberPrint(StringStream* accumulator);
-#ifdef DEBUG
- void HeapNumberVerify();
-#endif
+ bool HeapNumberBooleanValue();
+
+ void HeapNumberPrint(OStream& os); // NOLINT
+ DECLARE_VERIFIER(HeapNumber)
inline int get_exponent();
inline int get_sign();
@@ -1330,11 +1502,18 @@
// Layout description.
static const int kValueOffset = HeapObject::kHeaderSize;
// IEEE doubles are two 32 bit words. The first is just mantissa, the second
- // is a mixture of sign, exponent and mantissa. Our current platforms are all
- // little endian apart from non-EABI arm which is little endian with big
- // endian floating point word ordering!
+ // is a mixture of sign, exponent and mantissa. The offsets of two 32 bit
+ // words within double numbers are endian dependent and they are set
+ // accordingly.
+#if defined(V8_TARGET_LITTLE_ENDIAN)
static const int kMantissaOffset = kValueOffset;
static const int kExponentOffset = kValueOffset + 4;
+#elif defined(V8_TARGET_BIG_ENDIAN)
+ static const int kMantissaOffset = kValueOffset + 4;
+ static const int kExponentOffset = kValueOffset;
+#else
+#error Unknown byte ordering
+#endif
static const int kSize = kValueOffset + kDoubleSize;
static const uint32_t kSignMask = 0x80000000u;
@@ -1344,6 +1523,8 @@
static const int kExponentBits = 11;
static const int kExponentBias = 1023;
static const int kExponentShift = 20;
+ static const int kInfinityOrNanExponent =
+ (kExponentMask >> kExponentShift) - kExponentBias;
static const int kMantissaBitsInTopWord = 20;
static const int kNonMantissaBitsInTopWord = 12;
@@ -1386,37 +1567,34 @@
FORCE_DELETION
};
- // Casting.
- static inline JSReceiver* cast(Object* obj);
+ DECLARE_CAST(JSReceiver)
- static Handle<Object> SetProperty(Handle<JSReceiver> object,
- Handle<String> key,
- Handle<Object> value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
- // Can cause GC.
- MUST_USE_RESULT MaybeObject* SetProperty(String* key,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result,
- String* key,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSReceiver* setter,
- Object* value);
+ MUST_USE_RESULT static MaybeHandle<Object> SetElement(
+ Handle<JSReceiver> object,
+ uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+ StrictMode strict_mode);
- MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode);
- MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode);
+ // Implementation of [[HasProperty]], ECMA-262 5th edition, section 8.12.6.
+ MUST_USE_RESULT static inline Maybe<bool> HasProperty(
+ Handle<JSReceiver> object, Handle<Name> name);
+ MUST_USE_RESULT static inline Maybe<bool> HasOwnProperty(Handle<JSReceiver>,
+ Handle<Name> name);
+ MUST_USE_RESULT static inline Maybe<bool> HasElement(
+ Handle<JSReceiver> object, uint32_t index);
+ MUST_USE_RESULT static inline Maybe<bool> HasOwnElement(
+ Handle<JSReceiver> object, uint32_t index);
- // Set the index'th array element.
- // Can cause GC, or return failure if GC is required.
- MUST_USE_RESULT MaybeObject* SetElement(uint32_t index,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool check_prototype);
+ // Implementation of [[Delete]], ECMA-262 5th edition, section 8.12.7.
+ MUST_USE_RESULT static MaybeHandle<Object> DeleteProperty(
+ Handle<JSReceiver> object,
+ Handle<Name> name,
+ DeleteMode mode = NORMAL_DELETION);
+ MUST_USE_RESULT static MaybeHandle<Object> DeleteElement(
+ Handle<JSReceiver> object,
+ uint32_t index,
+ DeleteMode mode = NORMAL_DELETION);
// Tests for the fast common case for property enumeration.
bool IsSimpleEnum();
@@ -1428,44 +1606,49 @@
// function that was used to instantiate the object).
String* constructor_name();
- inline PropertyAttributes GetPropertyAttribute(String* name);
- PropertyAttributes GetPropertyAttributeWithReceiver(JSReceiver* receiver,
- String* name);
- PropertyAttributes GetLocalPropertyAttribute(String* name);
+ MUST_USE_RESULT static inline Maybe<PropertyAttributes> GetPropertyAttributes(
+ Handle<JSReceiver> object, Handle<Name> name);
+ MUST_USE_RESULT static Maybe<PropertyAttributes> GetPropertyAttributes(
+ LookupIterator* it);
+ MUST_USE_RESULT static Maybe<PropertyAttributes> GetOwnPropertyAttributes(
+ Handle<JSReceiver> object, Handle<Name> name);
- // Can cause a GC.
- inline bool HasProperty(String* name);
- inline bool HasLocalProperty(String* name);
- inline bool HasElement(uint32_t index);
+ MUST_USE_RESULT static inline Maybe<PropertyAttributes> GetElementAttribute(
+ Handle<JSReceiver> object, uint32_t index);
+ MUST_USE_RESULT static inline Maybe<PropertyAttributes>
+ GetOwnElementAttribute(Handle<JSReceiver> object, uint32_t index);
- // Return the object's prototype (might be Heap::null_value()).
- inline Object* GetPrototype();
-
- // Set the object's prototype (only JSReceiver and null are allowed).
- MUST_USE_RESULT MaybeObject* SetPrototype(Object* value,
- bool skip_hidden_prototypes);
+ // Return the constructor function (may be Heap::null_value()).
+ inline Object* GetConstructor();
// Retrieves a permanent object identity hash code. The undefined value might
- // be returned in case no hash was created yet and OMIT_CREATION was used.
- inline MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
+ // be returned in case no hash was created yet.
+ inline Object* GetIdentityHash();
- // 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);
+ // Retrieves a permanent object identity hash code. May create and store a
+ // hash code if needed and none exists.
+ inline static Handle<Smi> GetOrCreateIdentityHash(
+ Handle<JSReceiver> object);
- protected:
- Smi* GenerateIdentityHash();
+ enum KeyCollectionType { OWN_ONLY, INCLUDE_PROTOS };
+
+ // Computes the enumerable keys for a JSObject. Used for implementing
+ // "for (n in object) { }".
+ MUST_USE_RESULT static MaybeHandle<FixedArray> GetKeys(
+ Handle<JSReceiver> object,
+ KeyCollectionType type);
private:
- PropertyAttributes GetPropertyAttribute(JSReceiver* receiver,
- LookupResult* result,
- String* name,
- bool continue_search);
-
DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver);
};
+// Forward declaration for JSObject::GetOrCreateHiddenPropertiesHashTable.
+class ObjectHashTable;
+
+// Forward declaration for JSObject::Copy.
+class AllocationSite;
+
+
// The JSObject describes real heap allocated JavaScript objects with
// properties.
// Note that the map of JSObject changes during execution to enable inline
@@ -1478,7 +1661,7 @@
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).
//
@@ -1489,240 +1672,225 @@
// In the fast mode elements is a FixedArray and so each element can
// be quickly accessed. This fact is used in the generated code. The
// elements array can have one of three maps in this mode:
- // fixed_array_map, non_strict_arguments_elements_map or
+ // fixed_array_map, sloppy_arguments_elements_map or
// fixed_cow_array_map (for copy-on-write arrays). In the latter case
// the elements array may be shared by a few objects and so before
// writing to any element the array must be copied. Use
// EnsureWritableFastElements in this case.
//
// In the slow mode the elements is either a NumberDictionary, an
- // ExternalArray, or a FixedArray parameter map for a (non-strict)
+ // ExternalArray, or a FixedArray parameter map for a (sloppy)
// arguments object.
DECL_ACCESSORS(elements, FixedArrayBase)
inline void initialize_elements();
- MUST_USE_RESULT inline MaybeObject* ResetElements();
+ static void ResetElements(Handle<JSObject> object);
+ static inline void SetMapAndElements(Handle<JSObject> object,
+ Handle<Map> map,
+ Handle<FixedArrayBase> elements);
inline ElementsKind GetElementsKind();
inline ElementsAccessor* GetElementsAccessor();
- inline bool HasFastSmiOnlyElements();
+ // Returns true if an object has elements of FAST_SMI_ELEMENTS ElementsKind.
+ inline bool HasFastSmiElements();
+ // Returns true if an object has elements of FAST_ELEMENTS ElementsKind.
+ inline bool HasFastObjectElements();
+ // Returns true if an object has elements of FAST_ELEMENTS or
+ // FAST_SMI_ONLY_ELEMENTS.
+ inline bool HasFastSmiOrObjectElements();
+ // Returns true if an object has any of the fast elements kinds.
inline bool HasFastElements();
- // Returns if an object has either FAST_ELEMENT or FAST_SMI_ONLY_ELEMENT
- // elements. TODO(danno): Rename HasFastTypeElements to HasFastElements() and
- // HasFastElements to HasFastObjectElements.
- inline bool HasFastTypeElements();
+ // Returns true if an object has elements of FAST_DOUBLE_ELEMENTS
+ // ElementsKind.
inline bool HasFastDoubleElements();
- inline bool HasNonStrictArgumentsElements();
+ // Returns true if an object has elements of FAST_HOLEY_*_ELEMENTS
+ // ElementsKind.
+ inline bool HasFastHoleyElements();
+ inline bool HasSloppyArgumentsElements();
inline bool HasDictionaryElements();
- inline bool HasExternalPixelElements();
+
+ inline bool HasExternalUint8ClampedElements();
inline bool HasExternalArrayElements();
- inline bool HasExternalByteElements();
- inline bool HasExternalUnsignedByteElements();
- inline bool HasExternalShortElements();
- inline bool HasExternalUnsignedShortElements();
- inline bool HasExternalIntElements();
- inline bool HasExternalUnsignedIntElements();
- inline bool HasExternalFloatElements();
- inline bool HasExternalDoubleElements();
+ inline bool HasExternalInt8Elements();
+ inline bool HasExternalUint8Elements();
+ inline bool HasExternalInt16Elements();
+ inline bool HasExternalUint16Elements();
+ inline bool HasExternalInt32Elements();
+ inline bool HasExternalUint32Elements();
+ inline bool HasExternalFloat32Elements();
+ inline bool HasExternalFloat64Elements();
+
+ inline bool HasFixedTypedArrayElements();
+
+ inline bool HasFixedUint8ClampedElements();
+ inline bool HasFixedArrayElements();
+ inline bool HasFixedInt8Elements();
+ inline bool HasFixedUint8Elements();
+ inline bool HasFixedInt16Elements();
+ inline bool HasFixedUint16Elements();
+ inline bool HasFixedInt32Elements();
+ inline bool HasFixedUint32Elements();
+ inline bool HasFixedFloat32Elements();
+ inline bool HasFixedFloat64Elements();
+
bool HasFastArgumentsElements();
bool HasDictionaryArgumentsElements();
inline SeededNumberDictionary* element_dictionary(); // Gets slow elements.
- inline void set_map_and_elements(
- Map* map,
- FixedArrayBase* value,
- WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
-
// Requires: HasFastElements().
- MUST_USE_RESULT inline MaybeObject* EnsureWritableFastElements();
+ static Handle<FixedArray> EnsureWritableFastElements(
+ Handle<JSObject> object);
// Collects elements starting at index 0.
// Undefined values are placed after non-undefined values.
// Returns the number of non-undefined values.
- MUST_USE_RESULT MaybeObject* PrepareElementsForSort(uint32_t limit);
+ static Handle<Object> PrepareElementsForSort(Handle<JSObject> object,
+ uint32_t limit);
// As PrepareElementsForSort, but only on objects where elements is
- // a dictionary, and it will stay a dictionary.
- MUST_USE_RESULT MaybeObject* PrepareSlowElementsForSort(uint32_t limit);
+ // a dictionary, and it will stay a dictionary. Collates undefined and
+ // unexisting elements below limit from position zero of the elements.
+ static Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object,
+ uint32_t limit);
- MUST_USE_RESULT MaybeObject* GetPropertyWithCallback(Object* receiver,
- Object* structure,
- String* name);
+ MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithInterceptor(
+ LookupIterator* it, Handle<Object> value);
- // Can cause GC.
- MUST_USE_RESULT MaybeObject* SetPropertyForResult(LookupResult* result,
- String* key,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetPropertyWithFailedAccessCheck(
- LookupResult* result,
- String* name,
- Object* value,
- bool check_prototype,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetPropertyWithCallback(
- Object* structure,
- String* name,
- Object* value,
- JSObject* holder,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetPropertyWithInterceptor(
- String* name,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetPropertyPostInterceptor(
- String* name,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
+ // SetLocalPropertyIgnoreAttributes converts callbacks to fields. We need to
+ // grant an exemption to ExecutableAccessor callbacks in some cases.
+ enum ExecutableAccessorInfoHandling {
+ DEFAULT_HANDLING,
+ DONT_FORCE_FIELD
+ };
- static Handle<Object> SetLocalPropertyIgnoreAttributes(
+ MUST_USE_RESULT static MaybeHandle<Object> SetOwnPropertyIgnoreAttributes(
Handle<JSObject> object,
- Handle<String> key,
+ Handle<Name> key,
Handle<Object> value,
- PropertyAttributes attributes);
+ PropertyAttributes attributes,
+ ExecutableAccessorInfoHandling handling = DEFAULT_HANDLING);
- // Can cause GC.
- MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
- String* key,
- Object* value,
- PropertyAttributes attributes);
+ static void AddProperty(Handle<JSObject> object, Handle<Name> key,
+ Handle<Object> value, PropertyAttributes attributes);
- // Retrieve a value in a normalized object given a lookup result.
- // Handles the special representation of JS global objects.
- Object* GetNormalizedProperty(LookupResult* result);
+ // Extend the receiver with a single fast property appeared first in the
+ // passed map. This also extends the property backing store if necessary.
+ static void AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map);
- // Sets the property value in a normalized object given a lookup result.
- // Handles the special representation of JS global objects.
- Object* SetNormalizedProperty(LookupResult* result, Object* value);
+ // Migrates the given object to a map whose field representations are the
+ // lowest upper bound of all known representations for that field.
+ static void MigrateInstance(Handle<JSObject> instance);
+
+ // Migrates the given object only if the target map is already available,
+ // or returns false if such a map is not yet available.
+ static bool TryMigrateInstance(Handle<JSObject> instance);
// 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<Object> value,
- PropertyDetails details);
+ static void SetNormalizedProperty(Handle<JSObject> object,
+ Handle<Name> key,
+ Handle<Object> value,
+ PropertyDetails details);
- MUST_USE_RESULT MaybeObject* SetNormalizedProperty(String* name,
- Object* value,
- PropertyDetails details);
-
- // Deletes the named property in a normalized object.
- MUST_USE_RESULT MaybeObject* DeleteNormalizedProperty(String* name,
- DeleteMode mode);
+ static void OptimizeAsPrototype(Handle<JSObject> object,
+ PrototypeOptimizationMode mode);
+ static void ReoptimizeIfPrototype(Handle<JSObject> object);
// Retrieve interceptors.
InterceptorInfo* GetNamedInterceptor();
InterceptorInfo* GetIndexedInterceptor();
// Used from JSReceiver.
- PropertyAttributes GetPropertyAttributePostInterceptor(JSObject* receiver,
- String* name,
- bool continue_search);
- PropertyAttributes GetPropertyAttributeWithInterceptor(JSObject* receiver,
- String* name,
- bool continue_search);
- PropertyAttributes GetPropertyAttributeWithFailedAccessCheck(
- Object* receiver,
- LookupResult* result,
- String* name,
- bool continue_search);
+ MUST_USE_RESULT static Maybe<PropertyAttributes>
+ GetPropertyAttributesWithInterceptor(Handle<JSObject> holder,
+ Handle<Object> receiver,
+ Handle<Name> name);
+ MUST_USE_RESULT static Maybe<PropertyAttributes>
+ GetPropertyAttributesWithFailedAccessCheck(LookupIterator* it);
+ MUST_USE_RESULT static Maybe<PropertyAttributes>
+ GetElementAttributeWithReceiver(Handle<JSObject> object,
+ Handle<JSReceiver> receiver,
+ uint32_t index, bool check_prototype);
- static void DefineAccessor(Handle<JSObject> object,
- Handle<String> name,
- Handle<Object> getter,
- Handle<Object> setter,
- PropertyAttributes attributes);
- MUST_USE_RESULT MaybeObject* DefineAccessor(String* name,
- Object* getter,
- Object* setter,
- PropertyAttributes attributes);
- Object* LookupAccessor(String* name, AccessorComponent component);
+ // Retrieves an AccessorPair property from the given object. Might return
+ // undefined if the property doesn't exist or is of a different kind.
+ MUST_USE_RESULT static MaybeHandle<Object> GetAccessor(
+ Handle<JSObject> object,
+ Handle<Name> name,
+ AccessorComponent component);
- MUST_USE_RESULT MaybeObject* DefineAccessor(AccessorInfo* info);
+ // Defines an AccessorPair property on the given object.
+ // TODO(mstarzinger): Rename to SetAccessor().
+ static MaybeHandle<Object> DefineAccessor(Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> getter,
+ Handle<Object> setter,
+ PropertyAttributes attributes);
- // Used from Object::GetProperty().
- MUST_USE_RESULT MaybeObject* GetPropertyWithFailedAccessCheck(
- Object* receiver,
- LookupResult* result,
- String* name,
- PropertyAttributes* attributes);
- MUST_USE_RESULT MaybeObject* GetPropertyWithInterceptor(
- JSReceiver* receiver,
- String* name,
- PropertyAttributes* attributes);
- MUST_USE_RESULT MaybeObject* GetPropertyPostInterceptor(
- JSReceiver* receiver,
- String* name,
- PropertyAttributes* attributes);
- MUST_USE_RESULT MaybeObject* GetLocalPropertyPostInterceptor(
- JSReceiver* receiver,
- String* name,
- PropertyAttributes* attributes);
+ // Defines an AccessorInfo property on the given object.
+ MUST_USE_RESULT static MaybeHandle<Object> SetAccessor(
+ Handle<JSObject> object,
+ Handle<AccessorInfo> info);
+
+ MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithInterceptor(
+ Handle<JSObject> object,
+ Handle<Object> receiver,
+ Handle<Name> name);
// Returns true if this is an instance of an api function and has
// been modified since it was created. May give false positives.
bool IsDirty();
- // If the receiver is a JSGlobalProxy this method will return its prototype,
- // otherwise the result is the receiver itself.
- inline Object* BypassGlobalProxy();
-
// Accessors for hidden properties object.
//
- // 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
+ // Hidden properties are not own properties of the object itself.
+ // Instead they are stored in an auxiliary structure kept as an own
+ // 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.
// 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,
+ static Handle<Object> SetHiddenProperty(Handle<JSObject> object,
+ Handle<Name> key,
Handle<Object> value);
- // Returns a failure if a GC is required.
- MUST_USE_RESULT MaybeObject* SetHiddenProperty(String* key, Object* value);
- // Gets the value of a hidden property with the given key. Returns undefined
+ // Gets the value of a hidden property with the given key. Returns the hole
// 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(Handle<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.
- bool HasHiddenProperties();
+ static void DeleteHiddenProperty(Handle<JSObject> object,
+ Handle<Name> key);
+ // Returns true if the object has a property with the hidden string as name.
+ static bool HasHiddenProperties(Handle<JSObject> object);
- static int GetIdentityHash(Handle<JSObject> obj);
- MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
- MUST_USE_RESULT MaybeObject* SetIdentityHash(Object* hash, CreationFlag flag);
+ static void SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash);
- static Handle<Object> DeleteProperty(Handle<JSObject> obj,
- Handle<String> name);
- MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode);
-
- static Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
- MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode);
-
- inline void ValidateSmiOnlyElements();
+ static inline void ValidateElements(Handle<JSObject> object);
// Makes sure that this object can contain HeapObject as elements.
- MUST_USE_RESULT inline MaybeObject* EnsureCanContainHeapObjectElements();
+ static inline void EnsureCanContainHeapObjectElements(Handle<JSObject> obj);
// Makes sure that this object can contain the specified elements.
- MUST_USE_RESULT inline MaybeObject* EnsureCanContainElements(
+ static inline void EnsureCanContainElements(
+ Handle<JSObject> object,
Object** elements,
uint32_t count,
EnsureElementsMode mode);
- MUST_USE_RESULT inline MaybeObject* EnsureCanContainElements(
- FixedArrayBase* elements,
+ static inline void EnsureCanContainElements(
+ Handle<JSObject> object,
+ Handle<FixedArrayBase> elements,
+ uint32_t length,
EnsureElementsMode mode);
- MUST_USE_RESULT MaybeObject* EnsureCanContainElements(
+ static void EnsureCanContainElements(
+ Handle<JSObject> object,
Arguments* arguments,
uint32_t first_arg,
uint32_t arg_count,
EnsureElementsMode mode);
+ // Would we convert a fast elements array to dictionary mode given
+ // an access at key?
+ bool WouldConvertToSlowElements(Handle<Object> key);
// Do we want to keep the elements in fast case when increasing the
// capacity?
bool ShouldConvertToSlowElements(int new_capacity);
@@ -1736,98 +1904,63 @@
// 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,
+ // These methods do not perform access checks!
+ MUST_USE_RESULT static MaybeHandle<AccessorPair> GetOwnElementAccessorPair(
+ Handle<JSObject> object,
+ uint32_t index);
- // 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,
-
- // Element with given index is stored in slow backing store.
- DICTIONARY_ELEMENT
- };
-
- LocalElementType HasLocalElement(uint32_t index);
-
- bool HasElementWithInterceptor(JSReceiver* receiver, uint32_t index);
-
- MUST_USE_RESULT MaybeObject* SetFastElement(uint32_t index,
- Object* value,
- StrictModeFlag strict_mode,
- bool check_prototype);
-
- MUST_USE_RESULT MaybeObject* SetDictionaryElement(
- uint32_t index,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool check_prototype,
- SetPropertyMode set_mode = SET_PROPERTY);
-
- MUST_USE_RESULT MaybeObject* SetFastDoubleElement(
- uint32_t index,
- Object* value,
- StrictModeFlag strict_mode,
- bool check_prototype = true);
-
- static Handle<Object> SetOwnElement(Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- StrictModeFlag strict_mode);
-
- // Empty handle is returned if the element cannot be set to the given value.
- static MUST_USE_RESULT Handle<Object> SetElement(
+ MUST_USE_RESULT static MaybeHandle<Object> SetFastElement(
Handle<JSObject> object,
uint32_t index,
Handle<Object> value,
- PropertyAttributes attr,
- StrictModeFlag strict_mode,
- SetPropertyMode set_mode = SET_PROPERTY);
+ StrictMode strict_mode,
+ bool check_prototype);
- // A Failure object is returned if GC is needed.
- MUST_USE_RESULT MaybeObject* SetElement(
+ MUST_USE_RESULT static MaybeHandle<Object> SetOwnElement(
+ Handle<JSObject> object,
uint32_t index,
- Object* value,
+ Handle<Object> value,
+ StrictMode strict_mode);
+
+ // Empty handle is returned if the element cannot be set to the given value.
+ MUST_USE_RESULT static MaybeHandle<Object> SetElement(
+ Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode,
+ StrictMode strict_mode,
bool check_prototype = true,
SetPropertyMode set_mode = SET_PROPERTY);
// Returns the index'th element.
// The undefined object if index is out of bounds.
- MUST_USE_RESULT MaybeObject* GetElementWithInterceptor(Object* receiver,
- uint32_t index);
+ MUST_USE_RESULT static MaybeHandle<Object> GetElementWithInterceptor(
+ Handle<JSObject> object,
+ Handle<Object> receiver,
+ uint32_t index);
- enum SetFastElementsCapacityMode {
- kAllowSmiOnlyElements,
- kForceSmiOnlyElements,
- kDontAllowSmiOnlyElements
+ enum SetFastElementsCapacitySmiMode {
+ kAllowSmiElements,
+ kForceSmiElements,
+ kDontAllowSmiElements
};
// Replace the elements' backing store with fast elements of the given
// capacity. Update the length for JSArrays. Returns the new backing
// store.
- MUST_USE_RESULT MaybeObject* SetFastElementsCapacityAndLength(
+ static Handle<FixedArray> SetFastElementsCapacityAndLength(
+ Handle<JSObject> object,
int capacity,
int length,
- SetFastElementsCapacityMode set_capacity_mode);
- MUST_USE_RESULT MaybeObject* SetFastDoubleElementsCapacityAndLength(
+ SetFastElementsCapacitySmiMode smi_mode);
+ static void SetFastDoubleElementsCapacityAndLength(
+ Handle<JSObject> object,
int capacity,
int length);
@@ -1836,10 +1969,22 @@
inline bool HasNamedInterceptor();
inline bool HasIndexedInterceptor();
+ // Computes the enumerable keys from interceptors. Used for debug mirrors and
+ // by JSReceiver::GetKeys.
+ MUST_USE_RESULT static MaybeHandle<JSObject> GetKeysForNamedInterceptor(
+ Handle<JSObject> object,
+ Handle<JSReceiver> receiver);
+ MUST_USE_RESULT static MaybeHandle<JSObject> GetKeysForIndexedInterceptor(
+ Handle<JSObject> object,
+ Handle<JSReceiver> receiver);
+
// Support functions for v8 api (needed for correct interceptor behavior).
- bool HasRealNamedProperty(String* key);
- bool HasRealElementProperty(uint32_t index);
- bool HasRealNamedCallbackProperty(String* key);
+ MUST_USE_RESULT static Maybe<bool> HasRealNamedProperty(
+ Handle<JSObject> object, Handle<Name> key);
+ MUST_USE_RESULT static Maybe<bool> HasRealElementProperty(
+ Handle<JSObject> object, uint32_t index);
+ MUST_USE_RESULT static Maybe<bool> HasRealNamedCallbackProperty(
+ Handle<JSObject> object, Handle<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.
@@ -1851,30 +1996,22 @@
inline void SetInternalField(int index, Object* value);
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 LookupCallbackSetterInPrototypes(String* name, LookupResult* result);
- MUST_USE_RESULT MaybeObject* SetElementWithCallbackSetterInPrototypes(
- uint32_t index, Object* value, bool* found, StrictModeFlag strict_mode);
- void LookupCallback(String* name, LookupResult* result);
-
// Returns the number of properties on this object filtering out properties
// with the specified attributes (ignoring interceptors).
- int NumberOfLocalProperties(PropertyAttributes filter = NONE);
+ int NumberOfOwnProperties(PropertyAttributes filter = NONE);
// Fill in details for properties into storage starting at the specified
// index.
- void GetLocalPropertyNames(FixedArray* storage, int index);
+ void GetOwnPropertyNames(
+ FixedArray* storage, int index, PropertyAttributes filter = NONE);
// Returns the number of properties on this object filtering out properties
// with the specified attributes (ignoring interceptors).
- int NumberOfLocalElements(PropertyAttributes filter);
+ int NumberOfOwnElements(PropertyAttributes filter);
// Returns the number of enumerable elements (ignoring interceptors).
int NumberOfEnumElements();
// Returns the number of elements on this object filtering out elements
// with the specified attributes (ignoring interceptors).
- int GetLocalElementKeys(FixedArray* storage, PropertyAttributes filter);
+ int GetOwnElementKeys(FixedArray* storage, PropertyAttributes filter);
// Count and fill in the enumerable elements into storage.
// (storage->length() == NumberOfEnumElements()).
// If storage is NULL, will count the elements without adding
@@ -1882,76 +2019,14 @@
// Returns the number of enumerable elements.
int GetEnumElementKeys(FixedArray* storage);
- // 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,
- Object* value);
-
- // Add a constant function property to a fast-case object.
- // This leaves a CONSTANT_TRANSITION in the old map, and
- // if it is called on a second object with this map, a
- // normal property is added instead, with a map transition.
- // This avoids the creation of many maps with the same constant
- // function, all orphaned.
- MUST_USE_RESULT MaybeObject* AddConstantFunctionProperty(
- String* name,
- JSFunction* function,
- PropertyAttributes attributes);
-
- MUST_USE_RESULT MaybeObject* ReplaceSlowProperty(
- String* name,
- Object* value,
- PropertyAttributes attributes);
-
// Returns a new map with all transitions dropped from the object's current
// map and the ElementsKind set.
static Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,
ElementsKind to_kind);
- inline MUST_USE_RESULT MaybeObject* GetElementsTransitionMap(
- Isolate* isolate,
- ElementsKind elements_kind);
- MUST_USE_RESULT MaybeObject* GetElementsTransitionMapSlow(
- ElementsKind elements_kind);
+ static void TransitionElementsKind(Handle<JSObject> object,
+ ElementsKind to_kind);
- static Handle<Object> TransitionElementsKind(Handle<JSObject> object,
- ElementsKind to_kind);
-
- MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind);
-
- // Converts a descriptor of any other type to a real field,
- // backed by the properties array. Descriptors of visible
- // types, such as CONSTANT_FUNCTION, keep their enumeration order.
- // Converts the descriptor on the original object's map to a
- // map transition, and the the new field is on the object's new map.
- MUST_USE_RESULT MaybeObject* ConvertDescriptorToFieldAndMapTransition(
- String* name,
- Object* new_value,
- PropertyAttributes attributes);
-
- // Converts a descriptor of any other type to a real field,
- // backed by the properties array. Descriptors of visible
- // types, such as CONSTANT_FUNCTION, keep their enumeration order.
- MUST_USE_RESULT MaybeObject* ConvertDescriptorToField(
- String* name,
- Object* new_value,
- PropertyAttributes attributes);
-
- // Add a property to a fast-case object.
- MUST_USE_RESULT MaybeObject* AddFastProperty(String* name,
- Object* value,
- PropertyAttributes attributes);
-
- // Add a property to a slow-case object.
- MUST_USE_RESULT MaybeObject* AddSlowProperty(String* name,
- Object* value,
- PropertyAttributes attributes);
-
- // Add a property to an object.
- MUST_USE_RESULT MaybeObject* AddProperty(String* name,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
+ static void MigrateToMap(Handle<JSObject> object, Handle<Map> new_map);
// Convert the object to use the canonical dictionary
// representation. If the object is expected to have additional properties
@@ -1961,34 +2036,22 @@
PropertyNormalizationMode mode,
int expected_additional_properties);
- MUST_USE_RESULT MaybeObject* NormalizeProperties(
- PropertyNormalizationMode mode,
- int expected_additional_properties);
-
// Convert and update the elements backing store to be a
// SeededNumberDictionary dictionary. Returns the backing after conversion.
static Handle<SeededNumberDictionary> NormalizeElements(
Handle<JSObject> object);
- MUST_USE_RESULT MaybeObject* NormalizeElements();
-
- static void UpdateMapCodeCache(Handle<JSObject> object,
- Handle<String> name,
- Handle<Code> code);
-
- MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(String* name, Code* code);
-
// Transform slow named properties to fast variants.
- // Returns failure if allocation failed.
- static void TransformToFastProperties(Handle<JSObject> object,
- int unused_property_fields);
-
- MUST_USE_RESULT MaybeObject* TransformToFastProperties(
- int unused_property_fields);
+ static void MigrateSlowToFast(Handle<JSObject> object,
+ int unused_property_fields);
// Access fast-case object properties at index.
- inline Object* FastPropertyAt(int index);
- inline Object* FastPropertyAtPut(int index, Object* value);
+ static Handle<Object> FastPropertyAt(Handle<JSObject> object,
+ Representation representation,
+ FieldIndex index);
+ inline Object* RawFastPropertyAt(FieldIndex index);
+ inline void FastPropertyAtPut(FieldIndex index, Object* value);
+ void WriteToField(int descriptor, Object* value);
// Access to in object properties.
inline int GetInObjectPropertyOffset(int index);
@@ -1998,6 +2061,10 @@
WriteBarrierMode mode
= UPDATE_WRITE_BARRIER);
+ // Set the object's prototype (only JSReceiver and null are allowed values).
+ MUST_USE_RESULT static MaybeHandle<Object> SetPrototype(
+ Handle<JSObject> object, Handle<Object> value, bool from_javascript);
+
// Initializes the body after properties slot, properties slot is
// initialized by set_properties. Fill the pre-allocated fields with
// pre_allocated_value and the rest with filler_value.
@@ -2010,40 +2077,50 @@
// Check whether this object references another object
bool ReferencesObject(Object* obj);
- // Casting.
- static inline JSObject* cast(Object* obj);
-
// Disalow further properties to be added to the object.
- static Handle<Object> PreventExtensions(Handle<JSObject> object);
- MUST_USE_RESULT MaybeObject* PreventExtensions();
+ MUST_USE_RESULT static MaybeHandle<Object> PreventExtensions(
+ Handle<JSObject> object);
+ // ES5 Object.freeze
+ MUST_USE_RESULT static MaybeHandle<Object> Freeze(Handle<JSObject> object);
+
+ // Called the first time an object is observed with ES7 Object.observe.
+ static void SetObserved(Handle<JSObject> object);
+
+ // Copy object.
+ enum DeepCopyHints { kNoHints = 0, kObjectIsShallow = 1 };
+
+ static Handle<JSObject> Copy(Handle<JSObject> object);
+ MUST_USE_RESULT static MaybeHandle<JSObject> DeepCopy(
+ Handle<JSObject> object,
+ AllocationSiteUsageContext* site_context,
+ DeepCopyHints hints = kNoHints);
+ MUST_USE_RESULT static MaybeHandle<JSObject> DeepWalk(
+ Handle<JSObject> object,
+ AllocationSiteCreationContext* site_context);
+
+ static Handle<Object> GetDataProperty(Handle<JSObject> object,
+ Handle<Name> key);
+ static Handle<Object> GetDataProperty(LookupIterator* it);
+
+ DECLARE_CAST(JSObject)
// Dispatched behavior.
void JSObjectShortPrint(StringStream* accumulator);
+ DECLARE_PRINTER(JSObject)
+ DECLARE_VERIFIER(JSObject)
#ifdef OBJECT_PRINT
- inline void JSObjectPrint() {
- JSObjectPrint(stdout);
- }
- void JSObjectPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSObjectVerify();
-#endif
-#ifdef OBJECT_PRINT
- inline void PrintProperties() {
- PrintProperties(stdout);
- }
- void PrintProperties(FILE* out);
-
- inline void PrintElements() {
- PrintElements(stdout);
- }
- void PrintElements(FILE* out);
+ void PrintProperties(OStream& os); // NOLINT
+ void PrintElements(OStream& os); // NOLINT
+ void PrintTransitions(OStream& os); // NOLINT
#endif
- void PrintElementsTransition(
- FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
- ElementsKind to_kind, FixedArrayBase* to_elements);
+ static void PrintElementsTransition(
+ FILE* file, Handle<JSObject> object,
+ ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
+ ElementsKind to_kind, Handle<FixedArrayBase> to_elements);
+
+ void PrintInstanceMigration(FILE* file, Map* original_map, Map* new_map);
#ifdef DEBUG
// Structure for collecting spill information about JSObjects.
@@ -2066,12 +2143,15 @@
void IncrementSpillStatistics(SpillInformation* info);
#endif
- Object* SlowReverseLookup(Object* value);
- // Maximal number of fast properties for the JSObject. Used to
- // restrict the number of map transitions to avoid an explosion in
- // the number of maps for objects used as dictionaries.
- inline int MaxFastProperties();
+#ifdef VERIFY_HEAP
+ // If a GC was caused while constructing this object, the elements pointer
+ // may point to a one pointer filler map. The object won't be rooted, but
+ // our heap verification code could stumble across it.
+ bool ElementsAreSafeToExamine();
+#endif
+
+ Object* SlowReverseLookup(Object* value);
// Maximal number of elements (numbered 0 .. kMaxElementCount - 1).
// Also maximal value of JSArray's length property.
@@ -2092,8 +2172,14 @@
// don't want to be wasteful with long lived objects.
static const int kMaxUncheckedOldFastElementsLength = 500;
+ // Note that Page::kMaxRegularHeapObjectSize puts a limit on
+ // permissible values (see the DCHECK in heap.cc).
static const int kInitialMaxFastElementArray = 100000;
- static const int kMaxFastProperties = 12;
+
+ // This constant applies only to the initial map of "$Object" aka
+ // "global.Object" and not to arbitrary other JSObject maps.
+ static const int kInitialGlobalObjectUnusedPropertiesCount = 4;
+
static const int kMaxInstanceSize = 255 * kPointerSize;
// When extending the backing storage for property values, we increase
// its size by more than the 1 entry necessary, so sequentially adding fields
@@ -2105,62 +2191,136 @@
static const int kElementsOffset = kPropertiesOffset + kPointerSize;
static const int kHeaderSize = kElementsOffset + kPointerSize;
- STATIC_CHECK(kHeaderSize == Internals::kJSObjectHeaderSize);
+ STATIC_ASSERT(kHeaderSize == Internals::kJSObjectHeaderSize);
class BodyDescriptor : public FlexibleBodyDescriptor<kPropertiesOffset> {
public:
static inline int SizeOf(Map* map, HeapObject* object);
};
+ Context* GetCreationContext();
+
+ // 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);
+
+ static void MigrateToNewProperty(Handle<JSObject> object,
+ Handle<Map> transition,
+ Handle<Object> value);
+
private:
friend class DictionaryElementsAccessor;
+ friend class JSReceiver;
+ friend class Object;
- MUST_USE_RESULT MaybeObject* GetElementWithCallback(Object* receiver,
- Object* structure,
- uint32_t index,
- Object* holder);
- MUST_USE_RESULT MaybeObject* SetElementWithCallback(
- Object* structure,
+ static void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map);
+ static void MigrateFastToSlow(Handle<JSObject> object,
+ Handle<Map> new_map,
+ int expected_additional_properties);
+
+ static void GeneralizeFieldRepresentation(Handle<JSObject> object,
+ int modify_index,
+ Representation new_representation,
+ Handle<HeapType> new_field_type);
+
+ static void UpdateAllocationSite(Handle<JSObject> object,
+ ElementsKind to_kind);
+
+ // Used from Object::GetProperty().
+ MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithFailedAccessCheck(
+ LookupIterator* it);
+
+ MUST_USE_RESULT static MaybeHandle<Object> GetElementWithCallback(
+ Handle<JSObject> object,
+ Handle<Object> receiver,
+ Handle<Object> structure,
uint32_t index,
- Object* value,
- JSObject* holder,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetElementWithInterceptor(
+ Handle<Object> holder);
+
+ MUST_USE_RESULT static Maybe<PropertyAttributes>
+ GetElementAttributeWithInterceptor(Handle<JSObject> object,
+ Handle<JSReceiver> receiver,
+ uint32_t index, bool continue_search);
+ MUST_USE_RESULT static Maybe<PropertyAttributes>
+ GetElementAttributeWithoutInterceptor(Handle<JSObject> object,
+ Handle<JSReceiver> receiver,
+ uint32_t index,
+ bool continue_search);
+ MUST_USE_RESULT static MaybeHandle<Object> SetElementWithCallback(
+ Handle<JSObject> object,
+ Handle<Object> structure,
uint32_t index,
- Object* value,
+ Handle<Object> value,
+ Handle<JSObject> holder,
+ StrictMode strict_mode);
+ MUST_USE_RESULT static MaybeHandle<Object> SetElementWithInterceptor(
+ Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode,
+ StrictMode strict_mode,
bool check_prototype,
SetPropertyMode set_mode);
- MUST_USE_RESULT MaybeObject* SetElementWithoutInterceptor(
+ MUST_USE_RESULT static MaybeHandle<Object> SetElementWithoutInterceptor(
+ Handle<JSObject> object,
uint32_t index,
- Object* value,
+ Handle<Object> value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode,
+ StrictMode strict_mode,
bool check_prototype,
SetPropertyMode set_mode);
-
- // Searches the prototype chain for a callback setter and sets the property
- // with the setter if it finds one. The '*found' flag indicates whether
- // a setter was found or not.
- // This function can cause GC and can return a failure result with
- // '*found==true'.
- MUST_USE_RESULT MaybeObject* SetPropertyWithCallbackSetterInPrototypes(
- String* name,
- Object* value,
- PropertyAttributes attributes,
+ MUST_USE_RESULT
+ static MaybeHandle<Object> SetElementWithCallbackSetterInPrototypes(
+ Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
bool* found,
- StrictModeFlag strict_mode);
+ StrictMode strict_mode);
+ MUST_USE_RESULT static MaybeHandle<Object> SetDictionaryElement(
+ Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+ StrictMode strict_mode,
+ bool check_prototype,
+ SetPropertyMode set_mode = SET_PROPERTY);
+ MUST_USE_RESULT static MaybeHandle<Object> SetFastDoubleElement(
+ Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
+ StrictMode strict_mode,
+ bool check_prototype = true);
- MUST_USE_RESULT MaybeObject* DeletePropertyPostInterceptor(String* name,
- DeleteMode mode);
- MUST_USE_RESULT MaybeObject* DeletePropertyWithInterceptor(String* name);
+ MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithFailedAccessCheck(
+ LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
- MUST_USE_RESULT MaybeObject* DeleteElementWithInterceptor(uint32_t index);
+ // Add a property to a slow-case object.
+ static void AddSlowProperty(Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> value,
+ PropertyAttributes attributes);
- MUST_USE_RESULT MaybeObject* DeleteFastElement(uint32_t index);
- MUST_USE_RESULT MaybeObject* DeleteDictionaryElement(uint32_t index,
- DeleteMode mode);
+ MUST_USE_RESULT static MaybeHandle<Object> DeleteProperty(
+ Handle<JSObject> object,
+ Handle<Name> name,
+ DeleteMode mode);
+ MUST_USE_RESULT static MaybeHandle<Object> DeletePropertyWithInterceptor(
+ Handle<JSObject> holder, Handle<JSObject> receiver, Handle<Name> name);
+
+ // Deletes the named property in a normalized object.
+ static Handle<Object> DeleteNormalizedProperty(Handle<JSObject> object,
+ Handle<Name> name,
+ DeleteMode mode);
+
+ MUST_USE_RESULT static MaybeHandle<Object> DeleteElement(
+ Handle<JSObject> object,
+ uint32_t index,
+ DeleteMode mode);
+ MUST_USE_RESULT static MaybeHandle<Object> DeleteElementWithInterceptor(
+ Handle<JSObject> object,
+ uint32_t index);
bool ReferencesObjectFromElements(FixedArray* elements,
ElementsKind kind,
@@ -2172,37 +2332,39 @@
// Gets the current elements capacity and the number of used elements.
void GetElementsCapacityAndUsage(int* capacity, int* used);
- bool CanSetCallback(String* name);
- MUST_USE_RESULT MaybeObject* SetElementCallback(
- uint32_t index,
- Object* structure,
- PropertyAttributes attributes);
- MUST_USE_RESULT MaybeObject* SetPropertyCallback(
- String* name,
- Object* structure,
- PropertyAttributes attributes);
- MUST_USE_RESULT MaybeObject* DefineElementAccessor(
- uint32_t index,
- Object* getter,
- Object* setter,
- PropertyAttributes attributes);
- MUST_USE_RESULT MaybeObject* DefinePropertyAccessor(
- String* name,
- Object* getter,
- Object* setter,
- PropertyAttributes attributes);
- void LookupInDescriptor(String* name, LookupResult* result);
+ static bool CanSetCallback(Handle<JSObject> object, Handle<Name> name);
+ static void SetElementCallback(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> structure,
+ PropertyAttributes attributes);
+ static void SetPropertyCallback(Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> structure,
+ PropertyAttributes attributes);
+ static void DefineElementAccessor(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> getter,
+ Handle<Object> setter,
+ PropertyAttributes attributes);
- // Returns the hidden properties backing store object, currently
- // a StringDictionary, stored on this object.
- // If no hidden properties object has been put on this object,
- // return undefined, unless create_if_absent is true, in which case
- // a new dictionary is created, added to this object, and returned.
- MUST_USE_RESULT MaybeObject* GetHiddenPropertiesDictionary(
- bool create_if_absent);
- // Updates the existing hidden properties dictionary.
- MUST_USE_RESULT MaybeObject* SetHiddenPropertiesDictionary(
- StringDictionary* dictionary);
+ // Return the hash table backing store or the inline stored identity hash,
+ // whatever is found.
+ MUST_USE_RESULT Object* GetHiddenPropertiesHashTable();
+
+ // Return the hash table backing store for hidden properties. If there is no
+ // backing store, allocate one.
+ static Handle<ObjectHashTable> GetOrCreateHiddenPropertiesHashtable(
+ Handle<JSObject> object);
+
+ // Set the hidden property backing store to either a hash table or
+ // the inline-stored identity hash.
+ static Handle<Object> SetHiddenPropertiesHashTable(
+ Handle<JSObject> object,
+ Handle<Object> value);
+
+ MUST_USE_RESULT Object* GetIdentityHash();
+
+ static Handle<Smi> GetOrCreateIdentityHash(Handle<JSObject> object);
DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject);
};
@@ -2213,10 +2375,14 @@
class FixedArrayBase: public HeapObject {
public:
// [length]: length of the array.
- inline int length();
+ inline int length() const;
inline void set_length(int value);
- inline static FixedArrayBase* cast(Object* object);
+ // Get and set the length using acquire loads and release stores.
+ inline int synchronized_length() const;
+ inline void synchronized_set_length(int value);
+
+ DECLARE_CAST(FixedArrayBase)
// Layout description.
// Length is smi tagged when it is stored.
@@ -2226,51 +2392,55 @@
class FixedDoubleArray;
+class IncrementalMarking;
+
// FixedArray describes fixed-sized arrays with element type Object*.
class FixedArray: public FixedArrayBase {
public:
// Setter and getter for elements.
inline Object* get(int index);
+ static inline Handle<Object> get(Handle<FixedArray> array, int index);
// Setter that uses write barrier.
inline void set(int index, Object* value);
inline bool is_the_hole(int index);
- // Setter that doesn't need write barrier).
+ // Setter that doesn't need write barrier.
inline void set(int index, Smi* value);
// Setter with explicit barrier mode.
inline void set(int index, Object* value, WriteBarrierMode mode);
// Setters for frequently used oddballs located in old space.
inline void set_undefined(int index);
- // TODO(isolates): duplicate.
- inline void set_undefined(Heap* heap, int index);
inline void set_null(int index);
- // TODO(isolates): duplicate.
- inline void set_null(Heap* heap, int index);
inline void set_the_hole(int index);
- // Setters with less debug checks for the GC to use.
- inline void set_unchecked(int index, Smi* value);
- inline void set_null_unchecked(Heap* heap, int index);
- 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();
- // Copy operations.
- MUST_USE_RESULT inline MaybeObject* Copy();
- MUST_USE_RESULT MaybeObject* CopySize(int new_length);
+ // Gives access to raw memory which stores the array's data.
+ inline Object** data_start();
+
+ inline void FillWithHoles(int from, int to);
+
+ // Shrink length and insert filler objects.
+ void Shrink(int length);
+
+ // Copy operation.
+ static Handle<FixedArray> CopySize(Handle<FixedArray> array,
+ int new_length,
+ PretenureFlag pretenure = NOT_TENURED);
// Add the elements of a JSArray to this FixedArray.
- MUST_USE_RESULT MaybeObject* AddKeysFromJSArray(JSArray* array);
+ MUST_USE_RESULT static MaybeHandle<FixedArray> AddKeysFromArrayLike(
+ Handle<FixedArray> content,
+ Handle<JSObject> array);
- // Compute the union of this and other.
- MUST_USE_RESULT MaybeObject* UnionOfKeys(FixedArray* other);
+ // Computes the union of keys and return the result.
+ // Used for implementing "for (n in object) { }"
+ MUST_USE_RESULT static MaybeHandle<FixedArray> UnionOfKeys(
+ Handle<FixedArray> first,
+ Handle<FixedArray> second);
// Copy a sub array from the receiver to dest.
void CopyTo(int pos, FixedArray* dest, int dest_pos, int len);
@@ -2281,8 +2451,12 @@
// Code Generation support.
static int OffsetOfElementAt(int index) { return SizeFor(index); }
- // Casting.
- static inline FixedArray* cast(Object* obj);
+ // Garbage collection support.
+ Object** RawFieldOfElementAt(int index) {
+ return HeapObject::RawField(this, OffsetOfElementAt(index));
+ }
+
+ DECLARE_CAST(FixedArray)
// Maximal allowed size, in bytes, of a single FixedArray.
// Prevents overflowing size computations, as well as extreme memory
@@ -2292,14 +2466,9 @@
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
- void FixedArrayVerify();
// Checks if two FixedArrays have identical contents.
bool IsEqualTo(FixedArray* other);
#endif
@@ -2336,6 +2505,8 @@
Object* value);
private:
+ STATIC_ASSERT(kHeaderSize == Internals::kFixedArrayHeaderSize);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(FixedArray);
};
@@ -2346,21 +2517,23 @@
// Setter and getter for elements.
inline double get_scalar(int index);
inline int64_t get_representation(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<FixedDoubleArray> array, int index);
inline void set(int index, double value);
inline void set_the_hole(int index);
// Checking for the hole.
inline bool is_the_hole(int index);
- // Copy operations
- MUST_USE_RESULT inline MaybeObject* Copy();
-
// Garbage collection support.
inline static int SizeFor(int length) {
return kHeaderSize + length * kDoubleSize;
}
+ // Gives access to raw memory which stores the array's data.
+ inline double* data_start();
+
+ inline void FillWithHoles(int from, int to);
+
// Code Generation support.
static int OffsetOfElementAt(int index) { return SizeFor(index); }
@@ -2368,8 +2541,7 @@
inline static double hole_nan_as_double();
inline static double canonical_not_the_hole_nan_as_double();
- // Casting.
- static inline FixedDoubleArray* cast(Object* obj);
+ DECLARE_CAST(FixedDoubleArray)
// Maximal allowed size, in bytes, of a single FixedDoubleArray.
// Prevents overflowing size computations, as well as extreme memory
@@ -2379,38 +2551,332 @@
static const int kMaxLength = (kMaxSize - kHeaderSize) / kDoubleSize;
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void FixedDoubleArrayPrint() {
- FixedDoubleArrayPrint(stdout);
- }
- void FixedDoubleArrayPrint(FILE* out);
-#endif
-
-#ifdef DEBUG
- void FixedDoubleArrayVerify();
-#endif
+ DECLARE_PRINTER(FixedDoubleArray)
+ DECLARE_VERIFIER(FixedDoubleArray)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(FixedDoubleArray);
};
-class IncrementalMarking;
+// ConstantPoolArray describes a fixed-sized array containing constant pool
+// entries.
+//
+// A ConstantPoolArray can be structured in two different ways depending upon
+// whether it is extended or small. The is_extended_layout() method can be used
+// to discover which layout the constant pool has.
+//
+// The format of a small constant pool is:
+// [kSmallLayout1Offset] : Small section layout bitmap 1
+// [kSmallLayout2Offset] : Small section layout bitmap 2
+// [first_index(INT64, SMALL_SECTION)] : 64 bit entries
+// ... : ...
+// [first_index(CODE_PTR, SMALL_SECTION)] : code pointer entries
+// ... : ...
+// [first_index(HEAP_PTR, SMALL_SECTION)] : heap pointer entries
+// ... : ...
+// [first_index(INT32, SMALL_SECTION)] : 32 bit entries
+// ... : ...
+//
+// If the constant pool has an extended layout, the extended section constant
+// pool also contains an extended section, which has the following format at
+// location get_extended_section_header_offset():
+// [kExtendedInt64CountOffset] : count of extended 64 bit entries
+// [kExtendedCodePtrCountOffset] : count of extended code pointers
+// [kExtendedHeapPtrCountOffset] : count of extended heap pointers
+// [kExtendedInt32CountOffset] : count of extended 32 bit entries
+// [first_index(INT64, EXTENDED_SECTION)] : 64 bit entries
+// ... : ...
+// [first_index(CODE_PTR, EXTENDED_SECTION)]: code pointer entries
+// ... : ...
+// [first_index(HEAP_PTR, EXTENDED_SECTION)]: heap pointer entries
+// ... : ...
+// [first_index(INT32, EXTENDED_SECTION)] : 32 bit entries
+// ... : ...
+//
+class ConstantPoolArray: public HeapObject {
+ public:
+ enum WeakObjectState {
+ NO_WEAK_OBJECTS,
+ WEAK_OBJECTS_IN_OPTIMIZED_CODE,
+ WEAK_OBJECTS_IN_IC
+ };
+
+ enum Type {
+ INT64 = 0,
+ CODE_PTR,
+ HEAP_PTR,
+ INT32,
+ // Number of types stored by the ConstantPoolArrays.
+ NUMBER_OF_TYPES,
+ FIRST_TYPE = INT64,
+ LAST_TYPE = INT32
+ };
+
+ enum LayoutSection {
+ SMALL_SECTION = 0,
+ EXTENDED_SECTION,
+ NUMBER_OF_LAYOUT_SECTIONS
+ };
+
+ class NumberOfEntries BASE_EMBEDDED {
+ public:
+ inline NumberOfEntries() {
+ for (int i = 0; i < NUMBER_OF_TYPES; i++) {
+ element_counts_[i] = 0;
+ }
+ }
+
+ inline NumberOfEntries(int int64_count, int code_ptr_count,
+ int heap_ptr_count, int int32_count) {
+ element_counts_[INT64] = int64_count;
+ element_counts_[CODE_PTR] = code_ptr_count;
+ element_counts_[HEAP_PTR] = heap_ptr_count;
+ element_counts_[INT32] = int32_count;
+ }
+
+ inline NumberOfEntries(ConstantPoolArray* array, LayoutSection section) {
+ element_counts_[INT64] = array->number_of_entries(INT64, section);
+ element_counts_[CODE_PTR] = array->number_of_entries(CODE_PTR, section);
+ element_counts_[HEAP_PTR] = array->number_of_entries(HEAP_PTR, section);
+ element_counts_[INT32] = array->number_of_entries(INT32, section);
+ }
+
+ inline void increment(Type type);
+ inline int equals(const NumberOfEntries& other) const;
+ inline bool is_empty() const;
+ inline int count_of(Type type) const;
+ inline int base_of(Type type) const;
+ inline int total_count() const;
+ inline int are_in_range(int min, int max) const;
+
+ private:
+ int element_counts_[NUMBER_OF_TYPES];
+ };
+
+ class Iterator BASE_EMBEDDED {
+ public:
+ inline Iterator(ConstantPoolArray* array, Type type)
+ : array_(array),
+ type_(type),
+ final_section_(array->final_section()),
+ current_section_(SMALL_SECTION),
+ next_index_(array->first_index(type, SMALL_SECTION)) {
+ update_section();
+ }
+
+ inline Iterator(ConstantPoolArray* array, Type type, LayoutSection section)
+ : array_(array),
+ type_(type),
+ final_section_(section),
+ current_section_(section),
+ next_index_(array->first_index(type, section)) {
+ update_section();
+ }
+
+ inline int next_index();
+ inline bool is_finished();
+
+ private:
+ inline void update_section();
+ ConstantPoolArray* array_;
+ const Type type_;
+ const LayoutSection final_section_;
+
+ LayoutSection current_section_;
+ int next_index_;
+ };
+
+ // Getters for the first index, the last index and the count of entries of
+ // a given type for a given layout section.
+ inline int first_index(Type type, LayoutSection layout_section);
+ inline int last_index(Type type, LayoutSection layout_section);
+ inline int number_of_entries(Type type, LayoutSection layout_section);
+
+ // Returns the type of the entry at the given index.
+ inline Type get_type(int index);
+ inline bool offset_is_type(int offset, Type type);
+
+ // Setter and getter for pool elements.
+ inline Address get_code_ptr_entry(int index);
+ inline Object* get_heap_ptr_entry(int index);
+ inline int64_t get_int64_entry(int index);
+ inline int32_t get_int32_entry(int index);
+ inline double get_int64_entry_as_double(int index);
+
+ inline void set(int index, Address value);
+ inline void set(int index, Object* value);
+ inline void set(int index, int64_t value);
+ inline void set(int index, double value);
+ inline void set(int index, int32_t value);
+
+ // Setters which take a raw offset rather than an index (for code generation).
+ inline void set_at_offset(int offset, int32_t value);
+ inline void set_at_offset(int offset, int64_t value);
+ inline void set_at_offset(int offset, double value);
+ inline void set_at_offset(int offset, Address value);
+ inline void set_at_offset(int offset, Object* value);
+
+ // Setter and getter for weak objects state
+ inline void set_weak_object_state(WeakObjectState state);
+ inline WeakObjectState get_weak_object_state();
+
+ // Returns true if the constant pool has an extended layout, false if it has
+ // only the small layout.
+ inline bool is_extended_layout();
+
+ // Returns the last LayoutSection in this constant pool array.
+ inline LayoutSection final_section();
+
+ // Set up initial state for a small layout constant pool array.
+ inline void Init(const NumberOfEntries& small);
+
+ // Set up initial state for an extended layout constant pool array.
+ inline void InitExtended(const NumberOfEntries& small,
+ const NumberOfEntries& extended);
+
+ // Clears the pointer entries with GC safe values.
+ void ClearPtrEntries(Isolate* isolate);
+
+ // returns the total number of entries in the constant pool array.
+ inline int length();
+
+ // Garbage collection support.
+ inline int size();
+
+
+ inline static int MaxInt64Offset(int number_of_int64) {
+ return kFirstEntryOffset + (number_of_int64 * kInt64Size);
+ }
+
+ inline static int SizeFor(const NumberOfEntries& small) {
+ int size = kFirstEntryOffset +
+ (small.count_of(INT64) * kInt64Size) +
+ (small.count_of(CODE_PTR) * kPointerSize) +
+ (small.count_of(HEAP_PTR) * kPointerSize) +
+ (small.count_of(INT32) * kInt32Size);
+ return RoundUp(size, kPointerSize);
+ }
+
+ inline static int SizeForExtended(const NumberOfEntries& small,
+ const NumberOfEntries& extended) {
+ int size = SizeFor(small);
+ size = RoundUp(size, kInt64Size); // Align extended header to 64 bits.
+ size += kExtendedFirstOffset +
+ (extended.count_of(INT64) * kInt64Size) +
+ (extended.count_of(CODE_PTR) * kPointerSize) +
+ (extended.count_of(HEAP_PTR) * kPointerSize) +
+ (extended.count_of(INT32) * kInt32Size);
+ return RoundUp(size, kPointerSize);
+ }
+
+ inline static int entry_size(Type type) {
+ switch (type) {
+ case INT32:
+ return kInt32Size;
+ case INT64:
+ return kInt64Size;
+ case CODE_PTR:
+ case HEAP_PTR:
+ return kPointerSize;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+ }
+
+ // Code Generation support.
+ inline int OffsetOfElementAt(int index) {
+ int offset;
+ LayoutSection section;
+ if (is_extended_layout() && index >= first_extended_section_index()) {
+ section = EXTENDED_SECTION;
+ offset = get_extended_section_header_offset() + kExtendedFirstOffset;
+ } else {
+ section = SMALL_SECTION;
+ offset = kFirstEntryOffset;
+ }
+
+ // Add offsets for the preceding type sections.
+ DCHECK(index <= last_index(LAST_TYPE, section));
+ for (Type type = FIRST_TYPE; index > last_index(type, section);
+ type = next_type(type)) {
+ offset += entry_size(type) * number_of_entries(type, section);
+ }
+
+ // Add offset for the index in it's type.
+ Type type = get_type(index);
+ offset += entry_size(type) * (index - first_index(type, section));
+ return offset;
+ }
+
+ DECLARE_CAST(ConstantPoolArray)
+
+ // Garbage collection support.
+ Object** RawFieldOfElementAt(int index) {
+ return HeapObject::RawField(this, OffsetOfElementAt(index));
+ }
+
+ // Small Layout description.
+ static const int kSmallLayout1Offset = HeapObject::kHeaderSize;
+ static const int kSmallLayout2Offset = kSmallLayout1Offset + kInt32Size;
+ static const int kHeaderSize = kSmallLayout2Offset + kInt32Size;
+ static const int kFirstEntryOffset = ROUND_UP(kHeaderSize, kInt64Size);
+
+ static const int kSmallLayoutCountBits = 10;
+ static const int kMaxSmallEntriesPerType = (1 << kSmallLayoutCountBits) - 1;
+
+ // Fields in kSmallLayout1Offset.
+ class Int64CountField: public BitField<int, 1, kSmallLayoutCountBits> {};
+ class CodePtrCountField: public BitField<int, 11, kSmallLayoutCountBits> {};
+ class HeapPtrCountField: public BitField<int, 21, kSmallLayoutCountBits> {};
+ class IsExtendedField: public BitField<bool, 31, 1> {};
+
+ // Fields in kSmallLayout2Offset.
+ class Int32CountField: public BitField<int, 1, kSmallLayoutCountBits> {};
+ class TotalCountField: public BitField<int, 11, 12> {};
+ class WeakObjectStateField: public BitField<WeakObjectState, 23, 2> {};
+
+ // Extended layout description, which starts at
+ // get_extended_section_header_offset().
+ static const int kExtendedInt64CountOffset = 0;
+ static const int kExtendedCodePtrCountOffset =
+ kExtendedInt64CountOffset + kPointerSize;
+ static const int kExtendedHeapPtrCountOffset =
+ kExtendedCodePtrCountOffset + kPointerSize;
+ static const int kExtendedInt32CountOffset =
+ kExtendedHeapPtrCountOffset + kPointerSize;
+ static const int kExtendedFirstOffset =
+ kExtendedInt32CountOffset + kPointerSize;
+
+ // Dispatched behavior.
+ void ConstantPoolIterateBody(ObjectVisitor* v);
+
+ DECLARE_PRINTER(ConstantPoolArray)
+ DECLARE_VERIFIER(ConstantPoolArray)
+
+ private:
+ inline int first_extended_section_index();
+ inline int get_extended_section_header_offset();
+
+ inline static Type next_type(Type type) {
+ DCHECK(type >= FIRST_TYPE && type < NUMBER_OF_TYPES);
+ int type_int = static_cast<int>(type);
+ return static_cast<Type>(++type_int);
+ }
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantPoolArray);
+};
// DescriptorArrays are fixed arrays used to hold instance descriptors.
// The format of the these objects is:
-// TODO(1399): It should be possible to make room for bit_field3 in the map
-// without overloading the instance descriptors field in the map
-// (and storing it in the DescriptorArray when the map has one).
-// [0]: storage for bit_field3 for Map owning this object (Smi)
-// [1]: point to a fixed array with (value, detail) pairs.
-// [2]: next enumeration index (Smi), or pointer to small fixed array:
-// [0]: next enumeration index (Smi)
-// [1]: pointer to fixed array with enum cache
-// [3]: first key
-// [length() - 1]: last key
-//
+// [0]: Number of descriptors
+// [1]: Either Smi(0) if uninitialized, or a pointer to small fixed array:
+// [0]: pointer to fixed array with enum cache
+// [1]: either Smi(0) or pointer to fixed array with indices
+// [2]: first key
+// [2 + number of descriptors * kDescriptorSize]: start of slack
class DescriptorArray: public FixedArray {
public:
// Returns true for both shared empty_descriptor_array and for smis, which the
@@ -2420,43 +2886,58 @@
// Returns the number of descriptors in the array.
int number_of_descriptors() {
- ASSERT(length() > kFirstIndex || IsEmpty());
+ DCHECK(length() >= kFirstIndex || IsEmpty());
int len = length();
- return len <= kFirstIndex ? 0 : len - kFirstIndex;
+ return len == 0 ? 0 : Smi::cast(get(kDescriptorLengthIndex))->value();
}
- int NextEnumerationIndex() {
- if (IsEmpty()) return PropertyDetails::kInitialIndex;
- Object* obj = get(kEnumerationIndexIndex);
- if (obj->IsSmi()) {
- return Smi::cast(obj)->value();
- } else {
- Object* index = FixedArray::cast(obj)->get(kEnumCacheBridgeEnumIndex);
- return Smi::cast(index)->value();
- }
+ int number_of_descriptors_storage() {
+ int len = length();
+ return len == 0 ? 0 : (len - kFirstIndex) / kDescriptorSize;
}
- // Set next enumeration index and flush any enum cache.
- void SetNextEnumerationIndex(int value) {
- if (!IsEmpty()) {
- set(kEnumerationIndexIndex, Smi::FromInt(value));
- }
+ int NumberOfSlackDescriptors() {
+ return number_of_descriptors_storage() - number_of_descriptors();
}
+
+ inline void SetNumberOfDescriptors(int number_of_descriptors);
+ inline int number_of_entries() { return number_of_descriptors(); }
+
bool HasEnumCache() {
- return !IsEmpty() && !get(kEnumerationIndexIndex)->IsSmi();
+ return !IsEmpty() && !get(kEnumCacheIndex)->IsSmi();
}
- Object* GetEnumCache() {
- ASSERT(HasEnumCache());
- FixedArray* bridge = FixedArray::cast(get(kEnumerationIndexIndex));
- return bridge->get(kEnumCacheBridgeCacheIndex);
+ void CopyEnumCacheFrom(DescriptorArray* array) {
+ set(kEnumCacheIndex, array->get(kEnumCacheIndex));
}
- // TODO(1399): It should be possible to make room for bit_field3 in the map
- // without overloading the instance descriptors field in the map
- // (and storing it in the DescriptorArray when the map has one).
- inline int bit_field3_storage();
- inline void set_bit_field3_storage(int value);
+ FixedArray* GetEnumCache() {
+ DCHECK(HasEnumCache());
+ FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex));
+ return FixedArray::cast(bridge->get(kEnumCacheBridgeCacheIndex));
+ }
+
+ bool HasEnumIndicesCache() {
+ if (IsEmpty()) return false;
+ Object* object = get(kEnumCacheIndex);
+ if (object->IsSmi()) return false;
+ FixedArray* bridge = FixedArray::cast(object);
+ return !bridge->get(kEnumCacheBridgeIndicesCacheIndex)->IsSmi();
+ }
+
+ FixedArray* GetEnumIndicesCache() {
+ DCHECK(HasEnumIndicesCache());
+ FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex));
+ return FixedArray::cast(bridge->get(kEnumCacheBridgeIndicesCacheIndex));
+ }
+
+ Object** GetEnumCacheSlot() {
+ DCHECK(HasEnumCache());
+ return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
+ kEnumCacheOffset);
+ }
+
+ void ClearEnumCache();
// Initialize or change the enum cache,
// using the supplied storage for the small "bridge".
@@ -2464,20 +2945,126 @@
FixedArray* new_cache,
Object* new_index_cache);
+ bool CanHoldValue(int descriptor, Object* value);
+
// 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 Smi* GetDetails(int descriptor_number);
+ inline void SetValue(int descriptor_number, Object* value);
+ inline Object** GetValueSlot(int descriptor_number);
+ static inline int GetValueOffset(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);
- inline JSFunction* GetConstantFunction(int descriptor_number);
+ inline HeapType* GetFieldType(int descriptor_number);
+ inline Object* GetConstant(int descriptor_number);
inline Object* GetCallbacksObject(int descriptor_number);
inline AccessorDescriptor* GetCallbacks(int descriptor_number);
- inline bool IsProperty(int descriptor_number);
- inline bool IsTransitionOnly(int descriptor_number);
- inline bool IsNullDescriptor(int descriptor_number);
- inline bool IsDontEnum(int descriptor_number);
+ inline Name* GetSortedKey(int descriptor_number);
+ inline int GetSortedKeyIndex(int descriptor_number);
+ inline void SetSortedKey(int pointer, int descriptor_number);
+ inline void SetRepresentation(int descriptor_number,
+ Representation representation);
+
+ // Accessor for complete descriptor.
+ inline void Get(int descriptor_number, Descriptor* desc);
+ inline void Set(int descriptor_number, Descriptor* desc);
+ void Replace(int descriptor_number, Descriptor* descriptor);
+
+ // Append automatically sets the enumeration index. This should only be used
+ // to add descriptors in bulk at the end, followed by sorting the descriptor
+ // array.
+ inline void Append(Descriptor* desc);
+
+ static Handle<DescriptorArray> CopyUpTo(Handle<DescriptorArray> desc,
+ int enumeration_index,
+ int slack = 0);
+
+ static Handle<DescriptorArray> CopyUpToAddAttributes(
+ Handle<DescriptorArray> desc,
+ int enumeration_index,
+ PropertyAttributes attributes,
+ int slack = 0);
+
+ // Sort the instance descriptors by the hash codes of their keys.
+ void Sort();
+
+ // Search the instance descriptors for given name.
+ INLINE(int Search(Name* name, int number_of_own_descriptors));
+
+ // As the above, but uses DescriptorLookupCache and updates it when
+ // necessary.
+ INLINE(int SearchWithCache(Name* name, Map* map));
+
+ // Allocates a DescriptorArray, but returns the singleton
+ // empty descriptor array object if number_of_descriptors is 0.
+ static Handle<DescriptorArray> Allocate(Isolate* isolate,
+ int number_of_descriptors,
+ int slack = 0);
+
+ DECLARE_CAST(DescriptorArray)
+
+ // Constant for denoting key was not found.
+ static const int kNotFound = -1;
+
+ static const int kDescriptorLengthIndex = 0;
+ static const int kEnumCacheIndex = 1;
+ static const int kFirstIndex = 2;
+
+ // The length of the "bridge" to the enum cache.
+ static const int kEnumCacheBridgeLength = 2;
+ static const int kEnumCacheBridgeCacheIndex = 0;
+ static const int kEnumCacheBridgeIndicesCacheIndex = 1;
+
+ // Layout description.
+ static const int kDescriptorLengthOffset = FixedArray::kHeaderSize;
+ static const int kEnumCacheOffset = kDescriptorLengthOffset + kPointerSize;
+ static const int kFirstOffset = kEnumCacheOffset + kPointerSize;
+
+ // Layout description for the bridge array.
+ static const int kEnumCacheBridgeCacheOffset = FixedArray::kHeaderSize;
+
+ // Layout of descriptor.
+ static const int kDescriptorKey = 0;
+ static const int kDescriptorDetails = 1;
+ static const int kDescriptorValue = 2;
+ static const int kDescriptorSize = 3;
+
+#ifdef OBJECT_PRINT
+ // Print all the descriptors.
+ void PrintDescriptors(OStream& os); // NOLINT
+#endif
+
+#ifdef DEBUG
+ // Is the descriptor array sorted and without duplicates?
+ bool IsSortedNoDuplicates(int valid_descriptors = -1);
+
+ // Is the descriptor array consistent with the back pointers in targets?
+ bool IsConsistentWithBackPointers(Map* current_map);
+
+ // Are two DescriptorArrays equal?
+ bool IsEqualTo(DescriptorArray* other);
+#endif
+
+ // Returns the fixed array length required to hold number_of_descriptors
+ // descriptors.
+ static int LengthFor(int number_of_descriptors) {
+ return ToKeyIndex(number_of_descriptors);
+ }
+
+ private:
+ // WhitenessWitness is used to prove that a descriptor array is white
+ // (unmarked), so incremental write barriers can be skipped because the
+ // marking invariant cannot be broken and slots pointing into evacuation
+ // candidates will be discovered when the object is scanned. A witness is
+ // always stack-allocated right after creating an array. By allocating a
+ // witness, incremental marking is globally disabled. The witness is then
+ // passed along wherever needed to statically prove that the array is known to
+ // be white.
class WhitenessWitness {
public:
inline explicit WhitenessWitness(DescriptorArray* array);
@@ -2487,122 +3074,6 @@
IncrementalMarking* marking_;
};
- // Accessor for complete descriptor.
- inline void Get(int descriptor_number, Descriptor* desc);
- inline void Set(int descriptor_number,
- Descriptor* desc,
- const WhitenessWitness&);
-
- // Transfer a complete descriptor from the src descriptor array to the dst
- // one, dropping map transitions in CALLBACKS.
- static void CopyFrom(Handle<DescriptorArray> dst,
- int dst_index,
- Handle<DescriptorArray> src,
- int src_index,
- const WhitenessWitness& witness);
-
- // Transfer a complete descriptor from the src descriptor array to this
- // descriptor array, dropping map transitions in CALLBACKS.
- MUST_USE_RESULT MaybeObject* CopyFrom(int dst_index,
- DescriptorArray* src,
- int src_index,
- const WhitenessWitness&);
-
- // Copy the descriptor array, insert a new descriptor and optionally
- // remove map transitions. If the descriptor is already present, it is
- // replaced. If a replaced descriptor is a real property (not a transition
- // or null), its enumeration index is kept as is.
- // If adding a real property, map transitions must be removed. If adding
- // a transition, they must not be removed. All null descriptors are removed.
- MUST_USE_RESULT MaybeObject* CopyInsert(Descriptor* descriptor,
- TransitionFlag transition_flag);
-
- // Return a copy of the array with all transitions and null descriptors
- // removed. Return a Failure object in case of an allocation failure.
- MUST_USE_RESULT MaybeObject* RemoveTransitions();
-
- // Sort the instance descriptors by the hash codes of their keys.
- // Does not check for duplicates.
- void SortUnchecked(const WhitenessWitness&);
-
- // Sort the instance descriptors by the hash codes of their keys.
- // Checks the result for duplicates.
- void Sort(const WhitenessWitness&);
-
- // Search the instance descriptors for given name.
- inline int Search(String* name);
-
- // As the above, but uses DescriptorLookupCache and updates it when
- // necessary.
- inline int SearchWithCache(String* name);
-
- // Tells whether the name is present int the array.
- bool Contains(String* name) { return kNotFound != Search(name); }
-
- // Perform a binary search in the instance descriptors represented
- // by this fixed array. low and high are descriptor indices. If there
- // are three instance descriptors in this array it should be called
- // with low=0 and high=2.
- int BinarySearch(String* name, int low, int high);
-
- // Perform a linear search in the instance descriptors represented
- // by this fixed array. len is the number of descriptor indices that are
- // valid. Does not require the descriptors to be sorted.
- int LinearSearch(String* name, int len);
-
- // Allocates a DescriptorArray, but returns the singleton
- // empty descriptor array object if number_of_descriptors is 0.
- MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors);
-
- // Casting.
- static inline DescriptorArray* cast(Object* obj);
-
- // Constant for denoting key was not found.
- static const int kNotFound = -1;
-
- static const int kBitField3StorageIndex = 0;
- static const int kContentArrayIndex = 1;
- static const int kEnumerationIndexIndex = 2;
- static const int kFirstIndex = 3;
-
- // The length of the "bridge" to the enum cache.
- static const int kEnumCacheBridgeLength = 3;
- static const int kEnumCacheBridgeEnumIndex = 0;
- static const int kEnumCacheBridgeCacheIndex = 1;
- static const int kEnumCacheBridgeIndicesCacheIndex = 2;
-
- // Layout description.
- static const int kBitField3StorageOffset = FixedArray::kHeaderSize;
- static const int kContentArrayOffset = kBitField3StorageOffset + kPointerSize;
- static const int kEnumerationIndexOffset = kContentArrayOffset + kPointerSize;
- static const int kFirstOffset = kEnumerationIndexOffset + kPointerSize;
-
- // Layout description for the bridge array.
- static const int kEnumCacheBridgeEnumOffset = FixedArray::kHeaderSize;
- static const int kEnumCacheBridgeCacheOffset =
- kEnumCacheBridgeEnumOffset + kPointerSize;
-
-#ifdef OBJECT_PRINT
- // Print all the descriptors.
- inline void PrintDescriptors() {
- PrintDescriptors(stdout);
- }
- void PrintDescriptors(FILE* out);
-#endif
-
-#ifdef DEBUG
- // Is the descriptor array sorted and without duplicates?
- bool IsSortedNoDuplicates();
-
- // Are two DescriptorArrays equal?
- bool IsEqualTo(DescriptorArray* other);
-#endif
-
- // The maximum number of descriptors we want in a descriptor array (should
- // fit in a page).
- static const int kMaxNumberOfDescriptors = 1024 + 512;
-
- private:
// An entry in a DescriptorArray, represented as an (array, index) pair.
class Entry {
public:
@@ -2619,36 +3090,50 @@
// Conversion from descriptor number to array indices.
static int ToKeyIndex(int descriptor_number) {
- return descriptor_number+kFirstIndex;
+ return kFirstIndex +
+ (descriptor_number * kDescriptorSize) +
+ kDescriptorKey;
}
static int ToDetailsIndex(int descriptor_number) {
- return (descriptor_number << 1) + 1;
+ return kFirstIndex +
+ (descriptor_number * kDescriptorSize) +
+ kDescriptorDetails;
}
static int ToValueIndex(int descriptor_number) {
- return descriptor_number << 1;
+ return kFirstIndex +
+ (descriptor_number * kDescriptorSize) +
+ kDescriptorValue;
}
- bool is_null_descriptor(int descriptor_number) {
- return PropertyDetails(GetDetails(descriptor_number)).type() ==
- NULL_DESCRIPTOR;
- }
- // Swap operation on FixedArray without using write barriers.
- static inline void NoIncrementalWriteBarrierSwap(
- FixedArray* array, int first, int second);
+ // Transfer a complete descriptor from the src descriptor array to this
+ // descriptor array.
+ void CopyFrom(int index,
+ DescriptorArray* src,
+ const WhitenessWitness&);
- // Swap descriptor first and second.
- inline void NoIncrementalWriteBarrierSwapDescriptors(
- int first, int second);
+ inline void Set(int descriptor_number,
+ Descriptor* desc,
+ const WhitenessWitness&);
- FixedArray* GetContentArray() {
- return FixedArray::cast(get(kContentArrayIndex));
- }
+ // Swap first and second descriptor.
+ inline void SwapSortedKeys(int first, int second);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(DescriptorArray);
};
+enum SearchMode { ALL_ENTRIES, VALID_ENTRIES };
+
+template<SearchMode search_mode, typename T>
+inline int LinearSearch(T* array, Name* name, int len, int valid_entries);
+
+
+template<SearchMode search_mode, typename T>
+inline int Search(T* array, Name* name, int valid_entries = 0);
+
+
// HashTable is a subclass of FixedArray that implements a hash table
// that uses open addressing and quadratic probing.
//
@@ -2671,7 +3156,7 @@
// // 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 Handle<Object> AsHandle(Isolate* isolate, Key key);
// // The prefix size indicates number of elements in the beginning
// // of the backing storage.
// static const int kPrefixSize = ..;
@@ -2688,24 +3173,23 @@
static const bool UsesSeed = false;
static uint32_t Hash(Key key) { return 0; }
static uint32_t SeededHash(Key key, uint32_t seed) {
- ASSERT(UsesSeed);
+ DCHECK(UsesSeed);
return Hash(key);
}
static uint32_t HashForObject(Key key, Object* object) { return 0; }
static uint32_t SeededHashForObject(Key key, uint32_t seed, Object* object) {
- ASSERT(UsesSeed);
+ DCHECK(UsesSeed);
return HashForObject(key, object);
}
};
-template<typename Shape, typename Key>
+template<typename Derived, typename Shape, typename Key>
class HashTable: public FixedArray {
public:
// Wrapper methods
inline uint32_t Hash(Key key) {
if (Shape::UsesSeed) {
- return Shape::SeededHash(key,
- GetHeap()->HashSeed());
+ return Shape::SeededHash(key, GetHeap()->HashSeed());
} else {
return Shape::Hash(key);
}
@@ -2713,8 +3197,7 @@
inline uint32_t HashForObject(Key key, Object* object) {
if (Shape::UsesSeed) {
- return Shape::SeededHashForObject(key,
- GetHeap()->HashSeed(), object);
+ return Shape::SeededHashForObject(key, GetHeap()->HashSeed(), object);
} else {
return Shape::HashForObject(key, object);
}
@@ -2750,9 +3233,11 @@
SetNumberOfDeletedElements(NumberOfDeletedElements() + n);
}
- // Returns a new HashTable object. Might return Failure.
- MUST_USE_RESULT static MaybeObject* Allocate(
+ // Returns a new HashTable object.
+ MUST_USE_RESULT static Handle<Derived> New(
+ Isolate* isolate,
int at_least_space_for,
+ MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY,
PretenureFlag pretenure = NOT_TENURED);
// Computes the required capacity for a table holding the given
@@ -2772,8 +3257,7 @@
void IteratePrefix(ObjectVisitor* visitor);
void IterateElements(ObjectVisitor* visitor);
- // Casting.
- static inline HashTable* cast(Object* obj);
+ DECLARE_CAST(HashTable)
// Compute the probe offset (quadratic probing).
INLINE(static uint32_t GetProbeOffset(uint32_t n)) {
@@ -2805,7 +3289,12 @@
inline int FindEntry(Key key);
int FindEntry(Isolate* isolate, Key key);
+ // Rehashes the table in-place.
+ void Rehash(Key key);
+
protected:
+ friend class ObjectHashTable;
+
// Find the entry at which to insert element with the given key that
// has the given hash value.
uint32_t FindInsertionEntry(uint32_t hash);
@@ -2830,34 +3319,47 @@
// To scale a computed hash code to fit within the hash table, we
// use bit-wise AND with a mask, so the capacity must be positive
// and non-zero.
- ASSERT(capacity > 0);
- ASSERT(capacity <= kMaxCapacity);
+ DCHECK(capacity > 0);
+ DCHECK(capacity <= kMaxCapacity);
set(kCapacityIndex, Smi::FromInt(capacity));
}
// Returns probe entry.
static uint32_t GetProbe(uint32_t hash, uint32_t number, uint32_t size) {
- ASSERT(IsPowerOf2(size));
+ DCHECK(base::bits::IsPowerOfTwo32(size));
return (hash + GetProbeOffset(number)) & (size - 1);
}
- static uint32_t FirstProbe(uint32_t hash, uint32_t size) {
+ inline static uint32_t FirstProbe(uint32_t hash, uint32_t size) {
return hash & (size - 1);
}
- static uint32_t NextProbe(uint32_t last, uint32_t number, uint32_t size) {
+ inline static uint32_t NextProbe(
+ uint32_t last, uint32_t number, uint32_t size) {
return (last + number) & (size - 1);
}
- // Rehashes this hash-table into the new table.
- MUST_USE_RESULT MaybeObject* Rehash(HashTable* new_table, Key key);
-
// Attempt to shrink hash table after removal of key.
- MUST_USE_RESULT MaybeObject* Shrink(Key key);
+ MUST_USE_RESULT static Handle<Derived> Shrink(Handle<Derived> table, Key key);
// Ensure enough space for n additional elements.
- MUST_USE_RESULT MaybeObject* EnsureCapacity(int n, Key key);
+ MUST_USE_RESULT static Handle<Derived> EnsureCapacity(
+ Handle<Derived> table,
+ int n,
+ Key key,
+ PretenureFlag pretenure = NOT_TENURED);
+
+ private:
+ // Returns _expected_ if one of entries given by the first _probe_ probes is
+ // equal to _expected_. Otherwise, returns the entry given by the probe
+ // number _probe_.
+ uint32_t EntryForProbe(Key key, Object* k, int probe, uint32_t expected);
+
+ void Swap(uint32_t entry1, uint32_t entry2, WriteBarrierMode mode);
+
+ // Rehashes this hash-table into the new table.
+ void Rehash(Handle<Derived> new_table, Key key);
};
@@ -2871,69 +3373,70 @@
// Returns the hash value for object.
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 Handle<Object> AsHandle(Isolate* isolate) = 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);
}
+
static inline uint32_t Hash(HashTableKey* key) {
return key->Hash();
}
+
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();
- }
+
+ static inline Handle<Object> AsHandle(Isolate* isolate, HashTableKey* key);
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<StringTable,
+ 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,
- int from,
- int length,
- Object** s);
- MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol(Vector<const uc16> str,
- Object** s);
- MUST_USE_RESULT MaybeObject* LookupString(String* key, Object** s);
+ // Find string in the string table. If it is not there yet, it is
+ // added. The return value is the string found.
+ static Handle<String> LookupString(Isolate* isolate, Handle<String> key);
+ static Handle<String> LookupKey(Isolate* isolate, HashTableKey* key);
- // 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
- // parameter.
- bool LookupSymbolIfExists(String* str, String** symbol);
- bool LookupTwoCharsSymbolIfExists(uint32_t c1, uint32_t c2, String** symbol);
+ // Tries to internalize given string and returns string handle on success
+ // or an empty handle otherwise.
+ MUST_USE_RESULT static MaybeHandle<String> InternalizeStringIfExists(
+ Isolate* isolate,
+ Handle<String> string);
- // Casting.
- static inline SymbolTable* cast(Object* obj);
+ // Looks up a string that is equal to the given string and returns
+ // string handle if it is found, or an empty handle otherwise.
+ MUST_USE_RESULT static MaybeHandle<String> LookupStringIfExists(
+ Isolate* isolate,
+ Handle<String> str);
+ MUST_USE_RESULT static MaybeHandle<String> LookupTwoCharsStringIfExists(
+ Isolate* isolate,
+ uint16_t c1,
+ uint16_t c2);
+
+ DECLARE_CAST(StringTable)
private:
- MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s);
+ template <bool seq_one_byte>
+ friend class JsonParser;
- DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StringTable);
};
@@ -2942,6 +3445,7 @@
static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
}
+
static inline uint32_t Hash(HashTableKey* key) {
return key->Hash();
}
@@ -2950,9 +3454,7 @@
return key->HashForObject(object);
}
- MUST_USE_RESULT static inline MaybeObject* AsObject(HashTableKey* key) {
- return key->AsObject();
- }
+ static inline Handle<Object> AsHandle(Isolate* isolate, HashTableKey* key);
static const int kPrefixSize = 0;
static const int kEntrySize = 2;
@@ -2961,57 +3463,64 @@
// 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*> {
+class MapCache: public HashTable<MapCache, 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);
+ static Handle<MapCache> Put(
+ Handle<MapCache> map_cache, Handle<FixedArray> key, Handle<Map> value);
+ DECLARE_CAST(MapCache)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(MapCache);
};
-template <typename Shape, typename Key>
-class Dictionary: public HashTable<Shape, Key> {
- public:
- static inline Dictionary<Shape, Key>* cast(Object* obj) {
- return reinterpret_cast<Dictionary<Shape, Key>*>(obj);
- }
+template <typename Derived, typename Shape, typename Key>
+class Dictionary: public HashTable<Derived, Shape, Key> {
+ protected:
+ typedef HashTable<Derived, Shape, Key> DerivedHashTable;
+ public:
// Returns the value at entry.
Object* ValueAt(int entry) {
- return this->get(HashTable<Shape, Key>::EntryToIndex(entry) + 1);
+ return this->get(DerivedHashTable::EntryToIndex(entry) + 1);
}
// Set the value for entry.
void ValueAtPut(int entry, Object* value) {
- this->set(HashTable<Shape, Key>::EntryToIndex(entry) + 1, value);
+ this->set(DerivedHashTable::EntryToIndex(entry) + 1, value);
}
// Returns the property details for the property at entry.
PropertyDetails DetailsAt(int entry) {
- ASSERT(entry >= 0); // Not found is -1, which is not caught by get().
+ DCHECK(entry >= 0); // Not found is -1, which is not caught by get().
return PropertyDetails(
- Smi::cast(this->get(HashTable<Shape, Key>::EntryToIndex(entry) + 2)));
+ Smi::cast(this->get(DerivedHashTable::EntryToIndex(entry) + 2)));
}
// Set the details for entry.
void DetailsAtPut(int entry, PropertyDetails value) {
- this->set(HashTable<Shape, Key>::EntryToIndex(entry) + 2, value.AsSmi());
+ this->set(DerivedHashTable::EntryToIndex(entry) + 2, value.AsSmi());
}
// Sorting support
void CopyValuesTo(FixedArray* elements);
// Delete a property from the dictionary.
- Object* DeleteProperty(int entry, JSObject::DeleteMode mode);
+ static Handle<Object> DeleteProperty(
+ Handle<Derived> dictionary,
+ int entry,
+ JSObject::DeleteMode mode);
// Attempt to shrink the dictionary after deletion of key.
- MUST_USE_RESULT MaybeObject* Shrink(Key key);
+ MUST_USE_RESULT static inline Handle<Derived> Shrink(
+ Handle<Derived> dictionary,
+ Key key) {
+ return DerivedHashTable::Shrink(dictionary, key);
+ }
// Returns the number of elements in the dictionary filtering out properties
// with the specified attributes.
@@ -3026,102 +3535,109 @@
PropertyAttributes filter,
SortMode sort_mode);
// Fill in details for properties into storage.
- void CopyKeysTo(FixedArray* storage, int index, SortMode sort_mode);
+ void CopyKeysTo(FixedArray* storage,
+ int index,
+ PropertyAttributes filter,
+ SortMode sort_mode);
// Accessors for next enumeration index.
void SetNextEnumerationIndex(int index) {
+ DCHECK(index != 0);
this->set(kNextEnumerationIndexIndex, Smi::FromInt(index));
}
int NextEnumerationIndex() {
- return Smi::cast(FixedArray::get(kNextEnumerationIndexIndex))->value();
+ return Smi::cast(this->get(kNextEnumerationIndexIndex))->value();
}
- // Returns a new array for dictionary usage. Might return Failure.
- MUST_USE_RESULT static MaybeObject* Allocate(int at_least_space_for);
+ // Creates a new dictionary.
+ MUST_USE_RESULT static Handle<Derived> New(
+ Isolate* isolate,
+ int at_least_space_for,
+ PretenureFlag pretenure = NOT_TENURED);
// Ensure enough space for n additional elements.
- MUST_USE_RESULT MaybeObject* EnsureCapacity(int n, Key key);
+ static Handle<Derived> EnsureCapacity(Handle<Derived> obj, int n, Key key);
#ifdef OBJECT_PRINT
- inline void Print() {
- Print(stdout);
- }
- void Print(FILE* out);
+ void Print(OStream& os); // NOLINT
#endif
// Returns the key (slow).
Object* SlowReverseLookup(Object* value);
// Sets the entry to (key, value) pair.
inline void SetEntry(int entry,
- Object* key,
- Object* value);
+ Handle<Object> key,
+ Handle<Object> value);
inline void SetEntry(int entry,
- Object* key,
- Object* value,
+ Handle<Object> key,
+ Handle<Object> value,
PropertyDetails details);
- MUST_USE_RESULT MaybeObject* Add(Key key,
- Object* value,
- PropertyDetails details);
+ MUST_USE_RESULT static Handle<Derived> Add(
+ Handle<Derived> dictionary,
+ Key key,
+ Handle<Object> value,
+ PropertyDetails details);
protected:
// Generic at put operation.
- MUST_USE_RESULT MaybeObject* AtPut(Key key, Object* value);
+ MUST_USE_RESULT static Handle<Derived> AtPut(
+ Handle<Derived> dictionary,
+ Key key,
+ Handle<Object> value);
// Add entry to dictionary.
- MUST_USE_RESULT MaybeObject* AddEntry(Key key,
- Object* value,
- PropertyDetails details,
- uint32_t hash);
+ static void AddEntry(
+ Handle<Derived> dictionary,
+ Key key,
+ Handle<Object> value,
+ PropertyDetails details,
+ uint32_t hash);
// Generate new enumeration indices to avoid enumeration index overflow.
- MUST_USE_RESULT MaybeObject* GenerateNewEnumerationIndices();
- static const int kMaxNumberKeyIndex =
- HashTable<Shape, Key>::kPrefixStartIndex;
+ static void GenerateNewEnumerationIndices(Handle<Derived> dictionary);
+ static const int kMaxNumberKeyIndex = DerivedHashTable::kPrefixStartIndex;
static const int kNextEnumerationIndexIndex = kMaxNumberKeyIndex + 1;
};
-class StringDictionaryShape : public BaseShape<String*> {
+class NameDictionaryShape : public BaseShape<Handle<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(Handle<Name> key, Object* other);
+ static inline uint32_t Hash(Handle<Name> key);
+ static inline uint32_t HashForObject(Handle<Name> key, Object* object);
+ static inline Handle<Object> AsHandle(Isolate* isolate, Handle<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<NameDictionary,
+ NameDictionaryShape,
+ Handle<Name> > {
+ typedef Dictionary<
+ NameDictionary, NameDictionaryShape, Handle<Name> > DerivedDictionary;
+
public:
- static inline StringDictionary* cast(Object* obj) {
- ASSERT(obj->IsDictionary());
- return reinterpret_cast<StringDictionary*>(obj);
- }
+ DECLARE_CAST(NameDictionary)
// Copies enumerable keys to preallocated fixed array.
- void CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array);
-
- // For transforming properties of a JSObject.
- MUST_USE_RESULT MaybeObject* TransformPropertiesToFastFor(
- JSObject* obj,
- int unused_property_fields);
+ void CopyEnumKeysTo(FixedArray* storage);
+ inline static void DoGenerateNewEnumerationIndices(
+ Handle<NameDictionary> dictionary);
// Find entry for key, otherwise return kNotFound. Optimized version of
// HashTable::FindEntry.
- int FindEntry(String* key);
-
- bool ContainsTransition(int entry);
+ int FindEntry(Handle<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);
+ static inline Handle<Object> AsHandle(Isolate* isolate, uint32_t key);
static const int kEntrySize = 3;
static const bool kIsEnumerable = false;
};
@@ -3149,31 +3665,31 @@
class SeededNumberDictionary
- : public Dictionary<SeededNumberDictionaryShape, uint32_t> {
+ : public Dictionary<SeededNumberDictionary,
+ SeededNumberDictionaryShape,
+ uint32_t> {
public:
- static SeededNumberDictionary* cast(Object* obj) {
- ASSERT(obj->IsDictionary());
- return reinterpret_cast<SeededNumberDictionary*>(obj);
- }
+ DECLARE_CAST(SeededNumberDictionary)
// Type specific at put (default NONE attributes is used when adding).
- MUST_USE_RESULT MaybeObject* AtNumberPut(uint32_t key, Object* value);
- MUST_USE_RESULT MaybeObject* AddNumberEntry(uint32_t key,
- Object* value,
- PropertyDetails details);
+ MUST_USE_RESULT static Handle<SeededNumberDictionary> AtNumberPut(
+ Handle<SeededNumberDictionary> dictionary,
+ uint32_t key,
+ Handle<Object> value);
+ MUST_USE_RESULT static Handle<SeededNumberDictionary> AddNumberEntry(
+ Handle<SeededNumberDictionary> dictionary,
+ uint32_t key,
+ Handle<Object> value,
+ PropertyDetails details);
// Set an existing entry or add a new one if needed.
// Return the updated dictionary.
MUST_USE_RESULT static Handle<SeededNumberDictionary> Set(
Handle<SeededNumberDictionary> dictionary,
- uint32_t index,
+ uint32_t key,
Handle<Object> value,
PropertyDetails details);
- MUST_USE_RESULT MaybeObject* Set(uint32_t key,
- Object* value,
- PropertyDetails details);
-
void UpdateMaxNumberKey(uint32_t key);
// If slow elements are required we will never go back to fast-case
@@ -3197,76 +3713,70 @@
class UnseededNumberDictionary
- : public Dictionary<UnseededNumberDictionaryShape, uint32_t> {
+ : public Dictionary<UnseededNumberDictionary,
+ UnseededNumberDictionaryShape,
+ uint32_t> {
public:
- static UnseededNumberDictionary* cast(Object* obj) {
- ASSERT(obj->IsDictionary());
- return reinterpret_cast<UnseededNumberDictionary*>(obj);
- }
+ DECLARE_CAST(UnseededNumberDictionary)
// Type specific at put (default NONE attributes is used when adding).
- MUST_USE_RESULT MaybeObject* AtNumberPut(uint32_t key, Object* value);
- MUST_USE_RESULT MaybeObject* AddNumberEntry(uint32_t key, Object* value);
+ MUST_USE_RESULT static Handle<UnseededNumberDictionary> AtNumberPut(
+ Handle<UnseededNumberDictionary> dictionary,
+ uint32_t key,
+ Handle<Object> value);
+ MUST_USE_RESULT static Handle<UnseededNumberDictionary> AddNumberEntry(
+ Handle<UnseededNumberDictionary> dictionary,
+ uint32_t key,
+ Handle<Object> value);
// Set an existing entry or add a new one if needed.
// Return the updated dictionary.
MUST_USE_RESULT static Handle<UnseededNumberDictionary> Set(
Handle<UnseededNumberDictionary> dictionary,
- uint32_t index,
+ uint32_t key,
Handle<Object> value);
-
- MUST_USE_RESULT MaybeObject* Set(uint32_t key, Object* value);
};
-template <int entrysize>
-class ObjectHashTableShape : public BaseShape<Object*> {
+class ObjectHashTableShape : public BaseShape<Handle<Object> > {
public:
- 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);
+ static inline bool IsMatch(Handle<Object> key, Object* other);
+ static inline uint32_t Hash(Handle<Object> key);
+ static inline uint32_t HashForObject(Handle<Object> key, Object* object);
+ static inline Handle<Object> AsHandle(Isolate* isolate, Handle<Object> key);
static const int kPrefixSize = 0;
- static const int kEntrySize = entrysize;
-};
-
-
-// ObjectHashSet holds keys that are arbitrary objects by using the identity
-// hash of the key for hashing purposes.
-class ObjectHashSet: public HashTable<ObjectHashTableShape<1>, Object*> {
- public:
- static inline ObjectHashSet* cast(Object* obj) {
- ASSERT(obj->IsHashTable());
- return reinterpret_cast<ObjectHashSet*>(obj);
- }
-
- // Looks up whether the given key is part of this hash set.
- bool Contains(Object* key);
-
- // Adds the given key to this hash set.
- MUST_USE_RESULT MaybeObject* Add(Object* key);
-
- // Removes the given key from this hash set.
- MUST_USE_RESULT MaybeObject* Remove(Object* key);
+ static const int kEntrySize = 2;
};
// ObjectHashTable maps keys that are arbitrary objects to object values by
// using the identity hash of the key for hashing purposes.
-class ObjectHashTable: public HashTable<ObjectHashTableShape<2>, Object*> {
+class ObjectHashTable: public HashTable<ObjectHashTable,
+ ObjectHashTableShape,
+ Handle<Object> > {
+ typedef HashTable<
+ ObjectHashTable, ObjectHashTableShape, Handle<Object> > DerivedHashTable;
public:
- static inline ObjectHashTable* cast(Object* obj) {
- ASSERT(obj->IsHashTable());
- return reinterpret_cast<ObjectHashTable*>(obj);
- }
+ DECLARE_CAST(ObjectHashTable)
- // Looks up the value associated with the given key. The undefined value is
+ // Attempt to shrink hash table after removal of key.
+ MUST_USE_RESULT static inline Handle<ObjectHashTable> Shrink(
+ Handle<ObjectHashTable> table,
+ Handle<Object> key);
+
+ // Looks up the value associated with the given key. The hole value is
// returned in case the key is not present.
- Object* Lookup(Object* key);
+ Object* Lookup(Handle<Object> key);
- // Adds (or overwrites) the value associated with the given key. Mapping a
- // key to the undefined value causes removal of the whole entry.
- MUST_USE_RESULT MaybeObject* Put(Object* key, Object* value);
+ // Adds (or overwrites) the value associated with the given key.
+ static Handle<ObjectHashTable> Put(Handle<ObjectHashTable> table,
+ Handle<Object> key,
+ Handle<Object> value);
+
+ // Returns an ObjectHashTable (possibly |table|) where |key| has been removed.
+ static Handle<ObjectHashTable> Remove(Handle<ObjectHashTable> table,
+ Handle<Object> key,
+ bool* was_present);
private:
friend class MarkCompactCollector;
@@ -3281,6 +3791,269 @@
};
+// OrderedHashTable is a HashTable with Object keys that preserves
+// insertion order. There are Map and Set interfaces (OrderedHashMap
+// and OrderedHashTable, below). It is meant to be used by JSMap/JSSet.
+//
+// Only Object* keys are supported, with Object::SameValueZero() used as the
+// equality operator and Object::GetHash() for the hash function.
+//
+// Based on the "Deterministic Hash Table" as described by Jason Orendorff at
+// https://wiki.mozilla.org/User:Jorend/Deterministic_hash_tables
+// Originally attributed to Tyler Close.
+//
+// Memory layout:
+// [0]: bucket count
+// [1]: element count
+// [2]: deleted element count
+// [3..(3 + NumberOfBuckets() - 1)]: "hash table", where each item is an
+// offset into the data table (see below) where the
+// first item in this bucket is stored.
+// [3 + NumberOfBuckets()..length]: "data table", an array of length
+// Capacity() * kEntrySize, where the first entrysize
+// items are handled by the derived class and the
+// item at kChainOffset is another entry into the
+// data table indicating the next entry in this hash
+// bucket.
+//
+// When we transition the table to a new version we obsolete it and reuse parts
+// of the memory to store information how to transition an iterator to the new
+// table:
+//
+// Memory layout for obsolete table:
+// [0]: bucket count
+// [1]: Next newer table
+// [2]: Number of removed holes or -1 when the table was cleared.
+// [3..(3 + NumberOfRemovedHoles() - 1)]: The indexes of the removed holes.
+// [3 + NumberOfRemovedHoles()..length]: Not used
+//
+template<class Derived, class Iterator, int entrysize>
+class OrderedHashTable: public FixedArray {
+ public:
+ // Returns an OrderedHashTable with a capacity of at least |capacity|.
+ static Handle<Derived> Allocate(
+ Isolate* isolate, int capacity, PretenureFlag pretenure = NOT_TENURED);
+
+ // Returns an OrderedHashTable (possibly |table|) with enough space
+ // to add at least one new element.
+ static Handle<Derived> EnsureGrowable(Handle<Derived> table);
+
+ // Returns an OrderedHashTable (possibly |table|) that's shrunken
+ // if possible.
+ static Handle<Derived> Shrink(Handle<Derived> table);
+
+ // Returns a new empty OrderedHashTable and records the clearing so that
+ // exisiting iterators can be updated.
+ static Handle<Derived> Clear(Handle<Derived> table);
+
+ // Returns an OrderedHashTable (possibly |table|) where |key| has been
+ // removed.
+ static Handle<Derived> Remove(Handle<Derived> table, Handle<Object> key,
+ bool* was_present);
+
+ // Returns kNotFound if the key isn't present.
+ int FindEntry(Handle<Object> key, int hash);
+
+ // Like the above, but doesn't require the caller to provide a hash.
+ int FindEntry(Handle<Object> key);
+
+ int NumberOfElements() {
+ return Smi::cast(get(kNumberOfElementsIndex))->value();
+ }
+
+ int NumberOfDeletedElements() {
+ return Smi::cast(get(kNumberOfDeletedElementsIndex))->value();
+ }
+
+ int UsedCapacity() { return NumberOfElements() + NumberOfDeletedElements(); }
+
+ int NumberOfBuckets() {
+ return Smi::cast(get(kNumberOfBucketsIndex))->value();
+ }
+
+ // Returns the index into the data table where the new entry
+ // should be placed. The table is assumed to have enough space
+ // for a new entry.
+ int AddEntry(int hash);
+
+ // Removes the entry, and puts the_hole in entrysize pointers
+ // (leaving the hash table chain intact).
+ void RemoveEntry(int entry);
+
+ // Returns an index into |this| for the given entry.
+ int EntryToIndex(int entry) {
+ return kHashTableStartIndex + NumberOfBuckets() + (entry * kEntrySize);
+ }
+
+ Object* KeyAt(int entry) { return get(EntryToIndex(entry)); }
+
+ bool IsObsolete() {
+ return !get(kNextTableIndex)->IsSmi();
+ }
+
+ // The next newer table. This is only valid if the table is obsolete.
+ Derived* NextTable() {
+ return Derived::cast(get(kNextTableIndex));
+ }
+
+ // When the table is obsolete we store the indexes of the removed holes.
+ int RemovedIndexAt(int index) {
+ return Smi::cast(get(kRemovedHolesIndex + index))->value();
+ }
+
+ static const int kNotFound = -1;
+ static const int kMinCapacity = 4;
+
+ private:
+ static Handle<Derived> Rehash(Handle<Derived> table, int new_capacity);
+
+ void SetNumberOfBuckets(int num) {
+ set(kNumberOfBucketsIndex, Smi::FromInt(num));
+ }
+
+ void SetNumberOfElements(int num) {
+ set(kNumberOfElementsIndex, Smi::FromInt(num));
+ }
+
+ void SetNumberOfDeletedElements(int num) {
+ set(kNumberOfDeletedElementsIndex, Smi::FromInt(num));
+ }
+
+ int Capacity() {
+ return NumberOfBuckets() * kLoadFactor;
+ }
+
+ // Returns the next entry for the given entry.
+ int ChainAt(int entry) {
+ return Smi::cast(get(EntryToIndex(entry) + kChainOffset))->value();
+ }
+
+ int HashToBucket(int hash) {
+ return hash & (NumberOfBuckets() - 1);
+ }
+
+ int HashToEntry(int hash) {
+ int bucket = HashToBucket(hash);
+ return Smi::cast(get(kHashTableStartIndex + bucket))->value();
+ }
+
+ void SetNextTable(Derived* next_table) {
+ set(kNextTableIndex, next_table);
+ }
+
+ void SetRemovedIndexAt(int index, int removed_index) {
+ return set(kRemovedHolesIndex + index, Smi::FromInt(removed_index));
+ }
+
+ static const int kNumberOfBucketsIndex = 0;
+ static const int kNumberOfElementsIndex = kNumberOfBucketsIndex + 1;
+ static const int kNumberOfDeletedElementsIndex = kNumberOfElementsIndex + 1;
+ static const int kHashTableStartIndex = kNumberOfDeletedElementsIndex + 1;
+
+ static const int kNextTableIndex = kNumberOfElementsIndex;
+ static const int kRemovedHolesIndex = kHashTableStartIndex;
+
+ static const int kEntrySize = entrysize + 1;
+ static const int kChainOffset = entrysize;
+
+ static const int kLoadFactor = 2;
+ static const int kMaxCapacity =
+ (FixedArray::kMaxLength - kHashTableStartIndex)
+ / (1 + (kEntrySize * kLoadFactor));
+};
+
+
+class JSSetIterator;
+
+
+class OrderedHashSet: public OrderedHashTable<
+ OrderedHashSet, JSSetIterator, 1> {
+ public:
+ DECLARE_CAST(OrderedHashSet)
+
+ bool Contains(Handle<Object> key);
+ static Handle<OrderedHashSet> Add(
+ Handle<OrderedHashSet> table, Handle<Object> key);
+};
+
+
+class JSMapIterator;
+
+
+class OrderedHashMap:public OrderedHashTable<
+ OrderedHashMap, JSMapIterator, 2> {
+ public:
+ DECLARE_CAST(OrderedHashMap)
+
+ Object* Lookup(Handle<Object> key);
+ static Handle<OrderedHashMap> Put(
+ Handle<OrderedHashMap> table,
+ Handle<Object> key,
+ Handle<Object> value);
+
+ Object* ValueAt(int entry) {
+ return get(EntryToIndex(entry) + kValueOffset);
+ }
+
+ private:
+ static const int kValueOffset = 1;
+};
+
+
+template <int entrysize>
+class WeakHashTableShape : public BaseShape<Handle<Object> > {
+ public:
+ static inline bool IsMatch(Handle<Object> key, Object* other);
+ static inline uint32_t Hash(Handle<Object> key);
+ static inline uint32_t HashForObject(Handle<Object> key, Object* object);
+ static inline Handle<Object> AsHandle(Isolate* isolate, Handle<Object> key);
+ static const int kPrefixSize = 0;
+ static const int kEntrySize = entrysize;
+};
+
+
+// WeakHashTable maps keys that are arbitrary objects to object values.
+// It is used for the global weak hash table that maps objects
+// embedded in optimized code to dependent code lists.
+class WeakHashTable: public HashTable<WeakHashTable,
+ WeakHashTableShape<2>,
+ Handle<Object> > {
+ typedef HashTable<
+ WeakHashTable, WeakHashTableShape<2>, Handle<Object> > DerivedHashTable;
+ public:
+ DECLARE_CAST(WeakHashTable)
+
+ // Looks up the value associated with the given key. The hole value is
+ // returned in case the key is not present.
+ Object* Lookup(Handle<Object> key);
+
+ // Adds (or overwrites) the value associated with the given key. Mapping a
+ // key to the hole value causes removal of the whole entry.
+ MUST_USE_RESULT static Handle<WeakHashTable> Put(Handle<WeakHashTable> table,
+ Handle<Object> key,
+ Handle<Object> value);
+
+ // This function is called when heap verification is turned on.
+ void Zap(Object* value) {
+ int capacity = Capacity();
+ for (int i = 0; i < capacity; i++) {
+ set(EntryToIndex(i), value);
+ set(EntryToValueIndex(i), value);
+ }
+ }
+
+ private:
+ friend class MarkCompactCollector;
+
+ void AddEntry(int entry, Handle<Object> key, Handle<Object> value);
+
+ // Returns the index to the value of an entry.
+ static inline int EntryToValueIndex(int entry) {
+ return EntryToIndex(entry) + 1;
+ }
+};
+
+
// JSFunctionResultCache caches results of some JSFunction invocation.
// It is a fixed array with fixed structure:
// [0]: factory function
@@ -3310,12 +4083,9 @@
inline int finger_index();
inline void set_finger_index(int finger_index);
- // Casting
- static inline JSFunctionResultCache* cast(Object* obj);
+ DECLARE_CAST(JSFunctionResultCache)
-#ifdef DEBUG
- void JSFunctionResultCacheVerify();
-#endif
+ DECLARE_VERIFIER(JSFunctionResultCache)
};
@@ -3328,21 +4098,19 @@
// routines.
class ScopeInfo : public FixedArray {
public:
- static inline ScopeInfo* cast(Object* object);
+ DECLARE_CAST(ScopeInfo)
// Return the type of this scope.
- ScopeType Type();
+ ScopeType scope_type();
// Does this scope call eval?
bool CallsEval();
- // Return the language mode of this scope.
- LanguageMode language_mode();
+ // Return the strict mode of this scope.
+ StrictMode strict_mode();
- // Does this scope make a non-strict eval call?
- bool CallsNonStrictEval() {
- return CallsEval() && (language_mode() == CLASSIC_MODE);
- }
+ // Does this scope make a sloppy eval call?
+ bool CallsSloppyEval() { return CallsEval() && strict_mode() == SLOPPY; }
// Return the total number of locals allocated on the stack and in the
// context. This includes the parameters that are allocated in the context.
@@ -3372,6 +4140,12 @@
// Return if contexts are allocated for this scope.
bool HasContext();
+ // Return if this is a function scope with "use asm".
+ bool IsAsmModule() { return AsmModuleField::decode(Flags()); }
+
+ // Return if this is a nested function within an asm module scope.
+ bool IsAsmFunction() { return AsmFunctionField::decode(Flags()); }
+
// Return the function_name if present.
String* FunctionName();
@@ -3393,36 +4167,50 @@
// Return the initialization flag of the given context local.
InitializationFlag ContextLocalInitFlag(int var);
+ // Return the initialization flag of the given context local.
+ MaybeAssignedFlag ContextLocalMaybeAssignedFlag(int var);
+
+ // Return true if this local was introduced by the compiler, and should not be
+ // exposed to the user in a debugger.
+ bool LocalIsSynthetic(int var);
+
// 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,
- VariableMode* mode,
- InitializationFlag* init_flag);
+ static int ContextSlotIndex(Handle<ScopeInfo> scope_info, Handle<String> name,
+ VariableMode* mode, InitializationFlag* init_flag,
+ MaybeAssignedFlag* maybe_assigned_flag);
// 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 (named
+ // 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);
- static Handle<ScopeInfo> Create(Scope* scope);
+
+ // Copies all the context locals into an object used to materialize a scope.
+ static bool CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
+ 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();
@@ -3462,7 +4250,7 @@
FOR_EACH_NUMERIC_FIELD(DECL_INDEX)
#undef DECL_INDEX
#undef FOR_EACH_NUMERIC_FIELD
- kVariablePartIndex
+ kVariablePartIndex
};
// The layout of the variable part of a ScopeInfo is as follows:
@@ -3507,16 +4295,20 @@
};
// Properties of scopes.
- class TypeField: public BitField<ScopeType, 0, 3> {};
+ class ScopeTypeField: public BitField<ScopeType, 0, 3> {};
class CallsEvalField: public BitField<bool, 3, 1> {};
- class LanguageModeField: public BitField<LanguageMode, 4, 2> {};
- class FunctionVariableField: public BitField<FunctionVariableInfo, 6, 2> {};
- class FunctionVariableMode: public BitField<VariableMode, 8, 3> {};
+ class StrictModeField: public BitField<StrictMode, 4, 1> {};
+ class FunctionVariableField: public BitField<FunctionVariableInfo, 5, 2> {};
+ class FunctionVariableMode: public BitField<VariableMode, 7, 3> {};
+ class AsmModuleField : public BitField<bool, 10, 1> {};
+ class AsmFunctionField : public BitField<bool, 11, 1> {};
// BitFields representing the encoded information for context locals in the
// ContextLocalInfoEntries part.
class ContextLocalMode: public BitField<VariableMode, 0, 3> {};
class ContextLocalInitFlag: public BitField<InitializationFlag, 3, 1> {};
+ class ContextLocalMaybeAssignedFlag
+ : public BitField<MaybeAssignedFlag, 4, 1> {};
};
@@ -3525,19 +4317,27 @@
// needs very limited number of distinct normalized maps.
class NormalizedMapCache: public FixedArray {
public:
- static const int kEntries = 64;
+ static Handle<NormalizedMapCache> New(Isolate* isolate);
- MUST_USE_RESULT MaybeObject* Get(JSObject* object,
- PropertyNormalizationMode mode);
+ MUST_USE_RESULT MaybeHandle<Map> Get(Handle<Map> fast_map,
+ PropertyNormalizationMode mode);
+ void Set(Handle<Map> fast_map, Handle<Map> normalized_map);
void Clear();
- // Casting
- static inline NormalizedMapCache* cast(Object* obj);
+ DECLARE_CAST(NormalizedMapCache)
-#ifdef DEBUG
- void NormalizedMapCacheVerify();
-#endif
+ static inline bool IsNormalizedMapCache(const Object* obj);
+
+ DECLARE_VERIFIER(NormalizedMapCache)
+ private:
+ static const int kEntries = 64;
+
+ static inline int GetIndex(Handle<Map> map);
+
+ // The following declarations hide base class methods.
+ Object* get(int index);
+ void set(int index, Object* value);
};
@@ -3562,8 +4362,8 @@
// array, this function returns the number of elements a byte array should
// have.
static int LengthFor(int size_in_bytes) {
- ASSERT(IsAligned(size_in_bytes, kPointerSize));
- ASSERT(size_in_bytes >= kHeaderSize);
+ DCHECK(IsAligned(size_in_bytes, kPointerSize));
+ DCHECK(size_in_bytes >= kHeaderSize);
return size_in_bytes - kHeaderSize;
}
@@ -3573,22 +4373,14 @@
// Returns a pointer to the ByteArray object for a given data start address.
static inline ByteArray* FromDataStartAddress(Address address);
- // Casting.
- static inline ByteArray* cast(Object* obj);
+ DECLARE_CAST(ByteArray)
// Dispatched behavior.
inline int ByteArraySize() {
return SizeFor(this->length());
}
-#ifdef OBJECT_PRINT
- inline void ByteArrayPrint() {
- ByteArrayPrint(stdout);
- }
- void ByteArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ByteArrayVerify();
-#endif
+ DECLARE_PRINTER(ByteArray)
+ DECLARE_VERIFIER(ByteArray)
// Layout description.
static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
@@ -3608,23 +4400,19 @@
class FreeSpace: public HeapObject {
public:
// [size]: size of the free space including the header.
- inline int size();
+ inline int size() const;
inline void set_size(int value);
+ inline int nobarrier_size() const;
+ inline void nobarrier_set_size(int value);
+
inline int Size() { return size(); }
- // Casting.
- static inline FreeSpace* cast(Object* obj);
+ DECLARE_CAST(FreeSpace)
-#ifdef OBJECT_PRINT
- inline void FreeSpacePrint() {
- FreeSpacePrint(stdout);
- }
- void FreeSpacePrint(FILE* out);
-#endif
-#ifdef DEBUG
- void FreeSpaceVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(FreeSpace)
+ DECLARE_VERIFIER(FreeSpace)
// Layout description.
// Size is smi tagged when it is stored.
@@ -3638,6 +4426,20 @@
};
+// V has parameters (Type, type, TYPE, C type, element_size)
+#define TYPED_ARRAYS(V) \
+ V(Uint8, uint8, UINT8, uint8_t, 1) \
+ V(Int8, int8, INT8, int8_t, 1) \
+ V(Uint16, uint16, UINT16, uint16_t, 2) \
+ V(Int16, int16, INT16, int16_t, 2) \
+ V(Uint32, uint32, UINT32, uint32_t, 4) \
+ V(Int32, int32, INT32, int32_t, 4) \
+ V(Float32, float32, FLOAT32, float, 4) \
+ V(Float64, float64, FLOAT64, double, 8) \
+ V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t, 1)
+
+
+
// An ExternalArray represents a fixed-size array of primitive values
// which live outside the JavaScript heap. Its subclasses are used to
// implement the CanvasArray types being defined in the WebGL
@@ -3657,8 +4459,7 @@
// external array.
DECL_ACCESSORS(external_pointer, void) // Pointer to the data store.
- // Casting.
- static inline ExternalArray* cast(Object* obj);
+ DECLARE_CAST(ExternalArray)
// Maximal acceptable length for an external array.
static const int kMaxLength = 0x3fffffff;
@@ -3674,7 +4475,7 @@
};
-// A ExternalPixelArray represents a fixed-size byte array with special
+// A ExternalUint8ClampedArray represents a fixed-size byte array with special
// semantics used for implementing the CanvasPixelArray object. Please see the
// specification at:
@@ -3682,269 +4483,304 @@
// multipage/the-canvas-element.html#canvaspixelarray
// In particular, write access clamps the value written to 0 or 255 if the
// value written is outside this range.
-class ExternalPixelArray: public ExternalArray {
+class ExternalUint8ClampedArray: public ExternalArray {
public:
- inline uint8_t* external_pixel_pointer();
+ inline uint8_t* external_uint8_clamped_pointer();
// Setter and getter.
inline uint8_t get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalUint8ClampedArray> array,
+ int index);
inline void set(int index, uint8_t value);
- // This accessor applies the correct conversion from Smi, HeapNumber and
- // undefined and clamps the converted value between 0 and 255.
- Object* SetValue(uint32_t index, Object* value);
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined and clamps the converted value between 0 and 255.
+ static Handle<Object> SetValue(Handle<ExternalUint8ClampedArray> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalPixelArray* cast(Object* obj);
+ DECLARE_CAST(ExternalUint8ClampedArray)
-#ifdef OBJECT_PRINT
- inline void ExternalPixelArrayPrint() {
- ExternalPixelArrayPrint(stdout);
- }
- void ExternalPixelArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ExternalPixelArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalUint8ClampedArray)
+ DECLARE_VERIFIER(ExternalUint8ClampedArray)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalPixelArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint8ClampedArray);
};
-class ExternalByteArray: public ExternalArray {
+class ExternalInt8Array: public ExternalArray {
public:
// Setter and getter.
inline int8_t get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalInt8Array> array, int index);
inline void set(int index, int8_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
+ static Handle<Object> SetValue(Handle<ExternalInt8Array> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalByteArray* cast(Object* obj);
+ DECLARE_CAST(ExternalInt8Array)
-#ifdef OBJECT_PRINT
- inline void ExternalByteArrayPrint() {
- ExternalByteArrayPrint(stdout);
- }
- void ExternalByteArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ExternalByteArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalInt8Array)
+ DECLARE_VERIFIER(ExternalInt8Array)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalByteArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt8Array);
};
-class ExternalUnsignedByteArray: public ExternalArray {
+class ExternalUint8Array: public ExternalArray {
public:
// Setter and getter.
inline uint8_t get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalUint8Array> array, int index);
inline void set(int index, uint8_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
+ static Handle<Object> SetValue(Handle<ExternalUint8Array> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalUnsignedByteArray* cast(Object* obj);
+ DECLARE_CAST(ExternalUint8Array)
-#ifdef OBJECT_PRINT
- inline void ExternalUnsignedByteArrayPrint() {
- ExternalUnsignedByteArrayPrint(stdout);
- }
- void ExternalUnsignedByteArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ExternalUnsignedByteArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalUint8Array)
+ DECLARE_VERIFIER(ExternalUint8Array)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedByteArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint8Array);
};
-class ExternalShortArray: public ExternalArray {
+class ExternalInt16Array: public ExternalArray {
public:
// Setter and getter.
inline int16_t get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalInt16Array> array, int index);
inline void set(int index, int16_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
+ static Handle<Object> SetValue(Handle<ExternalInt16Array> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalShortArray* cast(Object* obj);
+ DECLARE_CAST(ExternalInt16Array)
-#ifdef OBJECT_PRINT
- inline void ExternalShortArrayPrint() {
- ExternalShortArrayPrint(stdout);
- }
- void ExternalShortArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ExternalShortArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalInt16Array)
+ DECLARE_VERIFIER(ExternalInt16Array)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalShortArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt16Array);
};
-class ExternalUnsignedShortArray: public ExternalArray {
+class ExternalUint16Array: public ExternalArray {
public:
// Setter and getter.
inline uint16_t get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalUint16Array> array,
+ int index);
inline void set(int index, uint16_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
+ static Handle<Object> SetValue(Handle<ExternalUint16Array> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalUnsignedShortArray* cast(Object* obj);
+ DECLARE_CAST(ExternalUint16Array)
-#ifdef OBJECT_PRINT
- inline void ExternalUnsignedShortArrayPrint() {
- ExternalUnsignedShortArrayPrint(stdout);
- }
- void ExternalUnsignedShortArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ExternalUnsignedShortArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalUint16Array)
+ DECLARE_VERIFIER(ExternalUint16Array)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedShortArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint16Array);
};
-class ExternalIntArray: public ExternalArray {
+class ExternalInt32Array: public ExternalArray {
public:
// Setter and getter.
inline int32_t get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalInt32Array> array, int index);
inline void set(int index, int32_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
+ static Handle<Object> SetValue(Handle<ExternalInt32Array> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalIntArray* cast(Object* obj);
+ DECLARE_CAST(ExternalInt32Array)
-#ifdef OBJECT_PRINT
- inline void ExternalIntArrayPrint() {
- ExternalIntArrayPrint(stdout);
- }
- void ExternalIntArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ExternalIntArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalInt32Array)
+ DECLARE_VERIFIER(ExternalInt32Array)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalIntArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt32Array);
};
-class ExternalUnsignedIntArray: public ExternalArray {
+class ExternalUint32Array: public ExternalArray {
public:
// Setter and getter.
inline uint32_t get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalUint32Array> array,
+ int index);
inline void set(int index, uint32_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
+ static Handle<Object> SetValue(Handle<ExternalUint32Array> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalUnsignedIntArray* cast(Object* obj);
+ DECLARE_CAST(ExternalUint32Array)
-#ifdef OBJECT_PRINT
- inline void ExternalUnsignedIntArrayPrint() {
- ExternalUnsignedIntArrayPrint(stdout);
- }
- void ExternalUnsignedIntArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ExternalUnsignedIntArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalUint32Array)
+ DECLARE_VERIFIER(ExternalUint32Array)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedIntArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint32Array);
};
-class ExternalFloatArray: public ExternalArray {
+class ExternalFloat32Array: public ExternalArray {
public:
// Setter and getter.
inline float get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalFloat32Array> array,
+ int index);
inline void set(int index, float value);
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
+ static Handle<Object> SetValue(Handle<ExternalFloat32Array> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalFloatArray* cast(Object* obj);
+ DECLARE_CAST(ExternalFloat32Array)
-#ifdef OBJECT_PRINT
- inline void ExternalFloatArrayPrint() {
- ExternalFloatArrayPrint(stdout);
- }
- void ExternalFloatArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ExternalFloatArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalFloat32Array)
+ DECLARE_VERIFIER(ExternalFloat32Array)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloatArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloat32Array);
};
-class ExternalDoubleArray: public ExternalArray {
+class ExternalFloat64Array: public ExternalArray {
public:
// Setter and getter.
inline double get_scalar(int index);
- MUST_USE_RESULT inline MaybeObject* get(int index);
+ static inline Handle<Object> get(Handle<ExternalFloat64Array> array,
+ int index);
inline void set(int index, double value);
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
+ static Handle<Object> SetValue(Handle<ExternalFloat64Array> array,
+ uint32_t index,
+ Handle<Object> value);
- // Casting.
- static inline ExternalDoubleArray* cast(Object* obj);
+ DECLARE_CAST(ExternalFloat64Array)
-#ifdef OBJECT_PRINT
- inline void ExternalDoubleArrayPrint() {
- ExternalDoubleArrayPrint(stdout);
- }
- void ExternalDoubleArrayPrint(FILE* out);
-#endif // OBJECT_PRINT
-#ifdef DEBUG
- void ExternalDoubleArrayVerify();
-#endif // DEBUG
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalFloat64Array)
+ DECLARE_VERIFIER(ExternalFloat64Array)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalDoubleArray);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloat64Array);
};
+class FixedTypedArrayBase: public FixedArrayBase {
+ public:
+ DECLARE_CAST(FixedTypedArrayBase)
+
+ static const int kDataOffset = kHeaderSize;
+
+ inline int size();
+
+ inline int TypedArraySize(InstanceType type);
+
+ // Use with care: returns raw pointer into heap.
+ inline void* DataPtr();
+
+ inline int DataSize();
+
+ private:
+ inline int DataSize(InstanceType type);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FixedTypedArrayBase);
+};
+
+
+template <class Traits>
+class FixedTypedArray: public FixedTypedArrayBase {
+ public:
+ typedef typename Traits::ElementType ElementType;
+ static const InstanceType kInstanceType = Traits::kInstanceType;
+
+ DECLARE_CAST(FixedTypedArray<Traits>)
+
+ static inline int ElementOffset(int index) {
+ return kDataOffset + index * sizeof(ElementType);
+ }
+
+ static inline int SizeFor(int length) {
+ return ElementOffset(length);
+ }
+
+ inline ElementType get_scalar(int index);
+ static inline Handle<Object> get(Handle<FixedTypedArray> array, int index);
+ inline void set(int index, ElementType value);
+
+ static inline ElementType from_int(int value);
+ static inline ElementType from_double(double value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ static Handle<Object> SetValue(Handle<FixedTypedArray<Traits> > array,
+ uint32_t index,
+ Handle<Object> value);
+
+ DECLARE_PRINTER(FixedTypedArray)
+ DECLARE_VERIFIER(FixedTypedArray)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FixedTypedArray);
+};
+
+#define FIXED_TYPED_ARRAY_TRAITS(Type, type, TYPE, elementType, size) \
+ class Type##ArrayTraits { \
+ public: /* NOLINT */ \
+ typedef elementType ElementType; \
+ static const InstanceType kInstanceType = FIXED_##TYPE##_ARRAY_TYPE; \
+ static const char* Designator() { return #type " array"; } \
+ static inline Handle<Object> ToHandle(Isolate* isolate, \
+ elementType scalar); \
+ static inline elementType defaultValue(); \
+ }; \
+ \
+ typedef FixedTypedArray<Type##ArrayTraits> Fixed##Type##Array;
+
+TYPED_ARRAYS(FIXED_TYPED_ARRAY_TRAITS)
+
+#undef FIXED_TYPED_ARRAY_TRAITS
+
// DeoptimizationInputData is a fixed array used to hold the deoptimization
// data for code generated by the Hydrogen/Lithium compiler. It also
// contains information about functions that were inlined. If N different
@@ -3960,10 +4796,12 @@
static const int kLiteralArrayIndex = 2;
static const int kOsrAstIdIndex = 3;
static const int kOsrPcOffsetIndex = 4;
- static const int kFirstDeoptEntryIndex = 5;
+ static const int kOptimizationIdIndex = 5;
+ static const int kSharedFunctionInfoIndex = 6;
+ static const int kFirstDeoptEntryIndex = 7;
// Offsets of deopt entry elements relative to the start of the entry.
- static const int kAstIdOffset = 0;
+ static const int kAstIdRawOffset = 0;
static const int kTranslationIndexOffset = 1;
static const int kArgumentsStackHeightOffset = 2;
static const int kPcOffset = 3;
@@ -3983,38 +4821,48 @@
DEFINE_ELEMENT_ACCESSORS(LiteralArray, FixedArray)
DEFINE_ELEMENT_ACCESSORS(OsrAstId, Smi)
DEFINE_ELEMENT_ACCESSORS(OsrPcOffset, Smi)
+ DEFINE_ELEMENT_ACCESSORS(OptimizationId, Smi)
+ DEFINE_ELEMENT_ACCESSORS(SharedFunctionInfo, Object)
#undef DEFINE_ELEMENT_ACCESSORS
// Accessors for elements of the ith deoptimization entry.
-#define DEFINE_ENTRY_ACCESSORS(name, type) \
- type* name(int i) { \
- return type::cast(get(IndexForEntry(i) + k##name##Offset)); \
- } \
- void Set##name(int i, type* value) { \
- set(IndexForEntry(i) + k##name##Offset, value); \
+#define DEFINE_ENTRY_ACCESSORS(name, type) \
+ type* name(int i) { \
+ return type::cast(get(IndexForEntry(i) + k##name##Offset)); \
+ } \
+ void Set##name(int i, type* value) { \
+ set(IndexForEntry(i) + k##name##Offset, value); \
}
- DEFINE_ENTRY_ACCESSORS(AstId, Smi)
+ DEFINE_ENTRY_ACCESSORS(AstIdRaw, Smi)
DEFINE_ENTRY_ACCESSORS(TranslationIndex, Smi)
DEFINE_ENTRY_ACCESSORS(ArgumentsStackHeight, Smi)
DEFINE_ENTRY_ACCESSORS(Pc, Smi)
-#undef DEFINE_ENTRY_ACCESSORS
+#undef DEFINE_DEOPT_ENTRY_ACCESSORS
+
+ BailoutId AstId(int i) {
+ return BailoutId(AstIdRaw(i)->value());
+ }
+
+ void SetAstId(int i, BailoutId value) {
+ SetAstIdRaw(i, Smi::FromInt(value.ToInt()));
+ }
int DeoptCount() {
return (length() - kFirstDeoptEntryIndex) / kDeoptEntrySize;
}
// Allocates a DeoptimizationInputData.
- MUST_USE_RESULT static MaybeObject* Allocate(int deopt_entry_count,
- PretenureFlag pretenure);
+ static Handle<DeoptimizationInputData> New(Isolate* isolate,
+ int deopt_entry_count,
+ PretenureFlag pretenure);
- // Casting.
- static inline DeoptimizationInputData* cast(Object* obj);
+ DECLARE_CAST(DeoptimizationInputData)
#ifdef ENABLE_DISASSEMBLER
- void DeoptimizationInputDataPrint(FILE* out);
+ void DeoptimizationInputDataPrint(OStream& os); // NOLINT
#endif
private:
@@ -4022,9 +4870,8 @@
return kFirstDeoptEntryIndex + (i * kDeoptEntrySize);
}
- static int LengthFor(int entry_count) {
- return IndexForEntry(entry_count);
- }
+
+ static int LengthFor(int entry_count) { return IndexForEntry(entry_count); }
};
@@ -4036,8 +4883,15 @@
class DeoptimizationOutputData: public FixedArray {
public:
int DeoptPoints() { return length() / 2; }
- Smi* AstId(int index) { return Smi::cast(get(index * 2)); }
- void SetAstId(int index, Smi* id) { set(index * 2, id); }
+
+ BailoutId AstId(int index) {
+ return BailoutId(Smi::cast(get(index * 2))->value());
+ }
+
+ void SetAstId(int index, BailoutId id) {
+ set(index * 2, Smi::FromInt(id.ToInt()));
+ }
+
Smi* PcAndState(int index) { return Smi::cast(get(1 + index * 2)); }
void SetPcAndState(int index, Smi* offset) { set(1 + index * 2, offset); }
@@ -4046,58 +4900,21 @@
}
// Allocates a DeoptimizationOutputData.
- MUST_USE_RESULT static MaybeObject* Allocate(int number_of_deopt_points,
- PretenureFlag pretenure);
+ static Handle<DeoptimizationOutputData> New(Isolate* isolate,
+ int number_of_deopt_points,
+ PretenureFlag pretenure);
- // Casting.
- static inline DeoptimizationOutputData* cast(Object* obj);
+ DECLARE_CAST(DeoptimizationOutputData)
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
- void DeoptimizationOutputDataPrint(FILE* out);
+ void DeoptimizationOutputDataPrint(OStream& os); // NOLINT
#endif
};
// Forward declaration.
-class JSGlobalPropertyCell;
-
-// TypeFeedbackCells is a fixed array used to hold the association between
-// cache cells and AST ids for code generated by the full compiler.
-// The format of the these objects is
-// [i * 2]: Global property cell of ith cache cell.
-// [i * 2 + 1]: Ast ID for ith cache cell.
-class TypeFeedbackCells: public FixedArray {
- public:
- int CellCount() { return length() / 2; }
- static int LengthOfFixedArray(int cell_count) { return cell_count * 2; }
-
- // Accessors for AST ids associated with cache values.
- inline Smi* AstId(int index);
- inline void SetAstId(int index, Smi* id);
-
- // Accessors for global property cells holding the cache values.
- inline JSGlobalPropertyCell* Cell(int index);
- inline void SetCell(int index, JSGlobalPropertyCell* cell);
-
- // The object that indicates an uninitialized cache.
- static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
-
- // The object that indicates a megamorphic state.
- static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
-
- // 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);
-
- // Casting.
- static inline TypeFeedbackCells* cast(Object* obj);
-
- static const int kForInFastCaseMarker = 0;
- static const int kForInSlowCaseMarker = 1;
-};
-
-
-// Forward declaration.
+class Cell;
+class PropertyCell;
class SafepointEntry;
class TypeFeedbackInfo;
@@ -4106,64 +4923,69 @@
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 NON_IC_KIND_LIST(V) \
+ V(FUNCTION) \
+ V(OPTIMIZED_FUNCTION) \
+ V(STUB) \
+ V(HANDLER) \
+ V(BUILTIN) \
+ V(REGEXP)
+
+#define IC_KIND_LIST(V) \
+ V(LOAD_IC) \
+ V(KEYED_LOAD_IC) \
+ V(CALL_IC) \
+ V(STORE_IC) \
+ V(KEYED_STORE_IC) \
+ V(BINARY_OP_IC) \
+ V(COMPARE_IC) \
+ V(COMPARE_NIL_IC) \
+ V(TO_BOOLEAN_IC)
+
+#define CODE_KIND_LIST(V) \
+ NON_IC_KIND_LIST(V) \
+ IC_KIND_LIST(V)
enum Kind {
- FUNCTION,
- OPTIMIZED_FUNCTION,
- STUB,
- BUILTIN,
- LOAD_IC,
- KEYED_LOAD_IC,
- CALL_IC,
- KEYED_CALL_IC,
- STORE_IC,
- KEYED_STORE_IC,
- UNARY_OP_IC,
- BINARY_OP_IC,
- COMPARE_IC,
- TO_BOOLEAN_IC,
- // No more than 16 kinds. The value currently encoded in four bits in
- // Flags.
-
- // Pseudo-kinds.
- REGEXP = BUILTIN,
- FIRST_IC_KIND = LOAD_IC,
- LAST_IC_KIND = TO_BOOLEAN_IC
+#define DEFINE_CODE_KIND_ENUM(name) name,
+ CODE_KIND_LIST(DEFINE_CODE_KIND_ENUM)
+#undef DEFINE_CODE_KIND_ENUM
+ NUMBER_OF_KINDS
};
- enum {
- NUMBER_OF_KINDS = LAST_IC_KIND + 1
+ // No more than 16 kinds. The value is currently encoded in four bits in
+ // Flags.
+ STATIC_ASSERT(NUMBER_OF_KINDS <= 16);
+
+ static const char* Kind2String(Kind kind);
+
+ // Types of stubs.
+ enum StubType {
+ NORMAL,
+ FAST
};
- typedef int ExtraICState;
-
- static const ExtraICState kNoExtraICState = 0;
+ static const int kPrologueOffsetNotSet = -1;
#ifdef ENABLE_DISASSEMBLER
// Printing
- static const char* Kind2String(Kind kind);
static const char* ICState2String(InlineCacheState state);
- static const char* PropertyType2String(PropertyType type);
- static void PrintExtraICState(FILE* out, Kind kind, ExtraICState extra);
- inline void Disassemble(const char* name) {
- Disassemble(name, stdout);
- }
- void Disassemble(const char* name, FILE* out);
+ static const char* StubType2String(StubType type);
+ static void PrintExtraICState(OStream& os, // NOLINT
+ Kind kind, ExtraICState extra);
+ void Disassemble(const char* name, OStream& os); // NOLINT
#endif // ENABLE_DISASSEMBLER
// [instruction_size]: Size of the native instructions
- inline int instruction_size();
+ inline int instruction_size() const;
inline void set_instruction_size(int value);
// [relocation_info]: Code relocation information
DECL_ACCESSORS(relocation_info, ByteArray)
void InvalidateRelocation();
+ void InvalidateEmbeddedObjects();
// [handler_table]: Fixed array containing offsets of exception handlers.
DECL_ACCESSORS(handler_table, FixedArray)
@@ -4171,9 +4993,20 @@
// [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.
- DECL_ACCESSORS(type_feedback_info, Object)
+ // [raw_type_feedback_info]: This field stores various things, depending on
+ // the kind of the code object.
+ // FUNCTION => type feedback information.
+ // STUB and ICs => major/minor key as Smi.
+ DECL_ACCESSORS(raw_type_feedback_info, Object)
+ inline Object* type_feedback_info();
+ inline void set_type_feedback_info(
+ Object* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+ inline uint32_t stub_key();
+ inline void set_stub_key(uint32_t key);
+
+ // [next_code_link]: Link for lists of optimized or deoptimized code.
+ // Note that storage for this field is overlapped with typefeedback_info.
+ DECL_ACCESSORS(next_code_link, Object)
// [gc_metadata]: Field used to hold GC related metadata. The contents of this
// field does not have to be traced during garbage collection since
@@ -4183,11 +5016,15 @@
// [ic_age]: Inline caching age: the value of the Heap::global_ic_age
// at the moment when this object was created.
inline void set_ic_age(int count);
- inline int ic_age();
+ inline int ic_age() const;
+
+ // [prologue_offset]: Offset of the function prologue, used for aging
+ // FUNCTIONs and OPTIMIZED_FUNCTIONs.
+ inline int prologue_offset() const;
+ inline void set_prologue_offset(int offset);
// Unchecked accessors to be used during GC.
inline ByteArray* unchecked_relocation_info();
- inline FixedArray* unchecked_deoptimization_data();
inline int relocation_size();
@@ -4199,30 +5036,52 @@
inline Kind kind();
inline InlineCacheState ic_state(); // Only valid for IC stubs.
inline ExtraICState extra_ic_state(); // Only valid for IC stubs.
- inline PropertyType type(); // Only valid for monomorphic IC stubs.
- inline int arguments_count(); // Only valid for call IC stubs.
+
+ inline StubType type(); // Only valid for monomorphic IC stubs.
// Testers for IC stub kinds.
inline bool is_inline_cache_stub();
+ inline bool is_debug_stub();
+ inline bool is_handler() { return kind() == HANDLER; }
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; }
inline bool is_keyed_store_stub() { return kind() == KEYED_STORE_IC; }
inline bool is_call_stub() { return kind() == CALL_IC; }
- inline bool is_keyed_call_stub() { return kind() == KEYED_CALL_IC; }
- inline bool is_unary_op_stub() { return kind() == UNARY_OP_IC; }
inline bool is_binary_op_stub() { return kind() == BINARY_OP_IC; }
inline bool is_compare_ic_stub() { return kind() == COMPARE_IC; }
+ inline bool is_compare_nil_ic_stub() { return kind() == COMPARE_NIL_IC; }
inline bool is_to_boolean_ic_stub() { return kind() == TO_BOOLEAN_IC; }
+ inline bool is_keyed_stub();
+ inline bool is_optimized_code() { return kind() == OPTIMIZED_FUNCTION; }
+ inline bool is_weak_stub();
+ inline void mark_as_weak_stub();
+ inline bool is_invalidated_weak_stub();
+ inline void mark_as_invalidated_weak_stub();
- // [major_key]: For kind STUB or BINARY_OP_IC, the major key.
- inline int major_key();
- inline void set_major_key(int value);
+ inline bool CanBeWeakStub() {
+ Kind k = kind();
+ return (k == LOAD_IC || k == STORE_IC || k == KEYED_LOAD_IC ||
+ k == KEYED_STORE_IC || k == COMPARE_NIL_IC) &&
+ ic_state() == MONOMORPHIC;
+ }
- // For stubs, tells whether they should always exist, so that they can be
- // called from other stubs.
- inline bool is_pregenerated();
- inline void set_is_pregenerated(bool value);
+ inline bool IsCodeStubOrIC();
+
+ inline void set_raw_kind_specific_flags1(int value);
+ inline void set_raw_kind_specific_flags2(int value);
+
+ // [is_crankshafted]: For kind STUB or ICs, tells whether or not a code
+ // object was generated by either the hydrogen or the TurboFan optimizing
+ // compiler (but it may not be an optimized function).
+ inline bool is_crankshafted();
+ inline bool is_hydrogen_stub(); // Crankshafted, but not a function.
+ inline void set_is_crankshafted(bool value);
+
+ // [is_turbofanned]: For kind STUB or OPTIMIZED_FUNCTION, tells whether the
+ // code object was generated by the TurboFan optimizing compiler.
+ inline bool is_turbofanned();
+ inline void set_is_turbofanned(bool value);
// [optimizable]: For FUNCTION kind, tells if it is optimizable.
inline bool optimizable();
@@ -4243,11 +5102,6 @@
inline bool is_compiled_optimizable();
inline void set_compiled_optimizable(bool value);
- // [has_self_optimization_header]: For FUNCTION kind, tells if it has
- // a self-optimization header.
- inline bool has_self_optimization_header();
- inline void set_self_optimization_header(bool value);
-
// [allow_osr_at_loop_nesting_level]: For FUNCTION kind, tells for
// how long the function has been marked for OSR and therefore which
// level of loop nesting we are willing to do on-stack replacement
@@ -4260,105 +5114,109 @@
inline int profiler_ticks();
inline void set_profiler_ticks(int ticks);
+ // [builtin_index]: For BUILTIN kind, tells which builtin index it has.
+ inline int builtin_index();
+ inline void set_builtin_index(int id);
+
// [stack_slots]: For kind OPTIMIZED_FUNCTION, the number of stack slots
// reserved in the code prologue.
inline unsigned stack_slots();
inline void set_stack_slots(unsigned slots);
- // [safepoint_table_start]: For kind OPTIMIZED_CODE, the offset in
+ // [safepoint_table_start]: For kind OPTIMIZED_FUNCTION, the offset in
// the instruction stream where the safepoint table starts.
inline unsigned safepoint_table_offset();
inline void set_safepoint_table_offset(unsigned offset);
- // [stack_check_table_start]: For kind FUNCTION, the offset in the
- // instruction stream where the stack check table starts.
- inline unsigned stack_check_table_offset();
- inline void set_stack_check_table_offset(unsigned offset);
+ // [back_edge_table_start]: For kind FUNCTION, the offset in the
+ // instruction stream where the back edge table starts.
+ inline unsigned back_edge_table_offset();
+ inline void set_back_edge_table_offset(unsigned offset);
- // [check type]: For kind CALL_IC, tells how to check if the
- // receiver is valid for the given call.
- inline CheckType check_type();
- inline void set_check_type(CheckType value);
-
- // [type-recording unary op type]: For kind UNARY_OP_IC.
- 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);
+ inline bool back_edges_patched_for_osr();
// [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);
// [has_function_cache]: For kind STUB tells whether there is a function
// cache is passed to the stub.
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);
+
+ // [constant_pool]: The constant pool for this function.
+ inline ConstantPoolArray* constant_pool();
+ inline void set_constant_pool(Object* constant_pool);
+
// Get the safepoint entry for the given pc.
SafepointEntry GetSafepointEntry(Address pc);
- // Mark this code object as not having a stack check table. Assumes kind
- // is FUNCTION.
- void SetNoStackCheckTable();
+ // Find an object in a stub with a specified map
+ Object* FindNthObject(int n, Map* match_map);
+
+ // Find the first allocation site in an IC stub.
+ AllocationSite* FindFirstAllocationSite();
// 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 handler in an IC stub.
+ Code* FindFirstHandler();
- static const int kExtraICStateGrowModeShift = 1;
+ // Find |length| handlers and put them into |code_list|. Returns false if not
+ // enough handlers can be found.
+ bool FindHandlers(CodeHandleList* code_list, int length = -1);
- static inline StrictModeFlag GetStrictMode(ExtraICState extra_ic_state) {
- return ExtraICStateStrictMode::decode(extra_ic_state);
- }
+ // Find the handler for |map|.
+ MaybeHandle<Code> FindHandlerForMap(Map* map);
- static inline KeyedAccessGrowMode GetKeyedAccessGrowMode(
- ExtraICState extra_ic_state) {
- return ExtraICStateKeyedAccessGrowMode::decode(extra_ic_state);
- }
+ // Find the first name in an IC stub.
+ Name* FindFirstName();
- static inline ExtraICState ComputeExtraICState(
- KeyedAccessGrowMode grow_mode,
- StrictModeFlag strict_mode) {
- return ExtraICStateKeyedAccessGrowMode::encode(grow_mode) |
- ExtraICStateStrictMode::encode(strict_mode);
- }
+ class FindAndReplacePattern;
+ // For each (map-to-find, object-to-replace) pair in the pattern, this
+ // function replaces the corresponding placeholder in the code with the
+ // object-to-replace. The function assumes that pairs in the pattern come in
+ // the same order as the placeholders in the code.
+ void FindAndReplace(const FindAndReplacePattern& pattern);
+
+ // The entire code object including its header is copied verbatim to the
+ // snapshot so that it can be written in one, fast, memcpy during
+ // deserialization. The deserializer will overwrite some pointers, rather
+ // like a runtime linker, but the random allocation addresses used in the
+ // mksnapshot process would still be present in the unlinked snapshot data,
+ // which would make snapshot production non-reproducible. This method wipes
+ // out the to-be-overwritten header data for reproducible snapshots.
+ inline void WipeOutHeader();
// Flags operations.
static inline Flags ComputeFlags(
- Kind kind,
- InlineCacheState ic_state = UNINITIALIZED,
- ExtraICState extra_ic_state = kNoExtraICState,
- PropertyType type = NORMAL,
- int argc = -1,
- InlineCacheHolderFlag holder = OWN_MAP);
+ Kind kind, InlineCacheState ic_state = UNINITIALIZED,
+ ExtraICState extra_ic_state = kNoExtraICState, StubType type = NORMAL,
+ CacheHolderFlag holder = kCacheOnReceiver);
static inline Flags ComputeMonomorphicFlags(
- Kind kind,
- PropertyType type,
- ExtraICState extra_ic_state = kNoExtraICState,
- InlineCacheHolderFlag holder = OWN_MAP,
- int argc = -1);
+ Kind kind, ExtraICState extra_ic_state = kNoExtraICState,
+ CacheHolderFlag holder = kCacheOnReceiver, StubType type = NORMAL);
+
+ static inline Flags ComputeHandlerFlags(
+ Kind handler_kind, StubType type = NORMAL,
+ CacheHolderFlag holder = kCacheOnReceiver);
static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
- static inline PropertyType ExtractTypeFromFlags(Flags flags);
+ static inline StubType ExtractTypeFromFlags(Flags flags);
+ static inline CacheHolderFlag ExtractCacheHolderFromFlags(Flags flags);
static inline Kind ExtractKindFromFlags(Flags flags);
- static inline InlineCacheHolderFlag ExtractCacheHolderFromFlags(Flags flags);
static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags);
- static inline int ExtractArgumentsCountFromFlags(Flags flags);
static inline Flags RemoveTypeFromFlags(Flags flags);
+ static inline Flags RemoveTypeAndHolderFromFlags(Flags flags);
// Convert a target address into a code object.
static inline Code* GetCodeFromTargetAddress(Address address);
@@ -4393,7 +5251,7 @@
// Returns the object size for a given body (used for allocation).
static int SizeFor(int body_size) {
- ASSERT_SIZE_TAG_ALIGNED(body_size);
+ DCHECK_SIZE_TAG_ALIGNED(body_size);
return RoundUp(kHeaderSize + body_size, kCodeAlignment);
}
@@ -4401,7 +5259,7 @@
// the layout of the code object into account.
int ExecutableSize() {
// Check that the assumptions about the layout of the code object holds.
- ASSERT_EQ(static_cast<int>(instruction_start() - address()),
+ DCHECK_EQ(static_cast<int>(instruction_start() - address()),
Code::kHeaderSize);
return instruction_size() + Code::kHeaderSize;
}
@@ -4410,8 +5268,7 @@
int SourcePosition(Address pc);
int SourceStatementPosition(Address pc);
- // Casting.
- static inline Code* cast(Object* obj);
+ DECLARE_CAST(Code)
// Dispatched behavior.
int CodeSize() { return SizeFor(body_size()); }
@@ -4419,16 +5276,67 @@
template<typename StaticVisitor>
inline void CodeIterateBody(Heap* heap);
-#ifdef OBJECT_PRINT
- inline void CodePrint() {
- CodePrint(stdout);
- }
- void CodePrint(FILE* out);
-#endif
-#ifdef DEBUG
- void CodeVerify();
-#endif
+
+ DECLARE_PRINTER(Code)
+ DECLARE_VERIFIER(Code)
+
void ClearInlineCaches();
+ void ClearInlineCaches(Kind kind);
+
+ BailoutId TranslatePcOffsetToAstId(uint32_t pc_offset);
+ uint32_t TranslateAstIdToPcOffset(BailoutId ast_id);
+
+#define DECLARE_CODE_AGE_ENUM(X) k##X##CodeAge,
+ enum Age {
+ kNotExecutedCodeAge = -2,
+ kExecutedOnceCodeAge = -1,
+ kNoAgeCodeAge = 0,
+ CODE_AGE_LIST(DECLARE_CODE_AGE_ENUM)
+ kAfterLastCodeAge,
+ kFirstCodeAge = kNotExecutedCodeAge,
+ kLastCodeAge = kAfterLastCodeAge - 1,
+ kCodeAgeCount = kAfterLastCodeAge - kNotExecutedCodeAge - 1,
+ kIsOldCodeAge = kSexagenarianCodeAge,
+ kPreAgedCodeAge = kIsOldCodeAge - 1
+ };
+#undef DECLARE_CODE_AGE_ENUM
+
+ // Code aging. Indicates how many full GCs this code has survived without
+ // being entered through the prologue. Used to determine when it is
+ // relatively safe to flush this code object and replace it with the lazy
+ // compilation stub.
+ static void MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate);
+ static void MarkCodeAsExecuted(byte* sequence, Isolate* isolate);
+ void MakeOlder(MarkingParity);
+ static bool IsYoungSequence(Isolate* isolate, byte* sequence);
+ bool IsOld();
+ Age GetAge();
+ // Gets the raw code age, including psuedo code-age values such as
+ // kNotExecutedCodeAge and kExecutedOnceCodeAge.
+ Age GetRawAge();
+ static inline Code* GetPreAgedCodeAgeStub(Isolate* isolate) {
+ return GetCodeAgeStub(isolate, kNotExecutedCodeAge, NO_MARKING_PARITY);
+ }
+
+ void PrintDeoptLocation(FILE* out, int bailout_id);
+ bool CanDeoptAt(Address pc);
+
+#ifdef VERIFY_HEAP
+ void VerifyEmbeddedObjectsDependency();
+#endif
+
+ inline bool CanContainWeakObjects() {
+ return is_optimized_code() || is_weak_stub();
+ }
+
+ inline bool IsWeakObject(Object* object) {
+ return (is_optimized_code() && !is_turbofanned() &&
+ IsWeakObjectInOptimizedCode(object)) ||
+ (is_weak_stub() && IsWeakObjectInIC(object));
+ }
+
+ static inline bool IsWeakObjectInOptimizedCode(Object* object);
+ static inline bool IsWeakObjectInIC(Object* object);
// Max loop nesting marker used to postpose OSR. We don't take loop
// nesting that is deeper than 5 levels into account.
@@ -4440,71 +5348,245 @@
static const int kHandlerTableOffset = kRelocationInfoOffset + kPointerSize;
static const int kDeoptimizationDataOffset =
kHandlerTableOffset + kPointerSize;
+ // For FUNCTION kind, we store the type feedback info here.
static const int kTypeFeedbackInfoOffset =
kDeoptimizationDataOffset + kPointerSize;
- static const int kGCMetadataOffset = kTypeFeedbackInfoOffset + kPointerSize;
+ static const int kNextCodeLinkOffset = kTypeFeedbackInfoOffset + kPointerSize;
+ static const int kGCMetadataOffset = kNextCodeLinkOffset + kPointerSize;
static const int kICAgeOffset =
kGCMetadataOffset + kPointerSize;
static const int kFlagsOffset = kICAgeOffset + kIntSize;
- static const int kKindSpecificFlagsOffset = kFlagsOffset + kIntSize;
- static const int kKindSpecificFlagsSize = 2 * kIntSize;
+ static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize;
+ static const int kKindSpecificFlags2Offset =
+ kKindSpecificFlags1Offset + kIntSize;
+ // Note: We might be able to squeeze this into the flags above.
+ static const int kPrologueOffset = kKindSpecificFlags2Offset + kIntSize;
+ static const int kConstantPoolOffset = kPrologueOffset + kPointerSize;
- static const int kHeaderPaddingStart = kKindSpecificFlagsOffset +
- kKindSpecificFlagsSize;
+ static const int kHeaderPaddingStart = kConstantPoolOffset + kIntSize;
// Add padding to align the instruction start following right after
// the Code object header.
static const int kHeaderSize =
(kHeaderPaddingStart + kCodeAlignmentMask) & ~kCodeAlignmentMask;
- // Byte offsets within kKindSpecificFlagsOffset.
- static const int kStubMajorKeyOffset = kKindSpecificFlagsOffset;
- static const int kOptimizableOffset = kKindSpecificFlagsOffset;
- static const int kStackSlotsOffset = kKindSpecificFlagsOffset;
- static const int kCheckTypeOffset = kKindSpecificFlagsOffset;
-
- static const int kUnaryOpTypeOffset = kStubMajorKeyOffset + 1;
- static const int kBinaryOpTypeOffset = kStubMajorKeyOffset + 1;
- static const int kCompareStateOffset = kStubMajorKeyOffset + 1;
- static const int kToBooleanTypeOffset = kStubMajorKeyOffset + 1;
- static const int kHasFunctionCacheOffset = kStubMajorKeyOffset + 1;
+ // Byte offsets within kKindSpecificFlags1Offset.
+ static const int kOptimizableOffset = kKindSpecificFlags1Offset;
static const int kFullCodeFlags = kOptimizableOffset + 1;
class FullCodeFlagsHasDeoptimizationSupportField:
public BitField<bool, 0, 1> {}; // NOLINT
class FullCodeFlagsHasDebugBreakSlotsField: public BitField<bool, 1, 1> {};
class FullCodeFlagsIsCompiledOptimizable: public BitField<bool, 2, 1> {};
- class FullCodeFlagsHasSelfOptimizationHeader: public BitField<bool, 3, 1> {};
- static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1;
-
- static const int kAllowOSRAtLoopNestingLevelOffset = kFullCodeFlags + 1;
- static const int kProfilerTicksOffset = kAllowOSRAtLoopNestingLevelOffset + 1;
-
- static const int kSafepointTableOffsetOffset = kStackSlotsOffset + kIntSize;
- static const int kStackCheckTableOffsetOffset = kStackSlotsOffset + kIntSize;
+ static const int kProfilerTicksOffset = kFullCodeFlags + 1;
// Flags layout. BitField<type, shift, size>.
- class ICStateField: public BitField<InlineCacheState, 0, 3> {};
- class TypeField: public BitField<PropertyType, 3, 4> {};
- class CacheHolderField: public BitField<InlineCacheHolderFlag, 7, 1> {};
- class KindField: public BitField<Kind, 8, 4> {};
- class ExtraICStateField: public BitField<ExtraICState, 12, 2> {};
- class IsPregeneratedField: public BitField<bool, 14, 1> {};
+ class ICStateField : public BitField<InlineCacheState, 0, 4> {};
+ class TypeField : public BitField<StubType, 4, 1> {};
+ class CacheHolderField : public BitField<CacheHolderFlag, 5, 2> {};
+ class KindField : public BitField<Kind, 7, 4> {};
+ class ExtraICStateField: public BitField<ExtraICState, 11,
+ PlatformSmiTagging::kSmiValueSize - 11 + 1> {}; // NOLINT
- // Signed field cannot be encoded using the BitField class.
- static const int kArgumentsCountShift = 15;
- static const int kArgumentsCountMask = ~((1 << kArgumentsCountShift) - 1);
+ // KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION)
+ static const int kStackSlotsFirstBit = 0;
+ static const int kStackSlotsBitCount = 24;
+ static const int kHasFunctionCacheBit =
+ kStackSlotsFirstBit + kStackSlotsBitCount;
+ static const int kMarkedForDeoptimizationBit = kHasFunctionCacheBit + 1;
+ static const int kWeakStubBit = kMarkedForDeoptimizationBit + 1;
+ static const int kInvalidatedWeakStubBit = kWeakStubBit + 1;
+ static const int kIsTurbofannedBit = kInvalidatedWeakStubBit + 1;
+
+ STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32);
+ STATIC_ASSERT(kIsTurbofannedBit + 1 <= 32);
+
+ class StackSlotsField: public BitField<int,
+ kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT
+ class HasFunctionCacheField : public BitField<bool, kHasFunctionCacheBit, 1> {
+ }; // NOLINT
+ class MarkedForDeoptimizationField
+ : public BitField<bool, kMarkedForDeoptimizationBit, 1> {}; // NOLINT
+ class WeakStubField : public BitField<bool, kWeakStubBit, 1> {}; // NOLINT
+ class InvalidatedWeakStubField
+ : public BitField<bool, kInvalidatedWeakStubBit, 1> {}; // NOLINT
+ class IsTurbofannedField : public BitField<bool, kIsTurbofannedBit, 1> {
+ }; // NOLINT
+
+ // KindSpecificFlags2 layout (ALL)
+ static const int kIsCrankshaftedBit = 0;
+ class IsCrankshaftedField: public BitField<bool,
+ kIsCrankshaftedBit, 1> {}; // NOLINT
+
+ // KindSpecificFlags2 layout (STUB and OPTIMIZED_FUNCTION)
+ static const int kSafepointTableOffsetFirstBit = kIsCrankshaftedBit + 1;
+ static const int kSafepointTableOffsetBitCount = 24;
+
+ STATIC_ASSERT(kSafepointTableOffsetFirstBit +
+ kSafepointTableOffsetBitCount <= 32);
+ STATIC_ASSERT(1 + kSafepointTableOffsetBitCount <= 32);
+
+ class SafepointTableOffsetField: public BitField<int,
+ kSafepointTableOffsetFirstBit,
+ kSafepointTableOffsetBitCount> {}; // NOLINT
+
+ // KindSpecificFlags2 layout (FUNCTION)
+ class BackEdgeTableOffsetField: public BitField<int,
+ kIsCrankshaftedBit + 1, 27> {}; // NOLINT
+ class AllowOSRAtLoopNestingLevelField: public BitField<int,
+ kIsCrankshaftedBit + 1 + 27, 4> {}; // NOLINT
+ STATIC_ASSERT(AllowOSRAtLoopNestingLevelField::kMax >= kMaxLoopNestingMarker);
+
+ static const int kArgumentsBits = 16;
+ 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;
+ friend class Deoptimizer; // For FindCodeAgeSequence.
+
+ void ClearInlineCaches(Kind* kind);
+
+ // Code aging
+ byte* FindCodeAgeSequence();
+ static void GetCodeAgeAndParity(Code* code, Age* age,
+ MarkingParity* parity);
+ static void GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
+ MarkingParity* parity);
+ static Code* GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity);
+
+ // Code aging -- platform-specific
+ static void PatchPlatformCodeAge(Isolate* isolate,
+ byte* sequence, Age age,
+ MarkingParity parity);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
};
+class CompilationInfo;
+
+// 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 IC stubs that weakly embed this map and depend on being
+ // invalidated when the map is garbage collected. Dependent IC stubs form
+ // a linked list. This group stores only the head of the list. This means
+ // that the number_of_entries(kWeakICGroup) is 0 or 1.
+ kWeakICGroup,
+ // Group of code that weakly embed this map and depend on being
+ // deoptimized when the map is garbage collected.
+ kWeakCodeGroup,
+ // Group of code that embed a transition to this map, and depend on being
+ // deoptimized when the transition is replaced by a new version.
+ kTransitionGroup,
+ // 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,
+ // Group of code that depends on elements not being added to objects with
+ // this map.
+ kElementsCantBeAddedGroup,
+ // Group of code that depends on global property values in property cells
+ // not being changed.
+ kPropertyCellChangedGroup,
+ // Group of code that omit run-time type checks for the field(s) introduced
+ // by this map.
+ kFieldTypeGroup,
+ // Group of code that omit run-time type checks for initial maps of
+ // constructors.
+ kInitialMapChangedGroup,
+ // Group of code that depends on tenuring information in AllocationSites
+ // not being changed.
+ kAllocationSiteTenuringChangedGroup,
+ // Group of code that depends on element transition information in
+ // AllocationSites not being changed.
+ kAllocationSiteTransitionChangedGroup
+ };
+
+ static const int kGroupCount = kAllocationSiteTransitionChangedGroup + 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<Object> object);
+ void UpdateToFinishedCode(DependencyGroup group,
+ CompilationInfo* info,
+ Code* code);
+ void RemoveCompilationInfo(DependentCode::DependencyGroup group,
+ CompilationInfo* info);
+
+ void DeoptimizeDependentCodeGroup(Isolate* isolate,
+ DependentCode::DependencyGroup group);
+
+ bool MarkCodeForDeoptimization(Isolate* isolate,
+ DependentCode::DependencyGroup group);
+ void AddToDependentICList(Handle<Code> stub);
+
+ // 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 bool is_code_at(int i);
+ inline Code* code_at(int i);
+ inline CompilationInfo* compilation_info_at(int i);
+ inline void set_object_at(int i, Object* object);
+ inline Object** slot_at(int i);
+ inline Object* object_at(int i);
+ inline void clear_at(int i);
+ inline void copy(int from, int to);
+ DECLARE_CAST(DependentCode)
+
+ static DependentCode* ForObject(Handle<HeapObject> object,
+ DependencyGroup group);
+
+ static const char* DependencyGroupName(DependencyGroup group);
+ static void SetMarkedForDeoptimization(Code* code, DependencyGroup group);
+
+ 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
@@ -4543,11 +5625,27 @@
inline void set_bit_field2(byte value);
// Bit field 3.
- // TODO(1399): It should be possible to make room for bit_field3 in the map
- // without overloading the instance descriptors field (and storing it in the
- // DescriptorArray when the map has one).
- inline int bit_field3();
- inline void set_bit_field3(int value);
+ inline uint32_t bit_field3();
+ inline void set_bit_field3(uint32_t bits);
+
+ class EnumLengthBits: public BitField<int,
+ 0, kDescriptorIndexBitCount> {}; // NOLINT
+ class NumberOfOwnDescriptorsBits: public BitField<int,
+ kDescriptorIndexBitCount, kDescriptorIndexBitCount> {}; // NOLINT
+ STATIC_ASSERT(kDescriptorIndexBitCount + kDescriptorIndexBitCount == 20);
+ class DictionaryMap : public BitField<bool, 20, 1> {};
+ class OwnsDescriptors : public BitField<bool, 21, 1> {};
+ class HasInstanceCallHandler : public BitField<bool, 22, 1> {};
+ class Deprecated : public BitField<bool, 23, 1> {};
+ class IsFrozen : public BitField<bool, 24, 1> {};
+ class IsUnstable : public BitField<bool, 25, 1> {};
+ class IsMigrationTarget : public BitField<bool, 26, 1> {};
+ class DoneInobjectSlackTracking : public BitField<bool, 27, 1> {};
+ // Bit 28 is free.
+
+ // Keep this bit field at the very end for better code in
+ // Builtins::kJSConstructStubGeneric stub.
+ class ConstructionCount: public BitField<int, 29, 3> {};
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
@@ -4564,7 +5662,7 @@
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));
}
@@ -4606,116 +5704,196 @@
}
// Tells whether the instance has a call-as-function handler.
- inline void set_has_instance_call_handler() {
- set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));
+ inline void set_is_observed() {
+ set_bit_field(bit_field() | (1 << kIsObserved));
}
- inline bool has_instance_call_handler() {
- return ((1 << kHasInstanceCallHandler) & bit_field()) != 0;
+ inline bool is_observed() {
+ return ((1 << kIsObserved) & bit_field()) != 0;
}
inline void set_is_extensible(bool value);
inline bool is_extensible();
+ inline void set_is_prototype_map(bool value);
+ inline bool is_prototype_map();
inline void set_elements_kind(ElementsKind elements_kind) {
- ASSERT(elements_kind < kElementsKindCount);
- ASSERT(kElementsKindCount <= (1 << kElementsKindBitCount));
- set_bit_field2((bit_field2() & ~kElementsKindMask) |
- (elements_kind << kElementsKindShift));
- ASSERT(this->elements_kind() == elements_kind);
+ DCHECK(elements_kind < kElementsKindCount);
+ DCHECK(kElementsKindCount <= (1 << Map::ElementsKindBits::kSize));
+ set_bit_field2(Map::ElementsKindBits::update(bit_field2(), elements_kind));
+ DCHECK(this->elements_kind() == elements_kind);
}
inline ElementsKind elements_kind() {
- return static_cast<ElementsKind>(
- (bit_field2() & kElementsKindMask) >> kElementsKindShift);
+ return Map::ElementsKindBits::decode(bit_field2());
}
// Tells whether the instance has fast elements that are only Smis.
- inline bool has_fast_smi_only_elements() {
- return elements_kind() == FAST_SMI_ONLY_ELEMENTS;
+ inline bool has_fast_smi_elements() {
+ return IsFastSmiElementsKind(elements_kind());
}
// Tells whether the instance has fast elements.
- inline bool has_fast_elements() {
- return elements_kind() == FAST_ELEMENTS;
+ inline bool has_fast_object_elements() {
+ return IsFastObjectElementsKind(elements_kind());
+ }
+
+ inline bool has_fast_smi_or_object_elements() {
+ return IsFastSmiOrObjectElementsKind(elements_kind());
}
inline bool has_fast_double_elements() {
- return elements_kind() == FAST_DOUBLE_ELEMENTS;
+ return IsFastDoubleElementsKind(elements_kind());
}
- inline bool has_non_strict_arguments_elements() {
- return elements_kind() == NON_STRICT_ARGUMENTS_ELEMENTS;
+ inline bool has_fast_elements() {
+ return IsFastElementsKind(elements_kind());
+ }
+
+ inline bool has_sloppy_arguments_elements() {
+ return elements_kind() == SLOPPY_ARGUMENTS_ELEMENTS;
}
inline bool has_external_array_elements() {
- ElementsKind kind(elements_kind());
- return kind >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
- kind <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND;
+ return IsExternalArrayElementsKind(elements_kind());
+ }
+
+ inline bool has_fixed_typed_array_elements() {
+ return IsFixedTypedArrayElementsKind(elements_kind());
}
inline bool has_dictionary_elements() {
- return elements_kind() == DICTIONARY_ELEMENTS;
+ return IsDictionaryElementsKind(elements_kind());
}
inline bool has_slow_elements_kind() {
return elements_kind() == DICTIONARY_ELEMENTS
- || elements_kind() == NON_STRICT_ARGUMENTS_ELEMENTS;
+ || elements_kind() == SLOPPY_ARGUMENTS_ELEMENTS;
}
static bool IsValidElementsTransition(ElementsKind from_kind,
ElementsKind to_kind);
- // Tells whether the map is attached to SharedFunctionInfo
- // (for inobject slack tracking).
- inline void set_attached_to_shared_function_info(bool value);
+ // Returns true if the current map doesn't have DICTIONARY_ELEMENTS but if a
+ // map with DICTIONARY_ELEMENTS was found in the prototype chain.
+ bool DictionaryElementsInPrototypeChainOnly();
- inline bool attached_to_shared_function_info();
+ inline bool HasTransitionArray() const;
+ inline bool HasElementsTransition();
+ inline Map* elements_transition_map();
- // Tells whether the map is shared between objects that may have different
- // behavior. If true, the map should never be modified, instead a clone
- // should be created and modified.
- inline void set_is_shared(bool value);
+ inline Map* GetTransition(int transition_index);
+ inline int SearchTransition(Name* name);
+ inline FixedArrayBase* GetInitialElements();
- inline bool is_shared();
+ DECL_ACCESSORS(transitions, TransitionArray)
+
+ static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
+ static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
+
+ // Try to follow an existing transition to a field with attributes NONE. The
+ // return value indicates whether the transition was successful.
+ static inline Handle<Map> FindTransitionToField(Handle<Map> map,
+ Handle<Name> key);
+
+ Map* FindRootMap();
+ Map* FindFieldOwner(int descriptor);
+
+ inline int GetInObjectPropertyOffset(int index);
+
+ int NumberOfFields();
+
+ // TODO(ishell): candidate with JSObject::MigrateToMap().
+ bool InstancesNeedRewriting(Map* target, int target_number_of_fields,
+ int target_inobject, int target_unused,
+ int* old_number_of_fields);
+ // TODO(ishell): moveit!
+ static Handle<Map> GeneralizeAllFieldRepresentations(Handle<Map> map);
+ MUST_USE_RESULT static Handle<HeapType> GeneralizeFieldType(
+ Handle<HeapType> type1,
+ Handle<HeapType> type2,
+ Isolate* isolate);
+ static void GeneralizeFieldType(Handle<Map> map,
+ int modify_index,
+ Handle<HeapType> new_field_type);
+ static Handle<Map> GeneralizeRepresentation(
+ Handle<Map> map,
+ int modify_index,
+ Representation new_representation,
+ Handle<HeapType> new_field_type,
+ StoreMode store_mode);
+ static Handle<Map> CopyGeneralizeAllRepresentations(
+ Handle<Map> map,
+ int modify_index,
+ StoreMode store_mode,
+ PropertyAttributes attributes,
+ const char* reason);
+ static Handle<Map> CopyGeneralizeAllRepresentations(
+ Handle<Map> map,
+ int modify_index,
+ StoreMode store_mode,
+ const char* reason);
+
+ static Handle<Map> PrepareForDataProperty(Handle<Map> old_map,
+ int descriptor_number,
+ Handle<Object> value);
+
+ static Handle<Map> Normalize(Handle<Map> map, PropertyNormalizationMode mode);
+
+ // Returns the constructor name (the name (possibly, inferred name) of the
+ // function that was used to instantiate the object).
+ String* constructor_name();
+
+ // Tells whether the map is used for JSObjects in dictionary mode (ie
+ // normalized objects, ie objects for which HasFastProperties returns false).
+ // A map can never be used for both dictionary mode and fast mode JSObjects.
+ // False by default and for HeapObjects that are not JSObjects.
+ inline void set_dictionary_map(bool value);
+ inline bool is_dictionary_map();
// Tells whether the instance needs security checks when accessing its
// properties.
inline void set_is_access_check_needed(bool access_check_needed);
inline bool is_access_check_needed();
+ // Returns true if map has a non-empty stub code cache.
+ inline bool has_code_cache();
+
// [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object)
// [constructor]: points back to the function responsible for this map.
DECL_ACCESSORS(constructor, Object)
- inline JSFunction* unchecked_constructor();
-
- // Should only be called by the code that initializes map to set initial valid
- // value of the instance descriptor member.
- inline void init_instance_descriptors();
-
// [instance descriptors]: describes the object.
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
-
- // Sets the instance descriptor array for the map to be an empty descriptor
- // array.
- inline void clear_instance_descriptors();
+ inline void InitializeDescriptors(DescriptorArray* descriptors);
// [stub cache]: contains stubs compiled for this map.
DECL_ACCESSORS(code_cache, Object)
+ // [dependent code]: list of optimized codes that weakly embed this map.
+ 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
+ // required.
+ inline Object* GetBackPointer();
+ inline void SetBackPointer(Object* value,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+ inline void init_back_pointer(Object* undefined);
+
// [prototype transitions]: cache of prototype transitions.
// Prototype transition is a transition that happens
// when we change object's prototype to a new one.
// Cache format:
// 0: finger - index of the first free cell in the cache
- // 1 + 2 * i: prototype
- // 2 + 2 * i: target map
- DECL_ACCESSORS(prototype_transitions, FixedArray)
-
- inline FixedArray* unchecked_prototype_transitions();
+ // 1: back pointer that overlaps with prototype transitions field.
+ // 2 + 2 * i: prototype
+ // 3 + 2 * i: target map
+ inline FixedArray* GetPrototypeTransitions();
+ inline bool HasPrototypeTransitions();
static const int kProtoTransitionHeaderSize = 1;
static const int kProtoTransitionNumberOfEntriesOffset = 0;
@@ -4724,50 +5902,170 @@
static const int kProtoTransitionMapOffset = 1;
inline int NumberOfProtoTransitions() {
- FixedArray* cache = prototype_transitions();
+ FixedArray* cache = GetPrototypeTransitions();
if (cache->length() == 0) return 0;
return
Smi::cast(cache->get(kProtoTransitionNumberOfEntriesOffset))->value();
}
inline void SetNumberOfProtoTransitions(int value) {
- FixedArray* cache = prototype_transitions();
- ASSERT(cache->length() != 0);
- cache->set_unchecked(kProtoTransitionNumberOfEntriesOffset,
- Smi::FromInt(value));
+ FixedArray* cache = GetPrototypeTransitions();
+ DCHECK(cache->length() != 0);
+ cache->set(kProtoTransitionNumberOfEntriesOffset, Smi::FromInt(value));
}
// Lookup in the map's instance descriptors and fill out the result
// with the given holder if the name is found. The holder may be
// NULL when this function is used from the compiler.
- void LookupInDescriptors(JSObject* holder,
- String* name,
- LookupResult* result);
+ inline void LookupDescriptor(JSObject* holder,
+ Name* name,
+ LookupResult* result);
- MUST_USE_RESULT MaybeObject* CopyDropDescriptors();
+ inline void LookupTransition(JSObject* holder,
+ Name* name,
+ LookupResult* result);
- MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode,
- NormalizedMapSharingMode sharing);
+ inline PropertyDetails GetLastDescriptorDetails();
+
+ // The size of transition arrays are limited so they do not end up in large
+ // object space. Otherwise ClearNonLiveTransitions would leak memory while
+ // applying in-place right trimming.
+ inline bool CanHaveMoreTransitions();
+
+ int LastAdded() {
+ int number_of_own_descriptors = NumberOfOwnDescriptors();
+ DCHECK(number_of_own_descriptors > 0);
+ return number_of_own_descriptors - 1;
+ }
+
+ int NumberOfOwnDescriptors() {
+ return NumberOfOwnDescriptorsBits::decode(bit_field3());
+ }
+
+ void SetNumberOfOwnDescriptors(int number) {
+ DCHECK(number <= instance_descriptors()->number_of_descriptors());
+ set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(), number));
+ }
+
+ inline Cell* RetrieveDescriptorsPointer();
+
+ int EnumLength() {
+ return EnumLengthBits::decode(bit_field3());
+ }
+
+ void SetEnumLength(int length) {
+ if (length != kInvalidEnumCacheSentinel) {
+ DCHECK(length >= 0);
+ DCHECK(length == 0 || instance_descriptors()->HasEnumCache());
+ DCHECK(length <= NumberOfOwnDescriptors());
+ }
+ set_bit_field3(EnumLengthBits::update(bit_field3(), length));
+ }
+
+ inline bool owns_descriptors();
+ inline void set_owns_descriptors(bool owns_descriptors);
+ inline bool has_instance_call_handler();
+ inline void set_has_instance_call_handler();
+ inline void freeze();
+ inline bool is_frozen();
+ inline void mark_unstable();
+ inline bool is_stable();
+ inline void set_migration_target(bool value);
+ inline bool is_migration_target();
+ inline void set_done_inobject_slack_tracking(bool value);
+ inline bool done_inobject_slack_tracking();
+ inline void set_construction_count(int value);
+ inline int construction_count();
+ inline void deprecate();
+ inline bool is_deprecated();
+ inline bool CanBeDeprecated();
+ // Returns a non-deprecated version of the input. If the input was not
+ // deprecated, it is directly returned. Otherwise, the non-deprecated version
+ // is found by re-transitioning from the root of the transition tree using the
+ // descriptor array of the map. Returns NULL if no updated map is found.
+ // This method also applies any pending migrations along the prototype chain.
+ static MaybeHandle<Map> TryUpdate(Handle<Map> map) WARN_UNUSED_RESULT;
+ // Same as above, but does not touch the prototype chain.
+ static MaybeHandle<Map> TryUpdateInternal(Handle<Map> map)
+ WARN_UNUSED_RESULT;
+
+ // Returns a non-deprecated version of the input. This method may deprecate
+ // existing maps along the way if encodings conflict. Not for use while
+ // gathering type feedback. Use TryUpdate in those cases instead.
+ static Handle<Map> Update(Handle<Map> map);
+
+ static Handle<Map> CopyDropDescriptors(Handle<Map> map);
+ static Handle<Map> CopyInsertDescriptor(Handle<Map> map,
+ Descriptor* descriptor,
+ TransitionFlag flag);
+
+ MUST_USE_RESULT static MaybeHandle<Map> CopyWithField(
+ Handle<Map> map,
+ Handle<Name> name,
+ Handle<HeapType> type,
+ PropertyAttributes attributes,
+ Representation representation,
+ TransitionFlag flag);
+
+ MUST_USE_RESULT static MaybeHandle<Map> CopyWithConstant(
+ Handle<Map> map,
+ Handle<Name> name,
+ Handle<Object> constant,
+ PropertyAttributes attributes,
+ TransitionFlag flag);
+
+ // Returns a new map with all transitions dropped from the given map and
+ // the ElementsKind set.
+ static Handle<Map> TransitionElementsTo(Handle<Map> map,
+ ElementsKind to_kind);
+
+ static Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind kind);
+
+ static Handle<Map> CopyAsElementsKind(Handle<Map> map,
+ ElementsKind kind,
+ TransitionFlag flag);
+
+ static Handle<Map> CopyForObserved(Handle<Map> map);
+
+ static Handle<Map> CopyForFreeze(Handle<Map> map);
+ // Maximal number of fast properties. Used to restrict the number of map
+ // transitions to avoid an explosion in the number of maps for objects used as
+ // dictionaries.
+ inline bool TooManyFastProperties(StoreFromKeyed store_mode);
+ static Handle<Map> TransitionToDataProperty(Handle<Map> map,
+ Handle<Name> name,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+ StoreFromKeyed store_mode);
+ static Handle<Map> TransitionToAccessorProperty(
+ Handle<Map> map, Handle<Name> name, AccessorComponent component,
+ Handle<Object> accessor, PropertyAttributes attributes);
+ static Handle<Map> ReconfigureDataProperty(Handle<Map> map, int descriptor,
+ PropertyAttributes attributes);
+
+ inline void AppendDescriptor(Descriptor* desc);
// Returns a copy of the map, with all transitions dropped from the
// instance descriptors.
- MUST_USE_RESULT MaybeObject* CopyDropTransitions();
-
- // Returns the property index for name (only valid for FAST MODE).
- int PropertyIndexFor(String* name);
+ static Handle<Map> Copy(Handle<Map> map);
+ static Handle<Map> Create(Isolate* isolate, int inobject_properties);
// Returns the next free property index (only valid for FAST MODE).
int NextFreePropertyIndex();
// Returns the number of properties described in instance_descriptors
// filtering out properties with the specified attributes.
- int NumberOfDescribedProperties(PropertyAttributes filter = NONE);
+ int NumberOfDescribedProperties(DescriptorFlag which = OWN_DESCRIPTORS,
+ PropertyAttributes filter = NONE);
- // Casting.
- static inline Map* cast(Object* obj);
+ // Returns the number of slots allocated for the initial properties
+ // backing storage for instances of this map.
+ int InitialPropertiesLength() {
+ return pre_allocated_property_fields() + unused_property_fields() -
+ inobject_properties();
+ }
- // Locate an accessor in the instance descriptor.
- AccessorDescriptor* FindAccessor(String* name);
+ DECLARE_CAST(Map)
// Code cache operations.
@@ -4776,84 +6074,90 @@
// 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);
+
+ // Extend the descriptor array of the map with the list of descriptors.
+ // In case of duplicates, the latest descriptor is used.
+ static void AppendCallbackDescriptors(Handle<Map> map,
+ Handle<Object> descriptors);
+
+ static void EnsureDescriptorSlack(Handle<Map> map, int slack);
// Returns the found code or undefined if absent.
- Object* FindInCodeCache(String* name, Code::Flags flags);
+ 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);
- // For every transition in this map, makes the transition's
- // target's prototype pointer point back to this map.
- // This is undone in MarkCompactCollector::ClearNonLiveTransitions().
- void CreateBackPointers();
-
- void CreateOneBackPointer(Object* transition_target);
-
- // Set all map transitions from this map to dead maps to null.
- // Also, restore the original prototype on the targets of these
- // transitions, so that we do not process this map again while
- // following back pointers.
- void ClearNonLiveTransitions(Heap* heap, Object* real_prototype);
-
- // Restore a possible back pointer in the prototype field of object.
- // Return true in that case and false otherwise. Set *keep_entry to
- // true when a live map transition has been found.
- bool RestoreOneBackPointer(Object* object,
- Object* real_prototype,
- bool* keep_entry);
+ // 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
+ // again while following back pointers.
+ void ClearNonLiveTransitions(Heap* heap);
// Computes a hash value for this map, to be used in HashTables and such.
int Hash();
- // Compares this map to another to see if they describe equivalent objects.
- // If |mode| is set to CLEAR_INOBJECT_PROPERTIES, |other| is treated as if
- // it had exactly zero inobject properties.
- // The "shared" flags of both this map and |other| are ignored.
- bool EquivalentToForNormalization(Map* other, PropertyNormalizationMode mode);
-
- // Returns the contents of this map's descriptor array for the given string.
- // May return NULL. |safe_to_add_transition| is set to false and NULL
- // is returned if adding transitions is not allowed.
- Object* GetDescriptorContents(String* sentinel_name,
- bool* safe_to_add_transitions);
-
// Returns the map that this map transitions to if its elements_kind
// is changed to |elements_kind|, or NULL if no such map is cached yet.
// |safe_to_add_transitions| is set to false if adding transitions is not
// allowed.
- Map* LookupElementsTransitionMap(ElementsKind elements_kind,
- bool* safe_to_add_transition);
-
- // Adds an entry to this map's descriptor array for a transition to
- // |transitioned_map| when its elements_kind is changed to |elements_kind|.
- MUST_USE_RESULT MaybeObject* AddElementsTransition(
- ElementsKind elements_kind, Map* transitioned_map);
+ Map* LookupElementsTransitionMap(ElementsKind elements_kind);
// Returns the transitioned map for this map with the most generic
// elements_kind that's found in |candidates|, or null handle if no match is
// found at all.
Handle<Map> FindTransitionedMap(MapHandleList* candidates);
- Map* FindTransitionedMap(MapList* candidates);
+ 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;
+ }
+
+ bool IsJSObjectMap() {
+ return instance_type() >= FIRST_JS_OBJECT_TYPE;
+ }
+ bool IsJSProxyMap() {
+ InstanceType type = instance_type();
+ return FIRST_JS_PROXY_TYPE <= type && type <= LAST_JS_PROXY_TYPE;
+ }
+ bool IsJSGlobalProxyMap() {
+ return instance_type() == JS_GLOBAL_PROXY_TYPE;
+ }
+ bool IsJSGlobalObjectMap() {
+ return instance_type() == JS_GLOBAL_OBJECT_TYPE;
+ }
+ bool IsGlobalObjectMap() {
+ const InstanceType type = instance_type();
+ return type == JS_GLOBAL_OBJECT_TYPE || type == JS_BUILTINS_OBJECT_TYPE;
+ }
+
+ inline bool CanOmitMapChecks();
+
+ static void AddDependentCompilationInfo(Handle<Map> map,
+ DependentCode::DependencyGroup group,
+ CompilationInfo* info);
+
+ static void AddDependentCode(Handle<Map> map,
+ DependentCode::DependencyGroup group,
+ Handle<Code> code);
+ static void AddDependentIC(Handle<Map> map,
+ Handle<Code> stub);
+
+ bool IsMapInArrayPrototypeChain();
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void MapPrint() {
- MapPrint(stdout);
- }
- void MapPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void MapVerify();
- void SharedMapVerify();
+ DECLARE_PRINTER(Map)
+ DECLARE_VERIFIER(Map)
+
+#ifdef VERIFY_HEAP
+ void DictionaryMapVerify();
+ void VerifyOmittedMapChecks();
#endif
inline int visitor_id();
@@ -4863,43 +6167,41 @@
void TraverseTransitionTree(TraverseCallback callback, void* data);
+ // When you set the prototype of an object using the __proto__ accessor you
+ // need a new map for the object (the prototype is stored in the map). In
+ // order not to multiply maps unnecessarily we store these as transitions in
+ // the original map. That way we can transition to the same map if the same
+ // prototype is set, rather than creating a new map every time. The
+ // transitions are in the form of a map where the keys are prototype objects
+ // and the values are the maps the are transitioned to.
static const int kMaxCachedPrototypeTransitions = 256;
-
- Object* GetPrototypeTransition(Object* prototype);
-
- MUST_USE_RESULT MaybeObject* PutPrototypeTransition(Object* prototype,
- Map* map);
+ static Handle<Map> TransitionToPrototype(Handle<Map> map,
+ Handle<Object> prototype);
static const int kMaxPreAllocatedPropertyFields = 255;
// Layout description.
static const int kInstanceSizesOffset = HeapObject::kHeaderSize;
static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize;
- static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize;
+ static const int kBitField3Offset = kInstanceAttributesOffset + kIntSize;
+ static const int kPrototypeOffset = kBitField3Offset + kPointerSize;
static const int kConstructorOffset = kPrototypeOffset + kPointerSize;
- // Storage for instance descriptors is overloaded to also contain additional
- // map flags when unused (bit_field3). When the map has instance descriptors,
- // the flags are transferred to the instance descriptor array and accessed
- // through an extra indirection.
- // TODO(1399): It should be possible to make room for bit_field3 in the map
- // without overloading the instance descriptors field, but the map is
- // currently perfectly aligned to 32 bytes and extending it at all would
- // double its size. After the increment GC work lands, this size restriction
- // could be loosened and bit_field3 moved directly back in the map.
- static const int kInstanceDescriptorsOrBitField3Offset =
+ // Storage for the transition array is overloaded to directly contain a back
+ // pointer if unused. When the map has transitions, the back pointer is
+ // transferred to the transition array and accessed through an extra
+ // indirection.
+ static const int kTransitionsOrBackPointerOffset =
kConstructorOffset + kPointerSize;
- static const int kCodeCacheOffset =
- kInstanceDescriptorsOrBitField3Offset + kPointerSize;
- static const int kPrototypeTransitionsOffset =
- kCodeCacheOffset + kPointerSize;
- static const int kPadStart = kPrototypeTransitionsOffset + kPointerSize;
- static const int kSize = MAP_POINTER_ALIGN(kPadStart);
+ static const int kDescriptorsOffset =
+ kTransitionsOrBackPointerOffset + kPointerSize;
+ static const int kCodeCacheOffset = kDescriptorsOffset + kPointerSize;
+ static const int kDependentCodeOffset = kCodeCacheOffset + kPointerSize;
+ static const int kSize = kDependentCodeOffset + kPointerSize;
// Layout of pointer fields. Heap iteration code relies on them
// being continuously allocated.
static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset;
- static const int kPointerFieldsEndOffset =
- Map::kPrototypeTransitionsOffset + kPointerSize;
+ static const int kPointerFieldsEndOffset = kSize;
// Byte offsets within kInstanceSizesOffset.
static const int kInstanceSizeOffset = kInstanceSizesOffset + 0;
@@ -4913,56 +6215,144 @@
static const int kVisitorIdOffset = kInstanceSizesOffset + kVisitorIdByte;
// Byte offsets within kInstanceAttributesOffset attributes.
+#if V8_TARGET_LITTLE_ENDIAN
+ // Order instance type and bit field together such that they can be loaded
+ // together as a 16-bit word with instance type in the lower 8 bits regardless
+ // of endianess. Also provide endian-independent offset to that 16-bit word.
static const int kInstanceTypeOffset = kInstanceAttributesOffset + 0;
- static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1;
- static const int kBitFieldOffset = kInstanceAttributesOffset + 2;
- static const int kBitField2Offset = kInstanceAttributesOffset + 3;
+ static const int kBitFieldOffset = kInstanceAttributesOffset + 1;
+#else
+ static const int kBitFieldOffset = kInstanceAttributesOffset + 0;
+ static const int kInstanceTypeOffset = kInstanceAttributesOffset + 1;
+#endif
+ static const int kInstanceTypeAndBitFieldOffset =
+ kInstanceAttributesOffset + 0;
+ static const int kBitField2Offset = kInstanceAttributesOffset + 2;
+ static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 3;
- STATIC_CHECK(kInstanceTypeOffset == Internals::kMapInstanceTypeOffset);
+ STATIC_ASSERT(kInstanceTypeAndBitFieldOffset ==
+ Internals::kMapInstanceTypeAndBitFieldOffset);
// Bit positions for bit field.
- static const int kUnused = 0; // To be used for marking recently used maps.
- static const int kHasNonInstancePrototype = 1;
- static const int kIsHiddenPrototype = 2;
- static const int kHasNamedInterceptor = 3;
- static const int kHasIndexedInterceptor = 4;
- static const int kIsUndetectable = 5;
- static const int kHasInstanceCallHandler = 6;
- static const int kIsAccessCheckNeeded = 7;
+ static const int kHasNonInstancePrototype = 0;
+ static const int kIsHiddenPrototype = 1;
+ static const int kHasNamedInterceptor = 2;
+ static const int kHasIndexedInterceptor = 3;
+ static const int kIsUndetectable = 4;
+ static const int kIsObserved = 5;
+ static const int kIsAccessCheckNeeded = 6;
+ class FunctionWithPrototype: public BitField<bool, 7, 1> {};
// Bit positions for bit field 2
static const int kIsExtensible = 0;
- static const int kFunctionWithPrototype = 1;
- static const int kStringWrapperSafeForDefaultValueOf = 2;
- static const int kAttachedToSharedFunctionInfo = 3;
- // No bits can be used after kElementsKindFirstBit, they are all reserved for
- // storing ElementKind.
- static const int kElementsKindShift = 4;
- static const int kElementsKindBitCount = 4;
+ static const int kStringWrapperSafeForDefaultValueOf = 1;
+ class IsPrototypeMapBits : public BitField<bool, 2, 1> {};
+ class ElementsKindBits: public BitField<ElementsKind, 3, 5> {};
// Derived values from bit field 2
- static const int kElementsKindMask = (-1 << kElementsKindShift) &
- ((1 << (kElementsKindShift + kElementsKindBitCount)) - 1);
static const int8_t kMaximumBitField2FastElementValue = static_cast<int8_t>(
- (FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1;
- static const int8_t kMaximumBitField2FastSmiOnlyElementValue =
- static_cast<int8_t>((FAST_SMI_ONLY_ELEMENTS + 1) <<
- Map::kElementsKindShift) - 1;
-
- // Bit positions for bit field 3
- static const int kIsShared = 0;
-
- // Layout of the default cache. It holds alternating name and code objects.
- static const int kCodeCacheEntrySize = 2;
- static const int kCodeCacheEntryNameOffset = 0;
- static const int kCodeCacheEntryCodeOffset = 1;
+ (FAST_ELEMENTS + 1) << Map::ElementsKindBits::kShift) - 1;
+ static const int8_t kMaximumBitField2FastSmiElementValue =
+ static_cast<int8_t>((FAST_SMI_ELEMENTS + 1) <<
+ Map::ElementsKindBits::kShift) - 1;
+ static const int8_t kMaximumBitField2FastHoleyElementValue =
+ static_cast<int8_t>((FAST_HOLEY_ELEMENTS + 1) <<
+ Map::ElementsKindBits::kShift) - 1;
+ static const int8_t kMaximumBitField2FastHoleySmiElementValue =
+ static_cast<int8_t>((FAST_HOLEY_SMI_ELEMENTS + 1) <<
+ Map::ElementsKindBits::kShift) - 1;
typedef FixedBodyDescriptor<kPointerFieldsBeginOffset,
kPointerFieldsEndOffset,
kSize> BodyDescriptor;
+ // Compares this map to another to see if they describe equivalent objects.
+ // If |mode| is set to CLEAR_INOBJECT_PROPERTIES, |other| is treated as if
+ // it had exactly zero inobject properties.
+ // The "shared" flags of both this map and |other| are ignored.
+ bool EquivalentToForNormalization(Map* other, PropertyNormalizationMode mode);
+
private:
- String* elements_transition_sentinel_name();
+ static void ConnectElementsTransition(Handle<Map> parent, Handle<Map> child);
+ static void ConnectTransition(Handle<Map> parent, Handle<Map> child,
+ Handle<Name> name, SimpleTransitionFlag flag);
+
+ bool EquivalentToForTransition(Map* other);
+ static Handle<Map> RawCopy(Handle<Map> map, int instance_size);
+ static Handle<Map> ShareDescriptor(Handle<Map> map,
+ Handle<DescriptorArray> descriptors,
+ Descriptor* descriptor);
+ static Handle<Map> CopyInstallDescriptors(
+ Handle<Map> map,
+ int new_descriptor,
+ Handle<DescriptorArray> descriptors);
+ static Handle<Map> CopyAddDescriptor(Handle<Map> map,
+ Descriptor* descriptor,
+ TransitionFlag flag);
+ static Handle<Map> CopyReplaceDescriptors(
+ Handle<Map> map,
+ Handle<DescriptorArray> descriptors,
+ TransitionFlag flag,
+ MaybeHandle<Name> maybe_name,
+ SimpleTransitionFlag simple_flag = FULL_TRANSITION);
+ static Handle<Map> CopyReplaceDescriptor(Handle<Map> map,
+ Handle<DescriptorArray> descriptors,
+ Descriptor* descriptor,
+ int index,
+ TransitionFlag flag);
+
+ static Handle<Map> CopyNormalized(Handle<Map> map,
+ PropertyNormalizationMode mode);
+
+ // 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();
+
+ static Handle<Map> TransitionElementsToSlow(Handle<Map> object,
+ ElementsKind to_kind);
+
+ // Zaps the contents of backing data structures. Note that the
+ // heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects
+ // holding weak references when incremental marking is used, because it also
+ // iterates over objects that are otherwise unreachable.
+ // In general we only want to call these functions in release mode when
+ // heap verification is turned on.
+ void ZapPrototypeTransitions();
+ void ZapTransitions();
+
+ void DeprecateTransitionTree();
+ void DeprecateTarget(Name* key, DescriptorArray* new_descriptors);
+
+ Map* FindLastMatchMap(int verbatim, int length, DescriptorArray* descriptors);
+
+ void UpdateFieldType(int descriptor_number, Handle<Name> name,
+ Handle<HeapType> new_type);
+
+ void PrintGeneralization(FILE* file,
+ const char* reason,
+ int modify_index,
+ int split,
+ int descriptors,
+ bool constant_to_field,
+ Representation old_representation,
+ Representation new_representation,
+ HeapType* old_field_type,
+ HeapType* new_field_type);
+
+ static inline void SetPrototypeTransitions(
+ Handle<Map> map,
+ Handle<FixedArray> prototype_transitions);
+
+ static Handle<Map> GetPrototypeTransition(Handle<Map> map,
+ Handle<Object> prototype);
+ static Handle<Map> PutPrototypeTransition(Handle<Map> map,
+ Handle<Object> prototype,
+ Handle<Map> target_map);
+
+ static const int kFastPropertiesSoftLimit = 12;
+ static const int kMaxFastProperties = 128;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
};
@@ -4973,7 +6363,27 @@
class Struct: public HeapObject {
public:
inline void InitializeBody(int object_size);
- static inline Struct* cast(Object* that);
+ DECLARE_CAST(Struct)
+};
+
+
+// A simple one-element struct, useful where smis need to be boxed.
+class Box : public Struct {
+ public:
+ // [value]: the boxed contents.
+ DECL_ACCESSORS(value, Object)
+
+ DECLARE_CAST(Box)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(Box)
+ DECLARE_VERIFIER(Box)
+
+ static const int kValueOffset = HeapObject::kHeaderSize;
+ static const int kSize = kValueOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Box);
};
@@ -5006,7 +6416,7 @@
DECL_ACCESSORS(name, Object)
// [id]: the script id.
- DECL_ACCESSORS(id, Object)
+ DECL_ACCESSORS(id, Smi)
// [line_offset]: script line offset in resource from where it was extracted.
DECL_ACCESSORS(line_offset, Smi)
@@ -5015,9 +6425,6 @@
// extracted.
DECL_ACCESSORS(column_offset, Smi)
- // [data]: additional data associated with this script.
- DECL_ACCESSORS(data, Object)
-
// [context_data]: context data for the context this script was compiled in.
DECL_ACCESSORS(context_data, Object)
@@ -5027,12 +6434,6 @@
// [type]: the script type.
DECL_ACCESSORS(type, Smi)
- // [compilation]: how the the script was compiled.
- DECL_ACCESSORS(compilation_type, Smi)
-
- // [is_compiled]: determines whether the script has already been compiled.
- DECL_ACCESSORS(compilation_state, Smi)
-
// [line_ends]: FixedArray of line ends positions.
DECL_ACCESSORS(line_ends, Object)
@@ -5044,41 +6445,84 @@
// function from which eval was called where eval was called.
DECL_ACCESSORS(eval_from_instructions_offset, Smi)
- static inline Script* cast(Object* obj);
+ // [flags]: Holds an exciting bitfield.
+ DECL_ACCESSORS(flags, Smi)
+
+ // [source_url]: sourceURL from magic comment
+ DECL_ACCESSORS(source_url, Object)
+
+ // [source_url]: sourceMappingURL magic comment
+ DECL_ACCESSORS(source_mapping_url, Object)
+
+ // [compilation_type]: how the the script was compiled. Encoded in the
+ // 'flags' field.
+ inline CompilationType compilation_type();
+ inline void set_compilation_type(CompilationType type);
+
+ // [compilation_state]: determines whether the script has already been
+ // compiled. Encoded in the 'flags' field.
+ inline CompilationState compilation_state();
+ inline void set_compilation_state(CompilationState state);
+
+ // [is_shared_cross_origin]: An opaque boolean set by the embedder via
+ // ScriptOrigin, and used by the embedder to make decisions about the
+ // script's level of privilege. V8 just passes this through. Encoded in
+ // the 'flags' field.
+ DECL_BOOLEAN_ACCESSORS(is_shared_cross_origin)
+
+ DECLARE_CAST(Script)
// If script source is an external string, check that the underlying
// resource is accessible. Otherwise, always return true.
inline bool HasValidSource();
-#ifdef OBJECT_PRINT
- inline void ScriptPrint() {
- ScriptPrint(stdout);
- }
- void ScriptPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ScriptVerify();
-#endif
+ // Convert code position into column number.
+ static int GetColumnNumber(Handle<Script> script, int code_pos);
+
+ // Convert code position into (zero-based) line number.
+ // The non-handlified version does not allocate, but may be much slower.
+ static int GetLineNumber(Handle<Script> script, int code_pos);
+ int GetLineNumber(int code_pos);
+
+ static Handle<Object> GetNameOrSourceURL(Handle<Script> script);
+
+ // Init line_ends array with code positions of line ends inside script source.
+ static void InitLineEnds(Handle<Script> script);
+
+ // Get the JS object wrapping the given script; create it if none exists.
+ static Handle<JSObject> GetWrapper(Handle<Script> script);
+ void ClearWrapperCache();
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(Script)
+ DECLARE_VERIFIER(Script)
static const int kSourceOffset = HeapObject::kHeaderSize;
static const int kNameOffset = kSourceOffset + kPointerSize;
static const int kLineOffsetOffset = kNameOffset + kPointerSize;
static const int kColumnOffsetOffset = kLineOffsetOffset + kPointerSize;
- static const int kDataOffset = kColumnOffsetOffset + kPointerSize;
- static const int kContextOffset = kDataOffset + kPointerSize;
+ static const int kContextOffset = kColumnOffsetOffset + kPointerSize;
static const int kWrapperOffset = kContextOffset + kPointerSize;
static const int kTypeOffset = kWrapperOffset + kPointerSize;
- static const int kCompilationTypeOffset = kTypeOffset + kPointerSize;
- static const int kCompilationStateOffset =
- kCompilationTypeOffset + kPointerSize;
- static const int kLineEndsOffset = kCompilationStateOffset + kPointerSize;
+ static const int kLineEndsOffset = kTypeOffset + kPointerSize;
static const int kIdOffset = kLineEndsOffset + kPointerSize;
static const int kEvalFromSharedOffset = kIdOffset + kPointerSize;
static const int kEvalFrominstructionsOffsetOffset =
kEvalFromSharedOffset + kPointerSize;
- static const int kSize = kEvalFrominstructionsOffsetOffset + kPointerSize;
+ static const int kFlagsOffset =
+ kEvalFrominstructionsOffsetOffset + kPointerSize;
+ static const int kSourceUrlOffset = kFlagsOffset + kPointerSize;
+ static const int kSourceMappingUrlOffset = kSourceUrlOffset + kPointerSize;
+ static const int kSize = kSourceMappingUrlOffset + kPointerSize;
private:
+ int GetLineNumberWithArray(int code_pos);
+
+ // Bit positions in the flags field.
+ static const int kCompilationTypeBit = 0;
+ static const int kCompilationStateBit = 1;
+ static const int kIsSharedCrossOriginBit = 2;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(Script);
};
@@ -5092,12 +6536,12 @@
//
// Installation of ids for the selected builtin functions is handled
// by the bootstrapper.
-//
-// NOTE: Order is important: math functions should be at the end of
-// the list and MathFloor should be the first math function.
#define FUNCTIONS_WITH_ID_LIST(V) \
+ V(Array.prototype, indexOf, ArrayIndexOf) \
+ V(Array.prototype, lastIndexOf, ArrayLastIndexOf) \
V(Array.prototype, push, ArrayPush) \
V(Array.prototype, pop, ArrayPop) \
+ V(Array.prototype, shift, ArrayShift) \
V(Function.prototype, apply, FunctionApply) \
V(String.prototype, charCodeAt, StringCharCodeAt) \
V(String.prototype, charAt, StringCharAt) \
@@ -5107,29 +6551,24 @@
V(Math, ceil, MathCeil) \
V(Math, abs, MathAbs) \
V(Math, log, MathLog) \
- V(Math, sin, MathSin) \
- V(Math, cos, MathCos) \
- V(Math, tan, MathTan) \
- V(Math, asin, MathASin) \
- V(Math, acos, MathACos) \
- V(Math, atan, MathATan) \
V(Math, exp, MathExp) \
V(Math, sqrt, MathSqrt) \
V(Math, pow, MathPow) \
- V(Math, random, MathRandom) \
V(Math, max, MathMax) \
- V(Math, min, MathMin)
-
+ V(Math, min, MathMin) \
+ V(Math, imul, MathImul) \
+ V(Math, clz32, MathClz32) \
+ V(Math, fround, MathFround)
enum BuiltinFunctionId {
+ kArrayCode,
#define DECLARE_FUNCTION_ID(ignored1, ignore2, name) \
k##name,
FUNCTIONS_WITH_ID_LIST(DECLARE_FUNCTION_ID)
#undef DECLARE_FUNCTION_ID
// Fake id for a special case of Math.pow. Note, it continues the
// list of math functions.
- kMathPowHalf,
- kFirstMathFunctionId = kMathFloor
+ kMathPowHalf
};
@@ -5142,6 +6581,50 @@
// [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.
+ DECL_ACCESSORS(optimized_code_map, Object)
+
+ // Returns index i of the entry with the specified context and OSR entry.
+ // At position i - 1 is the context, position i the code, and i + 1 the
+ // literals array. Returns -1 when no matching entry is found.
+ int SearchOptimizedCodeMap(Context* native_context, BailoutId osr_ast_id);
+
+ // Installs optimized code from the code map on the given closure. The
+ // index has to be consistent with a search result as defined above.
+ FixedArray* GetLiteralsFromOptimizedCodeMap(int index);
+
+ Code* GetCodeFromOptimizedCodeMap(int index);
+
+ // Clear optimized code map.
+ void ClearOptimizedCodeMap();
+
+ // Removed a specific optimized code object from the optimized code map.
+ void EvictFromOptimizedCodeMap(Code* optimized_code, const char* reason);
+
+ void ClearTypeFeedbackInfo();
+
+ // Trims the optimized code map after entries have been removed.
+ void TrimOptimizedCodeMap(int shrink_by);
+
+ // Add a new entry to the optimized code map.
+ static void AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared,
+ Handle<Context> native_context,
+ Handle<Code> code,
+ Handle<FixedArray> literals,
+ BailoutId osr_ast_id);
+
+ // Layout description of the optimized code map.
+ static const int kNextMapIndex = 0;
+ static const int kEntriesStart = 1;
+ static const int kContextOffset = 0;
+ static const int kCachedCodeOffset = 1;
+ static const int kLiteralsOffset = 2;
+ static const int kOsrAstIdOffset = 3;
+ static const int kEntryLength = 4;
+ static const int kInitialLength = kEntriesStart + kEntryLength;
// [scope_info]: Scope info.
DECL_ACCESSORS(scope_info, ScopeInfo)
@@ -5149,18 +6632,16 @@
// [construct stub]: Code stub for constructing instances of this function.
DECL_ACCESSORS(construct_stub, Code)
- inline Code* unchecked_code();
-
// Returns if this function has been compiled to native code yet.
inline bool is_compiled();
// [length]: The function length - usually the number of declared parameters.
// Use up to 2^30 parameters.
- inline int length();
+ inline int length() const;
inline void set_length(int value);
// [formal parameter count]: The declared number of parameters.
- inline int formal_parameter_count();
+ inline int formal_parameter_count() const;
inline void set_formal_parameter_count(int value);
// Set the formal parameter count so the function code will be
@@ -5168,100 +6649,13 @@
inline void DontAdaptArguments();
// [expected_nof_properties]: Expected number of properties for the function.
- inline int expected_nof_properties();
+ inline int expected_nof_properties() const;
inline void set_expected_nof_properties(int value);
- // Inobject slack tracking is the way to reclaim unused inobject space.
- //
- // The instance size is initially determined by adding some slack to
- // expected_nof_properties (to allow for a few extra properties added
- // after the constructor). There is no guarantee that the extra space
- // will not be wasted.
- //
- // Here is the algorithm to reclaim the unused inobject space:
- // - Detect the first constructor call for this SharedFunctionInfo.
- // When it happens enter the "in progress" state: remember the
- // constructor's initial_map and install a special construct stub that
- // counts constructor calls.
- // - While the tracking is in progress create objects filled with
- // one_pointer_filler_map instead of undefined_value. This way they can be
- // resized quickly and safely.
- // - Once enough (kGenerousAllocationCount) objects have been created
- // compute the 'slack' (traverse the map transition tree starting from the
- // initial_map and find the lowest value of unused_property_fields).
- // - Traverse the transition tree again and decrease the instance size
- // of every map. Existing objects will resize automatically (they are
- // filled with one_pointer_filler_map). All further allocations will
- // use the adjusted instance size.
- // - Decrease expected_nof_properties so that an allocations made from
- // another context will use the adjusted instance size too.
- // - Exit "in progress" state by clearing the reference to the initial_map
- // and setting the regular construct stub (generic or inline).
- //
- // The above is the main event sequence. Some special cases are possible
- // while the tracking is in progress:
- //
- // - GC occurs.
- // Check if the initial_map is referenced by any live objects (except this
- // SharedFunctionInfo). If it is, continue tracking as usual.
- // If it is not, clear the reference and reset the tracking state. The
- // tracking will be initiated again on the next constructor call.
- //
- // - The constructor is called from another context.
- // Immediately complete the tracking, perform all the necessary changes
- // to maps. This is necessary because there is no efficient way to track
- // multiple initial_maps.
- // Proceed to create an object in the current context (with the adjusted
- // size).
- //
- // - A different constructor function sharing the same SharedFunctionInfo is
- // called in the same context. This could be another closure in the same
- // context, or the first function could have been disposed.
- // This is handled the same way as the previous case.
- //
- // Important: inobject slack tracking is not attempted during the snapshot
- // creation.
-
- static const int kGenerousAllocationCount = 8;
-
- // [construction_count]: Counter for constructor calls made during
- // the tracking phase.
- inline int construction_count();
- inline void set_construction_count(int value);
-
- // [initial_map]: initial map of the first function called as a constructor.
- // Saved for the duration of the tracking phase.
- // This is a weak link (GC resets it to undefined_value if no other live
- // object reference this map).
- DECL_ACCESSORS(initial_map, Object)
-
- // True if the initial_map is not undefined and the countdown stub is
- // installed.
- inline bool IsInobjectSlackTrackingInProgress();
-
- // Starts the tracking.
- // Stores the initial map and installs the countdown stub.
- // IsInobjectSlackTrackingInProgress is normally true after this call,
- // except when tracking have not been started (e.g. the map has no unused
- // properties or the snapshot is being built).
- void StartInobjectSlackTracking(Map* map);
-
- // Completes the tracking.
- // IsInobjectSlackTrackingInProgress is false after this call.
- void CompleteInobjectSlackTracking();
-
- // Clears the initial_map before the GC marking phase to ensure the reference
- // is weak. IsInobjectSlackTrackingInProgress is false after this call.
- void DetachInitialMap();
-
- // Restores the link to the initial map after the GC marking phase.
- // IsInobjectSlackTrackingInProgress is true after this call.
- void AttachInitialMap(Map* map);
-
- // False if there are definitely no live objects created from this function.
- // True if live objects _may_ exist (existence not guaranteed).
- // May go back from true to false after GC.
- DECL_BOOLEAN_ACCESSORS(live_objects_may_exist)
+ // [feedback_vector] - accumulates ast node feedback from full-codegen and
+ // (increasingly) from crankshafted code where sufficient feedback isn't
+ // available.
+ DECL_ACCESSORS(feedback_vector, TypeFeedbackVector)
// [instance class name]: class name for instances.
DECL_ACCESSORS(instance_class_name, Object)
@@ -5283,7 +6677,7 @@
DECL_ACCESSORS(script, Object)
// [num_literals]: Number of literals used by this function.
- inline int num_literals();
+ inline int num_literals() const;
inline void set_num_literals(int value);
// [start_position_and_type]: Field used to store both the source code
@@ -5291,7 +6685,7 @@
// and whether or not the function is a toplevel function. The two
// least significants bit indicates whether the function is an
// expression and the rest contains the source code position.
- inline int start_position_and_type();
+ inline int start_position_and_type() const;
inline void set_start_position_and_type(int value);
// [debug info]: Debug information.
@@ -5308,15 +6702,15 @@
String* DebugName();
// Position of the 'function' token in the script source.
- inline int function_token_position();
+ inline int function_token_position() const;
inline void set_function_token_position(int function_token_position);
// Position of this function in the script source.
- inline int start_position();
+ inline int start_position() const;
inline void set_start_position(int start_position);
// End position of this function in the script source.
- inline int end_position();
+ inline int end_position() const;
inline void set_end_position(int end_position);
// Is this function a function expression in the source code.
@@ -5327,46 +6721,30 @@
// Bit field containing various information collected by the compiler to
// drive optimization.
- inline int compiler_hints();
+ inline int compiler_hints() const;
inline void set_compiler_hints(int value);
- inline int ast_node_count();
+ inline int ast_node_count() const;
inline void set_ast_node_count(int count);
- // A counter used to determine when to stress the deoptimizer with a
- // deopt.
- inline int deopt_counter();
- inline void set_deopt_counter(int counter);
+ inline int profiler_ticks() const;
+ inline void set_profiler_ticks(int ticks);
// Inline cache age is used to infer whether the function survived a context
// disposal or not. In the former case we reset the opt_count.
inline int ic_age();
inline void set_ic_age(int age);
- // Add information on assignments of the form this.x = ...;
- void SetThisPropertyAssignmentsInfo(
- bool has_only_simple_this_property_assignments,
- FixedArray* this_property_assignments);
-
- // Clear information on assignments of the form this.x = ...;
- void ClearThisPropertyAssignmentsInfo();
-
- // Indicate that this function only consists of assignments of the form
- // this.x = y; where y is either a constant or refers to an argument.
- inline bool has_only_simple_this_property_assignments();
-
// Indicates if this function can be lazy compiled.
// This is used to determine if we can safely flush code from a function
// when doing GC if we expect that the function will no longer be used.
DECL_BOOLEAN_ACCESSORS(allows_lazy_compilation)
- // Indicates how many full GCs this function has survived with assigned
- // code object. Used to determine when it is relatively safe to flush
- // this code object and replace it with lazy compilation stub.
- // Age is reset when GC notices that the code object is referenced
- // from the stack or compilation cache.
- inline int code_age();
- inline void set_code_age(int age);
+ // Indicates if this function can be lazy compiled without a context.
+ // This is used to determine if we can force compilation without reaching
+ // the function through program execution but through other means (e.g. heap
+ // iteration by the debugger).
+ DECL_BOOLEAN_ACCESSORS(allows_lazy_compilation_without_context)
// Indicates whether optimizations have been disabled for this
// shared function info. If a function is repeatedly optimized or if
@@ -5374,20 +6752,9 @@
// spending time attempting to optimize it again.
DECL_BOOLEAN_ACCESSORS(optimization_disabled)
- // Indicates the language mode of the function's code as defined by the
- // current harmony drafts for the next ES language standard. Possible
- // values are:
- // 1. CLASSIC_MODE - Unrestricted syntax and semantics, same as in ES5.
- // 2. STRICT_MODE - Restricted syntax and semantics, same as in ES5.
- // 3. EXTENDED_MODE - Only available under the harmony flag, not part of ES5.
- inline LanguageMode language_mode();
- inline void set_language_mode(LanguageMode language_mode);
-
- // Indicates whether the language mode of this function is CLASSIC_MODE.
- inline bool is_classic_mode();
-
- // Indicates whether the language mode of this function is EXTENDED_MODE.
- inline bool is_extended_mode();
+ // Indicates the language mode.
+ inline StrictMode strict_mode();
+ inline void set_strict_mode(StrictMode strict_mode);
// False if the function definitely does not allocate an arguments object.
DECL_BOOLEAN_ACCESSORS(uses_arguments)
@@ -5401,6 +6768,9 @@
// global object.
DECL_BOOLEAN_ACCESSORS(native)
+ // Indicate that this builtin needs to be inlined in crankshaft.
+ DECL_BOOLEAN_ACCESSORS(inline_builtin)
+
// Indicates that the function was created by the Function function.
// Though it's anonymous, toString should treat it as if it had the name
// "anonymous". We don't set the name itself so that the system does not
@@ -5418,11 +6788,26 @@
// Is this a function or top-level/eval code.
DECL_BOOLEAN_ACCESSORS(is_function)
- // Indicates that the function cannot be optimized.
- DECL_BOOLEAN_ACCESSORS(dont_optimize)
+ // Indicates that code for this function cannot be cached.
+ DECL_BOOLEAN_ACCESSORS(dont_cache)
- // Indicates that the function cannot be inlined.
- DECL_BOOLEAN_ACCESSORS(dont_inline)
+ // Indicates that code for this function cannot be flushed.
+ DECL_BOOLEAN_ACCESSORS(dont_flush)
+
+ // Indicates that this function is a generator.
+ DECL_BOOLEAN_ACCESSORS(is_generator)
+
+ // Indicates that this function is an arrow function.
+ DECL_BOOLEAN_ACCESSORS(is_arrow)
+
+ // Indicates that this function is a concise method.
+ DECL_BOOLEAN_ACCESSORS(is_concise_method)
+
+ // Indicates that this function is an asm function.
+ DECL_BOOLEAN_ACCESSORS(asm_function)
+
+ inline FunctionKind kind();
+ inline void set_kind(FunctionKind kind);
// Indicates whether or not the code in the shared function support
// deoptimization.
@@ -5433,38 +6818,52 @@
// Disable (further) attempted optimization of all functions sharing this
// shared function info.
- void DisableOptimization();
+ void DisableOptimization(BailoutReason reason);
- // Lookup the bailout ID and ASSERT that it exists in the non-optimized
+ inline BailoutReason DisableOptimizationReason();
+
+ // Lookup the bailout ID and DCHECK that it exists in the non-optimized
// code, returns whether it asserted (i.e., always true if assertions are
// disabled).
- bool VerifyBailoutId(int id);
-
- // Check whether a inlined constructor can be generated with the given
- // prototype.
- bool CanGenerateInlineConstructor(Object* prototype);
-
- // Prevents further attempts to generate inline constructors.
- // To be called if generation failed for any reason.
- void ForbidInlineConstructor();
-
- // For functions which only contains this property assignments this provides
- // access to the names for the properties assigned.
- DECL_ACCESSORS(this_property_assignments, Object)
- inline int this_property_assignments_count();
- inline void set_this_property_assignments_count(int value);
- String* GetThisPropertyAssignmentName(int index);
- bool IsThisPropertyAssignmentArgument(int index);
- int GetThisPropertyAssignmentArgument(int index);
- Object* GetThisPropertyAssignmentConstant(int index);
+ bool VerifyBailoutId(BailoutId id);
// [source code]: Source code for the function.
- bool HasSourceCode();
+ bool HasSourceCode() const;
Handle<Object> GetSourceCode();
+ // Number of times the function was optimized.
inline int opt_count();
inline void set_opt_count(int opt_count);
+ // Number of times the function was deoptimized.
+ inline void set_deopt_count(int value);
+ inline int deopt_count();
+ inline void increment_deopt_count();
+
+ // Number of time we tried to re-enable optimization after it
+ // was disabled due to high number of deoptimizations.
+ inline void set_opt_reenable_tries(int value);
+ inline int opt_reenable_tries();
+
+ inline void TryReenableOptimization();
+
+ // Stores deopt_count, opt_reenable_tries and ic_age as bit-fields.
+ inline void set_counters(int value);
+ inline int counters() const;
+
+ // Stores opt_count and bailout_reason as bit-fields.
+ inline void set_opt_count_and_bailout_reason(int value);
+ inline int opt_count_and_bailout_reason() const;
+
+ void set_bailout_reason(BailoutReason reason) {
+ set_opt_count_and_bailout_reason(
+ DisabledOptimizationReasonBits::update(opt_count_and_bailout_reason(),
+ reason));
+ }
+
+ // Check whether or not this function is inlineable.
+ bool IsInlineable();
+
// Source size of this function.
int SourceSize();
@@ -5475,31 +6874,12 @@
int CalculateInObjectProperties();
// 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
-#ifdef DEBUG
- void SharedFunctionInfoVerify();
-#endif
+ DECLARE_PRINTER(SharedFunctionInfo)
+ DECLARE_VERIFIER(SharedFunctionInfo)
void ResetForNewContext(int new_ic_age);
- // Helpers to compile the shared code. Returns true on success, false on
- // failure (e.g., stack overflow during compilation).
- static bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag);
- static bool CompileLazy(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag);
-
- void SharedFunctionInfoIterateBody(ObjectVisitor* v);
-
- // Casting.
- static inline SharedFunctionInfo* cast(Object* obj);
+ DECLARE_CAST(SharedFunctionInfo)
// Constants.
static const int kDontAdaptArgumentsSentinel = -1;
@@ -5508,7 +6888,8 @@
// Pointer fields.
static const int kNameOffset = HeapObject::kHeaderSize;
static const int kCodeOffset = kNameOffset + kPointerSize;
- static const int kScopeInfoOffset = kCodeOffset + kPointerSize;
+ static const int kOptimizedCodeMapOffset = kCodeOffset + kPointerSize;
+ static const int kScopeInfoOffset = kOptimizedCodeMapOffset + kPointerSize;
static const int kConstructStubOffset = kScopeInfoOffset + kPointerSize;
static const int kInstanceClassNameOffset =
kConstructStubOffset + kPointerSize;
@@ -5517,17 +6898,12 @@
static const int kScriptOffset = kFunctionDataOffset + kPointerSize;
static const int kDebugInfoOffset = kScriptOffset + kPointerSize;
static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
- static const int kInitialMapOffset =
+ static const int kFeedbackVectorOffset =
kInferredNameOffset + kPointerSize;
- static const int kThisPropertyAssignmentsOffset =
- kInitialMapOffset + kPointerSize;
- // ic_age is a Smi field. It could be grouped with another Smi field into a
- // PSEUDO_SMI_ACCESSORS pair (on x64), if one becomes available.
- static const int kICAgeOffset = kThisPropertyAssignmentsOffset + kPointerSize;
#if V8_HOST_ARCH_32_BIT
// Smi fields.
static const int kLengthOffset =
- kICAgeOffset + kPointerSize;
+ kFeedbackVectorOffset + kPointerSize;
static const int kFormalParameterCountOffset = kLengthOffset + kPointerSize;
static const int kExpectedNofPropertiesOffset =
kFormalParameterCountOffset + kPointerSize;
@@ -5541,16 +6917,17 @@
kEndPositionOffset + kPointerSize;
static const int kCompilerHintsOffset =
kFunctionTokenPositionOffset + kPointerSize;
- static const int kThisPropertyAssignmentsCountOffset =
+ static const int kOptCountAndBailoutReasonOffset =
kCompilerHintsOffset + kPointerSize;
- static const int kOptCountOffset =
- kThisPropertyAssignmentsCountOffset + kPointerSize;
- static const int kAstNodeCountOffset = kOptCountOffset + kPointerSize;
- static const int kDeoptCounterOffset = kAstNodeCountOffset + kPointerSize;
-
+ static const int kCountersOffset =
+ kOptCountAndBailoutReasonOffset + kPointerSize;
+ static const int kAstNodeCountOffset =
+ kCountersOffset + kPointerSize;
+ static const int kProfilerTicksOffset =
+ kAstNodeCountOffset + kPointerSize;
// Total size.
- static const int kSize = kDeoptCounterOffset + kPointerSize;
+ static const int kSize = kProfilerTicksOffset + kPointerSize;
#else
// The only reason to use smi fields instead of int fields
// is to allow iteration without maps decoding during
@@ -5562,7 +6939,7 @@
// word is not set and thus this word cannot be treated as pointer
// to HeapObject during old space traversal.
static const int kLengthOffset =
- kICAgeOffset + kPointerSize;
+ kFeedbackVectorOffset + kPointerSize;
static const int kFormalParameterCountOffset =
kLengthOffset + kIntSize;
@@ -5581,68 +6958,67 @@
static const int kCompilerHintsOffset =
kFunctionTokenPositionOffset + kIntSize;
- static const int kThisPropertyAssignmentsCountOffset =
+ static const int kOptCountAndBailoutReasonOffset =
kCompilerHintsOffset + kIntSize;
- static const int kOptCountOffset =
- kThisPropertyAssignmentsCountOffset + kIntSize;
+ static const int kCountersOffset =
+ kOptCountAndBailoutReasonOffset + kIntSize;
- static const int kAstNodeCountOffset = kOptCountOffset + kIntSize;
- static const int kDeoptCounterOffset = kAstNodeCountOffset + kIntSize;
+ static const int kAstNodeCountOffset =
+ kCountersOffset + kIntSize;
+ static const int kProfilerTicksOffset =
+ kAstNodeCountOffset + kIntSize;
// Total size.
- static const int kSize = kDeoptCounterOffset + kIntSize;
+ static const int kSize = kProfilerTicksOffset + kIntSize;
#endif
- // The construction counter for inobject slack tracking is stored in the
- // most significant byte of compiler_hints which is otherwise unused.
- // Its offset depends on the endian-ness of the architecture.
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- static const int kConstructionCountOffset = kCompilerHintsOffset + 3;
-#elif __BYTE_ORDER == __BIG_ENDIAN
- static const int kConstructionCountOffset = kCompilerHintsOffset + 0;
-#else
-#error Unknown byte ordering
-#endif
-
static const int kAlignedSize = POINTER_SIZE_ALIGN(kSize);
typedef FixedBodyDescriptor<kNameOffset,
- kThisPropertyAssignmentsOffset + kPointerSize,
+ kFeedbackVectorOffset + kPointerSize,
kSize> BodyDescriptor;
// 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;
- static const int kCodeAgeMask = (1 << kCodeAgeSize) - 1;
-
enum CompilerHints {
- kHasOnlySimpleThisPropertyAssignments,
kAllowLazyCompilation,
- kLiveObjectsMayExist,
- kCodeAgeShift,
- kOptimizationDisabled = kCodeAgeShift + kCodeAgeSize,
+ kAllowLazyCompilationWithoutContext,
+ kOptimizationDisabled,
kStrictModeFunction,
- kExtendedModeFunction,
kUsesArguments,
kHasDuplicateParameters,
kNative,
+ kInlineBuiltin,
kBoundFunction,
kIsAnonymous,
kNameShouldPrintAsAnonymous,
kIsFunction,
- kDontOptimize,
- kDontInline,
+ kDontCache,
+ kDontFlush,
+ kIsArrow,
+ kIsGenerator,
+ kIsConciseMethod,
+ kIsAsmFunction,
kCompilerHintsCount // Pseudo entry
};
+ class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 3> {};
+
+ class DeoptCountBits : public BitField<int, 0, 4> {};
+ class OptReenableTriesBits : public BitField<int, 4, 18> {};
+ class ICAgeBits : public BitField<int, 22, 8> {};
+
+ class OptCountBits : public BitField<int, 0, 22> {};
+ class DisabledOptimizationReasonBits : public BitField<int, 22, 8> {};
+
private:
#if V8_HOST_ARCH_32_BIT
// On 32 bit platforms, compiler hints is a smi.
@@ -5664,26 +7040,18 @@
static const int kStrictModeBitWithinByte =
(kStrictModeFunction + kCompilerHintsSmiTagSize) % kBitsPerByte;
- static const int kExtendedModeBitWithinByte =
- (kExtendedModeFunction + kCompilerHintsSmiTagSize) % kBitsPerByte;
-
static const int kNativeBitWithinByte =
(kNative + kCompilerHintsSmiTagSize) % kBitsPerByte;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
+#if defined(V8_TARGET_LITTLE_ENDIAN)
static const int kStrictModeByteOffset = kCompilerHintsOffset +
(kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte;
- static const int kExtendedModeByteOffset = kCompilerHintsOffset +
- (kExtendedModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte;
static const int kNativeByteOffset = kCompilerHintsOffset +
(kNative + kCompilerHintsSmiTagSize) / kBitsPerByte;
-#elif __BYTE_ORDER == __BIG_ENDIAN
+#elif defined(V8_TARGET_BIG_ENDIAN)
static const int kStrictModeByteOffset = kCompilerHintsOffset +
(kCompilerHintsSize - 1) -
((kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte);
- static const int kExtendedModeByteOffset = kCompilerHintsOffset +
- (kCompilerHintsSize - 1) -
- ((kExtendedModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte);
static const int kNativeByteOffset = kCompilerHintsOffset +
(kCompilerHintsSize - 1) -
((kNative + kCompilerHintsSmiTagSize) / kBitsPerByte);
@@ -5696,6 +7064,112 @@
};
+// Printing support.
+struct SourceCodeOf {
+ explicit SourceCodeOf(SharedFunctionInfo* v, int max = -1)
+ : value(v), max_length(max) {}
+ const SharedFunctionInfo* value;
+ int max_length;
+};
+
+
+OStream& operator<<(OStream& os, const SourceCodeOf& v);
+
+
+class JSGeneratorObject: public JSObject {
+ public:
+ // [function]: The function corresponding to this generator object.
+ DECL_ACCESSORS(function, JSFunction)
+
+ // [context]: The context of the suspended computation.
+ DECL_ACCESSORS(context, Context)
+
+ // [receiver]: The receiver of the suspended computation.
+ DECL_ACCESSORS(receiver, Object)
+
+ // [continuation]: Offset into code of continuation.
+ //
+ // A positive offset indicates a suspended generator. The special
+ // kGeneratorExecuting and kGeneratorClosed values indicate that a generator
+ // cannot be resumed.
+ inline int continuation() const;
+ inline void set_continuation(int continuation);
+ inline bool is_closed();
+ inline bool is_executing();
+ inline bool is_suspended();
+
+ // [operand_stack]: Saved operand stack.
+ DECL_ACCESSORS(operand_stack, FixedArray)
+
+ // [stack_handler_index]: Index of first stack handler in operand_stack, or -1
+ // if the captured activation had no stack handler.
+ inline int stack_handler_index() const;
+ inline void set_stack_handler_index(int stack_handler_index);
+
+ DECLARE_CAST(JSGeneratorObject)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSGeneratorObject)
+ DECLARE_VERIFIER(JSGeneratorObject)
+
+ // Magic sentinel values for the continuation.
+ static const int kGeneratorExecuting = -1;
+ static const int kGeneratorClosed = 0;
+
+ // Layout description.
+ static const int kFunctionOffset = JSObject::kHeaderSize;
+ static const int kContextOffset = kFunctionOffset + kPointerSize;
+ static const int kReceiverOffset = kContextOffset + kPointerSize;
+ static const int kContinuationOffset = kReceiverOffset + kPointerSize;
+ static const int kOperandStackOffset = kContinuationOffset + kPointerSize;
+ static const int kStackHandlerIndexOffset =
+ kOperandStackOffset + kPointerSize;
+ static const int kSize = kStackHandlerIndexOffset + kPointerSize;
+
+ // Resume mode, for use by runtime functions.
+ enum ResumeMode { NEXT, THROW };
+
+ // Yielding from a generator returns an object with the following inobject
+ // properties. See Context::iterator_result_map() for the map.
+ static const int kResultValuePropertyIndex = 0;
+ static const int kResultDonePropertyIndex = 1;
+ static const int kResultPropertyCount = 2;
+
+ static const int kResultValuePropertyOffset = JSObject::kHeaderSize;
+ static const int kResultDonePropertyOffset =
+ kResultValuePropertyOffset + kPointerSize;
+ static const int kResultSize = kResultDonePropertyOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSGeneratorObject);
+};
+
+
+// Representation for module instance objects.
+class JSModule: public JSObject {
+ public:
+ // [context]: the context holding the module's locals, or undefined if none.
+ DECL_ACCESSORS(context, Object)
+
+ // [scope_info]: Scope info.
+ DECL_ACCESSORS(scope_info, ScopeInfo)
+
+ DECLARE_CAST(JSModule)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSModule)
+ DECLARE_VERIFIER(JSModule)
+
+ // Layout description.
+ static const int kContextOffset = JSObject::kHeaderSize;
+ static const int kScopeInfoOffset = kContextOffset + kPointerSize;
+ static const int kSize = kScopeInfoOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSModule);
+};
+
+
// JSFunction describes JavaScript functions.
class JSFunction: public JSObject {
public:
@@ -5706,12 +7180,10 @@
// can be shared by instances.
DECL_ACCESSORS(shared, SharedFunctionInfo)
- inline SharedFunctionInfo* unchecked_shared();
-
// [context]: The context for this function.
inline Context* context();
- inline Object* unchecked_context();
inline void set_context(Object* context);
+ inline JSObject* global_proxy();
// [code]: The generated code object for this function. Executed
// when the function is invoked, e.g. foo() or new foo(). See
@@ -5719,13 +7191,18 @@
// 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();
-
// Tells whether this function is builtin.
inline bool IsBuiltin();
+ // Tells whether this function is defined in a native script.
+ inline bool IsFromNativeScript();
+
+ // Tells whether this function is defined in an extension script.
+ inline bool IsFromExtensionScript();
+
// Tells whether or not the function needs arguments adaption.
inline bool NeedsArgumentsAdaption();
@@ -5737,22 +7214,65 @@
// Mark this function for lazy recompilation. The function will be
// recompiled the next time it is executed.
- void MarkForLazyRecompilation();
-
- // Helpers to compile this function. Returns true on success, false on
- // failure (e.g., stack overflow during compilation).
- static bool CompileLazy(Handle<JSFunction> function,
- ClearExceptionFlag flag);
- static bool CompileOptimized(Handle<JSFunction> function,
- int osr_ast_id,
- ClearExceptionFlag flag);
+ void MarkForOptimization();
+ void MarkForConcurrentOptimization();
+ void MarkInOptimizationQueue();
// Tells whether or not the function is already marked for lazy
// recompilation.
- inline bool IsMarkedForLazyRecompilation();
+ inline bool IsMarkedForOptimization();
+ inline bool IsMarkedForConcurrentOptimization();
- // Check whether or not this function is inlineable.
- bool IsInlineable();
+ // Tells whether or not the function is on the concurrent recompilation queue.
+ inline bool IsInOptimizationQueue();
+
+ // Inobject slack tracking is the way to reclaim unused inobject space.
+ //
+ // The instance size is initially determined by adding some slack to
+ // expected_nof_properties (to allow for a few extra properties added
+ // after the constructor). There is no guarantee that the extra space
+ // will not be wasted.
+ //
+ // Here is the algorithm to reclaim the unused inobject space:
+ // - Detect the first constructor call for this JSFunction.
+ // When it happens enter the "in progress" state: initialize construction
+ // counter in the initial_map and set the |done_inobject_slack_tracking|
+ // flag.
+ // - While the tracking is in progress create objects filled with
+ // one_pointer_filler_map instead of undefined_value. This way they can be
+ // resized quickly and safely.
+ // - Once enough (kGenerousAllocationCount) objects have been created
+ // compute the 'slack' (traverse the map transition tree starting from the
+ // initial_map and find the lowest value of unused_property_fields).
+ // - Traverse the transition tree again and decrease the instance size
+ // of every map. Existing objects will resize automatically (they are
+ // filled with one_pointer_filler_map). All further allocations will
+ // use the adjusted instance size.
+ // - SharedFunctionInfo's expected_nof_properties left unmodified since
+ // allocations made using different closures could actually create different
+ // kind of objects (see prototype inheritance pattern).
+ //
+ // Important: inobject slack tracking is not attempted during the snapshot
+ // creation.
+
+ static const int kGenerousAllocationCount = Map::ConstructionCount::kMax;
+ static const int kFinishSlackTracking = 1;
+ static const int kNoSlackTracking = 0;
+
+ // True if the initial_map is set and the object constructions countdown
+ // counter is not zero.
+ inline bool IsInobjectSlackTrackingInProgress();
+
+ // Starts the tracking.
+ // Initializes object constructions countdown counter in the initial map.
+ // IsInobjectSlackTrackingInProgress is normally true after this call,
+ // except when tracking have not been started (e.g. the map has no unused
+ // properties or the snapshot is being built).
+ void StartInobjectSlackTracking();
+
+ // Completes the tracking.
+ // IsInobjectSlackTrackingInProgress is false after this call.
+ void CompleteInobjectSlackTracking();
// [literals_or_bindings]: Fixed array holding either
// the materialized literals or the bindings of a bound function.
@@ -5778,10 +7298,10 @@
// The initial map for an object created by this constructor.
inline Map* initial_map();
- inline void set_initial_map(Map* value);
- MUST_USE_RESULT inline MaybeObject* set_initial_map_and_cache_transitions(
- Map* value);
+ static void SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
+ Handle<Object> prototype);
inline bool has_initial_map();
+ static void EnsureHasInitialMap(Handle<JSFunction> function);
// Get and set the prototype property on a JSFunction. If the
// function has an initial map the prototype is set on the initial
@@ -5791,12 +7311,19 @@
inline bool has_instance_prototype();
inline Object* prototype();
inline Object* instance_prototype();
- MUST_USE_RESULT MaybeObject* SetInstancePrototype(Object* value);
- MUST_USE_RESULT MaybeObject* SetPrototype(Object* value);
+ static void SetPrototype(Handle<JSFunction> function,
+ Handle<Object> value);
+ static void SetInstancePrototype(Handle<JSFunction> function,
+ Handle<Object> value);
+
+ // Creates a new closure for the fucntion with the same bindings,
+ // bound values, and prototype. An equivalent of spec operations
+ // ``CloneMethod`` and ``CloneBoundFunction``.
+ static Handle<JSFunction> CloneClosure(Handle<JSFunction> function);
// After prototype is removed, it will not be created when accessed, and
// [[Construct]] from this function will not be allowed.
- Object* RemovePrototype();
+ bool RemovePrototype();
inline bool should_have_prototype();
// Accessor for this function's initial map's [[class]]
@@ -5808,44 +7335,38 @@
// Instances created afterwards will have a map whose [[class]] is
// set to 'value', but there is no guarantees on instances created
// before.
- Object* SetInstanceClassName(String* name);
+ void SetInstanceClassName(String* name);
// Returns if this function has been compiled to native code yet.
inline bool is_compiled();
- // [next_function_link]: Field for linking functions. This list is treated as
- // a weak list by the GC.
+ // [next_function_link]: Links functions into various lists, e.g. the list
+ // of optimized functions hanging off the native_context. The CodeFlusher
+ // uses this link to chain together flushing candidates. Treated weakly
+ // by the garbage collector.
DECL_ACCESSORS(next_function_link, Object)
// Prints the name of the function using PrintF.
- inline void PrintName() {
- PrintName(stdout);
- }
- void PrintName(FILE* out);
+ void PrintName(FILE* out = stdout);
- // Casting.
- static inline JSFunction* cast(Object* obj);
+ DECLARE_CAST(JSFunction)
// Iterates the objects, including code objects indirectly referenced
// through pointers to the first instruction in the code object.
void JSFunctionIterateBody(int object_size, ObjectVisitor* v);
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSFunctionPrint() {
- JSFunctionPrint(stdout);
- }
- void JSFunctionPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSFunctionVerify();
-#endif
+ DECLARE_PRINTER(JSFunction)
+ DECLARE_VERIFIER(JSFunction)
// Returns the number of allocated literals.
inline int NumberOfLiterals();
- // Retrieve the global context from a function's literal array.
- static Context* GlobalContextFromLiterals(FixedArray* literals);
+ // Retrieve the native context from a function's literal array.
+ static Context* NativeContextFromLiterals(FixedArray* literals);
+
+ // Used for flags such as --hydrogen-filter.
+ bool PassesFilter(const char* raw_filter);
// Layout descriptors. The last property (from kNonWeakFieldsEndOffset to
// kSize) is weak and has special handling during garbage collection.
@@ -5862,7 +7383,7 @@
// Layout of the literals array.
static const int kLiteralsPrefixSize = 1;
- static const int kLiteralGlobalContextIndex = 0;
+ static const int kLiteralNativeContextIndex = 0;
// Layout of the bound-function binding array.
static const int kBoundFunctionIndex = 0;
@@ -5884,27 +7405,25 @@
class JSGlobalProxy : public JSObject {
public:
- // [context]: the owner global context of this global proxy object.
+ // [native_context]: the owner native context of this global proxy object.
// It is null value if this object is not used by any context.
- DECL_ACCESSORS(context, Object)
+ DECL_ACCESSORS(native_context, Object)
- // Casting.
- static inline JSGlobalProxy* cast(Object* obj);
+ // [hash]: The hash code property (undefined if not initialized yet).
+ DECL_ACCESSORS(hash, Object)
+
+ DECLARE_CAST(JSGlobalProxy)
+
+ inline bool IsDetachedFrom(GlobalObject* global) const;
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSGlobalProxyPrint() {
- JSGlobalProxyPrint(stdout);
- }
- void JSGlobalProxyPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSGlobalProxyVerify();
-#endif
+ DECLARE_PRINTER(JSGlobalProxy)
+ DECLARE_VERIFIER(JSGlobalProxy)
// Layout description.
- static const int kContextOffset = JSObject::kHeaderSize;
- static const int kSize = kContextOffset + kPointerSize;
+ static const int kNativeContextOffset = JSObject::kHeaderSize;
+ static const int kHashOffset = kNativeContextOffset + kPointerSize;
+ static const int kSize = kHashOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalProxy);
@@ -5921,40 +7440,23 @@
// [builtins]: the object holding the runtime routines written in JS.
DECL_ACCESSORS(builtins, JSBuiltinsObject)
- // [global context]: the global context corresponding to this global object.
+ // [native context]: the natives corresponding to this global object.
+ DECL_ACCESSORS(native_context, Context)
+
+ // [global context]: the most recent (i.e. innermost) global context.
DECL_ACCESSORS(global_context, Context)
- // [global receiver]: the global receiver object of the context
- DECL_ACCESSORS(global_receiver, JSObject)
+ // [global proxy]: the global proxy object of the context
+ DECL_ACCESSORS(global_proxy, JSObject)
- // Retrieve the property cell used to store a property.
- JSGlobalPropertyCell* GetPropertyCell(LookupResult* result);
-
- // This is like GetProperty, but is used when you know the lookup won't fail
- // 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* answer = GetProperty(key)->ToObjectUnchecked();
- return answer;
- }
-
- // Ensure that the global object has a cell for the given property name.
- static Handle<JSGlobalPropertyCell> EnsurePropertyCell(
- Handle<GlobalObject> global,
- Handle<String> 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);
-
- // Casting.
- static inline GlobalObject* cast(Object* obj);
+ DECLARE_CAST(GlobalObject)
// Layout description.
static const int kBuiltinsOffset = JSObject::kHeaderSize;
- static const int kGlobalContextOffset = kBuiltinsOffset + kPointerSize;
- static const int kGlobalReceiverOffset = kGlobalContextOffset + kPointerSize;
- static const int kHeaderSize = kGlobalReceiverOffset + kPointerSize;
+ static const int kNativeContextOffset = kBuiltinsOffset + kPointerSize;
+ static const int kGlobalContextOffset = kNativeContextOffset + kPointerSize;
+ static const int kGlobalProxyOffset = kGlobalContextOffset + kPointerSize;
+ static const int kHeaderSize = kGlobalProxyOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(GlobalObject);
@@ -5964,19 +7466,17 @@
// JavaScript global object.
class JSGlobalObject: public GlobalObject {
public:
- // Casting.
- static inline JSGlobalObject* cast(Object* obj);
+ DECLARE_CAST(JSGlobalObject)
+
+ // Ensure that the global object has a cell for the given property name.
+ static Handle<PropertyCell> EnsurePropertyCell(Handle<JSGlobalObject> global,
+ Handle<Name> name);
+
+ inline bool IsDetached();
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSGlobalObjectPrint() {
- JSGlobalObjectPrint(stdout);
- }
- void JSGlobalObjectPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSGlobalObjectVerify();
-#endif
+ DECLARE_PRINTER(JSGlobalObject)
+ DECLARE_VERIFIER(JSGlobalObject)
// Layout description.
static const int kSize = GlobalObject::kHeaderSize;
@@ -5998,19 +7498,11 @@
inline Code* javascript_builtin_code(Builtins::JavaScript id);
inline void set_javascript_builtin_code(Builtins::JavaScript id, Code* value);
- // Casting.
- static inline JSBuiltinsObject* cast(Object* obj);
+ DECLARE_CAST(JSBuiltinsObject)
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSBuiltinsObjectPrint() {
- JSBuiltinsObjectPrint(stdout);
- }
- void JSBuiltinsObjectPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSBuiltinsObjectVerify();
-#endif
+ DECLARE_PRINTER(JSBuiltinsObject)
+ DECLARE_VERIFIER(JSBuiltinsObject)
// Layout description. The size of the builtins object includes
// room for two pointers per runtime routine written in javascript
@@ -6041,19 +7533,11 @@
// [value]: the object being wrapped.
DECL_ACCESSORS(value, Object)
- // Casting.
- static inline JSValue* cast(Object* obj);
+ DECLARE_CAST(JSValue)
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSValuePrint() {
- JSValuePrint(stdout);
- }
- void JSValuePrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSValueVerify();
-#endif
+ DECLARE_PRINTER(JSValue)
+ DECLARE_VERIFIER(JSValue)
// Layout description.
static const int kValueOffset = JSObject::kHeaderSize;
@@ -6087,29 +7571,22 @@
// [sec]: caches seconds. Either undefined, smi, or NaN.
DECL_ACCESSORS(sec, Object)
// [cache stamp]: sample of the date cache stamp at the
- // moment when local fields were cached.
+ // moment when chached fields were cached.
DECL_ACCESSORS(cache_stamp, Object)
- // Casting.
- static inline JSDate* cast(Object* obj);
+ DECLARE_CAST(JSDate)
// Returns the date field with the specified index.
// See FieldIndex for the list of date fields.
- static MaybeObject* GetField(Object* date, Smi* index);
+ static Object* GetField(Object* date, Smi* index);
void SetValue(Object* value, bool is_value_nan);
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSDatePrint() {
- JSDatePrint(stdout);
- }
- void JSDatePrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSDateVerify();
-#endif
+ DECLARE_PRINTER(JSDate)
+ DECLARE_VERIFIER(JSDate)
+
// The order is important. It must be kept in sync with date macros
// in macros.py.
enum FieldIndex {
@@ -6157,7 +7634,7 @@
Object* GetUTCField(FieldIndex index, double value, DateCache* date_cache);
// Computes and caches the cacheable fields of the date.
- inline void SetLocalFields(int64_t local_time_ms, DateCache* date_cache);
+ inline void SetCachedFields(int64_t local_time_ms, DateCache* date_cache);
DISALLOW_IMPLICIT_CONSTRUCTORS(JSDate);
@@ -6181,40 +7658,28 @@
// [script]: the script from which the error message originated.
DECL_ACCESSORS(script, Object)
- // [stack_trace]: the stack trace for this error message.
- DECL_ACCESSORS(stack_trace, Object)
-
// [stack_frames]: an array of stack frames for this error object.
DECL_ACCESSORS(stack_frames, Object)
// [start_position]: the start position in the script for the error message.
- inline int start_position();
+ inline int start_position() const;
inline void set_start_position(int value);
// [end_position]: the end position in the script for the error message.
- inline int end_position();
+ inline int end_position() const;
inline void set_end_position(int value);
- // Casting.
- static inline JSMessageObject* cast(Object* obj);
+ DECLARE_CAST(JSMessageObject)
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSMessageObjectPrint() {
- JSMessageObjectPrint(stdout);
- }
- void JSMessageObjectPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSMessageObjectVerify();
-#endif
+ DECLARE_PRINTER(JSMessageObject)
+ DECLARE_VERIFIER(JSMessageObject)
// Layout description.
static const int kTypeOffset = JSObject::kHeaderSize;
static const int kArgumentsOffset = kTypeOffset + kPointerSize;
static const int kScriptOffset = kArgumentsOffset + kPointerSize;
- static const int kStackTraceOffset = kScriptOffset + kPointerSize;
- static const int kStackFramesOffset = kStackTraceOffset + kPointerSize;
+ static const int kStackFramesOffset = kScriptOffset + kPointerSize;
static const int kStartPositionOffset = kStackFramesOffset + kPointerSize;
static const int kEndPositionOffset = kStartPositionOffset + kPointerSize;
static const int kSize = kEndPositionOffset + kPointerSize;
@@ -6235,7 +7700,7 @@
// If it is an atom regexp
// - a reference to a literal string to search for
// If it is an irregexp regexp:
-// - a reference to code for ASCII inputs (bytecode or compiled), or a smi
+// - a reference to code for Latin1 inputs (bytecode or compiled), or a smi
// used for tracking the last usage (used for code flushing).
// - a reference to code for UC16 inputs (bytecode or compiled), or a smi
// used for tracking the last usage (used for code flushing)..
@@ -6249,7 +7714,13 @@
// IRREGEXP: Compiled with Irregexp.
// IRREGEXP_NATIVE: Compiled to native code with Irregexp.
enum Type { NOT_COMPILED, ATOM, IRREGEXP };
- enum Flag { NONE = 0, GLOBAL = 1, IGNORE_CASE = 2, MULTILINE = 4 };
+ enum Flag {
+ NONE = 0,
+ GLOBAL = 1,
+ IGNORE_CASE = 2,
+ MULTILINE = 4,
+ STICKY = 8
+ };
class Flags {
public:
@@ -6257,6 +7728,7 @@
bool is_global() { return (value_ & GLOBAL) != 0; }
bool is_ignore_case() { return (value_ & IGNORE_CASE) != 0; }
bool is_multiline() { return (value_ & MULTILINE) != 0; }
+ bool is_sticky() { return (value_ & STICKY) != 0; }
uint32_t value() { return value_; }
private:
uint32_t value_;
@@ -6272,33 +7744,26 @@
// Set implementation data after the object has been prepared.
inline void SetDataAt(int index, Object* value);
- // Used during GC when flushing code or setting age.
- inline Object* DataAtUnchecked(int index);
- inline void SetDataAtUnchecked(int index, Object* value, Heap* heap);
- inline Type TypeTagUnchecked();
-
- static int code_index(bool is_ascii) {
- if (is_ascii) {
- return kIrregexpASCIICodeIndex;
+ static int code_index(bool is_latin1) {
+ if (is_latin1) {
+ return kIrregexpLatin1CodeIndex;
} else {
return kIrregexpUC16CodeIndex;
}
}
- static int saved_code_index(bool is_ascii) {
- if (is_ascii) {
- return kIrregexpASCIICodeSavedIndex;
+ static int saved_code_index(bool is_latin1) {
+ if (is_latin1) {
+ return kIrregexpLatin1CodeSavedIndex;
} else {
return kIrregexpUC16CodeSavedIndex;
}
}
- static inline JSRegExp* cast(Object* obj);
+ DECLARE_CAST(JSRegExp)
// Dispatched behavior.
-#ifdef DEBUG
- void JSRegExpVerify();
-#endif
+ DECLARE_VERIFIER(JSRegExp)
static const int kDataOffset = JSObject::kHeaderSize;
static const int kSize = kDataOffset + kPointerSize;
@@ -6315,23 +7780,23 @@
static const int kAtomDataSize = kAtomPatternIndex + 1;
- // Irregexp compiled code or bytecode for ASCII. If compilation
+ // Irregexp compiled code or bytecode for Latin1. If compilation
// fails, this fields hold an exception object that should be
// thrown if the regexp is used again.
- static const int kIrregexpASCIICodeIndex = kDataIndex;
+ static const int kIrregexpLatin1CodeIndex = kDataIndex;
// Irregexp compiled code or bytecode for UC16. If compilation
// fails, this fields hold an exception object that should be
// thrown if the regexp is used again.
static const int kIrregexpUC16CodeIndex = kDataIndex + 1;
- // Saved instance of Irregexp compiled code or bytecode for ASCII that
+ // Saved instance of Irregexp compiled code or bytecode for Latin1 that
// is a potential candidate for flushing.
- static const int kIrregexpASCIICodeSavedIndex = kDataIndex + 2;
+ static const int kIrregexpLatin1CodeSavedIndex = kDataIndex + 2;
// Saved instance of Irregexp compiled code or bytecode for UC16 that is
// a potential candidate for flushing.
static const int kIrregexpUC16CodeSavedIndex = kDataIndex + 3;
- // Maximal number of registers used by either ASCII or UC16.
+ // Maximal number of registers used by either Latin1 or UC16.
// Only used to check that there is enough stack space
static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 4;
// Number of captures in the compiled regexp.
@@ -6342,8 +7807,8 @@
// Offsets directly into the data fixed array.
static const int kDataTagOffset =
FixedArray::kHeaderSize + kTagIndex * kPointerSize;
- static const int kDataAsciiCodeOffset =
- FixedArray::kHeaderSize + kIrregexpASCIICodeIndex * kPointerSize;
+ static const int kDataOneByteCodeOffset =
+ FixedArray::kHeaderSize + kIrregexpLatin1CodeIndex * kPointerSize;
static const int kDataUC16CodeOffset =
FixedArray::kHeaderSize + kIrregexpUC16CodeIndex * kPointerSize;
static const int kIrregexpCaptureCountOffset =
@@ -6385,38 +7850,36 @@
return key->HashForObject(object);
}
- MUST_USE_RESULT static MaybeObject* AsObject(HashTableKey* key) {
- return key->AsObject();
- }
+ static inline Handle<Object> AsHandle(Isolate* isolate, HashTableKey* key);
static const int kPrefixSize = 0;
static const int kEntrySize = 2;
};
-class CompilationCacheTable: public HashTable<CompilationCacheShape,
+class CompilationCacheTable: public HashTable<CompilationCacheTable,
+ CompilationCacheShape,
HashTableKey*> {
public:
// Find cached value for a string key, otherwise return null.
- Object* Lookup(String* src);
- Object* LookupEval(String* src,
- Context* context,
- LanguageMode language_mode,
- int scope_position);
- Object* LookupRegExp(String* source, JSRegExp::Flags flags);
- MUST_USE_RESULT MaybeObject* Put(String* src, Object* value);
- MUST_USE_RESULT MaybeObject* PutEval(String* src,
- Context* context,
- SharedFunctionInfo* value,
- int scope_position);
- MUST_USE_RESULT MaybeObject* PutRegExp(String* src,
- JSRegExp::Flags flags,
- FixedArray* value);
-
- // Remove given value from cache.
+ Handle<Object> Lookup(Handle<String> src, Handle<Context> context);
+ Handle<Object> LookupEval(Handle<String> src,
+ Handle<SharedFunctionInfo> shared,
+ StrictMode strict_mode, int scope_position);
+ Handle<Object> LookupRegExp(Handle<String> source, JSRegExp::Flags flags);
+ static Handle<CompilationCacheTable> Put(
+ Handle<CompilationCacheTable> cache, Handle<String> src,
+ Handle<Context> context, Handle<Object> value);
+ static Handle<CompilationCacheTable> PutEval(
+ Handle<CompilationCacheTable> cache, Handle<String> src,
+ Handle<SharedFunctionInfo> context, Handle<SharedFunctionInfo> value,
+ int scope_position);
+ static Handle<CompilationCacheTable> PutRegExp(
+ Handle<CompilationCacheTable> cache, Handle<String> src,
+ JSRegExp::Flags flags, Handle<FixedArray> value);
void Remove(Object* value);
- static inline CompilationCacheTable* cast(Object* obj);
+ DECLARE_CAST(CompilationCacheTable)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheTable);
@@ -6429,11 +7892,12 @@
DECL_ACCESSORS(normal_type_cache, Object)
// Add the code object to the cache.
- MUST_USE_RESULT MaybeObject* Update(String* name, Code* code);
+ static void Update(
+ Handle<CodeCache> cache, Handle<Name> name, Handle<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
@@ -6444,17 +7908,11 @@
// Remove an object from the cache with the provided internal index.
void RemoveByIndex(Object* name, Code* code, int index);
- static inline CodeCache* cast(Object* obj);
+ DECLARE_CAST(CodeCache)
-#ifdef OBJECT_PRINT
- inline void CodeCachePrint() {
- CodeCachePrint(stdout);
- }
- void CodeCachePrint(FILE* out);
-#endif
-#ifdef DEBUG
- void CodeCacheVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(CodeCache)
+ DECLARE_VERIFIER(CodeCache)
static const int kDefaultCacheOffset = HeapObject::kHeaderSize;
static const int kNormalTypeCacheOffset =
@@ -6462,10 +7920,12 @@
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);
+ static void UpdateDefaultCache(
+ Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code);
+ static void UpdateNormalTypeCache(
+ Handle<CodeCache> code_cache, Handle<Name> name, Handle<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.
@@ -6491,25 +7951,27 @@
return key->HashForObject(object);
}
- MUST_USE_RESULT static MaybeObject* AsObject(HashTableKey* key) {
- return key->AsObject();
- }
+ static inline Handle<Object> AsHandle(Isolate* isolate, HashTableKey* key);
static const int kPrefixSize = 0;
static const int kEntrySize = 2;
};
-class CodeCacheHashTable: public HashTable<CodeCacheHashTableShape,
+class CodeCacheHashTable: public HashTable<CodeCacheHashTable,
+ 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);
+ static Handle<CodeCacheHashTable> Put(
+ Handle<CodeCacheHashTable> table,
+ Handle<Name> name,
+ Handle<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);
+ DECLARE_CAST(CodeCacheHashTable)
// Initial size of the fixed array backing the hash table.
static const int kInitialSize = 64;
@@ -6528,24 +7990,15 @@
Code::Flags flags,
Handle<Code> code);
- MUST_USE_RESULT MaybeObject* Update(MapHandleList* maps,
- Code::Flags flags,
- Code* code);
// Returns an undefined value if the entry is not found.
Handle<Object> Lookup(MapHandleList* maps, Code::Flags flags);
- static inline PolymorphicCodeCache* cast(Object* obj);
+ DECLARE_CAST(PolymorphicCodeCache)
-#ifdef OBJECT_PRINT
- inline void PolymorphicCodeCachePrint() {
- PolymorphicCodeCachePrint(stdout);
- }
- void PolymorphicCodeCachePrint(FILE* out);
-#endif
-#ifdef DEBUG
- void PolymorphicCodeCacheVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(PolymorphicCodeCache)
+ DECLARE_VERIFIER(PolymorphicCodeCache)
static const int kCacheOffset = HeapObject::kHeaderSize;
static const int kSize = kCacheOffset + kPointerSize;
@@ -6556,15 +8009,19 @@
class PolymorphicCodeCacheHashTable
- : public HashTable<CodeCacheHashTableShape, HashTableKey*> {
+ : public HashTable<PolymorphicCodeCacheHashTable,
+ CodeCacheHashTableShape,
+ HashTableKey*> {
public:
Object* Lookup(MapHandleList* maps, int code_kind);
- MUST_USE_RESULT MaybeObject* Put(MapHandleList* maps,
- int code_kind,
- Code* code);
+ static Handle<PolymorphicCodeCacheHashTable> Put(
+ Handle<PolymorphicCodeCacheHashTable> hash_table,
+ MapHandleList* maps,
+ int code_kind,
+ Handle<Code> code);
- static inline PolymorphicCodeCacheHashTable* cast(Object* obj);
+ DECLARE_CAST(PolymorphicCodeCacheHashTable)
static const int kInitialSize = 64;
private:
@@ -6578,36 +8035,278 @@
inline void set_ic_total_count(int count);
inline int ic_with_type_info_count();
- inline void set_ic_with_type_info_count(int count);
+ inline void change_ic_with_type_info_count(int delta);
- DECL_ACCESSORS(type_feedback_cells, TypeFeedbackCells)
+ inline int ic_generic_count();
+ inline void change_ic_generic_count(int delta);
- static inline TypeFeedbackInfo* cast(Object* obj);
+ inline void initialize_storage();
-#ifdef OBJECT_PRINT
- inline void TypeFeedbackInfoPrint() {
- TypeFeedbackInfoPrint(stdout);
- }
- void TypeFeedbackInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void TypeFeedbackInfoVerify();
-#endif
+ inline void change_own_type_change_checksum();
+ inline int own_type_change_checksum();
- static const int kIcTotalCountOffset = HeapObject::kHeaderSize;
- static const int kIcWithTypeinfoCountOffset =
- kIcTotalCountOffset + kPointerSize;
- static const int kTypeFeedbackCellsOffset =
- kIcWithTypeinfoCountOffset + kPointerSize;
- static const int kSize = kTypeFeedbackCellsOffset + kPointerSize;
+ inline void set_inlined_type_change_checksum(int checksum);
+ inline bool matches_inlined_type_change_checksum(int checksum);
+
+
+ DECLARE_CAST(TypeFeedbackInfo)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(TypeFeedbackInfo)
+ DECLARE_VERIFIER(TypeFeedbackInfo)
+
+ static const int kStorage1Offset = HeapObject::kHeaderSize;
+ static const int kStorage2Offset = kStorage1Offset + kPointerSize;
+ static const int kStorage3Offset = kStorage2Offset + kPointerSize;
+ static const int kSize = kStorage3Offset + kPointerSize;
private:
+ static const int kTypeChangeChecksumBits = 7;
+
+ class ICTotalCountField: public BitField<int, 0,
+ kSmiValueSize - kTypeChangeChecksumBits> {}; // NOLINT
+ class OwnTypeChangeChecksum: public BitField<int,
+ kSmiValueSize - kTypeChangeChecksumBits,
+ kTypeChangeChecksumBits> {}; // NOLINT
+ class ICsWithTypeInfoCountField: public BitField<int, 0,
+ kSmiValueSize - kTypeChangeChecksumBits> {}; // NOLINT
+ class InlinedTypeChangeChecksum: public BitField<int,
+ kSmiValueSize - kTypeChangeChecksumBits,
+ kTypeChangeChecksumBits> {}; // NOLINT
+
DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackInfo);
};
-// Representation of a slow alias as part of a non-strict arguments objects.
-// For fast aliases (if HasNonStrictArgumentsElements()):
+enum AllocationSiteMode {
+ DONT_TRACK_ALLOCATION_SITE,
+ TRACK_ALLOCATION_SITE,
+ LAST_ALLOCATION_SITE_MODE = TRACK_ALLOCATION_SITE
+};
+
+
+class AllocationSite: public Struct {
+ public:
+ static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024;
+ static const double kPretenureRatio;
+ static const int kPretenureMinimumCreated = 100;
+
+ // Values for pretenure decision field.
+ enum PretenureDecision {
+ kUndecided = 0,
+ kDontTenure = 1,
+ kMaybeTenure = 2,
+ kTenure = 3,
+ kZombie = 4,
+ kLastPretenureDecisionValue = kZombie
+ };
+
+ const char* PretenureDecisionName(PretenureDecision decision);
+
+ DECL_ACCESSORS(transition_info, Object)
+ // nested_site threads a list of sites that represent nested literals
+ // walked in a particular order. So [[1, 2], 1, 2] will have one
+ // nested_site, but [[1, 2], 3, [4]] will have a list of two.
+ DECL_ACCESSORS(nested_site, Object)
+ DECL_ACCESSORS(pretenure_data, Smi)
+ DECL_ACCESSORS(pretenure_create_count, Smi)
+ DECL_ACCESSORS(dependent_code, DependentCode)
+ DECL_ACCESSORS(weak_next, Object)
+
+ inline void Initialize();
+
+ // This method is expensive, it should only be called for reporting.
+ bool IsNestedSite();
+
+ // transition_info bitfields, for constructed array transition info.
+ class ElementsKindBits: public BitField<ElementsKind, 0, 15> {};
+ class UnusedBits: public BitField<int, 15, 14> {};
+ class DoNotInlineBit: public BitField<bool, 29, 1> {};
+
+ // Bitfields for pretenure_data
+ class MementoFoundCountBits: public BitField<int, 0, 26> {};
+ class PretenureDecisionBits: public BitField<PretenureDecision, 26, 3> {};
+ class DeoptDependentCodeBit: public BitField<bool, 29, 1> {};
+ STATIC_ASSERT(PretenureDecisionBits::kMax >= kLastPretenureDecisionValue);
+
+ // Increments the mementos found counter and returns true when the first
+ // memento was found for a given allocation site.
+ inline bool IncrementMementoFoundCount();
+
+ inline void IncrementMementoCreateCount();
+
+ PretenureFlag GetPretenureMode();
+
+ void ResetPretenureDecision();
+
+ PretenureDecision pretenure_decision() {
+ int value = pretenure_data()->value();
+ return PretenureDecisionBits::decode(value);
+ }
+
+ void set_pretenure_decision(PretenureDecision decision) {
+ int value = pretenure_data()->value();
+ set_pretenure_data(
+ Smi::FromInt(PretenureDecisionBits::update(value, decision)),
+ SKIP_WRITE_BARRIER);
+ }
+
+ bool deopt_dependent_code() {
+ int value = pretenure_data()->value();
+ return DeoptDependentCodeBit::decode(value);
+ }
+
+ void set_deopt_dependent_code(bool deopt) {
+ int value = pretenure_data()->value();
+ set_pretenure_data(
+ Smi::FromInt(DeoptDependentCodeBit::update(value, deopt)),
+ SKIP_WRITE_BARRIER);
+ }
+
+ int memento_found_count() {
+ int value = pretenure_data()->value();
+ return MementoFoundCountBits::decode(value);
+ }
+
+ inline void set_memento_found_count(int count);
+
+ int memento_create_count() {
+ return pretenure_create_count()->value();
+ }
+
+ void set_memento_create_count(int count) {
+ set_pretenure_create_count(Smi::FromInt(count), SKIP_WRITE_BARRIER);
+ }
+
+ // The pretenuring decision is made during gc, and the zombie state allows
+ // us to recognize when an allocation site is just being kept alive because
+ // a later traversal of new space may discover AllocationMementos that point
+ // to this AllocationSite.
+ bool IsZombie() {
+ return pretenure_decision() == kZombie;
+ }
+
+ bool IsMaybeTenure() {
+ return pretenure_decision() == kMaybeTenure;
+ }
+
+ inline void MarkZombie();
+
+ inline bool MakePretenureDecision(PretenureDecision current_decision,
+ double ratio,
+ bool maximum_size_scavenge);
+
+ inline bool DigestPretenuringFeedback(bool maximum_size_scavenge);
+
+ ElementsKind GetElementsKind() {
+ DCHECK(!SitePointsToLiteral());
+ int value = Smi::cast(transition_info())->value();
+ return ElementsKindBits::decode(value);
+ }
+
+ void SetElementsKind(ElementsKind kind) {
+ int value = Smi::cast(transition_info())->value();
+ set_transition_info(Smi::FromInt(ElementsKindBits::update(value, kind)),
+ SKIP_WRITE_BARRIER);
+ }
+
+ bool CanInlineCall() {
+ int value = Smi::cast(transition_info())->value();
+ return DoNotInlineBit::decode(value) == 0;
+ }
+
+ void SetDoNotInlineCall() {
+ int value = Smi::cast(transition_info())->value();
+ set_transition_info(Smi::FromInt(DoNotInlineBit::update(value, true)),
+ SKIP_WRITE_BARRIER);
+ }
+
+ bool SitePointsToLiteral() {
+ // If transition_info is a smi, then it represents an ElementsKind
+ // for a constructed array. Otherwise, it must be a boilerplate
+ // for an object or array literal.
+ return transition_info()->IsJSArray() || transition_info()->IsJSObject();
+ }
+
+ static void DigestTransitionFeedback(Handle<AllocationSite> site,
+ ElementsKind to_kind);
+
+ enum Reason {
+ TENURING,
+ TRANSITIONS
+ };
+
+ static void AddDependentCompilationInfo(Handle<AllocationSite> site,
+ Reason reason,
+ CompilationInfo* info);
+
+ DECLARE_PRINTER(AllocationSite)
+ DECLARE_VERIFIER(AllocationSite)
+
+ DECLARE_CAST(AllocationSite)
+ static inline AllocationSiteMode GetMode(
+ ElementsKind boilerplate_elements_kind);
+ static inline AllocationSiteMode GetMode(ElementsKind from, ElementsKind to);
+ static inline bool CanTrack(InstanceType type);
+
+ static const int kTransitionInfoOffset = HeapObject::kHeaderSize;
+ static const int kNestedSiteOffset = kTransitionInfoOffset + kPointerSize;
+ static const int kPretenureDataOffset = kNestedSiteOffset + kPointerSize;
+ static const int kPretenureCreateCountOffset =
+ kPretenureDataOffset + kPointerSize;
+ static const int kDependentCodeOffset =
+ kPretenureCreateCountOffset + kPointerSize;
+ static const int kWeakNextOffset = kDependentCodeOffset + kPointerSize;
+ static const int kSize = kWeakNextOffset + kPointerSize;
+
+ // During mark compact we need to take special care for the dependent code
+ // field.
+ static const int kPointerFieldsBeginOffset = kTransitionInfoOffset;
+ static const int kPointerFieldsEndOffset = kDependentCodeOffset;
+
+ // For other visitors, use the fixed body descriptor below.
+ typedef FixedBodyDescriptor<HeapObject::kHeaderSize,
+ kDependentCodeOffset + kPointerSize,
+ kSize> BodyDescriptor;
+
+ private:
+ inline DependentCode::DependencyGroup ToDependencyGroup(Reason reason);
+ bool PretenuringDecisionMade() {
+ return pretenure_decision() != kUndecided;
+ }
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSite);
+};
+
+
+class AllocationMemento: public Struct {
+ public:
+ static const int kAllocationSiteOffset = HeapObject::kHeaderSize;
+ static const int kSize = kAllocationSiteOffset + kPointerSize;
+
+ DECL_ACCESSORS(allocation_site, Object)
+
+ bool IsValid() {
+ return allocation_site()->IsAllocationSite() &&
+ !AllocationSite::cast(allocation_site())->IsZombie();
+ }
+ AllocationSite* GetAllocationSite() {
+ DCHECK(IsValid());
+ return AllocationSite::cast(allocation_site());
+ }
+
+ DECLARE_PRINTER(AllocationMemento)
+ DECLARE_VERIFIER(AllocationMemento)
+
+ DECLARE_CAST(AllocationMemento)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationMemento);
+};
+
+
+// Representation of a slow alias as part of a sloppy arguments objects.
+// For fast aliases (if HasSloppyArgumentsElements()):
// - the parameter map contains an index into the context
// - all attributes of the element have default values
// For slow aliases (if HasDictionaryArgumentsElements()):
@@ -6616,20 +8315,14 @@
// - all attributes are available as part if the property details
class AliasedArgumentsEntry: public Struct {
public:
- inline int aliased_context_slot();
+ inline int aliased_context_slot() const;
inline void set_aliased_context_slot(int count);
- static inline AliasedArgumentsEntry* cast(Object* obj);
+ DECLARE_CAST(AliasedArgumentsEntry)
-#ifdef OBJECT_PRINT
- inline void AliasedArgumentsEntryPrint() {
- AliasedArgumentsEntryPrint(stdout);
- }
- void AliasedArgumentsEntryPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void AliasedArgumentsEntryVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(AliasedArgumentsEntry)
+ DECLARE_VERIFIER(AliasedArgumentsEntry)
static const int kAliasedContextSlot = HeapObject::kHeaderSize;
static const int kSize = kAliasedContextSlot + kPointerSize;
@@ -6647,34 +8340,15 @@
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();
+ template <typename schar>
+ static inline uint32_t HashSequentialString(const schar* chars,
+ int length,
+ uint32_t seed);
- // Add a character to the hash and update the array index calculation.
- inline void AddCharacter(uint32_t c);
-
- // 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_; }
-
- bool is_valid() { return is_valid_; }
-
- void invalidate() { is_valid_ = false; }
+ // 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").
@@ -6686,29 +8360,47 @@
// use 27 instead.
static const int kZeroHash = 27;
- private:
- uint32_t array_index() {
- ASSERT(is_array_index());
- return array_index_;
- }
+ // Reusable parts of the hashing algorithm.
+ INLINE(static uint32_t AddCharacterCore(uint32_t running_hash, uint16_t c));
+ INLINE(static uint32_t GetHashCore(uint32_t running_hash));
- 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_;
bool is_first_char_;
- bool is_valid_;
- friend class TwoCharHashTableKey;
+ DISALLOW_COPY_AND_ASSIGN(StringHasher);
};
-// Calculates string hash.
-template <typename schar>
-inline uint32_t HashSequentialString(const schar* chars,
- int length,
- uint32_t seed);
+class IteratingStringHasher : public StringHasher {
+ public:
+ static inline uint32_t Hash(String* string, uint32_t seed);
+ inline void VisitOneByteString(const uint8_t* chars, int length);
+ inline void VisitTwoByteString(const uint16_t* chars, int length);
+
+ private:
+ inline IteratingStringHasher(int len, uint32_t seed)
+ : StringHasher(len, seed) {}
+ DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
+};
// The characteristics of a string are stored in its map. Retrieving these
@@ -6724,7 +8416,7 @@
// concrete performance benefit at that particular point in the code.
class StringShape BASE_EMBEDDED {
public:
- inline explicit StringShape(String* s);
+ inline explicit StringShape(const String* s);
inline explicit StringShape(Map* s);
inline explicit StringShape(InstanceType t);
inline bool IsSequential();
@@ -6732,11 +8424,11 @@
inline bool IsCons();
inline bool IsSliced();
inline bool IsIndirect();
- inline bool IsExternalAscii();
+ inline bool IsExternalOneByte();
inline bool IsExternalTwoByte();
- inline bool IsSequentialAscii();
+ inline bool IsSequentialOneByte();
inline bool IsSequentialTwoByte();
- inline bool IsSymbol();
+ inline bool IsInternalized();
inline StringRepresentationTag representation_tag();
inline uint32_t encoding_tag();
inline uint32_t full_representation_tag();
@@ -6760,6 +8452,132 @@
};
+// 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);
+ inline static bool Equals(Handle<Name> one, Handle<Name> two);
+
+ // Conversion.
+ inline bool AsArrayIndex(uint32_t* index);
+
+ // Whether name can only name own properties.
+ inline bool IsOwn();
+
+ DECLARE_CAST(Name)
+
+ 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_ASSERT((kArrayIndexLengthBits > 0));
+
+ class ArrayIndexValueBits : public BitField<unsigned int, kNofHashBitFields,
+ kArrayIndexValueBits> {}; // NOLINT
+ class ArrayIndexLengthBits : public BitField<unsigned int,
+ kNofHashBitFields + kArrayIndexValueBits,
+ kArrayIndexLengthBits> {}; // NOLINT
+
+ // 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_ASSERT(IS_POWER_OF_TWO(kMaxCachedArrayIndexLength + 1));
+
+ static const unsigned int kContainsCachedArrayIndexMask =
+ (~static_cast<unsigned>(kMaxCachedArrayIndexLength)
+ << ArrayIndexLengthBits::kShift) |
+ 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:
+ // [name]: the print name of a symbol, or undefined if none.
+ DECL_ACCESSORS(name, Object)
+
+ DECL_ACCESSORS(flags, Smi)
+
+ // [is_private]: whether this is a private symbol.
+ DECL_BOOLEAN_ACCESSORS(is_private)
+
+ // [is_own]: whether this is an own symbol, that is, only used to designate
+ // own properties of objects.
+ DECL_BOOLEAN_ACCESSORS(is_own)
+
+ DECLARE_CAST(Symbol)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(Symbol)
+ DECLARE_VERIFIER(Symbol)
+
+ // Layout description.
+ static const int kNameOffset = Name::kSize;
+ static const int kFlagsOffset = kNameOffset + kPointerSize;
+ static const int kSize = kFlagsOffset + kPointerSize;
+
+ typedef FixedBodyDescriptor<kNameOffset, kFlagsOffset, kSize> BodyDescriptor;
+
+ private:
+ static const int kPrivateBit = 0;
+ static const int kOwnBit = 1;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol);
+};
+
+
+class ConsString;
+
// The String abstract class captures JavaScript string values:
//
// Ecma-262:
@@ -6768,85 +8586,125 @@
// 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 };
+
+ // 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_ASSERT((kArrayIndexLengthBits > 0));
+
+ class ArrayIndexValueBits : public BitField<unsigned int, kNofHashBitFields,
+ kArrayIndexValueBits> {}; // NOLINT
+ class ArrayIndexLengthBits : public BitField<unsigned int,
+ kNofHashBitFields + kArrayIndexValueBits,
+ kArrayIndexLengthBits> {}; // NOLINT
+
+ // 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_ASSERT(IS_POWER_OF_TWO(kMaxCachedArrayIndexLength + 1));
+
+ static const unsigned int kContainsCachedArrayIndexMask =
+ (~static_cast<unsigned>(kMaxCachedArrayIndexLength)
+ << ArrayIndexLengthBits::kShift) |
+ kIsNotArrayIndexMask;
+
// 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
- // ASCII chars or two-byte UC16.
+ // one-byte chars or two-byte UC16.
// Returned by String::GetFlatContent().
class FlatContent {
public:
// Returns true if the string is flat and this structure contains content.
bool IsFlat() { return state_ != NON_FLAT; }
- // Returns true if the structure contains ASCII content.
- bool IsAscii() { return state_ == ASCII; }
+ // Returns true if the structure contains one-byte content.
+ bool IsOneByte() { return state_ == ONE_BYTE; }
// 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
- // true.
- Vector<const char> ToAsciiVector() {
- ASSERT_EQ(ASCII, state_);
- return Vector<const char>::cast(buffer_);
+ // Return the one byte content of the string. Only use if IsOneByte()
+ // returns true.
+ Vector<const uint8_t> ToOneByteVector() {
+ DCHECK_EQ(ONE_BYTE, state_);
+ return Vector<const uint8_t>(onebyte_start, length_);
}
// Return the two-byte content of the string. Only use if IsTwoByte()
// returns true.
Vector<const uc16> ToUC16Vector() {
- ASSERT_EQ(TWO_BYTE, state_);
- return Vector<const uc16>::cast(buffer_);
+ DCHECK_EQ(TWO_BYTE, state_);
+ return Vector<const uc16>(twobyte_start, length_);
+ }
+
+ uc16 Get(int i) {
+ DCHECK(i < length_);
+ DCHECK(state_ != NON_FLAT);
+ if (state_ == ONE_BYTE) return onebyte_start[i];
+ return twobyte_start[i];
}
private:
- enum State { NON_FLAT, ASCII, TWO_BYTE };
+ enum State { NON_FLAT, ONE_BYTE, TWO_BYTE };
// Constructors only used by String::GetFlatContent().
- explicit FlatContent(Vector<const char> chars)
- : buffer_(Vector<const byte>::cast(chars)),
- state_(ASCII) { }
- explicit FlatContent(Vector<const uc16> chars)
- : buffer_(Vector<const byte>::cast(chars)),
- state_(TWO_BYTE) { }
- FlatContent() : buffer_(), state_(NON_FLAT) { }
+ explicit FlatContent(const uint8_t* start, int length)
+ : onebyte_start(start), length_(length), state_(ONE_BYTE) {}
+ explicit FlatContent(const uc16* start, int length)
+ : twobyte_start(start), length_(length), state_(TWO_BYTE) { }
+ FlatContent() : onebyte_start(NULL), length_(0), state_(NON_FLAT) { }
- Vector<const byte> buffer_;
+ union {
+ const uint8_t* onebyte_start;
+ const uc16* twobyte_start;
+ };
+ int length_;
State state_;
friend class String;
};
// Get and set the length of the string.
- inline int length();
+ inline int length() const;
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);
+ // Get and set the length of the string using acquire loads and release
+ // stores.
+ inline int synchronized_length() const;
+ inline void synchronized_set_length(int 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
+ // Returns whether this string has only one-byte chars, i.e. all of them can
+ // be one-byte 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 IsTwoByteRepresentation();
+ // two-byte external representations even for one-byte data.
+ inline bool IsOneByteRepresentation() const;
+ inline bool IsTwoByteRepresentation() const;
// 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 HasOnlyOneByteChars();
// 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
// to this method are not efficient unless the string is flat.
- inline uint16_t Get(int index);
+ INLINE(uint16_t Get(int index));
- // Try to flatten the string. Checks first inline to see if it is
+ // Flattens the string. Checks first inline to see if it is
// necessary. Does nothing if the string is not a cons string.
// Flattening allocates a sequential string with the same data as
// the given string and mutates the cons string to a degenerate
@@ -6858,15 +8716,9 @@
//
// Degenerate cons strings are handled specially by the garbage
// collector (see IsShortcutCandidate).
- //
- // Use FlattenString from Handles.cc to flatten even in case an
- // allocation failure happens.
- inline MaybeObject* TryFlatten(PretenureFlag pretenure = NOT_TENURED);
- // Convenience function. Has exactly the same behavior as
- // TryFlatten(), except in the case of failure returns the original
- // string.
- inline String* TryFlattenGetString(PretenureFlag pretenure = NOT_TENURED);
+ static inline Handle<String> Flatten(Handle<String> string,
+ PretenureFlag pretenure = NOT_TENURED);
// Tries to return the content of a flat string as a structure holding either
// a flat vector of char or of uc16.
@@ -6880,18 +8732,14 @@
inline String* GetUnderlying();
// Mark the string as an undetectable object. It only applies to
- // ASCII and two byte string types.
+ // one-byte and two-byte string types.
bool MarkAsUndetectable();
- // Return a substring.
- MUST_USE_RESULT MaybeObject* SubString(int from,
- int to,
- PretenureFlag pretenure = NOT_TENURED);
-
// String equality operations.
inline bool Equals(String* other);
- bool IsEqualTo(Vector<const char> str);
- bool IsAsciiEqualTo(Vector<const char> str);
+ inline static bool Equals(Handle<String> one, Handle<String> two);
+ bool IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match = false);
+ bool IsOneByteEqualTo(Vector<const uint8_t> str);
bool IsTwoByteEqualTo(Vector<const uc16> str);
// Return a UTF8 representation of the string. The string is null
@@ -6921,29 +8769,16 @@
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);
- bool MakeExternal(v8::String::ExternalAsciiStringResource* resource);
+ bool MakeExternal(v8::String::ExternalOneByteStringResource* resource);
// Conversion.
inline bool AsArrayIndex(uint32_t* index);
- // Casting.
- static inline String* cast(Object* obj);
+ DECLARE_CAST(String)
void PrintOn(FILE* out);
@@ -6952,89 +8787,35 @@
// Dispatched behavior.
void StringShortPrint(StringStream* accumulator);
+ void PrintUC16(OStream& os, int start = 0, int end = -1); // NOLINT
#ifdef OBJECT_PRINT
- inline void StringPrint() {
- StringPrint(stdout);
- }
- void StringPrint(FILE* out);
-
char* ToAsciiArray();
#endif
-#ifdef DEBUG
- void StringVerify();
-#endif
+ DECLARE_PRINTER(String)
+ DECLARE_VERIFIER(String)
+
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;
+ STATIC_ASSERT(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits));
- // Max ASCII char code.
- static const int kMaxAsciiCharCode = unibrow::Utf8::kMaxOneByteChar;
- static const unsigned kMaxAsciiCharCodeU = unibrow::Utf8::kMaxOneByteChar;
+ // Max char codes.
+ static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar;
+ static const uint32_t kMaxOneByteCharCodeU = unibrow::Latin1::kMaxChar;
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;
+ static const uint32_t kMaxUtf16CodeUnitU = kMaxUtf16CodeUnit;
// Value of hash field containing computed hash equal to zero.
- static const int kZeroHash = kIsNotArrayIndexMask;
+ static const int kEmptyStringHash = kIsNotArrayIndexMask;
// Maximal string length.
- static const int kMaxLength = (1 << (32 - 2)) - 1;
+ static const int kMaxLength = (1 << 28) - 16;
// Max length for computing hash. For strings longer than this limit the
// string length is used as the hash value.
@@ -7044,21 +8825,8 @@
static const int kMaxShortPrintLength = 1024;
// Support for regular expressions.
- 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,
@@ -7066,73 +8834,92 @@
int from,
int to);
- static inline bool IsAscii(const char* chars, int length) {
+ // The return value may point to the first aligned word containing the first
+ // non-one-byte character, rather than directly to the non-one-byte character.
+ // If the return value is >= the passed length, the entire string was
+ // one-byte.
+ static inline int NonAsciiStart(const char* chars, int length) {
+ const char* start = chars;
const char* limit = chars + length;
-#ifdef V8_HOST_CAN_READ_UNALIGNED
- ASSERT(kMaxAsciiCharCode == 0x7F);
- const uintptr_t non_ascii_mask = kUintptrAllBitsSet / 0xFF * 0x80;
- while (chars <= limit - sizeof(uintptr_t)) {
- if (*reinterpret_cast<const uintptr_t*>(chars) & non_ascii_mask) {
- return false;
+
+ if (length >= kIntptrSize) {
+ // Check unaligned bytes.
+ while (!IsAligned(reinterpret_cast<intptr_t>(chars), sizeof(uintptr_t))) {
+ if (static_cast<uint8_t>(*chars) > unibrow::Utf8::kMaxOneByteChar) {
+ return static_cast<int>(chars - start);
+ }
+ ++chars;
}
- chars += sizeof(uintptr_t);
+ // Check aligned words.
+ DCHECK(unibrow::Utf8::kMaxOneByteChar == 0x7F);
+ const uintptr_t non_one_byte_mask = kUintptrAllBitsSet / 0xFF * 0x80;
+ while (chars + sizeof(uintptr_t) <= limit) {
+ if (*reinterpret_cast<const uintptr_t*>(chars) & non_one_byte_mask) {
+ return static_cast<int>(chars - start);
+ }
+ chars += sizeof(uintptr_t);
+ }
}
-#endif
+ // Check remaining unaligned bytes.
while (chars < limit) {
- if (static_cast<uint8_t>(*chars) > kMaxAsciiCharCodeU) return false;
+ if (static_cast<uint8_t>(*chars) > unibrow::Utf8::kMaxOneByteChar) {
+ return static_cast<int>(chars - start);
+ }
++chars;
}
- return true;
+
+ return static_cast<int>(chars - start);
}
- static inline bool IsAscii(const uc16* chars, int length) {
+ static inline bool IsAscii(const char* chars, int length) {
+ return NonAsciiStart(chars, length) >= length;
+ }
+
+ static inline 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 false;
+ if (*chars > kMaxOneByteCharCodeU) return static_cast<int>(chars - start);
++chars;
}
- return true;
+ return static_cast<int>(chars - start);
}
- 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;
- };
+ static inline bool IsOneByte(const uc16* chars, int length) {
+ return NonOneByteStart(chars, length) >= length;
+ }
- 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);
+
+ static Handle<FixedArray> CalculateLineEnds(Handle<String> string,
+ bool include_ending_line);
+
+ // Use the hash field to forward to the canonical internalized string
+ // when deserializing an internalized string.
+ inline void SetForwardedInternalizedString(String* string);
+ inline String* GetForwardedInternalizedString();
private:
- // 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);
+ friend class Name;
+ friend class StringTableInsertionKey;
- static inline bool IsHashFieldComputed(uint32_t field);
+ static Handle<String> SlowFlatten(Handle<ConsString> cons,
+ PretenureFlag tenure);
// 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);
+ static bool SlowEquals(Handle<String> one, Handle<String> two);
+
// Slow case of AsArrayIndex.
bool SlowAsArrayIndex(uint32_t* index);
@@ -7146,61 +8933,54 @@
// The SeqString abstract class captures sequential string values.
class SeqString: public String {
public:
- // Casting.
- static inline SeqString* cast(Object* obj);
+ DECLARE_CAST(SeqString)
// 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 static Handle<String> Truncate(Handle<SeqString> string,
+ int new_length);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString);
};
-// The AsciiString class captures sequential ASCII string objects.
-// Each character in the AsciiString is an ASCII character.
-class SeqAsciiString: public SeqString {
+// The OneByteString class captures sequential one-byte string objects.
+// Each character in the OneByteString is an one-byte character.
+class SeqOneByteString: public SeqString {
public:
- static const bool kHasAsciiEncoding = true;
+ static const bool kHasOneByteEncoding = 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);
+ DECLARE_CAST(SeqOneByteString)
// Garbage collection support. This method is called by the
- // garbage collector to compute the actual size of an AsciiString
+ // garbage collector to compute the actual size of an OneByteString
// instance.
- inline int SeqAsciiStringSize(InstanceType instance_type);
+ inline int SeqOneByteStringSize(InstanceType instance_type);
- // Computes the size for an AsciiString instance of a given length.
+ // Computes the size for an OneByteString instance of a given length.
static int SizeFor(int length) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length * kCharSize);
}
- // Maximal memory usage for a single sequential ASCII string.
+ // Maximal memory usage for a single sequential one-byte string.
static const int kMaxSize = 512 * MB - 1;
- // Maximal length of a single sequential ASCII string.
- // 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);
+ STATIC_ASSERT((kMaxSize - kHeaderSize) >= String::kMaxLength);
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(SeqAsciiString);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SeqOneByteString);
};
@@ -7208,7 +8988,7 @@
// Each character in the TwoByteString is a two-byte uint16_t.
class SeqTwoByteString: public SeqString {
public:
- static const bool kHasAsciiEncoding = false;
+ static const bool kHasOneByteEncoding = false;
// Dispatched behavior.
inline uint16_t SeqTwoByteStringGet(int index);
@@ -7222,8 +9002,7 @@
// For regexp code.
const uint16_t* SeqTwoByteStringGetData(unsigned start);
- // Casting
- static inline SeqTwoByteString* cast(Object* obj);
+ DECLARE_CAST(SeqTwoByteString)
// Garbage collection support. This method is called by the
// garbage collector to compute the actual size of a TwoByteString
@@ -7237,14 +9016,8 @@
// Maximal memory usage for a single sequential two-byte string.
static const int kMaxSize = 512 * MB - 1;
- // Maximal length of a single sequential two-byte string.
- // 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);
+ STATIC_ASSERT(static_cast<int>((kMaxSize - kHeaderSize)/sizeof(uint16_t)) >=
+ String::kMaxLength);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SeqTwoByteString);
@@ -7280,31 +9053,20 @@
// Dispatched behavior.
uint16_t ConsStringGet(int index);
- // Casting.
- static inline ConsString* cast(Object* obj);
+ DECLARE_CAST(ConsString)
// Layout description.
static const int kFirstOffset = POINTER_SIZE_ALIGN(String::kSize);
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;
typedef FixedBodyDescriptor<kFirstOffset, kSecondOffset + kPointerSize, kSize>
BodyDescriptor;
-#ifdef DEBUG
- void ConsStringVerify();
-#endif
+ DECLARE_VERIFIER(ConsString)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ConsString);
@@ -7326,28 +9088,21 @@
class SlicedString: public String {
public:
inline String* parent();
- inline void set_parent(String* parent);
- inline int offset();
+ inline void set_parent(String* parent,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+ inline int offset() const;
inline void set_offset(int offset);
// Dispatched behavior.
uint16_t SlicedStringGet(int index);
- // Casting.
- static inline SlicedString* cast(Object* obj);
+ DECLARE_CAST(SlicedString)
// Layout description.
static const int kParentOffset = POINTER_SIZE_ALIGN(String::kSize);
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;
@@ -7355,9 +9110,7 @@
kOffsetOffset + kPointerSize, kSize>
BodyDescriptor;
-#ifdef DEBUG
- void SlicedStringVerify();
-#endif
+ DECLARE_VERIFIER(SlicedString)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SlicedString);
@@ -7375,8 +9128,7 @@
// API. Therefore, ExternalStrings should not be used internally.
class ExternalString: public String {
public:
- // Casting
- static inline ExternalString* cast(Object* obj);
+ DECLARE_CAST(ExternalString)
// Layout description.
static const int kResourceOffset = POINTER_SIZE_ALIGN(String::kSize);
@@ -7384,23 +9136,26 @@
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();
- STATIC_CHECK(kResourceOffset == Internals::kStringResourceOffset);
+ STATIC_ASSERT(kResourceOffset == Internals::kStringResourceOffset);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalString);
};
-// The ExternalAsciiString class is an external string backed by an
-// ASCII string.
-class ExternalAsciiString: public ExternalString {
+// The ExternalOneByteString class is an external string backed by an
+// one-byte string.
+class ExternalOneByteString : public ExternalString {
public:
- static const bool kHasAsciiEncoding = true;
+ static const bool kHasOneByteEncoding = true;
- typedef v8::String::ExternalAsciiStringResource Resource;
+ typedef v8::String::ExternalOneByteStringResource Resource;
// The underlying resource.
inline const Resource* resource();
@@ -7412,30 +9167,21 @@
// 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);
+ inline uint16_t ExternalOneByteStringGet(int index);
- // Casting.
- static inline ExternalAsciiString* cast(Object* obj);
+ DECLARE_CAST(ExternalOneByteString)
// Garbage collection support.
- inline void ExternalAsciiStringIterateBody(ObjectVisitor* v);
+ inline void ExternalOneByteStringIterateBody(ObjectVisitor* v);
- 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);
+ template <typename StaticVisitor>
+ inline void ExternalOneByteStringIterateBody();
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalAsciiString);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalOneByteString);
};
@@ -7443,7 +9189,7 @@
// encoded string.
class ExternalTwoByteString: public ExternalString {
public:
- static const bool kHasAsciiEncoding = false;
+ static const bool kHasOneByteEncoding = false;
typedef v8::String::ExternalStringResource Resource;
@@ -7465,8 +9211,7 @@
// For regexp code.
inline const uint16_t* ExternalTwoByteStringGetData(unsigned start);
- // Casting.
- static inline ExternalTwoByteString* cast(Object* obj);
+ DECLARE_CAST(ExternalTwoByteString)
// Garbage collection support.
inline void ExternalTwoByteStringIterateBody(ObjectVisitor* v);
@@ -7474,12 +9219,6 @@
template<typename StaticVisitor>
inline void ExternalTwoByteStringIterateBody();
-
- // Support for StringInputBuffer.
- void ExternalTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
- unsigned* offset_ptr,
- unsigned chars);
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString);
};
@@ -7495,13 +9234,14 @@
virtual void IterateInstance(ObjectVisitor* v) { }
virtual void PostGarbageCollection() { }
- static void PostGarbageCollectionProcessing();
+ static void PostGarbageCollectionProcessing(Isolate* isolate);
static int ArchiveSpacePerThread();
static char* ArchiveState(Isolate* isolate, char* to);
static char* RestoreState(Isolate* isolate, char* from);
- static void Iterate(ObjectVisitor* v);
+ static void Iterate(Isolate* isolate, ObjectVisitor* v);
static void Iterate(ObjectVisitor* v, Relocatable* top);
static char* Iterate(ObjectVisitor* v, char* t);
+
private:
Isolate* isolate_;
Relocatable* prev_;
@@ -7520,38 +9260,95 @@
int length() { return length_; }
private:
String** str_;
- bool is_ascii_;
+ bool is_one_byte_;
int length_;
const void* start_;
};
-// 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
+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() {}
+ inline explicit ConsStringIteratorOp(ConsString* cons_string,
+ int offset = 0) {
+ Reset(cons_string, offset);
+ }
+ inline void Reset(ConsString* cons_string, int offset = 0) {
+ depth_ = 0;
+ // Next will always return NULL.
+ if (cons_string == NULL) return;
+ Initialize(cons_string, offset);
+ }
+ // Returns NULL when complete.
+ inline String* Next(int* offset_out) {
+ *offset_out = 0;
+ if (depth_ == 0) return NULL;
+ return Continue(offset_out);
+ }
+
+ private:
+ static const int kStackSize = 32;
+ // Use a mask instead of doing modulo operations for stack wrapping.
+ static const int kDepthMask = kStackSize-1;
+ STATIC_ASSERT(IS_POWER_OF_TWO(kStackSize));
+ static inline int OffsetForDepth(int depth);
+
+ inline void PushLeft(ConsString* string);
+ inline void PushRight(ConsString* string);
+ inline void AdjustMaximumDepth();
+ inline void Pop();
+ inline bool StackBlown() { return maximum_depth_ - depth_ == kStackSize; }
+ void Initialize(ConsString* cons_string, int offset);
+ String* Continue(int* offset_out);
+ String* NextLeaf(bool* blew_stack);
+ String* Search(int* offset_out);
+
+ // Stack must always contain only frames for which right traversal
+ // has not yet been performed.
+ ConsString* frames_[kStackSize];
+ ConsString* root_;
+ int depth_;
+ int maximum_depth_;
+ int consumed_;
+ DISALLOW_COPY_AND_ASSIGN(ConsStringIteratorOp);
+};
+
+
+class StringCharacterStream {
+ public:
+ inline StringCharacterStream(String* string,
+ ConsStringIteratorOp* op,
+ int offset = 0);
+ inline uint16_t GetNext();
+ inline bool HasMore();
+ inline void Reset(String* string, int offset = 0);
+ inline void VisitOneByteString(const uint8_t* chars, int length);
+ inline void VisitTwoByteString(const uint16_t* chars, int 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);
};
@@ -7577,21 +9374,20 @@
// [to_number]: Cached to_number computed at startup.
DECL_ACCESSORS(to_number, Object)
- inline byte kind();
+ inline byte kind() const;
inline void set_kind(byte kind);
- // Casting.
- static inline Oddball* cast(Object* obj);
+ DECLARE_CAST(Oddball)
// Dispatched behavior.
-#ifdef DEBUG
- void OddballVerify();
-#endif
+ DECLARE_VERIFIER(Oddball)
// Initialize the fields.
- MUST_USE_RESULT MaybeObject* Initialize(const char* to_string,
- Object* to_number,
- byte kind);
+ static void Initialize(Isolate* isolate,
+ Handle<Oddball> oddball,
+ const char* to_string,
+ Handle<Object> to_number,
+ byte kind);
// Layout description.
static const int kToStringOffset = HeapObject::kHeaderSize;
@@ -7606,34 +9402,43 @@
static const byte kNull = 3;
static const byte kArgumentMarker = 4;
static const byte kUndefined = 5;
- static const byte kOther = 6;
+ static const byte kUninitialized = 6;
+ static const byte kOther = 7;
+ static const byte kException = 8;
typedef FixedBodyDescriptor<kToStringOffset,
kToNumberOffset + kPointerSize,
kSize> BodyDescriptor;
+ STATIC_ASSERT(kKindOffset == Internals::kOddballKindOffset);
+ STATIC_ASSERT(kNull == Internals::kNullOddballKind);
+ STATIC_ASSERT(kUndefined == Internals::kUndefinedOddballKind);
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Oddball);
};
-class JSGlobalPropertyCell: public HeapObject {
+class Cell: public HeapObject {
public:
// [value]: value of the global property.
DECL_ACCESSORS(value, Object)
- // Casting.
- static inline JSGlobalPropertyCell* cast(Object* obj);
+ DECLARE_CAST(Cell)
-#ifdef DEBUG
- void JSGlobalPropertyCellVerify();
-#endif
-#ifdef OBJECT_PRINT
- inline void JSGlobalPropertyCellPrint() {
- JSGlobalPropertyCellPrint(stdout);
+ static inline Cell* FromValueAddress(Address value) {
+ Object* result = FromAddress(value - kValueOffset);
+ DCHECK(result->IsCell() || result->IsPropertyCell());
+ return static_cast<Cell*>(result);
}
- void JSGlobalPropertyCellPrint(FILE* out);
-#endif
+
+ inline Address ValueAddress() {
+ return address() + kValueOffset;
+ }
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(Cell)
+ DECLARE_VERIFIER(Cell)
// Layout description.
static const int kValueOffset = HeapObject::kHeaderSize;
@@ -7644,7 +9449,60 @@
kSize> BodyDescriptor;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalPropertyCell);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Cell);
+};
+
+
+class PropertyCell: public Cell {
+ public:
+ // [type]: type of the global property.
+ HeapType* type();
+ void set_type(HeapType* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
+ // [dependent_code]: dependent code that depends on the type of the global
+ // property.
+ DECL_ACCESSORS(dependent_code, DependentCode)
+
+ // Sets the value of the cell and updates the type field to be the union
+ // of the cell's current type and the value's type. If the change causes
+ // a change of the type of the cell's contents, code dependent on the cell
+ // will be deoptimized.
+ static void SetValueInferType(Handle<PropertyCell> cell,
+ Handle<Object> value);
+
+ // Computes the new type of the cell's contents for the given value, but
+ // without actually modifying the 'type' field.
+ static Handle<HeapType> UpdatedType(Handle<PropertyCell> cell,
+ Handle<Object> value);
+
+ static void AddDependentCompilationInfo(Handle<PropertyCell> cell,
+ CompilationInfo* info);
+
+ DECLARE_CAST(PropertyCell)
+
+ inline Address TypeAddress() {
+ return address() + kTypeOffset;
+ }
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(PropertyCell)
+ DECLARE_VERIFIER(PropertyCell)
+
+ // Layout description.
+ static const int kTypeOffset = kValueOffset + kPointerSize;
+ static const int kDependentCodeOffset = kTypeOffset + kPointerSize;
+ static const int kSize = kDependentCodeOffset + kPointerSize;
+
+ static const int kPointerFieldsBeginOffset = kValueOffset;
+ static const int kPointerFieldsEndOffset = kDependentCodeOffset;
+
+ typedef FixedBodyDescriptor<kValueOffset,
+ kSize,
+ kSize> BodyDescriptor;
+
+ private:
+ DECL_ACCESSORS(type_raw, Object)
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyCell);
};
@@ -7657,77 +9515,56 @@
// [hash]: The hash code property (undefined if not initialized yet).
DECL_ACCESSORS(hash, Object)
- // Casting.
- static inline JSProxy* cast(Object* obj);
+ DECLARE_CAST(JSProxy)
- bool HasPropertyWithHandler(String* name);
- bool HasElementWithHandler(uint32_t index);
-
- MUST_USE_RESULT MaybeObject* GetPropertyWithHandler(
- Object* receiver,
- String* name);
- MUST_USE_RESULT MaybeObject* GetElementWithHandler(
- Object* receiver,
+ MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithHandler(
+ Handle<JSProxy> proxy,
+ Handle<Object> receiver,
+ Handle<Name> name);
+ MUST_USE_RESULT static inline MaybeHandle<Object> GetElementWithHandler(
+ Handle<JSProxy> proxy,
+ Handle<Object> receiver,
uint32_t index);
- MUST_USE_RESULT MaybeObject* SetPropertyWithHandler(
- String* name,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetElementWithHandler(
- uint32_t index,
- Object* value,
- StrictModeFlag strict_mode);
+ // If the handler defines an accessor property with a setter, invoke it.
+ // If it defines an accessor property without a setter, or a data property
+ // that is read-only, throw. In all these cases set '*done' to true,
+ // otherwise set it to false.
+ MUST_USE_RESULT
+ static MaybeHandle<Object> SetPropertyViaPrototypesWithHandler(
+ Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
+ Handle<Object> value, StrictMode strict_mode, bool* done);
- // If the handler defines an accessor property, invoke its setter
- // (or throw if only a getter exists) and set *found to true. Otherwise false.
- MUST_USE_RESULT MaybeObject* SetPropertyWithHandlerIfDefiningSetter(
- String* name,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool* found);
+ MUST_USE_RESULT static Maybe<PropertyAttributes>
+ GetPropertyAttributesWithHandler(Handle<JSProxy> proxy,
+ Handle<Object> receiver,
+ Handle<Name> name);
+ MUST_USE_RESULT static Maybe<PropertyAttributes>
+ GetElementAttributeWithHandler(Handle<JSProxy> proxy,
+ Handle<JSReceiver> receiver,
+ uint32_t index);
+ MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithHandler(
+ Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
+ Handle<Object> value, StrictMode strict_mode);
- MUST_USE_RESULT MaybeObject* DeletePropertyWithHandler(
- String* name,
- DeleteMode mode);
- MUST_USE_RESULT MaybeObject* DeleteElementWithHandler(
- uint32_t index,
- DeleteMode mode);
-
- MUST_USE_RESULT PropertyAttributes GetPropertyAttributeWithHandler(
- JSReceiver* receiver,
- String* name);
- MUST_USE_RESULT PropertyAttributes GetElementAttributeWithHandler(
- JSReceiver* receiver,
- uint32_t index);
-
- MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
-
- // Turn this into an (empty) JSObject.
- void Fix();
+ // Turn the proxy into an (empty) JSObject.
+ static void Fix(Handle<JSProxy> proxy);
// Initializes the body after the handler slot.
inline void InitializeBody(int object_size, Object* value);
// Invoke a trap by name. If the trap does not exist on this's handler,
// but derived_trap is non-NULL, invoke that instead. May cause GC.
- Handle<Object> CallTrap(const char* name,
- Handle<Object> derived_trap,
- int argc,
- Handle<Object> args[]);
+ MUST_USE_RESULT static MaybeHandle<Object> CallTrap(
+ Handle<JSProxy> proxy,
+ const char* name,
+ Handle<Object> derived_trap,
+ int argc,
+ Handle<Object> args[]);
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSProxyPrint() {
- JSProxyPrint(stdout);
- }
- void JSProxyPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSProxyVerify();
-#endif
+ DECLARE_PRINTER(JSProxy)
+ DECLARE_VERIFIER(JSProxy)
// Layout description. We add padding so that a proxy has the same
// size as a virgin JSObject. This is essential for becoming a JSObject
@@ -7739,13 +9576,40 @@
static const int kHeaderSize = kPaddingOffset;
static const int kPaddingSize = kSize - kPaddingOffset;
- STATIC_CHECK(kPaddingSize >= 0);
+ STATIC_ASSERT(kPaddingSize >= 0);
typedef FixedBodyDescriptor<kHandlerOffset,
kPaddingOffset,
kSize> BodyDescriptor;
private:
+ friend class JSReceiver;
+
+ MUST_USE_RESULT static inline MaybeHandle<Object> SetElementWithHandler(
+ Handle<JSProxy> proxy,
+ Handle<JSReceiver> receiver,
+ uint32_t index,
+ Handle<Object> value,
+ StrictMode strict_mode);
+
+ MUST_USE_RESULT static Maybe<bool> HasPropertyWithHandler(
+ Handle<JSProxy> proxy, Handle<Name> name);
+ MUST_USE_RESULT static inline Maybe<bool> HasElementWithHandler(
+ Handle<JSProxy> proxy, uint32_t index);
+
+ MUST_USE_RESULT static MaybeHandle<Object> DeletePropertyWithHandler(
+ Handle<JSProxy> proxy,
+ Handle<Name> name,
+ DeleteMode mode);
+ MUST_USE_RESULT static MaybeHandle<Object> DeleteElementWithHandler(
+ Handle<JSProxy> proxy,
+ uint32_t index,
+ DeleteMode mode);
+
+ MUST_USE_RESULT Object* GetIdentityHash();
+
+ static Handle<Smi> GetOrCreateIdentityHash(Handle<JSProxy> proxy);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxy);
};
@@ -7758,19 +9622,11 @@
// [construct_trap]: The construct trap.
DECL_ACCESSORS(construct_trap, Object)
- // Casting.
- static inline JSFunctionProxy* cast(Object* obj);
+ DECLARE_CAST(JSFunctionProxy)
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSFunctionProxyPrint() {
- JSFunctionProxyPrint(stdout);
- }
- void JSFunctionProxyPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSFunctionProxyVerify();
-#endif
+ DECLARE_PRINTER(JSFunctionProxy)
+ DECLARE_VERIFIER(JSFunctionProxy)
// Layout description.
static const int kCallTrapOffset = JSProxy::kPaddingOffset;
@@ -7779,7 +9635,7 @@
static const int kSize = JSFunction::kSize;
static const int kPaddingSize = kSize - kPaddingOffset;
- STATIC_CHECK(kPaddingSize >= 0);
+ STATIC_ASSERT(kPaddingSize >= 0);
typedef FixedBodyDescriptor<kHandlerOffset,
kConstructTrapOffset + kPointerSize,
@@ -7790,62 +9646,155 @@
};
-// The JSSet describes EcmaScript Harmony sets
-class JSSet: public JSObject {
+class JSCollection : public JSObject {
public:
- // [set]: the backing hash set containing keys.
+ // [table]: the backing hash table
DECL_ACCESSORS(table, Object)
- // Casting.
- static inline JSSet* cast(Object* obj);
-
-#ifdef OBJECT_PRINT
- inline void JSSetPrint() {
- JSSetPrint(stdout);
- }
- void JSSetPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSSetVerify();
-#endif
-
static const int kTableOffset = JSObject::kHeaderSize;
static const int kSize = kTableOffset + kPointerSize;
private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSCollection);
+};
+
+
+// The JSSet describes EcmaScript Harmony sets
+class JSSet : public JSCollection {
+ public:
+ DECLARE_CAST(JSSet)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSSet)
+ DECLARE_VERIFIER(JSSet)
+
+ private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSSet);
};
// The JSMap describes EcmaScript Harmony maps
-class JSMap: public JSObject {
+class JSMap : public JSCollection {
public:
- // [table]: the backing hash table mapping keys to values.
- DECL_ACCESSORS(table, Object)
+ DECLARE_CAST(JSMap)
- // Casting.
- static inline JSMap* cast(Object* obj);
-
-#ifdef OBJECT_PRINT
- inline void JSMapPrint() {
- JSMapPrint(stdout);
- }
- void JSMapPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSMapVerify();
-#endif
-
- static const int kTableOffset = JSObject::kHeaderSize;
- static const int kSize = kTableOffset + kPointerSize;
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSMap)
+ DECLARE_VERIFIER(JSMap)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSMap);
};
-// The JSWeakMap describes EcmaScript Harmony weak maps
-class JSWeakMap: public JSObject {
+// OrderedHashTableIterator is an iterator that iterates over the keys and
+// values of an OrderedHashTable.
+//
+// The iterator has a reference to the underlying OrderedHashTable data,
+// [table], as well as the current [index] the iterator is at.
+//
+// When the OrderedHashTable is rehashed it adds a reference from the old table
+// to the new table as well as storing enough data about the changes so that the
+// iterator [index] can be adjusted accordingly.
+//
+// When the [Next] result from the iterator is requested, the iterator checks if
+// there is a newer table that it needs to transition to.
+template<class Derived, class TableType>
+class OrderedHashTableIterator: public JSObject {
+ public:
+ // [table]: the backing hash table mapping keys to values.
+ DECL_ACCESSORS(table, Object)
+
+ // [index]: The index into the data table.
+ DECL_ACCESSORS(index, Object)
+
+ // [kind]: The kind of iteration this is. One of the [Kind] enum values.
+ DECL_ACCESSORS(kind, Object)
+
+#ifdef OBJECT_PRINT
+ void OrderedHashTableIteratorPrint(OStream& os); // NOLINT
+#endif
+
+ static const int kTableOffset = JSObject::kHeaderSize;
+ static const int kIndexOffset = kTableOffset + kPointerSize;
+ static const int kKindOffset = kIndexOffset + kPointerSize;
+ static const int kSize = kKindOffset + kPointerSize;
+
+ enum Kind {
+ kKindKeys = 1,
+ kKindValues = 2,
+ kKindEntries = 3
+ };
+
+ // Whether the iterator has more elements. This needs to be called before
+ // calling |CurrentKey| and/or |CurrentValue|.
+ bool HasMore();
+
+ // Move the index forward one.
+ void MoveNext() {
+ set_index(Smi::FromInt(Smi::cast(index())->value() + 1));
+ }
+
+ // Populates the array with the next key and value and then moves the iterator
+ // forward.
+ // This returns the |kind| or 0 if the iterator is already at the end.
+ Smi* Next(JSArray* value_array);
+
+ // Returns the current key of the iterator. This should only be called when
+ // |HasMore| returns true.
+ inline Object* CurrentKey();
+
+ private:
+ // Transitions the iterator to the non obsolete backing store. This is a NOP
+ // if the [table] is not obsolete.
+ void Transition();
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(OrderedHashTableIterator);
+};
+
+
+class JSSetIterator: public OrderedHashTableIterator<JSSetIterator,
+ OrderedHashSet> {
+ public:
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSSetIterator)
+ DECLARE_VERIFIER(JSSetIterator)
+
+ DECLARE_CAST(JSSetIterator)
+
+ // Called by |Next| to populate the array. This allows the subclasses to
+ // populate the array differently.
+ inline void PopulateValueArray(FixedArray* array);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSSetIterator);
+};
+
+
+class JSMapIterator: public OrderedHashTableIterator<JSMapIterator,
+ OrderedHashMap> {
+ public:
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSMapIterator)
+ DECLARE_VERIFIER(JSMapIterator)
+
+ DECLARE_CAST(JSMapIterator)
+
+ // Called by |Next| to populate the array. This allows the subclasses to
+ // populate the array differently.
+ inline void PopulateValueArray(FixedArray* array);
+
+ private:
+ // Returns the current value of the iterator. This should only be called when
+ // |HasMore| returns true.
+ inline Object* CurrentValue();
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSMapIterator);
+};
+
+
+// Base class for both JSWeakMap and JSWeakSet
+class JSWeakCollection: public JSObject {
public:
// [table]: the backing hash table mapping keys to values.
DECL_ACCESSORS(table, Object)
@@ -7853,28 +9802,180 @@
// [next]: linked list of encountered weak maps during GC.
DECL_ACCESSORS(next, Object)
- // Casting.
- static inline JSWeakMap* cast(Object* obj);
-
-#ifdef OBJECT_PRINT
- inline void JSWeakMapPrint() {
- JSWeakMapPrint(stdout);
- }
- void JSWeakMapPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSWeakMapVerify();
-#endif
-
static const int kTableOffset = JSObject::kHeaderSize;
static const int kNextOffset = kTableOffset + kPointerSize;
static const int kSize = kNextOffset + kPointerSize;
private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakCollection);
+};
+
+
+// The JSWeakMap describes EcmaScript Harmony weak maps
+class JSWeakMap: public JSWeakCollection {
+ public:
+ DECLARE_CAST(JSWeakMap)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSWeakMap)
+ DECLARE_VERIFIER(JSWeakMap)
+
+ private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakMap);
};
+// The JSWeakSet describes EcmaScript Harmony weak sets
+class JSWeakSet: public JSWeakCollection {
+ public:
+ DECLARE_CAST(JSWeakSet)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSWeakSet)
+ DECLARE_VERIFIER(JSWeakSet)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakSet);
+};
+
+
+class JSArrayBuffer: public JSObject {
+ public:
+ // [backing_store]: backing memory for this array
+ DECL_ACCESSORS(backing_store, void)
+
+ // [byte_length]: length in bytes
+ DECL_ACCESSORS(byte_length, Object)
+
+ // [flags]
+ DECL_ACCESSORS(flag, Smi)
+
+ inline bool is_external();
+ inline void set_is_external(bool value);
+
+ inline bool should_be_freed();
+ inline void set_should_be_freed(bool value);
+
+ // [weak_next]: linked list of array buffers.
+ DECL_ACCESSORS(weak_next, Object)
+
+ // [weak_first_array]: weak linked list of views.
+ DECL_ACCESSORS(weak_first_view, Object)
+
+ DECLARE_CAST(JSArrayBuffer)
+
+ // Neutering. Only neuters the buffer, not associated typed arrays.
+ void Neuter();
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSArrayBuffer)
+ DECLARE_VERIFIER(JSArrayBuffer)
+
+ static const int kBackingStoreOffset = JSObject::kHeaderSize;
+ static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize;
+ static const int kFlagOffset = kByteLengthOffset + kPointerSize;
+ static const int kWeakNextOffset = kFlagOffset + kPointerSize;
+ static const int kWeakFirstViewOffset = kWeakNextOffset + kPointerSize;
+ static const int kSize = kWeakFirstViewOffset + kPointerSize;
+
+ static const int kSizeWithInternalFields =
+ kSize + v8::ArrayBuffer::kInternalFieldCount * kPointerSize;
+
+ private:
+ // Bit position in a flag
+ static const int kIsExternalBit = 0;
+ static const int kShouldBeFreed = 1;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer);
+};
+
+
+class JSArrayBufferView: public JSObject {
+ public:
+ // [buffer]: ArrayBuffer that this typed array views.
+ DECL_ACCESSORS(buffer, Object)
+
+ // [byte_length]: offset of typed array in bytes.
+ DECL_ACCESSORS(byte_offset, Object)
+
+ // [byte_length]: length of typed array in bytes.
+ DECL_ACCESSORS(byte_length, Object)
+
+ // [weak_next]: linked list of typed arrays over the same array buffer.
+ DECL_ACCESSORS(weak_next, Object)
+
+ DECLARE_CAST(JSArrayBufferView)
+
+ DECLARE_VERIFIER(JSArrayBufferView)
+
+ static const int kBufferOffset = JSObject::kHeaderSize;
+ static const int kByteOffsetOffset = kBufferOffset + kPointerSize;
+ static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize;
+ static const int kWeakNextOffset = kByteLengthOffset + kPointerSize;
+ static const int kViewSize = kWeakNextOffset + kPointerSize;
+
+ protected:
+ void NeuterView();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBufferView);
+};
+
+
+class JSTypedArray: public JSArrayBufferView {
+ public:
+ // [length]: length of typed array in elements.
+ DECL_ACCESSORS(length, Object)
+
+ // Neutering. Only neuters this typed array.
+ void Neuter();
+
+ DECLARE_CAST(JSTypedArray)
+
+ ExternalArrayType type();
+ size_t element_size();
+
+ Handle<JSArrayBuffer> GetBuffer();
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSTypedArray)
+ DECLARE_VERIFIER(JSTypedArray)
+
+ static const int kLengthOffset = kViewSize + kPointerSize;
+ static const int kSize = kLengthOffset + kPointerSize;
+
+ static const int kSizeWithInternalFields =
+ kSize + v8::ArrayBufferView::kInternalFieldCount * kPointerSize;
+
+ private:
+ static Handle<JSArrayBuffer> MaterializeArrayBuffer(
+ Handle<JSTypedArray> typed_array);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
+};
+
+
+class JSDataView: public JSArrayBufferView {
+ public:
+ // Only neuters this DataView
+ void Neuter();
+
+ DECLARE_CAST(JSDataView)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSDataView)
+ DECLARE_VERIFIER(JSDataView)
+
+ static const int kSize = kViewSize;
+
+ static const int kSizeWithInternalFields =
+ kSize + v8::ArrayBufferView::kInternalFieldCount * kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSDataView);
+};
+
+
// Foreign describes objects pointing from JavaScript to C structures.
// Since they cannot contain references to JS HeapObjects they can be
// placed in old_data_space.
@@ -7884,8 +9985,7 @@
inline Address foreign_address();
inline void set_foreign_address(Address value);
- // Casting.
- static inline Foreign* cast(Object* obj);
+ DECLARE_CAST(Foreign)
// Dispatched behavior.
inline void ForeignIterateBody(ObjectVisitor* v);
@@ -7893,22 +9993,16 @@
template<typename StaticVisitor>
inline void ForeignIterateBody();
-#ifdef OBJECT_PRINT
- inline void ForeignPrint() {
- ForeignPrint(stdout);
- }
- void ForeignPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ForeignVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(Foreign)
+ DECLARE_VERIFIER(Foreign)
// Layout description.
static const int kForeignAddressOffset = HeapObject::kHeaderSize;
static const int kSize = kForeignAddressOffset + kPointerSize;
- STATIC_CHECK(kForeignAddressOffset == Internals::kForeignAddressOffset);
+ STATIC_ASSERT(kForeignAddressOffset == Internals::kForeignAddressOffset);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Foreign);
@@ -7929,38 +10023,45 @@
// is set to a smi. This matches the set function on FixedArray.
inline void set_length(Smi* length);
- MUST_USE_RESULT MaybeObject* JSArrayUpdateLengthFromIndex(uint32_t index,
- Object* value);
+ static void JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
+ uint32_t index,
+ Handle<Object> value);
+
+ static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map);
+ static bool WouldChangeReadOnlyLength(Handle<JSArray> array, uint32_t index);
+ static MaybeHandle<Object> ReadOnlyLengthError(Handle<JSArray> array);
// 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);
+ static void Initialize(Handle<JSArray> array, int capacity, int length = 0);
// Initializes the array to a certain length.
inline bool AllowsSetElementsLength();
- MUST_USE_RESULT MaybeObject* SetElementsLength(Object* length);
+ // Can cause GC.
+ MUST_USE_RESULT static MaybeHandle<Object> SetElementsLength(
+ Handle<JSArray> array,
+ Handle<Object> length);
// Set the content of the array to the content of storage.
- MUST_USE_RESULT inline MaybeObject* SetContent(FixedArrayBase* storage);
+ static inline void SetContent(Handle<JSArray> array,
+ Handle<FixedArrayBase> storage);
- // Casting.
- static inline JSArray* cast(Object* obj);
+ DECLARE_CAST(JSArray)
- // Uses handles. Ensures that the fixed array backing the JSArray has at
+ // Ensures that the fixed array backing the JSArray has at
// least the stated size.
- inline void EnsureSize(int minimum_size_of_backing_fixed_array);
+ static inline void EnsureSize(Handle<JSArray> array,
+ int minimum_size_of_backing_fixed_array);
+
+ // Expand the fixed array backing of a fast-case JSArray to at least
+ // the requested size.
+ static void Expand(Handle<JSArray> array,
+ int minimum_size_of_backing_fixed_array);
// Dispatched behavior.
-#ifdef OBJECT_PRINT
- inline void JSArrayPrint() {
- JSArrayPrint(stdout);
- }
- void JSArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void JSArrayVerify();
-#endif
+ DECLARE_PRINTER(JSArray)
+ DECLARE_VERIFIER(JSArray)
// Number of element slots to pre-allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
@@ -7970,14 +10071,14 @@
static const int kSize = kLengthOffset + kPointerSize;
private:
- // Expand the fixed array backing of a fast-case JSArray to at least
- // the requested size.
- void Expand(int minimum_size_of_backing_fixed_array);
-
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArray);
};
+Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
+ Handle<Map> initial_map);
+
+
// JSRegExpResult is just a JSArray with a specific initial map.
// This initial map adds in-object properties for "index" and "input"
// properties, as assigned by RegExp.prototype.exec, which allows
@@ -7998,22 +10099,11 @@
};
-// 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)
inline bool all_can_read();
inline void set_all_can_read(bool value);
@@ -8021,42 +10111,186 @@
inline bool all_can_write();
inline void set_all_can_write(bool value);
- inline bool prohibits_overwriting();
- inline void set_prohibits_overwriting(bool value);
-
inline PropertyAttributes property_attributes();
inline void set_property_attributes(PropertyAttributes attributes);
- static inline AccessorInfo* cast(Object* obj);
+ // Checks whether the given receiver is compatible with this accessor.
+ static bool IsCompatibleReceiverType(Isolate* isolate,
+ Handle<AccessorInfo> info,
+ Handle<HeapType> type);
+ inline bool IsCompatibleReceiver(Object* receiver);
-#ifdef OBJECT_PRINT
- inline void AccessorInfoPrint() {
- AccessorInfoPrint(stdout);
- }
- void AccessorInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void AccessorInfoVerify();
-#endif
+ DECLARE_CAST(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;
+ // Dispatched behavior.
+ DECLARE_VERIFIER(AccessorInfo)
+
+ // Append all descriptors to the array that are not already there.
+ // Return number added.
+ static int AppendUnique(Handle<Object> descriptors,
+ Handle<FixedArray> array,
+ int valid_descriptors);
+
+ static const int kNameOffset = HeapObject::kHeaderSize;
static const int kFlagOffset = kNameOffset + kPointerSize;
- static const int kSize = kFlagOffset + kPointerSize;
+ static const int kExpectedReceiverTypeOffset = kFlagOffset + kPointerSize;
+ static const int kSize = kExpectedReceiverTypeOffset + kPointerSize;
private:
+ inline bool HasExpectedReceiverType() {
+ return expected_receiver_type()->IsFunctionTemplateInfo();
+ }
// Bit positions in flag.
static const int kAllCanReadBit = 0;
static const int kAllCanWriteBit = 1;
- static const int kProhibitsOverwritingBit = 2;
- class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
+ class AttributesField: public BitField<PropertyAttributes, 2, 3> {};
DISALLOW_IMPLICIT_CONSTRUCTORS(AccessorInfo);
};
+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)
+
+ DECLARE_CAST(DeclaredAccessorDescriptor)
+
+ 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)
+
+ DECLARE_CAST(DeclaredAccessorInfo)
+
+ // 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 derived 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)
+
+ DECLARE_CAST(ExecutableAccessorInfo)
+
+ // 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;
+
+ inline void clear_setter();
+
+ 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
@@ -8068,9 +10302,21 @@
DECL_ACCESSORS(getter, Object)
DECL_ACCESSORS(setter, Object)
- static inline AccessorPair* cast(Object* obj);
+ DECLARE_CAST(AccessorPair)
- MUST_USE_RESULT MaybeObject* CopyWithoutTransitions();
+ static Handle<AccessorPair> Copy(Handle<AccessorPair> pair);
+
+ Object* get(AccessorComponent component) {
+ return component == ACCESSOR_GETTER ? getter() : setter();
+ }
+
+ void set(AccessorComponent component, Object* value) {
+ if (component == ACCESSOR_GETTER) {
+ set_getter(value);
+ } else {
+ set_setter(value);
+ }
+ }
// Note: Returns undefined instead in case of a hole.
Object* GetComponent(AccessorComponent component);
@@ -8085,12 +10331,9 @@
return IsJSAccessor(getter()) || IsJSAccessor(setter());
}
-#ifdef OBJECT_PRINT
- void AccessorPairPrint(FILE* out = stdout);
-#endif
-#ifdef DEBUG
- void AccessorPairVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(AccessorPair)
+ DECLARE_VERIFIER(AccessorPair)
static const int kGetterOffset = HeapObject::kHeaderSize;
static const int kSetterOffset = kGetterOffset + kPointerSize;
@@ -8116,17 +10359,11 @@
DECL_ACCESSORS(indexed_callback, Object)
DECL_ACCESSORS(data, Object)
- static inline AccessCheckInfo* cast(Object* obj);
+ DECLARE_CAST(AccessCheckInfo)
-#ifdef OBJECT_PRINT
- inline void AccessCheckInfoPrint() {
- AccessCheckInfoPrint(stdout);
- }
- void AccessCheckInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void AccessCheckInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(AccessCheckInfo)
+ DECLARE_VERIFIER(AccessCheckInfo)
static const int kNamedCallbackOffset = HeapObject::kHeaderSize;
static const int kIndexedCallbackOffset = kNamedCallbackOffset + kPointerSize;
@@ -8147,17 +10384,11 @@
DECL_ACCESSORS(enumerator, Object)
DECL_ACCESSORS(data, Object)
- static inline InterceptorInfo* cast(Object* obj);
+ DECLARE_CAST(InterceptorInfo)
-#ifdef OBJECT_PRINT
- inline void InterceptorInfoPrint() {
- InterceptorInfoPrint(stdout);
- }
- void InterceptorInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void InterceptorInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(InterceptorInfo)
+ DECLARE_VERIFIER(InterceptorInfo)
static const int kGetterOffset = HeapObject::kHeaderSize;
static const int kSetterOffset = kGetterOffset + kPointerSize;
@@ -8177,17 +10408,11 @@
DECL_ACCESSORS(callback, Object)
DECL_ACCESSORS(data, Object)
- static inline CallHandlerInfo* cast(Object* obj);
+ DECLARE_CAST(CallHandlerInfo)
-#ifdef OBJECT_PRINT
- inline void CallHandlerInfoPrint() {
- CallHandlerInfoPrint(stdout);
- }
- void CallHandlerInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void CallHandlerInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(CallHandlerInfo)
+ DECLARE_VERIFIER(CallHandlerInfo)
static const int kCallbackOffset = HeapObject::kHeaderSize;
static const int kDataOffset = kCallbackOffset + kPointerSize;
@@ -8202,14 +10427,15 @@
public:
DECL_ACCESSORS(tag, Object)
DECL_ACCESSORS(property_list, Object)
+ DECL_ACCESSORS(property_accessors, Object)
-#ifdef DEBUG
- void TemplateInfoVerify();
-#endif
+ DECLARE_VERIFIER(TemplateInfo)
- static const int kTagOffset = HeapObject::kHeaderSize;
+ static const int kTagOffset = HeapObject::kHeaderSize;
static const int kPropertyListOffset = kTagOffset + kPointerSize;
- static const int kHeaderSize = kPropertyListOffset + kPointerSize;
+ static const int kPropertyAccessorsOffset =
+ kPropertyListOffset + kPointerSize;
+ static const int kHeaderSize = kPropertyAccessorsOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(TemplateInfo);
@@ -8220,7 +10446,6 @@
public:
DECL_ACCESSORS(serial_number, Object)
DECL_ACCESSORS(call_code, Object)
- DECL_ACCESSORS(property_accessors, Object)
DECL_ACCESSORS(prototype_template, Object)
DECL_ACCESSORS(parent_template, Object)
DECL_ACCESSORS(named_property_handler, Object)
@@ -8232,6 +10457,9 @@
DECL_ACCESSORS(access_check_info, Object)
DECL_ACCESSORS(flag, Smi)
+ inline int length() const;
+ inline void set_length(int value);
+
// Following properties use flag bits.
DECL_BOOLEAN_ACCESSORS(hidden_prototype)
DECL_BOOLEAN_ACCESSORS(undetectable)
@@ -8239,24 +10467,19 @@
// requires access check.
DECL_BOOLEAN_ACCESSORS(needs_access_check)
DECL_BOOLEAN_ACCESSORS(read_only_prototype)
+ DECL_BOOLEAN_ACCESSORS(remove_prototype)
+ DECL_BOOLEAN_ACCESSORS(do_not_cache)
- static inline FunctionTemplateInfo* cast(Object* obj);
+ DECLARE_CAST(FunctionTemplateInfo)
-#ifdef OBJECT_PRINT
- inline void FunctionTemplateInfoPrint() {
- FunctionTemplateInfoPrint(stdout);
- }
- void FunctionTemplateInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void FunctionTemplateInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(FunctionTemplateInfo)
+ DECLARE_VERIFIER(FunctionTemplateInfo)
static const int kSerialNumberOffset = TemplateInfo::kHeaderSize;
static const int kCallCodeOffset = kSerialNumberOffset + kPointerSize;
- static const int kPropertyAccessorsOffset = kCallCodeOffset + kPointerSize;
static const int kPrototypeTemplateOffset =
- kPropertyAccessorsOffset + kPointerSize;
+ kCallCodeOffset + kPointerSize;
static const int kParentTemplateOffset =
kPrototypeTemplateOffset + kPointerSize;
static const int kNamedPropertyHandlerOffset =
@@ -8271,7 +10494,12 @@
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;
+
+ // Returns true if |object| is an instance of this function template.
+ bool IsTemplateFor(Object* object);
+ bool IsTemplateFor(Map* map);
private:
// Bit position in the flag, from least significant bit position.
@@ -8279,6 +10507,8 @@
static const int kUndetectableBit = 1;
static const int kNeedsAccessCheckBit = 2;
static const int kReadOnlyPrototypeBit = 3;
+ static const int kRemovePrototypeBit = 4;
+ static const int kDoNotCacheBit = 5;
DISALLOW_IMPLICIT_CONSTRUCTORS(FunctionTemplateInfo);
};
@@ -8289,17 +10519,11 @@
DECL_ACCESSORS(constructor, Object)
DECL_ACCESSORS(internal_field_count, Object)
- static inline ObjectTemplateInfo* cast(Object* obj);
+ DECLARE_CAST(ObjectTemplateInfo)
-#ifdef OBJECT_PRINT
- inline void ObjectTemplateInfoPrint() {
- ObjectTemplateInfoPrint(stdout);
- }
- void ObjectTemplateInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void ObjectTemplateInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(ObjectTemplateInfo)
+ DECLARE_VERIFIER(ObjectTemplateInfo)
static const int kConstructorOffset = TemplateInfo::kHeaderSize;
static const int kInternalFieldCountOffset =
@@ -8313,17 +10537,11 @@
DECL_ACCESSORS(receiver, Object)
DECL_ACCESSORS(args, Object)
- static inline SignatureInfo* cast(Object* obj);
+ DECLARE_CAST(SignatureInfo)
-#ifdef OBJECT_PRINT
- inline void SignatureInfoPrint() {
- SignatureInfoPrint(stdout);
- }
- void SignatureInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void SignatureInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(SignatureInfo)
+ DECLARE_VERIFIER(SignatureInfo)
static const int kReceiverOffset = Struct::kHeaderSize;
static const int kArgsOffset = kReceiverOffset + kPointerSize;
@@ -8338,24 +10556,17 @@
public:
DECL_ACCESSORS(types, Object)
- static inline TypeSwitchInfo* cast(Object* obj);
+ DECLARE_CAST(TypeSwitchInfo)
-#ifdef OBJECT_PRINT
- inline void TypeSwitchInfoPrint() {
- TypeSwitchInfoPrint(stdout);
- }
- void TypeSwitchInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void TypeSwitchInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(TypeSwitchInfo)
+ DECLARE_VERIFIER(TypeSwitchInfo)
static const int kTypesOffset = Struct::kHeaderSize;
static const int kSize = kTypesOffset + kPointerSize;
};
-#ifdef ENABLE_DEBUGGER_SUPPORT
// The DebugInfo class holds additional information for a function being
// debugged.
class DebugInfo: public Struct {
@@ -8390,17 +10601,11 @@
// Get the number of break points for this function.
int GetBreakPointCount();
- static inline DebugInfo* cast(Object* obj);
+ DECLARE_CAST(DebugInfo)
-#ifdef OBJECT_PRINT
- inline void DebugInfoPrint() {
- DebugInfoPrint(stdout);
- }
- void DebugInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void DebugInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(DebugInfo)
+ DECLARE_VERIFIER(DebugInfo)
static const int kSharedFunctionInfoIndex = Struct::kHeaderSize;
static const int kOriginalCodeIndex = kSharedFunctionInfoIndex + kPointerSize;
@@ -8411,6 +10616,8 @@
kActiveBreakPointsCountIndex + kPointerSize;
static const int kSize = kBreakPointsStateIndex + kPointerSize;
+ static const int kEstimatedNofBreakPointsInFunction = 16;
+
private:
static const int kNoBreakPointInfo = -1;
@@ -8448,17 +10655,11 @@
// Get the number of break points for this code position.
int GetBreakPointCount();
- static inline BreakPointInfo* cast(Object* obj);
+ DECLARE_CAST(BreakPointInfo)
-#ifdef OBJECT_PRINT
- inline void BreakPointInfoPrint() {
- BreakPointInfoPrint(stdout);
- }
- void BreakPointInfoPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void BreakPointInfoVerify();
-#endif
+ // Dispatched behavior.
+ DECLARE_PRINTER(BreakPointInfo)
+ DECLARE_VERIFIER(BreakPointInfo)
static const int kCodePositionIndex = Struct::kHeaderSize;
static const int kSourcePositionIndex = kCodePositionIndex + kPointerSize;
@@ -8471,17 +10672,19 @@
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BreakPointInfo);
};
-#endif // ENABLE_DEBUGGER_SUPPORT
#undef DECL_BOOLEAN_ACCESSORS
#undef DECL_ACCESSORS
+#undef DECLARE_CAST
+#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(kSmiRootList, "smi_root_list", "(Smi roots)") \
+ V(kInternalizedString, "internalized_string", "(Internal string)") \
V(kBootstrapper, "bootstrapper", "(Bootstrapper)") \
V(kTop, "top", "(Isolate)") \
V(kRelocatable, "relocatable", "(Relocatable)") \
@@ -8490,6 +10693,7 @@
V(kHandleScope, "handlescope", "(Handle scope)") \
V(kBuiltins, "builtins", "(Builtins)") \
V(kGlobalHandles, "globalhandles", "(Global handles)") \
+ V(kEternalHandles, "eternalhandles", "(Eternal handles)") \
V(kThreadManager, "threadmanager", "(Thread manager)") \
V(kExtensions, "Extensions", "(Extensions)")
@@ -8516,6 +10720,12 @@
// [start, end). Any or all of the values may be modified on return.
virtual void VisitPointers(Object** start, Object** end) = 0;
+ // Handy shorthand for visiting a single pointer.
+ virtual void VisitPointer(Object** p) { VisitPointers(p, p + 1); }
+
+ // Visit weak next_code_link in Code object.
+ virtual void VisitNextCodeLink(Object** p) { VisitPointers(p, p + 1); }
+
// To allow lazy clearing of inline caches the visitor has
// a rich interface for iterating over Code objects..
@@ -8526,38 +10736,32 @@
virtual void VisitCodeEntry(Address entry_address);
// Visits a global property cell reference in the instruction stream.
- virtual void VisitGlobalPropertyCell(RelocInfo* rinfo);
+ virtual void VisitCell(RelocInfo* rinfo);
// Visits a runtime entry in the instruction stream.
virtual void VisitRuntimeEntry(RelocInfo* rinfo) {}
- // Visits the resource of an ASCII or two-byte string.
- virtual void VisitExternalAsciiString(
- v8::String::ExternalAsciiStringResource** resource) {}
+ // Visits the resource of an one-byte or two-byte string.
+ virtual void VisitExternalOneByteString(
+ v8::String::ExternalOneByteStringResource** resource) {}
virtual void VisitExternalTwoByteString(
v8::String::ExternalStringResource** resource) {}
// Visits a debug call target in the instruction stream.
virtual void VisitDebugTarget(RelocInfo* rinfo);
- // Handy shorthand for visiting a single pointer.
- virtual void VisitPointer(Object** p) { VisitPointers(p, p + 1); }
+ // Visits the byte sequence in a function's prologue that contains information
+ // about the code's age.
+ virtual void VisitCodeAgeSequence(RelocInfo* rinfo);
// Visit pointer embedded into a code object.
virtual void VisitEmbeddedPointer(RelocInfo* rinfo);
- virtual void VisitSharedFunctionInfo(SharedFunctionInfo* shared) {}
-
- // Visits a contiguous arrays of external references (references to the C++
- // heap) in the half-open range [start, end). Any or all of the values
- // may be modified on return.
- virtual void VisitExternalReferences(Address* start, Address* end) {}
-
+ // Visits an external reference embedded into a code object.
virtual void VisitExternalReference(RelocInfo* rinfo);
- inline void VisitExternalReference(Address* p) {
- VisitExternalReferences(p, p + 1);
- }
+ // Visits an external reference. The value may be modified on return.
+ virtual void VisitExternalReference(Address* p) {}
// Visits a handle that has an embedder-assigned class ID.
virtual void VisitEmbedderReference(Object** p, uint16_t class_id) {}