Author: Wim Lavrijsen <[email protected]>
Branch: reflex-support
Changeset: r59434:a3036ea55d22
Date: 2012-12-14 17:13 -0800
http://bitbucket.org/pypy/pypy/changeset/a3036ea55d22/
Log: rework how constructors are used to allow for overloader operator
new/delete (albeit that Reflex does not support that, but cling/llvm
does)
diff --git a/pypy/module/cppyy/capi/__init__.py
b/pypy/module/cppyy/capi/__init__.py
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -168,7 +168,7 @@
c_constructor = rffi.llexternal(
"cppyy_constructor",
- [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+ [C_METHOD, C_TYPE, rffi.INT, rffi.VOIDP], C_OBJECT,
threadsafe=ts_call,
compilation_info=backend.eci)
_c_call_o = rffi.llexternal(
diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
--- a/pypy/module/cppyy/executor.py
+++ b/pypy/module/cppyy/executor.py
@@ -137,11 +137,13 @@
return space.wrap(result)
-class ConstructorExecutor(VoidExecutor):
+class ConstructorExecutor(FunctionExecutor):
- def execute(self, space, cppmethod, cppthis, num_args, args):
- capi.c_constructor(cppmethod, cppthis, num_args, args)
- return space.w_None
+ def execute(self, space, cppmethod, cpptype, num_args, args):
+ from pypy.module.cppyy import interp_cppyy
+ newthis = capi.c_constructor(cppmethod, cpptype, num_args, args)
+ assert lltype.typeOf(newthis) == capi.C_OBJECT
+ return space.wrap(newthis)
class InstancePtrExecutor(FunctionExecutor):
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
--- a/pypy/module/cppyy/include/capi.h
+++ b/pypy/module/cppyy/include/capi.h
@@ -42,7 +42,7 @@
void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs,
void* args);
char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs,
void* args);
- void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int
nargs, void* args);
+ cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t
klass, int nargs, void* args);
cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self,
int nargs, void* args, cppyy_type_t result_type);
cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope,
cppyy_index_t idx);
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
@@ -373,20 +373,19 @@
class CPPConstructor(CPPMethod):
- """Method dispatcher that constructs new objects. In addition to the call,
- it allocates memory for the newly constructed object and sets ownership
- to Python."""
+ """Method dispatcher that constructs new objects. This method can not have
+ a fast path, a the allocation of the object is currently left to the
+ reflection layer only, b/c the C++ class may have an overloaded operator
+ new, disallowing malloc here."""
_immutable_ = True
def call(self, cppthis, args_w):
- newthis = capi.c_allocate(self.scope)
- assert lltype.typeOf(newthis) == capi.C_OBJECT
- try:
- CPPMethod.call(self, newthis, args_w)
- except:
- capi.c_deallocate(self.scope, newthis)
- raise
+ # TODO: these casts are very, very un-pretty; need to find a way of
+ # re-using CPPMethod's features w/o these roundabouts
+ vscope = rffi.cast(capi.C_OBJECT, self.scope.handle)
+ w_result = CPPMethod.call(self, vscope, args_w)
+ newthis = rffi.cast(capi.C_OBJECT, self.space.int_w(w_result))
return wrap_new_cppobject_nocast(
self.space, self.space.w_None, self.scope, newthis, isref=False,
python_owns=True)
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
@@ -451,10 +451,19 @@
return cppstring_to_cstring("");
}
-void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs,
void* args) {
- G__setgvp((long)self);
- cppyy_call_T(method, self, nargs, args);
+cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle,
int nargs, void* args) {
+ cppyy_object_t self = (cppyy_object_t)NULL;
+ if ((InterpretedFuncs_t::size_type)method >= g_interpreted.size()) {
+ G__setgvp((long)G__PVOID);
+ self = (cppyy_object_t)cppyy_call_l(method, (cppyy_object_t)NULL,
nargs, args);
+ } else {
+ // for macro's/interpreted classes
+ self = cppyy_allocate(handle);
+ G__setgvp((long)self);
+ cppyy_call_T(method, self, nargs, args);
+ }
G__setgvp((long)G__PVOID);
+ return self;
}
cppyy_object_t cppyy_call_o(cppyy_type_t method, cppyy_object_t self, int
nargs, void* args,
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx
b/pypy/module/cppyy/src/reflexcwrapper.cxx
--- a/pypy/module/cppyy/src/reflexcwrapper.cxx
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -177,8 +177,10 @@
return cppstring_to_cstring(result);
}
-void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs,
void* args) {
+cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle,
int nargs, void* args) {
+ cppyy_object_t self = cppyy_allocate(handle);
cppyy_call_v(method, self, nargs, args);
+ return self;
}
cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int
nargs, void* args,
diff --git a/pypy/module/cppyy/test/advancedcpp.cxx
b/pypy/module/cppyy/test/advancedcpp.cxx
--- a/pypy/module/cppyy/test/advancedcpp.cxx
+++ b/pypy/module/cppyy/test/advancedcpp.cxx
@@ -83,3 +83,23 @@
multi1::~multi1() {}
multi2::~multi2() {}
multi::~multi() {}
+
+
+// for testing calls to overloaded new
+int new_overloader::s_instances = 0;
+
+void* new_overloader::operator new(std::size_t size) {
+ ++s_instances;
+ return ::operator new(size);
+}
+
+void* new_overloader::operator new(std::size_t, void* p) throw() {
+ // no ++s_instances, as no memory is allocated
+ return p;
+}
+
+void new_overloader::operator delete(void* p, std::size_t) {
+ if (p == 0) return;
+ --s_instances;
+ ::operator delete(p);
+}
diff --git a/pypy/module/cppyy/test/advancedcpp.h
b/pypy/module/cppyy/test/advancedcpp.h
--- a/pypy/module/cppyy/test/advancedcpp.h
+++ b/pypy/module/cppyy/test/advancedcpp.h
@@ -1,3 +1,4 @@
+#include <new>
#include <vector>
@@ -358,3 +359,15 @@
private:
int m_int;
};
+
+
+//===========================================================================
+class new_overloader { // for testing calls to overloaded new
+public:
+ static int s_instances;
+
+public:
+ void* operator new(std::size_t size);
+ void* operator new(std::size_t, void* p) throw();
+ void operator delete(void* p, std::size_t size);
+};
diff --git a/pypy/module/cppyy/test/advancedcpp.xml
b/pypy/module/cppyy/test/advancedcpp.xml
--- a/pypy/module/cppyy/test/advancedcpp.xml
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -37,4 +37,6 @@
<class pattern="multi*" />
+ <class name="new_overloader" />
+
</lcgdict>
diff --git a/pypy/module/cppyy/test/advancedcpp_LinkDef.h
b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
--- a/pypy/module/cppyy/test/advancedcpp_LinkDef.h
+++ b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
@@ -64,4 +64,6 @@
#pragma link C++ class multi2;
#pragma link C++ class multi;
+#pragma link C++ class new_overloader;
+
#endif
diff --git a/pypy/module/cppyy/test/test_advancedcpp.py
b/pypy/module/cppyy/test/test_advancedcpp.py
--- a/pypy/module/cppyy/test/test_advancedcpp.py
+++ b/pypy/module/cppyy/test/test_advancedcpp.py
@@ -509,3 +509,28 @@
assert type(c2) == cppyy.gbl.c_class_2
assert c2.m_c == 3
c2.destruct()
+
+ def test14_new_overloader(self):
+ """Verify that class-level overloaded new/delete are called"""
+
+ # TODO: operator new appears to be respected by CINT, but operator
+ # delete is not called through root/meta. Anyway, Reflex gets it all
+ # wrong (clear from the generated code). Keep this test as it should
+ # be all better in the cling/llvm world ...
+
+ if self.capi_identity == 'Reflex': # don't test anything
+ return
+
+ import cppyy
+
+ assert cppyy.gbl.new_overloader.s_instances == 0
+ nl = cppyy.gbl.new_overloader()
+ assert cppyy.gbl.new_overloader.s_instances == 1
+ nl.destruct()
+
+ if self.capi_identity == 'CINT': # do not test delete
+ return
+
+ import gc
+ gc.collect()
+ assert cppyy.gbl.new_overloader.s_instances == 0
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit