@@ -75,8 +75,11 @@ import StdNames.nme
75
75
* Unreachable jumps will be eliminated by local dead code analysis.
76
76
* After JVM is smart enough to remove next-line jumps
77
77
*
78
- * Note that Label DefDefs can be only nested in Block, otherwise no one would
79
- * be able to call them Other DefDefs are eliminated
78
+ * Note that his phase Ychecking this phase required softening scoping rules
79
+ * as it intentionally allowed to break scoping rules inside methods for labels.
80
+ * This is modified by setting `labelsReordered` flag in Phases.
81
+ *
82
+ * @author Dmitry Petrashko
80
83
*/
81
84
class LabelDefs extends MiniPhaseTransform {
82
85
def phaseName : String = " labelDef"
@@ -90,76 +93,24 @@ class LabelDefs extends MiniPhaseTransform {
90
93
else {
91
94
collectLabelDefs.clear
92
95
val newRhs = collectLabelDefs.transform(tree.rhs)
93
- val labelCalls = collectLabelDefs.labelCalls
94
- var entryPoints = collectLabelDefs.parentLabelCalls
95
96
var labelDefs = collectLabelDefs.labelDefs
96
- var callCounts = collectLabelDefs.callCounts
97
-
98
- // make sure that for every label there's a single location it should return and single entry point
99
- // if theres already a location that it returns to that's a failure
100
- val disallowed = new mutable.HashMap [Symbol , Tree ]()
101
- queue.sizeHint(labelCalls.size + entryPoints.size)
102
97
103
98
def putLabelDefsNearCallees = new TreeMap () {
104
99
105
100
override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = {
106
101
tree match {
107
- case t : Apply if (entryPoints.contains(t)) =>
108
- entryPoints = entryPoints - t
109
- labelLevel = labelLevel + 1
110
- val r = Block (moveLabels(t), t)
111
- labelLevel = labelLevel - 1
112
- if (labelLevel == 0 ) beingAppended.clear()
113
- r
114
- case _ => if (entryPoints.nonEmpty && labelDefs.nonEmpty) super .transform(tree) else tree
115
- }
102
+ case t : Apply if labelDefs.contains(t.symbol) =>
103
+ val labelDef = labelDefs(t.symbol)
104
+ labelDefs -= t.symbol
116
105
117
- }
118
- }
106
+ val labelDef2 = transform(labelDef)
107
+ Block (labelDef2 :: Nil , t)
119
108
120
- def moveLabels (entryPoint : Apply ): List [Tree ] = {
121
- val entrySym = entryPoint.symbol
122
- if ((entrySym is Flags .Label ) && labelDefs.contains(entrySym)) {
123
- val visitedNow = new mutable.HashMap [Symbol , Tree ]()
124
- val treesToAppend = new ArrayBuffer [Tree ]() // order matters. parents should go first
125
- treesToAppend += labelDefs(entrySym)
126
- queue.clear()
127
-
128
- var visited = 0
129
- queue += entryPoint
130
- while (visited < queue.size) {
131
- val owningLabelDefSym = queue(visited).symbol
132
- for (call <- labelCalls(owningLabelDefSym)) {
133
- val callSym = call.symbol
134
- if (! beingAppended.contains(callSym)) {
135
- if (disallowed.contains(callSym)) {
136
- val oldCall = disallowed(callSym)
137
- ctx.error(s " Multiple return locations for Label $oldCall and $call" , callSym.pos)
138
- } else {
139
- if ((! visitedNow.contains(callSym)) && labelDefs.contains(callSym)) {
140
- val defTree = labelDefs(callSym)
141
- visitedNow.put(callSym, defTree)
142
- val callCount = callCounts(callSym)
143
- if (callCount > 1 ) {
144
- if (! treesToAppend.contains(defTree)) {
145
- treesToAppend += defTree
146
- queue += call
147
-
148
- }
149
- } else if (entryPoint.symbol ne callSym) entryPoints += call
150
- }
151
- }
152
- }
153
- }
154
-
155
- visited += 1
109
+ case _ => if (labelDefs.nonEmpty) super .transform(tree) else tree
156
110
}
157
- beingAppended ++= treesToAppend.map(_.symbol)
158
- treesToAppend.toList.map(putLabelDefsNearCallees.transform)
159
- } else Nil
111
+ }
160
112
}
161
113
162
-
163
114
val res = cpy.DefDef (tree)(rhs = putLabelDefsNearCallees.transform(newRhs))
164
115
165
116
res
@@ -168,22 +119,11 @@ class LabelDefs extends MiniPhaseTransform {
168
119
169
120
object collectLabelDefs extends TreeMap () {
170
121
171
- // label calls from this DefDef
172
- var parentLabelCalls : mutable.Set [Tree ] = new mutable.HashSet [Tree ]()
173
- var callCounts : mutable.Map [Symbol , Int ] = new mutable.HashMap [Symbol , Int ]().withDefaultValue(0 )
174
-
175
- def shouldMoveLabel = true
176
-
177
122
// labelSymbol -> Defining tree
178
123
val labelDefs = new mutable.HashMap [Symbol , Tree ]()
179
- // owner -> all calls by this owner
180
- val labelCalls = new mutable.HashMap [Symbol , mutable.Set [Tree ]]()
181
- var owner : Symbol = null
182
124
183
125
def clear = {
184
- parentLabelCalls.clear()
185
126
labelDefs.clear()
186
- labelCalls.clear()
187
127
}
188
128
189
129
override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = tree match {
@@ -196,30 +136,14 @@ class LabelDefs extends MiniPhaseTransform {
196
136
}
197
137
case t : DefDef =>
198
138
assert(t.symbol is Flags .Label )
199
-
200
- val st = parentLabelCalls
201
- parentLabelCalls = new mutable.HashSet [Tree ]()
202
- val symt = owner
203
- owner = t.symbol
204
-
205
139
val r = super .transform(tree)
206
-
207
- owner = symt
208
- labelCalls(r.symbol) = parentLabelCalls
209
- parentLabelCalls = st
210
-
211
- if (shouldMoveLabel) {
212
- labelDefs(r.symbol) = r
213
- EmptyTree
214
- } else r
140
+ labelDefs(r.symbol) = r
141
+ EmptyTree
215
142
case t : Apply if t.symbol is Flags .Label =>
216
143
val sym = t.symbol
217
- parentLabelCalls = parentLabelCalls + t
218
- if (owner != sym) callCounts(sym) = callCounts(sym) + 1
219
144
super .transform(tree)
220
145
case _ =>
221
146
super .transform(tree)
222
-
223
147
}
224
148
}
225
149
}
0 commit comments