1 /* 2 * Copyright (c) 2011, 2012, 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 import javax.tools.annotation.GenerateNativeHeader; 34 35 /* No native methods here, but the constants are needed in the supporting JNI code */ 36 @GenerateNativeHeader 37 public abstract class Invoke { 38 public abstract void invoke(NativeArgumentBuffer argBuf); 39 public abstract void invoke(NativeArgumentBuffer buffer, Struct retvalStruct); 40 41 // 42 43 /* No native methods here, but the constants are needed in the supporting JNI code */ 44 @GenerateNativeHeader 45 public static final class FunCall extends Invoke{ 46 static native void invoke(long cifPtr, long fxnPtr, long retValPtr, long argsPtr); 47 48 final long fxnPtr; 49 final CIF cif; 50 51 FunCall(long fxnPtr, CIF cif) { 52 this.fxnPtr = fxnPtr; 53 this.cif = cif; 54 } 55 56 public FunCall(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { 57 this(Function.getFxnPtr(name), CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, argCoders)); 58 } 59 60 public FunCall(final MacOSXFramework framework, final String name, final Coder returnCoder, final Coder ... argCoders) { 61 this(Function.getFxnPtr(name, framework), CIF.createCIFFor(framework.getRuntime().getThreadLocalState(), returnCoder, argCoders)); 62 } 63 64 public void init(final NativeArgumentBuffer argBuf) { 65 argBuf.reset(); 66 } 67 68 @Override public void invoke(final NativeArgumentBuffer argBuf) { 69 invoke(argBuf, argBuf.retValPtr); 70 } 71 72 @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { 73 invoke(buffer, retvalStruct.raw.bufferPtr); 74 } 75 76 void invoke(final NativeArgumentBuffer argBuf, final long retValPtr) { 77 invoke(cif.cif.bufferPtr, fxnPtr, retValPtr, argBuf.buffer.bufferPtr); 78 } 79 } 80 81 /* No native methods here, but the constants are needed in the supporting JNI code */ 82 @GenerateNativeHeader 83 public static final class MsgSend extends Invoke{ 84 static{ System.load("/usr/lib/libobjc.dylib"); } 85 86 private static final long OBJC_MSG_SEND_FXN_PTR = new Function("objc_msgSend").fxnPtr; 87 private static final long OBJC_MSG_SEND_FPRET_FXN_PTR = new Function("objc_msgSend_fpret").fxnPtr; 88 private static final long OBJC_MSG_SEND_STRET_FXN_PTR = new Function("objc_msgSend_stret").fxnPtr; 89 90 final FunCall funCall; 91 final long selPtr; 92 93 public MsgSend(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { 94 this.funCall = new FunCall(getMsgSendFxnPtr(returnCoder), 95 CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, getSelCoders(argCoders))); 96 this.selPtr = SEL.getSelectorPtr(name); 97 } 98 99 public void init(final NativeArgumentBuffer nativeBuffer, final ID obj) { 100 funCall.init(nativeBuffer); 101 IDCoder.INST.push(nativeBuffer, obj); 102 PrimitivePointerCoder.INST.push(nativeBuffer.runtime, nativeBuffer, selPtr); 103 } 104 105 @Override public void invoke(final NativeArgumentBuffer argBuf) { 106 funCall.invoke(argBuf); 107 } 108 109 @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { 110 funCall.invoke(buffer, retvalStruct); 111 } 112 113 // support 114 115 static Coder[] getSelCoders(final Coder[] argCoders) { 116 final Coder[] selArgCoders = new Coder[argCoders.length + 2]; 117 selArgCoders[0] = IDCoder.INST; 118 selArgCoders[1] = SELCoder.INST; 119 for (int i = 0; i < argCoders.length; i++) 120 selArgCoders[i + 2] = argCoders[i]; 121 return selArgCoders; 122 } 123 124 static long getMsgSendFxnPtr(final Coder returnCoder) { 125 if(returnCoder instanceof StructCoder){ 126 StructCoder scoder = (StructCoder) returnCoder; 127 128 switch(JObjCRuntime.ARCH){ 129 case ppc: 130 return OBJC_MSG_SEND_STRET_FXN_PTR; 131 case i386: 132 switch(scoder.sizeof){ 133 case 1: case 2: case 4: case 8: 134 return OBJC_MSG_SEND_FXN_PTR; 135 } 136 return OBJC_MSG_SEND_STRET_FXN_PTR; 137 case x86_64: 138 if(scoder.sizeof > 16) 139 return OBJC_MSG_SEND_STRET_FXN_PTR; 140 else 141 return OBJC_MSG_SEND_FXN_PTR; 142 default: 143 throw new RuntimeException(); 144 } 145 } 146 147 final int typeCode = returnCoder.getTypeCode(); 148 149 switch(JObjCRuntime.ARCH){ 150 case ppc: 151 return OBJC_MSG_SEND_FXN_PTR; 152 case i386: 153 switch(typeCode) { 154 case Coder.FFI_FLOAT: case Coder.FFI_DOUBLE: case Coder.FFI_LONGDOUBLE: 155 return OBJC_MSG_SEND_FPRET_FXN_PTR; 156 } 157 return OBJC_MSG_SEND_FXN_PTR; 158 case x86_64: 159 if(typeCode == Coder.FFI_LONGDOUBLE) 160 return OBJC_MSG_SEND_FPRET_FXN_PTR; 161 return OBJC_MSG_SEND_FXN_PTR; 162 default: 163 throw new RuntimeException(); 164 } 165 } 166 } 167 168 /* No native methods here, but the constants are needed in the supporting JNI code */ 169 @GenerateNativeHeader 170 public static final class MsgSendSuper extends Invoke{ 171 static{ System.load("/usr/lib/libobjc.dylib"); } 172 173 private static final long OBJC_MSG_SEND_SUPER_FXN_PTR = new Function("objc_msgSendSuper").fxnPtr; 174 private static final long OBJC_MSG_SEND_SUPER_STRET_FXN_PTR = new Function("objc_msgSendSuper_stret").fxnPtr; 175 176 final FunCall funCall; 177 final long selPtr; 178 179 public MsgSendSuper(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { 180 this.funCall = new FunCall(getMsgSendSuperFxnPtr(returnCoder), 181 CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, getSuperSelCoders(argCoders))); 182 this.selPtr = SEL.getSelectorPtr(name); 183 } 184 185 public void init(final NativeArgumentBuffer argBuf, final ID obj, final NSClass cls) { 186 funCall.init(argBuf); 187 188 // Instead of mallocing a struct, or keeping another thread local, 189 // let's write objc_super out to the argbuf, and then point an argument 190 // to the data. 191 192 final long valPtr = argBuf.argValuesPtr; 193 final int ptrLen = JObjCRuntime.PTR_LEN; 194 195 IDCoder .INST.push(argBuf.runtime, valPtr, obj); 196 NSClassCoder.INST.push(argBuf.runtime, valPtr + ptrLen, cls); 197 argBuf.argValuesPtr += ptrLen + ptrLen; 198 199 PrimitivePointerCoder.INST.push(argBuf.runtime, argBuf, valPtr); 200 PrimitivePointerCoder.INST.push(argBuf.runtime, argBuf, selPtr); 201 } 202 203 @Override public void invoke(final NativeArgumentBuffer argBuf) { 204 funCall.invoke(argBuf); 205 } 206 207 @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { 208 funCall.invoke(buffer, retvalStruct); 209 } 210 211 // 212 213 private final static StructCoder objc_super_coder = new StructCoder(JObjCRuntime.PTR_LEN*2, IDCoder.INST, NSClassCoder.INST){ 214 @Override protected Struct newInstance(JObjCRuntime runtime) { return null; }}; 215 216 static Coder[] getSuperSelCoders(final Coder[] argCoders) { 217 final Coder[] selArgCoders = new Coder[argCoders.length + 2]; 218 selArgCoders[0] = objc_super_coder; 219 selArgCoders[1] = SELCoder.INST; 220 for (int i = 0; i < argCoders.length; i++) 221 selArgCoders[i + 2] = argCoders[i]; 222 return selArgCoders; 223 } 224 225 static long getMsgSendSuperFxnPtr(final Coder returnCoder){ 226 long normal = MsgSend.getMsgSendFxnPtr(returnCoder); 227 if(normal == MsgSend.OBJC_MSG_SEND_STRET_FXN_PTR) 228 return OBJC_MSG_SEND_SUPER_STRET_FXN_PTR; 229 else 230 return OBJC_MSG_SEND_SUPER_FXN_PTR; 231 } 232 } 233 }