All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robovm.objc.ObjCRuntime Maven / Gradle / Ivy

There is a newer version: 2.3.21
Show newest version
/*
 * Copyright (C) 2012 RoboVM AB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.robovm.objc;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.robovm.rt.VM;
import org.robovm.rt.bro.Bro;
import org.robovm.rt.bro.Runtime;
import org.robovm.rt.bro.Struct;
import org.robovm.rt.bro.annotation.Bridge;
import org.robovm.rt.bro.annotation.ByVal;
import org.robovm.rt.bro.annotation.Library;
import org.robovm.rt.bro.annotation.Pointer;
import org.robovm.rt.bro.annotation.StructRet;
import org.robovm.rt.bro.ptr.BytePtr;

/**
 *
 */
@Library("objc")
public class ObjCRuntime {

    private static final Map, Integer> structSizes = new HashMap, Integer>();
    
    static {
        Bro.bind(ObjCRuntime.class);
    }
    
    public static void bind() {
        Class caller = VM.getStackClasses(0, 1)[0];
        bind(caller);
    }
    
    public static void bind(Class c) {
        for (Method method : c.getDeclaredMethods()) {
            Bridge bridge = method.getAnnotation(Bridge.class);
            if (bridge != null && (bridge.symbol() == null || "".equals(bridge.symbol()))) {
                Class[] paramTypes = method.getParameterTypes();
                if (paramTypes.length >= 2) {
                    // An ObjC method takes at least 2 parameters (self, selector)
                    // or (super, selector).
                    if (paramTypes[1] == Selector.class) {
                        String symbol = null;
                        if (paramTypes[0] == ObjCSuper.class) {
                            symbol = "objc_msgSendSuper";
                        } else if (ObjCObject.class.isAssignableFrom(paramTypes[0])) {
                            // self should be an instance of ObjCObject
                            symbol = "objc_msgSend";
                        } else if (paramTypes[0] == long.class) {
                            // Also allow @Pointer long as type of self
                            Annotation[] paramAnnos = method.getParameterAnnotations()[0];
                            for (Annotation a : paramAnnos) {
                                if (a.annotationType() == Pointer.class) {
                                    symbol = "objc_msgSend";
                                    break;
                                }
                            }
                        }
                        if (symbol != null) {
                            // So this is a bridge to an ObjC method. If the method
                            // returns a struct by value we may have to use the
                            // special stret versions of objc_msgSend/objc_msgSendSuper.
                            if (isStret(method)) {
                                symbol += "_stret";
                            }
                            long f = Runtime.resolveBridge("objc", symbol, method);
                            VM.bindBridgeMethod(method, f);
                        }
                    }
                    
                }
            }
        }
        Bro.bind(c);
    }
    
    static boolean isStret(Method method) {
        Class returnType = method.getReturnType();
        if (returnType.getSuperclass() == Struct.class 
                && (method.getAnnotation(ByVal.class) != null 
                || returnType.getAnnotation(ByVal.class) != null)) {
            int structSize = getStructSize(returnType);
            if (Bro.IS_X86 && Bro.IS_32BIT) {
                if (structSize > 2 && structSize != 4 && structSize != 8) {
                    // On x86 stret has to be used for all structs except
                    // of size 1, 2, 4 and 8 bytes.
                    return true;
                }
            } else if (Bro.IS_X86 && Bro.IS_64BIT) {
                if (structSize > 16) {
                    return true;
                }
            } else if (Bro.IS_ARM && Bro.IS_32BIT) {
                if (structSize > 4) {
                    // On ARM stret has to be used for structs
                    // larger than 4 bytes
                    return true;
                }
            } else if (Bro.IS_ARM && Bro.IS_64BIT) {
                // iOS ARM64 doesn't have objc_msgSend_stret
                return false;
            } else {
                throw new Error("Unsupported architecture");
            }
        }
        return false;
    }
    
    static synchronized int getStructSize(Class cls) {
        Integer size = structSizes.get(cls);
        if (size == null) {
            try {
                Method sizeOf = cls.getMethod("sizeOf");
                size = (Integer) sizeOf.invoke(null);
            } catch (Exception e) {
                throw new Error(e);
            }
            structSizes.put(cls, size);
        }
        return size;
    }
    
    
    /* selector */
    
    @Bridge
    public static native BytePtr sel_getName(Selector sel);

    @Bridge
    public static native Selector sel_registerName(BytePtr str);
    
    /* objc */
    
    @Bridge
    public static native @Pointer long objc_getClass(@Pointer long name);
    
    @Bridge
    public static native @Pointer long objc_getMetaClass(@Pointer long name);

    @Bridge
    public static native @Pointer long objc_allocateClassPair(@Pointer long superclass, @Pointer long name, @Pointer long extraBytes);
    
    @Bridge
    public static native void objc_registerClassPair(@Pointer long cls);
    
    @Bridge
    public static native @Pointer long objc_getProtocol(@Pointer long name);
    
    @Bridge
    public static native @Pointer long objc_allocateProtocol(@Pointer long name);
    
    @Bridge
    public static native void objc_registerProtocol(@Pointer long protocol);
    
    @Bridge
    public static native void objc_setAssociatedObject(@Pointer long object, @Pointer long key, @Pointer long value, int policy);

    @Bridge
    public static native @Pointer long objc_getAssociatedObject(@Pointer long object, @Pointer long key);

    @Bridge
    public static native @Pointer long objc_copyProtocolList (@Pointer long outCount);

    /* object */
    
    @Bridge
    public static native @Pointer long object_getClass(@Pointer long object);
    
    @Bridge
    public static native @Pointer long object_setClass(@Pointer long object, @Pointer long cls);

    @Bridge
    public static native @Pointer long object_getClassName(@Pointer long object);
    
    @Bridge
    public static native @Pointer long object_dispose(@Pointer long object);
    
    @Bridge
    public static native @Pointer long object_getIvar(@Pointer long object, @Pointer long ivar);

    @Bridge
    public static native void object_setIvar(@Pointer long object, @Pointer long ivar, @Pointer long value);
    
    /* class */

    @Bridge
    public static native @Pointer long class_getSuperclass(@Pointer long cls);

    @Bridge
    public static native @Pointer long class_isMetaClass(@Pointer long cls);
    
    @Bridge
    public static native @Pointer long class_getName(@Pointer long cls);
    
    @Bridge
    public static native @Pointer long class_getInstanceMethod(@Pointer long aClass, @Pointer long aSelector);

    @Bridge
    public static native @Pointer long class_getClassMethod(@Pointer long aClass, @Pointer long aSelector);
    
    @Bridge
    public static native  boolean class_addProtocol(@Pointer long cls, @Pointer long protocol);
    
    @Bridge
    public static native boolean class_conformsToProtocol(@Pointer long cls, @Pointer long protocol);

    @Bridge
    public static native @Pointer long class_copyProtocolList(@Pointer long cls, @Pointer long outCount);
    
    @Bridge
    public static native @Pointer long class_copyMethodList(@Pointer long cls, @Pointer long outCount);

    @Bridge
    public static native @Pointer long class_copyPropertyList(@Pointer long cls, @Pointer long outCount);

    @Bridge
    public static native boolean class_addMethod(@Pointer long cls, @Pointer long name, @Pointer long imp, @Pointer long types);
    
    @Bridge
    public static native @Pointer long class_replaceMethod(@Pointer long cls, @Pointer long name, @Pointer long imp, @Pointer long types);
    
    @Bridge
    public static native @Pointer long class_getMethodImplementation(@Pointer long cls, @Pointer long name);
    
    @Bridge
    public static native boolean class_addIvar(@Pointer long cls, @Pointer long name, int size, byte alignment, @Pointer long types);
    
    @Bridge
    public static native @Pointer long class_getInstanceVariable(@Pointer long cls, @Pointer long name);
    
    @Bridge
    public static native @Pointer long class_getClassVariable(@Pointer long cls, @Pointer long name);
    
    @Bridge
    public static native @Pointer long class_getIvarLayout(@Pointer long cls);
    
    @Bridge
    public static native void class_setIvarLayout(@Pointer long cls, @Pointer long layout);
    
    @Bridge
    public static native @Pointer long class_getProperty(@Pointer long cls, @Pointer long name);
    
    @Bridge
    public static native boolean class_respondsToSelector(@Pointer long cls, @Pointer long sel);
    
    /* protocol */
    
    @Bridge
    public static native @Pointer long protocol_getName(@Pointer long protocol);
    
    @Bridge
    public static native void protocol_addProtocol(@Pointer long protocol, @Pointer long addition);
    
    @Bridge
    public static native boolean protocol_conformsToProtocol(@Pointer long protocol, @Pointer long other);

    @Bridge
    public static native @Pointer long protocol_getProperty(@Pointer long protocol, @Pointer long name, boolean isRequiredProperty, boolean isInstanceProperty);
    
    @Bridge
    public static native @Pointer long protocol_copyProtocolList(@Pointer long protocol, @Pointer long outCount);
    
    /* ivar */
    
    @Bridge
    public static native @Pointer long ivar_getName(@Pointer long ivar);

    @Bridge
    public static native @Pointer long ivar_getTypeEncoding(@Pointer long ivar);
    
    @Bridge
    public static native int ivar_getOffset(@Pointer long ivar);
    
    /* method */
    
    @Bridge
    public static native @Pointer long method_getName(@Pointer long m);
    
    @Bridge
    public static native @Pointer long method_copyReturnType(@Pointer long m);

    @Bridge
    public static native @Pointer long method_copyArgumentType(@Pointer long m, int index);
    
    @Bridge
    public static native int method_getNumberOfArguments(@Pointer long m);
    
    @Bridge
    public static native @Pointer long method_getTypeEncoding(@Pointer long method);
    
    @Bridge
    public static native @Pointer long method_getImplementation(@Pointer long method);
    
    @Bridge
    public static native @Pointer long method_setImplementation(@Pointer long m, @Pointer long imp);
    
    @Bridge
    public static native void method_exchangeImplementations(@Pointer long m1, @Pointer long m2);
    
    /* property */
    
    @Bridge
    public static native @Pointer long property_getName(@Pointer long property);

    @Bridge
    public static native BytePtr property_getAttributes(@Pointer long property);

    @Bridge
    public static native BytePtr property_copyAttributeValue(@Pointer long property, BytePtr attributeName);
    
    /* message */
    
    @Bridge(symbol = "objc_msgSend")
    public static native @Pointer long ptr_objc_msgSend(@Pointer long receiver, @Pointer long selector);

    @Bridge(symbol = "objc_msgSendSuper")
    public static native @Pointer long ptr_objc_msgSendSuper(@Pointer long zuper, @Pointer long selector);

    @Bridge(symbol = "objc_msgSend")
    public static native void void_objc_msgSend(@Pointer long receiver, @Pointer long selector);

    @Bridge(symbol = "objc_msgSendSuper")
    public static native void void_objc_msgSendSuper(@Pointer long zuper, @Pointer long selector);
    
    @Bridge(symbol = "objc_msgSend")
    public static native boolean boolean_objc_msgSend(@Pointer long receiver, @Pointer long selector);
    
    @Bridge(symbol = "objc_msgSend")
    public static native void void_objc_msgSend_ptr(@Pointer long receiver, @Pointer long selector, @Pointer long ptr);
    
    @Bridge(symbol = "objc_msgSend")
    public static native void void_objc_msgSend_boolean(@Pointer long receiver, @Pointer long selector, boolean b);
    
    @Bridge(symbol = "objc_msgSend")
    public static native int int_objc_msgSend(@Pointer long receiver, @Pointer long selector);

    @Bridge(symbol = "objc_msgSend")
    public static native @Pointer long ptr_objc_msgSend_ptr(@Pointer long receiver, @Pointer long selector, @Pointer long ptr);
    
    @Bridge(symbol = "objc_msgSend")
    public static native @Pointer long ptr_objc_msgSend_int(@Pointer long receiver, @Pointer long selector, int i);
    
    @Bridge(symbol = "objc_msgSend")
    public static native @Pointer long ptr_objc_msgSend_long(@Pointer long receiver, @Pointer long selector, long l);

    @Bridge(symbol = "objc_msgSend")
    public static native char char_objc_msgSend_int(@Pointer long receiver, @Pointer long selector, int i);
    
    @Bridge(symbol = "objc_msgSend_stret", optional = true) // Optional since it's not available on iOS ARM64
    public static native void objc_msgSend_stret(@StructRet @Pointer long ret, @Pointer long receiver, @Pointer long selector);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy