/* * 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 java.io.StringWriter; import java.lang.reflect.Method; import com.apple.jobjc.JObjCRuntime.Width; import com.apple.jobjc.PrimitiveCoder.BoolCoder; import com.apple.jobjc.PrimitiveCoder.DoubleCoder; import com.apple.jobjc.PrimitiveCoder.FloatCoder; import com.apple.jobjc.PrimitiveCoder.SCharCoder; import com.apple.jobjc.PrimitiveCoder.SIntCoder; import com.apple.jobjc.PrimitiveCoder.SLongLongCoder; import com.apple.jobjc.PrimitiveCoder.SShortCoder; import java.lang.annotation.Native; public abstract class Coder { private static native long getNativeFFITypePtrForCode(final int code); @Native static final int FFI_VOID = 0; @Native static final int FFI_PTR = FFI_VOID+1; @Native static final int FFI_SINT8 = FFI_PTR+1; @Native static final int FFI_UINT8 = FFI_SINT8+1; @Native static final int FFI_SINT16 = FFI_UINT8+1; @Native static final int FFI_UINT16 = FFI_SINT16+1; @Native static final int FFI_SINT32 = FFI_UINT16+1; @Native static final int FFI_UINT32 = FFI_SINT32+1; @Native static final int FFI_SINT64 = FFI_UINT32+1; @Native static final int FFI_UINT64 = FFI_SINT64+1; @Native static final int FFI_FLOAT = FFI_UINT64+1; @Native static final int FFI_DOUBLE = FFI_FLOAT+1; @Native static final int FFI_LONGDOUBLE = FFI_DOUBLE+1; private static long[] ffiCodesToFFITypePtrs; static{ System.loadLibrary("JObjC"); ffiCodesToFFITypePtrs = new long[FFI_LONGDOUBLE + 1]; for (int i = 0; i < FFI_LONGDOUBLE + 1; i++) ffiCodesToFFITypePtrs[i] = getNativeFFITypePtrForCode(i); } long getFFITypePtr() { return ffiCodesToFFITypePtrs[getTypeCode()]; } // runtime coding public abstract void push(final JObjCRuntime runtime, final long addr, final T x); public abstract T pop(final JObjCRuntime runtime, final long addr); public void push(final NativeArgumentBuffer args, final T x){ push(args.runtime, args.argValuesPtr, x); args.didPutArgValue(sizeof()); } public T pop(final NativeArgumentBuffer args){ return pop(args.runtime, args.retValPtr); } public abstract int sizeof(Width w); final public int sizeof(){ return sizeof(JObjCRuntime.WIDTH); } // public Coder(int ffiTypeCode, String objCEncoding, Class jclass, Class jprim) { this.ffiTypeCode = ffiTypeCode; this.objCEncoding = objCEncoding; this.jclass = jclass; this.jprim = jprim; } public Coder(int ffiTypeCode, String objCEncoding, Class jclass) { this(ffiTypeCode, objCEncoding, jclass, null); } private final int ffiTypeCode; private final String objCEncoding; private final Class jclass; private final Class jprim; final int getTypeCode() { return ffiTypeCode; } final String getObjCEncoding(){ return objCEncoding; } public final Class getJavaClass() { return jclass; } public final Class getJavaPrimitive() { return jprim; } // runtime coding private static Coder[] runtimeCoders; static public Coder getCoderAtRuntimeForType(Class cls){ if(runtimeCoders == null) runtimeCoders = new Coder[]{ NSClassCoder.INST, IDCoder.INST, PointerCoder.INST, DoubleCoder.INST, FloatCoder.INST, SLongLongCoder.INST, SIntCoder.INST, SShortCoder.INST, SCharCoder.INST, BoolCoder.INST, VoidCoder.INST }; for(Coder c : runtimeCoders) if((c.getJavaClass() != null && c.getJavaClass().isAssignableFrom(cls)) || (c.getJavaPrimitive() != null && c.getJavaPrimitive().isAssignableFrom(cls))) return c; if(Struct.class.isAssignableFrom(cls)){ try { Method m = cls.getDeclaredMethod("getStructCoder"); m.setAccessible(true); return (Coder) m.invoke(null); } catch (Exception e) { throw new RuntimeException(e); } } throw new RuntimeException("Could not find suitable coder for " + cls); } static public Coder getCoderAtRuntime(Object inst){ if(inst == null) return PointerCoder.INST; if(inst instanceof Struct) return ((Struct) inst).getCoder(); return getCoderAtRuntimeForType(inst.getClass()); } // public static final class VoidCoder extends Coder{ public static final VoidCoder INST = new VoidCoder(); public VoidCoder(){ super(FFI_VOID, "v", Void.class, void.class); } @Override public int sizeof(Width w) { return -1; } @Override public Object pop(JObjCRuntime runtime, long addr) { throw new RuntimeException("Trying to pop a Void."); } @Override public void push(JObjCRuntime runtime, long addr, Object x) { throw new RuntimeException("Trying to push a Void."); } } public static final class UnknownCoder extends Coder { public static final UnknownCoder INST = new UnknownCoder(); public UnknownCoder(){ super(-1, "?", null, null); } @Override public int sizeof(Width w) { return -1; } @Override public void push(JObjCRuntime runtime, long addr, Object x) { throw new RuntimeException("Coder not implemented");} @Override public Object pop(JObjCRuntime runtime, long addr) { throw new RuntimeException("Coder not implemented"); } } public static final class PrimitivePointerCoder extends Coder { public static final PrimitivePointerCoder INST = new PrimitivePointerCoder(); public PrimitivePointerCoder(){ super(Coder.FFI_PTR, "^?", Long.class, long.class); } @Override public int sizeof(Width w) { return JObjCRuntime.PTR_LEN; } public void push(JObjCRuntime runtime, long addr, long x) { if(JObjCRuntime.IS64) runtime.unsafe.putLong(addr, x); else runtime.unsafe.putInt(addr, (int) x); } public void push(final JObjCRuntime runtime, final NativeArgumentBuffer argBuf, final long ptr) { push(runtime, argBuf.argValuesPtr, ptr); argBuf.didPutArgValue(sizeof()); } public long popPtr(final JObjCRuntime runtime, final long addr) { return JObjCRuntime.IS64 ? runtime.unsafe.getLong(addr) : runtime.unsafe.getInt(addr); } public long popPtr(final JObjCRuntime runtime, final NativeArgumentBuffer argBuf) { return popPtr(runtime, argBuf.retValPtr); } @Override public Long pop(JObjCRuntime runtime, long addr) { return popPtr(runtime, addr); } @Override public void push(JObjCRuntime runtime, long addr, Long x) { push(runtime, addr, (long) x); } } public static final class PointerCoder extends Coder { public static final PointerCoder INST = new PointerCoder(); public PointerCoder(){ super(FFI_PTR, "^?", Pointer.class); } @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } @Override public Pointer pop(JObjCRuntime runtime, long addr) { return new Pointer(PrimitivePointerCoder.INST.popPtr(runtime, addr)); } @Override public void push(JObjCRuntime runtime, long addr, Pointer x) { PrimitivePointerCoder.INST.push(runtime, addr, x == null ? 0 : x.ptr); } } public static final class SELCoder extends Coder { public static final SELCoder INST = new SELCoder(); public SELCoder(){ super(FFI_PTR, ":", SEL.class); } @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } @Override public void push(JObjCRuntime runtime, long addr, SEL x) { PrimitivePointerCoder.INST.push(runtime, addr, x == null ? 0 : x.selPtr); } @Override public SEL pop(JObjCRuntime runtime, long addr) { return new SEL(PrimitivePointerCoder.INST.popPtr(runtime, addr)); } } public static abstract class StructCoder extends Coder { private final FFIType ffiType; final int sizeof; public StructCoder(final int sizeof, final Coder... elementCoders){ super(-1, objCEncoding(elementCoders), null); this.ffiType = new FFIType(elementCoders); this.sizeof = sizeof; } @Override public int sizeof(Width w) { return sizeof; } private static String objCEncoding(final Coder[] elementCoders) { StringWriter str = new StringWriter(); str.append("{?="); for(Coder c : elementCoders) str.append(c.getObjCEncoding()); str.append("}"); return str.toString(); } @Override long getFFITypePtr() { return ffiType.getPtr(); } @Override public void push(NativeArgumentBuffer argBuf, Struct x) { // Just point to the instance on the heap instead of copying it onto the arg buf. argBuf.doPutArgPtr(x.raw.bufferPtr); } @Override public void push(JObjCRuntime rt, long addr, Struct x) { rt.unsafe.copyMemory(x.raw.bufferPtr, addr, sizeof); } protected abstract Struct newInstance(JObjCRuntime runtime); @Override public Struct pop(final JObjCRuntime runtime, final long addr) { Struct s = newInstance(runtime); runtime.unsafe.copyMemory(addr, s.raw.bufferPtr, sizeof); return s; } } public static final class IDCoder extends Coder{ public static final IDCoder INST = new IDCoder(); public IDCoder(){ super(FFI_PTR, "@", ID.class); } @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } public T newID(final JObjCRuntime runtime, final long objPtr) { return (T) ID.getObjCObjectFor(runtime, objPtr); } @Override public ID pop(final JObjCRuntime runtime, final long addr) { return newID(runtime, PrimitivePointerCoder.INST.popPtr(runtime, addr)); } @Override public void push(final JObjCRuntime runtime, final long addr, final ID x) { PointerCoder.INST.push(runtime, addr, x); } } public static final class NSClassCoder extends Coder{ public static final NSClassCoder INST = new NSClassCoder(); public NSClassCoder(){ super(FFI_PTR, "#", NSClass.class); } @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } @Override public NSClass pop(JObjCRuntime runtime, long addr) { final long clsPtr = PrimitivePointerCoder.INST.popPtr(runtime, addr); if (clsPtr == 0) return null; return NSClass.getObjCClassFor(runtime, clsPtr); } @Override public void push(JObjCRuntime runtime, long addr, NSClass x) { PointerCoder.INST.push(runtime, addr, x); } } }