From b3bcd7310263121732fd052ae8f247f90d7bd406 Mon Sep 17 00:00:00 2001 From: Nikolai Tillmann Date: Fri, 31 Aug 2018 02:25:10 -0700 Subject: [PATCH] Add invariant that an object with modified properties must be valid. (#2278) Summary: Release notes: None The uncovered bug is tracked in #2279. Pull Request resolved: https://github.com/facebook/prepack/pull/2278 Differential Revision: D9472482 Pulled By: NTillmann fbshipit-source-id: 5d6e24abd76fd83e9078c3908fa0be0e7f0b2c51 --- src/serializer/ResidualHeapVisitor.js | 24 ++++++++++++++---------- src/utils/generator.js | 1 + src/values/ObjectValue.js | 5 +++++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/serializer/ResidualHeapVisitor.js b/src/serializer/ResidualHeapVisitor.js index 3eaddbeb8e..365780d005 100644 --- a/src/serializer/ResidualHeapVisitor.js +++ b/src/serializer/ResidualHeapVisitor.js @@ -847,6 +847,7 @@ export class ResidualHeapVisitor { } visitValueObject(val: ObjectValue): void { + invariant(val.isValid()); this._registerAdditionalRoot(val); if (isReactElement(val)) { this.residualReactElementVisitor.visitReactElement(val); @@ -1038,17 +1039,20 @@ export class ResidualHeapVisitor { this.postProcessValue(equivalentValue); return (equivalentValue: any); } - if (val instanceof ObjectValue && isReactElement(val)) { - if (val.temporalAlias !== undefined) { - return this.visitEquivalentValue(val.temporalAlias); + if (val instanceof ObjectValue) { + invariant(val.isValid()); + if (isReactElement(val)) { + if (val.temporalAlias !== undefined) { + return this.visitEquivalentValue(val.temporalAlias); + } + let equivalentReactElementValue = this.residualReactElementVisitor.reactElementEquivalenceSet.add(val); + if (this._mark(equivalentReactElementValue)) this.visitValueObject(equivalentReactElementValue); + return (equivalentReactElementValue: any); + } else if (isReactPropsObject(val)) { + let equivalentReactPropsValue = this.residualReactElementVisitor.reactPropsEquivalenceSet.add(val); + if (this._mark(equivalentReactPropsValue)) this.visitValueObject(equivalentReactPropsValue); + return (equivalentReactPropsValue: any); } - let equivalentReactElementValue = this.residualReactElementVisitor.reactElementEquivalenceSet.add(val); - if (this._mark(equivalentReactElementValue)) this.visitValueObject(equivalentReactElementValue); - return (equivalentReactElementValue: any); - } else if (val instanceof ObjectValue && isReactPropsObject(val)) { - let equivalentReactPropsValue = this.residualReactElementVisitor.reactPropsEquivalenceSet.add(val); - if (this._mark(equivalentReactPropsValue)) this.visitValueObject(equivalentReactPropsValue); - return (equivalentReactPropsValue: any); } this.visitValue(val); return val; diff --git a/src/utils/generator.js b/src/utils/generator.js index 371513ee32..71eba29a89 100644 --- a/src/utils/generator.js +++ b/src/utils/generator.js @@ -614,6 +614,7 @@ export class Generator { for (let propertyBinding of modifiedProperties.keys()) { let object = propertyBinding.object; + invariant(object.isValid()); if (createdObjects.has(object)) continue; // Created Object's binding if (ObjectValue.refuseSerializationOnPropertyBinding(propertyBinding)) continue; // modification to internal state // modifications to intrinsic objects are tracked in the generator diff --git a/src/values/ObjectValue.js b/src/values/ObjectValue.js index e912926898..e97845b676 100644 --- a/src/values/ObjectValue.js +++ b/src/values/ObjectValue.js @@ -308,6 +308,11 @@ export default class ObjectValue extends ConcreteValue { // never be serialized. refuseSerialization: boolean; + // Checks whether effects are properly applied. + isValid(): boolean { + return this._isPartial !== undefined; + } + equals(x: Value): boolean { return this === x; }