Removes temporalAliasArgs for an existing approach using the preludeGenerator (#2199)

Summary:
Release notes: none

As pointed out by Herman in https://github.com/facebook/prepack/pull/2193#discussion_r199628160. We don't need `temporalAliasArgs`, so this PR removes it from the codebase and uses the existing way via the preludeGenerator.

This also adds a helper function to make it easier to relate derived abstract values to their temporal args. Furthermore, `derivedIds` now stores the `TemporalBuildNodeEntryArgs` rather than `Array<Value>`, as the follow up PRs for doing the React related logic need to access more than just the array of args, it also needs access to `isPure`, `skipInvariant` etc so it can properly clone derived abstract values.
Closes https://github.com/facebook/prepack/pull/2199

Differential Revision: D8724017

Pulled By: trueadm

fbshipit-source-id: 3ad72d3b230f1d2dc7f81c2a8d07dd33d0c7aa5c
This commit is contained in:
Dominic Gannaway 2018-07-03 08:01:08 -07:00 committed by Facebook Github Bot
parent f12e0369f0
commit 8e37b36191
9 changed files with 32 additions and 42 deletions

View File

@ -522,8 +522,10 @@ export default function(realm: Realm): ObjectValue {
// Enable cloning via JSON.parse(JSON.stringify(...)).
let gen = realm.preludeGenerator;
invariant(gen); // text is abstract, so we are doing abstract interpretation
let args = gen.derivedIds.get(text.intrinsicName);
invariant(args && args[0] instanceof Value); // since text.kind === "JSON.stringify(...)"
let temporalBuildNodeEntryArgs = gen.derivedIds.get(text.intrinsicName);
invariant(temporalBuildNodeEntryArgs !== undefined);
let args = temporalBuildNodeEntryArgs.args;
invariant(args[0] instanceof Value); // since text.kind === "JSON.stringify(...)"
let inputClone = args[0]; // A temporal copy of the object that was the argument to stringify
// Clone it so that every call to parse produces a different instance from stringify's clone
let parseResult; // A clone of inputClone, because every call to parse produces a new object

View File

@ -295,10 +295,6 @@ export default function(realm: Realm): NativeFunctionValue {
temporalTo.values = new ValuesDomain(to);
}
to.temporalAlias = temporalTo;
// Store the args for the temporal so we can easily clone
// and reconstruct the temporal at another point, rather than
// mutate the existing temporal
realm.temporalAliasArgs.set(temporalTo, temporalArgs);
}
return to;
});

View File

@ -127,10 +127,6 @@ function createBabelHelpers(realm: Realm, global: ObjectValue | AbstractObjectVa
let template = createObjectWithoutProperties(obj, keys);
value.values = new ValuesDomain(template);
}
// Store the args for the temporal so we can easily clone
// and reconstruct the temporal at another point, rather than
// mutate the existing temporal
realm.temporalAliasArgs.set(value, temporalArgs);
// as we are returning an abstract object, we mark it as simple
value.makeSimple();
return value;

View File

@ -206,10 +206,6 @@ function createPropsObject(
temporalTo.values = new ValuesDomain(props);
}
props.temporalAlias = temporalTo;
// Store the args for the temporal so we can easily clone
// and reconstruct the temporal at another point, rather than
// mutate the existing temporal
realm.temporalAliasArgs.set(temporalTo, temporalArgs);
}
}
} else {

View File

@ -948,8 +948,9 @@ function applyClonedTemporalAlias(realm: Realm, props: ObjectValue, clonedProps:
// be a better option.
invariant(false, "TODO applyClonedTemporalAlias conditional");
}
let temporalArgs = realm.temporalAliasArgs.get(temporalAlias);
invariant(temporalArgs !== undefined);
let temporalBuildNodeEntryArgs = realm.getTemporalBuildNodeEntryArgsFromDerivedValue(temporalAlias);
invariant(temporalBuildNodeEntryArgs !== undefined);
let temporalArgs = temporalBuildNodeEntryArgs.args;
// replace the original props with the cloned one
let newTemporalArgs = temporalArgs.map(arg => (arg === props ? clonedProps : arg));
@ -966,10 +967,6 @@ function applyClonedTemporalAlias(realm: Realm, props: ObjectValue, clonedProps:
invariant(clonedProps instanceof ObjectValue);
temporalTo.values = new ValuesDomain(clonedProps);
clonedProps.temporalAlias = temporalTo;
// Store the args for the temporal so we can easily clone
// and reconstruct the temporal at another point, rather than
// mutate the existing temporal
realm.temporalAliasArgs.set(temporalTo, newTemporalArgs);
}
export function cloneProps(realm: Realm, props: ObjectValue, newChildren?: Value): ObjectValue {
@ -1079,10 +1076,6 @@ export function applyObjectAssignConfigsForReactElement(realm: Realm, to: Object
invariant(temporalTo instanceof AbstractObjectValue);
temporalTo.values = new ValuesDomain(to);
to.temporalAlias = temporalTo;
// Store the args for the temporal so we can easily clone
// and reconstruct the temporal at another point, rather than
// mutate the existing temporal
realm.temporalAliasArgs.set(temporalTo, temporalArgs);
return;
} else {
throw error;

View File

@ -63,7 +63,7 @@ import {
import type { Compatibility, RealmOptions, ReactOutputTypes, InvariantModeTypes } from "./options.js";
import invariant from "./invariant.js";
import seedrandom from "seedrandom";
import { Generator, PreludeGenerator } from "./utils/generator.js";
import { Generator, PreludeGenerator, type TemporalBuildNodeEntryArgs } from "./utils/generator.js";
import { emptyExpression, voidExpression } from "./utils/babelhelpers.js";
import { Environment, Functions, Join, Properties, To, Widen, Path } from "./singletons.js";
import type { ReactSymbolTypes } from "./react/utils.js";
@ -246,7 +246,6 @@ export class Realm {
this.evaluators = (Object.create(null): any);
this.partialEvaluators = (Object.create(null): any);
this.$GlobalEnv = ((undefined: any): LexicalEnvironment);
this.temporalAliasArgs = new WeakMap();
this.instantRender = {
enabled: opts.instantRender || false,
@ -339,12 +338,6 @@ export class Realm {
$GlobalEnv: LexicalEnvironment;
intrinsics: Intrinsics;
// temporalAliasArgs is used to map a temporal abstract object value
// to its respective temporal args used to originally create the temporal.
// This is used to "clone" immutable objects where they have a dependency
// on a temporal alias (for example, Object.assign) when used with snapshotting
temporalAliasArgs: WeakMap<AbstractObjectValue | ObjectValue, Array<Value>>;
instantRender: {
enabled: boolean,
};
@ -1745,4 +1738,13 @@ export class Realm {
isNameStringUnique(nameString: string): boolean {
return !this._abstractValuesDefined.has(nameString);
}
getTemporalBuildNodeEntryArgsFromDerivedValue(value: Value): void | TemporalBuildNodeEntryArgs {
let name = value.intrinsicName;
invariant(name);
let preludeGenerator = this.preludeGenerator;
invariant(preludeGenerator !== undefined);
let temporalBuildNodeEntryArgs = preludeGenerator.derivedIds.get(name);
return temporalBuildNodeEntryArgs;
}
}

View File

@ -22,7 +22,7 @@ import {
} from "../values/index.js";
import type { BabelNodeStatement } from "babel-types";
import type { SerializedBody } from "./types.js";
import { Generator } from "../utils/generator.js";
import { Generator, type TemporalBuildNodeEntryArgs } from "../utils/generator.js";
import invariant from "../invariant.js";
import { BodyReference } from "./types.js";
import { ResidualFunctions } from "./ResidualFunctions.js";
@ -68,7 +68,7 @@ export class Emitter {
residualFunctions: ResidualFunctions,
referencedDeclaredValues: Map<Value, void | FunctionValue>,
conditionalFeasibility: Map<AbstractValue, { t: boolean, f: boolean }>,
derivedIds: Map<string, Array<Value>>
derivedIds: Map<string, TemporalBuildNodeEntryArgs>
) {
this._mainBody = { type: "MainGenerator", parentBody: undefined, entries: [], done: false };
this._waitingForValues = new Map();

View File

@ -115,7 +115,7 @@ export class GeneratorEntry {
}
}
type TemporalBuildNodeEntryArgs = {
export type TemporalBuildNodeEntryArgs = {
declared?: AbstractValue | ConcreteValue,
args: Array<Value>,
// If we're just trying to add roots for the serializer to notice, we don't need a buildNode.
@ -926,13 +926,12 @@ export class Generator {
): ConcreteValue {
invariant(buildNode_ instanceof Function || args.length === 0);
let id = t.identifier(this.preludeGenerator.nameGenerator.generate("derived"));
this.preludeGenerator.derivedIds.set(id.name, args);
let value = buildValue(id.name);
if (value instanceof ObjectValue) {
value.intrinsicNameGenerated = true;
value._isScopedTemplate = true; // because this object doesn't exist ahead of time, and the visitor would otherwise declare it in the common scope
}
this._addEntry({
this._addDerivedEntry(id.name, {
isPure: optionalArgs ? optionalArgs.isPure : undefined,
declared: value,
args,
@ -964,7 +963,6 @@ export class Generator {
): AbstractValue {
invariant(buildNode_ instanceof Function || args.length === 0);
let id = t.identifier(this.preludeGenerator.nameGenerator.generate("derived"));
this.preludeGenerator.derivedIds.set(id.name, args);
let options = {};
if (optionalArgs && optionalArgs.kind) options.kind = optionalArgs.kind;
let Constructor = Value.isTypeCompatibleWith(types.getType(), ObjectValue) ? AbstractObjectValue : AbstractValue;
@ -977,7 +975,7 @@ export class Generator {
id,
options
);
this._addEntry({
this._addDerivedEntry(id.name, {
isPure: optionalArgs ? optionalArgs.isPure : undefined,
declared: res,
args,
@ -1072,10 +1070,15 @@ export class Generator {
// PITFALL Warning: adding a new kind of TemporalBuildNodeEntry that is not the result of a join or composition
// will break this purgeEntriesWithGeneratorDepencies.
_addEntry(entry: TemporalBuildNodeEntryArgs) {
_addEntry(entry: TemporalBuildNodeEntryArgs): void {
this._entries.push(new TemporalBuildNodeEntry(entry));
}
_addDerivedEntry(id: string, entry: TemporalBuildNodeEntryArgs): void {
this._addEntry(entry);
this.preludeGenerator.derivedIds.set(id, entry);
}
appendGenerator(other: Generator, leadingComment: string): void {
invariant(other !== this);
invariant(other.realm === this.realm);
@ -1182,7 +1185,7 @@ export class PreludeGenerator {
}
prelude: Array<BabelNodeStatement>;
derivedIds: Map<string, Array<Value>>;
derivedIds: Map<string, TemporalBuildNodeEntryArgs>;
memoizedRefs: Map<string, BabelNodeIdentifier>;
nameGenerator: NameGenerator;
usesThis: boolean;

View File

@ -146,7 +146,9 @@ export default class AbstractValue extends Value {
function add_intrinsic(name: string) {
if (name.startsWith("_$")) {
if (gen === undefined) return;
add_args(gen.derivedIds.get(name));
let temporalBuildNodeEntryArgs = gen.derivedIds.get(name);
invariant(temporalBuildNodeEntryArgs !== undefined);
add_args(temporalBuildNodeEntryArgs.args);
} else if (names.indexOf(name) < 0) {
names.push(name);
}