Skip to content

Commit 110ee3f

Browse files
committed
More details on Lazy Vals
1 parent 4385494 commit 110ee3f

File tree

2 files changed

+91
-7
lines changed

2 files changed

+91
-7
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
layout: doc-page
3+
title: Changed: Lazy Vals - More Details
4+
---
5+
6+
Dotty implements [Version 6](https://docs.scala-lang.org/sips/improved-lazy-val-initialization.html#version-6---no-synchronization-on-this-and-concurrent-initialization-of-fields)
7+
of the [SIP-20] improved lazy vals initialization proposal.
8+
9+
## Motivation
10+
11+
The newly proposed lazy val initialization mechanism aims to eliminate the acquisition of resources
12+
during the execution of the lazy val initializer block, thus reducing the possibility of a deadlock.
13+
The concrete deadlock scenarios that the new lazy val initialization scheme eliminates are
14+
summarized in the [SIP-20] document.
15+
16+
## Implementation
17+
18+
Given a lazy field of the form:
19+
20+
```scala
21+
class Foo {
22+
@volatile lazy val bar = <RHS>
23+
}
24+
```
25+
26+
The Dotty compiler will generate code equivalent to:
27+
28+
```scala
29+
class Foo {
30+
import dotty.runtime.LazyVals
31+
var value_0: Int = _
32+
var bitmap = 0
33+
val bitmap_offset = LazyVals.getOffset(classOf[LazyCell], "bitmap")
34+
35+
def bar(): Int = {
36+
var result: Int = 0
37+
var retry: Boolean = true
38+
var flag: Long = 0L
39+
while (retry) {
40+
flag = LazyVals.get(this, bitmap_offset)
41+
LazyVals.STATE(flag, <field-id>) match {
42+
case <state-0> =>
43+
if (LazyVals.CAS(this, bitmap_offset, flag, <state-1>)) {
44+
try result = <RHS>
45+
catch {
46+
case ex =>
47+
LazyVals.setFlag(this, bitmap_offset, <state-0>, <field-id>)
48+
throw ex
49+
}
50+
value_0 = result
51+
LazyVals.setFlag(this, bitmap_offset, <state-3>, <field-id>)
52+
retry = false
53+
}
54+
case <state-1> | <state-2> =>
55+
LazyVals.wait4Notification(this, bitmap_offset, flag, <field-id>)
56+
case <state-3> =>
57+
retry = false
58+
result = $target
59+
}
60+
}
61+
result
62+
}
63+
}
64+
```
65+
66+
The state of the lazy val `<state-i>` is represented with 4 values: 0, 1, 2 and 3. The state 0
67+
represents a non-initialized lazy val. The state 1 represents a lazy val that is currently being
68+
initialized by some thread. The state 2 denotes that there are concurrent readers of the lazy val.
69+
The state 3 represents a lazy val that has been initialized. `<field-id>` is the id of the lazy
70+
val. This id grows with the number of volatile lazy vals defined in the class.
71+
72+
## Reference
73+
74+
* [SIP-20]
75+
76+
[SIP-20]: https://docs.scala-lang.org/sips/improved-lazy-val-initialization.html
Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
---
22
layout: doc-page
3-
title: Changed: Lazy Vals and @volatile
3+
title: Changed: Lazy Vals
44
---
55

6-
Lazy val initialization no longer guarantees safe publishing. This change was done
7-
to avoid the performance overhead of thread synchonization because many lazy vals are only used in a single-threaded context.
6+
Lazy field initialization no longer guarantees safe publishing. This change was done
7+
to avoid the performance overhead of thread synchonization because most lazy vals are only used in
8+
a single-threaded context.
89

9-
To get back safe publishing you need to annotate a lazy val with `@volatile`. In
10+
## Compatibility considerations
1011

11-
@volatile lazy val x = expr
12+
To get back safe publishing (Scala 2's default) you need to annotate a lazy val with `@volatile`. In
1213

13-
it is guaranteed that readers of a lazy val will see the value of `x`
14-
once it is assigned.
14+
```scala
15+
@volatile lazy val x = expr
16+
```
17+
18+
it is guaranteed that readers of a lazy val will see the value of `x` once it is assigned.
19+
20+
Local lazy vals (i.e. defined inside methods) are left unchanged.
1521

1622
The [ScalaFix](https://scalacenter.github.io/scalafix/) rewrite tool
1723
as well as Dotty's own `-language:Scala2 -rewrite` option will rewrite all normal
1824
lazy vals to volatile ones in order to keep their semantics compatible
1925
with current Scala's.
26+
27+
[More details](./lazy-vals-spec.html)

0 commit comments

Comments
 (0)