@@ -91,6 +91,54 @@ private[spark] object ClosureCleaner extends Logging {
91
91
(seen - obj.getClass).toList
92
92
}
93
93
94
+ /** Initializes the accessed fields for outer classes and their super classes. */
95
+ private def initAccessedFields (
96
+ accessedFields : Map [Class [_], Set [String ]],
97
+ outerClasses : Seq [Class [_]]): Unit = {
98
+ for (cls <- outerClasses) {
99
+ var currentClass = cls
100
+ assert(currentClass != null , " The outer class can't be null." )
101
+
102
+ while (currentClass != null ) {
103
+ accessedFields(currentClass) = Set .empty[String ]
104
+ currentClass = currentClass.getSuperclass()
105
+ }
106
+ }
107
+ }
108
+
109
+ /** Sets accessed fields for given class in clone object based on given object. */
110
+ private def setAccessedFields (
111
+ outerClass : Class [_],
112
+ clone : AnyRef ,
113
+ obj : AnyRef ,
114
+ accessedFields : Map [Class [_], Set [String ]]): Unit = {
115
+ for (fieldName <- accessedFields(outerClass)) {
116
+ val field = outerClass.getDeclaredField(fieldName)
117
+ field.setAccessible(true )
118
+ val value = field.get(obj)
119
+ field.set(clone, value)
120
+ }
121
+ }
122
+
123
+ /** Clones a given object and sets accessed fields in cloned object. */
124
+ private def cloneAndSetFields (
125
+ parent : AnyRef ,
126
+ obj : AnyRef ,
127
+ outerClass : Class [_],
128
+ accessedFields : Map [Class [_], Set [String ]]): AnyRef = {
129
+ val clone = instantiateClass(outerClass, parent)
130
+
131
+ var currentClass = outerClass
132
+ assert(currentClass != null , " The outer class can't be null." )
133
+
134
+ while (currentClass != null ) {
135
+ setAccessedFields(currentClass, clone, obj, accessedFields)
136
+ currentClass = currentClass.getSuperclass()
137
+ }
138
+
139
+ clone
140
+ }
141
+
94
142
/**
95
143
* Clean the given closure in place.
96
144
*
@@ -202,9 +250,8 @@ private[spark] object ClosureCleaner extends Logging {
202
250
logDebug(s " + populating accessed fields because this is the starting closure " )
203
251
// Initialize accessed fields with the outer classes first
204
252
// This step is needed to associate the fields to the correct classes later
205
- for (cls <- outerClasses) {
206
- accessedFields(cls) = Set .empty[String ]
207
- }
253
+ initAccessedFields(accessedFields, outerClasses)
254
+
208
255
// Populate accessed fields by visiting all fields and methods accessed by this and
209
256
// all of its inner closures. If transitive cleaning is enabled, this may recursively
210
257
// visits methods that belong to other classes in search of transitively referenced fields.
@@ -250,13 +297,8 @@ private[spark] object ClosureCleaner extends Logging {
250
297
// required fields from the original object. We need the parent here because the Java
251
298
// language specification requires the first constructor parameter of any closure to be
252
299
// its enclosing object.
253
- val clone = instantiateClass(cls, parent)
254
- for (fieldName <- accessedFields(cls)) {
255
- val field = cls.getDeclaredField(fieldName)
256
- field.setAccessible(true )
257
- val value = field.get(obj)
258
- field.set(clone, value)
259
- }
300
+ val clone = cloneAndSetFields(parent, obj, cls, accessedFields)
301
+
260
302
// If transitive cleaning is enabled, we recursively clean any enclosing closure using
261
303
// the already populated accessed fields map of the starting closure
262
304
if (cleanTransitively && isClosure(clone.getClass)) {
@@ -395,8 +437,15 @@ private[util] class FieldAccessFinder(
395
437
if (! visitedMethods.contains(m)) {
396
438
// Keep track of visited methods to avoid potential infinite cycles
397
439
visitedMethods += m
398
- ClosureCleaner .getClassReader(cl).accept(
399
- new FieldAccessFinder (fields, findTransitively, Some (m), visitedMethods), 0 )
440
+
441
+ var currentClass = cl
442
+ assert(currentClass != null , " The outer class can't be null." )
443
+
444
+ while (currentClass != null ) {
445
+ ClosureCleaner .getClassReader(currentClass).accept(
446
+ new FieldAccessFinder (fields, findTransitively, Some (m), visitedMethods), 0 )
447
+ currentClass = currentClass.getSuperclass()
448
+ }
400
449
}
401
450
}
402
451
}
0 commit comments