We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / bytecode / CallVariant.h
1 /*
2  * Copyright (C) 2014-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 "FunctionExecutable.h"
29 #include "JSCast.h"
30 #include "JSFunction.h"
31 #include "NativeExecutable.h"
32
33 namespace JSC {
34
35 // The CallVariant class is meant to encapsulate a callee in a way that is useful for call linking
36 // and inlining. Because JavaScript has closures, and because JSC implements the notion of internal
37 // non-function objects that nevertheless provide call traps, the call machinery wants to see a
38 // callee in one of the following four forms:
39 //
40 // JSFunction callee: This means that we expect the callsite to always call a particular function
41 //     instance, that is associated with a particular lexical environment. This pinpoints not
42 //     just the code that will be called (i.e. the executable) but also the scope within which
43 //     the code runs.
44 //
45 // Executable callee: This corresponds to a call to a closure. In this case, we know that the
46 //     callsite will call a JSFunction, but we do not know which particular JSFunction. We do know
47 //     what code will be called - i.e. we know the executable.
48 //
49 // InternalFunction callee: JSC supports a special kind of native functions that support bizarre
50 //     semantics. These are always singletons. If we know that the callee is an InternalFunction
51 //     then we know both the code that will be called and the scope; in fact the "scope" is really
52 //     just the InternalFunction itself.
53 //
54 // Something else: It's possible call all manner of rubbish in JavaScript. This implicitly supports
55 //     bizarre object callees, but it can't really tell you anything interesting about them other
56 //     than the fact that they don't fall into any of the above categories.
57 //
58 // This class serves as a kind of union over these four things. It does so by just holding a
59 // JSCell*. We determine which of the modes its in by doing type checks on the cell. Note that we
60 // cannot use WriteBarrier<> here because this gets used inside the compiler.
61
62 class CallVariant {
63 public:
64     explicit CallVariant(JSCell* callee = nullptr)
65         : m_callee(callee)
66     {
67     }
68     
69     CallVariant(WTF::HashTableDeletedValueType)
70         : m_callee(deletedToken())
71     {
72     }
73     
74     explicit operator bool() const { return !!m_callee; }
75     
76     // If this variant refers to a function, change it to refer to its executable.
77     ALWAYS_INLINE CallVariant despecifiedClosure() const
78     {
79         if (m_callee->type() == JSFunctionType)
80             return CallVariant(jsCast<JSFunction*>(m_callee)->executable());
81         return *this;
82     }
83     
84     JSCell* rawCalleeCell() const { return m_callee; }
85     
86     InternalFunction* internalFunction() const
87     {
88         return jsDynamicCast<InternalFunction*>(*m_callee->vm(), m_callee);
89     }
90     
91     JSFunction* function() const
92     {
93         return jsDynamicCast<JSFunction*>(*m_callee->vm(), m_callee);
94     }
95     
96     bool isClosureCall() const { return !!jsDynamicCast<ExecutableBase*>(*m_callee->vm(), m_callee); }
97     
98     ExecutableBase* executable() const
99     {
100         if (JSFunction* function = this->function())
101             return function->executable();
102         return jsDynamicCast<ExecutableBase*>(*m_callee->vm(), m_callee);
103     }
104     
105     JSCell* nonExecutableCallee() const
106     {
107         RELEASE_ASSERT(!isClosureCall());
108         return m_callee;
109     }
110     
111     Intrinsic intrinsicFor(CodeSpecializationKind kind) const
112     {
113         if (ExecutableBase* executable = this->executable())
114             return executable->intrinsicFor(kind);
115         return NoIntrinsic;
116     }
117     
118     FunctionExecutable* functionExecutable() const
119     {
120         if (ExecutableBase* executable = this->executable())
121             return jsDynamicCast<FunctionExecutable*>(*m_callee->vm(), executable);
122         return nullptr;
123     }
124
125     NativeExecutable* nativeExecutable() const
126     {
127         if (ExecutableBase* executable = this->executable())
128             return jsDynamicCast<NativeExecutable*>(*m_callee->vm(), executable);
129         return nullptr;
130     }
131
132     const DOMJIT::Signature* signatureFor(CodeSpecializationKind kind) const
133     {
134         if (NativeExecutable* nativeExecutable = this->nativeExecutable())
135             return nativeExecutable->signatureFor(kind);
136         return nullptr;
137     }
138     
139     bool finalize();
140     
141     bool merge(const CallVariant&);
142     
143     void filter(VM&, JSValue);
144     
145     void dump(PrintStream& out) const;
146     
147     bool isHashTableDeletedValue() const
148     {
149         return m_callee == deletedToken();
150     }
151     
152     bool operator==(const CallVariant& other) const
153     {
154         return m_callee == other.m_callee;
155     }
156     
157     bool operator!=(const CallVariant& other) const
158     {
159         return !(*this == other);
160     }
161     
162     bool operator<(const CallVariant& other) const
163     {
164         return m_callee < other.m_callee;
165     }
166     
167     bool operator>(const CallVariant& other) const
168     {
169         return other < *this;
170     }
171     
172     bool operator<=(const CallVariant& other) const
173     {
174         return !(*this < other);
175     }
176     
177     bool operator>=(const CallVariant& other) const
178     {
179         return other <= *this;
180     }
181     
182     unsigned hash() const
183     {
184         return WTF::PtrHash<JSCell*>::hash(m_callee);
185     }
186     
187 private:
188     static JSCell* deletedToken() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); }
189     
190     JSCell* m_callee;
191 };
192
193 struct CallVariantHash {
194     static unsigned hash(const CallVariant& key) { return key.hash(); }
195     static bool equal(const CallVariant& a, const CallVariant& b) { return a == b; }
196     static const bool safeToCompareToEmptyOrDeleted = true;
197 };
198
199 typedef Vector<CallVariant, 1> CallVariantList;
200
201 // Returns a new variant list by attempting to either append the given variant or merge it with one
202 // of the variants we already have by despecifying closures.
203 CallVariantList variantListWithVariant(const CallVariantList&, CallVariant);
204
205 // Returns a new list where every element is despecified, and the list is deduplicated.
206 CallVariantList despecifiedVariantList(const CallVariantList&);
207
208 } // namespace JSC
209
210 namespace WTF {
211
212 template<typename T> struct DefaultHash;
213 template<> struct DefaultHash<JSC::CallVariant> {
214     typedef JSC::CallVariantHash Hash;
215 };
216
217 template<typename T> struct HashTraits;
218 template<> struct HashTraits<JSC::CallVariant> : SimpleClassHashTraits<JSC::CallVariant> { };
219
220 } // namespace WTF