You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Stackability means that all fields of a class are initialized at the end of the
112
115
class body. Scala enforces this property in syntax by demanding that all fields
@@ -159,41 +162,137 @@ Monotonicity is based on a well-known technique called _heap monotonic
159
162
typestate_ to ensure soundness in the presence of aliasing
160
163
[1]. Roughly speaking, it means initialization state should not go backwards.
161
164
162
-
Scopability means that there are no side channels to access to partially constructed objects. Control effects like coroutines, delimited
165
+
Scopability means that there are no side channels to access to partially
166
+
constructed objects. Control effects like coroutines, delimited
163
167
control, resumable exceptions may break the property, as they can transport a
164
168
value upper in the stack (not in scope) to be reachable from the current scope.
165
169
Static fields can also serve as a teleport thus breaks this property. In the
166
170
implementation, we need to enforce that teleported values are transitively
167
171
initialized.
168
172
169
-
The principles enable _local reasoning_ of initialization, which means:
173
+
The three principles above contribute to _local reasoning about initialization_,
174
+
which means:
170
175
171
176
> An initialized environment can only produce initialized values.
172
177
173
178
For example, if the arguments to an `new`-expression are transitively
174
179
initialized, so is the result. If the receiver and arguments in a method call
175
180
are transitively initialized, so is the result.
176
181
182
+
Local reasoning about initialization is the key to give rise to a fast
183
+
initialization checker, as it avoids whole-program analysis.
184
+
185
+
The principle of authority goes hand-in-hand with monotonicity: the principle
186
+
of monotonicity stipulates that initialization states cannot go backwards, while
187
+
the principle of authority stipulates that the initialization states may not
188
+
go forward at arbitrary locations due to aliasing. In Scala, we may only
189
+
advance initialization states of objects in the class body when a field is
190
+
defined with a mandatory initializer or at local reasoning points when the object
191
+
becomes transitively initialized.
192
+
193
+
## Abstract Values
194
+
195
+
There are three fundamental abstractions for initialization states of objects:
196
+
197
+
-__Cold__: A cold object may have uninitialized fields.
198
+
-__Warm__: A warm object has all its fields initialized but may reach _cold_ objects.
199
+
-__Hot__: A hot object is transitively initialized, i.e., it only reaches warm objects.
200
+
201
+
In the initialization checker, the abstraction `Warm` is refined to handle inner
202
+
classes and multiple constructors:
203
+
204
+
-__Warm[C] { outer = V, ctor, args = Vs }__: A warm object of class `C`, where the immediate outer of `C` is `V`, the constructor is `ctor` and constructor arguments are `Vs`.
205
+
206
+
The initialization checker checks each class separately. The abstraction `ThisRef`
207
+
represents the current object under initialization:
208
+
209
+
-__ThisRef[C]__: The current object of class `C` under initialization.
210
+
211
+
The initialization state of the current object is stored in the heap as an
212
+
abstract object. The abstract heap also serves as a cache for the field values
213
+
of warm objects.
214
+
215
+
Two more abstractions are introduced to support functions and conditional
216
+
expressions:
217
+
218
+
-__Fun(e, V, C)__: A abstract function value where `e` is the code, `V` is the
219
+
abstract value for `this` inside the function body and the function is located
220
+
inside the class `C`.
221
+
222
+
-__Refset(Vs)__: A set of abstract values `Vs`.
223
+
177
224
## Rules
178
225
179
226
With the established principles and design goals, following rules are imposed:
180
227
181
-
1. In an assignment `o.x = e`, the expression `e` may only point to transitively initialized objects.
228
+
1. The field access `e.f` or method call `e.m()` is illegal if `e` is _cold_.
229
+
230
+
A cold value should not be used.
231
+
232
+
2. The field access `e.f` is invalid if `e` has the value `ThisRef` and `f` is not initialized.
233
+
234
+
3. In an assignment `o.x = e`, the expression `e` must be _effectively hot_.
182
235
183
236
This is how monotonicity is enforced in the system. Note that in an
184
-
initialization `val f: T = e`, the expression `e` may point to an object
185
-
under initialization. This requires a distinction between mutation and
186
-
initialization in order to enforce different rules. Scala
187
-
has different syntax for them, it thus is not an issue.
237
+
initialization `val f: T = e`, the expression `e` may point to an non-hot
238
+
value.
188
239
189
-
2. Objects under initialization may not be passed as arguments to method calls.
240
+
4. Arguments to method calls must be _effectively hot_.
190
241
191
242
Escape of `this` in the constructor is commonly regarded as an anti-pattern.
243
+
192
244
However, escape of `this` as constructor arguments are allowed, to support
193
245
creation of cyclic data structures. The checker will ensure that the escaped
194
246
non-initialized object is not used, i.e. calling methods or accessing fields
195
247
on the escaped object is not allowed.
196
248
249
+
An exception is for calling synthetic `apply`s of case classes. For example,
250
+
the method call `Some.apply(e)` will be interpreted as `new Some(e)`, thus
251
+
is valid even if `e` is not hot.
252
+
253
+
Another exception too this rule is parametric method calls. For example, in
254
+
`List.apply(e)`, the argument `e` may be non-hot. If that is the case, the
255
+
result value of the parametric method call is taken as _cold_.
256
+
257
+
5. Method calls on hot values with effectively hot arguments product hot results.
258
+
259
+
This rule is assured by local reasoning about initialization.
260
+
261
+
6. Method calls on `ThisRef` and warm values will be resolved statically and the
262
+
method bodies will be checked.
263
+
264
+
7. In a new expression `new p.C(args)`, if the values of `p` and `args` are
265
+
effectively hot, then the result value is also hot.
266
+
267
+
This is assured by local reasoning about initialization.
268
+
269
+
8. In a new expression `new p.C(args)`, if any value of `p` and `args` is not
270
+
effectively hot, then the result value takes the form `Warm[C] { outer = Vp, args = Vargs }`.
271
+
272
+
In the above, `Vp` is the widened value of `p` --- the widening happens if `p`
273
+
is a warm value `Warm[D] { outer = V, args }` and we widen it to
274
+
`Warm[D] { outer = Cold, args }`.
275
+
276
+
The variable `Vargs` represents values of `args` with non-hot values widened
277
+
to `Cold`.
278
+
279
+
The widening is motivated to finitize the abstract domain and ensure
280
+
terimination of the initialization check.
281
+
282
+
9. The scrutinee in pattern match, the values in return and throw statements must be _effectively hot_.
283
+
284
+
A value `v` is _effectively hot_ if any of the following is true:
285
+
286
+
-`v` is `Hot`.
287
+
-`v` is `ThisRef` and all fields of the underlying object are initialized.
288
+
-`v` is `Warm[C] { outer = V, ctor, args = Vs }` and
289
+
1.`C` does not contain inner classes;
290
+
2. Calling any method on `v` encounters no errors and the method return value is _effectively hot_;
291
+
3. Each field of `v` is _effectively hot_.
292
+
-`v` is `Fun(e, V, C)` and calling the function encounters no errors and the
293
+
function return value is _effectively hot_.
294
+
-`ThisRef` is _effectively hot_.
295
+
197
296
## Modularity
198
297
199
298
The analysis takes the primary constructor of concrete classes as entry points.
@@ -234,3 +333,4 @@ mark some fields as lazy.
234
333
235
334
1. Fähndrich, M. and Leino, K.R.M., 2003, July. [_Heap monotonic typestates_](https://www.microsoft.com/en-us/research/publication/heap-monotonic-typestate/). In International Workshop on Aliasing, Confinement and Ownership in object-oriented programming (IWACO).
236
335
2. Fengyun Liu, Ondřej Lhoták, Aggelos Biboudis, Paolo G. Giarrusso, and Martin Odersky. 2020. [_A type-and-effect system for object initialization_](https://dl.acm.org/doi/10.1145/3428243). OOPSLA, 2020.
0 commit comments