693e2ce6c657fff6744c2f1de62c310e7fa0c981
[WebKit-https.git] / Source / JavaScriptCore / b3 / B3CheckSpecial.h
1 /*
2  * Copyright (C) 2015-2016 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 #if ENABLE(B3_JIT)
29
30 #include "AirArg.h"
31 #include "AirKind.h"
32 #include "B3StackmapSpecial.h"
33 #include <wtf/HashMap.h>
34
35 namespace JSC { namespace B3 {
36
37 namespace Air {
38 struct Inst;
39 }
40
41 // We want to lower Check instructions to a branch, but then we want to route that branch to our
42 // out-of-line code instead of doing anything else. For this reason, a CheckSpecial will remember
43 // which branch opcode we have selected along with the number of args in the overload we want. It
44 // will create an Inst with that opcode plus the appropriate args from the owning Inst whenever you
45 // call any of the callbacks.
46 //
47 // Note that for CheckAdd, CheckSub, and CheckMul we expect that the B3 arguments are the reverse
48 // of the Air arguments (Add(a, b) => Add32 b, a). Except:
49 // - CheckSub(0, x), which turns into BranchNeg32 x.
50 // - CheckMul(a, b), which turns into Mul32 b, a but we pass Any for a's ValueRep.
51
52 class CheckSpecial : public StackmapSpecial {
53 public:
54     // Support for hash consing these things.
55     class Key {
56     public:
57         Key()
58             : m_stackmapRole(SameAsRep)
59             , m_numArgs(0)
60         {
61         }
62         
63         Key(Air::Kind kind, unsigned numArgs, RoleMode stackmapRole = SameAsRep)
64             : m_kind(kind)
65             , m_stackmapRole(stackmapRole)
66             , m_numArgs(numArgs)
67         {
68         }
69
70         explicit Key(const Air::Inst&);
71
72         bool operator==(const Key& other) const
73         {
74             return m_kind == other.m_kind
75                 && m_numArgs == other.m_numArgs
76                 && m_stackmapRole == other.m_stackmapRole;
77         }
78
79         bool operator!=(const Key& other) const
80         {
81             return !(*this == other);
82         }
83
84         explicit operator bool() const { return *this != Key(); }
85
86         Air::Kind kind() const { return m_kind; }
87         unsigned numArgs() const { return m_numArgs; }
88         RoleMode stackmapRole() const { return m_stackmapRole; }
89
90         void dump(PrintStream& out) const;
91
92         Key(WTF::HashTableDeletedValueType)
93             : m_stackmapRole(SameAsRep)
94             , m_numArgs(1)
95         {
96         }
97
98         bool isHashTableDeletedValue() const
99         {
100             return *this == Key(WTF::HashTableDeletedValue);
101         }
102
103         unsigned hash() const
104         {
105             // Seriously, we don't need to be smart here. It just doesn't matter.
106             return m_kind.hash() + m_numArgs + m_stackmapRole;
107         }
108         
109     private:
110         Air::Kind m_kind;
111         RoleMode m_stackmapRole;
112         unsigned m_numArgs;
113     };
114     
115     CheckSpecial(Air::Kind, unsigned numArgs, RoleMode stackmapRole = SameAsRep);
116     CheckSpecial(const Key&);
117     ~CheckSpecial();
118
119 protected:
120     // Constructs and returns the Inst representing the branch that this will use.
121     Air::Inst hiddenBranch(const Air::Inst&) const;
122
123     void forEachArg(Air::Inst&, const ScopedLambda<Air::Inst::EachArgCallback>&) final;
124     bool isValid(Air::Inst&) final;
125     bool admitsStack(Air::Inst&, unsigned argIndex) final;
126     bool admitsExtendedOffsetAddr(Air::Inst&, unsigned) final;
127     Optional<unsigned> shouldTryAliasingDef(Air::Inst&) final;
128
129     // NOTE: the generate method will generate the hidden branch and then register a LatePath that
130     // generates the stackmap. Super crazy dude!
131
132     CCallHelpers::Jump generate(Air::Inst&, CCallHelpers&, Air::GenerationContext&) final;
133
134     void dumpImpl(PrintStream&) const final;
135     void deepDumpImpl(PrintStream&) const final;
136
137 private:
138     Air::Kind m_checkKind;
139     RoleMode m_stackmapRole;
140     unsigned m_numCheckArgs;
141 };
142
143 struct CheckSpecialKeyHash {
144     static unsigned hash(const CheckSpecial::Key& key) { return key.hash(); }
145     static bool equal(const CheckSpecial::Key& a, const CheckSpecial::Key& b) { return a == b; }
146     static const bool safeToCompareToEmptyOrDeleted = true;
147 };
148
149 } } // namespace JSC::B3
150
151 namespace WTF {
152
153 template<typename T> struct DefaultHash;
154 template<> struct DefaultHash<JSC::B3::CheckSpecial::Key> {
155     typedef JSC::B3::CheckSpecialKeyHash Hash;
156 };
157
158 template<typename T> struct HashTraits;
159 template<> struct HashTraits<JSC::B3::CheckSpecial::Key> : SimpleClassHashTraits<JSC::B3::CheckSpecial::Key> {
160     // I don't want to think about this very hard, it's not worth it. I'm a be conservative.
161     static const bool emptyValueIsZero = false;
162 };
163
164 } // namespace WTF
165
166 #endif // ENABLE(B3_JIT)