Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Instabilities and Unnecessary Sorting in the Generated Code #3315

Conversation

InsertCreativityHere
Copy link
Member

This PR fixes #3313 and #3205.

All of the instabilities were caused by places where we were calling sort on lists of shared_ptrs, which meant we were sorting things by unstable memory addresses.
Thankfully, all of the sorting we were trying to do in those places was unnecessary and removed.

The two types of sorting which is removed by this PR:

  • We used to sort the exception specifications of operation, so it'd be safe to call unique to remove duplicates.
    But this is useless. The Slice compiler already disallows the same exception to appear twice in an exception specification.
  • We used to sort out operations by name, so it'd be safe to call unique to remove duplicates.
    But again, the Slice compiler issues errors if there's any conflicts, even from inherited names (including diamonds).

One exception:
We still sort our operations by name in C++ because we use a binary search over operation names to perform dispatch.
So we require the names to be alphabetized. We re-use the same list for generating the actual operations and the dispatch, and I just left it alone. It's fine.

@@ -3053,7 +3053,6 @@ Slice::InterfaceDef::allBases() const
{
InterfaceList result = _bases;
result.sort(containedCompare);
result.unique(containedEqual);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is illegal to list the same interface multiple times in an inheritance list, so there's no point to calling unique on _bases here.

@@ -3584,7 +3583,6 @@ Slice::Exception::createDataMember(
checkIdentifier(name); // Don't return here -- we create the data member anyway.

// Check whether any bases have defined a member with the same name already.
ExceptionList bl = allBases();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead variable.

Comment on lines -564 to -565
throws.sort();
throws.unique();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer sort our exception specifications, because there's no point to calling unique.
The Slice compiler already ensures this for us.

// Arrange exceptions into most-derived to least-derived order. If we don't
// do this, a base exception handler can appear before a derived exception
// handler, causing compiler warnings and resulting in the base exception
// being marshaled instead of the derived exception.
//
throws.sort(Slice::DerivedToBaseCompare());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that in the languages, we do still sort them by derived-to-base.
This sorting is stable (it won't re-arrange elements that are 'equal'). And this is necessary to prevent dead catch blocks.

We do this in all compilers except 'ice2slice' (where it's correct not to) and 'slice2php', 'slice2py', and 'slice2rb'.
It is suspicious that we aren't sorting exceptions in those languages.

string ns = getNamespace(p);
string name = getDispatchParams(*i, retS, params, args, ns);
_out << sp << nl << "public abstract " << retS << " " << name << spar << params << epar << ';';
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified this whole block.
But the main change was removing the sorting of OperationPtr that it used to be doing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a review comment from Bernard, I just inlined the simplified version of this function.

// being marshaled instead of the derived exception.
//
throws.sort(Slice::DerivedToBaseCompare());

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code.

@@ -3956,8 +3954,6 @@ Slice::Gen::ProxyVisitor::ProxyVisitor(const string& dir) : JavaVisitor(dir) {}
bool
Slice::Gen::ProxyVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p)
{
const OperationList ops = p->allOperations();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another dead variable...

@@ -2035,7 +2036,6 @@ Slice::Gen::TypeScriptImportVisitor::visitInterfaceDefStart(const InterfaceDefPt
}

// Add imports required for operation parameters and return types.
const OperationList operationList = p->allOperations();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead.

@@ -1713,7 +1713,6 @@ CodeVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p)
const string scoped = p->scoped();
const string abs = getAbsolute(p);
InterfaceList bases = p->bases();
const OperationList allOps = p->allOperations();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead.

Copy link
Member

@bernardnormier bernardnormier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I woud also remove:

allOpNames.unique();

from line 2564 in slice2cpp/Gen.cpp.

@@ -317,26 +317,31 @@ Slice::CsVisitor::writeUnmarshalDataMember(
void
Slice::CsVisitor::writeInheritedOperations(const InterfaceDefPtr& p)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be cleaner to eliminate this helper function (called once) and just call allOperations on the interface in the calling function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to make it too hard to review the changes, but you're right.
I 'inlined' this code, and actually managed to simplify a good chunk of the code around where we called this too.

@InsertCreativityHere
Copy link
Member Author

Originally I left that unique in because I was planning to check out the code around it, because I smelled a bug.
But I went ahead and removed this unique in this PR and just opened an issue for my suspicion:
#3318

@@ -2657,7 +2651,6 @@ Slice::Gen::InterfaceVisitor::visitInterfaceDefEnd(const InterfaceDefPtr& p)
allOpNames.push_back("ice_isA");
allOpNames.push_back("ice_ping");
allOpNames.sort();
allOpNames.unique();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Slice compiler ensures that there are no duplicate operation names, even among inherited operations.

}
}
}
for (const auto& op : allOps)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where writeInheritedOperations was inlined to.

@@ -3223,17 +3177,14 @@ Slice::Gen::DispatcherVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p)
_out << fixId(name);

_out << sb;

for (const auto& op : p->operations())
for (const auto& op : p->allOperations())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we just call allOperations instead of operations followed by writeInheritedOperations.

A side effect of this is that now, the order that we generate operations in is reversed. It used to be Derived -> Base, but now it's Derived -> Base.

@InsertCreativityHere InsertCreativityHere merged commit 8fcf209 into zeroc-ice:main Jan 8, 2025
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

User-Defined Operations are Not Generated in a Stable Ordering with slice2cs
3 participants