1 /* 2 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.apple.jobjc; 26 27 import com.apple.jobjc.Coder.IDCoder; 28 import com.apple.jobjc.Coder.NSClassCoder; 29 import com.apple.jobjc.Coder.PrimitivePointerCoder; 30 import com.apple.jobjc.Coder.SELCoder; 31 import com.apple.jobjc.Coder.StructCoder; 32 33 34 public abstract class Invoke { 35 public abstract void invoke(NativeArgumentBuffer argBuf); 36 public abstract void invoke(NativeArgumentBuffer buffer, Struct retvalStruct); 37 38 // 39 40 public static final class FunCall extends Invoke{ 41 static native void invoke(long cifPtr, long fxnPtr, long retValPtr, long argsPtr); 42 43 final long fxnPtr; 44 final CIF cif; 45 46 FunCall(long fxnPtr, CIF cif) { 47 this.fxnPtr = fxnPtr; 48 this.cif = cif; 49 } 50 51 public FunCall(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { 52 this(Function.getFxnPtr(name), CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, argCoders)); 53 } 54 55 public FunCall(final MacOSXFramework framework, final String name, final Coder returnCoder, final Coder ... argCoders) { 56 this(Function.getFxnPtr(name, framework), CIF.createCIFFor(framework.getRuntime().getThreadLocalState(), returnCoder, argCoders)); 57 } 58 59 public void init(final NativeArgumentBuffer argBuf) { 60 argBuf.reset(); 61 } 62 63 @Override public void invoke(final NativeArgumentBuffer argBuf) { 64 invoke(argBuf, argBuf.retValPtr); 65 } 66 67 @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { 68 invoke(buffer, retvalStruct.raw.bufferPtr); 69 } 70 71 void invoke(final NativeArgumentBuffer argBuf, final long retValPtr) { 72 invoke(cif.cif.bufferPtr, fxnPtr, retValPtr, argBuf.buffer.bufferPtr); 73 } 74 } 75 76 public static final class MsgSend extends Invoke{ 77 static{ System.load("/usr/lib/libobjc.dylib"); } 78 79 private static final long OBJC_MSG_SEND_FXN_PTR = new Function("objc_msgSend").fxnPtr; 80 private static final long OBJC_MSG_SEND_FPRET_FXN_PTR = new Function("objc_msgSend_fpret").fxnPtr; 81 private static final long OBJC_MSG_SEND_STRET_FXN_PTR = new Function("objc_msgSend_stret").fxnPtr; 82 83 final FunCall funCall; 84 final long selPtr; 85 86 public MsgSend(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { 87 this.funCall = new FunCall(getMsgSendFxnPtr(returnCoder), 88 CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, getSelCoders(argCoders))); 89 this.selPtr = SEL.getSelectorPtr(name); 90 } 91 92 public void init(final NativeArgumentBuffer nativeBuffer, final ID obj) { 93 funCall.init(nativeBuffer); 94 IDCoder.INST.push(nativeBuffer, obj); 95 PrimitivePointerCoder.INST.push(nativeBuffer.runtime, nativeBuffer, selPtr); 96 } 97 98 @Override public void invoke(final NativeArgumentBuffer argBuf) { 99 funCall.invoke(argBuf); 100 } 101 102 @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { 103 funCall.invoke(buffer, retvalStruct); 104 } 105 106 // support 107 108 static Coder[] getSelCoders(final Coder[] argCoders) { 109 final Coder[] selArgCoders = new Coder[argCoders.length + 2]; 110 selArgCoders[0] = IDCoder.INST; 111 selArgCoders[1] = SELCoder.INST; 112 for (int i = 0; i < argCoders.length; i++) 113 selArgCoders[i + 2] = argCoders[i]; 114 return selArgCoders; 115 } 116 117 static long getMsgSendFxnPtr(final Coder returnCoder) { 118 if(returnCoder instanceof StructCoder){ 119 StructCoder scoder = (StructCoder) returnCoder; 120 121 switch(JObjCRuntime.ARCH){ 122 case ppc: 123 return OBJC_MSG_SEND_STRET_FXN_PTR; 124 case i386: 125 switch(scoder.sizeof){ 126 case 1: case 2: case 4: case 8: 127 return OBJC_MSG_SEND_FXN_PTR; 128 } 129 return OBJC_MSG_SEND_STRET_FXN_PTR; 130 case x86_64: 131 if(scoder.sizeof > 16) 132 return OBJC_MSG_SEND_STRET_FXN_PTR; 133 else 134 return OBJC_MSG_SEND_FXN_PTR; 135 default: 136 throw new RuntimeException(); 137 } 138 } 139 140 final int typeCode = returnCoder.getTypeCode(); 141 142 switch(JObjCRuntime.ARCH){ 143 case ppc: 144 return OBJC_MSG_SEND_FXN_PTR; 145 case i386: 146 switch(typeCode) { 147 case Coder.FFI_FLOAT: case Coder.FFI_DOUBLE: case Coder.FFI_LONGDOUBLE: 148 return OBJC_MSG_SEND_FPRET_FXN_PTR; 149 } 150 return OBJC_MSG_SEND_FXN_PTR; 151 case x86_64: 152 if(typeCode == Coder.FFI_LONGDOUBLE) 153 return OBJC_MSG_SEND_FPRET_FXN_PTR; 154 return OBJC_MSG_SEND_FXN_PTR; 155 default: 156 throw new RuntimeException(); 157 } 158 } 159 } 160 161 public static final class MsgSendSuper extends Invoke{ 162 static{ System.load("/usr/lib/libobjc.dylib"); } 163 164 private static final long OBJC_MSG_SEND_SUPER_FXN_PTR = new Function("objc_msgSendSuper").fxnPtr; 165 private static final long OBJC_MSG_SEND_SUPER_STRET_FXN_PTR = new Function("objc_msgSendSuper_stret").fxnPtr; 166 167 final FunCall funCall; 168 final long selPtr; 169 170 public MsgSendSuper(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { 171 this.funCall = new FunCall(getMsgSendSuperFxnPtr(returnCoder), 172 CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, getSuperSelCoders(argCoders))); 173 this.selPtr = SEL.getSelectorPtr(name); 174 } 175 176 public void init(final NativeArgumentBuffer argBuf, final ID obj, final NSClass cls) { 177 funCall.init(argBuf); 178 179 // Instead of mallocing a struct, or keeping another thread local, 180 // let's write objc_super out to the argbuf, and then point an argument 181 // to the data. 182 183 final long valPtr = argBuf.argValuesPtr; 184 final int ptrLen = JObjCRuntime.PTR_LEN; 185 186 IDCoder .INST.push(argBuf.runtime, valPtr, obj); 187 NSClassCoder.INST.push(argBuf.runtime, valPtr + ptrLen, cls); 188 argBuf.argValuesPtr += ptrLen + ptrLen; 189 190 PrimitivePointerCoder.INST.push(argBuf.runtime, argBuf, valPtr); 191 PrimitivePointerCoder.INST.push(argBuf.runtime, argBuf, selPtr); 192 } 193 194 @Override public void invoke(final NativeArgumentBuffer argBuf) { 195 funCall.invoke(argBuf); 196 } 197 198 @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { 199 funCall.invoke(buffer, retvalStruct); 200 } 201 202 // 203 204 private final static StructCoder objc_super_coder = new StructCoder(JObjCRuntime.PTR_LEN*2, IDCoder.INST, NSClassCoder.INST){ 205 @Override protected Struct newInstance(JObjCRuntime runtime) { return null; }}; 206 207 static Coder[] getSuperSelCoders(final Coder[] argCoders) { 208 final Coder[] selArgCoders = new Coder[argCoders.length + 2]; 209 selArgCoders[0] = objc_super_coder; 210 selArgCoders[1] = SELCoder.INST; 211 for (int i = 0; i < argCoders.length; i++) 212 selArgCoders[i + 2] = argCoders[i]; 213 return selArgCoders; 214 } 215 216 static long getMsgSendSuperFxnPtr(final Coder returnCoder){ 217 long normal = MsgSend.getMsgSendFxnPtr(returnCoder); 218 if(normal == MsgSend.OBJC_MSG_SEND_STRET_FXN_PTR) 219 return OBJC_MSG_SEND_SUPER_STRET_FXN_PTR; 220 else 221 return OBJC_MSG_SEND_SUPER_FXN_PTR; 222 } 223 } 224 }