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 java.io.StringWriter; 28 import java.lang.reflect.Method; 29 30 import com.apple.jobjc.JObjCRuntime.Width; 31 import com.apple.jobjc.PrimitiveCoder.BoolCoder; 32 import com.apple.jobjc.PrimitiveCoder.DoubleCoder; 33 import com.apple.jobjc.PrimitiveCoder.FloatCoder; 34 import com.apple.jobjc.PrimitiveCoder.SCharCoder; 35 import com.apple.jobjc.PrimitiveCoder.SIntCoder; 36 import com.apple.jobjc.PrimitiveCoder.SLongLongCoder; 37 import com.apple.jobjc.PrimitiveCoder.SShortCoder; 38 import javax.tools.annotation.GenerateNativeHeader; 39 40 public abstract class Coder<T> { 41 private static native long getNativeFFITypePtrForCode(final int code); 42 43 static final int FFI_VOID = 0; 44 static final int FFI_PTR = FFI_VOID+1; 45 46 static final int FFI_SINT8 = FFI_PTR+1; 47 static final int FFI_UINT8 = FFI_SINT8+1; 48 static final int FFI_SINT16 = FFI_UINT8+1; 49 static final int FFI_UINT16 = FFI_SINT16+1; 50 static final int FFI_SINT32 = FFI_UINT16+1; 51 static final int FFI_UINT32 = FFI_SINT32+1; 52 static final int FFI_SINT64 = FFI_UINT32+1; 53 static final int FFI_UINT64 = FFI_SINT64+1; 54 55 static final int FFI_FLOAT = FFI_UINT64+1; 56 static final int FFI_DOUBLE = FFI_FLOAT+1; 57 static final int FFI_LONGDOUBLE = FFI_DOUBLE+1; 58 59 private static long[] ffiCodesToFFITypePtrs; 60 static{ 61 System.loadLibrary("JObjC"); 62 ffiCodesToFFITypePtrs = new long[FFI_LONGDOUBLE + 1]; 63 for (int i = 0; i < FFI_LONGDOUBLE + 1; i++) ffiCodesToFFITypePtrs[i] = getNativeFFITypePtrForCode(i); 64 } 65 66 long getFFITypePtr() { 67 return ffiCodesToFFITypePtrs[getTypeCode()]; 68 } 69 70 // runtime coding 71 public abstract void push(final JObjCRuntime runtime, final long addr, final T x); 72 public abstract T pop(final JObjCRuntime runtime, final long addr); 73 74 public void push(final NativeArgumentBuffer args, final T x){ 75 push(args.runtime, args.argValuesPtr, x); 76 args.didPutArgValue(sizeof()); 77 } 126 try { 127 Method m = cls.getDeclaredMethod("getStructCoder"); 128 m.setAccessible(true); 129 return (Coder) m.invoke(null); 130 } catch (Exception e) { 131 throw new RuntimeException(e); 132 } 133 } 134 135 throw new RuntimeException("Could not find suitable coder for " + cls); 136 } 137 138 static public Coder getCoderAtRuntime(Object inst){ 139 if(inst == null) return PointerCoder.INST; 140 if(inst instanceof Struct) return ((Struct) inst).getCoder(); 141 return getCoderAtRuntimeForType(inst.getClass()); 142 } 143 144 // 145 146 /* No native methods here, but the constants are needed in the supporting JNI code */ 147 @GenerateNativeHeader 148 public static final class VoidCoder extends Coder<Object>{ 149 public static final VoidCoder INST = new VoidCoder(); 150 public VoidCoder(){ super(FFI_VOID, "v", Void.class, void.class); } 151 @Override public int sizeof(Width w) { return -1; } 152 @Override public Object pop(JObjCRuntime runtime, long addr) { throw new RuntimeException("Trying to pop a Void."); } 153 @Override public void push(JObjCRuntime runtime, long addr, Object x) { throw new RuntimeException("Trying to push a Void."); } 154 } 155 156 /* No native methods here, but the constants are needed in the supporting JNI code */ 157 @GenerateNativeHeader 158 public static final class UnknownCoder extends Coder<Object> { 159 public static final UnknownCoder INST = new UnknownCoder(); 160 public UnknownCoder(){ super(-1, "?", null, null); } 161 @Override public int sizeof(Width w) { return -1; } 162 @Override public void push(JObjCRuntime runtime, long addr, Object x) { throw new RuntimeException("Coder not implemented");} 163 @Override public Object pop(JObjCRuntime runtime, long addr) { throw new RuntimeException("Coder not implemented"); } 164 } 165 166 /* No native methods here, but the constants are needed in the supporting JNI code */ 167 @GenerateNativeHeader 168 public static final class PrimitivePointerCoder extends Coder<Long> { 169 public static final PrimitivePointerCoder INST = new PrimitivePointerCoder(); 170 public PrimitivePointerCoder(){ super(Coder.FFI_PTR, "^?", Long.class, long.class); } 171 @Override public int sizeof(Width w) { return JObjCRuntime.PTR_LEN; } 172 173 public void push(JObjCRuntime runtime, long addr, long x) { 174 if(JObjCRuntime.IS64) 175 runtime.unsafe.putLong(addr, x); 176 else 177 runtime.unsafe.putInt(addr, (int) x); 178 } 179 180 public void push(final JObjCRuntime runtime, final NativeArgumentBuffer argBuf, final long ptr) { 181 push(runtime, argBuf.argValuesPtr, ptr); 182 argBuf.didPutArgValue(sizeof()); 183 } 184 185 public long popPtr(final JObjCRuntime runtime, final long addr) { 186 return JObjCRuntime.IS64 ? runtime.unsafe.getLong(addr) : runtime.unsafe.getInt(addr); 187 } 188 189 public long popPtr(final JObjCRuntime runtime, final NativeArgumentBuffer argBuf) { 190 return popPtr(runtime, argBuf.retValPtr); 191 } 192 193 @Override public Long pop(JObjCRuntime runtime, long addr) { return popPtr(runtime, addr); } 194 @Override public void push(JObjCRuntime runtime, long addr, Long x) { push(runtime, addr, (long) x); } 195 } 196 197 /* No native methods here, but the constants are needed in the supporting JNI code */ 198 @GenerateNativeHeader 199 public static final class PointerCoder extends Coder<Pointer> { 200 public static final PointerCoder INST = new PointerCoder(); 201 public PointerCoder(){ super(FFI_PTR, "^?", Pointer.class); } 202 @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } 203 204 @Override public Pointer pop(JObjCRuntime runtime, long addr) { 205 return new Pointer(PrimitivePointerCoder.INST.popPtr(runtime, addr)); 206 } 207 @Override public void push(JObjCRuntime runtime, long addr, Pointer x) { 208 PrimitivePointerCoder.INST.push(runtime, addr, x == null ? 0 : x.ptr); 209 } 210 } 211 212 /* No native methods here, but the constants are needed in the supporting JNI code */ 213 @GenerateNativeHeader 214 public static final class SELCoder extends Coder<SEL> { 215 public static final SELCoder INST = new SELCoder(); 216 public SELCoder(){ super(FFI_PTR, ":", SEL.class); } 217 @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } 218 219 @Override public void push(JObjCRuntime runtime, long addr, SEL x) { 220 PrimitivePointerCoder.INST.push(runtime, addr, x == null ? 0 : x.selPtr); 221 } 222 @Override public SEL pop(JObjCRuntime runtime, long addr) { 223 return new SEL(PrimitivePointerCoder.INST.popPtr(runtime, addr)); 224 } 225 } 226 227 /* No native methods here, but the constants are needed in the supporting JNI code */ 228 @GenerateNativeHeader 229 public static abstract class StructCoder extends Coder<Struct> { 230 private final FFIType ffiType; 231 final int sizeof; 232 233 public StructCoder(final int sizeof, final Coder... elementCoders){ 234 super(-1, objCEncoding(elementCoders), null); 235 this.ffiType = new FFIType(elementCoders); 236 this.sizeof = sizeof; 237 } 238 239 @Override public int sizeof(Width w) { return sizeof; } 240 241 private static String objCEncoding(final Coder[] elementCoders) { 242 StringWriter str = new StringWriter(); 243 str.append("{?="); 244 for(Coder c : elementCoders) 245 str.append(c.getObjCEncoding()); 246 str.append("}"); 247 return str.toString(); 248 } 250 @Override long getFFITypePtr() { return ffiType.getPtr(); } 251 252 @Override public void push(NativeArgumentBuffer argBuf, Struct x) { 253 // Just point to the instance on the heap instead of copying it onto the arg buf. 254 argBuf.doPutArgPtr(x.raw.bufferPtr); 255 } 256 257 @Override public void push(JObjCRuntime rt, long addr, Struct x) { 258 rt.unsafe.copyMemory(x.raw.bufferPtr, addr, sizeof); 259 } 260 261 protected abstract Struct newInstance(JObjCRuntime runtime); 262 263 @Override public Struct pop(final JObjCRuntime runtime, final long addr) { 264 Struct s = newInstance(runtime); 265 runtime.unsafe.copyMemory(addr, s.raw.bufferPtr, sizeof); 266 return s; 267 } 268 } 269 270 /* No native methods here, but the constants are needed in the supporting JNI code */ 271 @GenerateNativeHeader 272 public static final class IDCoder extends Coder<ID>{ 273 public static final IDCoder INST = new IDCoder(); 274 public IDCoder(){ super(FFI_PTR, "@", ID.class); } 275 @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } 276 277 public <T extends ID> T newID(final JObjCRuntime runtime, final long objPtr) { 278 return (T) ID.getObjCObjectFor(runtime, objPtr); 279 } 280 281 @Override public ID pop(final JObjCRuntime runtime, final long addr) { 282 return newID(runtime, PrimitivePointerCoder.INST.popPtr(runtime, addr)); 283 } 284 285 @Override public void push(final JObjCRuntime runtime, final long addr, final ID x) { 286 PointerCoder.INST.push(runtime, addr, x); 287 } 288 } 289 290 /* No native methods here, but the constants are needed in the supporting JNI code */ 291 @GenerateNativeHeader 292 public static final class NSClassCoder extends Coder<NSClass>{ 293 public static final NSClassCoder INST = new NSClassCoder(); 294 public NSClassCoder(){ super(FFI_PTR, "#", NSClass.class); } 295 @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } 296 297 @Override public NSClass pop(JObjCRuntime runtime, long addr) { 298 final long clsPtr = PrimitivePointerCoder.INST.popPtr(runtime, addr); 299 if (clsPtr == 0) return null; 300 return NSClass.getObjCClassFor(runtime, clsPtr); 301 } 302 @Override public void push(JObjCRuntime runtime, long addr, NSClass x) { 303 PointerCoder.INST.push(runtime, addr, x); 304 } 305 } 306 } | 1 /* 2 * Copyright (c) 2011, 2013, 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 java.io.StringWriter; 28 import java.lang.reflect.Method; 29 30 import com.apple.jobjc.JObjCRuntime.Width; 31 import com.apple.jobjc.PrimitiveCoder.BoolCoder; 32 import com.apple.jobjc.PrimitiveCoder.DoubleCoder; 33 import com.apple.jobjc.PrimitiveCoder.FloatCoder; 34 import com.apple.jobjc.PrimitiveCoder.SCharCoder; 35 import com.apple.jobjc.PrimitiveCoder.SIntCoder; 36 import com.apple.jobjc.PrimitiveCoder.SLongLongCoder; 37 import com.apple.jobjc.PrimitiveCoder.SShortCoder; 38 import java.lang.annotation.Native; 39 40 public abstract class Coder<T> { 41 private static native long getNativeFFITypePtrForCode(final int code); 42 43 @Native static final int FFI_VOID = 0; 44 @Native static final int FFI_PTR = FFI_VOID+1; 45 46 @Native static final int FFI_SINT8 = FFI_PTR+1; 47 @Native static final int FFI_UINT8 = FFI_SINT8+1; 48 @Native static final int FFI_SINT16 = FFI_UINT8+1; 49 @Native static final int FFI_UINT16 = FFI_SINT16+1; 50 @Native static final int FFI_SINT32 = FFI_UINT16+1; 51 @Native static final int FFI_UINT32 = FFI_SINT32+1; 52 @Native static final int FFI_SINT64 = FFI_UINT32+1; 53 @Native static final int FFI_UINT64 = FFI_SINT64+1; 54 55 @Native static final int FFI_FLOAT = FFI_UINT64+1; 56 @Native static final int FFI_DOUBLE = FFI_FLOAT+1; 57 @Native static final int FFI_LONGDOUBLE = FFI_DOUBLE+1; 58 59 private static long[] ffiCodesToFFITypePtrs; 60 static{ 61 System.loadLibrary("JObjC"); 62 ffiCodesToFFITypePtrs = new long[FFI_LONGDOUBLE + 1]; 63 for (int i = 0; i < FFI_LONGDOUBLE + 1; i++) ffiCodesToFFITypePtrs[i] = getNativeFFITypePtrForCode(i); 64 } 65 66 long getFFITypePtr() { 67 return ffiCodesToFFITypePtrs[getTypeCode()]; 68 } 69 70 // runtime coding 71 public abstract void push(final JObjCRuntime runtime, final long addr, final T x); 72 public abstract T pop(final JObjCRuntime runtime, final long addr); 73 74 public void push(final NativeArgumentBuffer args, final T x){ 75 push(args.runtime, args.argValuesPtr, x); 76 args.didPutArgValue(sizeof()); 77 } 126 try { 127 Method m = cls.getDeclaredMethod("getStructCoder"); 128 m.setAccessible(true); 129 return (Coder) m.invoke(null); 130 } catch (Exception e) { 131 throw new RuntimeException(e); 132 } 133 } 134 135 throw new RuntimeException("Could not find suitable coder for " + cls); 136 } 137 138 static public Coder getCoderAtRuntime(Object inst){ 139 if(inst == null) return PointerCoder.INST; 140 if(inst instanceof Struct) return ((Struct) inst).getCoder(); 141 return getCoderAtRuntimeForType(inst.getClass()); 142 } 143 144 // 145 146 public static final class VoidCoder extends Coder<Object>{ 147 public static final VoidCoder INST = new VoidCoder(); 148 public VoidCoder(){ super(FFI_VOID, "v", Void.class, void.class); } 149 @Override public int sizeof(Width w) { return -1; } 150 @Override public Object pop(JObjCRuntime runtime, long addr) { throw new RuntimeException("Trying to pop a Void."); } 151 @Override public void push(JObjCRuntime runtime, long addr, Object x) { throw new RuntimeException("Trying to push a Void."); } 152 } 153 154 public static final class UnknownCoder extends Coder<Object> { 155 public static final UnknownCoder INST = new UnknownCoder(); 156 public UnknownCoder(){ super(-1, "?", null, null); } 157 @Override public int sizeof(Width w) { return -1; } 158 @Override public void push(JObjCRuntime runtime, long addr, Object x) { throw new RuntimeException("Coder not implemented");} 159 @Override public Object pop(JObjCRuntime runtime, long addr) { throw new RuntimeException("Coder not implemented"); } 160 } 161 162 public static final class PrimitivePointerCoder extends Coder<Long> { 163 public static final PrimitivePointerCoder INST = new PrimitivePointerCoder(); 164 public PrimitivePointerCoder(){ super(Coder.FFI_PTR, "^?", Long.class, long.class); } 165 @Override public int sizeof(Width w) { return JObjCRuntime.PTR_LEN; } 166 167 public void push(JObjCRuntime runtime, long addr, long x) { 168 if(JObjCRuntime.IS64) 169 runtime.unsafe.putLong(addr, x); 170 else 171 runtime.unsafe.putInt(addr, (int) x); 172 } 173 174 public void push(final JObjCRuntime runtime, final NativeArgumentBuffer argBuf, final long ptr) { 175 push(runtime, argBuf.argValuesPtr, ptr); 176 argBuf.didPutArgValue(sizeof()); 177 } 178 179 public long popPtr(final JObjCRuntime runtime, final long addr) { 180 return JObjCRuntime.IS64 ? runtime.unsafe.getLong(addr) : runtime.unsafe.getInt(addr); 181 } 182 183 public long popPtr(final JObjCRuntime runtime, final NativeArgumentBuffer argBuf) { 184 return popPtr(runtime, argBuf.retValPtr); 185 } 186 187 @Override public Long pop(JObjCRuntime runtime, long addr) { return popPtr(runtime, addr); } 188 @Override public void push(JObjCRuntime runtime, long addr, Long x) { push(runtime, addr, (long) x); } 189 } 190 191 public static final class PointerCoder extends Coder<Pointer> { 192 public static final PointerCoder INST = new PointerCoder(); 193 public PointerCoder(){ super(FFI_PTR, "^?", Pointer.class); } 194 @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } 195 196 @Override public Pointer pop(JObjCRuntime runtime, long addr) { 197 return new Pointer(PrimitivePointerCoder.INST.popPtr(runtime, addr)); 198 } 199 @Override public void push(JObjCRuntime runtime, long addr, Pointer x) { 200 PrimitivePointerCoder.INST.push(runtime, addr, x == null ? 0 : x.ptr); 201 } 202 } 203 204 public static final class SELCoder extends Coder<SEL> { 205 public static final SELCoder INST = new SELCoder(); 206 public SELCoder(){ super(FFI_PTR, ":", SEL.class); } 207 @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } 208 209 @Override public void push(JObjCRuntime runtime, long addr, SEL x) { 210 PrimitivePointerCoder.INST.push(runtime, addr, x == null ? 0 : x.selPtr); 211 } 212 @Override public SEL pop(JObjCRuntime runtime, long addr) { 213 return new SEL(PrimitivePointerCoder.INST.popPtr(runtime, addr)); 214 } 215 } 216 217 public static abstract class StructCoder extends Coder<Struct> { 218 private final FFIType ffiType; 219 final int sizeof; 220 221 public StructCoder(final int sizeof, final Coder... elementCoders){ 222 super(-1, objCEncoding(elementCoders), null); 223 this.ffiType = new FFIType(elementCoders); 224 this.sizeof = sizeof; 225 } 226 227 @Override public int sizeof(Width w) { return sizeof; } 228 229 private static String objCEncoding(final Coder[] elementCoders) { 230 StringWriter str = new StringWriter(); 231 str.append("{?="); 232 for(Coder c : elementCoders) 233 str.append(c.getObjCEncoding()); 234 str.append("}"); 235 return str.toString(); 236 } 238 @Override long getFFITypePtr() { return ffiType.getPtr(); } 239 240 @Override public void push(NativeArgumentBuffer argBuf, Struct x) { 241 // Just point to the instance on the heap instead of copying it onto the arg buf. 242 argBuf.doPutArgPtr(x.raw.bufferPtr); 243 } 244 245 @Override public void push(JObjCRuntime rt, long addr, Struct x) { 246 rt.unsafe.copyMemory(x.raw.bufferPtr, addr, sizeof); 247 } 248 249 protected abstract Struct newInstance(JObjCRuntime runtime); 250 251 @Override public Struct pop(final JObjCRuntime runtime, final long addr) { 252 Struct s = newInstance(runtime); 253 runtime.unsafe.copyMemory(addr, s.raw.bufferPtr, sizeof); 254 return s; 255 } 256 } 257 258 public static final class IDCoder extends Coder<ID>{ 259 public static final IDCoder INST = new IDCoder(); 260 public IDCoder(){ super(FFI_PTR, "@", ID.class); } 261 @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } 262 263 public <T extends ID> T newID(final JObjCRuntime runtime, final long objPtr) { 264 return (T) ID.getObjCObjectFor(runtime, objPtr); 265 } 266 267 @Override public ID pop(final JObjCRuntime runtime, final long addr) { 268 return newID(runtime, PrimitivePointerCoder.INST.popPtr(runtime, addr)); 269 } 270 271 @Override public void push(final JObjCRuntime runtime, final long addr, final ID x) { 272 PointerCoder.INST.push(runtime, addr, x); 273 } 274 } 275 276 public static final class NSClassCoder extends Coder<NSClass>{ 277 public static final NSClassCoder INST = new NSClassCoder(); 278 public NSClassCoder(){ super(FFI_PTR, "#", NSClass.class); } 279 @Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); } 280 281 @Override public NSClass pop(JObjCRuntime runtime, long addr) { 282 final long clsPtr = PrimitivePointerCoder.INST.popPtr(runtime, addr); 283 if (clsPtr == 0) return null; 284 return NSClass.getObjCClassFor(runtime, clsPtr); 285 } 286 @Override public void push(JObjCRuntime runtime, long addr, NSClass x) { 287 PointerCoder.INST.push(runtime, addr, x); 288 } 289 } 290 } |