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