1 /* 2 * Copyright (C) 2010 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 SpecializedThunkJIT_h 27 #define SpecializedThunkJIT_h 28 29 #if ENABLE(JIT) 30 31 #include "Executable.h" 32 #include "JSInterfaceJIT.h" 33 #include "LinkBuffer.h" 34 35 namespace JSC { 36 37 class SpecializedThunkJIT : public JSInterfaceJIT { 38 public: 39 static const int ThisArgument = -1; 40 SpecializedThunkJIT(int expectedArgCount, JSGlobalData* globalData, ExecutablePool* pool) 41 : m_expectedArgCount(expectedArgCount) 42 , m_globalData(globalData) 43 , m_pool(pool) 44 { 45 // Check that we have the expected number of arguments 46 m_failures.append(branch32(NotEqual, Address(callFrameRegister, RegisterFile::ArgumentCount * (int)sizeof(Register)), TrustedImm32(expectedArgCount + 1))); 47 } 48 49 void loadDoubleArgument(int argument, FPRegisterID dst, RegisterID scratch) 50 { 51 unsigned src = argumentToVirtualRegister(argument); 52 m_failures.append(emitLoadDouble(src, dst, scratch)); 53 } 54 55 void loadCellArgument(int argument, RegisterID dst) 56 { 57 unsigned src = argumentToVirtualRegister(argument); 58 m_failures.append(emitLoadJSCell(src, dst)); 59 } 60 61 void loadJSStringArgument(int argument, RegisterID dst) 62 { 63 loadCellArgument(argument, dst); 64 m_failures.append(branchPtr(NotEqual, Address(dst, 0), TrustedImmPtr(m_globalData->jsStringVPtr))); 65 m_failures.append(branchTest32(NonZero, Address(dst, OBJECT_OFFSETOF(JSString, m_fiberCount)))); 66 } 67 68 void loadInt32Argument(int argument, RegisterID dst, Jump& failTarget) 69 { 70 unsigned src = argumentToVirtualRegister(argument); 71 failTarget = emitLoadInt32(src, dst); 72 } 73 74 void loadInt32Argument(int argument, RegisterID dst) 75 { 76 Jump conversionFailed; 77 loadInt32Argument(argument, dst, conversionFailed); 78 m_failures.append(conversionFailed); 79 } 80 81 void appendFailure(const Jump& failure) 82 { 83 m_failures.append(failure); 84 } 85 86 void returnJSValue(RegisterID src) 87 { 88 if (src != regT0) 89 move(src, regT0); 90 loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister); 91 ret(); 92 } 93 94 void returnDouble(FPRegisterID src) 95 { 96 #if USE(JSVALUE64) 97 moveDoubleToPtr(src, regT0); 98 subPtr(tagTypeNumberRegister, regT0); 99 #else 100 storeDouble(src, Address(stackPointerRegister, -(int)sizeof(double))); 101 loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.tag) - sizeof(double)), regT1); 102 loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.payload) - sizeof(double)), regT0); 103 #endif 104 loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister); 105 ret(); 106 } 107 108 void returnInt32(RegisterID src) 109 { 110 if (src != regT0) 111 move(src, regT0); 112 tagReturnAsInt32(); 113 loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister); 114 ret(); 115 } 116 117 void returnJSCell(RegisterID src) 118 { 119 if (src != regT0) 120 move(src, regT0); 121 tagReturnAsJSCell(); 122 loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister); 123 ret(); 124 } 125 126 MacroAssemblerCodePtr finalize(MacroAssemblerCodePtr fallback) 127 { 128 LinkBuffer patchBuffer(this, m_pool.get(), 0); 129 patchBuffer.link(m_failures, CodeLocationLabel(fallback)); 130 return patchBuffer.finalizeCode().m_code; 131 } 132 133 private: 134 int argumentToVirtualRegister(unsigned argument) 135 { 136 return -static_cast<int>(RegisterFile::CallFrameHeaderSize + (m_expectedArgCount - argument)); 137 } 138 139 void tagReturnAsInt32() 140 { 141 #if USE(JSVALUE64) 142 orPtr(tagTypeNumberRegister, regT0); 143 #else 144 move(TrustedImm32(JSValue::Int32Tag), regT1); 145 #endif 146 } 147 148 void tagReturnAsJSCell() 149 { 150 #if USE(JSVALUE32_64) 151 move(TrustedImm32(JSValue::CellTag), regT1); 152 #endif 153 } 154 155 int m_expectedArgCount; 156 JSGlobalData* m_globalData; 157 RefPtr<ExecutablePool> m_pool; 158 MacroAssembler::JumpList m_failures; 159 }; 160 161 } 162 163 #endif // ENABLE(JIT) 164 165 #endif // SpecializedThunkJIT_h 166