• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_OBJECTS_INSTANCE_TYPE_H_
6 #define V8_OBJECTS_INSTANCE_TYPE_H_
7 
8 #include "src/objects/elements-kind.h"
9 #include "src/objects/objects-definitions.h"
10 
11 // Has to be the last include (doesn't have include guards):
12 #include "src/objects/object-macros.h"
13 #include "torque-generated/instance-types.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 // We use the full 16 bits of the instance_type field to encode heap object
19 // instance types. All the high-order bits (bits 6-15) are cleared if the object
20 // is a string, and contain set bits if it is not a string.
21 const uint32_t kIsNotStringMask = ~((1 << 6) - 1);
22 const uint32_t kStringTag = 0x0;
23 
24 // For strings, bits 0-2 indicate the representation of the string. In
25 // particular, bit 0 indicates whether the string is direct or indirect.
26 const uint32_t kStringRepresentationMask = (1 << 3) - 1;
27 enum StringRepresentationTag {
28   kSeqStringTag = 0x0,
29   kConsStringTag = 0x1,
30   kExternalStringTag = 0x2,
31   kSlicedStringTag = 0x3,
32   kThinStringTag = 0x5
33 };
34 const uint32_t kIsIndirectStringMask = 1 << 0;
35 const uint32_t kIsIndirectStringTag = 1 << 0;
36 // NOLINTNEXTLINE(runtime/references) (false positive)
37 STATIC_ASSERT((kSeqStringTag & kIsIndirectStringMask) == 0);
38 // NOLINTNEXTLINE(runtime/references) (false positive)
39 STATIC_ASSERT((kExternalStringTag & kIsIndirectStringMask) == 0);
40 // NOLINTNEXTLINE(runtime/references) (false positive)
41 STATIC_ASSERT((kConsStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);
42 // NOLINTNEXTLINE(runtime/references) (false positive)
43 STATIC_ASSERT((kSlicedStringTag & kIsIndirectStringMask) ==
44               kIsIndirectStringTag);
45 // NOLINTNEXTLINE(runtime/references) (false positive)
46 STATIC_ASSERT((kThinStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);
47 
48 // For strings, bit 3 indicates whether the string consists of two-byte
49 // characters or one-byte characters.
50 const uint32_t kStringEncodingMask = 1 << 3;
51 const uint32_t kTwoByteStringTag = 0;
52 const uint32_t kOneByteStringTag = 1 << 3;
53 
54 // For strings, bit 4 indicates whether the data pointer of an external string
55 // is cached. Note that the string representation is expected to be
56 // kExternalStringTag.
57 const uint32_t kUncachedExternalStringMask = 1 << 4;
58 const uint32_t kUncachedExternalStringTag = 1 << 4;
59 
60 // For strings, bit 5 indicates that the string is internalized (if not set) or
61 // isn't (if set).
62 const uint32_t kIsNotInternalizedMask = 1 << 5;
63 const uint32_t kNotInternalizedTag = 1 << 5;
64 const uint32_t kInternalizedTag = 0;
65 
66 // A ConsString with an empty string as the right side is a candidate
67 // for being shortcut by the garbage collector. We don't allocate any
68 // non-flat internalized strings, so we do not shortcut them thereby
69 // avoiding turning internalized strings into strings. The bit-masks
70 // below contain the internalized bit as additional safety.
71 // See heap.cc, mark-compact.cc and objects-visiting.cc.
72 const uint32_t kShortcutTypeMask =
73     kIsNotStringMask | kIsNotInternalizedMask | kStringRepresentationMask;
74 const uint32_t kShortcutTypeTag = kConsStringTag | kNotInternalizedTag;
75 
IsShortcutCandidate(int type)76 static inline bool IsShortcutCandidate(int type) {
77   return ((type & kShortcutTypeMask) == kShortcutTypeTag);
78 }
79 
80 enum InstanceType : uint16_t {
81   // String types.
82   INTERNALIZED_STRING_TYPE =
83       kTwoByteStringTag | kSeqStringTag | kInternalizedTag,
84   ONE_BYTE_INTERNALIZED_STRING_TYPE =
85       kOneByteStringTag | kSeqStringTag | kInternalizedTag,
86   EXTERNAL_INTERNALIZED_STRING_TYPE =
87       kTwoByteStringTag | kExternalStringTag | kInternalizedTag,
88   EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE =
89       kOneByteStringTag | kExternalStringTag | kInternalizedTag,
90   UNCACHED_EXTERNAL_INTERNALIZED_STRING_TYPE =
91       EXTERNAL_INTERNALIZED_STRING_TYPE | kUncachedExternalStringTag |
92       kInternalizedTag,
93   UNCACHED_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE =
94       EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kUncachedExternalStringTag |
95       kInternalizedTag,
96   STRING_TYPE = INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
97   ONE_BYTE_STRING_TYPE =
98       ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
99   CONS_STRING_TYPE = kTwoByteStringTag | kConsStringTag | kNotInternalizedTag,
100   CONS_ONE_BYTE_STRING_TYPE =
101       kOneByteStringTag | kConsStringTag | kNotInternalizedTag,
102   SLICED_STRING_TYPE =
103       kTwoByteStringTag | kSlicedStringTag | kNotInternalizedTag,
104   SLICED_ONE_BYTE_STRING_TYPE =
105       kOneByteStringTag | kSlicedStringTag | kNotInternalizedTag,
106   EXTERNAL_STRING_TYPE =
107       EXTERNAL_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
108   EXTERNAL_ONE_BYTE_STRING_TYPE =
109       EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
110   UNCACHED_EXTERNAL_STRING_TYPE =
111       UNCACHED_EXTERNAL_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
112   UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE =
113       UNCACHED_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
114   THIN_STRING_TYPE = kTwoByteStringTag | kThinStringTag | kNotInternalizedTag,
115   THIN_ONE_BYTE_STRING_TYPE =
116       kOneByteStringTag | kThinStringTag | kNotInternalizedTag,
117 
118 // Most instance types are defined in Torque, with the exception of the string
119 // types above. They are ordered by inheritance hierarchy so that we can easily
120 // use range checks to determine whether an object is an instance of a subclass
121 // of any type. There are a few more constraints specified in the Torque type
122 // definitions:
123 // - Some instance types are exposed in v8.h, so they are locked to specific
124 //   values to not unnecessarily change the ABI.
125 // - JSSpecialObject and JSCustomElementsObject are aligned with the beginning
126 //   of the JSObject range, so that we can use a larger range check from
127 //   FIRST_JS_RECEIVER_TYPE to the end of those ranges and include JSProxy too.
128 // - JSFunction is last, meaning we can use a single inequality check to
129 //   determine whether an instance type is within the range for any class in the
130 //   inheritance hierarchy of JSFunction. This includes commonly-checked classes
131 //   JSObject and JSReceiver.
132 #define MAKE_TORQUE_INSTANCE_TYPE(TYPE, value) TYPE = value,
133   TORQUE_ASSIGNED_INSTANCE_TYPES(MAKE_TORQUE_INSTANCE_TYPE)
134 #undef MAKE_TORQUE_INSTANCE_TYPE
135 
136   // Pseudo-types
137   FIRST_UNIQUE_NAME_TYPE = INTERNALIZED_STRING_TYPE,
138   LAST_UNIQUE_NAME_TYPE = SYMBOL_TYPE,
139   FIRST_NONSTRING_TYPE = SYMBOL_TYPE,
140   // Boundary for testing JSReceivers that need special property lookup handling
141   LAST_SPECIAL_RECEIVER_TYPE = LAST_JS_SPECIAL_OBJECT_TYPE,
142   // Boundary case for testing JSReceivers that may have elements while having
143   // an empty fixed array as elements backing store. This is true for string
144   // wrappers.
145   LAST_CUSTOM_ELEMENTS_RECEIVER = LAST_JS_CUSTOM_ELEMENTS_OBJECT_TYPE,
146 
147   // Convenient names for things where the generated name is awkward:
148   FIRST_TYPE = FIRST_HEAP_OBJECT_TYPE,
149   LAST_TYPE = LAST_HEAP_OBJECT_TYPE,
150   FIRST_FUNCTION_TYPE = FIRST_JS_FUNCTION_OR_BOUND_FUNCTION_TYPE,
151   LAST_FUNCTION_TYPE = LAST_JS_FUNCTION_OR_BOUND_FUNCTION_TYPE,
152   BIGINT_TYPE = BIG_INT_BASE_TYPE,
153 };
154 
155 // This constant is defined outside of the InstanceType enum because the
156 // string instance types are sparse and there's no such string instance type.
157 // But it's still useful for range checks to have such a value.
158 constexpr InstanceType LAST_STRING_TYPE =
159     static_cast<InstanceType>(FIRST_NONSTRING_TYPE - 1);
160 
161 // NOLINTNEXTLINE(runtime/references) (false positive)
162 STATIC_ASSERT((FIRST_NONSTRING_TYPE & kIsNotStringMask) != kStringTag);
163 STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);
164 STATIC_ASSERT(JS_API_OBJECT_TYPE == Internals::kJSApiObjectType);
165 STATIC_ASSERT(JS_SPECIAL_API_OBJECT_TYPE == Internals::kJSSpecialApiObjectType);
166 STATIC_ASSERT(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);
167 STATIC_ASSERT(ODDBALL_TYPE == Internals::kOddballType);
168 STATIC_ASSERT(FOREIGN_TYPE == Internals::kForeignType);
169 
170 // Verify that string types are all less than other types.
171 #define CHECK_STRING_RANGE(TYPE, ...) \
172   STATIC_ASSERT(TYPE < FIRST_NONSTRING_TYPE);
173 STRING_TYPE_LIST(CHECK_STRING_RANGE)
174 #undef CHECK_STRING_RANGE
175 #define CHECK_NONSTRING_RANGE(TYPE) STATIC_ASSERT(TYPE >= FIRST_NONSTRING_TYPE);
176 TORQUE_ASSIGNED_INSTANCE_TYPE_LIST(CHECK_NONSTRING_RANGE)
177 #undef CHECK_NONSTRING_RANGE
178 
179 // Two ranges don't cleanly follow the inheritance hierarchy. Here we ensure
180 // that only expected types fall within these ranges.
181 // - From FIRST_JS_RECEIVER_TYPE to LAST_SPECIAL_RECEIVER_TYPE should correspond
182 //   to the union type JSProxy | JSSpecialObject.
183 // - From FIRST_JS_RECEIVER_TYPE to LAST_CUSTOM_ELEMENTS_RECEIVER should
184 //   correspond to the union type JSProxy | JSCustomElementsObject.
185 // Note in particular that these ranges include all subclasses of JSReceiver
186 // that are not also subclasses of JSObject (currently only JSProxy).
187 #define CHECK_INSTANCE_TYPE(TYPE)                                          \
188   STATIC_ASSERT((TYPE >= FIRST_JS_RECEIVER_TYPE &&                         \
189                  TYPE <= LAST_SPECIAL_RECEIVER_TYPE) ==                    \
190                 (TYPE == JS_PROXY_TYPE || TYPE == JS_GLOBAL_OBJECT_TYPE || \
191                  TYPE == JS_GLOBAL_PROXY_TYPE ||                           \
192                  TYPE == JS_MODULE_NAMESPACE_TYPE ||                       \
193                  TYPE == JS_SPECIAL_API_OBJECT_TYPE));                     \
194   STATIC_ASSERT((TYPE >= FIRST_JS_RECEIVER_TYPE &&                         \
195                  TYPE <= LAST_CUSTOM_ELEMENTS_RECEIVER) ==                 \
196                 (TYPE == JS_PROXY_TYPE || TYPE == JS_GLOBAL_OBJECT_TYPE || \
197                  TYPE == JS_GLOBAL_PROXY_TYPE ||                           \
198                  TYPE == JS_MODULE_NAMESPACE_TYPE ||                       \
199                  TYPE == JS_SPECIAL_API_OBJECT_TYPE ||                     \
200                  TYPE == JS_PRIMITIVE_WRAPPER_TYPE));
201 TORQUE_ASSIGNED_INSTANCE_TYPE_LIST(CHECK_INSTANCE_TYPE)
202 #undef CHECK_INSTANCE_TYPE
203 
204 // Make sure it doesn't matter whether we sign-extend or zero-extend these
205 // values, because Torque treats InstanceType as signed.
206 STATIC_ASSERT(LAST_TYPE < 1 << 15);
207 
208 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
209                                            InstanceType instance_type);
210 
211 // List of object types that have a single unique instance type.
212 #define INSTANCE_TYPE_CHECKERS_SINGLE(V)           \
213   TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(V) \
214   TORQUE_INSTANCE_CHECKERS_SINGLE_ONLY_DECLARED(V) \
215   V(BigInt, BIGINT_TYPE)                           \
216   V(FixedArrayExact, FIXED_ARRAY_TYPE)
217 
218 #define INSTANCE_TYPE_CHECKERS_RANGE(V)           \
219   TORQUE_INSTANCE_CHECKERS_RANGE_FULLY_DEFINED(V) \
220   TORQUE_INSTANCE_CHECKERS_RANGE_ONLY_DECLARED(V)
221 
222 #define INSTANCE_TYPE_CHECKERS_CUSTOM(V) \
223   V(ExternalString)                      \
224   V(InternalizedString)
225 
226 #define INSTANCE_TYPE_CHECKERS(V)  \
227   INSTANCE_TYPE_CHECKERS_SINGLE(V) \
228   INSTANCE_TYPE_CHECKERS_RANGE(V)  \
229   INSTANCE_TYPE_CHECKERS_CUSTOM(V)
230 
231 namespace InstanceTypeChecker {
232 #define IS_TYPE_FUNCTION_DECL(Type, ...) \
233   V8_INLINE bool Is##Type(InstanceType instance_type);
234 
235 INSTANCE_TYPE_CHECKERS(IS_TYPE_FUNCTION_DECL)
236 
237 #define TYPED_ARRAY_IS_TYPE_FUNCTION_DECL(Type, ...) \
238   IS_TYPE_FUNCTION_DECL(Fixed##Type##Array)
239 TYPED_ARRAYS(TYPED_ARRAY_IS_TYPE_FUNCTION_DECL)
240 #undef TYPED_ARRAY_IS_TYPE_FUNCTION_DECL
241 
242 #undef IS_TYPE_FUNCTION_DECL
243 }  // namespace InstanceTypeChecker
244 
245 // This list must contain only maps that are shared by all objects of their
246 // instance type.
247 #define UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR(V, _)                       \
248   V(_, AccessorInfoMap, accessor_info_map, AccessorInfo)                    \
249   V(_, AccessorPairMap, accessor_pair_map, AccessorPair)                    \
250   V(_, AllocationMementoMap, allocation_memento_map, AllocationMemento)     \
251   V(_, ArrayBoilerplateDescriptionMap, array_boilerplate_description_map,   \
252     ArrayBoilerplateDescription)                                            \
253   V(_, BreakPointMap, break_point_map, BreakPoint)                          \
254   V(_, BreakPointInfoMap, break_point_info_map, BreakPointInfo)             \
255   V(_, CachedTemplateObjectMap, cached_template_object_map,                 \
256     CachedTemplateObject)                                                   \
257   V(_, CellMap, cell_map, Cell)                                             \
258   V(_, WeakCellMap, weak_cell_map, WeakCell)                                \
259   V(_, CodeMap, code_map, Code)                                             \
260   V(_, CoverageInfoMap, coverage_info_map, CoverageInfo)                    \
261   V(_, DebugInfoMap, debug_info_map, DebugInfo)                             \
262   V(_, FeedbackVectorMap, feedback_vector_map, FeedbackVector)              \
263   V(_, FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArray)       \
264   V(_, FunctionTemplateInfoMap, function_template_info_map,                 \
265     FunctionTemplateInfo)                                                   \
266   V(_, HeapNumberMap, heap_number_map, HeapNumber)                          \
267   V(_, MetaMap, meta_map, Map)                                              \
268   V(_, PreparseDataMap, preparse_data_map, PreparseData)                    \
269   V(_, PrototypeInfoMap, prototype_info_map, PrototypeInfo)                 \
270   V(_, SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfo) \
271   V(_, SmallOrderedHashSetMap, small_ordered_hash_set_map,                  \
272     SmallOrderedHashSet)                                                    \
273   V(_, SmallOrderedHashMapMap, small_ordered_hash_map_map,                  \
274     SmallOrderedHashMap)                                                    \
275   V(_, SmallOrderedNameDictionaryMap, small_ordered_name_dictionary_map,    \
276     SmallOrderedNameDictionary)                                             \
277   V(_, SymbolMap, symbol_map, Symbol)                                       \
278   V(_, TransitionArrayMap, transition_array_map, TransitionArray)           \
279   V(_, Tuple2Map, tuple2_map, Tuple2)                                       \
280   V(_, UncompiledDataWithoutPreparseDataMap,                                \
281     uncompiled_data_without_preparse_data_map,                              \
282     UncompiledDataWithoutPreparseData)                                      \
283   V(_, UncompiledDataWithPreparseDataMap,                                   \
284     uncompiled_data_with_preparse_data_map, UncompiledDataWithPreparseData) \
285   V(_, WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArray)             \
286   TORQUE_DEFINED_MAP_CSA_LIST_GENERATOR(V, _)
287 
288 }  // namespace internal
289 }  // namespace v8
290 
291 #include "src/objects/object-macros-undef.h"
292 
293 #endif  // V8_OBJECTS_INSTANCE_TYPE_H_
294