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

Emit efficient code for switch over strings #11937

Merged
merged 1 commit into from Aug 24, 2021

Conversation

harpocrates
Copy link
Contributor

The pattern matcher will now emit Match with String scrutinee as
well as the existing Int scrutinee. The JVM backend handles this case
by emitting bytecode that switches on the String's hashCode (this
matches what Java does). The SJS already handles String matches.

The approach is similar to scala/scala#8451 (see scala/bug#11740 too),
except that instead of doing a transformation on the AST, we just emit the
right bytecode straight away. This is desirable since it means that
Scala.js (and any other backend) can choose their own optimised strategy
for compiling a match on strings.

Fixes #11923

@smarter smarter requested a review from sjrd March 29, 2021 15:47
@harpocrates
Copy link
Contributor Author

I'm not sure how to make tests that check the backend code generation, in order to assert that we really do end up seeing a lookupswitch/tableswitch for the JVM and a switch for JS. I see the initial Scala 2 patch included such a test but I don't see anything of the sort to serve as inspiration in Scala 3. Any pointers to existing similar tests would be most welcome!

@smarter
Copy link
Member

smarter commented Mar 29, 2021

Bytecode tests usually go in https://github.com/lampepfl/dotty/blob/master/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala which makes use of https://github.com/lampepfl/dotty/blob/master/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTest.scala which defines a verifySwitch method you could try to reuse.

@sjrd
Copy link
Member

sjrd commented Mar 29, 2021

I'm not sure how to make tests that check the backend code generation, in order to assert that we really do end up seeing a lookupswitch/tableswitch for the JVM and a switch for JS.

For JS you won't be able to assert that, because in fact Scala.js 1.x has no way to represent switches on Strings in its IR. So they are compiled as if/else chains at the moment. There is an issue upstream to address that (scala-js/scala-js#3843), but it need not concern you here for now.

* On a second pass, we emit the switch blocks, one for each different target.
/* A Match node contains one or more case clauses, each case clause lists one or more
* Int/String values to use as keys, and a code block. The exception is the "default" case
* clause which doesn't list any key (there is exactly one of these per match).
*/
private def genMatch(tree: Match): BType = tree match {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that the bytecode this generates ends up having a number of bogus goto,nop,..,nop,athrow sequences in it. Scala 2 doesn't have these because it does some extra dead-code elimination to clean up junk like this (the extra instructions are produced by ClassWriter). I hope to get around to that at some point, but likely not in this PR.

Copy link
Member

@dwijnand dwijnand left a comment

Choose a reason for hiding this comment

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

This is a long one to review, so this is just a first comment from what I looked at.

@bishabosha bishabosha assigned dwijnand and unassigned sjrd Aug 2, 2021
@bishabosha
Copy link
Member

bishabosha commented Aug 18, 2021

Hey @harpocrates do you need any more help with this?, a rebase should fix the CI failure

The pattern matcher will now emit `Match` with `String` scrutinee as
well as the existing `Int` scrutinee. The JVM backend handles this case
by emitting bytecode that switches on the String's `hashCode` (this
matches what Java does). The SJS already handles `String` matches.

The approach is similar to scala/scala#8451 (see scala/bug#11740 too),
except that instead of doing a transformation on the AST, we just emit the
right bytecode straight away. This is desirable since it means that
Scala.js (and any other backend) can choose their own optimised strategy
for compiling a match on strings.

Fixes scala#11923
@harpocrates
Copy link
Contributor Author

@bishabosha I don't think there is anything else I'm supposed to do - this is just waiting on a review.

I just rebased (and flattened the uninteresting history). I did not realize anything was waiting on that - thank you for the ping!

@bishabosha bishabosha merged commit 633f896 into scala:master Aug 24, 2021
@bishabosha bishabosha added the release-notes Should be mentioned in the release notes label Aug 24, 2021
@bishabosha
Copy link
Member

I think it would be nice to include a few sentences about this in the release notes

@dwijnand dwijnand removed their request for review August 26, 2021 09:22
@dwijnand dwijnand removed their assignment Aug 26, 2021
@Kordyjan Kordyjan added this to the 3.1.0 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-notes Should be mentioned in the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Matching strings should emit switches (as in Scala 2)
6 participants