Skip to content

Commit 571a436

Browse files
committed
[memory-analysis] Added a field to CPPMethod to store memory-ownership information and this information effects kIsCreator flag of overload group , currently analyzer is not called, just attribute checker is called
1 parent d5ad230 commit 571a436

11 files changed

Lines changed: 106 additions & 0 deletions

‎src/cpyrt/CPPMethod.cxx‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,23 @@ PyObject* cpyrt::CPPMethod::GetArgDefault(int iarg, bool silent) {
749749

750750
bool cpyrt::CPPMethod::IsConst() { return interop::IsConstMethod(GetMethod()); }
751751

752+
//----------------------------------------------------------------------------
753+
// FIXME: For now every allocation is assumed to be done with `new`
754+
// will be fixed soon. Also the reason function returns an AllocType
755+
// instead of bool, IsAllocator function from CppInterOp changed a little,
756+
// but these changes did not merged to main yet, another reason is next PR
757+
// will add user-optional analyzer so the function needs to return allocation
758+
// way
759+
interop::AllocType cpyrt::CPPMethod::GetAllocBehaviour() {
760+
if (fAllocType.has_value())
761+
return *fAllocType;
762+
if (interop::IsAllocator(GetMethod())) {
763+
fAllocType = interop::AllocType::New;
764+
return interop::AllocType::New;
765+
}
766+
fAllocType = interop::AllocType::None;
767+
return interop::AllocType::None;
768+
}
752769
//----------------------------------------------------------------------------
753770
PyObject* cpyrt::CPPMethod::GetScopeProxy() {
754771
// Get or build the scope of this method.

‎src/cpyrt/CPPMethod.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "PyCallable.h"
66

77
// Standard
8+
#include <optional>
89
#include <string>
910
#include <unordered_map>
1011
#include <vector>
@@ -63,6 +64,7 @@ class CPPMethod : public PyCallable {
6364
PyObject* GetCoVarNames() override;
6465
PyObject* GetArgDefault(int iarg, bool silent = true) override;
6566
bool IsConst() override;
67+
cppjit::interop::AllocType GetAllocBehaviour() override;
6668

6769
PyObject* GetScopeProxy() override;
6870
cppjit::interop::TCppFuncAddr_t GetFunctionAddress() override;
@@ -117,6 +119,7 @@ class CPPMethod : public PyCallable {
117119
protected:
118120
// cached value that doubles as initialized flag (uninitialized if -1)
119121
int fArgsRequired;
122+
std::optional<cppjit::interop::AllocType> fAllocType;
120123
};
121124

122125
} // namespace cppjit::cpyrt

‎src/cpyrt/CPPOverload.cxx‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ static inline PyObject* HandleReturn(CPPOverload* pymeth, CPPInstance* im_self,
155155
CPPInstance* cppres =
156156
(CPPInstance*)(CPPInstance_Check(result) ? result : nullptr);
157157

158+
interop::AllocType AT =
159+
pymeth->fMethodInfo->fMethods[0]->GetAllocBehaviour();
160+
if (AT != interop::AllocType::None && AT != interop::AllocType::Null &&
161+
AT != interop::AllocType::Unknown)
162+
pymeth->fMethodInfo->fFlags |= CallContext::kIsCreator;
163+
158164
// if this method creates new objects, always take ownership
159165
if (IsCreator(pymeth->fMethodInfo->fFlags)) {
160166

‎src/cpyrt/PyCallable.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class PyCallable {
3737
virtual PyObject* GetCoVarNames() = 0;
3838
virtual PyObject* GetArgDefault(int /* iarg */, bool silent = true) = 0;
3939
virtual bool IsConst() { return false; }
40+
virtual cppjit::interop::AllocType GetAllocBehaviour() {
41+
return cppjit::interop::AllocType::None;
42+
}
4043

4144
virtual PyObject* GetScopeProxy() = 0;
4245
virtual cppjit::interop::TCppFuncAddr_t GetFunctionAddress() = 0;

‎src/cpyrt/cppjit_interop.h‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ struct ObjectRef {
9292
friend bool operator==(ObjectRef a, ObjectRef b) { return a.data == b.data; }
9393
friend bool operator!=(ObjectRef a, ObjectRef b) { return !(a == b); }
9494
};
95+
96+
enum class AllocType : unsigned char {
97+
None,
98+
New,
99+
NewArr,
100+
Malloc,
101+
Unknown,
102+
CustomAlloc,
103+
Null,
104+
OperatorNew,
105+
OperatorNewArr
106+
};
95107
} // namespace Cpp
96108

97109
template <> struct std::hash<Cpp::DeclRef> {
@@ -122,6 +134,7 @@ typedef Cpp::ObjectRef TCppObject_t;
122134
typedef Cpp::FuncRef TCppMethod_t;
123135
typedef size_t TCppIndex_t;
124136
typedef void* TCppFuncAddr_t;
137+
typedef Cpp::AllocType AllocType;
125138

126139
// direct interpreter access -------------------------------------------------
127140
CPPJIT_IMPORT
@@ -368,6 +381,8 @@ CPPJIT_IMPORT
368381
std::string GetDoxygenComment(TCppScope_t scope, bool strip_markers = true);
369382
CPPJIT_IMPORT
370383
bool IsConstMethod(TCppMethod_t);
384+
CPPJIT_IMPORT
385+
bool IsAllocator(TCppMethod_t);
371386
// Templated method/function reflection information
372387
// ------------------------------------
373388
CPPJIT_IMPORT

‎src/interop/cpp_cppjit.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ typedef Cpp::FuncRef TCppMethod_t;
5353
typedef Cpp::InterpRef TInterp_t;
5454
typedef size_t TCppIndex_t;
5555
typedef void* TCppFuncAddr_t;
56+
typedef Cpp::AllocType AllocType;
5657

5758
// direct interpreter access -------------------------------------------------
5859
RPY_EXPORTED
@@ -306,6 +307,8 @@ RPY_EXPORTED
306307
std::string GetDoxygenComment(TCppScope_t scope, bool strip_markers = true);
307308
RPY_EXPORTED
308309
bool IsConstMethod(TCppMethod_t);
310+
RPY_EXPORTED
311+
bool IsAllocator(TCppMethod_t);
309312
// Templated method/function reflection information
310313
// ------------------------------------
311314
RPY_EXPORTED

‎src/interop/interop_wrapper.cxx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,11 @@ interop::TCppType_t interop::GetMethodReturnType(TCppMethod_t method) {
11841184
return Cpp::GetFunctionReturnType(method);
11851185
}
11861186

1187+
bool interop::IsAllocator(TCppMethod_t method) {
1188+
std::lock_guard<std::recursive_mutex> Lock(InterOpMutex);
1189+
return Cpp::IsAllocator(method);
1190+
}
1191+
11871192
std::string interop::GetMethodReturnTypeAsString(TCppMethod_t method) {
11881193
std::lock_guard<std::recursive_mutex> Lock(InterOpMutex);
11891194
return Cpp::GetTypeAsString(

‎test/Makefile‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dictnames = advancedcpp \
1010
doc_helper \
1111
example01 \
1212
fragile \
13+
memory_analysis \
1314
operators \
1415
overloads \
1516
pythonizables \

‎test/cpp/memory_analysis.cxx‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include "memory_analysis.h"
2+
__attribute__((malloc)) memAnalysisKlass* allocTest() {
3+
return new memAnalysisKlass;
4+
}
5+
6+
__attribute__((ownership_returns(malloc))) memAnalysisKlass*
7+
allocTestReturns() {
8+
return new memAnalysisKlass;
9+
}

‎test/cpp/memory_analysis.h‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef MEMORY_ANALYSIS_H
2+
#define MEMORY_ANALYSIS_H
3+
4+
#include <new>
5+
#include <stdlib.h>
6+
7+
class memAnalysisKlass {
8+
int val;
9+
};
10+
__attribute__((malloc)) memAnalysisKlass* allocTest();
11+
__attribute__((ownership_returns(malloc))) memAnalysisKlass* allocTestReturns();
12+
13+
#endif // MEMORY_ANALYSIS_H

0 commit comments

Comments
 (0)