001/* 002 * BridJ - Dynamic and blazing-fast native interop for Java. 003 * http://bridj.googlecode.com/ 004 * 005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/) 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * * Redistributions of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * * Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in the 015 * documentation and/or other materials provided with the distribution. 016 * * Neither the name of Olivier Chafik nor the 017 * names of its contributors may be used to endorse or promote products 018 * derived from this software without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY 021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 */ 031package org.bridj; 032 033import java.lang.reflect.*; 034import java.nio.*; 035import java.util.*; 036import static org.bridj.StructUtils.*; 037import org.bridj.cpp.CPPObject; 038import org.bridj.cpp.CPPRuntime; 039import org.bridj.cpp.CPPType; 040import org.bridj.util.DefaultParameterizedType; 041import org.bridj.util.Utils; 042 043/** 044 * Internal metadata on a struct field 045 */ 046public class StructFieldDescription { 047 048 public final List<StructFieldDeclaration> aggregatedFields = new ArrayList<StructFieldDeclaration>(); 049 public long alignment = -1; 050 public long byteOffset = -1, byteLength = -1; 051 public long bitOffset = 0; 052 public long bitLength = -1; 053 public long arrayLength = 1; 054 public long bitMask = -1; 055 public boolean isArray, isNativeObject; 056 public Type nativeTypeOrPointerTargetType; 057 public java.lang.reflect.Field field; 058 Type valueType; 059 Method getter; 060 String name; 061 boolean isCLong, isSizeT; 062 063 public void offset(long bytes) { 064 byteOffset += bytes; 065 } 066 067 @Override 068 public String toString() { 069 return "Field(byteOffset = " + byteOffset + ", byteLength = " + byteLength + ", bitOffset = " + bitOffset + ", bitLength = " + bitLength + (nativeTypeOrPointerTargetType == null ? "" : ", ttype = " + nativeTypeOrPointerTargetType) + ")"; 070 } 071 072 static Type resolveType(Type tpe, Type structType) { 073 if (tpe == null || (tpe instanceof WildcardType)) { 074 return null; 075 } 076 077 Type ret; 078 if (tpe instanceof ParameterizedType) { 079 ParameterizedType pt = (ParameterizedType) tpe; 080 Type[] actualTypeArguments = pt.getActualTypeArguments(); 081 Type[] resolvedActualTypeArguments = new Type[actualTypeArguments.length]; 082 for (int i = 0; i < actualTypeArguments.length; i++) { 083 resolvedActualTypeArguments[i] = resolveType(actualTypeArguments[i], structType); 084 } 085 Type resolvedOwnerType = resolveType(pt.getOwnerType(), structType); 086 Type rawType = pt.getRawType(); 087 if ((tpe instanceof CPPType) || CPPObject.class.isAssignableFrom(Utils.getClass(rawType))) // TODO args 088 { 089 ret = new CPPType(resolvedOwnerType, rawType, resolvedActualTypeArguments); 090 } else { 091 ret = new DefaultParameterizedType(resolvedOwnerType, rawType, resolvedActualTypeArguments); 092 } 093 } else if (tpe instanceof TypeVariable) { 094 TypeVariable tv = (TypeVariable) tpe; 095 Class<?> structClass = Utils.getClass(structType); 096 TypeVariable[] typeParameters = structClass.getTypeParameters(); 097 int i = Arrays.asList(typeParameters).indexOf(tv); 098 // TODO recurse on pt.getOwnerType() if i < 0. 099 if (i >= 0) { 100 if (structType instanceof ParameterizedType) { 101 ParameterizedType pt = (ParameterizedType) structType; 102 //Type[] typeParams = CPPRuntime.getTemplateTypeParameters(null, tpe) 103 ret = pt.getActualTypeArguments()[i]; 104 } else { 105 throw new RuntimeException("Type " + structType + " does not have params, cannot resolve " + tpe); 106 } 107 } else { 108 throw new RuntimeException("Type param " + tpe + " not found in params of " + structType + " (" + Arrays.asList(typeParameters) + ")"); 109 } 110 } else { 111 ret = tpe; 112 } 113 114 assert !Utils.containsTypeVariables(ret); 115// throw new RuntimeException("Type " + ret + " cannot be resolved"); 116 117 return ret; 118 } 119 120 static StructFieldDescription aggregateDeclarations(Type structType, List<StructFieldDeclaration> fieldGroup) { 121 StructFieldDescription aggregatedField = new StructFieldDescription(); 122 boolean isMultiFields = fieldGroup.size() > 1; 123 aggregatedField.aggregatedFields.addAll(fieldGroup); 124 for (StructFieldDeclaration field : fieldGroup) { 125 if (field.valueClass.isArray()) { 126 throw new RuntimeException("Struct fields cannot be array types : please use a combination of Pointer and @Array (for instance, an int[10] is a @Array(10) Pointer<Integer>)."); 127 } 128 if (field.valueClass.isPrimitive()) { 129 if (field.desc.isCLong) { 130 field.desc.byteLength = CLong.SIZE; 131 } else if (field.desc.isSizeT) { 132 field.desc.byteLength = SizeT.SIZE; 133 } else { 134 field.desc.byteLength = primTypeLength(field.valueClass); 135 if (field.desc.alignment < 0) 136 field.desc.alignment = primTypeAlignment(field.valueClass, field.desc.byteLength); 137 } 138 } else if (field.valueClass == CLong.class) { 139 field.desc.byteLength = CLong.SIZE; 140 } else if (field.valueClass == SizeT.class) { 141 field.desc.byteLength = SizeT.SIZE; 142 } else if (StructObject.class.isAssignableFrom(field.valueClass)) { 143 field.desc.nativeTypeOrPointerTargetType = resolveType(field.desc.valueType, structType); 144 StructDescription desc = StructIO.getInstance(field.valueClass, field.desc.valueType).desc; 145 field.desc.byteLength = desc.getStructSize(); 146 if (field.desc.alignment < 0) 147 field.desc.alignment = desc.getStructAlignment(); 148 field.desc.isNativeObject = true; 149 } else if (ValuedEnum.class.isAssignableFrom(field.valueClass)) { 150 field.desc.nativeTypeOrPointerTargetType = resolveType((field.desc.valueType instanceof ParameterizedType) ? PointerIO.getClass(((ParameterizedType) field.desc.valueType).getActualTypeArguments()[0]) : null, structType); 151 Class c = PointerIO.getClass(field.desc.nativeTypeOrPointerTargetType); 152 if (IntValuedEnum.class.isAssignableFrom(c)) { 153 field.desc.byteLength = 4; 154 } else { 155 throw new RuntimeException("Enum type unknown : " + c); 156 } 157 //field.callIO = CallIO.Utils.createPointerCallIO(field.valueClass, field.desc.valueType); 158 } else if (TypedPointer.class.isAssignableFrom(field.valueClass)) { 159 field.desc.nativeTypeOrPointerTargetType = resolveType(field.desc.valueType, structType); 160 if (field.desc.isArray) { 161 throw new RuntimeException("Typed pointer field cannot be an array : " + field.desc.name); 162 } 163 field.desc.byteLength = Pointer.SIZE; 164 //field.callIO = CallIO.Utils.createPointerCallIO(field.valueClass, field.desc.valueType); 165 } else if (Pointer.class.isAssignableFrom(field.valueClass)) { 166 Type tpe = (field.desc.valueType instanceof ParameterizedType) ? ((ParameterizedType) field.desc.valueType).getActualTypeArguments()[0] : null; 167 field.desc.nativeTypeOrPointerTargetType = resolveType(tpe, structType); 168 if (field.desc.isArray) { 169 field.desc.byteLength = BridJ.sizeOf(field.desc.nativeTypeOrPointerTargetType); 170 if (field.desc.alignment < 0) 171 field.desc.alignment = alignmentOf(field.desc.nativeTypeOrPointerTargetType); 172 } else { 173 field.desc.byteLength = Pointer.SIZE; 174 } 175 //field.callIO = CallIO.Utils.createPointerCallIO(field.valueClass, field.desc.valueType); 176 } else if (Buffer.class.isAssignableFrom(field.valueClass)) { 177 if (field.valueClass == IntBuffer.class) { 178 field.desc.byteLength = 4; 179 } else if (field.valueClass == LongBuffer.class) { 180 field.desc.byteLength = 8; 181 } else if (field.valueClass == ShortBuffer.class) { 182 field.desc.byteLength = 2; 183 } else if (field.valueClass == ByteBuffer.class) { 184 field.desc.byteLength = 1; 185 } else if (field.valueClass == FloatBuffer.class) { 186 field.desc.byteLength = 4; 187 } else if (field.valueClass == DoubleBuffer.class) { 188 field.desc.byteLength = 8; 189 } else { 190 throw new UnsupportedOperationException("Field array type " + field.valueClass.getName() + " not supported yet"); 191 } 192 } else if (field.valueClass.isArray() && field.valueClass.getComponentType().isPrimitive()) { 193 field.desc.byteLength = primTypeLength(field.valueClass.getComponentType()); 194 if (field.desc.alignment < 0) 195 field.desc.alignment = primTypeAlignment(field.valueClass, field.desc.byteLength); 196 } else { 197 //throw new UnsupportedOperationException("Field type " + field.valueClass.getName() + " not supported yet"); 198 StructDescription desc = StructIO.getInstance(field.valueClass, field.desc.valueType).desc; 199 long s = desc.getStructSize(); 200 if (s > 0) { 201 field.desc.byteLength = s; 202 } else { 203 throw new UnsupportedOperationException("Field type " + field.valueClass.getName() + " not supported yet"); 204 } 205 } 206 207 aggregatedField.alignment = Math.max( 208 aggregatedField.alignment, 209 field.desc.alignment >= 0 210 ? field.desc.alignment 211 : field.desc.byteLength); 212 213 long length = field.desc.arrayLength * field.desc.byteLength; 214 if (length >= aggregatedField.byteLength) { 215 aggregatedField.byteLength = length; 216 } 217 218 if (field.desc.bitLength >= 0) { 219 if (isMultiFields) { 220 throw new RuntimeException("No support for bit fields unions yet !"); 221 } 222 aggregatedField.bitLength = field.desc.bitLength; 223 aggregatedField.byteLength = (aggregatedField.bitLength >>> 3) + ((aggregatedField.bitLength & 7) != 0 ? 1 : 0); 224 } 225 } 226 return aggregatedField; 227 } 228 229 void computeBitMask() { 230 if (bitLength < 0) { 231 bitMask = -1; 232 } else { 233 bitMask = 0; 234 for (int i = 0; i < bitLength; i++) { 235 bitMask = bitMask << 1 | 1; 236 } 237 bitMask = bitMask << bitOffset; 238 } 239 } 240}