Skip to content

Commit f2b0b48

Browse files
committed
Use array new for codegen in JitCall
1 parent ee6e034 commit f2b0b48

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>
@@ -1920,42 +1921,58 @@ void collect_type_info(const FunctionDecl* FD, QualType& QT,
19201921

19211922
void make_narg_ctor(const FunctionDecl* FD, const unsigned N,
19221923
std::ostringstream& typedefbuf, std::ostringstream& callbuf,
1923-
const std::string& class_name, int indent_level) {
1924+
const std::string& class_name, int indent_level,
1925+
bool array = false) {
19241926
// Make a code string that follows this pattern:
19251927
//
19261928
// ClassName(args...)
1929+
// OR
1930+
// ClassName[nary] // array of objects
19271931
//
19281932

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

19611978
const DeclContext* get_non_transparent_decl_context(const FunctionDecl* FD) {
@@ -2114,18 +2131,59 @@ void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
21142131
std::ostringstream& buf, int indent_level) {
21152132
// Make a code string that follows this pattern:
21162133
//
2117-
// (*(ClassName**)ret) = (obj) ?
2118-
// new (*(ClassName**)ret) ClassName(args...) : new ClassName(args...);
2119-
//
2134+
// Array new if nary has been passed, and nargs is 0 (must be default ctor)
2135+
// if (nary) {
2136+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary] :
2137+
// new ClassName[nary];
2138+
// }
2139+
// else {
2140+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
2141+
// : new ClassName(args...);
2142+
// }
21202143
{
21212144
std::ostringstream typedefbuf;
21222145
std::ostringstream callbuf;
21232146
//
21242147
// Write the return value assignment part.
21252148
//
21262149
indent(callbuf, indent_level);
2150+
const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
2151+
2152+
// Activate this block only if array new is possible
2153+
// if (nary) {
2154+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary]
2155+
// : new ClassName[nary];
2156+
// }
2157+
// else {
2158+
if (CD->isDefaultConstructor()) {
2159+
callbuf << "if (nary > 1) {\n";
2160+
indent(callbuf, indent_level);
2161+
callbuf << "(*(" << class_name << "**)ret) = ";
2162+
callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
2163+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2164+
true);
2165+
2166+
callbuf << ": new ";
2167+
//
2168+
// Write the actual expression.
2169+
//
2170+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2171+
true);
2172+
//
2173+
// End the new expression statement.
2174+
//
2175+
callbuf << ";\n";
2176+
indent(callbuf, indent_level);
2177+
callbuf << "}\n";
2178+
callbuf << "else {\n";
2179+
}
2180+
2181+
// Standard branch:
2182+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
2183+
// : new ClassName(args...);
2184+
indent(callbuf, indent_level);
21272185
callbuf << "(*(" << class_name << "**)ret) = ";
2128-
callbuf << "(obj) ? new (*(" << class_name << "**)ret) ";
2186+
callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
21292187
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
21302188

21312189
callbuf << ": new ";
@@ -2137,6 +2195,10 @@ void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
21372195
// End the new expression statement.
21382196
//
21392197
callbuf << ";\n";
2198+
indent(callbuf, --indent_level);
2199+
if (CD->isDefaultConstructor())
2200+
callbuf << "}\n";
2201+
21402202
//
21412203
// Output the whole new expression and return statement.
21422204
//
@@ -2651,8 +2713,14 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD,
26512713
"__attribute__((annotate(\"__cling__ptrcheck(off)\")))\n"
26522714
"extern \"C\" void ";
26532715
buf << wrapper_name;
2654-
buf << "(void* obj, int nargs, void** args, void* ret)\n"
2655-
"{\n";
2716+
if (Cpp::IsConstructor(FD)) {
2717+
buf << "(void* ret, unsigned long nary, unsigned long nargs, void** args, "
2718+
"void* is_arena)\n"
2719+
"{\n";
2720+
} else
2721+
buf << "(void* obj, unsigned long nargs, void** args, void* ret)\n"
2722+
"{\n";
2723+
26562724
++indent_level;
26572725
if (min_args == num_params) {
26582726
// No parameters with defaults.

0 commit comments

Comments
 (0)