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