| /* |
| * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package com.apple.jobjc; |
| |
| import com.apple.jobjc.Coder.IDCoder; |
| import com.apple.jobjc.Coder.NSClassCoder; |
| import com.apple.jobjc.Coder.PrimitivePointerCoder; |
| import com.apple.jobjc.Coder.SELCoder; |
| import com.apple.jobjc.Coder.StructCoder; |
| |
| |
| public abstract class Invoke { |
| public abstract void invoke(NativeArgumentBuffer argBuf); |
| public abstract void invoke(NativeArgumentBuffer buffer, Struct retvalStruct); |
| |
| // |
| |
| public static final class FunCall extends Invoke{ |
| static native void invoke(long cifPtr, long fxnPtr, long retValPtr, long argsPtr); |
| |
| final long fxnPtr; |
| final CIF cif; |
| |
| FunCall(long fxnPtr, CIF cif) { |
| this.fxnPtr = fxnPtr; |
| this.cif = cif; |
| } |
| |
| public FunCall(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { |
| this(Function.getFxnPtr(name), CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, argCoders)); |
| } |
| |
| public FunCall(final MacOSXFramework framework, final String name, final Coder returnCoder, final Coder ... argCoders) { |
| this(Function.getFxnPtr(name, framework), CIF.createCIFFor(framework.getRuntime().getThreadLocalState(), returnCoder, argCoders)); |
| } |
| |
| public void init(final NativeArgumentBuffer argBuf) { |
| argBuf.reset(); |
| } |
| |
| @Override public void invoke(final NativeArgumentBuffer argBuf) { |
| invoke(argBuf, argBuf.retValPtr); |
| } |
| |
| @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { |
| invoke(buffer, retvalStruct.raw.bufferPtr); |
| } |
| |
| void invoke(final NativeArgumentBuffer argBuf, final long retValPtr) { |
| invoke(cif.cif.bufferPtr, fxnPtr, retValPtr, argBuf.buffer.bufferPtr); |
| } |
| } |
| |
| public static final class MsgSend extends Invoke{ |
| static{ System.load("/usr/lib/libobjc.dylib"); } |
| |
| private static final long OBJC_MSG_SEND_FXN_PTR = new Function("objc_msgSend").fxnPtr; |
| private static final long OBJC_MSG_SEND_FPRET_FXN_PTR = new Function("objc_msgSend_fpret").fxnPtr; |
| private static final long OBJC_MSG_SEND_STRET_FXN_PTR = new Function("objc_msgSend_stret").fxnPtr; |
| |
| final FunCall funCall; |
| final long selPtr; |
| |
| public MsgSend(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { |
| this.funCall = new FunCall(getMsgSendFxnPtr(returnCoder), |
| CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, getSelCoders(argCoders))); |
| this.selPtr = SEL.getSelectorPtr(name); |
| } |
| |
| public void init(final NativeArgumentBuffer nativeBuffer, final ID obj) { |
| funCall.init(nativeBuffer); |
| IDCoder.INST.push(nativeBuffer, obj); |
| PrimitivePointerCoder.INST.push(nativeBuffer.runtime, nativeBuffer, selPtr); |
| } |
| |
| @Override public void invoke(final NativeArgumentBuffer argBuf) { |
| funCall.invoke(argBuf); |
| } |
| |
| @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { |
| funCall.invoke(buffer, retvalStruct); |
| } |
| |
| // support |
| |
| static Coder[] getSelCoders(final Coder[] argCoders) { |
| final Coder[] selArgCoders = new Coder[argCoders.length + 2]; |
| selArgCoders[0] = IDCoder.INST; |
| selArgCoders[1] = SELCoder.INST; |
| for (int i = 0; i < argCoders.length; i++) |
| selArgCoders[i + 2] = argCoders[i]; |
| return selArgCoders; |
| } |
| |
| static long getMsgSendFxnPtr(final Coder returnCoder) { |
| if(returnCoder instanceof StructCoder){ |
| StructCoder scoder = (StructCoder) returnCoder; |
| |
| switch(JObjCRuntime.ARCH){ |
| case ppc: |
| return OBJC_MSG_SEND_STRET_FXN_PTR; |
| case i386: |
| switch(scoder.sizeof){ |
| case 1: case 2: case 4: case 8: |
| return OBJC_MSG_SEND_FXN_PTR; |
| } |
| return OBJC_MSG_SEND_STRET_FXN_PTR; |
| case x86_64: |
| if(scoder.sizeof > 16) |
| return OBJC_MSG_SEND_STRET_FXN_PTR; |
| else |
| return OBJC_MSG_SEND_FXN_PTR; |
| default: |
| throw new RuntimeException(); |
| } |
| } |
| |
| final int typeCode = returnCoder.getTypeCode(); |
| |
| switch(JObjCRuntime.ARCH){ |
| case ppc: |
| return OBJC_MSG_SEND_FXN_PTR; |
| case i386: |
| switch(typeCode) { |
| case Coder.FFI_FLOAT: case Coder.FFI_DOUBLE: case Coder.FFI_LONGDOUBLE: |
| return OBJC_MSG_SEND_FPRET_FXN_PTR; |
| } |
| return OBJC_MSG_SEND_FXN_PTR; |
| case x86_64: |
| if(typeCode == Coder.FFI_LONGDOUBLE) |
| return OBJC_MSG_SEND_FPRET_FXN_PTR; |
| return OBJC_MSG_SEND_FXN_PTR; |
| default: |
| throw new RuntimeException(); |
| } |
| } |
| } |
| |
| public static final class MsgSendSuper extends Invoke{ |
| static{ System.load("/usr/lib/libobjc.dylib"); } |
| |
| private static final long OBJC_MSG_SEND_SUPER_FXN_PTR = new Function("objc_msgSendSuper").fxnPtr; |
| private static final long OBJC_MSG_SEND_SUPER_STRET_FXN_PTR = new Function("objc_msgSendSuper_stret").fxnPtr; |
| |
| final FunCall funCall; |
| final long selPtr; |
| |
| public MsgSendSuper(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) { |
| this.funCall = new FunCall(getMsgSendSuperFxnPtr(returnCoder), |
| CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, getSuperSelCoders(argCoders))); |
| this.selPtr = SEL.getSelectorPtr(name); |
| } |
| |
| public void init(final NativeArgumentBuffer argBuf, final ID obj, final NSClass cls) { |
| funCall.init(argBuf); |
| |
| // Instead of mallocing a struct, or keeping another thread local, |
| // let's write objc_super out to the argbuf, and then point an argument |
| // to the data. |
| |
| final long valPtr = argBuf.argValuesPtr; |
| final int ptrLen = JObjCRuntime.PTR_LEN; |
| |
| IDCoder .INST.push(argBuf.runtime, valPtr, obj); |
| NSClassCoder.INST.push(argBuf.runtime, valPtr + ptrLen, cls); |
| argBuf.argValuesPtr += ptrLen + ptrLen; |
| |
| PrimitivePointerCoder.INST.push(argBuf.runtime, argBuf, valPtr); |
| PrimitivePointerCoder.INST.push(argBuf.runtime, argBuf, selPtr); |
| } |
| |
| @Override public void invoke(final NativeArgumentBuffer argBuf) { |
| funCall.invoke(argBuf); |
| } |
| |
| @Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) { |
| funCall.invoke(buffer, retvalStruct); |
| } |
| |
| // |
| |
| private final static StructCoder objc_super_coder = new StructCoder(JObjCRuntime.PTR_LEN*2, IDCoder.INST, NSClassCoder.INST){ |
| @Override protected Struct newInstance(JObjCRuntime runtime) { return null; }}; |
| |
| static Coder[] getSuperSelCoders(final Coder[] argCoders) { |
| final Coder[] selArgCoders = new Coder[argCoders.length + 2]; |
| selArgCoders[0] = objc_super_coder; |
| selArgCoders[1] = SELCoder.INST; |
| for (int i = 0; i < argCoders.length; i++) |
| selArgCoders[i + 2] = argCoders[i]; |
| return selArgCoders; |
| } |
| |
| static long getMsgSendSuperFxnPtr(final Coder returnCoder){ |
| long normal = MsgSend.getMsgSendFxnPtr(returnCoder); |
| if(normal == MsgSend.OBJC_MSG_SEND_STRET_FXN_PTR) |
| return OBJC_MSG_SEND_SUPER_STRET_FXN_PTR; |
| else |
| return OBJC_MSG_SEND_SUPER_FXN_PTR; |
| } |
| } |
| } |