[pypy-commit] pypy reflex-support: far from functional, this is a start for the cling backend

wlav noreply at buildbot.pypy.org
Wed Jan 29 02:10:43 CET 2014


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r68985:8f1d5735b2a5
Date: 2014-01-28 17:09 -0800
http://bitbucket.org/pypy/pypy/changeset/8f1d5735b2a5/

Log:	far from functional, this is a start for the cling backend

diff --git a/pypy/module/cppyy/capi/cling_capi.py b/pypy/module/cppyy/capi/cling_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/cling_capi.py
@@ -0,0 +1,69 @@
+import py, os
+
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.rtyper.lltypesystem import rffi
+from rpython.rlib import libffi, rdynload
+
+__all__ = ['identify', 'std_string_name', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+import commands
+(config_stat, incdir) = commands.getstatusoutput("root-config --incdir")
+
+if os.environ.get("ROOTSYS"):
+    if config_stat != 0:     # presumably Reflex-only
+        rootincpath = [os.path.join(os.environ["ROOTSYS"], "interpreter/cling/include"),
+                       os.path.join(os.environ["ROOTSYS"], "interpreter/llvm/inst/include")]
+        rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+    else:
+        rootincpath = [incdir]
+        rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+    if config_stat == 0:
+        rootincpath = [incdir]
+        rootlibpath = commands.getoutput("root-config --libdir").split()
+    else:
+        rootincpath = []
+        rootlibpath = []
+
+def identify():
+    return 'Cling'
+
+ts_reflect = False
+ts_call    = 'auto'
+ts_memory  = 'auto'
+ts_helper  = 'auto'
+
+std_string_name = 'std::basic_string<char>'
+
+eci = ExternalCompilationInfo(
+    separate_module_files=[srcpath.join("clingcwrapper.cxx")],
+    include_dirs=[incpath] + rootincpath,
+    includes=["clingcwrapper.h"],
+    library_dirs=rootlibpath,
+    libraries=["Cling"],
+    compile_extra=["-fno-strict-aliasing"],
+    use_cpp_linker=True,
+)
+
+_c_load_dictionary = rffi.llexternal(
+    "cppyy_load_dictionary",
+    [rffi.CCHARP], rdynload.DLLHANDLE,
+    releasegil=False,
+    compilation_info=eci)
+
+def c_load_dictionary(name):
+    pch = _c_load_dictionary(name)
+    return pch
+
+
+# Cling-specific pythonizations
+def register_pythonizations(space):
+    "NOT_RPYTHON"
+    pass
+
+def pythonize(space, name, w_pycppclass):
+    pass
diff --git a/pypy/module/cppyy/include/clingcwrapper.h b/pypy/module/cppyy/include/clingcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/clingcwrapper.h
@@ -0,0 +1,37 @@
+#ifndef CPPYY_CLINGCWRAPPER
+#define CPPYY_CLINGCWRAPPER
+
+#include "capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+    /* misc helpers */
+    void* cppyy_load_dictionary(const char* lib_name);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+// TODO: pick up from llvm-config --cxxflags
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+// Wrapper callback: except this to become available from Cling directly
+typedef void (*CPPYY_Cling_Wrapper_t)(void*, int, void**, void*);
+
+#endif // ifndef CPPYY_CLINGCWRAPPER
diff --git a/pypy/module/cppyy/src/clingcwrapper.cxx b/pypy/module/cppyy/src/clingcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/clingcwrapper.cxx
@@ -0,0 +1,1810 @@
+#include "cppyy.h"
+#include "clingcwrapper.h"
+
+/*************************************************************************
+ * Copyright (C) 1995-2014, the ROOT team.                               *
+ * LICENSE: LGPLv2.1; see http://root.cern.ch/drupal/content/license     *
+ * CONTRIBUTORS: see http://root.cern.ch/drupal/content/contributors     *
+ *************************************************************************/
+
+#include <stdint.h>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Type.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Sema/Sema.h"
+
+#include "cling/Interpreter/DynamicLibraryManager.h"
+#include "cling/Interpreter/Interpreter.h"
+#include "cling/Interpreter/LookupHelper.h"
+#include "cling/Interpreter/StoredValueRef.h"
+#include "cling/MetaProcessor/MetaProcessor.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <iostream>
+#include <map>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+using namespace clang;
+
+
+/* cling initialization --------------------------------------------------- */
+namespace {
+
+cling::Interpreter* gCppyy_Cling;
+cling::MetaProcessor* gCppyy_MetaProcessor;
+
+struct Cppyy_InitCling { // TODO: check whether ROOT/meta's TCling is linked in
+    Cppyy_InitCling() {
+        std::vector<std::string> cling_args_storage;
+        cling_args_storage.push_back("cling4cppyy");
+
+        // TODO: get this from env
+        cling_args_storage.push_back("-I/home/wlavrijsen/rootdev/root/etc");
+
+        std::vector<const char*> interp_args;
+        for (std::vector<std::string>::const_iterator iarg = cling_args_storage.begin();
+                iarg != cling_args_storage.end(); ++iarg)
+           interp_args.push_back(iarg->c_str());
+
+        // TODO: get this from env
+        const char* llvm_resource_dir = "/home/wlavrijsen/rootdev/root/etc/cling";
+        gCppyy_Cling = new cling::Interpreter(
+            interp_args.size(), &(interp_args[0]), llvm_resource_dir);
+
+        // fInterpreter->installLazyFunctionCreator(llvmLazyFunctionCreator);
+
+        {
+            // R__LOCKGUARD(gInterpreterMutex);
+            gCppyy_Cling->AddIncludePath("/home/wlavrijsen/rootdev/root/etc/cling");
+            gCppyy_Cling->AddIncludePath(".");
+        }
+
+        // don't check whether modules' files exist.
+        gCppyy_Cling->getCI()->getPreprocessorOpts().DisablePCHValidation = true;
+
+        // Use a stream that doesn't close its file descriptor.
+        static llvm::raw_fd_ostream fMPOuts (STDOUT_FILENO, /* ShouldClose */ false);
+        gCppyy_MetaProcessor = new cling::MetaProcessor(*gCppyy_Cling, fMPOuts);
+
+        gCppyy_Cling->enableDynamicLookup();
+    }
+} _init;
+
+typedef std::map<std::string, cppyy_scope_t> NamedHandles_t;
+static NamedHandles_t s_named;
+
+struct SimpleScope {
+    std::vector<FunctionDecl*> m_methods;
+    std::vector<Decl*> m_data;
+};
+
+typedef std::map<cppyy_scope_t, SimpleScope*> Scopes_t;
+static Scopes_t s_scopes;
+
+typedef std::map<cppyy_method_t, CPPYY_Cling_Wrapper_t> Wrappers_t;
+static Wrappers_t s_wrappers;
+
+} // unnamed namespace
+
+
+/* local helpers --------------------------------------------------------- */
+static inline void print_error(const std::string& where, const std::string& what) {
+    std::cerr << where << ": " << what << std::endl;
+}
+
+static inline char* cppstring_to_cstring(const std::string& name) {
+    char* name_char = (char*)malloc(name.size() + 1);
+    strcpy(name_char, name.c_str());
+    return name_char;
+}
+
+static inline SimpleScope* scope_from_handle(cppyy_type_t handle) {
+    return s_scopes[(cppyy_scope_t)handle];
+}
+
+static inline std::string qualtype_to_string(const QualType& qt, const ASTContext& atx) {
+    std::string result;
+
+    PrintingPolicy policy(atx.getPrintingPolicy());
+    policy.SuppressTagKeyword = true;        // no class or struct keyword
+    policy.SuppressScope = true;             // force scope from a clang::ElaboratedType
+    policy.AnonymousTagLocations = false;    // no file name + line number for anonymous types
+        // The scope suppression is required for getting rid of the anonymous part of the name
+        // of a class defined in an anonymous namespace.
+    
+    qt.getAsStringInternal(result, policy);
+    return result;
+}
+
+static inline std::vector<void*> build_args(int nargs, void* args) {
+    std::vector<void*> arguments;
+    arguments.reserve(nargs);
+    for (int i = 0; i < nargs; ++i) {
+	char tc = ((CPPYY_G__value*)args)[i].type;
+        if (tc != 'a' && tc != 'o')
+            arguments.push_back(&((CPPYY_G__value*)args)[i]);
+        else
+            arguments.push_back((void*)(*(long*)&((CPPYY_G__value*)args)[i]));
+    }
+    return arguments;
+}
+
+
+/* name to opaque C++ scope representation -------------------------------- */
+int cppyy_num_scopes(cppyy_scope_t handle) {
+    return 0;
+}
+
+char* cppyy_resolve_name(const char* cppitem_name) {
+    std::cout << " RESOLVING: " << cppitem_name << std::endl;
+    return cppstring_to_cstring(cppitem_name);
+}
+
+cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+    const cling::LookupHelper& lh = gCppyy_Cling->getLookupHelper();
+    const Type* type = 0;
+    const Decl* decl = lh.findScope(scope_name, &type, /* intantiateTemplate= */ true);
+    if (!decl) {
+        //std::string buf = TClassEdit::InsertStd(name);
+        //decl = lh.findScope(buf, &type, /* intantiateTemplate= */ true);
+    }
+    if (!decl && type) {
+        const TagType* tagtype = type->getAs<TagType>();
+        if (tagtype) {
+            decl = tagtype->getDecl();
+        }
+    }
+
+    std::cout << "FOR: " << scope_name << " RECEIVED: " << type << " AND: " << decl << std::endl;
+    if (decl) {
+        DeclContext* dc = llvm::cast<DeclContext>(const_cast<Decl*>(decl));
+        SimpleScope* s = new SimpleScope;
+        for (DeclContext::decl_iterator idecl = dc->decls_begin(); *idecl; ++idecl) {
+            if (FunctionDecl* m = llvm::dyn_cast_or_null<FunctionDecl>(*idecl))
+                s->m_methods.push_back(m);
+            else if (FieldDecl* d = llvm::dyn_cast_or_null<FieldDecl>(*idecl))
+                s->m_data.push_back(d);
+        }
+        s_scopes[(cppyy_scope_t)decl] = s;
+    }
+
+    return (cppyy_scope_t)decl;    // lookup failure return 0 (== error)
+}
+
+
+/* method/function dispatching -------------------------------------------- */
+
+// TODO: expect the below to live in libCling.so
+static CPPYY_Cling_Wrapper_t make_wrapper(const FunctionDecl* fdecl);
+static void exec_with_valref_return(void* address, cling::StoredValueRef* ret, const FunctionDecl*);
+static long long sv_to_long_long(const cling::StoredValueRef& svref);
+// -- TODO: expect the above to live in libCling.so
+
+
+template<typename T>
+static inline T cppyy_call_T(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    if (s_wrappers.find(method) == s_wrappers.end()) {
+        make_wrapper((FunctionDecl*)method);
+    }
+    cling::StoredValueRef ret;
+    //    std::vector<void*> arguments = build_args(nargs, args);
+    //    CPPYY_Cling_Wrapper_t cb = (CPPYY_Cling_Wrapper_t)method;
+    exec_with_valref_return((void*)self, &ret, (FunctionDecl*)method);
+    //    (*cb)((void*)self, nargs, const_cast<void**>(arguments.data()), ret);
+    return static_cast<T>(sv_to_long_long(ret));
+}
+
+
+
+int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return cppyy_call_T<int>(method, self, nargs, args);
+}
+
+
+
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
+    return (cppyy_methptrgetter_t)0;
+}
+
+
+/* handling of function argument buffer ----------------------------------- */
+void* cppyy_allocate_function_args(size_t nargs) {
+    CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value));
+    for (size_t i = 0; i < nargs; ++i)
+        args[i].type = 'l';
+    return (void*)args;
+}
+
+void cppyy_deallocate_function_args(void* args) {
+    free(args);
+}
+
+size_t cppyy_function_arg_sizeof() {
+    return sizeof(CPPYY_G__value);
+}
+
+size_t cppyy_function_arg_typeoffset() {
+    return offsetof(CPPYY_G__value, type);
+}
+
+
+/* scope reflection information ------------------------------------------- */
+int cppyy_is_namespace(cppyy_scope_t /* handle */) {
+    return 0;
+}   
+
+int cppyy_is_enum(const char* /* type_name */) {
+    return 0;
+}
+    
+    
+/* class reflection information ------------------------------------------- */
+char* cppyy_final_name(cppyy_type_t handle) {
+    for (NamedHandles_t::iterator isp = s_named.begin(); isp != s_named.end(); ++isp) {
+        if (isp->second == (cppyy_scope_t)handle)
+            return cppstring_to_cstring(isp->first);
+    }
+    return cppstring_to_cstring("<unknown>");
+}
+
+char* cppyy_scoped_final_name(cppyy_type_t handle) {
+    return cppyy_final_name(handle);
+}   
+
+int cppyy_has_complex_hierarchy(cppyy_type_t /* handle */) {
+    return 1;
+}
+
+
+/* method/function reflection information --------------------------------- */
+int cppyy_num_methods(cppyy_scope_t handle) {
+    SimpleScope* s = scope_from_handle(handle);
+    if (!s) return 0;
+    return s->m_methods.size();
+}
+
+cppyy_index_t cppyy_method_index_at(cppyy_scope_t /* scope */, int imeth) {
+    return (cppyy_index_t)imeth;
+}
+
+char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t method_index) {
+    SimpleScope* s = scope_from_handle(handle);
+    if (!s) return cppstring_to_cstring("<unknown>");
+    FunctionDecl* meth = s->m_methods.at(method_index);
+    std::cout << " METHOD NAME: " << meth->getDeclName().getAsString() << std::endl;
+    return cppstring_to_cstring(meth->getDeclName().getAsString());
+}
+
+char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t method_index) {
+    SimpleScope* s = scope_from_handle(handle);
+    if (!s) return cppstring_to_cstring("<unknown>");
+    FunctionDecl* meth = s->m_methods.at(method_index);
+    const std::string& ret_type =
+        qualtype_to_string(meth->getCallResultType(), meth->getASTContext());
+    std::cout << "    -> RET TYPE: " << ret_type << std::endl;
+    return cppstring_to_cstring(ret_type);
+}
+    
+int cppyy_method_num_args(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) {
+    return 1;
+}
+
+int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t method_index) {
+    return cppyy_method_num_args(handle, method_index);
+}
+
+char* cppyy_method_arg_type(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /* arg_index */) {
+    return cppstring_to_cstring("double");
+}
+
+char* cppyy_method_arg_default(cppyy_scope_t handle, cppyy_index_t method_index, int arg_index) {
+    return cppstring_to_cstring("");
+}
+
+char* cppyy_method_signature(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) {
+    return cppstring_to_cstring("double");
+}
+
+int cppyy_method_is_template(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) {
+    return 0;
+}
+    
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t method_index) {
+    SimpleScope* s = scope_from_handle(handle);
+    if (!s) return (cppyy_method_t)0;
+    return (cppyy_method_t)s->m_methods.at(method_index);
+}
+
+
+/* method properties -----------------------------------------------------  */
+int cppyy_is_constructor(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
+    return 0;
+}
+
+int cppyy_is_staticmethod(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
+    return 1;
+}
+
+
+/* data member reflection information ------------------------------------- */
+int cppyy_num_datamembers(cppyy_scope_t /* handle */) {
+    return 0;
+}
+
+
+/* misc helpers ----------------------------------------------------------- */
+void cppyy_free(void* ptr) {
+    free(ptr);
+}
+
+
+void* cppyy_load_dictionary(const char* lib_name) {
+    // TODO: need to rethink this; for now it creates reflection info from
+    //       <lib_name>.h while loading lib<lib_name>.so
+
+    // Load a library file in cling's memory.
+    // if 'system' is true, the library is never unloaded.
+    // Return 0 on success, -1 on failure.
+    // R__LOCKGUARD2(gInterpreterMutex);
+    std::cout << " NOW LOADING: " << lib_name << std::endl;
+
+    cling::StoredValueRef call_res;
+    cling::Interpreter::CompilationResult comp_res = cling::Interpreter::kSuccess;
+    std::ostringstream line;
+    line << "#include \"" << lib_name << ".h\"";
+    gCppyy_MetaProcessor->process(line.str().c_str(), comp_res, &call_res);
+
+    std::string to_load = "lib";
+    to_load += lib_name;
+    to_load += ".so";
+    cling::DynamicLibraryManager::LoadLibResult res
+        = gCppyy_Cling->getDynamicLibraryManager()->loadLibrary(to_load, /* not unload */ true);
+    // if (res == cling::DynamicLibraryManager::kLoadLibSuccess) {
+    //     UpdateListOfLoadedSharedLibraries();
+    // }
+    switch (res) {
+    case cling::DynamicLibraryManager::kLoadLibSuccess: return (void*)1;
+    case cling::DynamicLibraryManager::kLoadLibExists:  return (void*)2;
+    default: break;
+    };
+    return (void*)1;
+}
+
+
+/* to-be libCling code taken from ROOT/meta ------------------------------- */
+
+// TODO: expect the below to live in libCling.so
+
+template <typename T>
+T sv_to_long_long_u_or_not(const cling::StoredValueRef& svref) {
+    const cling::Value& valref = svref.get();
+    QualType QT = valref.getClangType();
+    if (QT.isNull()) {
+        print_error("sv_to_long_long_u_or_not", "null type!");
+        return 0;
+    }
+    llvm::GenericValue gv = valref.getGV();
+    if (QT->isMemberPointerType()) {
+        const MemberPointerType* MPT =
+            QT->getAs<MemberPointerType>();
+        if (MPT->isMemberDataPointer()) {
+            return (T) (ptrdiff_t) gv.PointerVal;
+        }
+        return (T) gv.PointerVal;
+    }
+    if (QT->isPointerType() || QT->isArrayType() || QT->isRecordType() ||
+        QT->isReferenceType()) {
+        return (T) gv.PointerVal;
+    }
+    if (const EnumType* ET = llvm::dyn_cast<EnumType>(&*QT)) {
+        if (ET->getDecl()->getIntegerType()->hasSignedIntegerRepresentation())
+            return (T) gv.IntVal.getSExtValue();
+        else
+            return (T) gv.IntVal.getZExtValue();
+    }
+    if (const BuiltinType* BT = llvm::dyn_cast<BuiltinType>(&*QT)) {
+      if (BT->isSignedInteger()) {
+          return gv.IntVal.getSExtValue();
+      } else if (BT->isUnsignedInteger()) {
+          return (T) gv.IntVal.getZExtValue();
+      } else {
+          switch (BT->getKind()) {
+          case BuiltinType::Float:
+              return (T) gv.FloatVal;
+          case BuiltinType::Double:
+              return (T) gv.DoubleVal;
+          case BuiltinType::LongDouble:
+              // FIXME: Implement this!
+              break;
+          case BuiltinType::NullPtr:
+              // C++11 nullptr
+              return 0;
+          default: break;
+          }
+      }
+    }
+    print_error("sv_to_long_long_u_or_not", "cannot handle this type!");
+    QT->dump();
+    return 0;
+}
+
+static long long sv_to_long_long(const cling::StoredValueRef& svref) {
+    return sv_to_long_long_u_or_not<long long>(svref);
+}
+
+static
+unsigned long long sv_to_ulong_long(const cling::StoredValueRef& svref) {
+   return sv_to_long_long_u_or_not<unsigned long long>(svref);
+}
+
+
+namespace {
+
+class ValHolder {
+public:
+   union {
+      long double ldbl;
+      double dbl;
+      float flt;
+      //__uint128_t ui128;
+      //__int128_t i128;
+      unsigned long long ull;
+      long long ll;
+      unsigned long ul;
+      long l;
+      unsigned int ui;
+      int i;
+      unsigned short us;
+      short s;
+      //char32_t c32;
+      //char16_t c16;
+      //unsigned wchar_t uwc; - non-standard
+      wchar_t wc;
+      unsigned char uc;
+      signed char sc;
+      char c;
+      bool b;
+      void* vp;
+   } u;
+};
+
+} // unnamed namespace
+
+static void exec(void* address, void* ret, const FunctionDecl* fdecl) {
+    std::vector<ValHolder> vh_ary;
+    std::vector<void*> vp_ary;
+
+    //
+    //  Convert the arguments from cling::StoredValueRef to their
+    //  actual type and store them in a holder for passing to the
+    //  wrapper function by pointer to value.
+    //
+    unsigned num_params = fdecl->getNumParams();
+    /*    unsigned num_args = fArgVals.size();
+
+    if (num_args < fdecl->getMinRequiredArguments ()) {
+        Error("TClingCallFunc::exec",
+              "Not enough arguments provided for %s (%d instead of the minimum %d)",
+              fMethod->Name(ROOT::TMetaUtils::TNormalizedCtxt(fInterp->getLookupHelper())),
+              num_args,fdecl->getMinRequiredArguments ());
+        return;
+    }
+    if (address == 0 && llvm::dyn_cast<CXXMethodDecl>(fdecl)
+        && !(llvm::dyn_cast<CXXMethodDecl>(fdecl))->isStatic()
+        && !llvm::dyn_cast<CXXConstructorDecl>(fdecl)) {
+        Error("TClingCallFunc::exec",
+              "The method %s is called without an object.",
+              fMethod->Name(ROOT::TMetaUtils::TNormalizedCtxt(fInterp->getLookupHelper())));
+        return;
+    }
+    vh_ary.reserve(num_args);
+    vp_ary.reserve(num_args);
+    for (unsigned i = 0U; i < num_args; ++i) {
+        QualType Ty;
+        if (i < num_params) {
+            const ParmVarDecl* PVD = fdecl->getParamDecl(i);
+            Ty = PVD->getType();
+        }
+        else {
+            Ty = fArgVals[i].get().getClangType();
+        }
+        QualType QT = Ty.getCanonicalType();
+        if (QT->isReferenceType()) {
+            ValHolder vh;
+            vh.u.vp = (void*) sv_to_ulong_long(fArgVals[i]);
+            vh_ary.push_back(vh);
+            vp_ary.push_back(&vh_ary.back());
+        }
+        else if (QT->isMemberPointerType()) {
+            ValHolder vh;
+            vh.u.vp = (void*) sv_to_ulong_long(fArgVals[i]);
+            vh_ary.push_back(vh);
+            vp_ary.push_back(&vh_ary.back());
+        }
+        else if (QT->isPointerType() || QT->isArrayType()) {
+            ValHolder vh;
+            vh.u.vp = (void*) sv_to_ulong_long(fArgVals[i]);
+            vh_ary.push_back(vh);
+            vp_ary.push_back(&vh_ary.back());
+        }
+        else if (QT->isRecordType()) {
+            ValHolder vh;
+            vh.u.vp = (void*) sv_to_ulong_long(fArgVals[i]);
+            vh_ary.push_back(vh);
+            vp_ary.push_back(&vh_ary.back());
+        }
+        else if (const EnumType* ET = llvm::dyn_cast<EnumType>(&*QT)) {
+            // Note: We may need to worry about the underlying type
+            //       of the enum here.
+            (void) ET;
+            ValHolder vh;
+            vh.u.i = (int) sv_to_long_long(fArgVals[i]);
+            vh_ary.push_back(vh);
+            vp_ary.push_back(&vh_ary.back());
+        }
+        else if (const BuiltinType* BT = llvm::dyn_cast<BuiltinType>(&*QT)) {
+            //
+            //  WARNING!!!
+            //
+            //  This switch is organized in order-of-declaration
+            //  so that the produced assembly code is optimal.
+            //  Do not reorder!
+            //
+            switch (BT->getKind()) {
+            //
+            //  Builtin Types
+            //
+            case BuiltinType::Void: {
+                // void
+                print_error("exec", "invalid argument type (void)");
+                return;
+            }
+            //
+            //  Unsigned Types
+            //
+            case BuiltinType::Bool: {
+                // bool
+                ValHolder vh;
+                vh.u.b = (bool) sv_to_ulong_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::Char_U: {
+                // char on targets where it is unsigned
+                ValHolder vh;
+                vh.u.c = (char) sv_to_ulong_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::UChar: {
+                // unsigned char
+                ValHolder vh;
+                vh.u.uc = (unsigned char) sv_to_ulong_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break; 
+            }
+            case BuiltinType::WChar_U: {
+                // wchar_t on targets where it is unsigned.
+                // The standard doesn't allow to specify signednedd of wchar_t
+                // thus this maps simply to wchar_t.
+                ValHolder vh;
+                vh.u.wc = (wchar_t) sv_to_ulong_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::Char16:
+            case BuiltinType::Char32: {
+                print_error("exec", "unsupported argument");
+                QT->dump();
+                return;
+            }
+            case BuiltinType::UShort: {
+                // unsigned short
+                ValHolder vh;
+                vh.u.us = (unsigned short) sv_to_ulong_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::UInt: {
+                // unsigned int
+                ValHolder vh;
+                vh.u.ui = (unsigned int) sv_to_ulong_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::ULong: {
+                // unsigned long
+                ValHolder vh;
+                vh.u.ul = (unsigned long) sv_to_ulong_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::ULongLong: {
+                // unsigned long long
+                ValHolder vh;
+                vh.u.ull = (unsigned long long) sv_to_ulong_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::UInt128: {
+                print_error("exec", "unsupported argument");
+                QT->dump();
+                return;
+            }
+            //
+            //  Signed Types
+            //
+            case BuiltinType::Char_S: {
+                // char on targets where it is signed
+                ValHolder vh;
+                vh.u.c = (char) sv_to_long_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::SChar: {
+                // signed char
+                ValHolder vh;
+                vh.u.sc = (signed char) sv_to_long_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::WChar_S: {
+                // wchar_t on targets where it is signed.
+                // The standard doesn't allow to specify signednedd of wchar_t
+                // thus this maps simply to wchar_t.
+                ValHolder vh;
+                vh.u.wc = (wchar_t) sv_to_long_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::Short: {
+                // short
+                ValHolder vh;
+                vh.u.s = (short) sv_to_long_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::Int: {
+                // int
+                ValHolder vh;
+                vh.u.i = (int) sv_to_long_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::Long: {
+                // long
+                ValHolder vh;
+                vh.u.l = (long) sv_to_long_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::LongLong: {
+                // long long
+                ValHolder vh;
+                vh.u.ll = (long long) sv_to_long_long(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::Int128:
+            case BuiltinType::Half: {
+                // half in OpenCL, __fp16 in ARM NEON
+                print_error("exec", "unsupported argument");
+                QT->dump();
+                return;
+            }
+            case BuiltinType::Float: {
+                // float
+                ValHolder vh;
+                vh.u.flt = sv_to<float>(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::Double: {
+                // double
+                ValHolder vh;
+                vh.u.dbl = sv_to<double>(fArgVals[i]);
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            case BuiltinType::LongDouble: {
+                // long double
+                print_error("exec", "unsupported argument");
+                QT->dump();
+                return;
+            }
+            //
+            //  Language-Specific Types
+            //
+            case BuiltinType::NullPtr: {
+                // C++11 nullptr
+                ValHolder vh;
+                vh.u.vp = (void*) fArgVals[i].get().getGV().PointerVal;
+                vh_ary.push_back(vh);
+                vp_ary.push_back(&vh_ary.back());
+                break;
+            }
+            default: {
+                print_error("exec", "unsupported argument");
+                QT->dump();
+                return;
+            }
+         }
+      }
+      else {
+          print_error("exec", "invalid type (unrecognized)!");
+          QT->dump();
+          return;
+      }
+      }*/
+
+    CPPYY_Cling_Wrapper_t wrapper = s_wrappers[(cppyy_method_t)fdecl];
+    (*wrapper)(address, (int)0/*num_args*/, (void**)vp_ary.data(), ret);
+}
+
+
+static void exec_with_valref_return(void* address, cling::StoredValueRef* ret, const FunctionDecl* fdecl) {
+    if (!ret) {
+        exec(address, 0, fdecl);
+        return;
+    }
+    std::cout << " USING DECL: " << fdecl << std::endl;
+    fdecl->dump();
+    ASTContext& Context = fdecl->getASTContext();
+
+    if (const CXXConstructorDecl* CD = llvm::dyn_cast<CXXConstructorDecl>(fdecl)) {
+        const TypeDecl* TD = llvm::dyn_cast<TypeDecl>(CD->getDeclContext());
+        QualType ClassTy(TD->getTypeForDecl(), 0);
+        QualType QT = Context.getLValueReferenceType(ClassTy);
+        llvm::GenericValue gv;
+        exec(address, &gv.PointerVal, fdecl);
+        *ret = cling::StoredValueRef::bitwiseCopy(
+            *gCppyy_Cling, cling::Value(gv, QT));
+        return;
+    }
+    QualType QT = fdecl->getResultType().getCanonicalType();
+    if (QT->isReferenceType()) {
+        llvm::GenericValue gv;
+        exec(address, &gv.PointerVal, fdecl);
+        *ret = cling::StoredValueRef::bitwiseCopy(
+            *gCppyy_Cling, cling::Value(gv, QT));
+        return;
+    }
+    else if (QT->isMemberPointerType()) {
+        const MemberPointerType* MPT =
+            QT->getAs<MemberPointerType>();
+        if (MPT->isMemberDataPointer()) {
+            // A member data pointer is a actually a struct with one
+            // member of ptrdiff_t, the offset from the base of the object
+            // storage to the storage for the designated data member.
+            llvm::GenericValue gv;
+            exec(address, &gv.PointerVal, fdecl);
+            *ret = cling::StoredValueRef::bitwiseCopy(
+                *gCppyy_Cling, cling::Value(gv, QT));
+            return;
+        }
+        // We are a function member pointer.
+        llvm::GenericValue gv;
+        exec(address, &gv.PointerVal, fdecl);
+        *ret = cling::StoredValueRef::bitwiseCopy(
+            *gCppyy_Cling, cling::Value(gv, QT));
+        return;
+    }
+    else if (QT->isPointerType() || QT->isArrayType()) {
+        // Note: ArrayType is an illegal function return value type.
+        llvm::GenericValue gv;
+        exec(address, &gv.PointerVal, fdecl);
+        *ret = cling::StoredValueRef::bitwiseCopy(
+            *gCppyy_Cling, cling::Value(gv, QT));
+        return;
+    }
+    else if (QT->isRecordType()) {
+        uint64_t size = Context.getTypeSizeInChars(QT).getQuantity();
+        void* p = ::operator new(size);
+        exec(address, p, fdecl);
+        *ret = cling::StoredValueRef::bitwiseCopy(
+            *gCppyy_Cling, cling::Value(llvm::PTOGV(p), QT));
+        return;
+    }
+    else if (const EnumType* ET = llvm::dyn_cast<EnumType>(&*QT)) {
+        // Note: We may need to worry about the underlying type
+        //       of the enum here.
+        (void) ET;
+        uint64_t numBits = Context.getTypeSize(QT);
+        int retVal = 0;
+        exec(address, &retVal, fdecl);
+        llvm::GenericValue gv;
+        gv.IntVal = llvm::APInt(numBits, (uint64_t)retVal, true /*isSigned*/);
+        *ret =  cling::StoredValueRef::bitwiseCopy(
+            *gCppyy_Cling, cling::Value(gv, QT));
+        return;
+    }
+    else if (const BuiltinType* BT = llvm::dyn_cast<BuiltinType>(&*QT)) {
+        llvm::GenericValue gv;
+
+        uint64_t numBits = Context.getTypeSize(QT);
+        switch (BT->getKind()) {
+        //
+        //  builtin types
+        //
+        case BuiltinType::Void: {
+            exec(address, 0, fdecl);
+            return;
+        }
+        //
+        //  unsigned integral types
+        //
+        case BuiltinType::Bool: {
+            bool retVal = false;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t)retVal, false /*isSigned*/);
+            break;
+        }
+        case BuiltinType::Char_U: {
+            // char on targets where it is unsigned
+            char retVal = '\0';
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
+            break;
+        }
+        case BuiltinType::UChar: {
+            unsigned char retVal = '\0';
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
+            break;
+        }
+        case BuiltinType::WChar_U: {
+            // wchar_t on targets where it is unsigned.
+            // The standard doesn't allow to specify signedness of wchar_t
+            // thus this maps simply to wchar_t.
+            wchar_t retVal = L'\0';
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
+            break;
+        }
+        case BuiltinType::UShort: {
+            unsigned short retVal = 0;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
+            break;
+        }
+        case BuiltinType::UInt: {
+            unsigned int retVal = 0;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
+            break;
+        }
+        case BuiltinType::ULong: {
+            // unsigned long
+            unsigned long retVal = 0;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
+            break;
+        }
+        case BuiltinType::ULongLong: {
+            // unsigned long long
+            unsigned long long retVal = 0;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
+            break;
+        }
+        //
+        //  signed integral types
+        //
+        case BuiltinType::Char_S: {
+            // char on targets where it is signed
+            char retVal = '\0';
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
+            break;
+        }
+        case BuiltinType::SChar: {
+            // signed char
+            signed char retVal = '\0';
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
+            break;
+        }
+        case BuiltinType::WChar_S: {
+            // wchar_t on targets where it is signed.
+            // The standard doesn't allow to specify signednedd of wchar_t
+            // thus this maps simply to wchar_t.
+            wchar_t retVal = L'\0';
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
+            break;
+        }
+        case BuiltinType::Short: {
+            // short
+            short retVal = 0;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
+            break;
+        }
+        case BuiltinType::Int: {
+            // int
+            int retVal = 0;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
+            break;
+        }
+        case BuiltinType::Long: {
+            long retVal = 0;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
+            break;
+        }
+        case BuiltinType::LongLong: {
+            long long retVal = 0;
+            exec(address, &retVal, fdecl);
+            gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
+            break;
+        }
+        case BuiltinType::Float: {
+            exec(address, &gv.FloatVal, fdecl);
+            break;
+        }
+        case BuiltinType::Double: {
+            exec(address, &gv.DoubleVal, fdecl);
+            break;
+        }
+        case BuiltinType::Char16:
+        case BuiltinType::Char32:
+        case BuiltinType::Half:
+        case BuiltinType::Int128:
+        case BuiltinType::UInt128:
+        case BuiltinType::LongDouble: 
+        case BuiltinType::NullPtr:
+        default: {
+            print_error("exec_with_valref", "unsupported return type");
+            return;
+        }
+        }
+
+        *ret = cling::StoredValueRef::bitwiseCopy(*gCppyy_Cling, cling::Value(gv, QT));
+        return;
+    }
+
+    std::cout << "exec_with_valref: some error occurred ... " << std::endl;
+}
+
+
+static const std::string indent_string("   ");
+static unsigned long long wrapper_serial = 0LL;
+
+void collect_type_info(QualType& QT, std::ostringstream& typedefbuf,
+        std::ostringstream& callbuf, std::string& type_name, bool& isReference,
+        int& ptrCnt, int indent_level, bool forArgument, const FunctionDecl* fdecl) {
+    //
+    //  Collect information about type type of a function parameter
+    //  needed for building the wrapper function.
+    //
+    PrintingPolicy Policy(fdecl->getASTContext().getPrintingPolicy());
+    isReference = false;
+    ptrCnt = 0;
+    if (QT->isRecordType() && forArgument) {
+        // Note: We treat object of class type as if it were a reference
+        //       type because we hold it by pointer.
+        isReference = true;
+        QT.getAsStringInternal(type_name, Policy);
+        // And drop the default arguments if any (at least until the clang
+        // type printer properly handle template paratemeter that are enumerator).
+        //R__DropDefaultArg(type_name);
+        return;
+    }
+    while (1) {
+        if (QT->isArrayType()) {
+            ++ptrCnt;
+            QT = cast<clang::ArrayType>(QT)->getElementType();
+            continue;
+        }
+        else if (QT->isFunctionPointerType()) {
+            std::string fp_typedef_name;
+            {
+                std::ostringstream nm;
+                nm << "FP" << wrapper_serial++;
+                type_name = nm.str();
+                llvm::raw_string_ostream OS(fp_typedef_name);
+                QT.print(OS, Policy, type_name);
+                OS.flush();
+            }
+            for (int i = 0; i < indent_level; ++i) {
+                typedefbuf << indent_string;
+            }
+            typedefbuf << "typedef " << fp_typedef_name << ";\n";
+            break;
+        }
+        else if (QT->isMemberPointerType()) {
+            std::string mp_typedef_name;
+            {
+                std::ostringstream nm;
+                nm << "MP" << wrapper_serial++;
+                type_name = nm.str();
+                llvm::raw_string_ostream OS(mp_typedef_name);
+                QT.print(OS, Policy, type_name);
+                OS.flush();
+            }
+            for (int i = 0; i < indent_level; ++i) {
+                typedefbuf << indent_string;
+            }
+            typedefbuf << "typedef " << mp_typedef_name << ";\n";
+            break;
+        }
+        else if (QT->isPointerType()) {
+            ++ptrCnt;
+            QT = cast<clang::PointerType>(QT)->getPointeeType();
+            continue;
+        }
+        else if (QT->isReferenceType()) {
+            isReference = true;
+            QT = cast<ReferenceType>(QT)->getPointeeType();
+            continue;
+        }
+        QT.getAsStringInternal(type_name, Policy);
+        break;
+    }
+    // And drop the default arguments if any (at least until the clang
+    // type printer properly handle template paratemeter that are enumerator).
+    // R__DropDefaultArg(type_name);
+}
+
+void make_narg_ctor(const unsigned N, std::ostringstream& typedefbuf,
+         std::ostringstream& callbuf, const std::string& class_name,
+         int indent_level, const FunctionDecl* fdecl) {
+    // Make a code string that follows this pattern:
+    //
+    // new ClassName(args...)
+    //
+    callbuf << "new " << class_name << "(";
+    for (unsigned i = 0U; i < N; ++i) {
+        const ParmVarDecl* PVD = fdecl->getParamDecl(i);
+        QualType Ty = PVD->getType();
+        QualType QT = Ty.getCanonicalType();
+        std::string type_name;
+        bool isReference = false;
+        int ptrCnt = 0;
+        collect_type_info(QT, typedefbuf, callbuf, type_name,
+                          isReference, ptrCnt, indent_level, true, fdecl);
+        if (i) {
+            callbuf << ',';
+            if (i % 2) {
+                callbuf << ' ';
+            }
+            else {
+                callbuf << "\n";
+                for (int j = 0; j <= indent_level; ++j) {
+                    callbuf << indent_string;
+                }
+            }
+        }
+        if (isReference) {
+            std::string stars;
+            for (int j = 0; j < ptrCnt; ++j) {
+                stars.push_back('*');
+            }
+            callbuf << "**(" << type_name.c_str() << stars << "**)args["
+                    << i << "]";
+        }
+        else if (ptrCnt) {
+            std::string stars;
+            for (int j = 0; j < ptrCnt; ++j) {
+                stars.push_back('*');
+            }
+            callbuf << "*(" << type_name.c_str() << stars << "*)args["
+                    << i << "]";
+        }
+        else {
+            callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
+        }
+    }
+    callbuf << ")";
+}
+
+void make_narg_call(const unsigned N, std::ostringstream& typedefbuf,
+        std::ostringstream& callbuf, const std::string& class_name,int indent_level, const FunctionDecl* fdecl) {
+    //
+    // Make a code string that follows this pattern:
+    //
+    // ((<class>*)obj)-><method>(*(<arg-i-type>*)args[i], ...)
+    //
+    if (const CXXMethodDecl* MD = llvm::dyn_cast<CXXMethodDecl>(fdecl)) {
+        // This is a class, struct, or union member.
+        if (MD->isConst())
+            callbuf << "((const " << class_name << "*)obj)->";
+        else
+            callbuf << "((" << class_name << "*)obj)->";
+    }
+    else if (const NamedDecl* ND = llvm::dyn_cast<NamedDecl>(fdecl->getDeclContext())) {
+        // This is a namespace member.
+        (void) ND;
+        callbuf << class_name << "::";
+    }
+    //   callbuf << fMethod->Name() << "(";
+    {
+        std::string name;
+        {
+            llvm::raw_string_ostream stream(name);
+            fdecl->getNameForDiagnostic(stream, fdecl->getASTContext().getPrintingPolicy(), /*Qualified=*/false);
+        }
+        callbuf << name << "(";
+    }
+    for (unsigned i = 0U; i < N; ++i) {
+        const ParmVarDecl* PVD = fdecl->getParamDecl(i);
+        QualType Ty = PVD->getType();
+        QualType QT = Ty.getCanonicalType();
+        std::string type_name;
+        bool isReference = false;
+        int ptrCnt = 0;
+        collect_type_info(QT, typedefbuf, callbuf, type_name,
+                          isReference, ptrCnt, indent_level, true, fdecl);
+        if (i) {
+            callbuf << ',';
+            if (i % 2) {
+                callbuf << ' ';
+            }
+            else {
+                callbuf << "\n";
+                for (int j = 0; j <= indent_level; ++j) {
+                    callbuf << indent_string;
+                }
+            }
+        }
+        if (isReference) {
+            std::string stars;
+            for (int j = 0; j < ptrCnt; ++j) {
+                stars.push_back('*');
+            }
+            callbuf << "**(" << type_name.c_str() << stars << "**)args["
+                    << i << "]";
+        }
+        else if (ptrCnt) {
+            std::string stars;
+            for (int j = 0; j < ptrCnt; ++j) {
+                stars.push_back('*');
+            }
+            callbuf << "*(" << type_name.c_str() << stars << "*)args["
+                    << i << "]";
+        }
+        else {
+            callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
+        }
+    }
+    callbuf << ")";
+}
+
+void make_narg_ctor_with_return(const unsigned N, const std::string& class_name,
+        std::ostringstream& buf, int indent_level, const FunctionDecl* fdecl) {
+    // Make a code string that follows this pattern:
+    //
+    // if (ret) {
+    //    (*(ClassName**)ret) = new ClassName(args...);
+    // }
+    // else {
+    //    new ClassName(args...);
+    // }
+    //
+    for (int i = 0; i < indent_level; ++i) {
+        buf << indent_string;
+    }
+    buf << "if (ret) {\n";
+    ++indent_level;
+    {
+        std::ostringstream typedefbuf;
+        std::ostringstream callbuf;
+        //
+        //  Write the return value assignment part.
+        //
+        for (int i = 0; i < indent_level; ++i) {
+            callbuf << indent_string;
+        }
+        callbuf << "(*(" << class_name << "**)ret) = ";
+        //
+        //  Write the actual new expression.
+        //
+        make_narg_ctor(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
+        //
+        //  End the new expression statement.
+        //
+        callbuf << ";\n";
+        for (int i = 0; i < indent_level; ++i) {
+            callbuf << indent_string;
+        }
+        callbuf << "return;\n";
+        //
+        //  Output the whole new expression and return statement.
+        //
+        buf << typedefbuf.str() << callbuf.str();
+    }
+    --indent_level;
+    for (int i = 0; i < indent_level; ++i) {
+        buf << indent_string;
+    }
+    buf << "}\n";
+   for (int i = 0; i < indent_level; ++i) {
+      buf << indent_string;
+   }
+   buf << "else {\n";
+   ++indent_level;
+   {
+       std::ostringstream typedefbuf;
+       std::ostringstream callbuf;
+       for (int i = 0; i < indent_level; ++i) {
+           callbuf << indent_string;
+       }
+       make_narg_ctor(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
+       callbuf << ";\n";
+       for (int i = 0; i < indent_level; ++i) {
+           callbuf << indent_string;
+       }
+       callbuf << "return;\n";
+       buf << typedefbuf.str() << callbuf.str();
+   }
+   --indent_level;
+   for (int i = 0; i < indent_level; ++i) {
+       buf << indent_string;
+   }
+   buf << "}\n";
+}
+
+void make_narg_call_with_return(const unsigned N, const std::string& class_name,
+        std::ostringstream& buf, int indent_level, const FunctionDecl* fdecl) {
+    // Make a code string that follows this pattern:
+    //
+    // if (ret) {
+    //    new (ret) (return_type) ((class_name*)obj)->func(args...);
+    // }
+    // else {
+    //    ((class_name*)obj)->func(args...);
+    // }
+    //
+    if (const CXXConstructorDecl* CD = dyn_cast<CXXConstructorDecl>(fdecl)) {
+        (void) CD;
+        make_narg_ctor_with_return(N, class_name, buf, indent_level, fdecl);
+        return;
+    }
+    QualType QT = fdecl->getResultType().getCanonicalType();
+    if (QT->isVoidType()) {
+        std::ostringstream typedefbuf;
+        std::ostringstream callbuf;
+        for (int i = 0; i < indent_level; ++i) {
+            callbuf << indent_string;
+        }
+        make_narg_call(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
+        callbuf << ";\n";
+        for (int i = 0; i < indent_level; ++i) {
+            callbuf << indent_string;
+        }
+        callbuf << "return;\n";
+        buf << typedefbuf.str() << callbuf.str();
+    }
+    else {
+        for (int i = 0; i < indent_level; ++i) {
+            buf << indent_string;
+        }
+        buf << "if (ret) {\n";
+        ++indent_level;
+        {
+            std::ostringstream typedefbuf;
+            std::ostringstream callbuf;
+            //
+            //  Write the placement part of the placement new.
+            //
+            for (int i = 0; i < indent_level; ++i) {
+                callbuf << indent_string;
+            }
+            callbuf << "new (ret) ";
+            std::string type_name;
+            bool isReference = false;
+            int ptrCnt = 0;
+            collect_type_info(QT, typedefbuf, callbuf, type_name,
+                              isReference, ptrCnt, indent_level, false, fdecl);
+            //
+            //  Write the type part of the placement new.
+            //
+            if (isReference) {
+                std::string stars;
+                for (int j = 0; j < ptrCnt; ++j) {
+                    stars.push_back('*');
+                }
+                callbuf << "(" << type_name.c_str() << stars << "*) (&";
+            }
+            else if (ptrCnt) {
+                std::string stars;
+                for (int j = 0; j < ptrCnt; ++j) {
+                    stars.push_back('*');
+                }
+                callbuf << "(" << type_name.c_str() << stars << ") (";
+            }
+            else {
+                callbuf << "(" << type_name.c_str() << ") (";
+            }
+            //
+            //  Write the actual function call.
+            //
+            make_narg_call(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
+            //
+            //  End the placement new.
+            //
+            callbuf << ");\n";
+            for (int i = 0; i < indent_level; ++i) {
+                callbuf << indent_string;
+            }
+            callbuf << "return;\n";
+            //
+            //  Output the whole placement new expression and return statement.
+            //
+            buf << typedefbuf.str() << callbuf.str();
+        }
+        --indent_level;
+        for (int i = 0; i < indent_level; ++i) {
+            buf << indent_string;
+        }
+        buf << "}\n";
+        for (int i = 0; i < indent_level; ++i) {
+            buf << indent_string;
+        }
+        buf << "else {\n";
+        ++indent_level;
+        {
+            std::ostringstream typedefbuf;
+            std::ostringstream callbuf;
+            for (int i = 0; i < indent_level; ++i) {
+                callbuf << indent_string;
+            }
+            make_narg_call(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
+            callbuf << ";\n";
+            for (int i = 0; i < indent_level; ++i) {
+                callbuf << indent_string;
+            }
+            callbuf << "return;\n";
+            buf << typedefbuf.str() << callbuf.str();
+        }
+        --indent_level;
+        for (int i = 0; i < indent_level; ++i) {
+            buf << indent_string;
+        }
+        buf << "}\n";
+    }
+}
+
+static CPPYY_Cling_Wrapper_t make_wrapper(const FunctionDecl* fdecl) {
+    ASTContext& Context = fdecl->getASTContext();
+    PrintingPolicy Policy(Context.getPrintingPolicy());
+    //
+    //  Get the class or namespace name.
+    //
+    std::string class_name;
+    //    if (const TypeDecl* TD = llvm::dyn_cast<TypeDecl>(fdecl->getDeclContext())) {
+    //        // This is a class, struct, or union member.
+    //        QualType QT(TD->getTypeForDecl(), 0);
+    //        ROOT::TMetaUtils::GetFullyQualifiedTypeName(class_name, QT, *gCppyy_Cling);
+    //        // And drop the default arguments if any (at least until the clang
+    //        // type printer properly handle template paratemeter that are enumerator).
+    //        R__DropDefaultArg(class_name);
+    //    }
+    //    else
+    if (const NamedDecl* ND = llvm::dyn_cast<NamedDecl>(fdecl->getDeclContext())) {
+        // This is a namespace member.
+        llvm::raw_string_ostream stream(class_name);
+        ND->getNameForDiagnostic(stream, Policy, /*Qualified=*/true);
+        stream.flush();
+    }
+    //
+    //  Check to make sure that we can
+    //  instantiate and codegen this function.
+    //
+    bool needInstantiation = false;
+    const FunctionDecl* Definition = 0;
+    if (!fdecl->isDefined(Definition)) {
+        FunctionDecl::TemplatedKind TK = fdecl->getTemplatedKind();
+        switch (TK) {
+        case FunctionDecl::TK_NonTemplate: {
+            // Ordinary function, not a template specialization.
+            // Note: This might be ok, the body might be defined
+            //       in a library, and all we have seen is the
+            //       header file.
+            //print_error("make_wrapper",
+            //    "cannot make wrapper for a function which is declared but not defined!");
+            //return 0;
+            break;
+        }
+        case FunctionDecl::TK_FunctionTemplate: {
+            // This decl is actually a function template,
+            // not a function at all.
+            print_error("make_wrapper", "cannot make wrapper for a function template!");
+            return 0;
+        }
+        case FunctionDecl::TK_MemberSpecialization: {
+            // This function is the result of instantiating an ordinary
+            // member function of a class template, or of instantiating
+            // an ordinary member function of a class member of a class
+            // template, or of specializing a member function template
+            // of a class template, or of specializing a member function
+            // template of a class member of a class template.
+            if (!fdecl->isTemplateInstantiation()) {
+                // We are either TSK_Undeclared or
+                // TSK_ExplicitSpecialization.
+                // Note: This might be ok, the body might be defined
+                //       in a library, and all we have seen is the
+                //       header file.
+                //print_error("make_wrapper",
+                //    "cannot make wrapper for a function template explicit specialization"
+                //    " which is declared but not defined!");
+                //return 0;
+                break;
+            }
+            const FunctionDecl* Pattern = fdecl->getTemplateInstantiationPattern();
+            if (!Pattern) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a member function instantiation with no pattern!");
+                return 0;
+            }
+            FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
+            TemplateSpecializationKind PTSK =
+                Pattern->getTemplateSpecializationKind();
+            if (
+                // The pattern is an ordinary member function.
+                (PTK == FunctionDecl::TK_NonTemplate) || 
+                // The pattern is an explicit specialization, and
+                // so is not a template.
+                ((PTK != FunctionDecl::TK_FunctionTemplate) &&
+                 ((PTSK == TSK_Undeclared) ||
+                  (PTSK == TSK_ExplicitSpecialization)))
+                ) {
+                // Note: This might be ok, the body might be defined
+                //       in a library, and all we have seen is the
+                //       header file.
+                break;
+            }
+            else if (!Pattern->hasBody()) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a member function instantiation with no body!");
+                return 0;
+            }
+            if (fdecl->isImplicitlyInstantiable()) {
+                needInstantiation = true;
+            }
+            break;
+        }
+        case FunctionDecl::TK_FunctionTemplateSpecialization: {
+            // This function is the result of instantiating a function
+            // template or possibly an explicit specialization of a
+            // function template.  Could be a namespace scope function or a
+            // member function.
+            if (!fdecl->isTemplateInstantiation()) {
+                // We are either TSK_Undeclared or
+                // TSK_ExplicitSpecialization.
+                // Note: This might be ok, the body might be defined
+                //       in a library, and all we have seen is the
+                //       header file.
+                //print_error("make_wrapper",
+                //    "Cannot make wrapper for a function template "
+                //    "explicit specialization which is declared but not defined!");
+                //return 0;
+                break;
+            }
+            const FunctionDecl* Pattern = fdecl->getTemplateInstantiationPattern();
+            if (!Pattern) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a function template instantiation with no pattern!");
+                return 0;
+            }
+            FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
+            TemplateSpecializationKind PTSK =
+                Pattern->getTemplateSpecializationKind();
+            if (
+                // The pattern is an ordinary member function.
+                (PTK == FunctionDecl::TK_NonTemplate) || 
+                // The pattern is an explicit specialization, and
+                // so is not a template.
+                ((PTK != FunctionDecl::TK_FunctionTemplate) &&
+                 ((PTSK == TSK_Undeclared) ||
+                  (PTSK == TSK_ExplicitSpecialization)))
+                ) {
+                // Note: This might be ok, the body might be defined
+                //       in a library, and all we have seen is the
+                //       header file.
+                break;
+            }
+            if (!Pattern->hasBody()) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a function template instantiation with no body!");
+                return 0;
+            }
+            if (fdecl->isImplicitlyInstantiable()) {
+                needInstantiation = true;
+            }
+            break;
+        }
+        case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
+            // This function is the result of instantiating or
+            // specializing a  member function of a class template,
+            // or a member function of a class member of a class template,
+            // or a member function template of a class template, or a
+            // member function template of a class member of a class
+            // template where at least some part of the function is
+            // dependent on a template argument.
+            if (!fdecl->isTemplateInstantiation()) {
+                // We are either TSK_Undeclared or
+                // TSK_ExplicitSpecialization.
+                // Note: This might be ok, the body might be defined
+                //       in a library, and all we have seen is the
+                //       header file.
+                //print_error("make_wrapper",
+                //    "Cannot make wrapper for a dependent function template explicit specialization
+                //    " which is declared but not defined!");
+                //return 0;
+                break;
+            }
+            const FunctionDecl* Pattern = fdecl->getTemplateInstantiationPattern();
+            if (!Pattern) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a dependent function template instantiation with no pattern!");
+                return 0;
+            }
+            FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
+            TemplateSpecializationKind PTSK =
+                Pattern->getTemplateSpecializationKind();
+            if (
+                // The pattern is an ordinary member function.
+                (PTK == FunctionDecl::TK_NonTemplate) || 
+                // The pattern is an explicit specialization, and
+                // so is not a template.
+                ((PTK != FunctionDecl::TK_FunctionTemplate) &&
+                 ((PTSK == TSK_Undeclared) ||
+                  (PTSK == TSK_ExplicitSpecialization)))
+                ) {
+                // Note: This might be ok, the body might be defined
+                //       in a library, and all we have seen is the
+                //       header file.
+                break;
+            }
+            if (!Pattern->hasBody()) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a dependent function template instantiation with no body!");
+                return 0;
+            }
+            if (fdecl->isImplicitlyInstantiable()) {
+                needInstantiation = true;
+            }
+            break;
+        }
+        default: {
+            // Will only happen if clang implementation changes.
+            // Protect ourselves in case that happens.
+            print_error("make_wrapper", "unhandled template kind!");
+            return 0;
+        }
+        }
+        // We do not set needInstantiation to true in these cases:
+        //
+        // isInvalidDecl()
+        // TSK_Undeclared
+        // TSK_ExplicitInstantiationDefinition
+        // TSK_ExplicitSpecialization && !getClassScopeSpecializationPattern()
+        // TSK_ExplicitInstantiationDeclaration &&
+        //    getTemplateInstantiationPattern() &&
+        //    PatternDecl->hasBody() &&
+        //    !PatternDecl->isInlined()
+        //
+        // Set it true in these cases:
+        //
+        // TSK_ImplicitInstantiation
+        // TSK_ExplicitInstantiationDeclaration && (!getPatternDecl() ||
+        //    !PatternDecl->hasBody() || PatternDecl->isInlined())
+        //
+    }
+    if (needInstantiation) {
+        clang::FunctionDecl* FDmod = const_cast<clang::FunctionDecl*>(fdecl);
+        clang::Sema& S = gCppyy_Cling->getSema();
+        // Could trigger deserialization of decls.
+        cling::Interpreter::PushTransactionRAII RAII(gCppyy_Cling);
+        S.InstantiateFunctionDefinition(SourceLocation(), FDmod,
+                                        /*Recursive=*/ true,
+                                        /*DefinitionRequired=*/ true);
+        if (!fdecl->isDefined(Definition)) {
+            print_error("make_wrapper", "failed to force template instantiation!");
+            return 0;
+        }
+    }
+    if (Definition) {
+        FunctionDecl::TemplatedKind TK = Definition->getTemplatedKind();
+        switch (TK) {
+        case FunctionDecl::TK_NonTemplate: {
+            // Ordinary function, not a template specialization.
+            if (Definition->isDeleted()) {
+                print_error("make_wrapper", "cannot make wrapper for a deleted function!");
+                return 0;
+            }
+            else if (Definition->isLateTemplateParsed()) {
+                print_error("make_wrapper",
+                    "Cannot make wrapper for a late template parsed function!");
+                return 0;
+            }
+            //else if (Definition->isDefaulted()) {
+            //   // Might not have a body, but we can still use it.
+            //}
+            //else {
+            //   // Has a body.
+            //}
+            break;
+        }
+        case FunctionDecl::TK_FunctionTemplate: {
+            // This decl is actually a function template,
+            // not a function at all.
+            print_error("make_wrapper", "cannot make wrapper for a function template!");
+            return 0;
+        }
+        case FunctionDecl::TK_MemberSpecialization: {
+            // This function is the result of instantiating an ordinary
+            // member function of a class template or of a member class
+            // of a class template.
+            if (Definition->isDeleted()) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a deleted member function of a specialization!");
+                return 0;
+            }
+            else if (Definition->isLateTemplateParsed()) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a late template parsed member function of a specialization!");
+                return 0;
+            }
+            //else if (Definition->isDefaulted()) {
+            //   // Might not have a body, but we can still use it.
+            //}
+            //else {
+            //   // Has a body.
+            //}
+            break;
+        }
+        case FunctionDecl::TK_FunctionTemplateSpecialization: {
+            // This function is the result of instantiating a function
+            // template or possibly an explicit specialization of a
+            // function template.  Could be a namespace scope function or a
+            // member function.
+            if (Definition->isDeleted()) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a deleted function template specialization!");
+                return 0;
+            }
+            else if (Definition->isLateTemplateParsed()) {
+                print_error("make_wrapper",
+                   "cannot make wrapper for a late template parsed function template specialization!");
+                return 0;
+            }
+            //else if (Definition->isDefaulted()) {
+            //   // Might not have a body, but we can still use it.
+            //}
+            //else {
+            //   // Has a body.
+            //}
+            break;
+        }
+        case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
+            // This function is the result of instantiating or
+            // specializing a  member function of a class template,
+            // or a member function of a class member of a class template,
+            // or a member function template of a class template, or a
+            // member function template of a class member of a class
+            // template where at least some part of the function is
+            // dependent on a template argument.
+            if (Definition->isDeleted()) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a deleted dependent function template specialization!");
+                return 0;
+            }
+            else if (Definition->isLateTemplateParsed()) {
+                print_error("make_wrapper",
+                    "cannot make wrapper for a late template parsed "
+                    "dependent function template specialization!");
+                return 0;
+            }
+            //else if (Definition->isDefaulted()) {
+            //   // Might not have a body, but we can still use it.
+            //}
+            //else {
+            //   // Has a body.
+            //}
+            break;
+        }
+        default: {
+            // Will only happen if clang implementation changes.
+            // Protect ourselves in case that happens.
+            print_error("make_wrapper", "unhandled template kind!");
+            return 0;
+        }
+        }
+    }
+    unsigned min_args = fdecl->getMinRequiredArguments();
+    unsigned num_params = fdecl->getNumParams();
+    //
+    //  Make the wrapper name.
+    //
+    std::string wrapper_name;
+    {
+        std::ostringstream buf;
+        buf << "__cf";
+        //const NamedDecl* ND = llvm::dyn_cast<NamedDecl>(fdecl);
+        //std::string mn;
+        //gCppyy_Cling->maybeMangleDeclName(ND, mn);
+        //buf << '_' << mn;
+        buf << '_' << wrapper_serial++;
+        wrapper_name = buf.str();
+    }
+    //
+    //  Write the wrapper code.
+    // FIXME: this should be synthesized into the AST!
+    //
+    int indent_level = 0;
+    std::ostringstream buf;
+    buf << "__attribute__((used)) ";
+    buf << "extern \"C\" void ";
+    buf << wrapper_name;
+    buf << "(void* obj, int nargs, void** args, void* ret)\n";
+    buf << "{\n";
+    ++indent_level;
+    if (min_args == num_params) {
+        // No parameters with defaults.
+        make_narg_call_with_return(num_params, class_name, buf, indent_level, fdecl);
+    }
+    else {
+        // We need one function call clause compiled for every
+        // possible number of arguments per call.
+        for (unsigned N = min_args; N <= num_params; ++N) {
+            for (int i = 0; i < indent_level; ++i) {
+                buf << indent_string;
+            }
+            buf << "if (nargs == " << N << ") {\n";
+            ++indent_level;
+            make_narg_call_with_return(N, class_name, buf, indent_level, fdecl);
+            --indent_level;
+            for (int i = 0; i < indent_level; ++i) {
+                buf << indent_string;
+            }
+            buf << "}\n";
+        }
+    }
+    --indent_level;
+    buf << "}\n";
+    //
+    //  Compile the wrapper code.
+    //
+    std::string wrapper_code(buf.str());
+    std::cout << "   CREATED WRAPPER: " << std::endl;
+    std::cout << wrapper_code << std::endl;
+    void* wrapper = gCppyy_Cling->compileFunction(
+        wrapper_name, wrapper_code, false /*ifUnique*/, true /*withAcessControl*/);
+    if (wrapper)
+        s_wrappers.insert(std::make_pair((cppyy_method_t)fdecl, (CPPYY_Cling_Wrapper_t)wrapper));
+    return (CPPYY_Cling_Wrapper_t)wrapper;
+}


More information about the pypy-commit mailing list