Skip to content

Commit 56e27b7

Browse files
committed
Add array new for ctor codegen in JitCall
1 parent 81a81ba commit 56e27b7

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>
@@ -1902,42 +1903,58 @@ void collect_type_info(const FunctionDecl* FD, QualType& QT,
19021903

19031904
void make_narg_ctor(const FunctionDecl* FD, const unsigned N,
19041905
std::ostringstream& typedefbuf, std::ostringstream& callbuf,
1905-
const std::string& class_name, int indent_level) {
1906+
const std::string& class_name, int indent_level,
1907+
bool array = false) {
19061908
// Make a code string that follows this pattern:
19071909
//
19081910
// ClassName(args...)
1911+
// OR
1912+
// ClassName[nary] // array of objects
19091913
//
19101914

1911-
callbuf << class_name << "(";
1912-
for (unsigned i = 0U; i < N; ++i) {
1913-
const ParmVarDecl* PVD = FD->getParamDecl(i);
1914-
QualType Ty = PVD->getType();
1915-
QualType QT = Ty.getCanonicalType();
1916-
std::string type_name;
1917-
EReferenceType refType = kNotReference;
1918-
bool isPointer = false;
1919-
collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
1920-
isPointer, indent_level, true);
1921-
if (i) {
1922-
callbuf << ',';
1923-
if (i % 2) {
1924-
callbuf << ' ';
1915+
if (array)
1916+
callbuf << class_name << "[nary]";
1917+
else
1918+
callbuf << class_name;
1919+
1920+
// We cannot pass initialization parameters if we call array new
1921+
if (N && !array) {
1922+
callbuf << "(";
1923+
for (unsigned i = 0U; i < N; ++i) {
1924+
const ParmVarDecl* PVD = FD->getParamDecl(i);
1925+
QualType Ty = PVD->getType();
1926+
QualType QT = Ty.getCanonicalType();
1927+
std::string type_name;
1928+
EReferenceType refType = kNotReference;
1929+
bool isPointer = false;
1930+
collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
1931+
isPointer, indent_level, true);
1932+
if (i) {
1933+
callbuf << ',';
1934+
if (i % 2) {
1935+
callbuf << ' ';
1936+
} else {
1937+
callbuf << "\n";
1938+
indent(callbuf, indent_level);
1939+
}
1940+
}
1941+
if (refType != kNotReference) {
1942+
callbuf << "(" << type_name.c_str()
1943+
<< (refType == kLValueReference ? "&" : "&&") << ")*("
1944+
<< type_name.c_str() << "*)args[" << i << "]";
1945+
} else if (isPointer) {
1946+
callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
19251947
} else {
1926-
callbuf << "\n";
1927-
indent(callbuf, indent_level + 1);
1948+
callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
19281949
}
19291950
}
1930-
if (refType != kNotReference) {
1931-
callbuf << "(" << type_name.c_str()
1932-
<< (refType == kLValueReference ? "&" : "&&") << ")*("
1933-
<< type_name.c_str() << "*)args[" << i << "]";
1934-
} else if (isPointer) {
1935-
callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
1936-
} else {
1937-
callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
1938-
}
1951+
callbuf << ")";
1952+
}
1953+
// This can be zero or default-initialized
1954+
else if (auto* CD = dyn_cast<CXXConstructorDecl>(FD);
1955+
CD && CD->isDefaultConstructor() && !array) {
1956+
callbuf << "()";
19391957
}
1940-
callbuf << ")";
19411958
}
19421959

19431960
const DeclContext* get_non_transparent_decl_context(const FunctionDecl* FD) {
@@ -2095,18 +2112,59 @@ void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
20952112
std::ostringstream& buf, int indent_level) {
20962113
// Make a code string that follows this pattern:
20972114
//
2098-
// (*(ClassName**)ret) = (obj) ?
2099-
// new (*(ClassName**)ret) ClassName(args...) : new ClassName(args...);
2100-
//
2115+
// Array new if nary has been passed, and nargs is 0 (must be default ctor)
2116+
// if (nary) {
2117+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary] :
2118+
// new ClassName[nary];
2119+
// }
2120+
// else {
2121+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
2122+
// : new ClassName(args...);
2123+
// }
21012124
{
21022125
std::ostringstream typedefbuf;
21032126
std::ostringstream callbuf;
21042127
//
21052128
// Write the return value assignment part.
21062129
//
21072130
indent(callbuf, indent_level);
2131+
const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
2132+
2133+
// Activate this block only if array new is possible
2134+
// if (nary) {
2135+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary]
2136+
// : new ClassName[nary];
2137+
// }
2138+
// else {
2139+
if (CD->isDefaultConstructor()) {
2140+
callbuf << "if (nary > 1) {\n";
2141+
indent(callbuf, indent_level);
2142+
callbuf << "(*(" << class_name << "**)ret) = ";
2143+
callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
2144+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2145+
true);
2146+
2147+
callbuf << ": new ";
2148+
//
2149+
// Write the actual expression.
2150+
//
2151+
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
2152+
true);
2153+
//
2154+
// End the new expression statement.
2155+
//
2156+
callbuf << ";\n";
2157+
indent(callbuf, indent_level);
2158+
callbuf << "}\n";
2159+
callbuf << "else {\n";
2160+
}
2161+
2162+
// Standard branch:
2163+
// (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
2164+
// : new ClassName(args...);
2165+
indent(callbuf, indent_level);
21082166
callbuf << "(*(" << class_name << "**)ret) = ";
2109-
callbuf << "(obj) ? new (*(" << class_name << "**)ret) ";
2167+
callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
21102168
make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
21112169

21122170
callbuf << ": new ";
@@ -2118,6 +2176,10 @@ void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
21182176
// End the new expression statement.
21192177
//
21202178
callbuf << ";\n";
2179+
indent(callbuf, --indent_level);
2180+
if (CD->isDefaultConstructor())
2181+
callbuf << "}\n";
2182+
21212183
//
21222184
// Output the whole new expression and return statement.
21232185
//
@@ -2630,8 +2692,14 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD,
26302692
"__attribute__((annotate(\"__cling__ptrcheck(off)\")))\n"
26312693
"extern \"C\" void ";
26322694
buf << wrapper_name;
2633-
buf << "(void* obj, int nargs, void** args, void* ret)\n"
2634-
"{\n";
2695+
if (Cpp::IsConstructor(FD)) {
2696+
buf << "(void* ret, unsigned long nary, unsigned long nargs, void** args, "
2697+
"void* is_arena)\n"
2698+
"{\n";
2699+
} else
2700+
buf << "(void* obj, unsigned long nargs, void** args, void* ret)\n"
2701+
"{\n";
2702+
26352703
++indent_level;
26362704
if (min_args == num_params) {
26372705
// No parameters with defaults.

0 commit comments

Comments
 (0)