9
9
import scala.collection.mutable.ListBuffer
10
10
import symtab.Flags._
11
11
import symtab.SymbolTable
12
import scala.language.postfixOps
13
14
/** XXX to resolve: TreeGen only assumes global is a SymbolTable, but
14
15
* TreeDSL at the moment expects a Global. Can we get by with SymbolTable?
16
abstract class TreeGen {
17
val global: SymbolTable
17
abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
20
21
import definitions._
22
def rootId(name: Name) = Select(Ident(nme.ROOTPKG), name)
23
def rootScalaDot(name: Name) = Select(rootId(nme.scala_) setSymbol ScalaPackage, name)
24
def scalaDot(name: Name) = Select(Ident(nme.scala_) setSymbol ScalaPackage, name)
25
def scalaAnyRefConstr = scalaDot(tpnme.AnyRef)
26
def scalaUnitConstr = scalaDot(tpnme.Unit)
27
def scalaScalaObjectConstr = scalaDot(tpnme.ScalaObject)
28
def productConstr = scalaDot(tpnme.Product)
29
def serializableConstr = scalaDot(tpnme.Serializable)
31
def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree, abstractFun: Boolean = false): Tree = {
32
val cls = if (abstractFun)
33
mkAttributedRef(AbstractFunctionClass(argtpes.length))
35
mkAttributedRef(FunctionClass(argtpes.length))
36
AppliedTypeTree(cls, argtpes :+ restpe)
39
/** Builds a reference to value whose type is given stable prefix.
40
* The type must be suitable for this. For example, it
41
* must not be a TypeRef pointing to an abstract type variable.
43
def mkAttributedQualifier(tpe: Type): Tree =
44
mkAttributedQualifier(tpe, NoSymbol)
46
/** Builds a reference to value whose type is given stable prefix.
47
* If the type is unsuitable, e.g. it is a TypeRef for an
48
* abstract type variable, then an Ident will be made using
49
* termSym as the Ident's symbol. In that case, termSym must
52
def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = tpe match {
55
case ThisType(clazz) =>
56
if (clazz.isEffectiveRoot) EmptyTree
57
else mkAttributedThis(clazz)
58
case SingleType(pre, sym) =>
59
applyIfNoArgs(mkAttributedStableRef(pre, sym))
60
case TypeRef(pre, sym, args) =>
63
} else if (sym.isModuleClass) {
64
applyIfNoArgs(mkAttributedRef(pre, sym.sourceModule))
65
} else if (sym.isModule || sym.isClass) {
66
assert(phase.erasedTypes, tpe)
68
} else if (sym.isType) {
69
assert(termSym != NoSymbol, tpe)
70
mkAttributedIdent(termSym) setType tpe
72
mkAttributedRef(pre, sym)
75
case ConstantType(value) =>
76
Literal(value) setType tpe
78
case AnnotatedType(_, atp, _) =>
79
mkAttributedQualifier(atp)
81
case RefinedType(parents, _) =>
82
// I am unclear whether this is reachable, but
83
// the following implementation looks logical -Lex
84
val firstStable = parents.find(_.isStable)
85
assert(!firstStable.isEmpty, tpe)
86
mkAttributedQualifier(firstStable.get)
89
abort("bad qualifier: " + tpe)
91
/** If this is a reference to a method with an empty
92
* parameter list, wrap it in an apply.
94
private def applyIfNoArgs(qual: Tree) = qual.tpe match {
95
case MethodType(Nil, restpe) => Apply(qual, Nil) setType restpe
99
/** Builds a reference to given symbol with given stable prefix. */
100
def mkAttributedRef(pre: Type, sym: Symbol): Tree = {
101
val qual = mkAttributedQualifier(pre)
103
case EmptyTree => mkAttributedIdent(sym)
104
case This(clazz) if qual.symbol.isEffectiveRoot => mkAttributedIdent(sym)
105
case _ => mkAttributedSelect(qual, sym)
109
/** Builds a reference to given symbol. */
110
def mkAttributedRef(sym: Symbol): Tree =
111
if (sym.owner.isClass) mkAttributedRef(sym.owner.thisType, sym)
112
else mkAttributedIdent(sym)
114
/** Builds an untyped reference to given symbol. */
115
def mkUnattributedRef(sym: Symbol): Tree =
116
if (sym.owner.isClass) Select(This(sym.owner), sym)
119
/** Replaces tree type with a stable type if possible */
120
def stabilize(tree: Tree): Tree = {
121
for(tp <- stableTypeFor(tree)) tree.tpe = tp
125
/** Computes stable type for a tree if possible */
126
def stableTypeFor(tree: Tree): Option[Type] = tree match {
127
case Ident(_) if tree.symbol.isStable =>
128
Some(singleType(tree.symbol.owner.thisType, tree.symbol))
129
case Select(qual, _) if ((tree.symbol ne null) && (qual.tpe ne null)) && // turned assert into guard for #4064
130
tree.symbol.isStable && qual.tpe.isStable =>
131
Some(singleType(qual.tpe, tree.symbol))
136
/** Cast `tree' to type `pt' */
137
def mkCast(tree: Tree, pt: Type): Tree = {
138
if (settings.debug.value) log("casting " + tree + ":" + tree.tpe + " to " + pt)
139
assert(!tree.tpe.isInstanceOf[MethodType], tree)
140
assert(!pt.typeSymbol.isPackageClass)
141
assert(!pt.typeSymbol.isPackageObjectClass)
142
assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize)) //@MAT only called during erasure, which already takes care of that
143
atPos(tree.pos)(mkAsInstanceOf(tree, pt, false))
146
/** Builds a reference with stable type to given symbol */
147
def mkAttributedStableRef(pre: Type, sym: Symbol): Tree =
148
stabilize(mkAttributedRef(pre, sym))
150
def mkAttributedStableRef(sym: Symbol): Tree =
151
stabilize(mkAttributedRef(sym))
153
def mkAttributedThis(sym: Symbol): Tree =
154
This(sym.name.toTypeName) setSymbol sym setType sym.thisType
156
def mkAttributedIdent(sym: Symbol): Tree =
157
Ident(sym.name) setSymbol sym setType sym.tpe
159
def mkAttributedSelect(qual: Tree, sym: Symbol): Tree = {
160
// Tests involving the repl fail without the .isEmptyPackage condition.
161
if (qual.symbol != null && (qual.symbol.isEffectiveRoot || qual.symbol.isEmptyPackage))
162
mkAttributedIdent(sym)
165
if (sym != null && sym.owner.isPackageObjectClass && sym.owner.owner == qual.tpe.typeSymbol) {
166
val obj = sym.owner.sourceModule
167
Select(qual, nme.PACKAGEkw) setSymbol obj setType singleType(qual.tpe, obj)
171
val tree = Select(pkgQualifier, sym)
172
if (pkgQualifier.tpe == null) tree
173
else tree setType (qual.tpe memberType sym)
177
private def mkTypeApply(value: Tree, tpe: Type, what: Symbol) =
180
mkAttributedSelect(value, what),
181
List(TypeTree(tpe.normalize))
185
/** Builds an instance test with given value and type. */
186
def mkIsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree =
187
mkTypeApply(value, tpe, (if (any) Any_isInstanceOf else Object_isInstanceOf))
189
/** Builds a cast with given value and type. */
190
def mkAsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree =
191
mkTypeApply(value, tpe, (if (any) Any_asInstanceOf else Object_asInstanceOf))
193
/** Cast `tree' to 'pt', unless tpe is a subtype of pt, or pt is Unit. */
194
def maybeMkAsInstanceOf(tree: Tree, pt: Type, tpe: Type, beforeRefChecks: Boolean = false): Tree =
195
if ((pt == UnitClass.tpe) || (tpe <:< pt)) {
196
log("no need to cast from " + tpe + " to " + pt)
201
TypeApply(mkAttributedSelect(tree, Any_asInstanceOf), List(TypeTree(pt)))
203
mkAsInstanceOf(tree, pt)
206
def mkClassOf(tp: Type): Tree =
207
Literal(Constant(tp)) setType ConstantType(Constant(tp))// ClassType(tp)
209
23
def mkCheckInit(tree: Tree): Tree = {
211
25
if (tree.tpe != null || !tree.hasSymbol) tree.tpe
221
/** Builds a list with given head and tail. */
222
def mkNewCons(head: Tree, tail: Tree): Tree =
223
New(Apply(mkAttributedRef(ConsClass), List(head, tail)))
225
/** Builds a list with given head and tail. */
226
def mkNil: Tree = mkAttributedRef(NilModule)
228
/** Builds a tree representing an undefined local, as in
230
* which is appropriate to the given Type.
35
/** Builds a fully attributed wildcard import node.
232
def mkZero(tp: Type): Tree = {
233
val tree = tp.typeSymbol match {
234
case UnitClass => Literal(())
235
case BooleanClass => Literal(false)
236
case FloatClass => Literal(0.0f)
237
case DoubleClass => Literal(0.0d)
238
case ByteClass => Literal(0.toByte)
239
case ShortClass => Literal(0.toShort)
240
case IntClass => Literal(0)
241
case LongClass => Literal(0L)
242
case CharClass => Literal(0.toChar)
244
if (NullClass.tpe <:< tp) Literal(null: Any)
245
else abort("Cannot determine zero for " + tp)
37
def mkWildcardImport(pkg: Symbol): Import = {
38
assert(pkg ne null, this)
39
val qual = gen.mkAttributedStableRef(pkg)
44
setInfo analyzer.ImportType(qual)
47
Import(qual, ImportSelector.wildList)
250
/** Builds a tuple */
251
def mkTuple(elems: List[Tree]): Tree =
252
if (elems.isEmpty) Literal(())
254
Select(mkAttributedRef(TupleClass(elems.length).caseModule), nme.apply),
258
def mkAnd(tree1: Tree, tree2: Tree): Tree =
259
Apply(Select(tree1, Boolean_and), List(tree2))
262
def mkOr(tree1: Tree, tree2: Tree): Tree =
263
Apply(Select(tree1, Boolean_or), List(tree2))
265
54
// wrap the given expression in a SoftReference so it can be gc-ed
266
def mkSoftRef(expr: Tree): Tree = New(TypeTree(SoftReferenceClass.tpe), List(List(expr)))
55
def mkSoftRef(expr: Tree): Tree = atPos(expr.pos)(New(SoftReferenceClass.tpe, expr))
57
// annotate the expression with @unchecked
58
def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) {
59
// This can't be "Annotated(New(UncheckedClass), expr)" because annotations
60
// are very picky about things and it crashes the compiler with "unexpected new".
61
Annotated(New(scalaDot(UncheckedClass.name), ListOfNil), expr)
63
// if it's a Match, mark the selector unchecked; otherwise nothing.
64
def mkUncheckedMatch(tree: Tree) = tree match {
65
case Match(selector, cases) => atPos(tree.pos)(Match(mkUnchecked(selector), cases))
69
def mkSynthSwitchSelector(expr: Tree): Tree = atPos(expr.pos) {
70
// This can't be "Annotated(New(SwitchClass), expr)" because annotations
71
// are very picky about things and it crashes the compiler with "unexpected new".
72
Annotated(Ident(nme.synthSwitch), expr)
75
// TODO: would be so much nicer if we would know during match-translation (i.e., type checking)
76
// whether we should emit missingCase-style apply (and isDefinedAt), instead of transforming trees post-factum
78
def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = unknownTree(orig)
79
def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = unknownTree(orig)
80
def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree): Tree = unknownTree(orig)
82
def genVirtualizedMatch(prologue: List[Tree], cases: List[Tree], matchEndDef: Tree): Tree = Block(prologue ++ cases, matchEndDef)
84
def apply(matchExpr: Tree): Tree = matchExpr match {
85
// old-style match or virtpatmat switch
86
case Match(selector, cases) => // println("simple match: "+ (selector, cases) + "for:\n"+ matchExpr )
87
caseMatch(matchExpr, selector, cases, identity)
88
// old-style match or virtpatmat switch
89
case Block((vd: ValDef) :: Nil, orig@Match(selector, cases)) => // println("block match: "+ (selector, cases, vd) + "for:\n"+ matchExpr )
90
caseMatch(matchExpr, selector, cases, m => copyBlock(matchExpr, List(vd), m))
92
case Apply(Apply(TypeApply(Select(tgt, nme.runOrElse), targs), List(scrut)), List(matcher)) if opt.virtPatmat => // println("virt match: "+ (tgt, targs, scrut, matcher) + "for:\n"+ matchExpr )
93
caseVirtualizedMatch(matchExpr, tgt, targs, scrut, matcher)
94
// optimized version of virtpatmat
95
case Block(stats, matchEndDef) if opt.virtPatmat && (stats forall treeInfo.hasSynthCaseSymbol) =>
96
// the assumption is once we encounter a case, the remainder of the block will consist of cases
97
// the prologue may be empty, usually it is the valdef that stores the scrut
98
val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef])
99
caseVirtualizedMatchOpt(matchExpr, prologue, cases, matchEndDef, identity)
100
// optimized version of virtpatmat
101
case Block(outerStats, orig@Block(stats, matchEndDef)) if opt.virtPatmat && (stats forall treeInfo.hasSynthCaseSymbol) =>
102
val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef])
103
caseVirtualizedMatchOpt(matchExpr, prologue, cases, matchEndDef, m => copyBlock(matchExpr, outerStats, m))
108
def unknownTree(t: Tree): Tree = throw new MatchError(t)
109
def copyBlock(orig: Tree, stats: List[Tree], expr: Tree): Block = Block(stats, expr)
111
def dropSyntheticCatchAll(cases: List[CaseDef]): List[CaseDef] =
112
if (!opt.virtPatmat) cases
114
case CaseDef(pat, EmptyTree, Throw(Apply(Select(New(exTpt), nme.CONSTRUCTOR), _))) if (treeInfo.isWildcardArg(pat) && (exTpt.tpe.typeSymbol eq MatchErrorClass)) => false
115
case CaseDef(pat, guard, body) => true
268
119
def mkCached(cvar: Symbol, expr: Tree): Tree = {
269
120
val cvarRef = mkUnattributedRef(cvar)
305
156
def mkModuleAccessDef(accessor: Symbol, msym: Symbol) =
306
157
DefDef(accessor, Select(This(msym.owner), msym))
308
def newModule(accessor: Symbol, tpe: Type) =
310
List(for (pt <- tpe.typeSymbol.primaryConstructor.info.paramTypes)
311
yield This(accessor.owner.enclClass)))
159
def newModule(accessor: Symbol, tpe: Type) = {
160
val ps = tpe.typeSymbol.primaryConstructor.info.paramTypes
161
if (ps.isEmpty) New(tpe)
162
else New(tpe, This(accessor.owner.enclClass))
314
166
def mkModuleAccessDcl(accessor: Symbol) =
315
167
DefDef(accessor setFlag lateDEFERRED, EmptyTree)
317
169
def mkRuntimeCall(meth: Name, args: List[Tree]): Tree =
318
Apply(Select(mkAttributedRef(ScalaRunTimeModule), meth), args)
170
mkRuntimeCall(meth, Nil, args)
320
172
def mkRuntimeCall(meth: Name, targs: List[Type], args: List[Tree]): Tree =
321
Apply(TypeApply(Select(mkAttributedRef(ScalaRunTimeModule), meth), targs map TypeTree), args)
173
mkMethodCall(ScalaRunTimeModule, meth, targs, args)
175
def mkSysErrorCall(message: String): Tree =
176
mkMethodCall(Sys_error, List(Literal(Constant(message))))
178
/** A creator for a call to a scala.reflect.Manifest or ClassManifest factory method.
180
* @param full full or partial manifest (target will be Manifest or ClassManifest)
181
* @param constructor name of the factory method (e.g. "classType")
182
* @param tparg the type argument
183
* @param args value arguments
186
def mkManifestFactoryCall(full: Boolean, constructor: String, tparg: Type, args: List[Tree]): Tree =
188
if (full) FullManifestModule else PartialManifestModule,
189
newTermName(constructor),
323
194
/** Make a synchronized block on 'monitor'. */
324
195
def mkSynchronized(monitor: Tree, body: Tree): Tree =
325
196
Apply(Select(monitor, Object_synchronized), List(body))
198
def mkAppliedTypeForCase(clazz: Symbol): Tree = {
199
val numParams = clazz.typeParams.size
200
if (clazz.typeParams.isEmpty) Ident(clazz)
201
else AppliedTypeTree(Ident(clazz), 1 to numParams map (_ => Bind(tpnme.WILDCARD, EmptyTree)) toList)
203
def mkBindForCase(patVar: Symbol, clazz: Symbol, targs: List[Type]): Tree = {
204
Bind(patVar, Typed(Ident(nme.WILDCARD),
205
if (targs.isEmpty) mkAppliedTypeForCase(clazz)
206
else AppliedTypeTree(Ident(clazz), targs map TypeTree)
209
def mkSuperSelect = Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR)
327
211
def wildcardStar(tree: Tree) =
328
212
atPos(tree.pos) { Typed(tree, Ident(tpnme.WILDCARD_STAR)) }
330
def paramToArg(vparam: Symbol) = {
331
val arg = Ident(vparam)
332
if (isRepeatedParamType(vparam.tpe)) wildcardStar(arg)
336
def paramToArg(vparam: ValDef) = {
337
val arg = Ident(vparam.name)
338
if (treeInfo.isRepeatedParamType(vparam.tpt)) wildcardStar(arg)
342
/** Make forwarder to method `target', passing all parameters in `params' */
214
def paramToArg(vparam: Symbol): Tree =
215
paramToArg(Ident(vparam), isRepeatedParamType(vparam.tpe))
217
def paramToArg(vparam: ValDef): Tree =
218
paramToArg(Ident(vparam.name), treeInfo.isRepeatedParamType(vparam.tpt))
220
def paramToArg(arg: Ident, isRepeatedParam: Boolean): Tree =
221
if (isRepeatedParam) wildcardStar(arg) else arg
223
/** Make forwarder to method `target`, passing all parameters in `params` */
343
224
def mkForwarder(target: Tree, vparamss: List[List[Symbol]]) =
344
225
(target /: vparamss)((fn, vparams) => Apply(fn, vparams map paramToArg))
348
229
* apply the element type directly.
350
231
def mkWrapArray(tree: Tree, elemtp: Type) = {
351
val sym = elemtp.typeSymbol
353
if (isValueClass(sym)) "wrap"+sym.name+"Array"
354
else if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(sym)) "wrapRefArray"
355
else "genericWrapArray"
357
if (isValueClass(sym))
358
Apply(Select(mkAttributedRef(PredefModule), meth), List(tree))
360
Apply(TypeApply(Select(mkAttributedRef(PredefModule), meth), List(TypeTree(elemtp))), List(tree))
234
wrapArrayMethodName(elemtp),
235
if (isPrimitiveValueType(elemtp)) Nil else List(elemtp),
240
/** Cast `tree` to type `pt` by creating
241
* one of the calls of the form
243
* x.asInstanceOf[`pt`] up to phase uncurry
244
* x.asInstanceOf[`pt`]() if after uncurry but before erasure
245
* x.$asInstanceOf[`pt`]() if at or after erasure
247
def mkCast(tree: Tree, pt: Type): Tree = {
248
debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase)
249
assert(!tree.tpe.isInstanceOf[MethodType], tree)
250
assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize))
252
mkAsInstanceOf(tree, pt, any = !phase.next.erasedTypes, wrapInApply = isAtPhaseAfter(currentRun.uncurryPhase))
256
// drop annotations generated by CPS plugin etc, since its annotationchecker rejects T @cps[U] <: Any
257
// let's assume for now annotations don't affect casts, drop them there, and bring them back using the outer Typed tree
258
def mkCastPreservingAnnotations(tree: Tree, pt: Type) =
259
Typed(mkCast(tree, pt.withoutAnnotations.dealias), TypeTree(pt))
363
261
/** Generate a cast for tree Tree representing Array with
364
262
* elem type elemtp to expected type pt.
366
264
def mkCastArray(tree: Tree, elemtp: Type, pt: Type) =
367
if (elemtp.typeSymbol == AnyClass && isValueClass(tree.tpe.typeArgs.head.typeSymbol))
368
mkCast(mkRuntimeCall("toObjectArray", List(tree)), pt)
265
if (elemtp.typeSymbol == AnyClass && isPrimitiveValueType(tree.tpe.typeArgs.head))
266
mkCast(mkRuntimeCall(nme.toObjectArray, List(tree)), pt)
270
def mkZeroContravariantAfterTyper(tp: Type): Tree = {
271
// contravariant -- for replacing an argument in a method call
272
// must use subtyping, as otherwise we miss types like `Any with Int`
274
if (NullClass.tpe <:< tp) Literal(Constant(null))
275
else if (UnitClass.tpe <:< tp) Literal(Constant())
276
else if (BooleanClass.tpe <:< tp) Literal(Constant(false))
277
else if (FloatClass.tpe <:< tp) Literal(Constant(0.0f))
278
else if (DoubleClass.tpe <:< tp) Literal(Constant(0.0d))
279
else if (ByteClass.tpe <:< tp) Literal(Constant(0.toByte))
280
else if (ShortClass.tpe <:< tp) Literal(Constant(0.toShort))
281
else if (IntClass.tpe <:< tp) Literal(Constant(0))
282
else if (LongClass.tpe <:< tp) Literal(Constant(0L))
283
else if (CharClass.tpe <:< tp) Literal(Constant(0.toChar))
284
else mkCast(Literal(Constant(null)), tp)
372
289
/** Translate names in Select/Ident nodes to type names.
374
291
def convertToTypeName(tree: Tree): Option[RefTree] = tree match {
384
301
case _ => EmptyTree
304
/** Create a ValDef initialized to the given expression, setting the
305
* symbol to its packed type, and an function for creating Idents
308
private def mkPackedValDef(expr: Tree, owner: Symbol, name: Name): (ValDef, () => Ident) = {
309
val packedType = typer.packedType(expr, owner)
310
val sym = owner.newValue(name, expr.pos.makeTransparent, SYNTHETIC) setInfo packedType
312
(ValDef(sym, expr), () => Ident(sym) setPos sym.pos.focus setType expr.tpe)
387
315
/** Used in situations where you need to access value of an expression several times
389
317
def evalOnce(expr: Tree, owner: Symbol, unit: CompilationUnit)(within: (() => Tree) => Tree): Tree = {
391
if (treeInfo.isPureExpr(expr)) {
319
if (treeInfo.isExprSafeToInline(expr)) {
392
320
within(() => if (used) expr.duplicate else { used = true; expr })
394
val temp = owner.newValue(expr.pos.makeTransparent, unit.freshTermName("ev$"))
395
.setFlag(SYNTHETIC).setInfo(expr.tpe)
396
val containing = within(() => Ident(temp) setPos temp.pos.focus setType expr.tpe)
323
val (valDef, identFn) = mkPackedValDef(expr, owner, unit.freshTermName("ev$"))
324
val containing = within(identFn)
397
325
ensureNonOverlapping(containing, List(expr))
398
Block(List(ValDef(temp, expr)), containing) setPos (containing.pos union expr.pos)
326
Block(List(valDef), containing) setPos (containing.pos union expr.pos)
425
353
else Block(prefix, containing) setPos (prefix.head.pos union containing.pos)
428
/** Return a double-checked locking idiom around the syncBody tree. It guards with 'cond' and
429
* synchronizez on 'clazz.this'. Additional statements can be included after initialization,
356
/** Return the synchronized part of the double-checked locking idiom around the syncBody tree. It guards with `cond` and
357
* synchronizez on `clazz.this`. Additional statements can be included after initialization,
430
358
* (outside the synchronized block).
432
360
* The idiom works only if the condition is using a volatile field.
433
361
* @see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
435
def mkDoubleCheckedLocking(clazz: Symbol, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
436
mkDoubleCheckedLocking(mkAttributedThis(clazz), cond, syncBody, stats)
363
def mkSynchronizedCheck(clazz: Symbol, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
364
mkSynchronizedCheck(mkAttributedThis(clazz), cond, syncBody, stats)
438
def mkDoubleCheckedLocking(attrThis: Tree, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree = {
443
If(cond, Block(syncBody: _*), EmptyTree)) ::
366
def mkSynchronizedCheck(attrThis: Tree, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
367
Block(mkSynchronized(
369
If(cond, Block(syncBody: _*), EmptyTree)) ::