Skip to content

Commit c58f4e4

Browse files
lrytzadriaanm
authored andcommitted
Include sources for scala-java8-compat instead of jar
This reverts commit e1895d6, titled "Add scala-java8-compat to scala-library.jar". Move SAM functions and `LambdaDeserializer` (from scala/scala-java8-compat@9253ed9) into `scala.runtime.java8` package under `src/library`. (The package name is the only diff -- they were in `scala.compat.java8` before). The original LambdaDeserializer: https://github.com/scala/scala-java8-compat/blob/c0732e6/src/main/java/scala/compat/java8/runtime/LambdaDeserializer.scala
1 parent 8247b8f commit c58f4e4

File tree

139 files changed

+3316
-41
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

139 files changed

+3316
-41
lines changed

build.xml

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,6 @@ TODO:
265265
-->
266266
<if><not><isset property="maven-deps-done"></isset></not><then>
267267
<mkdir dir="${user.home}/.m2/repository"/>
268-
269-
<artifact:remoteRepository id="sonatype-release" url="https://oss.sonatype.org/content/repositories/releases"/>
270-
<artifact:remoteRepository id="sonatype-snapshots" url="https://oss.sonatype.org/content/repositories/snapshots"/>
271-
<artifact:remoteRepository id="extra-repo" url="${extra.repo.url}"/>
272-
273268
<!-- This task has an issue where if the user directory does not exist, so we create it above. UGH. -->
274269
<artifact:dependencies pathId="extra.tasks.classpath" filesetId="extra.tasks.fileset">
275270
<dependency groupId="biz.aQute.bnd" artifactId="biz.aQute.bnd" version="2.4.1"/>
@@ -314,36 +309,6 @@ TODO:
314309
<artifact:remoteRepository id="sonatype-release" url="https://oss.sonatype.org/content/repositories/releases"/>
315310
<artifact:remoteRepository id="extra-repo" url="${extra.repo.url}"/>
316311

317-
<!-- scala-java8-compat, used by the experimental -target jvm-1.8 support. -->
318-
<if><isset property="scala-java8-compat.package"/><then>
319-
<property name="scala-java8-compat.version" value="0.5.0"/>
320-
<property name="scala-java8-compat.binary.version" value="2.11"/>
321-
<artifact:dependencies pathId="scala-java8-compat.classpath" filesetId="scala-java8-compat.fileset">
322-
<dependency groupId="org.scala-lang.modules" artifactId="scala-java8-compat_${scala-java8-compat.binary.version}" version="${scala-java8-compat.version}">
323-
<exclusion groupId="org.scala-lang" artifactId="scala-library"/>
324-
</dependency>
325-
</artifact:dependencies>
326-
<property name="scala-java8-compat-classes" value="${build-quick.dir}/scala-java8-compat"/>
327-
<delete dir="${scala-java8-compat-classes}"/>
328-
<unzip dest="${scala-java8-compat-classes}">
329-
<fileset refid="scala-java8-compat.fileset"/>
330-
<patternset>
331-
<include name="**/*.class"/>
332-
</patternset>
333-
</unzip>
334-
<path id="scala-java8-compat.libs">
335-
<pathelement location="${scala-java8-compat-classes}"/>
336-
</path>
337-
<fileset id="scala-java8-compat.fileset" dir="${scala-java8-compat-classes}">
338-
<include name="**/*"/>
339-
</fileset>
340-
</then>
341-
<else>
342-
<path id="scala-java8-compat.libs"/>
343-
<fileset id="scala-java8-compat.fileset" dir="." excludes="**"/>
344-
</else>
345-
</if>
346-
347312
<!-- prepare, for each of the names below, the property "@{name}.cross", set to the
348313
necessary cross suffix (usually something like "_2.11.0-M6". -->
349314
<prepareCross name="scala-xml" />
@@ -722,7 +687,6 @@ TODO:
722687
<pathelement location="${build-locker.dir}/classes/library"/>
723688
<path refid="forkjoin.classpath"/>
724689
<path refid="aux.libs"/>
725-
<path refid="scala-java8-compat.libs"/>
726690
</path>
727691

728692
<path id="locker.reflect.build.path">
@@ -744,7 +708,6 @@ TODO:
744708
<pathelement location="${build-quick.dir}/classes/library"/>
745709
<path refid="forkjoin.classpath"/>
746710
<path refid="aux.libs"/>
747-
<path refid="scala-java8-compat.libs"/>
748711
</path>
749712

750713
<path id="quick.reflect.build.path">
@@ -837,7 +800,6 @@ TODO:
837800
<path id="pack.library.files">
838801
<fileset dir="${build-quick.dir}/classes/library"/>
839802
<fileset dir="${forkjoin-classes}"/>
840-
<fileset refid="scala-java8-compat.fileset"/>
841803
</path>
842804

843805
<path id="pack.repl-jline.files"> <fileset dir="${build-quick.dir}/classes/repl-jline"/> </path>

src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
693693
* cache = new java.util.HashMap()
694694
* $deserializeLambdaCache$ = cache
695695
* }
696-
* return scala.compat.java8.runtime.LambdaDeserializer.deserializeLambda(MethodHandles.lookup(), cache, l);
696+
* return scala.runtime.LambdaDeserializer.deserializeLambda(MethodHandles.lookup(), cache, l);
697697
* }
698698
*/
699699
def addLambdaDeserialize(clazz: Symbol, jclass: asm.ClassVisitor): Unit = {
@@ -732,7 +732,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
732732
mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false)
733733
mv.visitVarInsn(ALOAD, 1)
734734
mv.visitVarInsn(ALOAD, 0)
735-
mv.visitMethodInsn(INVOKESTATIC, "scala/compat/java8/runtime/LambdaDeserializer", "deserializeLambda", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/util/Map;Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", false)
735+
mv.visitMethodInsn(INVOKESTATIC, "scala/runtime/LambdaDeserializer", "deserializeLambda", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/util/Map;Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", false)
736736
mv.visitInsn(ARETURN)
737737
mv.visitEnd()
738738
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package scala.runtime
2+
3+
import java.lang.invoke._
4+
5+
/**
6+
* This class is only intended to be called by synthetic `$deserializeLambda$` method that the Scala 2.12
7+
* compiler will add to classes hosting lambdas.
8+
*
9+
* It is not intended to be consumed directly.
10+
*/
11+
object LambdaDeserializer {
12+
/**
13+
* Deserialize a lambda by calling `LambdaMetafactory.altMetafactory` to spin up a lambda class
14+
* and instantiating this class with the captured arguments.
15+
*
16+
* A cache may be provided to ensure that subsequent deserialization of the same lambda expression
17+
* is cheap, it amounts to a reflective call to the constructor of the previously created class.
18+
* However, deserialization of the same lambda expression is not guaranteed to use the same class,
19+
* concurrent deserialization of the same lambda expression may spin up more than one class.
20+
*
21+
* Assumptions:
22+
* - No additional marker interfaces are required beyond `{java.io,scala.}Serializable`. These are
23+
* not stored in `SerializedLambda`, so we can't reconstitute them.
24+
* - No additional bridge methods are passed to `altMetafactory`. Again, these are not stored.
25+
*
26+
* @param lookup The factory for method handles. Must have access to the implementation method, the
27+
* functional interface class, and `java.io.Serializable` or `scala.Serializable` as
28+
* required.
29+
* @param cache A cache used to avoid spinning up a class for each deserialization of a given lambda. May be `null`
30+
* @param serialized The lambda to deserialize. Note that this is typically created by the `readResolve`
31+
* member of the anonymous class created by `LambdaMetaFactory`.
32+
* @return An instance of the functional interface
33+
*/
34+
def deserializeLambda(lookup: MethodHandles.Lookup, cache: java.util.Map[String, MethodHandle], serialized: SerializedLambda): AnyRef = {
35+
def slashDot(name: String) = name.replaceAll("/", ".")
36+
val loader = lookup.lookupClass().getClassLoader
37+
val implClass = loader.loadClass(slashDot(serialized.getImplClass))
38+
39+
def makeCallSite: CallSite = {
40+
import serialized._
41+
def parseDescriptor(s: String) =
42+
MethodType.fromMethodDescriptorString(s, loader)
43+
44+
val funcInterfaceSignature = parseDescriptor(getFunctionalInterfaceMethodSignature)
45+
val instantiated = parseDescriptor(getInstantiatedMethodType)
46+
val functionalInterfaceClass = loader.loadClass(slashDot(getFunctionalInterfaceClass))
47+
48+
val implMethodSig = parseDescriptor(getImplMethodSignature)
49+
// Construct the invoked type from the impl method type. This is the type of a factory
50+
// that will be generated by the meta-factory. It is a method type, with param types
51+
// coming form the types of the captures, and return type being the functional interface.
52+
val invokedType: MethodType = {
53+
// 1. Add receiver for non-static impl methods
54+
val withReceiver = getImplMethodKind match {
55+
case MethodHandleInfo.REF_invokeStatic | MethodHandleInfo.REF_newInvokeSpecial =>
56+
implMethodSig
57+
case _ =>
58+
implMethodSig.insertParameterTypes(0, implClass)
59+
}
60+
// 2. Remove lambda parameters, leaving only captures. Note: the receiver may be a lambda parameter,
61+
// such as in `Function<Object, String> s = Object::toString`
62+
val lambdaArity = funcInterfaceSignature.parameterCount()
63+
val from = withReceiver.parameterCount() - lambdaArity
64+
val to = withReceiver.parameterCount()
65+
66+
// 3. Drop the lambda return type and replace with the functional interface.
67+
withReceiver.dropParameterTypes(from, to).changeReturnType(functionalInterfaceClass)
68+
}
69+
70+
// Lookup the implementation method
71+
val implMethod: MethodHandle = try {
72+
findMember(lookup, getImplMethodKind, implClass, getImplMethodName, implMethodSig)
73+
} catch {
74+
case e: ReflectiveOperationException => throw new IllegalArgumentException("Illegal lambda deserialization", e)
75+
}
76+
77+
val flags: Int = LambdaMetafactory.FLAG_SERIALIZABLE | LambdaMetafactory.FLAG_MARKERS
78+
val isScalaFunction = functionalInterfaceClass.getName.startsWith("scala.Function")
79+
val markerInterface: Class[_] = loader.loadClass(if (isScalaFunction) ScalaSerializable else JavaIOSerializable)
80+
81+
LambdaMetafactory.altMetafactory(
82+
lookup, getFunctionalInterfaceMethodName, invokedType,
83+
84+
/* samMethodType = */ funcInterfaceSignature,
85+
/* implMethod = */ implMethod,
86+
/* instantiatedMethodType = */ instantiated,
87+
/* flags = */ flags.asInstanceOf[AnyRef],
88+
/* markerInterfaceCount = */ 1.asInstanceOf[AnyRef],
89+
/* markerInterfaces[0] = */ markerInterface,
90+
/* bridgeCount = */ 0.asInstanceOf[AnyRef]
91+
)
92+
}
93+
94+
val key = serialized.getImplMethodName + " : " + serialized.getImplMethodSignature
95+
val factory: MethodHandle = if (cache == null) {
96+
makeCallSite.getTarget
97+
} else cache.get(key) match {
98+
case null =>
99+
val callSite = makeCallSite
100+
val temp = callSite.getTarget
101+
cache.put(key, temp)
102+
temp
103+
case target => target
104+
}
105+
106+
val captures = Array.tabulate(serialized.getCapturedArgCount)(n => serialized.getCapturedArg(n))
107+
factory.invokeWithArguments(captures: _*)
108+
}
109+
110+
private val ScalaSerializable = "scala.Serializable"
111+
112+
private val JavaIOSerializable = {
113+
// We could actually omit this marker interface as LambdaMetaFactory will add it if
114+
// the FLAG_SERIALIZABLE is set and of the provided markers extend it. But the code
115+
// is cleaner if we uniformly add a single marker, so I'm leaving it in place.
116+
"java.io.Serializable"
117+
}
118+
119+
private def findMember(lookup: MethodHandles.Lookup, kind: Int, owner: Class[_],
120+
name: String, signature: MethodType): MethodHandle = {
121+
kind match {
122+
case MethodHandleInfo.REF_invokeStatic =>
123+
lookup.findStatic(owner, name, signature)
124+
case MethodHandleInfo.REF_newInvokeSpecial =>
125+
lookup.findConstructor(owner, signature)
126+
case MethodHandleInfo.REF_invokeVirtual | MethodHandleInfo.REF_invokeInterface =>
127+
lookup.findVirtual(owner, name, signature)
128+
case MethodHandleInfo.REF_invokeSpecial =>
129+
lookup.findSpecial(owner, name, signature, owner)
130+
}
131+
}
132+
}

0 commit comments

Comments
 (0)