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 StackAllocator_h 27#define StackAllocator_h 28 29#if ENABLE(CSS_SELECTOR_JIT) 30 31#include "RegisterAllocator.h" 32#include <JavaScriptCore/MacroAssembler.h> 33 34namespace WebCore { 35 36class StackAllocator { 37public: 38 class StackReference { 39 public: 40 StackReference() 41 : m_offsetFromTop(-1) 42 { } 43 explicit StackReference(unsigned offset) 44 : m_offsetFromTop(offset) 45 { } 46 operator unsigned() const { return m_offsetFromTop; } 47 private: 48 unsigned m_offsetFromTop; 49 }; 50 51 typedef Vector<StackReference, maximumRegisterCount> StackReferenceVector; 52 53 StackAllocator(JSC::MacroAssembler& assembler) 54 : m_assembler(assembler) 55 , m_offsetFromTop(0) 56 , m_hasFunctionCallPadding(false) 57 { 58 } 59 60 ~StackAllocator() 61 { 62 RELEASE_ASSERT(!m_offsetFromTop); 63 RELEASE_ASSERT(!m_hasFunctionCallPadding); 64 } 65 66 StackReference allocateUninitialized() 67 { 68 RELEASE_ASSERT(!m_hasFunctionCallPadding); 69 m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(-stackUnitInBytes()), JSC::MacroAssembler::stackPointerRegister); 70 m_offsetFromTop += stackUnitInBytes(); 71 return StackReference(m_offsetFromTop); 72 } 73 74 StackReferenceVector push(const Vector<JSC::MacroAssembler::RegisterID>& registerIDs) 75 { 76 RELEASE_ASSERT(!m_hasFunctionCallPadding); 77 StackReferenceVector stackReferences; 78#if CPU(ARM64) 79 unsigned pushRegisterCount = registerIDs.size(); 80 for (unsigned i = 0; i < pushRegisterCount - 1; i += 2) { 81 m_assembler.pushPair(registerIDs[i + 1], registerIDs[i]); 82 m_offsetFromTop += stackUnitInBytes(); 83 stackReferences.append(StackReference(m_offsetFromTop - stackUnitInBytes() / 2)); 84 stackReferences.append(StackReference(m_offsetFromTop)); 85 } 86 if (pushRegisterCount % 2) 87 stackReferences.append(push(registerIDs[pushRegisterCount - 1])); 88#else 89 for (auto registerID : registerIDs) 90 stackReferences.append(push(registerID)); 91#endif 92 return stackReferences; 93 } 94 95 StackReference push(JSC::MacroAssembler::RegisterID registerID) 96 { 97 RELEASE_ASSERT(!m_hasFunctionCallPadding); 98 m_assembler.pushToSave(registerID); 99 m_offsetFromTop += stackUnitInBytes(); 100 return StackReference(m_offsetFromTop); 101 } 102 103 void pop(const StackReferenceVector& stackReferences, const Vector<JSC::MacroAssembler::RegisterID>& registerIDs) 104 { 105 RELEASE_ASSERT(!m_hasFunctionCallPadding); 106 107 unsigned popRegisterCount = registerIDs.size(); 108 RELEASE_ASSERT(stackReferences.size() == popRegisterCount); 109#if CPU(ARM64) 110 ASSERT(m_offsetFromTop >= stackUnitInBytes() * ((popRegisterCount + 1) / 2)); 111 unsigned popRegisterCountOdd = popRegisterCount % 2; 112 if (popRegisterCountOdd) 113 pop(stackReferences[popRegisterCount - 1], registerIDs[popRegisterCount - 1]); 114 for (unsigned i = popRegisterCount - popRegisterCountOdd; i > 0; i -= 2) { 115 RELEASE_ASSERT(stackReferences[i - 1] == m_offsetFromTop); 116 RELEASE_ASSERT(stackReferences[i - 2] == m_offsetFromTop - stackUnitInBytes() / 2); 117 RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes()); 118 m_offsetFromTop -= stackUnitInBytes(); 119 m_assembler.popPair(registerIDs[i - 1], registerIDs[i - 2]); 120 } 121#else 122 ASSERT(m_offsetFromTop >= stackUnitInBytes() * popRegisterCount); 123 for (unsigned i = popRegisterCount; i > 0; --i) 124 pop(stackReferences[i - 1], registerIDs[i - 1]); 125#endif 126 } 127 128 void pop(StackReference stackReference, JSC::MacroAssembler::RegisterID registerID) 129 { 130 RELEASE_ASSERT(stackReference == m_offsetFromTop); 131 RELEASE_ASSERT(!m_hasFunctionCallPadding); 132 RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes()); 133 m_offsetFromTop -= stackUnitInBytes(); 134 m_assembler.popToRestore(registerID); 135 } 136 137 void popAndDiscard(StackReference stackReference) 138 { 139 RELEASE_ASSERT(stackReference == m_offsetFromTop); 140 m_assembler.addPtr(JSC::MacroAssembler::TrustedImm32(stackUnitInBytes()), JSC::MacroAssembler::stackPointerRegister); 141 m_offsetFromTop -= stackUnitInBytes(); 142 } 143 144 void popAndDiscardUpTo(StackReference stackReference) 145 { 146 unsigned positionBeforeStackReference = stackReference - stackUnitInBytes(); 147 RELEASE_ASSERT(positionBeforeStackReference < m_offsetFromTop); 148 149 unsigned stackDelta = m_offsetFromTop - positionBeforeStackReference; 150 m_assembler.addPtr(JSC::MacroAssembler::TrustedImm32(stackDelta), JSC::MacroAssembler::stackPointerRegister); 151 m_offsetFromTop -= stackDelta; 152 } 153 154 void alignStackPreFunctionCall() 155 { 156#if CPU(X86_64) 157 RELEASE_ASSERT(!m_hasFunctionCallPadding); 158 unsigned topAlignment = stackUnitInBytes(); 159 if ((topAlignment + m_offsetFromTop) % 16) { 160 m_hasFunctionCallPadding = true; 161 m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(-stackUnitInBytes()), JSC::MacroAssembler::stackPointerRegister); 162 } 163#endif 164 } 165 166 void unalignStackPostFunctionCall() 167 { 168#if CPU(X86_64) 169 if (m_hasFunctionCallPadding) { 170 m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(stackUnitInBytes()), JSC::MacroAssembler::stackPointerRegister); 171 m_hasFunctionCallPadding = false; 172 } 173#endif 174 } 175 176 void merge(StackAllocator&& stackA, StackAllocator&& stackB) 177 { 178 RELEASE_ASSERT(stackA.m_offsetFromTop == stackB.m_offsetFromTop); 179 RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackB.m_hasFunctionCallPadding); 180 ASSERT(&stackA.m_assembler == &stackB.m_assembler); 181 ASSERT(&m_assembler == &stackB.m_assembler); 182 183 m_offsetFromTop = stackA.m_offsetFromTop; 184 m_hasFunctionCallPadding = stackA.m_hasFunctionCallPadding; 185 186 stackA.reset(); 187 stackB.reset(); 188 } 189 190 void merge(StackAllocator&& stackA, StackAllocator&& stackB, StackAllocator&& stackC) 191 { 192 RELEASE_ASSERT(stackA.m_offsetFromTop == stackB.m_offsetFromTop); 193 RELEASE_ASSERT(stackA.m_offsetFromTop == stackC.m_offsetFromTop); 194 RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackB.m_hasFunctionCallPadding); 195 RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackC.m_hasFunctionCallPadding); 196 ASSERT(&stackA.m_assembler == &stackB.m_assembler); 197 ASSERT(&stackA.m_assembler == &stackC.m_assembler); 198 ASSERT(&m_assembler == &stackB.m_assembler); 199 200 m_offsetFromTop = stackA.m_offsetFromTop; 201 m_hasFunctionCallPadding = stackA.m_hasFunctionCallPadding; 202 203 stackA.reset(); 204 stackB.reset(); 205 stackC.reset(); 206 } 207 208 unsigned offsetToStackReference(StackReference stackReference) 209 { 210 RELEASE_ASSERT(m_offsetFromTop >= stackReference); 211 return m_offsetFromTop - stackReference; 212 } 213 214private: 215 static unsigned stackUnitInBytes() 216 { 217 return JSC::MacroAssembler::pushToSaveByteOffset(); 218 } 219 220 void reset() 221 { 222 m_offsetFromTop = 0; 223 m_hasFunctionCallPadding = false; 224 } 225 226 JSC::MacroAssembler& m_assembler; 227 unsigned m_offsetFromTop; 228 bool m_hasFunctionCallPadding; 229}; 230 231} // namespace WebCore 232 233#endif // ENABLE(CSS_SELECTOR_JIT) 234 235#endif // StackAllocator_h 236