[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / JavaScriptCore / b3 / B3StackmapSpecial.cpp
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 #include "config.h"
27 #include "B3StackmapSpecial.h"
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirCode.h"
32 #include "AirGenerationContext.h"
33 #include "B3ValueInlines.h"
34
35 namespace JSC { namespace B3 {
36
37 using namespace Air;
38
39 StackmapSpecial::StackmapSpecial()
40 {
41 }
42
43 StackmapSpecial::~StackmapSpecial()
44 {
45 }
46
47 void StackmapSpecial::reportUsedRegisters(Inst& inst, const RegisterSet& usedRegisters)
48 {
49     StackmapValue* value = inst.origin->as<StackmapValue>();
50     ASSERT(value);
51
52     // FIXME: If the Inst that uses the StackmapSpecial gets duplicated, then we end up merging used
53     // register sets from multiple places. This currently won't happen since Air doesn't have taildup
54     // or things like that. But maybe eventually it could be a problem.
55     value->m_usedRegisters.merge(usedRegisters);
56 }
57
58 RegisterSet StackmapSpecial::extraClobberedRegs(Inst& inst)
59 {
60     StackmapValue* value = inst.origin->as<StackmapValue>();
61     ASSERT(value);
62
63     return value->lateClobbered();
64 }
65
66 RegisterSet StackmapSpecial::extraEarlyClobberedRegs(Inst& inst)
67 {
68     StackmapValue* value = inst.origin->as<StackmapValue>();
69     ASSERT(value);
70
71     return value->earlyClobbered();
72 }
73
74 void StackmapSpecial::forEachArgImpl(
75     unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
76     Inst& inst, RoleMode roleMode, std::optional<unsigned> firstRecoverableIndex,
77     const ScopedLambda<Inst::EachArgCallback>& callback)
78 {
79     StackmapValue* value = inst.origin->as<StackmapValue>();
80     ASSERT(value);
81
82     // Check that insane things have not happened.
83     ASSERT(inst.args.size() >= numIgnoredAirArgs);
84     ASSERT(value->children().size() >= numIgnoredB3Args);
85     ASSERT(inst.args.size() - numIgnoredAirArgs >= value->children().size() - numIgnoredB3Args);
86     
87     for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
88         Arg& arg = inst.args[i + numIgnoredAirArgs];
89         ConstrainedValue child = value->constrainedChild(i + numIgnoredB3Args);
90
91         Arg::Role role;
92         switch (roleMode) {
93         case ForceLateUseUnlessRecoverable:
94             ASSERT(firstRecoverableIndex);
95             if (arg != inst.args[*firstRecoverableIndex] && arg != inst.args[*firstRecoverableIndex + 1]) {
96                 role = Arg::LateColdUse;
97                 break;
98             }
99             FALLTHROUGH;
100         case SameAsRep:
101             switch (child.rep().kind()) {
102             case ValueRep::WarmAny:
103             case ValueRep::SomeRegister:
104             case ValueRep::Register:
105             case ValueRep::Stack:
106             case ValueRep::StackArgument:
107             case ValueRep::Constant:
108                 role = Arg::Use;
109                 break;
110             case ValueRep::LateRegister:
111                 role = Arg::LateUse;
112                 break;
113             case ValueRep::ColdAny:
114                 role = Arg::ColdUse;
115                 break;
116             case ValueRep::LateColdAny:
117                 role = Arg::LateColdUse;
118                 break;
119             default:
120                 RELEASE_ASSERT_NOT_REACHED();
121                 break;
122             }
123             break;
124         case ForceLateUse:
125             role = Arg::LateColdUse;
126             break;
127         }
128
129         Type type = child.value()->type();
130         callback(arg, role, Arg::typeForB3Type(type), Arg::widthForB3Type(type));
131     }
132 }
133
134 bool StackmapSpecial::isValidImpl(
135     unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
136     Inst& inst)
137 {
138     StackmapValue* value = inst.origin->as<StackmapValue>();
139     ASSERT(value);
140
141     // Check that insane things have not happened.
142     ASSERT(inst.args.size() >= numIgnoredAirArgs);
143     ASSERT(value->children().size() >= numIgnoredB3Args);
144
145     // For the Inst to be valid, it needs to have the right number of arguments.
146     if (inst.args.size() - numIgnoredAirArgs < value->children().size() - numIgnoredB3Args)
147         return false;
148
149     // Regardless of constraints, stackmaps have some basic requirements for their arguments. For
150     // example, you can't have a non-FP-offset address. This verifies those conditions as well as the
151     // argument types.
152     for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
153         Value* child = value->child(i + numIgnoredB3Args);
154         Arg& arg = inst.args[i + numIgnoredAirArgs];
155
156         if (!isArgValidForValue(arg, child))
157             return false;
158     }
159
160     // The number of constraints has to be no greater than the number of B3 children.
161     ASSERT(value->m_reps.size() <= value->children().size());
162
163     // Verify any explicitly supplied constraints.
164     for (unsigned i = numIgnoredB3Args; i < value->m_reps.size(); ++i) {
165         ValueRep& rep = value->m_reps[i];
166         Arg& arg = inst.args[i - numIgnoredB3Args + numIgnoredAirArgs];
167
168         if (!isArgValidForRep(code(), arg, rep))
169             return false;
170     }
171
172     return true;
173 }
174
175 bool StackmapSpecial::admitsStackImpl(
176     unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
177     Inst& inst, unsigned argIndex)
178 {
179     StackmapValue* value = inst.origin->as<StackmapValue>();
180     ASSERT(value);
181
182     unsigned stackmapArgIndex = argIndex - numIgnoredAirArgs + numIgnoredB3Args;
183
184     if (stackmapArgIndex >= value->numChildren()) {
185         // It's not a stackmap argument, so as far as we are concerned, it doesn't admit stack.
186         return false;
187     }
188
189     if (stackmapArgIndex >= value->m_reps.size()) {
190         // This means that there was no constraint.
191         return true;
192     }
193     
194     // We only admit stack for Any's, since Stack is not a valid input constraint, and StackArgument
195     // translates to a CallArg in Air.
196     if (value->m_reps[stackmapArgIndex].isAny())
197         return true;
198
199     return false;
200 }
201
202 Vector<ValueRep> StackmapSpecial::repsImpl(
203     GenerationContext& context, unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Inst& inst)
204 {
205     Vector<ValueRep> result;
206     for (unsigned i = 0; i < inst.origin->numChildren() - numIgnoredB3Args; ++i)
207         result.append(repForArg(*context.code, inst.args[i + numIgnoredAirArgs]));
208     return result;
209 }
210
211 bool StackmapSpecial::isArgValidForValue(const Air::Arg& arg, Value* value)
212 {
213     switch (arg.kind()) {
214     case Arg::Tmp:
215     case Arg::Imm:
216     case Arg::BigImm:
217         break;
218     default:
219         if (!arg.isStackMemory())
220             return false;
221         break;
222     }
223
224     return arg.canRepresent(value);
225 }
226
227 bool StackmapSpecial::isArgValidForRep(Air::Code& code, const Air::Arg& arg, const ValueRep& rep)
228 {
229     switch (rep.kind()) {
230     case ValueRep::WarmAny:
231     case ValueRep::ColdAny:
232     case ValueRep::LateColdAny:
233         // We already verified by isArgValidForValue().
234         return true;
235     case ValueRep::SomeRegister:
236     case ValueRep::SomeEarlyRegister:
237         return arg.isTmp();
238     case ValueRep::LateRegister:
239     case ValueRep::Register:
240         return arg == Tmp(rep.reg());
241     case ValueRep::StackArgument:
242         if (arg == Arg::callArg(rep.offsetFromSP()))
243             return true;
244         if (arg.isAddr() && code.frameSize()) {
245             if (arg.base() == Tmp(GPRInfo::callFrameRegister)
246                 && arg.offset() == rep.offsetFromSP() - code.frameSize())
247                 return true;
248             if (arg.base() == Tmp(MacroAssembler::stackPointerRegister)
249                 && arg.offset() == rep.offsetFromSP())
250                 return true;
251         }
252         return false;
253     default:
254         RELEASE_ASSERT_NOT_REACHED();
255         return false;
256     }
257 }
258
259 ValueRep StackmapSpecial::repForArg(Code& code, const Arg& arg)
260 {
261     switch (arg.kind()) {
262     case Arg::Tmp:
263         return ValueRep::reg(arg.reg());
264         break;
265     case Arg::Imm:
266     case Arg::BigImm:
267         return ValueRep::constant(arg.value());
268         break;
269     case Arg::Addr:
270         if (arg.base() == Tmp(GPRInfo::callFrameRegister))
271             return ValueRep::stack(arg.offset());
272         ASSERT(arg.base() == Tmp(MacroAssembler::stackPointerRegister));
273         return ValueRep::stack(arg.offset() - static_cast<int32_t>(code.frameSize()));
274     default:
275         ASSERT_NOT_REACHED();
276         return ValueRep();
277     }
278 }
279
280 } } // namespace JSC::B3
281
282 namespace WTF {
283
284 using namespace JSC::B3;
285
286 void printInternal(PrintStream& out, StackmapSpecial::RoleMode mode)
287 {
288     switch (mode) {
289     case StackmapSpecial::SameAsRep:
290         out.print("SameAsRep");
291         return;
292     case StackmapSpecial::ForceLateUseUnlessRecoverable:
293         out.print("ForceLateUseUnlessRecoverable");
294         return;
295     case StackmapSpecial::ForceLateUse:
296         out.print("ForceLateUse");
297         return;
298     }
299     RELEASE_ASSERT_NOT_REACHED();
300 }
301
302 } // namespace WTF
303
304 #endif // ENABLE(B3_JIT)