8000 Merge 2.12.x to 2.13.x [ci: last-only] by SethTisue · Pull Request #5862 · scala/scala · GitHub
[go: up one dir, main page]

Skip to content

Merge 2.12.x to 2.13.x [ci: last-only] #5862

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 37 commits into from
Apr 24, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
5cd3442
Better diagnostic for failing jvm/future-spec
retronym Mar 30, 2017
8ae0fda
Avoid needless work in the specialization info transform in the backend
retronym Feb 4, 2017
e65b714
Optimize SpecializeTypes#satisfiable
retronym Mar 16, 2017
fe4788b
Only do specialation definalization once per run
retronym Mar 20, 2017
e416a25
Optimize specializedTypeVars
retronym Mar 20, 2017
b3975a5
Optimize label defs finder in the backend
retronym Mar 15, 2017
7a6dc1a
Avoid excessive file stats during classfile writing
retronym Mar 15, 2017
455729e
Use AnyRefMap in labelReferences
retronym Mar 15, 2017
53dd4e4
Cache ClassSymbol.javaBinaryNameString
retronym Mar 13, 2017
1ae858c
Remove expensive assertion in the backend
retronym Mar 15, 2017
bebb188
Optimize method descriptor creation
retronym Mar 17, 2017
27be3a2
Avoid excessive IO in classfile parser
retronym Apr 4, 2017
a3987d8
Bump on 2.11.10 release
adriaanm Apr 10, 2017
7a5df57
Update README.md
adriaanm Apr 10, 2017
5167b69
MathJax CDN change and version bump
adriaanm Apr 10, 2017
8b4a033
upgrade to sbt 0.13.15
SethTisue Mar 14, 2017
77917e9
Actually retract clashing synthetic apply/unapply [backport]
adriaanm Apr 12, 2017
8a413ba
Merge pull request #5846 from adriaanm/t10261-2.11
adriaanm Apr 13, 2017
f668845
No-op merge 2.11.x into 2.12.x
adriaanm Apr 13, 2017
17e160d
Merge 2.11.x into 2.12.x
adriaanm Apr 13, 2017
771fe00
No-op merge 2.11.x into 2.12.x
adriaanm Apr 13, 2017
d61301d
Merge pull request #5851 from adriaanm/2.12-catchup-2.11
SethTisue Apr 13, 2017
070ab67
Review feedback: resurrect assertion, use LabelDefFinder.apply
retronym Apr 18, 2017
0c8bdf6
bump version to 2.12.3
SethTisue Apr 18, 2017
4efab51
Merge pull request #5775 from SethTisue/sbt-0.14
SethTisue Apr 18, 2017
7236da0
upgrade to partest 1.1.1
SethTisue Apr 18, 2017
a3ec4a0
Merge pull request #5855 from SethTisue/post-2.12.2-version-bump
SethTisue Apr 18, 2017
db80860
Merge pull request #5856 from SethTisue/partest-1.1.1
SethTisue Apr 18, 2017
d9343a7
Remove dead code catch in LambdaDeserializer
retronym Apr 20, 2017
6e7fd66
Merge pull request #5824 from retronym/faster/sourcefileattr
retronym Apr 21, 2017
3009880
Merge pull request #5820 from retronym/faster/backend
retronym Apr 21, 2017
81459e4
Merge pull request #5812 from retronym/faster/specialization
retronym Apr 21, 2017
9f522c6
Fix lambda deserialization in classes with 252+ lambdas
retronym Apr 18, 2017
7cc1f86
Merge pull request #5857 from retronym/ticket/10232
retronym Apr 24, 2017
3733536
Update error message for t5717
lrytz Apr 24, 2017
709a752
Merge pull request #5861 from lrytz/t5717-msg
SethTisue Apr 24, 2017
775bb11
Merge remote-tracking branch 'origin/2.12.x' into merge-2.12-to-2.13-…
SethTisue Apr 24, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix lambda deserialization in classes with 252+ lambdas
Create a lambda deserializer per group of target methods,
and call these sequentially trapping the particular pattern
of exception that is thrown when a target method is absent
from the map.

Fixes scala/bug#10232

```
  // access flags 0x100A
  private static synthetic $deserializeLambda$(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;
    TRYCATCHBLOCK L0 L1 L1 java/lang/IllegalArgumentException
   L0
    ALOAD 0
    INVOKEDYNAMIC lambdaDeserialize(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object; [
      // handle kind 0x6 : INVOKESTATIC
      scala/runtime/LambdaDeserialize.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
      // arguments:
      // handle kind 0x6 : INVOKESTATIC
      Test$.$anonfun$main$1$adapted(Lscala/Function1;)Ljava/lang/Object;,
      // handle kind 0x6 : INVOKESTATIC
      Test$.$anonfun$lambdas$1(Ljava/lang/Object;)Ljava/lang/String;,

      ...

      Test$.$anonfun$lambdas$249(Ljava/lang/Object;)Ljava/lang/String;,
      // handle kind 0x6 : INVOKESTATIC
      Test$.$anonfun$lambdas$250(Ljava/lang/Object;)Ljava/lang/String;
    ]
    ARETURN
   L1
    ALOAD 0
    INVOKEDYNAMIC lambdaDeserialize(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object; [
      // handle kind 0x6 : INVOKESTATIC
      scala/runtime/LambdaDeserialize.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
      // arguments:
      // handle kind 0x6 : INVOKESTATIC
      Test$.$anonfun$lambdas$251(Ljava/lang/Object;)Ljava/lang/String;,
      // handle kind 0x6 : INVOKESTATIC
      Test$.$anonfun$lambdas$252(Ljava/lang/Object;)Ljava/lang/String;,

      ...

      // handle kind 0x6 : INVOKESTATIC
      Test$.$anonfun$lambdas$256(Ljava/lang/Object;)Ljava/lang/String;
    ]
    ARETURN
    MAXSTACK = 2
    MAXLOCALS = 1

```
  • Loading branch information
retronym committed Apr 24, 2017
commit 9f522c6b3c4639e6b7c79c7a4ac2b63cb71ae420
3 changes: 3 additions & 0 deletions src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
lazy val jlCloneableRef : ClassBType = classBTypeFromSymbol(JavaCloneableClass) // java/lang/Cloneable
lazy val jiSerializableRef : ClassBType = classBTypeFromSymbol(JavaSerializableClass) // java/io/Serializable
lazy val jlClassCastExceptionRef : ClassBType = classBTypeFromSymbol(ClassCastExceptionClass) // java/lang/ClassCastException
lazy val jlIllegalArgExceptionRef : ClassBType = classBTypeFromSymbol(IllegalArgExceptionClass) // java/lang/IllegalArgumentException
lazy val juMapRef : ClassBType = classBTypeFromSymbol(JavaUtilMap) // java/util/Map
lazy val juHashMapRef 8000 : ClassBType = classBTypeFromSymbol(JavaUtilHashMap) // java/util/HashMap
lazy val sbScalaBeanInfoRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.beans.ScalaBeanInfo])
Expand Down Expand Up @@ -314,6 +315,7 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
def PredefRef : ClassBType
def jlCloneableRef : ClassBType
def jiSerializableRef : ClassBType
def jlIllegalArgExceptionRef : ClassBType
def juHashMapRef : ClassBType
def juMapRef : ClassBType
def jliCallSiteRef : ClassBType
Expand Down Expand Up @@ -379,6 +381,7 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def jlCloneableRef : ClassBType = _coreBTypes.jlCloneableRef
def jiSerializableRef : ClassBType = _coreBTypes.jiSerializableRef
def jlClassCastExceptionRef : ClassBType = _coreBTypes.jlClassCastExceptionRef
def jlIllegalArgExceptionRef : ClassBType = _coreBTypes.jlIllegalArgExceptionRef
def juMapRef : ClassBType = _coreBTypes.juMapRef
def juHashMapRef : ClassBType = _coreBTypes.juHashMapRef
def sbScalaBeanInfoRef : ClassBType = _coreBTypes.sbScalaBeanInfoRef
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,27 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {

class NonLubbingTypeFlowAnalyzer(val methodNode: MethodNode, classInternalName: InternalName) extends AsmAnalyzer(methodNode, classInternalName, new Analyzer(new NonLubbingTypeFlowInterpreter))

/**
/*
* Add:
*
* private static Object $deserializeLambda$(SerializedLambda l) {
* return indy[scala.runtime.LambdaDeserialize.bootstrap](l)
* }
* try return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup$0](l)
* catch {
* case i: IllegalArgumentException =>
* try return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup$1](l)
* catch {
* case i: IllegalArgumentException =>
* ...
* return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup${NUM_GROUPS-1}](l)
* }
*
* We use invokedynamic here to enable caching within the deserializer without needing to
* host a static field in the enclosing class. This allows us to add this method to interfaces
* that define lambdas in default methods.
*
* SI-10232 we can't pass arbitrary number of method handles to the final varargs parameter of the bootstrap
* method due to a limitation in the JVM. Instead, we emit a separate invokedynamic bytecode for each group of target
* methods.
*/
def addLambdaDeserialize(classNode: ClassNode, implMethods: Iterable[Handle]): Unit = {
val cw = classNode
Expand All @@ -87,15 +99,34 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {

val nilLookupDesc = MethodBType(Nil, jliMethodHandlesLookupRef).descriptor
val serlamObjDesc = MethodBType(jliSerializedLambdaRef :: Nil, ObjectRef).descriptor
val implMethodsArray = implMethods.toArray

{
val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", serlamObjDesc, null, null)
mv.visitCode()
val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", serlamObjDesc, null, null)
def emitLambdaDeserializeIndy(targetMethods: Seq[Handle]) {
mv.visitVarInsn(ALOAD, 0)
mv.visitInvokeDynamicInsn("lambdaDeserialize", serlamObjDesc, lambdaDeserializeBootstrapHandle, implMethods.toArray: _*)
mv.visitInvokeDynamicInsn("lambdaDeserialize", serlamObjDesc, lambdaDeserializeBootstrapHandle, targetMethods: _*)
}

val targetMethodGroupLimit = 255 - 1 - 3 // JVM limit. See See MAX_MH_ARITY in CallSite.java
val groups: Array[Array[Handle]] = implMethodsArray.grouped(targetMethodGroupLimit).toArray
val numGroups = groups.length

import scala.tools.asm.Label
val initialLabels = Array.fill(numGroups - 1)(new Label())
val terminalLabel = new Label
def nextLabel(i: Int) = if (i == numGroups - 2) terminalLabel else initialLabels(i + 1)

for ((label, i) <- initialLabels.iterator.zipWithIndex) {
mv.visitTryCatchBlock(label, nextLabel(i), nextLabel(i), jlIllegalArgExceptionRef.internalName)
}
for ((label, i) <- initialLabels.iterator.zipWithIndex) {
mv.visitLabel(label)
emitLambdaDeserializeIndy(groups(i))
mv.visitInsn(ARETURN)
mv.visitEnd()
}
mv.visitLabel(terminalLabel)
emitLambdaDeserializeIndy(groups(numGroups - 1))
mv.visitInsn(ARETURN)
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/internal/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val NullPointerExceptionClass = getClassByName(sn.NPException)
lazy val ThrowableClass = getClassByName(sn.Throwable)
lazy val UninitializedErrorClass = requiredClass[UninitializedFieldError]
lazy val IllegalArgExceptionClass = requiredClass[IllegalArgumentException]

lazy val UninitializedFieldConstructor = UninitializedErrorClass.primaryConstructor

Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.NullPointerExceptionClass
definitions.ThrowableClass
definitions.UninitializedErrorClass
definitions.IllegalArgExceptionClass
definitions.UninitializedFieldConstructor
definitions.PartialFunctionClass
definitions.AbstractPartialFunctionClass
Expand Down
275 changes: 275 additions & 0 deletions test/files/run/t10232.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}

object Test {
val lambdas: List[Any => String] = List(
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: A F438 ny) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" },
{ (t: Any) => "ab" }
)

def main(args: Array[String]): Unit = {
for (lambda <- lambdas) {
val outStream = new ByteArrayOutputStream
val oo = new ObjectOutputStream(outStream)
oo.writeObject(lambda)

val inStream = new ByteArrayInputStream(outStream.toByteArray)
val oi = new ObjectInputStream(inStream)
val lambda2 = oi.readObject().asInstanceOf[Any => String]
assert(lambda2(1) == "ab")
}
}
}
0