Skip to content

Commit e5e27ce

Browse files
committed
Use shaded ASM5 for closure cleaning.
1 parent d9e30c5 commit e5e27ce

File tree

9 files changed

+57
-39
lines changed

9 files changed

+57
-39
lines changed

core/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
<groupId>com.twitter</groupId>
5252
<artifactId>chill-java</artifactId>
5353
</dependency>
54+
<dependency>
55+
<groupId>org.apache.xbean</groupId>
56+
<artifactId>xbean-asm5-shaded</artifactId>
57+
</dependency>
5458
<dependency>
5559
<groupId>org.apache.hadoop</groupId>
5660
<artifactId>hadoop-client</artifactId>

core/src/main/scala/org/apache/spark/util/ClosureCleaner.scala

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import java.io.{ByteArrayInputStream, ByteArrayOutputStream}
2121

2222
import scala.collection.mutable.{Map, Set}
2323

24-
import com.esotericsoftware.reflectasm.shaded.org.objectweb.asm.{ClassReader, ClassVisitor, MethodVisitor, Type}
25-
import com.esotericsoftware.reflectasm.shaded.org.objectweb.asm.Opcodes._
24+
import org.apache.xbean.asm5.{ClassReader, ClassVisitor, MethodVisitor, Type}
25+
import org.apache.xbean.asm5.Opcodes._
2626

2727
import org.apache.spark.{Logging, SparkEnv, SparkException}
2828

@@ -325,19 +325,19 @@ private[spark] object ClosureCleaner extends Logging {
325325
private[spark] class ReturnStatementInClosureException
326326
extends SparkException("Return statements aren't allowed in Spark closures")
327327

328-
private class ReturnStatementFinder extends ClassVisitor(ASM4) {
328+
private class ReturnStatementFinder extends ClassVisitor(ASM5) {
329329
override def visitMethod(access: Int, name: String, desc: String,
330330
sig: String, exceptions: Array[String]): MethodVisitor = {
331331
if (name.contains("apply")) {
332-
new MethodVisitor(ASM4) {
332+
new MethodVisitor(ASM5) {
333333
override def visitTypeInsn(op: Int, tp: String) {
334334
if (op == NEW && tp.contains("scala/runtime/NonLocalReturnControl")) {
335335
throw new ReturnStatementInClosureException
336336
}
337337
}
338338
}
339339
} else {
340-
new MethodVisitor(ASM4) {}
340+
new MethodVisitor(ASM5) {}
341341
}
342342
}
343343
}
@@ -361,7 +361,7 @@ private[util] class FieldAccessFinder(
361361
findTransitively: Boolean,
362362
specificMethod: Option[MethodIdentifier[_]] = None,
363363
visitedMethods: Set[MethodIdentifier[_]] = Set.empty)
364-
extends ClassVisitor(ASM4) {
364+
extends ClassVisitor(ASM5) {
365365

366366
override def visitMethod(
367367
access: Int,
@@ -376,7 +376,7 @@ private[util] class FieldAccessFinder(
376376
return null
377377
}
378378

379-
new MethodVisitor(ASM4) {
379+
new MethodVisitor(ASM5) {
380380
override def visitFieldInsn(op: Int, owner: String, name: String, desc: String) {
381381
if (op == GETFIELD) {
382382
for (cl <- fields.keys if cl.getName == owner.replace('/', '.')) {
@@ -385,7 +385,8 @@ private[util] class FieldAccessFinder(
385385
}
386386
}
387387

388-
override def visitMethodInsn(op: Int, owner: String, name: String, desc: String) {
388+
override def visitMethodInsn(
389+
op: Int, owner: String, name: String, desc: String, itf: Boolean) {
389390
for (cl <- fields.keys if cl.getName == owner.replace('/', '.')) {
390391
// Check for calls a getter method for a variable in an interpreter wrapper object.
391392
// This means that the corresponding field will be accessed, so we should save it.
@@ -408,7 +409,7 @@ private[util] class FieldAccessFinder(
408409
}
409410
}
410411

411-
private class InnerClosureFinder(output: Set[Class[_]]) extends ClassVisitor(ASM4) {
412+
private class InnerClosureFinder(output: Set[Class[_]]) extends ClassVisitor(ASM5) {
412413
var myName: String = null
413414

414415
// TODO: Recursively find inner closures that we indirectly reference, e.g.
@@ -423,9 +424,9 @@ private class InnerClosureFinder(output: Set[Class[_]]) extends ClassVisitor(ASM
423424

424425
override def visitMethod(access: Int, name: String, desc: String,
425426
sig: String, exceptions: Array[String]): MethodVisitor = {
426-
new MethodVisitor(ASM4) {
427-
override def visitMethodInsn(op: Int, owner: String, name: String,
428-
desc: String) {
427+
new MethodVisitor(ASM5) {
428+
override def visitMethodInsn(
429+
op: Int, owner: String, name: String, desc: String, itf: Boolean) {
429430
val argTypes = Type.getArgumentTypes(desc)
430431
if (op == INVOKESPECIAL && name == "<init>" && argTypes.length > 0
431432
&& argTypes(0).toString.startsWith("L") // is it an object?

graphx/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
<type>test-jar</type>
4848
<scope>test</scope>
4949
</dependency>
50+
<dependency>
51+
<groupId>org.apache.xbean</groupId>
52+
<artifactId>xbean-asm5-shaded</artifactId>
53+
</dependency>
5054
<dependency>
5155
<groupId>com.google.guava</groupId>
5256
<artifactId>guava</artifactId>

graphx/src/main/scala/org/apache/spark/graphx/util/BytecodeUtils.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ import java.io.{ByteArrayInputStream, ByteArrayOutputStream}
2222
import scala.collection.mutable.HashSet
2323
import scala.language.existentials
2424

25-
import org.apache.spark.util.Utils
26-
27-
import com.esotericsoftware.reflectasm.shaded.org.objectweb.asm.{ClassReader, ClassVisitor, MethodVisitor}
28-
import com.esotericsoftware.reflectasm.shaded.org.objectweb.asm.Opcodes._
25+
import org.apache.xbean.asm5.{ClassReader, ClassVisitor, MethodVisitor}
26+
import org.apache.xbean.asm5.Opcodes._
2927

28+
import org.apache.spark.util.Utils
3029

3130
/**
3231
* Includes an utility function to test whether a function accesses a specific attribute
@@ -107,18 +106,19 @@ private[graphx] object BytecodeUtils {
107106
* MethodInvocationFinder("spark/graph/Foo", "test")
108107
* its methodsInvoked variable will contain the set of methods invoked directly by
109108
* Foo.test(). Interface invocations are not returned as part of the result set because we cannot
110-
* determine the actual metod invoked by inspecting the bytecode.
109+
* determine the actual method invoked by inspecting the bytecode.
111110
*/
112111
private class MethodInvocationFinder(className: String, methodName: String)
113-
extends ClassVisitor(ASM4) {
112+
extends ClassVisitor(ASM5) {
114113

115114
val methodsInvoked = new HashSet[(Class[_], String)]
116115

117116
override def visitMethod(access: Int, name: String, desc: String,
118117
sig: String, exceptions: Array[String]): MethodVisitor = {
119118
if (name == methodName) {
120-
new MethodVisitor(ASM4) {
121-
override def visitMethodInsn(op: Int, owner: String, name: String, desc: String) {
119+
new MethodVisitor(ASM5) {
120+
override def visitMethodInsn(
121+
op: Int, owner: String, name: String, desc: String, itf: Boolean) {
122122
if (op == INVOKEVIRTUAL || op == INVOKESPECIAL || op == INVOKESTATIC) {
123123
if (!skipClass(owner)) {
124124
methodsInvoked.add((Utils.classForName(owner.replace("/", ".")), name))

pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,14 @@
390390
</exclusion>
391391
</exclusions>
392392
</dependency>
393+
<!-- This artifact is a shaded version of ASM 5.0.4. The POM that was used to produce this
394+
is at https://github.com/apache/geronimo-xbean/tree/xbean-4.4/xbean-asm5-shaded
395+
For context on why we shade ASM, see SPARK-782 and SPARK-6152. -->
396+
<dependency>
397+
<groupId>org.apache.xbean</groupId>
398+
<artifactId>xbean-asm5-shaded</artifactId>
399+
<version>4.4</version>
400+
</dependency>
393401

394402
<!-- Shaded deps marked as provided. These are promoted to compile scope
395403
in the modules where we want the shaded classes to appear in the

repl/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@
9595
<groupId>org.apache.spark</groupId>
9696
<artifactId>spark-test-tags_${scala.binary.version}</artifactId>
9797
</dependency>
98+
<dependency>
99+
<groupId>org.apache.xbean</groupId>
100+
<artifactId>xbean-asm5-shaded</artifactId>
101+
</dependency>
98102

99103
<!-- Explicit listing of transitive deps that are shaded. Otherwise, odd compiler crashes. -->
100104
<dependency>

repl/src/main/scala/org/apache/spark/repl/ExecutorClassLoader.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,14 @@ import java.net.{HttpURLConnection, URI, URL, URLEncoder}
2323
import scala.util.control.NonFatal
2424

2525
import org.apache.hadoop.fs.{FileSystem, Path}
26+
import org.apache.xbean.asm5._
27+
import org.apache.xbean.asm5.Opcodes._
2628

2729
import org.apache.spark.{SparkConf, SparkEnv, Logging}
2830
import org.apache.spark.deploy.SparkHadoopUtil
2931
import org.apache.spark.util.Utils
3032
import org.apache.spark.util.ParentClassLoader
3133

32-
import com.esotericsoftware.reflectasm.shaded.org.objectweb.asm._
33-
import com.esotericsoftware.reflectasm.shaded.org.objectweb.asm.Opcodes._
34-
3534
/**
3635
* A ClassLoader that reads classes from a Hadoop FileSystem or HTTP URI,
3736
* used to load classes defined by the interpreter when the REPL is used.
@@ -192,7 +191,7 @@ class ExecutorClassLoader(conf: SparkConf, classUri: String, parent: ClassLoader
192191
}
193192

194193
class ConstructorCleaner(className: String, cv: ClassVisitor)
195-
extends ClassVisitor(ASM4, cv) {
194+
extends ClassVisitor(ASM5, cv) {
196195
override def visitMethod(access: Int, name: String, desc: String,
197196
sig: String, exceptions: Array[String]): MethodVisitor = {
198197
val mv = cv.visitMethod(access, name, desc, sig, exceptions)

sql/core/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@
110110
<artifactId>mockito-core</artifactId>
111111
<scope>test</scope>
112112
</dependency>
113+
<dependency>
114+
<groupId>org.apache.xbean</groupId>
115+
<artifactId>xbean-asm5-shaded</artifactId>
116+
<scope>test</scope>
117+
</dependency>
113118
</dependencies>
114119
<build>
115120
<outputDirectory>target/scala-${scala.binary.version}/classes</outputDirectory>

sql/core/src/test/scala/org/apache/spark/sql/execution/metric/SQLMetricsSuite.scala

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import java.io.{ByteArrayInputStream, ByteArrayOutputStream}
2121

2222
import scala.collection.mutable
2323

24-
import com.esotericsoftware.reflectasm.shaded.org.objectweb.asm._
25-
import com.esotericsoftware.reflectasm.shaded.org.objectweb.asm.Opcodes._
24+
import org.apache.xbean.asm5._
25+
import org.apache.xbean.asm5.Opcodes._
2626

2727
import org.apache.spark.SparkFunSuite
2828
import org.apache.spark.sql._
@@ -516,7 +516,7 @@ private class BoxingFinder(
516516
method: MethodIdentifier[_] = null,
517517
val boxingInvokes: mutable.Set[String] = mutable.Set.empty,
518518
visitedMethods: mutable.Set[MethodIdentifier[_]] = mutable.Set.empty)
519-
extends ClassVisitor(ASM4) {
519+
extends ClassVisitor(ASM5) {
520520

521521
private val primitiveBoxingClassName =
522522
Set("java/lang/Long",
@@ -533,11 +533,12 @@ private class BoxingFinder(
533533
MethodVisitor = {
534534
if (method != null && (method.name != name || method.desc != desc)) {
535535
// If method is specified, skip other methods.
536-
return new MethodVisitor(ASM4) {}
536+
return new MethodVisitor(ASM5) {}
537537
}
538538

539-
new MethodVisitor(ASM4) {
540-
override def visitMethodInsn(op: Int, owner: String, name: String, desc: String) {
539+
new MethodVisitor(ASM5) {
540+
override def visitMethodInsn(
541+
op: Int, owner: String, name: String, desc: String, itf: Boolean) {
541542
if (op == INVOKESPECIAL && name == "<init>" || op == INVOKESTATIC && name == "valueOf") {
542543
if (primitiveBoxingClassName.contains(owner)) {
543544
// Find boxing methods, e.g, new java.lang.Long(l) or java.lang.Long.valueOf(l)
@@ -572,15 +573,7 @@ private object BoxingFinder {
572573
// Copy data over, before delegating to ClassReader -
573574
// else we can run out of open file handles.
574575
Utils.copyStream(resourceStream, baos, true)
575-
// ASM4 doesn't support Java 8 classes, which requires ASM5.
576-
// So if the class is ASM5 (E.g., java.lang.Long when using JDK8 runtime to run these codes),
577-
// then ClassReader will throw IllegalArgumentException,
578-
// However, since this is only for testing, it's safe to skip these classes.
579-
try {
580-
Some(new ClassReader(new ByteArrayInputStream(baos.toByteArray)))
581-
} catch {
582-
case _: IllegalArgumentException => None
583-
}
576+
Some(new ClassReader(new ByteArrayInputStream(baos.toByteArray)))
584577
}
585578

586579
}

0 commit comments

Comments
 (0)