JSArrayBuffer should have its own JSType
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSCast.h
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include "JSCell.h"
29
30 namespace JSC {
31
32 template<typename To, typename From>
33 inline To jsCast(From* from)
34 {
35     static_assert(std::is_base_of<JSCell, typename std::remove_pointer<To>::type>::value && std::is_base_of<JSCell, typename std::remove_pointer<From>::type>::value, "JS casting expects that the types you are casting to/from are subclasses of JSCell");
36     ASSERT_WITH_SECURITY_IMPLICATION(!from || from->JSCell::inherits(*from->JSCell::vm(), std::remove_pointer<To>::type::info()));
37     return static_cast<To>(from);
38 }
39
40 template<typename To>
41 inline To jsCast(JSValue from)
42 {
43     static_assert(std::is_base_of<JSCell, typename std::remove_pointer<To>::type>::value, "JS casting expects that the types you are casting to is a subclass of JSCell");
44     ASSERT_WITH_SECURITY_IMPLICATION(from.isCell() && from.asCell()->JSCell::inherits(*from.asCell()->vm(), std::remove_pointer<To>::type::info()));
45     return static_cast<To>(from.asCell());
46 }
47
48 // Specific type overloads.
49 #define FOR_EACH_JS_DYNAMIC_CAST_JS_TYPE_OVERLOAD(macro) \
50     macro(JSFixedArray, JSType::JSFixedArrayType, JSType::JSFixedArrayType) \
51     macro(JSObject, FirstObjectType, LastObjectType) \
52     macro(JSFinalObject, JSType::FinalObjectType, JSType::FinalObjectType) \
53     macro(JSFunction, JSType::JSFunctionType, JSType::JSFunctionType) \
54     macro(InternalFunction, JSType::InternalFunctionType, JSType::InternalFunctionType) \
55     macro(JSArray, JSType::ArrayType, JSType::DerivedArrayType) \
56     macro(JSArrayBuffer, JSType::ArrayBufferType, JSType::ArrayBufferType) \
57     macro(JSArrayBufferView, FirstTypedArrayType, LastTypedArrayType) \
58     macro(JSSet, JSType::JSSetType, JSType::JSSetType) \
59     macro(JSMap, JSType::JSMapType, JSType::JSMapType) \
60     macro(JSWeakSet, JSType::JSWeakSetType, JSType::JSWeakSetType) \
61     macro(JSWeakMap, JSType::JSWeakMapType, JSType::JSWeakMapType) \
62     macro(NumberObject, JSType::NumberObjectType, JSType::NumberObjectType) \
63     macro(ProxyObject, JSType::ProxyObjectType, JSType::ProxyObjectType) \
64     macro(RegExpObject, JSType::RegExpObjectType, JSType::RegExpObjectType) \
65     macro(WebAssemblyToJSCallee, JSType::WebAssemblyToJSCalleeType, JSType::WebAssemblyToJSCalleeType) \
66     macro(DirectArguments, JSType::DirectArgumentsType, JSType::DirectArgumentsType) \
67     macro(ScopedArguments, JSType::ScopedArgumentsType, JSType::ScopedArgumentsType) \
68     macro(ClonedArguments, JSType::ClonedArgumentsType, JSType::ClonedArgumentsType) \
69     macro(JSGlobalObject, JSType::GlobalObjectType, JSType::GlobalObjectType) \
70     macro(JSGlobalLexicalEnvironment, JSType::GlobalLexicalEnvironmentType, JSType::GlobalLexicalEnvironmentType) \
71     macro(JSSegmentedVariableObject, JSType::GlobalObjectType, JSType::GlobalLexicalEnvironmentType) \
72     macro(JSModuleEnvironment, JSType::ModuleEnvironmentType, JSType::ModuleEnvironmentType) \
73     macro(JSLexicalEnvironment, JSType::LexicalEnvironmentType, JSType::ModuleEnvironmentType) \
74     macro(JSSymbolTableObject, JSType::GlobalObjectType, JSType::ModuleEnvironmentType) \
75     macro(JSScope, JSType::GlobalObjectType, JSType::WithScopeType) \
76
77
78 // Forward declare the classes because they may not already exist.
79 #define FORWARD_DECLARE_OVERLOAD_CLASS(className, jsType, op) class className;
80 FOR_EACH_JS_DYNAMIC_CAST_JS_TYPE_OVERLOAD(FORWARD_DECLARE_OVERLOAD_CLASS)
81 #undef FORWARD_DECLARE_OVERLOAD_CLASS
82
83 namespace JSCastingHelpers {
84
85 template<bool isFinal>
86 struct FinalTypeDispatcher {
87     template<typename Target, typename From>
88     static inline bool inheritsGeneric(VM& vm, From* from)
89     {
90         static_assert(!std::is_same<JSObject*, Target*>::value, "This ensures our overloads work");
91         static_assert(std::is_base_of<JSCell, Target>::value && std::is_base_of<JSCell, typename std::remove_pointer<From>::type>::value, "JS casting expects that the types you are casting to/from are subclasses of JSCell");
92         // Do not use inherits<Target>(vm) since inherits<T> depends on this function.
93         return from->JSCell::inherits(vm, Target::info());
94     }
95 };
96
97 template<>
98 struct FinalTypeDispatcher</* isFinal */ true> {
99     template<typename Target, typename From>
100     static inline bool inheritsGeneric(VM& vm, From* from)
101     {
102         static_assert(!std::is_same<JSObject*, Target*>::value, "This ensures our overloads work");
103         static_assert(std::is_base_of<JSCell, Target>::value && std::is_base_of<JSCell, typename std::remove_pointer<From>::type>::value, "JS casting expects that the types you are casting to/from are subclasses of JSCell");
104         static_assert(std::is_final<Target>::value, "Target is a final type");
105         bool canCast = from->JSCell::classInfo(vm) == Target::info();
106         // Do not use inherits<Target>(vm) since inherits<T> depends on this function.
107         ASSERT_UNUSED(vm, canCast == from->JSCell::inherits(vm, Target::info()));
108         return canCast;
109     }
110 };
111
112 template<typename Target, typename From>
113 inline bool inheritsJSTypeImpl(VM& vm, From* from, JSType firstType, JSType lastType)
114 {
115     static_assert(std::is_base_of<JSCell, Target>::value && std::is_base_of<JSCell, typename std::remove_pointer<From>::type>::value, "JS casting expects that the types you are casting to/from are subclasses of JSCell");
116     bool canCast = firstType <= from->type() && from->type() <= lastType;
117     // Do not use inherits<Target>(vm) since inherits<T> depends on this function.
118     ASSERT_UNUSED(vm, canCast == from->JSCell::inherits(vm, Target::info()));
119     return canCast;
120 }
121
122 // C++ has bad syntax so we need to use this struct because C++ doesn't have a
123 // way to say that we are overloading just the first type in a template list...
124 template<typename Target>
125 struct InheritsTraits {
126     template<typename From>
127     static inline bool inherits(VM& vm, From* from) { return FinalTypeDispatcher<std::is_final<Target>::value>::template inheritsGeneric<Target>(vm, from); }
128 };
129
130 #define DEFINE_TRAITS_FOR_JS_TYPE_OVERLOAD(className, firstJSType, lastJSType) \
131     template<> \
132     struct InheritsTraits<className> { \
133         template<typename From> \
134         static inline bool inherits(VM& vm, From* from) { return inheritsJSTypeImpl<className, From>(vm, from, static_cast<JSType>(firstJSType), static_cast<JSType>(lastJSType)); } \
135     }; \
136
137 FOR_EACH_JS_DYNAMIC_CAST_JS_TYPE_OVERLOAD(DEFINE_TRAITS_FOR_JS_TYPE_OVERLOAD)
138
139 #undef DEFINE_TRAITS_FOR_JS_TYPE_OVERLOAD
140
141
142 template<typename Target, typename From>
143 bool inherits(VM& vm, From* from)
144 {
145     using Dispatcher = InheritsTraits<Target>;
146     return Dispatcher::template inherits(vm, from);
147 }
148
149 } // namespace JSCastingHelpers
150
151 template<typename To, typename From>
152 To jsDynamicCast(VM& vm, From* from)
153 {
154     using Dispatcher = JSCastingHelpers::InheritsTraits<typename std::remove_cv<typename std::remove_pointer<To>::type>::type>;
155     if (LIKELY(Dispatcher::template inherits(vm, from)))
156         return static_cast<To>(from);
157     return nullptr;
158 }
159
160 template<typename To>
161 To jsDynamicCast(VM& vm, JSValue from)
162 {
163     if (UNLIKELY(!from.isCell()))
164         return nullptr;
165     return jsDynamicCast<To>(vm, from.asCell());
166 }
167
168 }