Change the exact attribute matching to be ASCII case-insensitive
[WebKit-https.git] / Source / WebCore / cssjit / FunctionCall.h
1 /*
2  * Copyright (C) 2013, 2014 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef FunctionCall_h
27 #define FunctionCall_h
28
29 #if ENABLE(CSS_SELECTOR_JIT)
30
31 #include "RegisterAllocator.h"
32 #include "StackAllocator.h"
33 #include <JavaScriptCore/GPRInfo.h>
34 #include <JavaScriptCore/MacroAssembler.h>
35
36 namespace WebCore {
37
38 class FunctionCall {
39 public:
40     FunctionCall(JSC::MacroAssembler& assembler, RegisterAllocator& registerAllocator, StackAllocator& stackAllocator, Vector<std::pair<JSC::MacroAssembler::Call, JSC::FunctionPtr>, 32>& callRegistry)
41         : m_assembler(assembler)
42         , m_registerAllocator(registerAllocator)
43         , m_stackAllocator(stackAllocator)
44         , m_callRegistry(callRegistry)
45         , m_argumentCount(0)
46         , m_firstArgument(InvalidGPRReg)
47         , m_secondArgument(InvalidGPRReg)
48     {
49     }
50
51     void setFunctionAddress(JSC::FunctionPtr functionAddress)
52     {
53         m_functionAddress = functionAddress;
54     }
55
56     void setOneArgument(const JSC::MacroAssembler::RegisterID& registerID)
57     {
58         m_argumentCount = 1;
59         m_firstArgument = registerID;
60     }
61
62     void setTwoArguments(const JSC::MacroAssembler::RegisterID& firstRegisterID, const JSC::MacroAssembler::RegisterID& secondRegisterID)
63     {
64         m_argumentCount = 2;
65         m_firstArgument = firstRegisterID;
66         m_secondArgument = secondRegisterID;
67     }
68
69     void call()
70     {
71         prepareAndCall();
72         cleanupPostCall();
73     }
74
75     JSC::MacroAssembler::Jump callAndBranchOnBooleanReturnValue(JSC::MacroAssembler::ResultCondition condition)
76     {
77 #if CPU(X86) || CPU(X86_64)
78         return callAndBranchOnCondition(condition, JSC::MacroAssembler::TrustedImm32(0xff));
79 #elif CPU(ARM64) || CPU(ARM)
80         return callAndBranchOnCondition(condition, JSC::MacroAssembler::TrustedImm32(-1));
81 #else
82 #error Missing implementationg for matching boolean return values.
83 #endif
84     }
85
86 private:
87     JSC::MacroAssembler::Jump callAndBranchOnCondition(JSC::MacroAssembler::ResultCondition condition, JSC::MacroAssembler::TrustedImm32 mask)
88     {
89         prepareAndCall();
90         m_assembler.test32(condition, JSC::GPRInfo::returnValueGPR, mask);
91         cleanupPostCall();
92         return m_assembler.branch(condition);
93     }
94
95     void swapArguments()
96     {
97         JSC::MacroAssembler::RegisterID a = m_firstArgument;
98         JSC::MacroAssembler::RegisterID b = m_secondArgument;
99         // x86 can swap without a temporary register. On other architectures, we need allocate a temporary register to switch the values.
100 #if CPU(X86) || CPU(X86_64)
101         m_assembler.swap(a, b);
102 #elif CPU(ARM64) || CPU(ARM_THUMB2)
103         m_assembler.move(a, tempRegister);
104         m_assembler.move(b, a);
105         m_assembler.move(tempRegister, b);
106 #else
107 #error Missing implementationg for matching swapping argument registers.
108 #endif
109     }
110
111     void prepareAndCall()
112     {
113         ASSERT(m_functionAddress.executableAddress());
114         ASSERT(!m_firstArgument || (m_firstArgument && !m_secondArgument) || (m_firstArgument && m_secondArgument));
115
116         saveAllocatedCallerSavedRegisters();
117         m_stackAllocator.alignStackPreFunctionCall();
118
119         if (m_argumentCount == 2) {
120             RELEASE_ASSERT(RegisterAllocator::isValidRegister(m_firstArgument));
121             RELEASE_ASSERT(RegisterAllocator::isValidRegister(m_secondArgument));
122
123             if (m_firstArgument != JSC::GPRInfo::argumentGPR0) {
124                 // If firstArgument is not in argumentGPR0, we need to handle potential conflicts:
125                 // -if secondArgument and firstArgument are in inversted registers, just swap the values.
126                 // -if secondArgument is in argumentGPR0 but firstArgument is not taking argumentGPR1, we can move in order secondArgument->argumentGPR1, firstArgument->argumentGPR0
127                 // -if secondArgument does not take argumentGPR0, firstArgument and secondArgument can be moved safely to destination.
128                 if (m_secondArgument == JSC::GPRInfo::argumentGPR0) {
129                     if (m_firstArgument == JSC::GPRInfo::argumentGPR1)
130                         swapArguments();
131                     else {
132                         m_assembler.move(JSC::GPRInfo::argumentGPR0, JSC::GPRInfo::argumentGPR1);
133                         m_assembler.move(m_firstArgument, JSC::GPRInfo::argumentGPR0);
134                     }
135                 } else {
136                     m_assembler.move(m_firstArgument, JSC::GPRInfo::argumentGPR0);
137                     if (m_secondArgument != JSC::GPRInfo::argumentGPR1)
138                         m_assembler.move(m_secondArgument, JSC::GPRInfo::argumentGPR1);
139                 }
140             } else {
141                 // We know firstArgument is already in place, we can safely move secondArgument.
142                 if (m_secondArgument != JSC::GPRInfo::argumentGPR1)
143                     m_assembler.move(m_secondArgument, JSC::GPRInfo::argumentGPR1);
144             }
145         } else if (m_argumentCount == 1) {
146             RELEASE_ASSERT(RegisterAllocator::isValidRegister(m_firstArgument));
147             if (m_firstArgument != JSC::GPRInfo::argumentGPR0)
148                 m_assembler.move(m_firstArgument, JSC::GPRInfo::argumentGPR0);
149         }
150
151         JSC::MacroAssembler::Call call = m_assembler.call();
152         m_callRegistry.append(std::make_pair(call, m_functionAddress));
153     }
154
155     void cleanupPostCall()
156     {
157         m_stackAllocator.unalignStackPostFunctionCall();
158         restoreAllocatedCallerSavedRegisters();
159     }
160
161     void saveAllocatedCallerSavedRegisters()
162     {
163         ASSERT(m_savedRegisterStackReferences.isEmpty());
164         ASSERT(m_savedRegisters.isEmpty());
165         const RegisterVector& allocatedRegisters = m_registerAllocator.allocatedRegisters();
166         for (auto registerID : allocatedRegisters) {
167             if (RegisterAllocator::isCallerSavedRegister(registerID))
168                 m_savedRegisters.append(registerID);
169         }
170         m_savedRegisterStackReferences = m_stackAllocator.push(m_savedRegisters);
171     }
172
173     void restoreAllocatedCallerSavedRegisters()
174     {
175         m_stackAllocator.pop(m_savedRegisterStackReferences, m_savedRegisters);
176         m_savedRegisterStackReferences.clear();
177     }
178
179     JSC::MacroAssembler& m_assembler;
180     RegisterAllocator& m_registerAllocator;
181     StackAllocator& m_stackAllocator;
182     Vector<std::pair<JSC::MacroAssembler::Call, JSC::FunctionPtr>, 32>& m_callRegistry;
183
184     RegisterVector m_savedRegisters;
185     StackAllocator::StackReferenceVector m_savedRegisterStackReferences;
186     
187     JSC::FunctionPtr m_functionAddress;
188     unsigned m_argumentCount;
189     JSC::MacroAssembler::RegisterID m_firstArgument;
190     JSC::MacroAssembler::RegisterID m_secondArgument;
191 };
192
193 } // namespace WebCore
194
195 #endif // ENABLE(CSS_SELECTOR_JIT)
196
197 #endif // FunctionCall_h