@@ -63,6 +63,7 @@ import {FunctionSignature} from '../HIR/ObjectShape';
6363import { getWriteErrorReason } from './InferFunctionEffects' ;
6464import prettyFormat from 'pretty-format' ;
6565import { createTemporaryPlace } from '../HIR/HIRBuilder' ;
66+ import { pretty } from './InferMutationAliasingRanges' ;
6667
6768export function inferMutationAliasingEffects (
6869 fn : HIRFunction ,
@@ -189,6 +190,7 @@ export function inferMutationAliasingEffects(
189190}
190191
191192class Context {
193+ internedEffects : Map < string , AliasingEffect > = new Map ( ) ;
192194 instructionSignatureCache : Map < Instruction , InstructionSignature > = new Map ( ) ;
193195 effectInstructionValueCache : Map < AliasingEffect , InstructionValue > =
194196 new Map ( ) ;
@@ -200,6 +202,17 @@ class Context {
200202 this . isFuctionExpression = isFunctionExpression ;
201203 this . fn = fn ;
202204 }
205+
206+ internEffect ( effect : AliasingEffect ) : AliasingEffect {
207+ const hash = hashEffect ( effect ) ;
208+ let interned = this . internedEffects . get ( hash ) ;
209+ if ( interned == null ) {
210+ console . log ( `intern: ${ hash } ` ) ;
211+ this . internedEffects . set ( hash , effect ) ;
212+ interned = effect ;
213+ }
214+ return interned ;
215+ }
203216}
204217
205218function inferParam (
@@ -388,10 +401,11 @@ function applySignature(
388401function applyEffect (
389402 context : Context ,
390403 state : InferenceState ,
391- effect : AliasingEffect ,
404+ _effect : AliasingEffect ,
392405 aliased : Set < IdentifierId > ,
393406 effects : Array < AliasingEffect > ,
394407) : void {
408+ const effect = context . internEffect ( _effect ) ;
395409 if ( DEBUG ) {
396410 console . log ( printAliasingEffect ( effect ) ) ;
397411 }
@@ -465,15 +479,12 @@ function applyEffect(
465479 break ;
466480 }
467481 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- }
482+ effects . push ( {
483+ // OK: recording information flow
484+ kind : 'CreateFrom' , // prev Alias
485+ from : effect . from ,
486+ into : effect . into ,
487+ } ) ;
477488 }
478489 }
479490 break ;
@@ -1363,11 +1374,19 @@ function computeSignatureForInstruction(
13631374 }
13641375 case 'PropertyLoad' :
13651376 case 'ComputedLoad' : {
1366- effects . push ( {
1367- kind : 'CreateFrom' ,
1368- from : value . object ,
1369- into : lvalue ,
1370- } ) ;
1377+ if ( isPrimitiveType ( lvalue . identifier ) ) {
1378+ effects . push ( {
1379+ kind : 'Create' ,
1380+ into : lvalue ,
1381+ value : ValueKind . Primitive ,
1382+ } ) ;
1383+ } else {
1384+ effects . push ( {
1385+ kind : 'CreateFrom' ,
1386+ from : value . object ,
1387+ into : lvalue ,
1388+ } ) ;
1389+ }
13711390 break ;
13721391 }
13731392 case 'PropertyStore' :
@@ -1378,8 +1397,11 @@ function computeSignatureForInstruction(
13781397 from : value . value ,
13791398 into : value . object ,
13801399 } ) ;
1381- // OK: lvalues are assigned to
1382- effects . push ( { kind : 'Assign' , from : value . value , into : lvalue } ) ;
1400+ effects . push ( {
1401+ kind : 'Create' ,
1402+ into : lvalue ,
1403+ value : ValueKind . Primitive ,
1404+ } ) ;
13831405 break ;
13841406 }
13851407 case 'ObjectMethod' :
@@ -2207,7 +2229,23 @@ export type AliasedPlace = {place: Place; kind: 'alias' | 'capture'};
22072229
22082230export type AliasingEffect =
22092231 /**
2210- * Marks the given value, its aliases, and indirect captures, as frozen.
2232+ * Marks the given value and its direct aliases as frozen.
2233+ *
2234+ * Captured values are *not* considered frozen, because we cannot be sure that a previously
2235+ * captured value will still be captured at the point of the freeze.
2236+ *
2237+ * For example:
2238+ * const x = {};
2239+ * const y = [x];
2240+ * y.pop(); // y dosn't contain x anymore!
2241+ * freeze(y);
2242+ * mutate(x); // safe to mutate!
2243+ *
2244+ * The exception to this is FunctionExpressions - since it is impossible to change which
2245+ * value a function closes over[1] we can transitively freeze functions and their captures.
2246+ *
2247+ * [1] Except for `let` values that are reassigned and closed over by a function, but we
2248+ * handle this explicitly with StoreContext/LoadContext.
22112249 */
22122250 | { kind : 'Freeze' ; value : Place ; reason : ValueReason }
22132251 /**
@@ -2305,6 +2343,67 @@ export type AliasingEffect =
23052343 error : CompilerErrorDetailOptions ;
23062344 } ;
23072345
2346+ function hashEffect ( effect : AliasingEffect ) : string {
2347+ switch ( effect . kind ) {
2348+ case 'Apply' : {
2349+ return [
2350+ effect . kind ,
2351+ effect . receiver . identifier . id ,
2352+ effect . function . identifier . id ,
2353+ effect . mutatesFunction ,
2354+ effect . args
2355+ . map ( a => {
2356+ if ( a . kind === 'Hole' ) {
2357+ return '' ;
2358+ } else if ( a . kind === 'Identifier' ) {
2359+ return a . identifier . id ;
2360+ } else {
2361+ return `...${ a . place . identifier . id } ` ;
2362+ }
2363+ } )
2364+ . join ( ',' ) ,
2365+ effect . into . identifier . id ,
2366+ ] . join ( ':' ) ;
2367+ }
2368+ case 'CreateFrom' :
2369+ case 'ImmutableCapture' :
2370+ case 'Assign' :
2371+ case 'Alias' :
2372+ case 'Capture' : {
2373+ return [
2374+ effect . kind ,
2375+ effect . from . identifier . id ,
2376+ effect . into . identifier . id ,
2377+ ] . join ( ':' ) ;
2378+ }
2379+ case 'Create' : {
2380+ return [ effect . kind , effect . into . identifier . id ] . join ( ':' ) ;
2381+ }
2382+ case 'Freeze' : {
2383+ return [ effect . kind , effect . value . identifier . id , effect . reason ] . join ( ':' ) ;
2384+ }
2385+ case 'MutateFrozen' :
2386+ case 'MutateGlobal' : {
2387+ return [ effect . kind , effect . place . identifier . id ] . join ( ':' ) ;
2388+ }
2389+ case 'Mutate' :
2390+ case 'MutateConditionally' :
2391+ case 'MutateTransitive' :
2392+ case 'MutateTransitiveConditionally' : {
2393+ return [ effect . kind , effect . value . identifier . id ] . join ( ':' ) ;
2394+ }
2395+ case 'CreateFunction' : {
2396+ return [
2397+ effect . kind ,
2398+ effect . into . identifier . id ,
2399+ // return places are a unique way to identify functions themselves
2400+ effect . function . loweredFunc . func . returns . identifier . id ,
2401+ effect . captures . map ( p => p . identifier . id ) . join ( ',' ) ,
2402+ ] . join ( ':' ) ;
2403+ }
2404+ }
2405+ }
2406+
23082407export type AliasingSignatureEffect = AliasingEffect ;
23092408
23102409export type AliasingSignature = {
0 commit comments