import ROOT from type_db import type_db def pyhead_size() : "return the size in bytes of the PyObject_head structure" return 16 def buffer_to_int( buf ): """ void pointers on the c++ side are represented in pyroot as buffers, which have to be converted to python int. This is one (stupid) way to do it """ s = repr(buf) if s == 'nullptr' : return 0 return int(s.split()[3][:-1],0) def get_tclass( objectproxy ): """ Get the TClass belonging to a pyroot object. Attempt to generate it if it does not exist yet. """ name = None if isinstance( objectproxy , ROOT.ObjectProxy ): name = type(objectproxy).__name__ if isinstance( objectproxy , type(ROOT.ObjectProxy) ): # is a class object, liek ROOT.TH1F name = objectproxy.__name__ if not name: raise TypeError("get_tclass called with wrong type") return ROOT.TClass.GetClass( name ) # code below gave lot of trouble and completely fucked up pyroot... # I leave this here as a warning for future generations #ROOT.gInterpreter.GenerateDictionary( type(objectproxy).__name__ ) #tclass = ROOT.gInterpreter.GenerateTClass( type(objectproxy).__name__, True ) # don't do this #return tclass def get_address( tfunction ): """ Return the address of (=pointer to) the c/c++ function that is described by the passed-in TFunction (or TMethod) object """ buf = ROOT.gInterpreter.FindSym( tfunction.GetMangledName() ) addrvoidp = buffer_to_int( buf ) if not addrvoidp : # In some cases, cling is lazy and it does not compile/emit the method # until needed. It seems that the following is a way to trigger # the compilaton. dummy = tfunction.InterfaceMethod() # now try again to get the pointer buf = ROOT.gInterpreter.FindSym( tfunction.GetMangledName() ) addrvoidp = buffer_to_int( buf ) if not addrvoidp : # give up raise LookupError("Could not find the mangled name ", tfunction.GetMangledName(), "corresponding to the function", tfunction, "in the symbol table" ) return addrvoidp #================================================================= # the following mix root and llvm/numba stuff... perhaps # should not be here #================================================================= import llvmlite from llvmlite.llvmpy.core import Type def get_llvm_function_type ( tfunction ) : ''' return the appropriate llvm type for the method ''' if not isinstance( tfunction, ROOT.TFunction ) : raise TypeError def tollvm( typename ): # a pointer is a pointer is a pointer if typename.endswith("*") : # void ptr seems to be forbidden return Type.pointer( Type.int(8) ) r = type_db.get( root_rep = typename ).llvm_type if not r : print ("faileure to convert c++ type ", root_rep ) raise TypeError return r # The tfunction interface is very limited and does not give access # to all the information I would like on the return type.. May # have to get my hands on the fInfo and go through gCling... for now: return_type = tollvm( tfunction.GetReturnTypeNormalizedName() ) if return_type == Type.void() : return_type = Type.int(32) # Iff it is a non-static class method, add a type for the this pointer is_static = tfunction.Property() & ROOT.kIsStatic > 0 if isinstance( tfunction, ROOT.TMethod ) : is_namespace = (tfunction.GetClass().Property() & ROOT.kIsNamespace) else : is_namespace = False if isinstance( tfunction, ROOT.TMethod ) and not is_static and not is_namespace : arg_types = [ Type.pointer(Type.int(8)) ] else : arg_types = [] x = [ tollvm(marg.GetTypeNormalizedName()) for marg in tfunction.GetListOfMethodArgs() ] #print (x) #print ("--->", tfunction, arg_types, list( tfunction.GetListOfMethodArgs() )) #print( tfunction.GetListOfMethodArgs()[0].GetTypeNormalizedName() ) r = Type.function ( return_type , arg_types+x ) #print " *** r = ", r return r def add_function( llvm_module , tfunction , prefix = "aa_"): "bind a tfunction or method to llvm name" # We could compile an extern c wrapper function here, or use # TFuntion::GetInterfaceMethod to use the one provided by root. # # For now, we just get the mangled symbol of the original c++ function # and hope for the best. name = prefix + tfunction.GetName() addrvoidp = get_address( tfunction ) llvmlite.binding.add_symbol( name, addrvoidp ) # fnty by hand for testing (TODO: automate) fnty = get_llvm_function_type( tfunction ) fn = llvm_module.get_or_insert_function(fnty, name=name ) return fn def add_function_code( name, code ) : ROOT.gInterpreter.Declare( code ) function = ROOT.gROOT.GetGlobalFunction( name ) buf = ROOT.gInterpreter.FindSym( function.GetMangledName() ) addrvoidp = buffer_to_int( buf ) binding.add_symbol( name, addrvoidp ) def dump_property( tfunction ): props = """ kIsClass kIsStruct kIsUnion kIsEnum kIsTypedef kIsFundamental kIsAbstract kIsVirtual kIsPureVirtual kIsPublic kIsProtected kIsPrivate kIsPointer kIsArray kIsStatic kIsDefault kIsReference kIsDirectInherit kIsCCompiled kIsCPPCompiled kIsCompiled kIsConstant kIsVirtualBase kIsConstPointer kIsExplicit kIsNamespace kIsConstMethod kIsUsingVariable kIsDefinedInStd """ bits = tfunction.Property() properties = [] for p_ in props.splitlines(): p = p_.strip() if not p : continue properties.append( p ) for p in properties: print "{:20s} {} ".format( p, (bits & getattr( ROOT, p )) > 0 ) if __name__ == '__main__' : m = ROOT.TClass.GetClass("TH1D").GetMethodAllAny("Fill") dump_property( m )