smlnj / legacy

This project is the old version of Standard ML of New Jersey that continues to support older systems (e.g., 32-bit machines).
BSD 3-Clause "New" or "Revised" License
25 stars 10 forks source link

Weak reference behaviour in top-level REPL affected by grouping of declarations in topdecs #270

Open pclayton opened 1 year ago

pclayton commented 1 year ago

Version

110.99.3 (Latest)

Operating System

OS Version

Linux fedora 6.0.18-200.fc36.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Jan 7 17:08:48 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

Processor

System Component

Core system

Severity

Minor

Description

When using weak references in the top level REPL, it appears that the grouping of declarations in topdecs affects whether a weak reference is alive. It is not clear whether this is due to subtle properties of weak references and the top level REPL or is a bug. This can be seen with the following two scripts which report different values for alive2.

The first script:

val c1 = ref 1

val value = ref c1

val weak = SMLofNJ.Weak.weak' value
;

val alive1 = SMLofNJ.Weak.strong' weak

val value = 0
;

val () = SMLofNJ.Internals.GC.doGC 100000
;
val alive2 = SMLofNJ.Weak.strong' weak
;

The second script is the same as the first script except that the first two declarations are followed by ;:

val c1 = ref 1
;
val value = ref c1
;
val weak = SMLofNJ.Weak.weak' value
;

val alive1 = SMLofNJ.Weak.strong' weak

val value = 0
;

val () = SMLofNJ.Internals.GC.doGC 100000
;
val alive2 = SMLofNJ.Weak.strong' weak
;

Transcript

Running the first script using the command

/opt/smlnj/smlnj-110.99.3/bin/sml << ++++
val c1 = ref 1

val value = ref c1

val weak = SMLofNJ.Weak.weak' value
;

val alive1 = SMLofNJ.Weak.strong' weak

val value = 0
;

val () = SMLofNJ.Internals.GC.doGC 100000
;
val alive2 = SMLofNJ.Weak.strong' weak
;
++++

produces the output

Standard ML of New Jersey (64-bit) v110.99.3 [built: Thu Sep 22 14:05:58 2022]
- [autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
[autoloading done]
val c1 = ref 1 : int ref
val value = ref (ref 1) : int ref ref
val weak = - : ?.Weak.weak'
val alive1 = true : bool
val value = 0 : int
val alive2 = true : bool
- 

Running the second script using the command

/opt/smlnj/smlnj-110.99.3/bin/sml << ++++
val c1 = ref 1
;
val value = ref c1
;
val weak = SMLofNJ.Weak.weak' value
;

val alive1 = SMLofNJ.Weak.strong' weak

val value = 0
;

val () = SMLofNJ.Internals.GC.doGC 100000
;
val alive2 = SMLofNJ.Weak.strong' weak
;
++++

produces the output

Standard ML of New Jersey (64-bit) v110.99.3 [built: Thu Sep 22 14:05:58 2022]
- val c1 = ref 1 : int ref
val value = ref (ref 1) : int ref ref
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
[autoloading done]
val weak = - : ?.Weak.weak'
val alive1 = true : bool
val value = 0 : int
val alive2 = false : bool
- 

Expected Behavior

We expect alive2 to be false in the output from both scripts because value is no longer reachable where alive2 is bound.

Steps to Reproduce

See transcript.

Additional Information

No response

Email address

phil.clayton@veonix.com

JohnReppy commented 1 year ago

I believe the issue is that each group of top-level declarations is treated as a compilation unit, which means that they are essentially defined inside an anonymous structure. The upside of this grouping is that they are optimized as a group, but the downside is that the lifetimes of the declarations in a group are going to be the same. It might be possible to tease these apart by generating additional code to rebind the top-level identifiers, but I'm not sure that it is worth the effort.

pclayton commented 1 year ago

If this just affects top-level declarations, then it sounds like there is no issue for applications built with SML/NJ. However it may affect test scripts run through the REPL - I observed this with use too.

dmacqueen commented 1 year ago

The “use” function is meant only for use at top-level in the REPL. It effectively behaves as though one typed the contents of the used file into the REPL. It’s effect when called from within a program is not well defined.

Dave

On Mar 1, 2023, at 4:50 AM, Phil Clayton @.***> wrote:

If this just affects top-level declarations, then it sounds like there is no issue for applications built with SML/NJ. However it may affect test scripts run through the REPL - I observed this with use too.

— Reply to this email directly, view it on GitHub https://github.com/smlnj/legacy/issues/270#issuecomment-1450098868, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGXNPIR5VEHQB5G3OCHJSTWZ5AX3ANCNFSM6AAAAAAVLMK5YU. You are receiving this because you are subscribed to this thread.

David MacQueen @.***