@@ -25,8 +25,8 @@ import scala.tools.nsc.backend.jvm.opt._
25
25
* be queried by concurrent threads.
26
26
*/
27
27
abstract class BTypes {
28
- val postProcessorFrontendAccess : PostProcessorFrontendAccess
29
- import postProcessorFrontendAccess .{frontendSynch , recordPerRunCache }
28
+ val frontendAccess : PostProcessorFrontendAccess
29
+ import frontendAccess .{frontendSynch , recordPerRunCache }
30
30
31
31
val coreBTypes : CoreBTypes { val bTypes : BTypes .this .type }
32
32
import coreBTypes ._
@@ -907,46 +907,6 @@ abstract class BTypes {
907
907
nestedClasses : Lazy [List [ClassBType ]], nestedInfo : Lazy [Option [NestedInfo ]],
908
908
inlineInfo : InlineInfo )
909
909
910
- object Lazy {
911
- def apply [T <: AnyRef ](t : => T ): Lazy [T ] = new Lazy [T ](() => t)
912
- }
913
-
914
- final class Lazy [T <: AnyRef ](t : () => T ) {
915
- private var value : T = null .asInstanceOf [T ]
916
-
917
- private var function = {
918
- val tt = t // prevent allocating a field for t
919
- () => { value = tt() }
920
- }
921
-
922
- override def toString = if (value == null ) " <?>" else value.toString
923
-
924
- def onForce (f<
10000
/span>: T => Unit ): Unit = {
925
- if (value != null ) f(value)
926
- else frontendSynch {
927
- if (value != null ) f(value)
928
- else {
929
- val prev = function
930
- function = () => {
931
- prev()
932
- f(value)
933
- }
934
- }
935
- }
936
- }
937
-
938
- def force : T = {
939
- if (value != null ) value
940
- else frontendSynch {
941
- if (value == null ) {
942
- function()
943
- function = null
944
- }
945
- value
946
- }
947
- }
948
- }
949
-
950
910
/**
951
911
* Information required to add a class to an InnerClass table.
952
912
* The spec summary above explains what information is required for the InnerClass entry.
@@ -1011,6 +971,89 @@ abstract class BTypes {
1011
971
* Used only in assertions. Abstract here because its implementation depends on global.
1012
972
*/
1013
973
def isCompilingPrimitive : Boolean
974
+
975
+ // The [[Lazy]] and [[LazyVar]] classes would conceptually be better placed within
976
+ // PostProcessorFrontendAccess (they access the `frontendLock` defined in that class). However,
977
+ // for every component in which we define nested classes, we need to make sure that the compiler
978
+ // knows that all component instances (val frontendAccess) in various classes are all the same,
979
+ // otherwise the prefixes don't match and we get type mismatch errors.
980
+ // Since we already do this dance (val bTypes: GenBCode.this.bTypes.type = GenBCode.this.bTypes)
981
+ // for BTypes, it's easier to add those nested classes to BTypes.
982
+
983
+ object Lazy {
984
+ def apply [T <: AnyRef ](t : => T ): Lazy [T ] = new Lazy [T ](() => t)
985
+ }
986
+
987
+ /**
988
+ * A lazy value that synchronizes on the `frontendLock`, and supports accumulating actions
989
+ * to be executed when it's forced.
990
+ */
991
+ final class Lazy [T <: AnyRef ](t : () => T ) {
992
+ @ volatile private var value : T = _
993
+
994
+ private var initFunction = {
995
+ val tt = t // prevent allocating a field for t
996
+ () => { value = tt() }
997
+ }
998
+
999
+ override def toString = if (value == null ) " <?>" else value.toString
1000
+
1001
+ def onForce (f : T => Unit ): Unit = {
1002
+ if (value != null ) f(value)
1003
+ else frontendSynch {
1004
+ if (value != null ) f(value)
1005
+ else {
1006
+ val prev = initFunction
1007
+ initFunction = () => {
1008
+ prev()
1009
+ f(value)
1010
+ }
1011
+ }
1012
+ }
1013
+ }
1014
+
1015
+ def force : T = {
1016
+ if (value != null ) value
1017
+ else frontendSynch {
1018
+ if (value == null ) {
1019
+ initFunction()
1020
+ initFunction = null
1021
+ }
1022
+ value
1023
+ }
1024
+ }
1025
+ }
1026
+
1027
+ /**
1028
+ * Create state that lazily evaluated (to work around / not worry about initialization ordering
1029
+ * issues). The state is re-initialized in each compiler run when the component is initialized.
1030
+ */
1031
+ def perRunLazy [T ](component : PerRunInit )(init : => T ): LazyVar [T ] = {
1032
+ val r = new LazyVar (() => init)
1033
+ component.perRunInit(r.reInitialize())
1034
+ r
1035
+ }
1036
+
1037
+ /**
1038
+ * This implements a lazy value that can be reset and re-initialized.
1039
+ * It synchronizes on `frontendLock` so that lazy state created through this utility can
1040
+ * be safely initialized in the post-processor.
1041
+ */
1042
+ class LazyVar [T ](init : () => T ) {
1043
+ @ volatile private [this ] var isInit : Boolean = false
1044
+ private [this ] var v : T = _
1045
+
1046
+ def get : T = {
1047
+ if (isInit) v
1048
+ else frontendSynch {
1049
+ if (! isInit) v = init()
1050
+ isInit = true
1051
+ v
1052
+ }
1053
+ }
1054
+
1055
+ def reInitialize (): Unit = frontendSynch(isInit = false )
1056
+ }
1014
1057
}
1015
1058
1016
1059
object BTypes {
0 commit comments