v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
casting.h
Go to the documentation of this file.
1// Copyright 2024 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_CASTING_H_
6#define V8_OBJECTS_CASTING_H_
7
8#include <type_traits>
9
11#include "src/base/logging.h"
12#include "src/objects/tagged.h"
13
14namespace v8::internal {
15
16// CastTraits<T> is a type trait that defines type checking behaviour for
17// tagged object casting. The expected specialization is:
18//
19// template<>
20// struct CastTraits<SomeObject> {
21// template<typename From>
22// static bool AllowFrom(Tagged<From> value) {
23// return IsSomeObject(value);
24// }
25// };
26//
27// or, likely, just specializations of AllowFrom for Object and HeapObject,
28// under the assumption that the HeapObject implementation is the same for all
29// HeapObjects and the Object implementation has additional overhead in Smi
30// checks.
31//
32// struct CastTraits<Object> {
33// static bool AllowFrom(Tagged<HeapObject> value) {
34// return IsSomeObject(value);
35// }
36// static bool AllowFrom(Tagged<Object> value) {
37// return IsSomeObject(value);
38// }
39// };
40//
41template <typename To>
43
44// `Is<T>(value)` checks whether `value` is a tagged object of type `T`.
45template <typename T, typename U>
46inline bool Is(Tagged<U> value) {
47 return CastTraits<T>::AllowFrom(value);
48}
49template <typename T, typename U>
50inline bool Is(IndirectHandle<U> value);
51template <typename T, typename U>
52inline bool Is(MaybeIndirectHandle<U> value);
53template <typename T, typename U>
54inline bool Is(DirectHandle<U> value);
55template <typename T, typename U>
56inline bool Is(MaybeDirectHandle<U> value);
57
58// `UncheckedCast<T>(value)` casts `value` to a tagged object of type `T`,
59// without checking the type of value.
60template <typename To, typename From>
62 return Tagged<To>(value.ptr());
63}
64template <typename To, typename From>
66template <typename To, typename From>
68template <typename To, typename From>
70template <typename To, typename From>
72
73// `TryCast<T>(value, &out)` casts `value` to a tagged object of type `T` and
74// writes the value to `out`, returning true if the cast succeeded and false if
75// it failed.
76template <typename To, typename From>
77inline bool TryCast(Tagged<From> value, Tagged<To>* out) {
78 if (!Is<To>(value)) return false;
79 *out = UncheckedCast<To>(value);
80 return true;
81}
82template <typename To, typename From>
84 if (!Is<To>(value)) return false;
85 *out = UncheckedCast<To>(value);
86 return true;
87}
88template <typename To, typename From>
90 if (!Is<To>(value)) return false;
91 *out = UncheckedCast<To>(value);
92 return true;
93}
94template <typename To, typename From>
96 if (!Is<To>(value)) return false;
97 *out = UncheckedCast<To>(value);
98 return true;
99}
100template <typename To, typename From>
103 if (!Is<To>(value)) return false;
104 *out = UncheckedCast<To>(value);
105 return true;
106}
107template <typename To, typename From>
110 if (!Is<To>(value)) return false;
111 *out = UncheckedCast<To>(value);
112 return true;
113}
114template <typename To, typename From>
116 if (!Is<To>(value)) return false;
117 *out = UncheckedCast<To>(value);
118 return true;
119}
120
121// Only initialise the SourceLocation in debug mode.
122#ifdef DEBUG
123#define INIT_SOURCE_LOCATION_IN_DEBUG v8::SourceLocation::Current()
124#else
125#define INIT_SOURCE_LOCATION_IN_DEBUG v8::SourceLocation()
126#endif
127
128#ifdef DEBUG
129template <typename T>
130bool GCAwareObjectTypeCheck(Tagged<Object> object, const Heap* heap);
131#endif // DEBUG
132
133// `GCSafeCast<T>(value)` casts `object` to a tagged object of type `T` and
134// should be used when the cast can be called from within a GC. The case all
135// includes a debug check that `object` is either a tagged object of type `T`,
136// or one of few special cases possible during GC (see GCAwareObjectTypeCheck):
137// 1) `object` was already evacuated and the forwarding address refers to a
138// tagged object of type `T`.
139// 2) During Scavenger, `object` is a large object.
140// 3) During a conservative Scavenger, `object` is a pinned object.
141template <typename T>
143 DCHECK(GCAwareObjectTypeCheck<T>(object, heap));
144 return UncheckedCast<T>(object);
145}
146
147// `Cast<T>(value)` casts `value` to a tagged object of type `T`, with a debug
148// check that `value` is a tagged object of type `T`.
149template <typename To, typename From>
153 V8_PRETTY_FUNCTION_VALUE_OR("Cast type check"), loc);
154 return UncheckedCast<To>(value);
155}
156template <typename To, typename From>
161 V8_PRETTY_FUNCTION_VALUE_OR("Cast type check"), loc);
162 return UncheckedCast<To>(value);
163}
164template <typename To, typename From>
166 DirectHandle<From> value,
169 V8_PRETTY_FUNCTION_VALUE_OR("Cast type check"), loc);
170 return UncheckedCast<To>(value);
171}
172template <typename To, typename From>
180template <typename To, typename From>
188
189// TODO(leszeks): Figure out a way to make these cast to actual pointers rather
190// than Tagged.
191template <typename To, typename From>
192inline Tagged<To> UncheckedCast(const From* value) {
193 return UncheckedCast<To>(Tagged(value));
194}
195template <typename To, typename From>
196inline Tagged<To> Cast(const From* value, const v8::SourceLocation& loc =
198 return Cast<To>(Tagged(value), loc);
199}
200template <typename To, typename From>
201inline Tagged<To> UncheckedCast(From value) {
202 return UncheckedCast<To>(Tagged(value));
203}
204template <typename To, typename From>
206 From value, const v8::SourceLocation& loc = INIT_SOURCE_LOCATION_IN_DEBUG) {
207 return Cast<To>(Tagged(value), loc);
208}
209
210// `Is<T>(maybe_weak_value)` specialization for possible weak values and strong
211// target `T`, that additionally first checks whether `maybe_weak_value` is
212// actually a strong value (or a Smi, which can't be weak).
213template <typename T, typename U>
214inline bool Is(Tagged<MaybeWeak<U>> value) {
215 // Cast from maybe weak to strong needs to be strong or smi.
216 if constexpr (!is_maybe_weak_v<T>) {
217 if (!value.IsStrongOrSmi()) return false;
218 return CastTraits<T>::AllowFrom(Tagged<U>(value.ptr()));
219 } else {
220 // Dispatches to CastTraits<MaybeWeak<T>> below.
221 return CastTraits<T>::AllowFrom(value);
222 }
223}
224template <typename T, typename... U>
225constexpr inline bool Is(Tagged<Union<U...>> value) {
226 using UnionU = Union<U...>;
227 if constexpr (is_subtype_v<UnionU, HeapObject>) {
228 return Is<T>(Tagged<HeapObject>(value));
229 } else if constexpr (is_subtype_v<UnionU, MaybeWeak<HeapObject>>) {
230 return Is<T>(Tagged<MaybeWeak<HeapObject>>(value));
231 } else if constexpr (is_subtype_v<UnionU, Object>) {
232 return Is<T>(Tagged<Object>(value));
233 } else {
235 return Is<T>(Tagged<MaybeWeak<Object>>(value));
236 }
237}
238
239// Specialization for maybe weak cast targets, which first converts the incoming
240// value to a strong reference and then checks if the cast to the strong T
241// is allowed. Cleared weak references always return true.
242template <typename T>
244 template <typename U>
245 static bool AllowFrom(Tagged<U> value) {
246 if constexpr (is_maybe_weak_v<U>) {
247 // Cleared values are always ok.
248 if (value.IsCleared()) return true;
249 // TODO(leszeks): Skip Smi check for values that are known to not be Smi.
250 if (value.IsSmi()) {
251 return CastTraits<T>::AllowFrom(Tagged<Smi>(value.ptr()));
252 }
254 } else {
255 return CastTraits<T>::AllowFrom(value);
256 }
257 }
258};
259
260template <>
262 static inline bool AllowFrom(Tagged<Object> value) { return true; }
263};
264template <>
266 static inline bool AllowFrom(Tagged<Object> value) { return value.IsSmi(); }
267 static inline bool AllowFrom(Tagged<HeapObject> value) { return false; }
268};
269template <>
271 static inline bool AllowFrom(Tagged<Object> value) {
272 return value.IsHeapObject();
273 }
274 static inline bool AllowFrom(Tagged<HeapObject> value) { return true; }
275};
276
277} // namespace v8::internal
278
279#undef INIT_SOURCE_LOCATION_IN_DEBUG
280
281#endif // V8_OBJECTS_CASTING_H_
#define T
#define INIT_SOURCE_LOCATION_IN_DEBUG
Definition casting.h:125
bool TryCast(Tagged< From > value, Tagged< To > *out)
Definition casting.h:77
Tagged< T > MakeStrong(Tagged< T > value)
Definition tagged.h:903
static constexpr bool is_maybe_weak_v
Definition tagged.h:94
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
Tagged(T object) -> Tagged< T >
MaybeHandle< T > MaybeIndirectHandle
Definition globals.h:1109
Tagged< T > GCSafeCast(Tagged< Object > object, const Heap *heap)
Definition casting.h:142
static constexpr bool is_subtype_v
Definition tagged.h:121
Handle< To > UncheckedCast(Handle< From > value)
Definition handles-inl.h:55
constexpr int U
Handle< T > IndirectHandle
Definition globals.h:1086
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_WITH_MSG_AND_LOC(condition, message, location)
Definition logging.h:484
#define DCHECK(condition)
Definition logging.h:482
#define V8_PRETTY_FUNCTION_VALUE_OR(ELSE)
Definition macros.h:221
static bool AllowFrom(Tagged< Object > value)
Definition casting.h:271
static bool AllowFrom(Tagged< HeapObject > value)
Definition casting.h:274
static bool AllowFrom(Tagged< U > value)
Definition casting.h:245
static bool AllowFrom(Tagged< Object > value)
Definition casting.h:262
static bool AllowFrom(Tagged< Object > value)
Definition casting.h:266
static bool AllowFrom(Tagged< HeapObject > value)
Definition casting.h:267