Skip to content

Commit 0dd269a

Browse files
committed
Use array new for codegen in JitCall
1 parent dbe7e84 commit 0dd269a

File tree

1 file changed

+101
-33
lines changed

1 file changed

+101
-33
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 101 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353

5454
#include <algorithm>
5555
#include <cassert>
56+
#include <cstddef>
5657
#include <deque>
5758
#include <iterator>
5859
#include <map>
@@ -1914,42 +1915,58 @@ void collect_type_info(const FunctionDecl* FD, QualType& QT,
19141915

19151916
void make_narg_ctor(const FunctionDecl* FD, const unsigned N,
19161917
std::ostringstream& typedefbuf, std::ostringstream& callbuf,
1917-
const std::string& class_name, int indent_level) {
1918+
const std::string& class_name, int indent_level,
1919+
bool array = false) {
19181920
// Make a code string that follows this pattern:
19191921
//
19201922
// ClassName(args...)
1923+
// OR
1924+
// ClassName[nary] // array of objects
19211925
//
19221926

1923-
callbuf << class_name << "(";
1924-
for (unsigned i = 0U; i < N; ++i) {
1925-
const ParmVarDecl* PVD = FD->getParamDecl(i);
1926-
QualType Ty = PVD->getType();
1927-
QualType QT = Ty.getCanonicalType();
1928-
std::string type_name;
1929-
EReferenceType refType = kNotReference;
1930-
bool isPointer = false;
1931-
collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
1932-
isPointer, indent_level, true);
1933-
if (i) {
1934-
callbuf << ',';
1935-
if (i % 2) {
1936-
callbuf << ' ';
1927+
if (array)
1928+
callbuf << class_name << "[nary]";
1929+
else
1930+
callbuf << class_name;
1931+
1932+
// We cannot pass initialization parameters if we call array new
1933+
if (N && !array) {
1934+
callbuf << "(";
1935+
for (unsigned i = 0U; i < N; ++i) {
1936+
const ParmVarDecl* PVD = FD->getParamDecl(i);
1937+
QualType Ty = PVD->getType();
1938+
QualType QT = Ty.getCanonicalType();
1939+
std::string type_name;
1940+
EReferenceType refType = kNotReference;
1941+
bool isPointer = false;
1942+
collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
1943+
isPointer, indent_level, true);
1944+
if (i) {
1945+
callbuf << ',';
1946+
if (i % 2) {
1947+
callbuf << ' ';
1948+
} else {
1949+
callbuf << "\n";
1950+
indent(callbuf, indent_level);
1951+
}
1952+
}
1953+
if (refType != kNotReference) {
1954+
callbuf << "(" << type_name.c_str()
1955+
<< (refType == kLValueReference ? "&" : "&&") << ")*("
1956+
<< type_name.c_str() << "*)args[" << i << "]";
1957+
} else if (isPointer) {
1958+
callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
19371959
} else {
1938-
callbuf << "\n";
1939-
indent(callbuf, indent_level + 1);
1960+
callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
19401961
}
19411962
}
1942-
if (refType != kNotReference) {
1943-
callbuf << "(" << type_name.c_str()
1944-
<< (refType == kLValueReference ? "&" : "&&") << ")*("
1945-
<< type_name.c_str() << "*)args[" << i << "]";
1946-
} else if (isPointer) {
1947-
callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
1948-
} else {
1949-
callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
1950-
}
1963+
callbuf << ")";
1964+
}
1965+
// This can be zero or default-initialized
1966+
else if (const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
1967+
CD && CD->isDefaultConstructor() && !array) {
1968+
callbuf << "()";
19511969
}
1952-
callbuf << ")";
19531970
}
19541971

19551972
const DeclContext* get_non_transparent_decl_context(const FunctionDecl* FD) {
@@ -2108,18 +2125,59 @@ void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
21082125
std::ostringstream& buf, int indent_level) {
21092126
// Make a code string that follows this pattern:
21102127
//
2111-
// (*(ClassName**)ret) = (obj) ?
2112-
// new (*(ClassName**)ret) ClassName(args...) : new ClassName(args...);
2113-
//
2128+
// Array new if nary has been passed, and nargs is 0 (must be default ctor)
2129+
// if (nary) {
2130+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary] :
2131+
// new ClassName[nary];
2132+
// }
2133+
// else {
2134+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
2135+
// : new ClassName(args...);
2136+
// }
21142137
{
21152138
std::ostringstream typedefbuf;
21162139
std::ostringstream callbuf;
21172140
//
21182141
// Write the return value assignment part.
21192142
//
21202143
indent(callbuf, indent_level);
2144+
const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
2145+
2146+
// Activate this block only if array new is possible
2147+
// if (nary) {
2148+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary]
2149+
// : new ClassName[nary];
2150+
// }
2151+
// else {
2152+
if (CD->isDefaultConstructor()) {
2153+
callbuf << "if (nary > 1) {\n";
2154+
indent(callbuf, indent_level);
2155+
callbuf << "(*(" << class_name << "**)ret) = ";
2156+
callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
2157+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2158+
true);
2159+
2160+
callbuf << ": new ";
2161+
//
2162+
// Write the actual expression.
2163+
//
2164+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2165+
true);
2166+
//
2167+
// End the new expression statement.
2168+
//
2169+
callbuf << ";\n";
2170+
indent(callbuf, indent_level);
2171+
callbuf << "}\n";
2172+
callbuf << "else {\n";
2173+
}
2174+
2175+
// Standard branch:
2176+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
2177+
// : new ClassName(args...);
2178+
indent(callbuf, indent_level);
21212179
callbuf << "(*(" << class_name << "**)ret) = ";
2122-
callbuf << "(obj) ? new (*(" << class_name << "**)ret) ";
2180+
callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
21232181
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
21242182

21252183
callbuf << ": new ";
@@ -2131,6 +2189,10 @@ void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
21312189
// End the new expression statement.
21322190
//
21332191
callbuf << ";\n";
2192+
indent(callbuf, --indent_level);
2193+
if (CD->isDefaultConstructor())
2194+
callbuf << "}\n";
2195+
21342196
//
21352197
// Output the whole new expression and return statement.
21362198
//
@@ -2643,8 +2705,14 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD,
26432705
"__attribute__((annotate(\"__cling__ptrcheck(off)\")))\n"
26442706
"extern \"C\" void ";
26452707
buf << wrapper_name;
2646-
buf << "(void* obj, int nargs, void** args, void* ret)\n"
2647-
"{\n";
2708+
if (Cpp::IsConstructor(FD)) {
2709+
buf << "(void* ret, unsigned long nary, unsigned long nargs, void** args, "
2710+
"void* is_arena)\n"
2711+
"{\n";
2712+
} else
2713+
buf << "(void* obj, unsigned long nargs, void** args, void* ret)\n"
2714+
"{\n";
2715+
26482716
++indent_level;
26492717
if (min_args == num_params) {
26502718
// No parameters with defaults.

0 commit comments

Comments
 (0)