Skip to content

Commit 1405afe

Browse files
committed
Use array new for codegen in JitCall
1 parent 9da1db4 commit 1405afe

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
@@ -54,6 +54,7 @@
5454

5555
#include <algorithm>
5656
#include <cassert>
57+
#include <cstddef>
5758
#include <deque>
5859
#include <iterator>
5960
#include <map>
@@ -1926,42 +1927,58 @@ void collect_type_info(const FunctionDecl* FD, QualType& QT,
19261927

19271928
void make_narg_ctor(const FunctionDecl* FD, const unsigned N,
19281929
std::ostringstream& typedefbuf, std::ostringstream& callbuf,
1929-
const std::string& class_name, int indent_level) {
1930+
const std::string& class_name, int indent_level,
1931+
bool array = false) {
19301932
// Make a code string that follows this pattern:
19311933
//
19321934
// ClassName(args...)
1935+
// OR
1936+
// ClassName[nary] // array of objects
19331937
//
19341938

1935-
callbuf << class_name << "(";
1936-
for (unsigned i = 0U; i < N; ++i) {
1937-
const ParmVarDecl* PVD = FD->getParamDecl(i);
1938-
QualType Ty = PVD->getType();
1939-
QualType QT = Ty.getCanonicalType();
1940-
std::string type_name;
1941-
EReferenceType refType = kNotReference;
1942-
bool isPointer = false;
1943-
collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
1944-
isPointer, indent_level, true);
1945-
if (i) {
1946-
callbuf << ',';
1947-
if (i % 2) {
1948-
callbuf << ' ';
1939+
if (array)
1940+
callbuf << class_name << "[nary]";
1941+
else
1942+
callbuf << class_name;
1943+
1944+
// We cannot pass initialization parameters if we call array new
1945+
if (N && !array) {
1946+
callbuf << "(";
1947+
for (unsigned i = 0U; i < N; ++i) {
1948+
const ParmVarDecl* PVD = FD->getParamDecl(i);
1949+
QualType Ty = PVD->getType();
1950+
QualType QT = Ty.getCanonicalType();
1951+
std::string type_name;
1952+
EReferenceType refType = kNotReference;
1953+
bool isPointer = false;
1954+
collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
1955+
isPointer, indent_level, true);
1956+
if (i) {
1957+
callbuf << ',';
1958+
if (i % 2) {
1959+
callbuf << ' ';
1960+
} else {
1961+
callbuf << "\n";
1962+
indent(callbuf, indent_level);
1963+
}
1964+
}
1965+
if (refType != kNotReference) {
1966+
callbuf << "(" << type_name.c_str()
1967+
<< (refType == kLValueReference ? "&" : "&&") << ")*("
1968+
<< type_name.c_str() << "*)args[" << i << "]";
1969+
} else if (isPointer) {
1970+
callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
19491971
} else {
1950-
callbuf << "\n";
1951-
indent(callbuf, indent_level + 1);
1972+
callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
19521973
}
19531974
}
1954-
if (refType != kNotReference) {
1955-
callbuf << "(" << type_name.c_str()
1956-
<< (refType == kLValueReference ? "&" : "&&") << ")*("
1957-
<< type_name.c_str() << "*)args[" << i << "]";
1958-
} else if (isPointer) {
1959-
callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
1960-
} else {
1961-
callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
1962-
}
1975+
callbuf << ")";
1976+
}
1977+
// This can be zero or default-initialized
1978+
else if (const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
1979+
CD && CD->isDefaultConstructor() && !array) {
1980+
callbuf << "()";
19631981
}
1964-
callbuf << ")";
19651982
}
19661983

19671984
const DeclContext* get_non_transparent_decl_context(const FunctionDecl* FD) {
@@ -2121,18 +2138,59 @@ void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
21212138
std::ostringstream& buf, int indent_level) {
21222139
// Make a code string that follows this pattern:
21232140
//
2124-
// (*(ClassName**)ret) = (obj) ?
2125-
// new (*(ClassName**)ret) ClassName(args...) : new ClassName(args...);
2126-
//
2141+
// Array new if nary has been passed, and nargs is 0 (must be default ctor)
2142+
// if (nary) {
2143+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary] :
2144+
// new ClassName[nary];
2145+
// }
2146+
// else {
2147+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
2148+
// : new ClassName(args...);
2149+
// }
21272150
{
21282151
std::ostringstream typedefbuf;
21292152
std::ostringstream callbuf;
21302153
//
21312154
// Write the return value assignment part.
21322155
//
21332156
indent(callbuf, indent_level);
2157+
const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
2158+
2159+
// Activate this block only if array new is possible
2160+
// if (nary) {
2161+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary]
2162+
// : new ClassName[nary];
2163+
// }
2164+
// else {
2165+
if (CD->isDefaultConstructor()) {
2166+
callbuf << "if (nary > 1) {\n";
2167+
indent(callbuf, indent_level);
2168+
callbuf << "(*(" << class_name << "**)ret) = ";
2169+
callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
2170+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2171+
true);
2172+
2173+
callbuf << ": new ";
2174+
//
2175+
// Write the actual expression.
2176+
//
2177+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2178+
true);
2179+
//
2180+
// End the new expression statement.
2181+
//
2182+
callbuf << ";\n";
2183+
indent(callbuf, indent_level);
2184+
callbuf << "}\n";
2185+
callbuf << "else {\n";
2186+
}
2187+
2188+
// Standard branch:
2189+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
2190+
// : new ClassName(args...);
2191+
indent(callbuf, indent_level);
21342192
callbuf << "(*(" << class_name << "**)ret) = ";
2135-
callbuf << "(obj) ? new (*(" << class_name << "**)ret) ";
2193+
callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
21362194
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
21372195

21382196
callbuf << ": new ";
@@ -2144,6 +2202,10 @@ void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
21442202
// End the new expression statement.
21452203
//
21462204
callbuf << ";\n";
2205+
indent(callbuf, --indent_level);
2206+
if (CD->isDefaultConstructor())
2207+
callbuf << "}\n";
2208+
21472209
//
21482210
// Output the whole new expression and return statement.
21492211
//
@@ -2652,8 +2714,14 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD,
26522714
"__attribute__((annotate(\"__cling__ptrcheck(off)\")))\n"
26532715
"extern \"C\" void ";
26542716
buf << wrapper_name;
2655-
buf << "(void* obj, int nargs, void** args, void* ret)\n"
2656-
"{\n";
2717+
if (Cpp::IsConstructor(FD)) {
2718+
buf << "(void* ret, unsigned long nary, unsigned long nargs, void** args, "
2719+
"void* is_arena)\n"
2720+
"{\n";
2721+
} else
2722+
buf << "(void* obj, unsigned long nargs, void** args, void* ret)\n"
2723+
"{\n";
2724+
26572725
++indent_level;
26582726
if (min_args == num_params) {
26592727
// No parameters with defaults.

0 commit comments

Comments
 (0)