1/* 2 * Copyright (C) 2008 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#ifndef JITStubCall_h 27#define JITStubCall_h 28 29#include "MacroAssemblerCodeRef.h" 30 31#if ENABLE(JIT) 32 33namespace JSC { 34 35 class JITStubCall { 36 public: 37 JITStubCall(JIT* jit, JSObject* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) 38 : m_jit(jit) 39 , m_stub(stub) 40#if USE(JSVALUE32_64) || !ASSERT_DISABLED 41 , m_returnType(Cell) 42#endif 43 , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) 44 { 45 } 46 47 JITStubCall(JIT* jit, JSPropertyNameIterator* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) 48 : m_jit(jit) 49 , m_stub(stub) 50#if USE(JSVALUE32_64) || !ASSERT_DISABLED 51 , m_returnType(Cell) 52#endif 53 , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) 54 { 55 } 56 57 JITStubCall(JIT* jit, void* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) 58 : m_jit(jit) 59 , m_stub(stub) 60#if USE(JSVALUE32_64) || !ASSERT_DISABLED 61 , m_returnType(VoidPtr) 62#endif 63 , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) 64 { 65 } 66 67 JITStubCall(JIT* jit, int (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) 68 : m_jit(jit) 69 , m_stub(stub) 70#if USE(JSVALUE32_64) || !ASSERT_DISABLED 71 , m_returnType(Int) 72#endif 73 , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) 74 { 75 } 76 77 JITStubCall(JIT* jit, bool (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) 78 : m_jit(jit) 79 , m_stub(stub) 80#if USE(JSVALUE32_64) || !ASSERT_DISABLED 81 , m_returnType(Int) 82#endif 83 , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) 84 { 85 } 86 87 JITStubCall(JIT* jit, void (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) 88 : m_jit(jit) 89 , m_stub(stub) 90#if USE(JSVALUE32_64) || !ASSERT_DISABLED 91 , m_returnType(Void) 92#endif 93 , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) 94 { 95 } 96 97 JITStubCall(JIT* jit, EncodedJSValue (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) 98 : m_jit(jit) 99 , m_stub(stub) 100#if USE(JSVALUE32_64) || !ASSERT_DISABLED 101 , m_returnType(Value) 102#endif 103 , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) 104 { 105 } 106 107 // Arguments are added first to last. 108 109 void skipArgument() 110 { 111 m_stackIndex += stackIndexStep; 112 } 113 114 void addArgument(JIT::TrustedImm32 argument) 115 { 116 m_jit->poke(argument, m_stackIndex); 117 m_stackIndex += stackIndexStep; 118 } 119 120 void addArgument(JIT::Imm32 argument) 121 { 122 m_jit->poke(argument, m_stackIndex); 123 m_stackIndex += stackIndexStep; 124 } 125 126 void addArgument(JIT::TrustedImmPtr argument) 127 { 128 m_jit->poke(argument, m_stackIndex); 129 m_stackIndex += stackIndexStep; 130 } 131 132 void addArgument(JIT::ImmPtr argument) 133 { 134 m_jit->poke(argument, m_stackIndex); 135 m_stackIndex += stackIndexStep; 136 } 137 138 void addArgument(JIT::RegisterID argument) 139 { 140#if USE(JSVALUE32_64) 141 m_jit->poke(argument, m_stackIndex); 142#else 143 m_jit->poke64(argument, m_stackIndex); 144#endif 145 m_stackIndex += stackIndexStep; 146 } 147 148#if USE(JSVALUE32_64) 149 void addArgument(const JSValue& value) 150 { 151 m_jit->poke(JIT::Imm32(value.payload()), m_stackIndex); 152 m_jit->poke(JIT::Imm32(value.tag()), m_stackIndex + 1); 153 m_stackIndex += stackIndexStep; 154 } 155#else 156 void addArgument(JIT::TrustedImm64 argument) 157 { 158 m_jit->poke(argument, m_stackIndex); 159 m_stackIndex += stackIndexStep; 160 } 161 162 void addArgument(JIT::Imm64 argument) 163 { 164 m_jit->poke(argument, m_stackIndex); 165 m_stackIndex += stackIndexStep; 166 } 167#endif 168 169 void addArgument(JIT::RegisterID tag, JIT::RegisterID payload) 170 { 171 m_jit->poke(payload, m_stackIndex); 172 m_jit->poke(tag, m_stackIndex + 1); 173 m_stackIndex += stackIndexStep; 174 } 175 176#if USE(JSVALUE32_64) 177 void addArgument(unsigned srcVirtualRegister) 178 { 179 if (m_jit->m_codeBlock->isConstantRegisterIndex(srcVirtualRegister)) { 180 addArgument(m_jit->getConstantOperand(srcVirtualRegister)); 181 return; 182 } 183 184 m_jit->emitLoad(srcVirtualRegister, JIT::regT1, JIT::regT0); 185 addArgument(JIT::regT1, JIT::regT0); 186 } 187 188 void getArgument(size_t argumentNumber, JIT::RegisterID tag, JIT::RegisterID payload) 189 { 190 size_t stackIndex = JITSTACKFRAME_ARGS_INDEX + (argumentNumber * stackIndexStep); 191 m_jit->peek(payload, stackIndex); 192 m_jit->peek(tag, stackIndex + 1); 193 } 194#else 195 void addArgument(unsigned src, JIT::RegisterID scratchRegister) // src is a virtual register. 196 { 197 if (m_jit->m_codeBlock->isConstantRegisterIndex(src)) 198 addArgument(JIT::Imm64(JSValue::encode(m_jit->m_codeBlock->getConstant(src)))); 199 else { 200 m_jit->load64(JIT::Address(JIT::callFrameRegister, src * sizeof(Register)), scratchRegister); 201 addArgument(scratchRegister); 202 } 203 m_jit->killLastResultRegister(); 204 } 205#endif 206 207 JIT::Call call() 208 { 209#if ENABLE(OPCODE_SAMPLING) 210 if (m_jit->m_bytecodeOffset != (unsigned)-1) 211 m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeOffset, true); 212#endif 213 214 m_jit->restoreArgumentReference(); 215 m_jit->updateTopCallFrame(); 216 JIT::Call call = m_jit->call(); 217 m_jit->m_calls.append(CallRecord(call, m_jit->m_bytecodeOffset, m_stub.value())); 218 219#if ENABLE(OPCODE_SAMPLING) 220 if (m_jit->m_bytecodeOffset != (unsigned)-1) 221 m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeOffset, false); 222#endif 223 224#if USE(JSVALUE32_64) 225 m_jit->unmap(); 226#else 227 m_jit->killLastResultRegister(); 228#endif 229 return call; 230 } 231 232#if USE(JSVALUE32_64) 233 JIT::Call call(unsigned dst) // dst is a virtual register. 234 { 235 ASSERT(m_returnType == Value || m_returnType == Cell); 236 JIT::Call call = this->call(); 237 if (m_returnType == Value) 238 m_jit->emitStore(dst, JIT::regT1, JIT::regT0); 239 else 240 m_jit->emitStoreCell(dst, JIT::returnValueRegister); 241 return call; 242 } 243 244 JIT::Call callWithValueProfiling(unsigned dst) 245 { 246 ASSERT(m_returnType == Value || m_returnType == Cell); 247 JIT::Call call = this->call(); 248 ASSERT(JIT::returnValueRegister == JIT::regT0); 249 if (m_returnType == Cell) 250 m_jit->move(JIT::TrustedImm32(JSValue::CellTag), JIT::regT1); 251 m_jit->emitValueProfilingSite(); 252 if (m_returnType == Value) 253 m_jit->emitStore(dst, JIT::regT1, JIT::regT0); 254 else 255 m_jit->emitStoreCell(dst, JIT::returnValueRegister); 256 return call; 257 } 258#else 259 JIT::Call call(unsigned dst) // dst is a virtual register. 260 { 261 ASSERT(m_returnType == Value || m_returnType == Cell); 262 JIT::Call call = this->call(); 263 m_jit->emitPutVirtualRegister(dst); 264 return call; 265 } 266 267 JIT::Call callWithValueProfiling(unsigned dst) 268 { 269 ASSERT(m_returnType == Value || m_returnType == Cell); 270 JIT::Call call = this->call(); 271 ASSERT(JIT::returnValueRegister == JIT::regT0); 272 m_jit->emitValueProfilingSite(); 273 m_jit->emitPutVirtualRegister(dst); 274 return call; 275 } 276#endif 277 278 JIT::Call call(JIT::RegisterID dst) // dst is a machine register. 279 { 280#if USE(JSVALUE32_64) || !ASSERT_DISABLED 281 ASSERT(m_returnType == Value || m_returnType == VoidPtr || m_returnType == Int || m_returnType == Cell); 282#endif 283 JIT::Call call = this->call(); 284 if (dst != JIT::returnValueRegister) 285 m_jit->move(JIT::returnValueRegister, dst); 286 return call; 287 } 288 289 private: 290 static const size_t stackIndexStep = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 2 : 1; 291 292 JIT* m_jit; 293 FunctionPtr m_stub; 294#if USE(JSVALUE32_64) || !ASSERT_DISABLED 295 enum { Void, VoidPtr, Int, Value, Cell } m_returnType; 296#endif 297 size_t m_stackIndex; 298 }; 299} 300 301#endif // ENABLE(JIT) 302 303#endif // JITStubCall_h 304