Skip to content

Commit 474a9c5

Browse files
committed
Add support for array of objects in Construct/Destruct
1 parent 03135b6 commit 474a9c5

File tree

4 files changed

+88
-37
lines changed

4 files changed

+88
-37
lines changed

include/clang-c/CXCppInterOp.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,8 @@ CINDEX_LINKAGE void clang_deallocate(CXObject address);
332332
* Creates an object of class \c scope and calls its default constructor. If \c
333333
* arena is set it uses placement new.
334334
*/
335-
CINDEX_LINKAGE CXObject clang_construct(CXScope scope, void* arena);
335+
CINDEX_LINKAGE CXObject clang_construct(CXScope scope, void* arena,
336+
size_t count);
336337

337338
/**
338339
* Creates a trampoline function and makes a call to a generic function or
@@ -349,7 +350,7 @@ CINDEX_LINKAGE CXObject clang_construct(CXScope scope, void* arena);
349350
* \param self The 'this pointer' of the object.
350351
*/
351352
CINDEX_LINKAGE void clang_invoke(CXScope func, void* result, void** args,
352-
size_t n, void* self);
353+
size_t n, size_t nary, void* self);
353354

354355
/**
355356
* Calls the destructor of object of type \c type. When withFree is true it
@@ -361,7 +362,8 @@ CINDEX_LINKAGE void clang_invoke(CXScope func, void* result, void** args,
361362
*
362363
* \param withFree Whether to call operator delete/free or not.
363364
*/
364-
CINDEX_LINKAGE void clang_destruct(CXObject This, CXScope S, bool withFree);
365+
CINDEX_LINKAGE void clang_destruct(CXObject This, CXScope S,
366+
bool withFree = true, size_t nary = 0UL);
365367

366368
/**
367369
* @}

include/clang/Interpreter/CppInterOp.h

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ namespace Cpp {
111111
// FIXME: Figure out how to unify the wrapper signatures.
112112
// FIXME: Hide these implementation details by moving wrapper generation in
113113
// this class.
114-
using GenericCall = void (*)(void*, int, void**, void*);
114+
115+
// (self, args, args, result, nary)
116+
using GenericCall = void (*)(void*, int, void**, void*, size_t);
117+
// (self, nary, withFree)
115118
using DestructorCall = void (*)(void*, unsigned long, int);
116119
private:
117120
union {
@@ -156,16 +159,17 @@ namespace Cpp {
156159
// self can go in the end and be nullptr by default; result can be a nullptr
157160
// by default. These changes should be synchronized with the wrapper if we
158161
// decide to directly.
159-
void Invoke(void* result, ArgList args = {}, void* self = nullptr) const {
162+
void Invoke(void* result, ArgList args = {}, void* self = nullptr,
163+
size_t nary = 0UL) const {
160164
// Forward if we intended to call a dtor with only 1 parameter.
161165
if (m_Kind == kDestructorCall && result && !args.m_Args)
162-
return InvokeDestructor(result, /*nary=*/0UL, /*withFree=*/true);
166+
return InvokeDestructor(result, nary, /*withFree=*/true);
163167

164168
#ifndef NDEBUG
165169
assert(AreArgumentsValid(result, args, self) && "Invalid args!");
166170
ReportInvokeStart(result, args, self);
167171
#endif // NDEBUG
168-
m_GenericCall(self, args.m_ArgSize, args.m_Args, result);
172+
m_GenericCall(self, args.m_ArgSize, args.m_Args, result, nary);
169173
}
170174
/// Makes a call to a destructor.
171175
///\param[in] object - the pointer of the object whose destructor we call.
@@ -753,20 +757,25 @@ namespace Cpp {
753757
CPPINTEROP_API std::vector<long int> GetDimensions(TCppType_t type);
754758

755759
/// Allocates memory for a given class.
756-
CPPINTEROP_API TCppObject_t Allocate(TCppScope_t scope);
760+
/// \c count is used to indicate the number of objects to allocate for.
761+
CPPINTEROP_API TCppObject_t Allocate(TCppScope_t scope,
762+
TCppIndex_t count = 1UL);
757763

758764
/// Deallocates memory for a given class.
759-
CPPINTEROP_API void Deallocate(TCppScope_t scope, TCppObject_t address);
765+
CPPINTEROP_API void Deallocate(TCppScope_t scope, TCppObject_t address,
766+
TCppIndex_t count = 1UL);
760767

761768
/// Creates an object of class \c scope and calls its default constructor. If
762769
/// \c arena is set it uses placement new.
770+
/// \c count is used to indicate the number of objects to construct.
763771
CPPINTEROP_API TCppObject_t Construct(TCppScope_t scope,
764-
void* arena = nullptr);
772+
void* arena = nullptr,
773+
TCppIndex_t count = 1UL);
765774

766775
/// Calls the destructor of object of type \c type. When withFree is true it
767776
/// calls operator delete/free.
768777
CPPINTEROP_API void Destruct(TCppObject_t This, TCppScope_t type,
769-
bool withFree = true);
778+
bool withFree = true, TCppIndex_t count = 0UL);
770779

771780
/// @name Stream Redirection
772781
///

lib/Interpreter/CXCppInterOp.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -598,25 +598,25 @@ void clang_deallocate(CXObject address) { ::operator delete(address); }
598598

599599
namespace Cpp {
600600
void* Construct(compat::Interpreter& interp, TCppScope_t scope,
601-
void* arena /*=nullptr*/);
601+
void* arena /*=nullptr*/, TCppIndex_t count);
602602
} // namespace Cpp
603603

604-
CXObject clang_construct(CXScope scope, void* arena) {
604+
CXObject clang_construct(CXScope scope, void* arena, size_t count) {
605605
return Cpp::Construct(*getInterpreter(scope),
606-
static_cast<void*>(getDecl(scope)), arena);
606+
static_cast<void*>(getDecl(scope)), arena, count);
607607
}
608608

609609
void clang_invoke(CXScope func, void* result, void** args, size_t n,
610-
void* self) {
610+
size_t nary, void* self) {
611611
Cpp::MakeFunctionCallable(getInterpreter(func), getDecl(func))
612-
.Invoke(result, {args, n}, self);
612+
.Invoke(result, {args, n}, self, nary);
613613
}
614614

615615
namespace Cpp {
616616
void Destruct(compat::Interpreter& interp, TCppObject_t This,
617-
clang::Decl* Class, bool withFree);
617+
clang::Decl* Class, bool withFree, size_t nary);
618618
} // namespace Cpp
619619

620-
void clang_destruct(CXObject This, CXScope S, bool withFree) {
621-
Cpp::Destruct(*getInterpreter(S), This, getDecl(S), withFree);
620+
void clang_destruct(CXObject This, CXScope S, bool withFree, size_t nary) {
621+
Cpp::Destruct(*getInterpreter(S), This, getDecl(S), withFree, nary);
622622
}

lib/Interpreter/CppInterOp.cpp

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,13 +1896,19 @@ namespace Cpp {
18961896
void make_narg_ctor(const FunctionDecl* FD, const unsigned N,
18971897
std::ostringstream& typedefbuf,
18981898
std::ostringstream& callbuf,
1899-
const std::string& class_name, int indent_level) {
1899+
const std::string& class_name, int indent_level,
1900+
bool array = false) {
19001901
// Make a code string that follows this pattern:
19011902
//
19021903
// ClassName(args...)
1904+
// OR
1905+
// ClassName[nary](args...) // array of objects
19031906
//
19041907

1905-
callbuf << class_name << "(";
1908+
callbuf << class_name;
1909+
if (array)
1910+
callbuf << "[nary]";
1911+
callbuf << "(";
19061912
for (unsigned i = 0U; i < N; ++i) {
19071913
const ParmVarDecl* PVD = FD->getParamDecl(i);
19081914
QualType Ty = PVD->getType();
@@ -2085,16 +2091,43 @@ namespace Cpp {
20852091
std::ostringstream& buf, int indent_level) {
20862092
// Make a code string that follows this pattern:
20872093
//
2088-
// (*(ClassName**)ret) = (obj) ?
2089-
// new (*(ClassName**)ret) ClassName(args...) : new ClassName(args...);
2090-
//
2094+
// // array of objects construction
2095+
// if (nary > 1) {
2096+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret)
2097+
// ClassName[nary](args...) : new ClassName[nary](args...);
2098+
// }
2099+
// else {
2100+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret)
2101+
// ClassName(args...) : new ClassName(args...);
2102+
// }
20912103
{
20922104
std::ostringstream typedefbuf;
20932105
std::ostringstream callbuf;
20942106
//
20952107
// Write the return value assignment part.
20962108
//
20972109
indent(callbuf, indent_level);
2110+
callbuf << "if (nary > 1) {\n";
2111+
indent(callbuf, indent_level);
2112+
callbuf << "(*(" << class_name << "**)ret) = ";
2113+
callbuf << "(obj) ? new (*(" << class_name << "**)ret) ";
2114+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2115+
true);
2116+
2117+
callbuf << ": new ";
2118+
//
2119+
// Write the actual expression.
2120+
//
2121+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2122+
true);
2123+
//
2124+
// End the new expression statement.
2125+
//
2126+
callbuf << ";\n";
2127+
indent(callbuf, indent_level);
2128+
callbuf << "}\n";
2129+
callbuf << "else {\n";
2130+
indent(callbuf, indent_level);
20982131
callbuf << "(*(" << class_name << "**)ret) = ";
20992132
callbuf << "(obj) ? new (*(" << class_name << "**)ret) ";
21002133
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
@@ -2108,6 +2141,8 @@ namespace Cpp {
21082141
// End the new expression statement.
21092142
//
21102143
callbuf << ";\n";
2144+
indent(callbuf, --indent_level);
2145+
callbuf << "}\n";
21112146
//
21122147
// Output the whole new expression and return statement.
21132148
//
@@ -2626,7 +2661,8 @@ namespace Cpp {
26262661
"__attribute__((annotate(\"__cling__ptrcheck(off)\")))\n"
26272662
"extern \"C\" void ";
26282663
buf << wrapper_name;
2629-
buf << "(void* obj, int nargs, void** args, void* ret)\n"
2664+
buf << "(void* obj, int nargs, void** args, void* ret, unsigned long "
2665+
"nary)\n"
26302666
"{\n";
26312667
++indent_level;
26322668
if (min_args == num_params) {
@@ -3577,17 +3613,18 @@ namespace Cpp {
35773613
}
35783614
}
35793615

3580-
TCppObject_t Allocate(TCppScope_t scope) {
3581-
return (TCppObject_t)::operator new(Cpp::SizeOf(scope));
3616+
TCppObject_t Allocate(TCppScope_t scope, TCppIndex_t count) {
3617+
return (TCppObject_t)::operator new(Cpp::SizeOf(scope) * count);
35823618
}
35833619

3584-
void Deallocate(TCppScope_t scope, TCppObject_t address) {
3585-
::operator delete(address);
3620+
void Deallocate(TCppScope_t scope, TCppObject_t address, TCppIndex_t count) {
3621+
size_t bytes = Cpp::SizeOf(scope) * count;
3622+
::operator delete(address, bytes);
35863623
}
35873624

35883625
// FIXME: Add optional arguments to the operator new.
35893626
TCppObject_t Construct(compat::Interpreter& interp, TCppScope_t scope,
3590-
void* arena /*=nullptr*/) {
3627+
void* arena /*=nullptr*/, TCppIndex_t count /*=1UL*/) {
35913628
auto* Class = (Decl*) scope;
35923629
// FIXME: Diagnose.
35933630
if (!HasDefaultConstructor(Class))
@@ -3596,7 +3633,8 @@ namespace Cpp {
35963633
auto* const Ctor = GetDefaultConstructor(interp, Class);
35973634
if (JitCall JC = MakeFunctionCallable(&interp, Ctor)) {
35983635
if (arena) {
3599-
JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new.
3636+
JC.Invoke(&arena, {}, (void*)~0,
3637+
count); // Tell Invoke to use placement new.
36003638
return arena;
36013639
}
36023640

@@ -3607,22 +3645,24 @@ namespace Cpp {
36073645
return nullptr;
36083646
}
36093647

3610-
TCppObject_t Construct(TCppScope_t scope, void* arena /*=nullptr*/) {
3611-
return Construct(getInterp(), scope, arena);
3648+
TCppObject_t Construct(TCppScope_t scope, void* arena /*=nullptr*/,
3649+
TCppIndex_t count /*=0UL*/) {
3650+
return Construct(getInterp(), scope, arena, count);
36123651
}
36133652

36143653
void Destruct(compat::Interpreter& interp, TCppObject_t This, Decl* Class,
3615-
bool withFree) {
3654+
bool withFree, TCppIndex_t nary) {
36163655
if (auto wrapper = make_dtor_wrapper(interp, Class)) {
3617-
(*wrapper)(This, /*nary=*/0, withFree);
3656+
(*wrapper)(This, nary, withFree);
36183657
return;
36193658
}
36203659
// FIXME: Diagnose.
36213660
}
36223661

3623-
void Destruct(TCppObject_t This, TCppScope_t scope, bool withFree /*=true*/) {
3662+
void Destruct(TCppObject_t This, TCppScope_t scope, bool withFree /*=true*/,
3663+
TCppIndex_t count /*=1UL*/) {
36243664
auto* Class = static_cast<Decl*>(scope);
3625-
Destruct(getInterp(), This, Class, withFree);
3665+
Destruct(getInterp(), This, Class, withFree, count);
36263666
}
36273667

36283668
class StreamCaptureInfo {

0 commit comments

Comments
 (0)