blob: 48ffc98663f55cd1d65c16e976120eab75f25204 [file] [log] [blame]
/*
* 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;
}
}
}