[pypy-commit] pypy reflex-support: o) set of CINT-backend tests
wlav
noreply at buildbot.pypy.org
Thu Jul 5 05:28:05 CEST 2012
Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r55925:a54c37b4006f
Date: 2012-07-04 20:27 -0700
http://bitbucket.org/pypy/pypy/changeset/a54c37b4006f/
Log: o) set of CINT-backend tests o) enable use of interpreted classes
(CINT only) o) code cleanup
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -423,8 +423,7 @@
def _build_methods(self):
assert len(self.methods) == 0
methods_temp = {}
- N = capi.c_num_methods(self)
- for i in range(N):
+ for i in range(capi.c_num_methods(self)):
idx = capi.c_method_index_at(self, i)
pyname = helper.map_operator_name(
capi.c_method_name(self, idx),
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
--- a/pypy/module/cppyy/pythonify.py
+++ b/pypy/module/cppyy/pythonify.py
@@ -254,7 +254,7 @@
except AttributeError:
pass
- if not (pycppitem is None): # pycppitem could be a bound C++ NULL, so check explicitly for Py_None
+ if pycppitem is not None: # pycppitem could be a bound C++ NULL, so check explicitly for Py_None
return pycppitem
raise AttributeError("'%s' has no attribute '%s'" % (str(scope), name))
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx
--- a/pypy/module/cppyy/src/cintcwrapper.cxx
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -1,8 +1,6 @@
#include "cppyy.h"
#include "cintcwrapper.h"
-#include "Api.h"
-
#include "TROOT.h"
#include "TError.h"
#include "TList.h"
@@ -23,6 +21,8 @@
#include "TMethod.h"
#include "TMethodArg.h"
+#include "Api.h"
+
#include <assert.h>
#include <string.h>
#include <map>
@@ -31,9 +31,8 @@
#include <utility>
-/* CINT internals (some won't work on Windows) -------------------------- */
+/* ROOT/CINT internals --------------------------------------------------- */
extern long G__store_struct_offset;
-extern "C" void* G__SetShlHandle(char*);
extern "C" void G__LockCriticalSection();
extern "C" void G__UnlockCriticalSection();
@@ -66,26 +65,15 @@
typedef std::map<std::string, ClassRefs_t::size_type> ClassRefIndices_t;
static ClassRefIndices_t g_classref_indices;
-class ClassRefsInit {
-public:
- ClassRefsInit() { // setup dummy holders for global and std namespaces
- assert(g_classrefs.size() == (ClassRefs_t::size_type)GLOBAL_HANDLE);
- g_classref_indices[""] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
- g_classrefs.push_back(TClassRef(""));
- g_classref_indices["std"] = g_classrefs.size();
- g_classrefs.push_back(TClassRef("")); // CINT ignores std
- g_classref_indices["::std"] = g_classrefs.size();
- g_classrefs.push_back(TClassRef("")); // id.
- }
-};
-static ClassRefsInit _classrefs_init;
-
typedef std::vector<TFunction> GlobalFuncs_t;
static GlobalFuncs_t g_globalfuncs;
typedef std::vector<TGlobal> GlobalVars_t;
static GlobalVars_t g_globalvars;
+typedef std::vector<G__MethodInfo> InterpretedFuncs_t;
+static InterpretedFuncs_t g_interpreted;
+
/* initialization of the ROOT system (debatable ... ) --------------------- */
namespace {
@@ -95,12 +83,12 @@
TCppyyApplication(const char* acn, Int_t* argc, char** argv, Bool_t do_load = kTRUE)
: TApplication(acn, argc, argv) {
- // Explicitly load libMathCore as CINT will not auto load it when using one
- // of its globals. Once moved to Cling, which should work correctly, we
- // can remove this statement.
- gSystem->Load("libMathCore");
+ // Explicitly load libMathCore as CINT will not auto load it when using
+ // one of its globals. Once moved to Cling, which should work correctly,
+ // we can remove this statement.
+ gSystem->Load("libMathCore");
- if (do_load) {
+ if (do_load) {
// follow TRint to minimize differences with CINT
ProcessLine("#include <iostream>", kTRUE);
ProcessLine("#include <_string>", kTRUE); // for std::string iostream.
@@ -130,10 +118,30 @@
class ApplicationStarter {
public:
ApplicationStarter() {
+ // setup dummy holders for global and std namespaces
+ assert(g_classrefs.size() == (ClassRefs_t::size_type)GLOBAL_HANDLE);
+ g_classref_indices[""] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+ g_classrefs.push_back(TClassRef(""));
+ g_classref_indices["std"] = g_classrefs.size();
+ g_classrefs.push_back(TClassRef("")); // CINT ignores std
+ g_classref_indices["::std"] = g_classrefs.size();
+ g_classrefs.push_back(TClassRef("")); // id.
+
+ // an offset for the interpreted methods
+ g_interpreted.push_back(G__MethodInfo());
+
+ // actual application init, if necessary
if (!gApplication) {
int argc = 1;
char* argv[1]; argv[0] = (char*)appname;
gApplication = new TCppyyApplication(appname, &argc, argv, kTRUE);
+ if (!gProgName) // should have been set by TApplication
+ gSystem->SetProgname(appname);
+ }
+
+ // program name should've been set by TApplication; just in case ...
+ if (!gProgName) {
+ gSystem->SetProgname(appname);
}
}
} _applicationStarter;
@@ -325,11 +333,21 @@
static inline G__value cppyy_call_T(cppyy_method_t method,
cppyy_object_t self, int nargs, void* args) {
- G__InterfaceMethod meth = (G__InterfaceMethod)method;
G__param* libp = (G__param*)((char*)args - offsetof(G__param, para));
assert(libp->paran == nargs);
fixup_args(libp);
+ if ((InterpretedFuncs_t::size_type)method < g_interpreted.size()) {
+ // the idea here is that all these low values are invalid memory addresses,
+ // allowing the reuse of method to index the stored bytecodes
+ G__CallFunc callf;
+ callf.SetFunc(g_interpreted[(size_t)method]);
+ callf.SetArgs(*libp);
+ return callf.Execute((void*)self);
+ }
+
+ G__InterfaceMethod meth = (G__InterfaceMethod)method;
+
G__value result;
G__setnull(&result);
@@ -338,13 +356,13 @@
long index = (long)&method;
G__CurrentCall(G__SETMEMFUNCENV, 0, &index);
-
+
// TODO: access to store_struct_offset won't work on Windows
long store_struct_offset = G__store_struct_offset;
if (self)
G__store_struct_offset = (long)self;
- meth(&result, 0, libp, 0);
+ meth(&result, (char*)0, libp, 0);
if (self)
G__store_struct_offset = store_struct_offset;
@@ -663,8 +681,27 @@
cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t idx) {
+ TClassRef cr = type_from_handle(handle);
TFunction* f = type_get_method(handle, idx);
- return (cppyy_method_t)f->InterfaceMethod();
+ if (cr && cr.GetClass() && !cr->IsLoaded()) {
+ G__ClassInfo* gcl = (G__ClassInfo*)cr->GetClassInfo();
+ if (gcl) {
+ long offset;
+ std::ostringstream sig;
+ int nArgs = f->GetNargs();
+ for (int iarg = 0; iarg < nArgs; ++iarg) {
+ sig << ((TMethodArg*)f->GetListOfMethodArgs()->At(iarg))->GetFullTypeName();
+ if (iarg != nArgs-1) sig << ", ";
+ }
+ G__MethodInfo gmi = gcl->GetMethod(
+ f->GetName(), sig.str().c_str(), &offset, G__ClassInfo::ExactMatch);
+ cppyy_method_t method = (cppyy_method_t)g_interpreted.size();
+ g_interpreted.push_back(gmi);
+ return method;
+ }
+ }
+ cppyy_method_t method = (cppyy_method_t)f->InterfaceMethod();
+ return method;
}
cppyy_index_t cppyy_get_global_operator(cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx
--- a/pypy/module/cppyy/test/example01.cxx
+++ b/pypy/module/cppyy/test/example01.cxx
@@ -156,6 +156,8 @@
return ::globalAddOneToInt(a);
}
+int ns_example01::gMyGlobalInt = 99;
+
// argument passing
#define typeValueImp(itype, tname) \
diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h
--- a/pypy/module/cppyy/test/example01.h
+++ b/pypy/module/cppyy/test/example01.h
@@ -60,10 +60,11 @@
};
-// global functions
+// global functions and data
int globalAddOneToInt(int a);
namespace ns_example01 {
int globalAddOneToInt(int a);
+ extern int gMyGlobalInt;
}
#define itypeValue(itype, tname) \
@@ -72,6 +73,7 @@
#define ftypeValue(ftype) \
ftype ftype##Value(ftype arg0, int argn=0, ftype arg1=1., ftype arg2=2.)
+
// argument passing
class ArgPasser { // use a class for now as methptrgetter not
public: // implemented for global functions
diff --git a/pypy/module/cppyy/test/example01.xml b/pypy/module/cppyy/test/example01.xml
--- a/pypy/module/cppyy/test/example01.xml
+++ b/pypy/module/cppyy/test/example01.xml
@@ -11,6 +11,7 @@
<namespace name="ns_example01" />
<function name="ns_example01::globalAddOneToInt" />
+ <variable name="ns_example01::gMyGlobalInt" />
<class name="ArgPasser" />
diff --git a/pypy/module/cppyy/test/example01_LinkDef.h b/pypy/module/cppyy/test/example01_LinkDef.h
--- a/pypy/module/cppyy/test/example01_LinkDef.h
+++ b/pypy/module/cppyy/test/example01_LinkDef.h
@@ -16,4 +16,6 @@
#pragma link C++ namespace ns_example01;
#pragma link C++ function ns_example01::globalAddOneToInt(int);
+#pragma link C++ variable ns_example01::gMyGlobalInt;
+
#endif
diff --git a/pypy/module/cppyy/test/simple_class.C b/pypy/module/cppyy/test/simple_class.C
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/simple_class.C
@@ -0,0 +1,15 @@
+class MySimpleBase {
+public:
+ MySimpleBase() {}
+};
+
+class MySimpleDerived : public MySimpleBase {
+public:
+ MySimpleDerived() { m_data = -42; }
+ int get_data() { return m_data; }
+ void set_data(int data) { m_data = data; }
+public:
+ int m_data;
+};
+
+typedef MySimpleDerived MySimpleDerived_t;
diff --git a/pypy/module/cppyy/test/test_cint.py b/pypy/module/cppyy/test/test_cint.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_cint.py
@@ -0,0 +1,87 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+# These tests are for the CINT backend only (they exercise ROOT features
+# and classes that are not loaded/available with the Reflex backend). At
+# some point, these tests are likely covered by the CLang/LLVM backend.
+from pypy.module.cppyy import capi
+if capi.identify() != 'CINT':
+ py.test.skip("backend-specific: CINT-only tests")
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+class AppTestCINT:
+ def setup_class(cls):
+ cls.space = space
+
+ def test01_globals(self):
+ """Test the availability of ROOT globals"""
+
+ import cppyy
+
+ assert cppyy.gbl.gROOT
+ assert cppyy.gbl.gApplication
+ assert cppyy.gbl.gSystem
+ assert cppyy.gbl.TInterpreter.Instance()
+ assert cppyy.gbl.TDirectory.CurrentDirectory()
+
+ def test02_write_access_to_globals(self):
+ """Test overwritability of ROOT globals"""
+
+ import cppyy
+
+ oldval = cppyy.gbl.gDebug
+ assert oldval != 3
+
+ proxy = cppyy.gbl.__class__.gDebug
+ cppyy.gbl.gDebug = 3
+ assert proxy.__get__(proxy) == 3
+
+ # this is where this test differs from test03_write_access_to_globals
+ # in test_pythonify.py
+ cppyy.gbl.gROOT.ProcessLine('int gDebugCopy = gDebug;')
+ assert cppyy.gbl.gDebugCopy == 3
+
+ cppyy.gbl.gDebug = oldval
+
+ def test03_create_access_to_globals(self):
+ """Test creation and access of new ROOT globals"""
+
+ import cppyy
+
+ cppyy.gbl.gROOT.ProcessLine('double gMyOwnGlobal = 3.1415')
+ assert cppyy.gbl.gMyOwnGlobal == 3.1415
+
+ proxy = cppyy.gbl.__class__.gMyOwnGlobal
+ assert proxy.__get__(proxy) == 3.1415
+
+ def test04_auto_loading(self):
+ """Test auto-loading by retrieving a non-preloaded class"""
+
+ import cppyy
+
+ l = cppyy.gbl.TLorentzVector()
+ assert isinstance(l, cppyy.gbl.TLorentzVector)
+
+ def test05_macro_loading(self):
+ """Test accessibility to macro classes"""
+
+ import cppyy
+
+ loadres = cppyy.gbl.gROOT.LoadMacro('simple_class.C')
+ assert loadres == 0
+
+ base = cppyy.gbl.MySimpleBase
+ simple = cppyy.gbl.MySimpleDerived
+ simple_t = cppyy.gbl.MySimpleDerived_t
+
+ assert issubclass(simple, base)
+ assert simple is simple_t
+
+ c = simple()
+ assert isinstance(c, simple)
+ assert c.m_data == c.get_data()
+
+ c.set_data(13)
+ assert c.m_data == 13
+ assert c.get_data() == 13
diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py
--- a/pypy/module/cppyy/test/test_pythonify.py
+++ b/pypy/module/cppyy/test/test_pythonify.py
@@ -345,3 +345,17 @@
example01_pythonize = 1
raises(TypeError, cppyy.add_pythonization, 'example01', example01_pythonize)
+
+ def test03_write_access_to_globals(self):
+ """Test overwritability of globals"""
+
+ import cppyy
+
+ oldval = cppyy.gbl.ns_example01.gMyGlobalInt
+ assert oldval == 99
+
+ proxy = cppyy.gbl.ns_example01.__class__.gMyGlobalInt
+ cppyy.gbl.ns_example01.gMyGlobalInt = 3
+ assert proxy.__get__(proxy) == 3
+
+ cppyy.gbl.ns_example01.gMyGlobalInt = oldval
diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py
--- a/pypy/module/cppyy/test/test_zjit.py
+++ b/pypy/module/cppyy/test/test_zjit.py
@@ -6,6 +6,9 @@
from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root
from pypy.module.cppyy import interp_cppyy, capi
+# These tests are for the backend that support the fast path only.
+if capi.identify() == 'CINT':
+ py.test.skip("CINT does not support fast path")
# load cpyext early, or its global vars are counted as leaks in the test
# (note that the module is not otherwise used in the test itself)
@@ -177,9 +180,6 @@
return True
class TestFastPathJIT(LLJitMixin):
- if not capi.identify() != 'CINT':
- py.test.skip("CINT does not support fast path")
-
def _run_zjit(self, method_name):
space = FakeSpace()
drv = jit.JitDriver(greens=[], reds=["i", "inst", "cppmethod"])
More information about the pypy-commit
mailing list