Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,43 @@ type ValidationContext = {
class DerivationCache {
hasChanges: boolean = false;
cache: Map<IdentifierId, DerivationMetadata> = new Map();
private previousCache: Map<IdentifierId, DerivationMetadata> | null = null;

takeSnapshot(): void {
this.previousCache = new Map();
for (const [key, value] of this.cache.entries()) {
this.previousCache.set(key, {
place: value.place,
sourcesIds: new Set(value.sourcesIds),
typeOfValue: value.typeOfValue,
});
}
}

checkForChanges(): void {
if (this.previousCache === null) {
this.hasChanges = true;
return;
}

for (const [key, value] of this.cache.entries()) {
const previousValue = this.previousCache.get(key);
if (
previousValue === undefined ||
!this.isDerivationEqual(previousValue, value)
) {
this.hasChanges = true;
return;
}
}

if (this.cache.size !== this.previousCache.size) {
this.hasChanges = true;
return;
}

this.hasChanges = false;
}

snapshot(): boolean {
const hasChanges = this.hasChanges;
Expand Down Expand Up @@ -92,14 +129,7 @@ class DerivationCache {
newValue.sourcesIds.add(derivedVar.identifier.id);
}

const existingValue = this.cache.get(derivedVar.identifier.id);
if (
existingValue === undefined ||
!this.isDerivationEqual(existingValue, newValue)
) {
this.cache.set(derivedVar.identifier.id, newValue);
this.hasChanges = true;
}
this.cache.set(derivedVar.identifier.id, newValue);
}

private isDerivationEqual(
Expand Down Expand Up @@ -175,7 +205,6 @@ export function validateNoDerivedComputationsInEffects_exp(
sourcesIds: new Set([param.identifier.id]),
typeOfValue: 'fromProps',
});
context.derivationCache.hasChanges = true;
}
}
} else if (fn.fnType === 'Component') {
Expand All @@ -186,19 +215,21 @@ export function validateNoDerivedComputationsInEffects_exp(
sourcesIds: new Set([props.identifier.id]),
typeOfValue: 'fromProps',
});
context.derivationCache.hasChanges = true;
}
}

let isFirstPass = true;
do {
context.derivationCache.takeSnapshot();

for (const block of fn.body.blocks.values()) {
recordPhiDerivations(block, context);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm what's the reasoning for moving when we record phis? A block's phis often defines values used by the block so we may find that the derivation cache is missing values when processing instructions with this change.

In the below example, we want to call recordPhiDerivations to insert x@2 into the context. Then, when we walk over the instructions of the fallthrough block (LoadLocal x@2, Call doSomething), we can read the proper typeOfValue from context

let x = thing1; // x@0
if (cond) {
  x = {}; // x@1
}
// x@2 = phi(x@0, x@1)
doSomething(x) // <- references x@2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, my bad, I moved it when debugging the infinite loop. I'll move it back

for (const instr of block.instructions) {
recordInstructionDerivations(instr, context, isFirstPass);
}
}

context.derivationCache.checkForChanges();
isFirstPass = false;
} while (context.derivationCache.snapshot());

Expand Down Expand Up @@ -331,11 +362,24 @@ function recordInstructionDerivations(
case Effect.ConditionallyMutateIterator:
case Effect.Mutate: {
if (isMutable(instr, operand)) {
context.derivationCache.addDerivationEntry(
operand,
sources,
typeOfValue,
);
if (context.derivationCache.cache.has(operand.identifier.id)) {
const operandMetadata = context.derivationCache.cache.get(
operand.identifier.id,
);

if (operandMetadata !== undefined) {
operandMetadata.typeOfValue = joinValue(
typeOfValue,
operandMetadata.typeOfValue,
);
}
} else {
context.derivationCache.addDerivationEntry(
operand,
sources,
typeOfValue,
);
}
}
break;
}
Expand Down
Loading