@@ -189,6 +189,7 @@ export function inferMutationAliasingEffects(
189189}
190190
191191class Context {
192+ internedEffects : Map < string , AliasingEffect > = new Map ( ) ;
192193 instructionSignatureCache : Map < Instruction , InstructionSignature > = new Map ( ) ;
193194 effectInstructionValueCache : Map < AliasingEffect , InstructionValue > =
194195 new Map ( ) ;
@@ -200,6 +201,17 @@ class Context {
200201 this . isFuctionExpression = isFunctionExpression ;
201202 this . fn = fn ;
202203 }
204+
205+ internEffect ( effect : AliasingEffect ) : AliasingEffect {
206+ const hash = hashEffect ( effect ) ;
207+ let interned = this . internedEffects . get ( hash ) ;
208+ if ( interned == null ) {
209+ console . log ( `intern: ${ hash } ` ) ;
210+ this . internedEffects . set ( hash , effect ) ;
211+ interned = effect ;
212+ }
213+ return interned ;
214+ }
203215}
204216
205217function inferParam (
@@ -388,10 +400,11 @@ function applySignature(
388400function applyEffect (
389401 context : Context ,
390402 state : InferenceState ,
391- effect : AliasingEffect ,
403+ _effect : AliasingEffect ,
392404 aliased : Set < IdentifierId > ,
393405 effects : Array < AliasingEffect > ,
394406) : void {
407+ const effect = context . internEffect ( _effect ) ;
395408 if ( DEBUG ) {
396409 console . log ( printAliasingEffect ( effect ) ) ;
397410 }
@@ -465,15 +478,12 @@ function applyEffect(
465478 break ;
466479 }
467480 default : {
468- // Even if the source is non-primitive, the destination may be. skip primitives.
469- if ( ! isPrimitiveType ( effect . into . identifier ) ) {
470- effects . push ( {
471- // OK: recording information flow
472- kind : 'CreateFrom' , // prev Alias
473- from : effect . from ,
474- into : effect . into ,
475- } ) ;
476- }
481+ effects . push ( {
482+ // OK: recording information flow
483+ kind : 'CreateFrom' , // prev Alias
484+ from : effect . from ,
485+ into : effect . into ,
486+ } ) ;
477487 }
478488 }
479489 break ;
@@ -1363,11 +1373,19 @@ function computeSignatureForInstruction(
13631373 }
13641374 case 'PropertyLoad' :
13651375 case 'ComputedLoad' : {
1366- effects . push ( {
1367- kind : 'CreateFrom' ,
1368- from : value . object ,
1369- into : lvalue ,
1370- } ) ;
1376+ if ( isPrimitiveType ( lvalue . identifier ) ) {
1377+ effects . push ( {
1378+ kind : 'Create' ,
1379+ into : lvalue ,
1380+ value : ValueKind . Primitive ,
1381+ } ) ;
1382+ } else {
1383+ effects . push ( {
1384+ kind : 'CreateFrom' ,
1385+ from : value . object ,
1386+ into : lvalue ,
1387+ } ) ;
1388+ }
13711389 break ;
13721390 }
13731391 case 'PropertyStore' :
@@ -1378,8 +1396,11 @@ function computeSignatureForInstruction(
13781396 from : value . value ,
13791397 into : value . object ,
13801398 } ) ;
1381- // OK: lvalues are assigned to
1382- effects . push ( { kind : 'Assign' , from : value . value , into : lvalue } ) ;
1399+ effects . push ( {
1400+ kind : 'Create' ,
1401+ into : lvalue ,
1402+ value : ValueKind . Primitive ,
1403+ } ) ;
13831404 break ;
13841405 }
13851406 case 'ObjectMethod' :
@@ -2207,7 +2228,23 @@ export type AliasedPlace = {place: Place; kind: 'alias' | 'capture'};
22072228
22082229export type AliasingEffect =
22092230 /**
2210- * Marks the given value, its aliases, and indirect captures, as frozen.
2231+ * Marks the given value and its direct aliases as frozen.
2232+ *
2233+ * Captured values are *not* considered frozen, because we cannot be sure that a previously
2234+ * captured value will still be captured at the point of the freeze.
2235+ *
2236+ * For example:
2237+ * const x = {};
2238+ * const y = [x];
2239+ * y.pop(); // y dosn't contain x anymore!
2240+ * freeze(y);
2241+ * mutate(x); // safe to mutate!
2242+ *
2243+ * The exception to this is FunctionExpressions - since it is impossible to change which
2244+ * value a function closes over[1] we can transitively freeze functions and their captures.
2245+ *
2246+ * [1] Except for `let` values that are reassigned and closed over by a function, but we
2247+ * handle this explicitly with StoreContext/LoadContext.
22112248 */
22122249 | { kind : 'Freeze' ; value : Place ; reason : ValueReason }
22132250 /**
@@ -2305,6 +2342,67 @@ export type AliasingEffect =
23052342 error : CompilerErrorDetailOptions ;
23062343 } ;
23072344
2345+ function hashEffect ( effect : AliasingEffect ) : string {
2346+ switch ( effect . kind ) {
2347+ case 'Apply' : {
2348+ return [
2349+ effect . kind ,
2350+ effect . receiver . identifier . id ,
2351+ effect . function . identifier . id ,
2352+ effect . mutatesFunction ,
2353+ effect . args
2354+ . map ( a => {
2355+ if ( a . kind === 'Hole' ) {
2356+ return '' ;
2357+ } else if ( a . kind === 'Identifier' ) {
2358+ return a . identifier . id ;
2359+ } else {
2360+ return `...${ a . place . identifier . id } ` ;
2361+ }
2362+ } )
2363+ . join ( ',' ) ,
2364+ effect . into . identifier . id ,
2365+ ] . join ( ':' ) ;
2366+ }
2367+ case 'CreateFrom' :
2368+ case 'ImmutableCapture' :
2369+ case 'Assign' :
2370+ case 'Alias' :
2371+ case 'Capture' : {
2372+ return [
2373+ effect . kind ,
2374+ effect . from . identifier . id ,
2375+ effect . into . identifier . id ,
2376+ ] . join ( ':' ) ;
2377+ }
2378+ case 'Create' : {
2379+ return [ effect . kind , effect . into . identifier . id ] . join ( ':' ) ;
2380+ }
2381+ case 'Freeze' : {
2382+ return [ effect . kind , effect . value . identifier . id , effect . reason ] . join ( ':' ) ;
2383+ }
2384+ case 'MutateFrozen' :
2385+ case 'MutateGlobal' : {
2386+ return [ effect . kind , effect . place . identifier . id ] . join ( ':' ) ;
2387+ }
2388+ case 'Mutate' :
2389+ case 'MutateConditionally' :
2390+ case 'MutateTransitive' :
2391+ case 'MutateTransitiveConditionally' : {
2392+ return [ effect . kind , effect . value . identifier . id ] . join ( ':' ) ;
2393+ }
2394+ case 'CreateFunction' : {
2395+ return [
2396+ effect . kind ,
2397+ effect . into . identifier . id ,
2398+ // return places are a unique way to identify functions themselves
2399+ effect . function . loweredFunc . func . returns . identifier . id ,
2400+ effect . captures . map ( p => p . identifier . id ) . join ( ',' ) ,
2401+ ] . join ( ':' ) ;
2402+ }
2403+ }
2404+ }
2405+
23082406export type AliasingSignatureEffect = AliasingEffect ;
23092407
23102408export type AliasingSignature = {
0 commit comments