diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-07-19 12:43:27 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-07-20 10:24:43 +0200 |
commit | 2b1e4efa0a8f30bda7fde8492e8ecfdcbf4801cb (patch) | |
tree | e1df6785a3eafafe08675a4f0cc35e4e4cab5a75 /src/compiler/scala/tools/nsc/backend/jvm | |
parent | 3c43a7bc389eba0d7d52ef0d0cdb19812c4a8a0f (diff) | |
download | scala-2b1e4efa0a8f30bda7fde8492e8ecfdcbf4801cb.tar.gz scala-2b1e4efa0a8f30bda7fde8492e8ecfdcbf4801cb.tar.bz2 scala-2b1e4efa0a8f30bda7fde8492e8ecfdcbf4801cb.zip |
SD-48 limit the lenght of inlined local variable names
When inlining local variables, the names are prefixed with the callee
method name. In long chains of inlining, these names can grow
indefinitely. This commits introduces a limit.
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm')
3 files changed, 31 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index 7b2686e7a9..e04e73304f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -1164,4 +1164,7 @@ object BTypes { // no static way (without symbol table instance) to get to nme.ScalaATTR / ScalaSignatureATTR val ScalaAttributeName = "Scala" val ScalaSigAttributeName = "ScalaSig" + + // when inlining, local variable names of the callee are prefixed with the name of the callee method + val InlinedLocalVariablePrefixMaxLenght = 128 } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala index e21c46dbe9..bfd92cac5c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala @@ -324,15 +324,33 @@ object BytecodeUtils { * Clone the local variable descriptors of `methodNode` and map their `start` and `end` labels * according to the `labelMap`. */ - def cloneLocalVariableNodes(methodNode: MethodNode, labelMap: Map[LabelNode, LabelNode], prefix: String, shift: Int): List[LocalVariableNode] = { - methodNode.localVariables.iterator().asScala.map(localVariable => new LocalVariableNode( - prefix + localVariable.name, - localVariable.desc, - localVariable.signature, - labelMap(localVariable.start), - labelMap(localVariable.end), - localVariable.index + shift - )).toList + def cloneLocalVariableNodes(methodNode: MethodNode, labelMap: Map[LabelNode, LabelNode], calleeMethodName: String, shift: Int): List[LocalVariableNode] = { + methodNode.localVariables.iterator().asScala.map(localVariable => { + val name = + if (calleeMethodName.length + localVariable.name.length < BTypes.InlinedLocalVariablePrefixMaxLenght) { + calleeMethodName + "_" + localVariable.name + } else { + val parts = localVariable.name.split("_").toVector + val (methNames, varName) = (calleeMethodName +: parts.init, parts.last) + // keep at least 5 characters per method name + val maxNumMethNames = BTypes.InlinedLocalVariablePrefixMaxLenght / 5 + val usedMethNames = + if (methNames.length < maxNumMethNames) methNames + else { + val half = maxNumMethNames / 2 + methNames.take(half) ++ methNames.takeRight(half) + } + val charsPerMethod = BTypes.InlinedLocalVariablePrefixMaxLenght / usedMethNames.length + usedMethNames.foldLeft("")((res, methName) => res + methName.take(charsPerMethod) + "_") + varName + } + new LocalVariableNode( + name, + localVariable.desc, + localVariable.signature, + labelMap(localVariable.start), + labelMap(localVariable.end), + localVariable.index + shift) + }).toList } /** diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala index 9c5a1a9f98..50dd65c56c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala @@ -382,7 +382,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { callsiteMethod.instructions.insert(callsiteInstruction, clonedInstructions) callsiteMethod.instructions.remove(callsiteInstruction) - callsiteMethod.localVariables.addAll(cloneLocalVariableNodes(callee, labelsMap, callee.name + "_", localVarShift).asJava) + callsiteMethod.localVariables.addAll(cloneLocalVariableNodes(callee, labelsMap, callee.name, localVarShift).asJava) // prepend the handlers of the callee. the order of handlers matters: when an exception is thrown // at some instruction, the first handler guarding that instruction and having a matching exception // type is executed. prepending the callee's handlers makes sure to test those handlers first if |