• 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 7-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 << 7) - 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 STATIC_ASSERT((kSeqStringTag & kIsIndirectStringMask) == 0);
37 STATIC_ASSERT((kExternalStringTag & kIsIndirectStringMask) == 0);
38 STATIC_ASSERT((kConsStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);
39 STATIC_ASSERT((kSlicedStringTag & kIsIndirectStringMask) ==
40               kIsIndirectStringTag);
41 STATIC_ASSERT((kThinStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);
42 
43 // For strings, bit 3 indicates whether the string consists of two-byte
44 // characters or one-byte characters.
45 const uint32_t kStringEncodingMask = 1 << 3;
46 const uint32_t kTwoByteStringTag = 0;
47 const uint32_t kOneByteStringTag = 1 << 3;
48 
49 // Combined tags for convenience (add more if needed).
50 constexpr uint32_t kStringRepresentationAndEncodingMask =
51     kStringRepresentationMask | kStringEncodingMask;
52 constexpr uint32_t kSeqOneByteStringTag = kSeqStringTag | kOneByteStringTag;
53 constexpr uint32_t kSeqTwoByteStringTag = kSeqStringTag | kTwoByteStringTag;
54 constexpr uint32_t kExternalOneByteStringTag =
55     kExternalStringTag | kOneByteStringTag;
56 constexpr uint32_t kExternalTwoByteStringTag =
57     kExternalStringTag | kTwoByteStringTag;
58 
59 // For strings, bit 4 indicates whether the data pointer of an external string
60 // is cached. Note that the string representation is expected to be
61 // kExternalStringTag.
62 const uint32_t kUncachedExternalStringMask = 1 << 4;
63 const uint32_t kUncachedExternalStringTag = 1 << 4;
64 
65 // For strings, bit 5 indicates that the string is internalized (if not set) or
66 // isn't (if set).
67 const uint32_t kIsNotInternalizedMask = 1 << 5;
68 const uint32_t kNotInternalizedTag = 1 << 5;
69 const uint32_t kInternalizedTag = 0;
70 
71 // For strings, bit 6 indicates that the string is accessible by more than one
72 // thread. Note that a string that is allocated in the shared heap is not
73 // accessible by more than one thread until it is explicitly shared (e.g. by
74 // postMessage).
75 //
76 // Runtime code that shares strings with other threads directly need to manually
77 // set this bit.
78 //
79 // TODO(v8:12007): External strings cannot be shared yet.
80 //
81 // TODO(v8:12007): This bit is currently ignored on internalized strings, which
82 // are either always shared or always not shared depending on
83 // FLAG_shared_string_table. This will be hardcoded once
84 // FLAG_shared_string_table is removed.
85 const uint32_t kSharedStringMask = 1 << 6;
86 const uint32_t kSharedStringTag = 1 << 6;
87 
88 constexpr uint32_t kStringRepresentationEncodingAndSharedMask =
89     kStringRepresentationAndEncodingMask | kSharedStringMask;
90 
91 // A ConsString with an empty string as the right side is a candidate
92 // for being shortcut by the garbage collector. We don't allocate any
93 // non-flat internalized strings, so we do not shortcut them thereby
94 // avoiding turning internalized strings into strings. The bit-masks
95 // below contain the internalized bit as additional safety.
96 // See heap.cc, mark-compact.cc and objects-visiting.cc.
97 const uint32_t kShortcutTypeMask =
98     kIsNotStringMask | kIsNotInternalizedMask | kStringRepresentationMask;
99 const uint32_t kShortcutTypeTag = kConsStringTag | kNotInternalizedTag;
100 
IsShortcutCandidate(int type)101 static inline bool IsShortcutCandidate(int type) {
102   return ((type & kShortcutTypeMask) == kShortcutTypeTag);
103 }
104 
105 enum InstanceType : uint16_t {
106   // String types.
107   INTERNALIZED_STRING_TYPE =
108       kTwoByteStringTag | kSeqStringTag | kInternalizedTag,
109   ONE_BYTE_INTERNALIZED_STRING_TYPE =
110       kOneByteStringTag | kSeqStringTag | kInternalizedTag,
111   EXTERNAL_INTERNALIZED_STRING_TYPE =
112       kTwoByteStringTag | kExternalStringTag | kInternalizedTag,
113   EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE =
114       kOneByteStringTag | kExternalStringTag | kInternalizedTag,
115   UNCACHED_EXTERNAL_INTERNALIZED_STRING_TYPE =
116       EXTERNAL_INTERNALIZED_STRING_TYPE | kUncachedExternalStringTag |
117       kInternalizedTag,
118   UNCACHED_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE =
119       EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kUncachedExternalStringTag |
120       kInternalizedTag,
121   STRING_TYPE = INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
122   ONE_BYTE_STRING_TYPE =
123       ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
124   CONS_STRING_TYPE = kTwoByteStringTag | kConsStringTag | kNotInternalizedTag,
125   CONS_ONE_BYTE_STRING_TYPE =
126       kOneByteStringTag | kConsStringTag | kNotInternalizedTag,
127   SLICED_STRING_TYPE =
128       kTwoByteStringTag | kSlicedStringTag | kNotInternalizedTag,
129   SLICED_ONE_BYTE_STRING_TYPE =
130       kOneByteStringTag | kSlicedStringTag | kNotInternalizedTag,
131   EXTERNAL_STRING_TYPE =
132       EXTERNAL_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
133   EXTERNAL_ONE_BYTE_STRING_TYPE =
134       EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
135   UNCACHED_EXTERNAL_STRING_TYPE =
136       UNCACHED_EXTERNAL_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
137   UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE =
138       UNCACHED_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
139   THIN_STRING_TYPE = kTwoByteStringTag | kThinStringTag | kNotInternalizedTag,
140   THIN_ONE_BYTE_STRING_TYPE =
141       kOneByteStringTag | kThinStringTag | kNotInternalizedTag,
142   SHARED_STRING_TYPE = STRING_TYPE | kSharedStringTag,
143   SHARED_ONE_BYTE_STRING_TYPE = ONE_BYTE_STRING_TYPE | kSharedStringTag,
144   SHARED_THIN_STRING_TYPE = THIN_STRING_TYPE | kSharedStringTag,
145   SHARED_THIN_ONE_BYTE_STRING_TYPE =
146       THIN_ONE_BYTE_STRING_TYPE | kSharedStringTag,
147 
148 // Most instance types are defined in Torque, with the exception of the string
149 // types above. They are ordered by inheritance hierarchy so that we can easily
150 // use range checks to determine whether an object is an instance of a subclass
151 // of any type. There are a few more constraints specified in the Torque type
152 // definitions:
153 // - Some instance types are exposed in v8.h, so they are locked to specific
154 //   values to not unnecessarily change the ABI.
155 // - JSSpecialObject and JSCustomElementsObject are aligned with the beginning
156 //   of the JSObject range, so that we can use a larger range check from
157 //   FIRST_JS_RECEIVER_TYPE to the end of those ranges and include JSProxy too.
158 #define MAKE_TORQUE_INSTANCE_TYPE(TYPE, value) TYPE = value,
159   TORQUE_ASSIGNED_INSTANCE_TYPES(MAKE_TORQUE_INSTANCE_TYPE)
160 #undef MAKE_TORQUE_INSTANCE_TYPE
161 
162   // Pseudo-types
163   FIRST_UNIQUE_NAME_TYPE = INTERNALIZED_STRING_TYPE,
164   LAST_UNIQUE_NAME_TYPE = SYMBOL_TYPE,
165   FIRST_NONSTRING_TYPE = SYMBOL_TYPE,
166   // Callable JS Functions are all JS Functions except class constructors.
167   FIRST_CALLABLE_JS_FUNCTION_TYPE = FIRST_JS_FUNCTION_TYPE,
168   LAST_CALLABLE_JS_FUNCTION_TYPE = JS_CLASS_CONSTRUCTOR_TYPE - 1,
169   // Boundary for testing JSReceivers that need special property lookup handling
170   LAST_SPECIAL_RECEIVER_TYPE = LAST_JS_SPECIAL_OBJECT_TYPE,
171   // Boundary case for testing JSReceivers that may have elements while having
172   // an empty fixed array as elements backing store. This is true for string
173   // wrappers.
174   LAST_CUSTOM_ELEMENTS_RECEIVER = LAST_JS_CUSTOM_ELEMENTS_OBJECT_TYPE,
175 
176   // Convenient names for things where the generated name is awkward:
177   FIRST_TYPE = FIRST_HEAP_OBJECT_TYPE,
178   LAST_TYPE = LAST_HEAP_OBJECT_TYPE,
179   BIGINT_TYPE = BIG_INT_BASE_TYPE,
180 
181 #ifdef V8_EXTERNAL_CODE_SPACE
182   CODET_TYPE = CODE_DATA_CONTAINER_TYPE,
183 #else
184   CODET_TYPE = CODE_TYPE,
185 #endif
186 };
187 
188 // This constant is defined outside of the InstanceType enum because the
189 // string instance types are sparse and there's no such string instance type.
190 // But it's still useful for range checks to have such a value.
191 constexpr InstanceType LAST_STRING_TYPE =
192     static_cast<InstanceType>(FIRST_NONSTRING_TYPE - 1);
193 
194 STATIC_ASSERT((FIRST_NONSTRING_TYPE & kIsNotStringMask) != kStringTag);
195 STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);
196 STATIC_ASSERT(FIRST_JS_API_OBJECT_TYPE == Internals::kFirstJSApiObjectType);
197 STATIC_ASSERT(LAST_JS_API_OBJECT_TYPE == Internals::kLastJSApiObjectType);
198 STATIC_ASSERT(JS_SPECIAL_API_OBJECT_TYPE == Internals::kJSSpecialApiObjectType);
199 STATIC_ASSERT(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);
200 STATIC_ASSERT(ODDBALL_TYPE == Internals::kOddballType);
201 STATIC_ASSERT(FOREIGN_TYPE == Internals::kForeignType);
202 
203 // Verify that string types are all less than other types.
204 #define CHECK_STRING_RANGE(TYPE, ...) \
205   STATIC_ASSERT(TYPE < FIRST_NONSTRING_TYPE);
206 STRING_TYPE_LIST(CHECK_STRING_RANGE)
207 #undef CHECK_STRING_RANGE
208 #define CHECK_NONSTRING_RANGE(TYPE) STATIC_ASSERT(TYPE >= FIRST_NONSTRING_TYPE);
209 TORQUE_ASSIGNED_INSTANCE_TYPE_LIST(CHECK_NONSTRING_RANGE)
210 #undef CHECK_NONSTRING_RANGE
211 
212 // classConstructor type has to be the last one in the JS Function type range.
213 STATIC_ASSERT(JS_CLASS_CONSTRUCTOR_TYPE == LAST_JS_FUNCTION_TYPE);
214 static_assert(JS_CLASS_CONSTRUCTOR_TYPE < FIRST_CALLABLE_JS_FUNCTION_TYPE ||
215                   JS_CLASS_CONSTRUCTOR_TYPE > LAST_CALLABLE_JS_FUNCTION_TYPE,
216               "JS_CLASS_CONSTRUCTOR_TYPE must not be in the callable JS "
217               "function type range");
218 
219 // Two ranges don't cleanly follow the inheritance hierarchy. Here we ensure
220 // that only expected types fall within these ranges.
221 // - From FIRST_JS_RECEIVER_TYPE to LAST_SPECIAL_RECEIVER_TYPE should correspond
222 //   to the union type JSProxy | JSSpecialObject.
223 // - From FIRST_JS_RECEIVER_TYPE to LAST_CUSTOM_ELEMENTS_RECEIVER should
224 //   correspond to the union type JSProxy | JSCustomElementsObject.
225 // Note in particular that these ranges include all subclasses of JSReceiver
226 // that are not also subclasses of JSObject (currently only JSProxy).
227 // clang-format off
228 #define CHECK_INSTANCE_TYPE(TYPE)                                          \
229   STATIC_ASSERT((TYPE >= FIRST_JS_RECEIVER_TYPE &&                         \
230                  TYPE <= LAST_SPECIAL_RECEIVER_TYPE) ==                    \
231                 (IF_WASM(EXPAND, TYPE == WASM_STRUCT_TYPE ||               \
232                                  TYPE == WASM_ARRAY_TYPE ||)               \
233                  TYPE == JS_PROXY_TYPE || TYPE == JS_GLOBAL_OBJECT_TYPE || \
234                  TYPE == JS_GLOBAL_PROXY_TYPE ||                           \
235                  TYPE == JS_MODULE_NAMESPACE_TYPE ||                       \
236                  TYPE == JS_SPECIAL_API_OBJECT_TYPE));                     \
237   STATIC_ASSERT((TYPE >= FIRST_JS_RECEIVER_TYPE &&                         \
238                  TYPE <= LAST_CUSTOM_ELEMENTS_RECEIVER) ==                 \
239                 (IF_WASM(EXPAND, TYPE == WASM_STRUCT_TYPE ||               \
240                                  TYPE == WASM_ARRAY_TYPE ||)               \
241                  TYPE == JS_PROXY_TYPE || TYPE == JS_GLOBAL_OBJECT_TYPE || \
242                  TYPE == JS_GLOBAL_PROXY_TYPE ||                           \
243                  TYPE == JS_MODULE_NAMESPACE_TYPE ||                       \
244                  TYPE == JS_SPECIAL_API_OBJECT_TYPE ||                     \
245                  TYPE == JS_PRIMITIVE_WRAPPER_TYPE));
246 // clang-format on
247 TORQUE_ASSIGNED_INSTANCE_TYPE_LIST(CHECK_INSTANCE_TYPE)
248 #undef CHECK_INSTANCE_TYPE
249 
250 // Make sure it doesn't matter whether we sign-extend or zero-extend these
251 // values, because Torque treats InstanceType as signed.
252 STATIC_ASSERT(LAST_TYPE < 1 << 15);
253 
254 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
255                                            InstanceType instance_type);
256 
257 // List of object types that have a single unique instance type.
258 #define INSTANCE_TYPE_CHECKERS_SINGLE(V)           \
259   TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(V) \
260   TORQUE_INSTANCE_CHECKERS_SINGLE_ONLY_DECLARED(V) \
261   V(BigInt, BIGINT_TYPE)                           \
262   V(FixedArrayExact, FIXED_ARRAY_TYPE)
263 
264 #define INSTANCE_TYPE_CHECKERS_RANGE(V)           \
265   TORQUE_INSTANCE_CHECKERS_RANGE_FULLY_DEFINED(V) \
266   TORQUE_INSTANCE_CHECKERS_RANGE_ONLY_DECLARED(V)
267 
268 #define INSTANCE_TYPE_CHECKERS_CUSTOM(V) \
269   V(FreeSpaceOrFiller)                   \
270   V(ExternalString)                      \
271   V(InternalizedString)
272 
273 #define INSTANCE_TYPE_CHECKERS(V)  \
274   INSTANCE_TYPE_CHECKERS_SINGLE(V) \
275   INSTANCE_TYPE_CHECKERS_RANGE(V)  \
276   INSTANCE_TYPE_CHECKERS_CUSTOM(V)
277 
278 namespace InstanceTypeChecker {
279 #define IS_TYPE_FUNCTION_DECL(Type, ...) \
280   V8_INLINE constexpr bool Is##Type(InstanceType instance_type);
281 
282 INSTANCE_TYPE_CHECKERS(IS_TYPE_FUNCTION_DECL)
283 
284 #define TYPED_ARRAY_IS_TYPE_FUNCTION_DECL(Type, ...) \
285   IS_TYPE_FUNCTION_DECL(Fixed##Type##Array)
286 TYPED_ARRAYS(TYPED_ARRAY_IS_TYPE_FUNCTION_DECL)
287 #undef TYPED_ARRAY_IS_TYPE_FUNCTION_DECL
288 
289 #undef IS_TYPE_FUNCTION_DECL
290 }  // namespace InstanceTypeChecker
291 
292 // This list must contain only maps that are shared by all objects of their
293 // instance type AND respective object must not represent a parent class for
294 // multiple instance types (e.g. DescriptorArray has a unique map, but it has
295 // a subclass StrongDescriptorArray which is included into the "DescriptorArray"
296 // range of instance types).
297 #define UNIQUE_LEAF_INSTANCE_TYPE_MAP_LIST_GENERATOR(V, _)                     \
298   V(_, AccessorInfoMap, accessor_info_map, AccessorInfo)                       \
299   V(_, AccessorPairMap, accessor_pair_map, AccessorPair)                       \
300   V(_, AllocationMementoMap, allocation_memento_map, AllocationMemento)        \
301   V(_, ArrayBoilerplateDescriptionMap, array_boilerplate_description_map,      \
302     ArrayBoilerplateDescription)                                               \
303   V(_, BreakPointMap, break_point_map, BreakPoint)                             \
304   V(_, BreakPointInfoMap, break_point_info_map, BreakPointInfo)                \
305   V(_, BytecodeArrayMap, bytecode_array_map, BytecodeArray)                    \
306   V(_, CachedTemplateObjectMap, cached_template_object_map,                    \
307     CachedTemplateObject)                                                      \
308   V(_, CellMap, cell_map, Cell)                                                \
309   V(_, WeakCellMap, weak_cell_map, WeakCell)                                   \
310   V(_, CodeMap, code_map, Code)                                                \
311   V(_, CodeDataContainerMap, code_data_container_map, CodeDataContainer)       \
312   V(_, CoverageInfoMap, coverage_info_map, CoverageInfo)                       \
313   V(_, DebugInfoMap, debug_info_map, DebugInfo)                                \
314   V(_, FreeSpaceMap, free_space_map, FreeSpace)                                \
315   V(_, FeedbackVectorMap, feedback_vector_map, FeedbackVector)                 \
316   V(_, FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArray)          \
317   V(_, FunctionTemplateInfoMap, function_template_info_map,                    \
318     FunctionTemplateInfo)                                                      \
319   V(_, MegaDomHandlerMap, mega_dom_handler_map, MegaDomHandler)                \
320   V(_, MetaMap, meta_map, Map)                                                 \
321   V(_, PreparseDataMap, preparse_data_map, PreparseData)                       \
322   V(_, PropertyArrayMap, property_array_map, PropertyArray)                    \
323   V(_, PrototypeInfoMap, prototype_info_map, PrototypeInfo)                    \
324   V(_, SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfo)    \
325   V(_, SmallOrderedHashSetMap, small_ordered_hash_set_map,                     \
326     SmallOrderedHashSet)                                                       \
327   V(_, SmallOrderedHashMapMap, small_ordered_hash_map_map,                     \
328     SmallOrderedHashMap)                                                       \
329   V(_, SmallOrderedNameDictionaryMap, small_ordered_name_dictionary_map,       \
330     SmallOrderedNameDictionary)                                                \
331   V(_, SwissNameDictionaryMap, swiss_name_dictionary_map, SwissNameDictionary) \
332   V(_, SymbolMap, symbol_map, Symbol)                                          \
333   V(_, TransitionArrayMap, transition_array_map, TransitionArray)              \
334   V(_, Tuple2Map, tuple2_map, Tuple2)
335 
336 // This list must contain only maps that are shared by all objects of their
337 // instance type.
338 #define UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR(V, _)           \
339   UNIQUE_LEAF_INSTANCE_TYPE_MAP_LIST_GENERATOR(V, _)            \
340   V(_, HeapNumberMap, heap_number_map, HeapNumber)              \
341   V(_, WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArray) \
342   TORQUE_DEFINED_MAP_CSA_LIST_GENERATOR(V, _)
343 
344 }  // namespace internal
345 }  // namespace v8
346 
347 #include "src/objects/object-macros-undef.h"
348 
349 #endif  // V8_OBJECTS_INSTANCE_TYPE_H_
350