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.TypeVariable; 034import java.lang.reflect.WildcardType; 035import org.bridj.CallIO.NativeObjectHandler; 036import org.bridj.util.*; 037import java.lang.reflect.ParameterizedType; 038import java.lang.reflect.Method; 039import java.lang.reflect.Modifier; 040import java.lang.reflect.Member; 041import java.lang.reflect.AnnotatedElement; 042import java.lang.reflect.Type; 043import java.nio.*; 044import java.util.ArrayList; 045import java.util.Collections; 046import java.util.Comparator; 047import java.util.HashMap; 048import java.util.LinkedHashMap; 049import java.util.HashSet; 050import java.util.List; 051import java.util.Map; 052import java.util.TreeMap; 053import java.util.Set; 054import java.util.concurrent.*; 055import org.bridj.ann.Virtual; 056import org.bridj.ann.Array; 057import org.bridj.ann.Union; 058import org.bridj.ann.Bits; 059import org.bridj.ann.Field; 060import org.bridj.ann.Struct; 061import org.bridj.ann.Alignment; 062import static org.bridj.Pointer.*; 063import static org.bridj.StructUtils.*; 064 065/** 066 * Representation of a C struct's memory layout, built thanks to the annotations 067 * found in the Java bindings.<br> 068 * End-users should not use this class, it's used by runtimes.<br> 069 * Annotations currently used are 070 * {@link org.bridj.ann.Virtual}, {@link org.bridj.ann.Array}, {@link org.bridj.ann.Bits}, {@link org.bridj.ann.Field}, {@link org.bridj.ann.Alignment} 071 * and {@link org.bridj.ann.Struct} 072 * 073 * @author ochafik 074 */ 075public class StructDescription { 076 077 protected volatile StructFieldDescription[] fields; 078 protected long structSize = -1; 079 protected long structAlignment = -1; 080 protected final Class<?> structClass; 081 protected final Type structType; 082 protected boolean hasFieldFields; 083 084 public void prependBytes(long bytes) { 085 build(); 086 for (StructFieldDescription field : fields) { 087 field.offset(bytes); 088 } 089 structSize += bytes; 090 } 091 092 public void appendBytes(long bytes) { 093 build(); 094 structSize += bytes; 095 } 096 097 public void setFieldOffset(String fieldName, long fieldOffset, boolean propagateChanges) { 098 build(); 099 100 long propagatedOffsetDelta = 0; 101 long originalOffset = 0; 102 for (StructFieldDescription field : fields) { 103 if (field.name.equals(fieldName)) { 104 originalOffset = field.byteOffset; 105 propagatedOffsetDelta = fieldOffset - field.byteOffset; 106 field.offset(propagatedOffsetDelta); 107 if (!propagateChanges) { 108 long minSize = fieldOffset + field.byteLength; 109 structSize = structSize < minSize ? minSize : structSize; 110 return; 111 } 112 } 113 } 114 structSize += propagatedOffsetDelta; 115 for (StructFieldDescription field : fields) { 116 if (!field.name.equals(fieldName) && field.byteOffset > originalOffset) { 117 field.offset(propagatedOffsetDelta); 118 } 119 } 120 } 121 StructCustomizer customizer; 122 123 public StructDescription(Class<?> structClass, Type structType, StructCustomizer customizer) { 124 this.structClass = structClass; 125 this.structType = structType; 126 this.customizer = customizer; 127 if (Utils.containsTypeVariables(structType)) { 128 throw new RuntimeException("Type " + structType + " contains unresolved type variables!"); 129 } 130 // Don't call build here, for recursive initialization cases. 131 } 132 133 boolean isVirtual() { 134 for (Method m : structClass.getMethods()) { 135 if (m.getAnnotation(Virtual.class) != null) { 136 return true; 137 } 138 } 139 return false; 140 } 141 142 public Class<?> getStructClass() { 143 return structClass; 144 } 145 146 public Type getStructType() { 147 return structType; 148 } 149 150 @Override 151 public String toString() { 152 return "StructDescription(" + Utils.toString(structType) + ")"; 153 } 154 155 /// Call whenever an instanceof a struct that depends on that StructIO is created 156 void build() { 157 if (fields == null) { 158 synchronized (this) { 159 if (fields == null) { 160 computeStructLayout(this, customizer); 161 customizer.afterBuild(this); 162 if (BridJ.debug) { 163 BridJ.info(describe()); 164 } 165 } 166 } 167 } 168 } 169 170 public final long getStructSize() { 171 build(); 172 return structSize; 173 } 174 175 public final long getStructAlignment() { 176 build(); 177 return structAlignment; 178 } 179 private List<StructFieldDescription> aggregatedFields; 180 181 public void setAggregatedFields(List<StructFieldDescription> aggregatedFields) { 182 this.aggregatedFields = aggregatedFields; 183 } 184 185 public List<StructFieldDescription> getAggregatedFields() { 186 build(); 187 return aggregatedFields; 188 } 189 SolidRanges solidRanges; 190 191 public SolidRanges getSolidRanges() { 192 build(); 193 return solidRanges; 194 } 195 196 public final String describe(StructObject struct) { 197 return StructUtils.describe(struct, structType, fields); 198 } 199 200 public final String describe() { 201 StringBuilder b = new StringBuilder(); 202 b.append("// "); 203 b.append("size = ").append(structSize).append(", "); 204 b.append("alignment = ").append(structAlignment); 205 b.append("\nstruct "); 206 b.append(StructUtils.describe(structType)).append(" { "); 207 for (int iField = 0, nFields = fields.length; iField < nFields; iField++) { 208 StructFieldDescription fd = fields[iField]; 209 b.append("\n\t"); 210 b.append("@Field(").append(iField).append(") "); 211 if (fd.isCLong) { 212 b.append("@CLong "); 213 } else if (fd.isSizeT) { 214 b.append("@Ptr "); 215 } 216 b.append(StructUtils.describe(fd.valueType)).append(" ").append(fd.name).append("; "); 217 218 b.append("// "); 219 b.append("offset = ").append(fd.byteOffset).append(", "); 220 b.append("length = ").append(fd.byteLength).append(", "); 221 if (fd.bitOffset != 0) { 222 b.append("bitOffset = ").append(fd.bitOffset).append(", "); 223 } 224 if (fd.bitLength != -1) { 225 b.append("bitLength = ").append(fd.bitLength).append(", "); 226 } 227 if (fd.arrayLength != 1) { 228 b.append("arrayLength = ").append(fd.arrayLength).append(", "); 229 } 230 if (fd.alignment != 1) { 231 b.append("alignment = ").append(fd.alignment);//.append(", "); 232 } 233 } 234 b.append("\n}"); 235 return b.toString(); 236 } 237}