Skip to content

Change backend name handling #2322

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

Merged
merged 8 commits into from
Apr 28, 2017
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Apr 27, 2017

Change backend name handling to support symbolic names. The idea is to
narrow the interface to names in the backend interface and avoid direct calls
to toString on names.

odersky added 5 commits April 27, 2017 19:15
Needs updated backend

# Conflicts:
#	compiler/src/dotty/tools/dotc/core/Names.scala
Also, fix a discrepancy in the signature of newWeakSet

# Conflicts:
#	scala-backend
Avoid using toString directly.
@odersky odersky changed the title [WIP] Change backend name handling Change backend name handling Apr 27, 2017
@odersky odersky requested review from smarter and DarkDimius April 27, 2017 21:12
@odersky
Copy link
Contributor Author

odersky commented Apr 27, 2017

How did I verify that this works? Starting with 2c4ac2c, I added an assertion that useMangled is false when taking the toString of a name. I had to temporarily reset useMangled in lots of front and middle end code called by the backend, so that in the end only real toString calls from the backend remained. I verified that all unit tests could be run without triggering the assertion.

It's tricky to make this a CI-suitable test though, because it is inherently sequential. Name#toString does not know about the context, so we need a global variable to control the assertion, which is not thread-safe.

So for the moment I submit as is. If toString calls should be introduced in the backend in the future they would likely produce wrong code for symbolic names (once these are in). I am aware that it's a weak barrier against regression. Once we get get parametricity in Any, we can enforce it in the types, so then we will be in the dry.

@smarter
Copy link
Member

smarter commented Apr 28, 2017

It's tricky to make this a CI-suitable test though, because it is inherently sequential. Name#toString does not know about the context, so we need a global variable to control the assertion, which is not thread-safe.

How about doing this instead:

def toString = {
  if (Config.checkBackendNames) {
    assert(!Thread.currentThread.getStackTrace.exists(_.toString.contains("dotty.tools.dotc.backend.jvm.GenBCode"),
      "Backend should not call Name#toString, Name#mangledString should be used instead."))
  }
  // ...
}

@smarter
Copy link
Member

smarter commented Apr 28, 2017

Better way to use getStackTrace:

Thread.currentThread.getStackTrace.exists(_.getClassName == classOf[GenBCode].getName)

Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM

def javaBinaryName: Name = javaClassName.replace('.', '/').toTypeName // TODO: can we make this a string? addModuleSuffix(fullNameInternal('/'))
def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString
def javaSimpleName: String = toDenot(sym).name.mangledString // addModuleSuffix(simpleName.dropLocal)
def javaBinaryName: String = javaClassName.replace('.', '/') // TODO: can we make this a string? addModuleSuffix(fullNameInternal('/'))
Copy link
Member

Choose a reason for hiding this comment

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

This TODO is no longer necessary.

@@ -67,6 +67,7 @@ object Names {
def asSimpleName: SimpleTermName
def toSimpleName: SimpleTermName
def mangled: Name
Copy link
Member

Choose a reason for hiding this comment

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

Would be nice to add some documentation on the meaning/use of mangled.

@odersky
Copy link
Contributor Author

odersky commented Apr 28, 2017

But then we'd have to leave in the ~15 exceptions which allow toString when backend calls something else which requires it (such as .member). Possible but ugly.

// We print the stacktrace instead of doing an assert directly,
// because asserts are caught in exception handlers which might
// cause other failures. In that case the first, important failure
// is lost.
println("Backend should not call Name#toString, Name#mangledString should be used instead.")
Copy link
Member

@smarter smarter Apr 28, 2017

Choose a reason for hiding this comment

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

Use Console.err.println (or System.err.println) instead. printStackTrace will print on stderr, and if you use println right before it which prints on stdout, the output might get mixed.

// We print the stacktrace instead of doing an assert directly,
// because asserts are caught in exception handlers which might
// cause other failures. In that case the first, important failure
// is lost.
println("Backend should not call Name#toString, Name#mangledString should be used instead.")
new Error().printStackTrace()
Copy link
Member

Choose a reason for hiding this comment

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

Nicer way: Thread.dumpStack()

@@ -301,6 +305,9 @@ object Names {
new String(chrs, start, length)
}

/** It's OK to take a toString if the stacktrace does not occur a method
Copy link
Member

Choose a reason for hiding this comment

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

typo: "a method" -> "in a method"
And on the line below: "or it also" -> "or if it also"

!trace.exists(_.getClassName.endsWith("GenBCode")) ||
trace.exists(elem =>
List(
"mangledString",
Copy link
Member

Choose a reason for hiding this comment

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

An alternative to defining a whitelist in this way would be to define a new method named something like unmangledString that does what toString currently do, and have toString forward to it. Then we can just change all the code calling toString to use unmangledString instead, but keep the stacktrace check in toString

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that would affect too many things. Note that most of the whitelist does not call toString directly, sometimes there are 10-20 calls in between.

Copy link
Contributor

@DarkDimius DarkDimius left a comment

Choose a reason for hiding this comment

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

I've left small suggestion to make checkBackendNames into a flag, instead of compile-time constant. I don't think this code is performance critical, given that Dotty doesn't call it much at all and backend only calls it once for every name when generates its own representation.

Dotty-wise looks good enough to me.
Checking stack-trace seems to be robust enough, given that is passes in both boostrapped and non-bootstrapped mode.

* so not suitable for continuous testing. But it can be used to find a problem
* when running a specific test.
*/
final val checkBackendNames = false
Copy link
Contributor

Choose a reason for hiding this comment

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

I would propose to make this configurable as a flag. So that we can ask users to enable checked mode in case something looks very strange in their reports.

Copy link
Contributor Author

@odersky odersky Apr 28, 2017

Choose a reason for hiding this comment

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

Maybe that's a bit paranoid? So far, errors resulting from producing symbolic strings were very easy to diagnose.

@odersky odersky merged commit a447c5b into scala:master Apr 28, 2017
@allanrenucci allanrenucci deleted the change-backend-names branch December 14, 2017 16:58
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.

3 participants