Skip to content

avoid duplicate call to dist/bin/common via refactored scalac #12197

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 10 commits into from
Apr 27, 2021
Merged
5 changes: 2 additions & 3 deletions compiler/test-resources/repl/defaultClassloader
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
scala> val d: java.sql.Date = new java.sql.Date(100L)
val d: java.sql.Date = 1970-01-01

scala> val d: Long = (new java.sql.Date(100L)).getTime
val d: Long = 100
4 changes: 3 additions & 1 deletion compiler/test/dotty/tools/scripting/ClasspathTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ClasspathTests:
val packBinDir = "dist/target/pack/bin"
val scalaCopy = makeTestableScriptCopy("scala")
val scalacCopy = makeTestableScriptCopy("scalac")
val commonCopy = makeTestableScriptCopy("common")

// only interested in classpath test scripts
def testFiles = scripts("/scripting").filter { _.getName.matches("classpath.*[.]sc") }
Expand All @@ -38,7 +39,8 @@ class ClasspathTests:
if Files.exists(scriptPath) then
val lines = Files.readAllLines(scriptPath).asScala.map {
_.replaceAll("/scalac", "/scalac-copy").
replaceFirst("^eval(.*JAVACMD.*)", "echo $1")
replaceAll("/common", "/common-copy").
replaceFirst("^ *eval(.*JAVACMD.*)", "echo $1")
}
val bytes = (lines.mkString("\n")+"\n").getBytes
Files.write(scriptCopy, bytes)
Expand Down
105 changes: 98 additions & 7 deletions dist/bin/common
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ case "`uname`" in
esac

unset CYGPATHCMD
if [[ $cygwin || $mingw || $msys ]]; then
if [[ ${cygwin-} || ${mingw-} || ${msys-} ]]; then
# ConEmu terminal is incompatible with jna-5.*.jar
[[ ($CONEMUANSI || $ConEmuANSI) ]] && conemu=true
[[ (${CONEMUANSI-} || ${ConEmuANSI-}) ]] && conemu=true
# cygpath is used by various windows shells: cygwin, git-sdk, gitbash, msys, etc.
CYGPATHCMD=`which cygpath 2>/dev/null`
case "$TERM" in
rxvt* | xterm* | cygwin*)
stty -icanon min 1 -echo
SCALA_OPTS="$SCALA_OPTS -Djline.terminal=unix"
JAVA_OPTS="$JAVA_OPTS -Djline.terminal=unix"
;;
esac
fi
Expand Down Expand Up @@ -111,14 +111,14 @@ CLASSPATH_SUFFIX=""
PSEP=":"

# translate paths to Windows-mixed format before running java
if [ -n "$CYGPATHCMD" ]; then
[ -n "$PROG_HOME" ] &&
if [ -n "${CYGPATHCMD-}" ]; then
[ -n "${PROG_HOME-}" ] &&
PROG_HOME=`"$CYGPATHCMD" -am "$PROG_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`"$CYGPATHCMD" -am "$JAVA_HOME"`
CLASSPATH_SUFFIX=";"
PSEP=";"
elif [[ $mingw || $msys ]]; then
elif [[ ${mingw-} || ${msys-} ]]; then
# For Mingw / Msys, convert paths from UNIX format before anything is touched
[ -n "$PROG_HOME" ] &&
PROG_HOME="`(cd "$PROG_HOME"; pwd -W | sed 's|/|\\\\|g')`"
Expand Down Expand Up @@ -155,8 +155,99 @@ SBT_INTF=$(find_lib "*compiler-interface*")
JLINE_READER=$(find_lib "*jline-reader-3*")
JLINE_TERMINAL=$(find_lib "*jline-terminal-3*")
JLINE_TERMINAL_JNA=$(find_lib "*jline-terminal-jna-3*")
[[ $conemu ]] || JNA=$(find_lib "*jna-5*")
[[ ${conemu-} ]] || JNA=$(find_lib "*jna-5*")

# debug

DEBUG_STR=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005

classpathArgs () {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe rename it to reflect that it's used for the compiler JVM?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@liufengyun - good idea. I didn't see this until after I pushed changes, so we'll have to do that when we update the two other calls to bin/scalac.

# echo "dotty-compiler: $DOTTY_COMP"
# echo "dotty-interface: $DOTTY_INTF"
# echo "dotty-library: $DOTTY_LIB"
# echo "tasty-core: $TASTY_CORE"
# echo "scala-asm: $SCALA_ASM"
# echo "scala-lib: $SCALA_LIB"
# echo "sbt-intface: $SBT_INTF"

toolchain=""
toolchain+="$SCALA_LIB$PSEP"
toolchain+="$DOTTY_LIB$PSEP"
toolchain+="$SCALA_ASM$PSEP"
toolchain+="$SBT_INTF$PSEP"
toolchain+="$DOTTY_INTF$PSEP"
toolchain+="$DOTTY_COMP$PSEP"
toolchain+="$TASTY_CORE$PSEP"
toolchain+="$DOTTY_STAGING$PSEP"
toolchain+="$DOTTY_TASTY_INSPECTOR$PSEP"

# jine
toolchain+="$JLINE_READER$PSEP"
toolchain+="$JLINE_TERMINAL$PSEP"
toolchain+="$JLINE_TERMINAL_JNA$PSEP"
toolchain+="$JNA$PSEP"

if [ -n "$jvm_cp_args" ]; then
jvm_cp_args="$toolchain$jvm_cp_args"
else
jvm_cp_args="$toolchain$PSEP"
fi
}

default_java_opts="-Xmx768m -Xms768m"

CompilerMain=dotty.tools.dotc.Main
DecompilerMain=dotty.tools.dotc.decompiler.Main
ReplMain=dotty.tools.repl.Main
ScriptingMain=dotty.tools.scripting.Main

addJava () {
java_args+=("'$1'")
}
addScala () {
scala_args+=("'$1'")
}
addResidual () {
residual_args+=("'$1'")
}
addScripting () {
scripting_args+=("'$1'")
}
prepScalacCommandLine () {
withCompiler=true

while [[ $# -gt 0 ]]; do
case "$1" in
--) shift; for arg; do addResidual "$arg"; done; set -- ;;
-v|-verbose) verbose=true && addScala "-verbose" && shift ;;
-debug) DEBUG="$DEBUG_STR" && shift ;;
-q|-quiet) quiet=true && shift ;;

# Optimize for short-running applications, see https://github.com/lampepfl/dotty/issues/222
-Oshort) addJava "-XX:+TieredCompilation -XX:TieredStopAtLevel=1" && shift ;;
-repl) PROG_NAME="$ReplMain" && shift ;;
-script) PROG_NAME="$ScriptingMain" && target_script="$2" && shift && shift
while [[ $# -gt 0 ]]; do addScripting "$1" && shift ; done ;;
-compile) PROG_NAME="$CompilerMain" && shift ;;
-decompile) PROG_NAME="$DecompilerMain" && shift ;;
-print-tasty) PROG_NAME="$DecompilerMain" && addScala "-print-tasty" && shift ;;
-run) PROG_NAME="$ReplMain" && shift ;;
-colors) colors=true && shift ;;
-no-colors) unset colors && shift ;;
-with-compiler) jvm_cp_args="$PSEP$DOTTY_COMP$PSEP$TASTY_CORE" && shift ;;

# break out -D and -J options and add them to java_args so
# they reach the JVM in time to do some good. The -D options
# will be available as system properties.
-D*) addJava "$1" && shift ;;
-J*) addJava "${1:2}" && shift ;;
*) addResidual "$1" && shift ;;
esac
done

classpathArgs

if [ "$PROG_NAME" == "$ScriptingMain" ]; then
scripting_string="-script $target_script ${scripting_args[@]}"
fi
}
51 changes: 36 additions & 15 deletions dist/bin/scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#!/usr/bin/env bash

# Try to autodetect real location of the script

if [ -z "$PROG_HOME" ] ; then
if [ -z "${PROG_HOME-}" ] ; then
## resolve links - $0 may be a link to PROG_HOME
PRG="$0"

Expand All @@ -27,8 +26,8 @@ if [ -z "$PROG_HOME" ] ; then
cd "$saveddir"
fi

addJvmOptions () {
jvm_options+=("'$1'")
addJava () {
java_args+=("'$1'")
}

addScalacOptions () {
Expand Down Expand Up @@ -65,7 +64,7 @@ while [[ $# -gt 0 ]]; do
execute_run=true
shift
;;
-cp | -classpath )
-cp | -classpath)
CLASS_PATH="$2${PSEP}"
class_path_count+=1
shift
Expand Down Expand Up @@ -100,23 +99,33 @@ while [[ $# -gt 0 ]]; do
;;
-version)
# defer to scalac, then exit
addScalacOptions "${1}"
shift
eval "\"$PROG_HOME/bin/scalac\" ${cp_arg-} ${java_options[@]}"
eval "\"$PROG_HOME/bin/scalac\" -version"
scala_exit_status=$?
onExit
;;
-J*)
addJvmOptions "${1:2}"
addJava "${1:2}"
addScalacOptions "${1}"
shift ;;
*)
if [ $execute_script == false ]; then
# is a script if extension .scala or .sc or if has scala hash bang
if [[ -e "$1" && ("$1" == *.scala || "$1" == *.sc || -f "$1" && `head -n 1 -- "$1" | grep '#!.*scala'`) ]]; then
if [[ "$1" == *.scala || "$1" == *.sc ]]; then
# is a script if extension .scala or .sc
# (even if file not found, to avoid adding likely typo to residual_args)
execute_script=true
target_script="$1"
elif [[ (-f "$1" && `head -n 1 -- "$1" | grep '#!.*scala'`) ]]; then
execute_script=true
target_script="$1"
if [ ! -f $target_script ]; then
# likely a typo or missing script file, quit early
echo "not found: $target_script" 1>&2
scala_exit_status=2
onExit
fi
else
# unrecognized args appearing prior to a script name
residual_args+=("$1")
fi
else
Expand All @@ -128,8 +137,8 @@ while [[ $# -gt 0 ]]; do
esac
done

[ -n "${script_trace-}" ] && set -x
if [ $execute_script == true ]; then
[ -n "${script_trace-}" ] && set -x
if [ "$CLASS_PATH" ]; then
cp_arg="-classpath \"$CLASS_PATH\""
fi
Expand All @@ -141,8 +150,20 @@ if [ $execute_script == true ]; then
scala_exit_status=$?
else
[[ $save_compiled == true ]] && rm -f $target_jar
residual_args+=($setScriptName)
eval "\"$PROG_HOME/bin/scalac\" ${cp_arg-} ${java_options[@]} ${residual_args[@]} -script $target_script ${script_args[@]}"
set -- ${cp_arg-} ${java_options[@]} ${residual_args[@]} -script "$target_script" ${script_args[@]}
PROG_MAIN=$ScriptingMain
prepScalacCommandLine "$@"
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering what arguments are expected to be parsed here? If it's only 1 or 2, can we do it in bin/scala instead?

Copy link
Contributor Author

@philwalk philwalk Apr 23, 2021

Choose a reason for hiding this comment

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

I considered trying to do a less extensive change, but ran into problems.

One concern is has to do with alternate ways for launching a script. The following two command lines are currently supported valid ways to launch a script:

scala hello.sc
scalac -script hello.sc

These and other similar issues are tested in project/scripts/winCmdTests, and possibly elsewhere.

My assumption is that we want a functionally neutral refactoring, so scripts should use the same default values, for example default_java_opts="-Xmx768m -Xms768m"

They should leverage a single toolchain classpath, and should have access to and respond the same way to scalac options such as -Oshort, for example. So most of what happens in bin/scalac is needed to produce a functionally equivalent java command line.

Anyway, that's what led me to the current implementation, which can no doubt be improved in various ways.

Copy link
Contributor

Choose a reason for hiding this comment

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

scalac -script hello.sc

I am not sure if Scala 2 supports the above. If not, I think it does not have to be supported.

My assumption is that we want a functionally neutral refactoring, so scripts should use the same default values, for example default_java_opts="-Xmx768m -Xms768m"

This can be either duplicated or moved to bin/common -- maybe duplicating it is easier for maintenance.

They should leverage a single toolchain classpath, and should have access to and respond the same way to scalac options such as -Oshort, for example. So most of what happens in bin/scalac is needed to produce a functionally equivalent java command line.

Given that bin/scala already parses many options that bin/scalac parses, it does not matter to parse 1-2 more options.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Given that bin/scala already parses many options that bin/scalac parses, it does not matter to parse 1-2 more options.

Okay, I see what you have in mind. I'll will review it again.

I am not sure if Scala 2 supports the above. If not, I think it does not have to be supported.

I don't think it's supported by scala 2, although both ways of launching the script must provide -script <scriptname> on the generated java command line, because compiler/src/dotty/tools/scripting/Main.scala line 12 uses it to distinguish jvm parameters from script filename and args.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@liufengyun
Is your idea that we move the command line parsing from bin/common back to bin/scalac and selectively duplicate some of the needed parsing in bin/scala ?

# exec here would prevent onExit from being called, leaving terminal in unusable state
eval "\"$JAVACMD\"" \
${JAVA_OPTS:-$default_java_opts} \
"${DEBUG-}" \
"${java_args[@]}" \
"-classpath \"$jvm_cp_args\"" \
-Dscala.usejavacp=true \
"$PROG_NAME" \
"${scala_args[@]}" \
"${residual_args[@]}" \
"${scripting_string-}"
scala_exit_status=$?
fi
elif [ $execute_repl == true ] || ([ $execute_run == false ] && [ $options_indicator == 0 ]); then
Expand All @@ -151,7 +172,7 @@ elif [ $execute_repl == true ] || ([ $execute_run == false ] && [ $options_indic
fi
eval "\"$PROG_HOME/bin/scalac\" ${cp_arg-} ${java_options[@]} -repl ${residual_args[@]}"
scala_exit_status=$?
elif [ $execute_repl == true ] || [ ${#residual_args[@]} -ne 0 ]; then
elif [ ${#residual_args[@]} -ne 0 ]; then
cp_arg="$DOTTY_LIB$PSEP$SCALA_LIB"
if [ -z "$CLASS_PATH" ]; then
cp_arg+="$PSEP."
Expand All @@ -165,7 +186,7 @@ elif [ $execute_repl == true ] || [ ${#residual_args[@]} -ne 0 ]; then
cp_arg+="$PSEP$DOTTY_COMP$PSEP$TASTY_CORE$PSEP$DOTTY_INTF$PSEP$SCALA_ASM$PSEP$DOTTY_STAGING$PSEP$DOTTY_TASTY_INSPECTOR"
fi
# exec here would prevent onExit from being called, leaving terminal in unusable state
eval "\"$JAVACMD\"" "$DEBUG" "-classpath \"$cp_arg\"" "${jvm_options[@]}" "${residual_args[@]}"
eval "\"$JAVACMD\"" "$DEBUG" "-classpath \"$cp_arg\"" "${java_args[@]}" "${residual_args[@]}"
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the refactoring 👍

scala_exit_status=$?
else
echo "warning: command option is not correct."
Expand Down
96 changes: 8 additions & 88 deletions dist/bin/scalac
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env bash

if [ -z "$PROG_HOME" ] ; then
# Try to autodetect real location of the script
if [ -z "${PROG_HOME-}" ] ; then
## resolve links - $0 may be a link to PROG_HOME
PRG="$0"

Expand All @@ -27,102 +28,21 @@ fi

source "$PROG_HOME/bin/common"

default_java_opts="-Xmx768m -Xms768m"
withCompiler=true
[ -z "$PROG_NAME" ] && PROG_NAME=$CompilerMain

CompilerMain=dotty.tools.dotc.Main
DecompilerMain=dotty.tools.dotc.decompiler.Main
ReplMain=dotty.tools.repl.Main
ScriptingMain=dotty.tools.scripting.Main

PROG_NAME=$CompilerMain

addJava () {
java_args+=("'$1'")
}
addScala () {
scala_args+=("'$1'")
}
addResidual () {
residual_args+=("'$1'")
}
addScripting () {
scripting_args+=("'$1'")
}

classpathArgs () {
# echo "dotty-compiler: $DOTTY_COMP"
# echo "dotty-interface: $DOTTY_INTF"
# echo "dotty-library: $DOTTY_LIB"
# echo "tasty-core: $TASTY_CORE"
# echo "scala-asm: $SCALA_ASM"
# echo "scala-lib: $SCALA_LIB"
# echo "sbt-intface: $SBT_INTF"

toolchain=""
toolchain+="$SCALA_LIB$PSEP"
toolchain+="$DOTTY_LIB$PSEP"
toolchain+="$SCALA_ASM$PSEP"
toolchain+="$SBT_INTF$PSEP"
toolchain+="$DOTTY_INTF$PSEP"
toolchain+="$DOTTY_COMP$PSEP"
toolchain+="$TASTY_CORE$PSEP"
toolchain+="$DOTTY_STAGING$PSEP"
toolchain+="$DOTTY_TASTY_INSPECTOR$PSEP"

# jine
toolchain+="$JLINE_READER$PSEP"
toolchain+="$JLINE_TERMINAL$PSEP"
toolchain+="$JLINE_TERMINAL_JNA$PSEP"
toolchain+="$JNA$PSEP"

jvm_cp_args="-classpath \"$toolchain\""
}

while [[ $# -gt 0 ]]; do
case "$1" in
--) shift; for arg; do addResidual "$arg"; done; set -- ;;
-v|-verbose) verbose=true && addScala "-verbose" && shift ;;
-debug) DEBUG="$DEBUG_STR" && shift ;;
-q|-quiet) quiet=true && shift ;;

# Optimize for short-running applications, see https://github.com/lampepfl/dotty/issues/222
-Oshort) addJava "-XX:+TieredCompilation -XX:TieredStopAtLevel=1" && shift ;;
-repl) PROG_NAME="$ReplMain" && shift ;;
-script) PROG_NAME="$ScriptingMain" && target_script="$2" && shift && shift
while [[ $# -gt 0 ]]; do addScripting "$1" && shift ; done ;;
-compile) PROG_NAME="$CompilerMain" && shift ;;
-decompile) PROG_NAME="$DecompilerMain" && shift ;;
-print-tasty) PROG_NAME="$DecompilerMain" && addScala "-print-tasty" && shift ;;
-run) PROG_NAME="$ReplMain" && shift ;;
-colors) colors=true && shift ;;
-no-colors) unset colors && shift ;;
-with-compiler) jvm_cp_args="$PSEP$DOTTY_COMP$PSEP$TASTY_CORE" && shift ;;

# break out -D and -J options and add them to java_args so
# they reach the JVM in time to do some good. The -D options
# will be available as system properties.
-D*) addJava "$1" && shift ;;
-J*) addJava "${1:2}" && shift ;;
*) addResidual "$1" && shift ;;
esac
done

classpathArgs

if [ "$PROG_NAME" == "$ScriptingMain" ]; then
scripting_string="-script $target_script ${scripting_args[@]}"
fi
prepScalacCommandLine "$@"

# exec here would prevent onExit from being called, leaving terminal in unusable state
[ -n "$script_trace" ] && set -x
eval "\"$JAVACMD\"" \
${JAVA_OPTS:-$default_java_opts} \
"${DEBUG-}" \
"${java_args[@]}" \
"$jvm_cp_args" \
"-classpath \"$jvm_cp_args\"" \
-Dscala.usejavacp=true \
"$PROG_NAME" \
"${scala_args[@]}" \
"${residual_args[@]}" \
"${scripting_string-}"
scala_exit_status=$?
onExit

Loading