001    
002    /*
003     * To change this template, choose Tools | Templates
004     * and open the template in the editor.
005     */
006    package org.bridj.cpp;
007                                                
008    import org.bridj.SizeT;
009    import java.util.Set;
010    import org.bridj.ann.Template;
011    import org.bridj.DynamicFunction;
012    import org.bridj.demangling.Demangler.IdentLike;
013    import org.bridj.demangling.Demangler.MemberRef;
014    import org.bridj.util.Pair;
015    import java.lang.reflect.Constructor;
016    import org.bridj.DynamicFunctionFactory;
017    import org.bridj.ann.Convention;
018    import org.bridj.Callback;
019    import org.bridj.Platform;
020    import java.io.FileNotFoundException;
021    import java.lang.reflect.Method;
022    import java.lang.reflect.Modifier;
023    import java.lang.reflect.GenericDeclaration;
024    import java.lang.reflect.AnnotatedElement;
025    import java.lang.reflect.TypeVariable;
026    import java.util.HashMap;
027    import java.util.Map;
028    
029    import org.bridj.BridJ;
030    import static org.bridj.BridJ.*;
031    import org.bridj.JNI;
032    import org.bridj.MethodCallInfo;
033    import org.bridj.NativeLibrary;
034    import org.bridj.NativeObject;
035    import org.bridj.Pointer;
036    import org.bridj.PointerIO;
037    
038    import static org.bridj.dyncall.DyncallLibrary.*;
039    
040    import org.bridj.demangling.Demangler.Symbol;
041    import org.bridj.NativeEntities.Builder;
042    import org.bridj.ann.Virtual;
043    import org.bridj.CRuntime;
044    import org.bridj.NativeLibrary.SymbolAccepter;
045    import org.bridj.util.Utils;
046    import java.lang.reflect.Type;
047    import java.util.ArrayList;
048    import java.util.List;
049    import java.util.Arrays;
050    import java.util.HashSet;
051    import java.util.TreeMap;
052    import org.bridj.ann.Convention.Style;
053    import org.bridj.demangling.Demangler.SpecialName;
054    import static org.bridj.Pointer.*;
055    import org.bridj.demangling.Demangler;
056    
057    /**
058     * C++ runtime (derives from the C runtime).<br>
059     * Deals with registration and lifecycle of C++ classes and methods (virtual or not).
060     * @author ochafik
061     */
062    public class CPPRuntime extends CRuntime {
063    
064            public static final int DEFAULT_CONSTRUCTOR = -1, SKIP_CONSTRUCTOR = -2;
065            
066        public static CPPRuntime getInstance() {
067            return BridJ.getRuntimeByRuntimeClass(CPPRuntime.class);
068        }
069        public Object[] getTemplateParameters(CPPObject object, Class<?> typeClass) {
070            synchronized(object) {
071                    Object[] params = null;
072                    if (object.templateParameters != null) {
073                            params = object.templateParameters.get(typeClass);
074                    }
075                    return params;// == null ? new Object[0] : params;
076            }
077        }
078        public void setTemplateParameters(CPPObject object, Class<?> typeClass, Object[] params) {
079            synchronized(object) {
080                    if (object.templateParameters == null)
081                    object.templateParameters = new HashMap<Class<?>, Object[]>();
082                object.templateParameters.put(typeClass, params);
083            }
084        }
085        protected interface ClassTypeVariableExtractor {
086                    Type extract(CPPObject instance);
087        }
088        protected interface MethodTypeVariableExtractor {
089                    Type extract(CPPObject instance, Object[] methodTemplateParameters);
090        }
091    
092        protected static int getAnnotatedTemplateTypeVariableIndexInArguments(TypeVariable<?> var) {
093                    GenericDeclaration d = var.getGenericDeclaration();
094                    AnnotatedElement e = (AnnotatedElement)d;
095                    
096                    Template t = e.getAnnotation(Template.class);
097                    if (t == null)
098                            throw new RuntimeException(e + " is not a C++ class template (misses the @" + Template.class.getName() + " annotation)");
099                    
100                    int iTypeVar = Arrays.asList(d.getTypeParameters()).indexOf(var);
101                    int nTypes = 0, iParam = -1;
102                    Class<?>[] values = t.value();
103                    for (int i = 0, n = values.length; i < n; i++) {
104                            Class<?> c = values[i];
105                            if (c == Class.class || c == Type.class)
106                                    nTypes++;
107                            
108                            if (nTypes == iTypeVar) {
109                                    iParam = i;
110                                    break;
111                            }
112                    }
113                    if (iParam < 0)
114                    throw new RuntimeException("Couldn't find the type variable " + var + " (offset " + iTypeVar + ") in the @" + Template.class.getName() + " annotation : " + Arrays.asList(values));
115            
116                    return iParam;
117        }
118        protected ClassTypeVariableExtractor createClassTypeVariableExtractor(TypeVariable<Class<?>> var) {
119                    final Class<?> typeClass = var.getGenericDeclaration();
120                    final int iTypeInParams = getAnnotatedTemplateTypeVariableIndexInArguments(var);
121                    return new ClassTypeVariableExtractor() {
122                            public Type extract(CPPObject instance) {
123                                    typeClass.cast(instance);
124                                    Object[] params = getTemplateParameters(instance, typeClass);
125                                    if (params == null)
126                                            throw new RuntimeException("No type parameters found in this instance : " + instance);
127                                    
128                                    return (Type)params[iTypeInParams];
129                            }
130                    };
131        }
132        protected MethodTypeVariableExtractor createMethodTypeVariableExtractor(TypeVariable<?> var) {
133                    GenericDeclaration d = var.getGenericDeclaration();
134                    if (d instanceof Class) {
135                            final Class<?> typeClass = (Class<?>)d;
136                            final ClassTypeVariableExtractor ce = createClassTypeVariableExtractor((TypeVariable)var);
137                            return new MethodTypeVariableExtractor() {
138                                    public Type extract(CPPObject instance, Object[] methodTemplateParameters) {
139                                            return ce.extract(instance);
140                                    }
141                            };
142                    } else {
143                            Method method = (Method)d;
144                            final Class<?> typeClass = method.getDeclaringClass();
145                            
146                            final int iTypeInParams = getAnnotatedTemplateTypeVariableIndexInArguments(var);
147                            return new MethodTypeVariableExtractor() {
148                                    public Type extract(CPPObject instance, Object[] methodTemplateParameters) {
149                                            typeClass.cast(instance);
150                                            return (Type)methodTemplateParameters[iTypeInParams];
151                                    }
152                            };
153                    }
154        }
155        
156        @Override
157        public <T extends NativeObject> Class<? extends T> getActualInstanceClass(Pointer<T> pInstance, Type officialType) {
158            //String className = null;
159            // For C++ classes in general, take type info at offset -1 of vtable (if first field matches the address of a known static or dynamic virtual table) and use it to create the correct instance.
160    //              Pointer<?> vptr = pInstance.getPointer(0);
161    //              Symbol symbol = BridJ.getSymbolByAddress(vptr.getPeer());
162    //              if (symbol != null && symbol.isVirtualTable()) {
163    //                      if (symbol.enclosingType.matches(officialType))
164    //                              return officialType;
165    //                      
166    //                      try {
167    //                              Class<?> type = BridJ.getCPPRuntime().getCPPClass(symbol.enclosingType);
168    //                              if (officialType == null || officialType.isAssignableFrom(type))
169    //                                      return type;
170    //                      } catch (ClassNotFoundException ex) {}
171    //                      return officialType;
172    //                      
173    //                      /*long tinf = JNI.get_pointer(ptr - Pointer.SIZE);
174    //                      symbol = BridJ.getSymbolByAddress(tinf);
175    //                      if (symbol != null && symbol.isTypeInfo()) {
176    //                              
177    //                      }*/
178    //              }
179            // For Objective-C classes, use "const char* className = class_getName([yourObject class]);" and match to registered classes or more
180            // Bundle auto-generated type mappings files : bridj::CPPTest=org.bridj.test.cpp.CPPTest
181            // 
182            return Utils.getClass(officialType);
183        }
184        Map<Class<?>, Integer> virtualMethodsCounts = new HashMap<Class<?>, Integer>();
185    
186        public int getVirtualMethodsCount(Class<?> type) {
187            Integer count = virtualMethodsCounts.get(type);
188            if (count == null) {
189                List<VirtMeth> mets = new ArrayList<VirtMeth>();
190                listVirtualMethods(type, mets);
191    
192                // TODO unify this !
193                virtualMethodsCounts.put(type, count = mets.size());
194            }
195            return count;
196        }
197    
198        protected static class VirtMeth {
199            Method implementation, definition;
200        }
201        protected void listVirtualMethods(Class<?> type, List<VirtMeth> out) {
202            if (!CPPObject.class.isAssignableFrom(type)) {
203                return;
204            }
205    
206            Class<?> sup = type.getSuperclass();
207            if (sup != CPPObject.class) {
208                listVirtualMethods(sup, out);
209            }
210    
211            int nParentMethods = out.size();
212    
213            Map<Integer, VirtMeth> newVirtuals = new TreeMap<Integer, VirtMeth>();
214    
215            methods:
216            for (Method method : type.getDeclaredMethods()) {
217                String methodName = method.getName();
218                Type[] methodParameterTypes = method.getGenericParameterTypes();
219                for (int iParentMethod = 0; iParentMethod < nParentMethods; iParentMethod++) {
220                    VirtMeth pvm = out.get(iParentMethod);
221                    Method parentMethod = pvm.definition;
222                    if (parentMethod.getDeclaringClass() == type)
223                        continue; // was just added in the same listVirtualMethods call !
224    
225                    //if (parentMethod.getAnnotation(Virtual.class) == null)
226                    //    continue; // not a virtual method, too bad
227    
228                    if (parentMethod.getName().equals(methodName) && isOverridenSignature(parentMethod.getGenericParameterTypes(), methodParameterTypes, 0)) {
229                        VirtMeth vm = new VirtMeth();
230                        vm.definition = pvm.definition;
231                        vm.implementation = method;
232                        out.set(iParentMethod, vm);
233                        continue methods;
234                    }
235                }
236    
237                Virtual virtual = method.getAnnotation(Virtual.class);
238                if (virtual != null) {
239                    VirtMeth vm = new VirtMeth();
240                    vm.definition = vm.implementation = method;
241                    newVirtuals.put(virtual.value(), vm);
242                }
243            }
244            out.addAll(newVirtuals.values());
245        }
246    
247        @Override
248        protected void registerNativeMethod(Class<?> type, NativeLibrary typeLibrary, Method method, NativeLibrary methodLibrary, Builder builder, MethodCallInfoBuilder methodCallInfoBuilder) throws FileNotFoundException {
249    
250            int modifiers = method.getModifiers();
251            boolean isCPPClass = CPPObject.class.isAssignableFrom(method.getDeclaringClass());
252    
253    //              Annotation[][] anns = method.getParameterAnnotations();
254            if (!isCPPClass) {
255                super.registerNativeMethod(type, typeLibrary, method, methodLibrary, builder, methodCallInfoBuilder);
256                return;
257            }
258    
259            MethodCallInfo mci = methodCallInfoBuilder.apply(method);
260    
261            Virtual va = method.getAnnotation(Virtual.class);
262            if (va == null) {
263                Symbol symbol = methodLibrary.getSymbol(method);
264                mci.setForwardedPointer(symbol == null ? 0 : symbol.getAddress());
265                if (mci.getForwardedPointer() == 0) {
266                    assert error("Method " + method.toGenericString() + " is not virtual but its address could not be resolved in the library.");
267                    return;
268                }
269                if (Modifier.isStatic(modifiers)) {
270                    builder.addFunction(mci);
271                    if (debug)
272                            info("Registering " + method + " as function or static C++ method " + symbol.getName());
273                } else {
274                    builder.addFunction(mci);
275                    if (debug)
276                            info("Registering " + method + " as C++ method " + symbol.getName());
277                }
278            } else {
279                if (Modifier.isStatic(modifiers)) {
280                    warning("Method " + method.toGenericString() + " is native and maps to a function, but is not static.");
281                }
282                
283                int theoreticalVirtualIndex = va.value();
284                int theoreticalAbsoluteVirtualIndex = theoreticalVirtualIndex < 0 ? - 1 : getAbsoluteVirtualIndex(method, theoreticalVirtualIndex, type);
285                
286                int absoluteVirtualIndex;
287                
288                Pointer<Pointer<?>> pVirtualTable = isCPPClass && typeLibrary != null ? (Pointer)pointerToAddress(getVirtualTable(type, typeLibrary), Pointer.class) : null;
289                if (pVirtualTable == null) {
290                    if (theoreticalAbsoluteVirtualIndex < 0) {
291                        error("Method " + method.toGenericString() + " is virtual but the virtual table of class " + type.getName() + " was not found and the virtual method index is not provided in its @Virtual annotation.");
292                        return;
293                    }
294                    absoluteVirtualIndex = theoreticalAbsoluteVirtualIndex;
295                } else {
296                    int guessedAbsoluteVirtualIndex = getPositionInVirtualTable(pVirtualTable, method, typeLibrary);
297                    if (guessedAbsoluteVirtualIndex < 0) {
298                        if (theoreticalAbsoluteVirtualIndex < 0) {
299                            error("Method " + method.toGenericString() + " is virtual but its position could not be found in the virtual table.");
300                            return;
301                        } else {
302                            absoluteVirtualIndex = theoreticalAbsoluteVirtualIndex;
303                        }
304                    } else {
305                        if (theoreticalAbsoluteVirtualIndex >= 0 && guessedAbsoluteVirtualIndex != theoreticalAbsoluteVirtualIndex) {
306                            warning("Method " + method.toGenericString() + " has @Virtual annotation indicating virtual index " + theoreticalAbsoluteVirtualIndex + ", but analysis of the actual virtual table rather indicates it has index " + guessedAbsoluteVirtualIndex + " (using the guess)");
307                        }
308                        absoluteVirtualIndex = guessedAbsoluteVirtualIndex;
309                    }
310                }
311                mci.setVirtualIndex(absoluteVirtualIndex);
312                if (debug)
313                                    info("Registering " + method.toGenericString() + " as virtual C++ method with absolute virtual table index = " + absoluteVirtualIndex);
314                builder.addVirtualMethod(mci);
315            }
316        }
317        int getAbsoluteVirtualIndex(Method method, int virtualIndex, Class<?> type) {
318            Class<?> superclass = type.getSuperclass();
319            int virtualOffset = getVirtualMethodsCount(superclass);
320            boolean isNewVirtual = true;
321            if (superclass != null) {
322                try {
323                    // TODO handle polymorphism in overloads :
324                    superclass.getMethod(method.getName(), method.getParameterTypes());
325                    isNewVirtual = false;
326                } catch (NoSuchMethodException ex) {}
327            }
328            int absoluteVirtualIndex = isNewVirtual ? virtualOffset + virtualIndex : virtualIndex;
329            return absoluteVirtualIndex;
330        }
331        public static class MemoryOperators {
332                    protected DynamicFunction<Pointer<?>> newFct;
333                    protected DynamicFunction<Pointer<?>> newArrayFct;
334                    protected DynamicFunction<Void> deleteFct;
335                    protected DynamicFunction<Void> deleteArrayFct;
336                    
337                protected MemoryOperators() {}
338                    public MemoryOperators(NativeLibrary library) {
339                            for (Symbol sym : library.getSymbols()) {
340                                    try {
341                            MemberRef parsedRef = sym.getParsedRef();
342                            IdentLike n = parsedRef.getMemberName();
343                            
344                            if (SpecialName.New.equals(n))
345                                newFct = pointerToAddress(sym.getAddress()).asDynamicFunction(null, Pointer.class, SizeT.class);
346                            else if (SpecialName.NewArray.equals(n))
347                                newFct = pointerToAddress(sym.getAddress()).asDynamicFunction(null, Pointer.class, SizeT.class);
348                            else if (SpecialName.Delete.equals(n))
349                                newFct = pointerToAddress(sym.getAddress()).asDynamicFunction(null, Void.class, Pointer.class);
350                            else if (SpecialName.DeleteArray.equals(n))
351                                newFct = pointerToAddress(sym.getAddress()).asDynamicFunction(null, Void.class, Pointer.class);
352                            
353                                    } catch (Exception ex) {}
354                            }
355                    }
356                
357                public Pointer<?> cppNew(long size) {
358                    return newFct.apply(new SizeT(size));
359                }
360                public Pointer<?> cppNewArray(long size) {
361                    return newArrayFct.apply(new SizeT(size));
362                }
363                public void cppDelete(Pointer<?> ptr) {
364                    deleteFct.apply(ptr);
365                }
366                public void cppDeleteArray(Pointer<?> ptr) {
367                    deleteArrayFct.apply(ptr);
368                }
369        }
370        volatile MemoryOperators memoryOperators;
371    
372        public synchronized MemoryOperators getMemoryOperators() {
373            if (memoryOperators == null) {
374                try {
375                    NativeLibrary libStdCpp = BridJ.getNativeLibrary("stdc++");
376                    memoryOperators = new MemoryOperators(libStdCpp);
377                } catch (Exception ex) {
378                    BridJ.error(null, ex);
379                }
380            }
381            return memoryOperators;
382        }
383        
384        int getPositionInVirtualTable(Method method, NativeLibrary library) {
385                    Class<?> type = method.getDeclaringClass();
386                    Pointer<Pointer<?>> pVirtualTable = (Pointer)pointerToAddress(getVirtualTable(type, library), Pointer.class);
387                    return getPositionInVirtualTable(pVirtualTable, method, library);
388            }
389        String getCPPClassName(Class<?> declaringClass) {
390                    return declaringClass.getSimpleName();
391            }
392    
393            public int getPositionInVirtualTable(Pointer<Pointer<?>> pVirtualTable, Method method, NativeLibrary library) {
394                    //Pointer<?> typeInfo = pVirtualTable.get(1);
395                    int methodsOffset = 0;//library.isMSVC() ? 0 : -2;///2;
396                    String className = getCPPClassName(method.getDeclaringClass());
397                    for (int iVirtual = 0;; iVirtual++) {
398                            Pointer<?> pMethod = pVirtualTable.get(methodsOffset + iVirtual);
399                            String virtualMethodName = pMethod == null ? null : library.getSymbolName(pMethod.getPeer());
400                            //System.out.println("#\n# At index " + methodsOffset + " + " + iVirtual + " of vptr for class " + className + ", found symbol " + Long.toHexString(pMethod.getPeer()) + " = '" + virtualMethodName + "'\n#");
401                            if (virtualMethodName == null) {
402                    if (debug)
403                            info("\tVtable(" + className + ")[" + iVirtual + "] = null");
404                    return -1;
405                }
406                try {
407                    MemberRef mr = library.parseSymbol(virtualMethodName);
408                    if (debug)
409                            info("\tVtable(" + className + ")[" + iVirtual + "] = " + virtualMethodName + " = " + mr);
410                    if (mr != null && mr.matchesSignature(method))
411                        return iVirtual;
412                    else if (library.isMSVC() && !mr.matchesEnclosingType(method))
413                        break; // no NULL terminator in MSVC++ vtables, so we have to guess when we've reached the end
414                } catch (Demangler.DemanglingException ex) {
415                    BridJ.warning("Failed to demangle '" + virtualMethodName + "' during inspection of virtual table for '" + method.toGenericString() + "' : " + ex);
416                }
417                
418                    }
419                    return -1;
420            }
421        static int getDefaultDyncallCppConvention() {
422            int convention = DC_CALL_C_DEFAULT;
423            if (!Platform.is64Bits() && Platform.isWindows()) {
424                convention = DC_CALL_C_X86_WIN32_THIS_MS;
425            }
426            return convention;
427        }
428        
429        private String ptrToString(Pointer<?> ptr, NativeLibrary library) {
430            return ptr == null ? "null" : Long.toHexString(ptr.getPeer()) + " (" + library.getSymbolName(ptr.getPeer()) + ")";
431        }
432    
433        @Convention(Style.ThisCall)
434        public abstract static class CPPDestructor extends Callback {
435            public abstract void destroy(long peer);
436        }
437    
438        Set<Type> typesThatDontNeedASyntheticVirtualTable = new HashSet<Type>();
439        Map<Type, VTable> syntheticVirtualTables = new HashMap<Type, VTable>();
440    
441        protected boolean installRegularVTablePtr(Type type, NativeLibrary library, Pointer<?> peer) {
442            long vtablePtr = getVirtualTable(type, library);
443            if (vtablePtr != 0) {
444                if (BridJ.debug)
445                    BridJ.info("Installing regular vtable pointer " + Pointer.pointerToAddress(vtablePtr) + " to instance at " + peer + " (type = " + Utils.toString(type) + ")");
446                peer.setSizeT(vtablePtr);
447                return true;
448            }
449            return false;
450        }
451        protected boolean installSyntheticVTablePtr(Type type, NativeLibrary library, Pointer<?> peer) {
452            synchronized (syntheticVirtualTables) {
453                VTable vtable = syntheticVirtualTables.get(type);
454                if (vtable == null) {
455                    if (!typesThatDontNeedASyntheticVirtualTable.contains(type)) {
456                        List<VirtMeth> methods = new ArrayList<VirtMeth>();
457                        listVirtualMethods(Utils.getClass(type), methods);
458                        boolean needsASyntheticVirtualTable = false;
459                        for (VirtMeth method : methods)
460                            if (!Modifier.isNative(method.implementation.getModifiers())) {
461                                needsASyntheticVirtualTable = true;
462                                break;
463                            }
464                        if (needsASyntheticVirtualTable) {
465                            Type parentType = Utils.getParent(type);
466                            Pointer<Pointer> parentVTablePtr = null;
467                            if (CPPObject.class.isAssignableFrom(Utils.getClass(parentType))) {
468                                parentVTablePtr = peer.getPointer(Pointer.class);
469                                if (BridJ.debug) {
470                                    BridJ.info("Found parent virtual table pointer = " + ptrToString(parentVTablePtr, library));
471                                    /*Pointer<Pointer> expectedParentVTablePtr = pointerToAddress(getVirtualTable(parentType, library), Pointer.class);
472                                    if (expectedParentVTablePtr != null && !Utils.eq(parentVTablePtr, expectedParentVTablePtr))
473                                        BridJ.warning("Weird parent virtual table pointer : expected " + ptrToString(expectedParentVTablePtr, library) + ", got " + ptrToString(parentVTablePtr, library));
474                                    */
475    
476                                }
477                                //parentVTablePtr = pointerToAddress(getVirtualTable(parentType, library), Pointer.class);
478                            }
479                            syntheticVirtualTables.put(type, vtable = synthetizeVirtualTable(type, parentVTablePtr, methods, library));
480                        } else {
481                            typesThatDontNeedASyntheticVirtualTable.add(type);
482                        }
483                    }
484                }
485                if (vtable != null) {
486                    if (BridJ.debug)
487                        BridJ.info("Installing synthetic vtable pointer " + vtable.ptr + " to instance at " + peer + " (type = " + Utils.toString(type) + ", " + vtable.callbacks.size() + " callbacks)");
488                    peer.setPointer(vtable.ptr);
489                    return vtable.ptr != null;
490                } else
491                    return false;
492            }
493        }
494        static class VTable {
495            Pointer<Pointer<?>> ptr;
496            Map<Method, Pointer<?>> callbacks = new HashMap<Method, Pointer<?>>();
497        }
498        protected VTable synthetizeVirtualTable(Type type, Pointer<Pointer> parentVTablePtr, List<VirtMeth> methods, NativeLibrary library) {
499            int nMethods = methods.size();
500            //Pointer<Pointer> parentVTablePtr = pointerToAddress(getVirtualTable(Utils.getParent(type), library), Pointer.class);
501            VTable vtable = new VTable();
502            vtable.ptr = allocatePointers(nMethods + 2).next(2); // leave two null pointers at index -2 and -1, to say there's no runtime type information available.
503    
504            Class<?> c = Utils.getClass(type);
505            for (int iMethod = 0; iMethod < nMethods; iMethod++) {
506                VirtMeth vm = methods.get(iMethod);
507                Pointer<?> pMethod;
508                if (Modifier.isNative(vm.implementation.getModifiers())) {
509                    pMethod = parentVTablePtr == null ? null : parentVTablePtr.get(iMethod);
510                } else {
511                    try {
512                        MethodCallInfo mci = new MethodCallInfo(vm.implementation, vm.definition);
513                        mci.setDeclaringClass(vm.implementation.getDeclaringClass());
514                        pMethod = createCToJavaCallback(mci, c);
515                        vtable.callbacks.put(vm.implementation, pMethod);
516                    } catch (Throwable th) {
517                        BridJ.error("Failed to register overridden method " + vm.implementation + " for type " + type + " (original method = " + vm.definition + ")", th);
518                        pMethod = null;
519                    }
520                }
521                vtable.ptr.set(iMethod, (Pointer)pMethod);
522            }
523            return vtable;
524        }
525        static int getTemplateParametersCount(Class<?> typeClass) {
526                    Template t = typeClass.getAnnotation(Template.class);
527                    // TODO do something with these args !
528                    int templateParametersCount = t == null ? 0 : t.value().length;
529                    return templateParametersCount;
530        }
531        Map<Pair<Type, Integer>, DynamicFunction> constructors = new HashMap<Pair<Type, Integer>, DynamicFunction>();
532        DynamicFunction getConstructor(final Class<?> typeClass, final Type type, NativeLibrary lib, int constructorId) {
533            Pair<Type, Integer> key = new Pair<Type, Integer>(type, constructorId);
534            DynamicFunction constructor = constructors.get(key);
535            if (constructor == null) {
536                try {
537                    final Constructor<?> constr;
538                    try {
539                                    constr = findConstructor(typeClass, constructorId, true);
540                                    
541                                    if (debug)
542                                            BridJ.info("Found constructor for " + Utils.toString(type) + " : " + constr);
543                    } catch (NoSuchMethodException ex) {
544                                    if (debug)
545                                            BridJ.info("No constructor for " + Utils.toString(type));
546                                    return null;
547                    }
548                    Symbol symbol = lib == null ? null : lib.getFirstMatchingSymbol(new SymbolAccepter() { public boolean accept(Symbol symbol) {
549                        return symbol.matchesConstructor(constr.getDeclaringClass() == Utils.getClass(type) ? type : constr.getDeclaringClass() /* TODO */, constr);
550                    }});
551                    if (symbol == null) {
552                            if (debug)
553                                    BridJ.info("No matching constructor for " + Utils.toString(type) + " (" + constr + ")");
554                                            return null;
555                    }
556    
557                    if (debug)
558                            info("Registering constructor " + constr + " as " + symbol.getName());
559    
560                    // TODO do something with these args !
561                    int templateParametersCount = getTemplateParametersCount(typeClass);
562    
563                    Class<?>[] consParamTypes = constr.getParameterTypes();
564                    Class<?>[] consThisParamTypes = new Class[consParamTypes.length + 1 - templateParametersCount];
565                    consThisParamTypes[0] = Pointer.class;
566                    System.arraycopy(consParamTypes, templateParametersCount, consThisParamTypes, 1, consParamTypes.length - templateParametersCount);
567    
568                    DynamicFunctionFactory constructorFactory = getDynamicFunctionFactory(lib, Style.ThisCall, void.class, consThisParamTypes);
569    
570                    constructor = constructorFactory.newInstance(pointerToAddress(symbol.getAddress()));
571                    constructors.put(key, constructor);
572                } catch (Throwable th) {
573                            th.printStackTrace();
574                    throw new RuntimeException("Unable to create constructor " + constructorId + " for " + type + " : " + th, th);
575                }
576            }
577            return constructor;
578        }
579        Map<Type, CPPDestructor> destructors = new HashMap<Type, CPPDestructor>();
580        CPPDestructor getDestructor(final Class<?> typeClass, Type type, NativeLibrary lib) {
581            CPPDestructor destructor = destructors.get(type);
582            if (destructor == null) {
583                Symbol symbol = lib.getFirstMatchingSymbol(new SymbolAccepter() { public boolean accept(Symbol symbol) {
584                    return symbol.matchesDestructor(typeClass);
585                }});
586                if (BridJ.debug && symbol != null)
587                    info("Registering destructor of " + Utils.toString(type) + " as " + symbol.getName());
588    
589                if (symbol != null)
590                    destructors.put(type, destructor = pointerToAddress(symbol.getAddress(), CPPDestructor.class).get());
591            }
592            return destructor;
593        }
594        Pointer.Releaser newCPPReleaser(final Type type) {
595            try {
596                final Class<?> typeClass = Utils.getClass(type);
597                NativeLibrary lib = BridJ.getNativeLibrary(typeClass);
598                return newCPPReleaser(type, typeClass, lib);
599            } catch (Throwable th) {
600                throw new RuntimeException("Failed to create a C++ destructor for type " + Utils.toString(type) + " : " + th, th);
601            }
602        }
603        Pointer.Releaser newCPPReleaser(final Type type, final Class<?> typeClass, NativeLibrary lib) throws FileNotFoundException {
604            Pointer.Releaser releaser = null;
605            //final Class<?> typeClass = Utils.getClass(type);
606            //NativeLibrary lib = BridJ.getNativeLibrary(typeClass);
607            if (lib != null && BridJ.enableDestructors) {
608                final CPPDestructor destructor = getDestructor(typeClass, type, lib);
609                if (destructor != null)
610                    releaser = new Pointer.Releaser() { //@Override 
611                    public void release(Pointer<?> p) {
612                           if (BridJ.debug)
613                               BridJ.info("Destructing instance of C++ type " + Utils.toString(type) + " (address = " + p + ", destructor = " + pointerTo(destructor) + ")");
614    
615                        //System.out.println("Destructing instance of C++ type " + type + "...");
616                        long peer = p.getPeer();
617                        destructor.destroy(peer);
618                        BridJ.setJavaObjectFromNativePeer(peer, null);
619                    }};
620            }
621            return releaser;
622        }
623        protected <T extends CPPObject> Pointer<T> newCPPInstance(T instance, final Type type, int constructorId, Object... args) {
624            Pointer<T> peer = null;
625            try {
626                final Class<T> typeClass = Utils.getClass(type);
627                NativeLibrary lib = BridJ.getNativeLibrary(typeClass);
628    
629                if (BridJ.debug)
630                                    info("Creating C++ instance of type " + type + " with args " + Arrays.asList(args));
631                Pointer.Releaser releaser = newCPPReleaser(type, typeClass, lib);
632    
633                long size = sizeOf(type, null);
634                peer = (Pointer) Pointer.allocateBytes(PointerIO.getInstance(type), size, releaser).as(type);
635                
636                DynamicFunction constructor = constructorId == SKIP_CONSTRUCTOR ? null : getConstructor(typeClass, type, lib, constructorId);
637                
638                if (lib != null && CPPObject.class.isAssignableFrom(typeClass)) {
639                    installRegularVTablePtr(type, lib, peer);
640                } else {
641                    // TODO ObjCObject : call alloc on class type !!
642                }
643                
644                // Setting the C++ template parameters in the instance :
645                int templateParametersCount = getTemplateParametersCount(typeClass);
646                if (templateParametersCount > 0) {
647                    Object[] templateArgs = new Object[templateParametersCount];
648                    System.arraycopy(args, 0, templateArgs, 0, templateParametersCount);
649                    setTemplateParameters(instance, typeClass, templateArgs);
650                }
651                
652                // Calling the constructor with the non-template parameters :
653                if (constructor != null) {
654                                    Object[] consThisArgs = new Object[args.length - templateParametersCount + 1];
655                                    consThisArgs[0] = peer;
656                                    System.arraycopy(args, templateParametersCount, consThisArgs, 1, args.length - templateParametersCount);
657    
658                                    constructor.apply(consThisArgs);
659                            }
660                            
661                            // Install synthetic virtual table and associate the Java instance to the corresponding native pointer : 
662                if (CPPObject.class.isAssignableFrom(typeClass)) {
663                    if (installSyntheticVTablePtr(type, lib, peer))
664                        BridJ.setJavaObjectFromNativePeer(peer.getPeer(), instance);
665                } else {
666                    // TODO ObjCObject : call alloc on class type !!
667                }
668                return peer;
669            } catch (Exception ex) {
670                ex.printStackTrace();
671                if (peer != null) {
672                    peer.release();
673                }
674                throw new RuntimeException("Failed to allocate new instance of type " + type, ex);
675            }
676        }
677        
678        
679        /*
680            Map<Type, Pointer<Pointer<?>>> vtablePtrs = new HashMap<Type, Pointer<Pointer<?>>>();
681            @SuppressWarnings("unchecked")
682            public
683            //Pointer<Pointer<?>>
684        long getVirtualTable(Type type, NativeLibrary library) {
685                    Pointer<Pointer<?>> p = vtablePtrs.get(type);
686                    if (p == null) {
687                            Class<?> typeClass = Utils.getClass(type);
688                            // TODO ask for real template name
689                            String className = typeClass.getSimpleName();
690                            String vtableSymbol;
691                if (Platform.isWindows())
692                    vtableSymbol = "??_7" + className + "@@6B@";
693                else
694                    vtableSymbol = "_ZTV" + className.length() + className;
695    
696                long addr = library.getSymbolAddress(vtableSymbol);
697                            //long addr = JNI.findSymbolInLibrary(getHandle(), vtableSymbolName);
698    //                      System.out.println(TestCPP.hex(addr));
699    //                      TestCPP.print(type.getName() + " vtable", addr, 5, 2);
700                    
701                            p = (Pointer)Pointer.pointerToAddress(addr, Pointer.class);
702                            vtablePtrs.put(type, p);
703                    }
704                    return p.getPeer();
705            }*/
706        
707        Map<Type, Long> vtables = new HashMap<Type, Long>();
708            long getVirtualTable(Type type, NativeLibrary library) {
709            Long vtable = vtables.get(type);
710            if (vtable == null) {
711                final Class<?> typeClass = Utils.getClass(type);
712                if (false) {
713                        String className = typeClass.getSimpleName();
714                                    String vtableSymbol;
715                        if (Platform.isWindows())
716                            vtableSymbol = "??_7" + className + "@@6B@";
717                        else
718                            vtableSymbol = "_ZTV" + className.length() + className;
719            
720                                    vtables.put(type, vtable = library.getSymbolAddress(vtableSymbol));
721                            } else {
722                                    Symbol symbol = library.getFirstMatchingSymbol(new SymbolAccepter() { public boolean accept(Symbol symbol) { 
723                                            return symbol.matchesVirtualTable(typeClass);
724                                    }});
725                                    if (symbol != null) {
726                                            if (BridJ.debug)
727                                                    info("Registering vtable of " + Utils.toString(type) + " as " + symbol.getName());
728    //                    Pointer<Pointer> pp = pointerToAddress(symbol.getAddress(), Pointer.class);
729    //                    
730    //                    for (int i = 0; i < 6; i++) {
731    //                        Pointer p = pp.get(i);
732    ////                        if (p == null)
733    ////                            break;
734    //                        String n = p == null ? null : library.getSymbolName(p.getPeer());
735    //                        info("\tVtable entry " + i + " = " + p + " (" + n + ")");
736    ////                        if (n == null)
737    ////                            break;
738    //                    }
739                    }
740                    else if (getVirtualMethodsCount(typeClass) > 0)
741                        error("Failed to find a vtable for type " + Utils.toString(type));
742                    
743                    if (symbol != null) {
744                        long address = symbol.getAddress();
745                        vtable = library.isMSVC() ? address : address + 2 * Pointer.SIZE;
746                    } else {
747                        vtable = 0L;
748                    }
749                                    vtables.put(type, vtable);//*/
750                            }
751            }
752            return vtable;
753        }
754        
755        public class CPPTypeInfo<T extends CPPObject> extends CTypeInfo<T> {
756            public CPPTypeInfo(Type type) {
757                super(type);
758            }
759            Map<TypeVariable<Class<?>>, ClassTypeVariableExtractor> classTypeVariableExtractors;
760            Map<TypeVariable<?>, MethodTypeVariableExtractor> methodTypeVariableExtractors;
761    
762            public Type resolveClassType(CPPObject instance, TypeVariable<?> var) {
763                return getClassTypeVariableExtractor((TypeVariable)var).extract(instance);
764            }
765                    public Type resolveMethodType(CPPObject instance, Object[] methodTemplateParameters, TypeVariable<?> var) {
766                return getMethodTypeVariableExtractor(var).extract(instance, methodTemplateParameters);
767            }
768                    protected synchronized ClassTypeVariableExtractor getClassTypeVariableExtractor(TypeVariable<Class<?>> var) {
769                            if (classTypeVariableExtractors == null)
770                                    classTypeVariableExtractors = new HashMap<TypeVariable<Class<?>>, ClassTypeVariableExtractor>();
771                            ClassTypeVariableExtractor e = classTypeVariableExtractors.get(var);
772                            if (e == null)
773                                    classTypeVariableExtractors.put(var, e = createClassTypeVariableExtractor(var));
774                            return e;
775            }
776                    protected synchronized MethodTypeVariableExtractor getMethodTypeVariableExtractor(TypeVariable<?> var) {
777                            if (methodTypeVariableExtractors == null)
778                                    methodTypeVariableExtractors = new HashMap<TypeVariable<?>, MethodTypeVariableExtractor>();
779                            MethodTypeVariableExtractor e = methodTypeVariableExtractors.get(var);
780                            if (e == null)
781                                    methodTypeVariableExtractors.put(var, e = createMethodTypeVariableExtractor(var));
782                            return e;
783            }
784    
785            @Override
786            public long sizeOf() {
787                // TODO handle template size here ? (depends on template args)
788                return super.sizeOf();
789            }
790    
791            @Override
792            public T createReturnInstance() {
793                try {
794                    Object[] templateParameters = getTemplateParameters(type);
795                    T instance = (T) getCastClass().newInstance();
796                    initialize(instance, SKIP_CONSTRUCTOR, templateParameters);
797                    //setTemplateParameters(instance, typeClass, getTemplateParameters(type));
798                    return instance;
799                } catch (Throwable th) {
800                    throw new RuntimeException("Failed to create a return instance for type " + Utils.toString(type) + " : " + th, th);
801                }
802            }
803    
804            @Override
805            public T cast(Pointer peer) {
806                if (BridJ.isCastingNativeObjectReturnTypeInCurrentThread()) {
807                    peer = peer.withReleaser(newCPPReleaser(type));
808                }
809                T instance = super.cast(peer);
810                Object[] templateParameters = getTemplateParameters(type);
811                setTemplateParameters(instance, (Class)typeClass, templateParameters);
812                return instance;
813            }
814            
815            @SuppressWarnings("unchecked")
816            @Override
817            public void initialize(T instance, int constructorId, Object... args) {
818                if (instance instanceof CPPObject) {
819                    //instance.peer = allocate(instance.getClass(), constructorId, args);
820                    int[] position = new int[] { 0 };
821    
822                    Type cppType = CPPType.parseCPPType(CPPType.cons((Class<? extends CPPObject>)typeClass, args), position);
823                    //int actualArgsOffset = position[0] - 1, nActualArgs = args.length - actualArgsOffset;
824                    //System.out.println("actualArgsOffset = " + actualArgsOffset);
825                    //Object[] actualArgs = new Object[nActualArgs];
826                    //System.arraycopy(args, actualArgsOffset, actualArgs, 0, nActualArgs);
827    
828                    setNativeObjectPeer(instance, newCPPInstance((CPPObject)instance, cppType, constructorId, args));
829                    super.initialize(instance, DEFAULT_CONSTRUCTOR);
830                } else {
831                    super.initialize(instance, constructorId, args);
832                }
833            }
834    
835            @Override
836            public T clone(T instance) throws CloneNotSupportedException {
837                if (instance instanceof CPPObject) {
838                    // TODO use copy constructor !!!
839                }
840                return super.clone(instance);
841            }
842    
843            @Override
844            public void destroy(T instance) {
845                //TODO call destructor here ? (and call here from finalizer manually created by autogenerated classes
846            }
847    
848            private Object[] getTemplateParameters(Type type) {
849                if (!(type instanceof CPPType))
850                    return null;
851                return ((CPPType)type).getTemplateParameters();
852            }
853            }
854        /// Needs not be fast : TypeInfo will be cached in BridJ anyway !
855        @Override
856        public <T extends NativeObject> TypeInfo<T> getTypeInfo(final Type type) {
857            return new CPPTypeInfo(type);
858        }
859    
860        public <T extends CPPObject> CPPTypeInfo<T> getCPPTypeInfo(final Type type) {
861            return (CPPTypeInfo)getTypeInfo(type);
862        }
863    }