Unify logic for checking for intrinsic objects that have been derived (#2581)

Summary:
Release notes: none

This PR cleans up some of the `onArrayWithWidenedNumericProperty` logic, making it more generic for cases where we want to use concrete derived object values. Furthermore, it strengthens the validation process by checking for existence of `isScopedTemplate` on the internal object.
Pull Request resolved: https://github.com/facebook/prepack/pull/2581

Differential Revision: D10141954

Pulled By: trueadm

fbshipit-source-id: 8de828080b8a41357830cdbf7e49359512bc7244
This commit is contained in:
Dominic Gannaway 2018-10-02 03:27:13 -07:00 committed by Facebook Github Bot
parent ed784d6899
commit 5fc6feeeb2
7 changed files with 18 additions and 18 deletions

View File

@ -305,7 +305,7 @@ function InternalCloneObject(realm: Realm, val: ObjectValue): ObjectValue {
}
if (val.isPartialObject()) clone.makePartial();
if (val.isSimpleObject()) clone.makeSimple();
clone._isScopedTemplate = true; // because this object doesn't exist ahead of time, and the visitor would otherwise declare it in the common scope
clone.isScopedTemplate = true; // because this object doesn't exist ahead of time, and the visitor would otherwise declare it in the common scope
return clone;
}

View File

@ -11,7 +11,6 @@
import {
AbstractValue,
ArrayValue,
BoundFunctionValue,
FunctionValue,
ObjectValue,
@ -38,9 +37,9 @@ type EmitterDependenciesVisitorCallbacks<T> = {
// Callback invoked whenever a dependency is visited that is an abstract value with an identifier.
// A return value that is not undefined indicates that the visitor should stop, and return the value as the overall result.
onAbstractValueWithIdentifier?: AbstractValue => void | T,
// Callback invoked whenever a dependency is visited that is an array value with a widened numeric property.
// Callback invoked whenever a dependency is visited that is an intrinsic object that was derived
// A return value that is not undefined indicates that the visitor should stop, and return the value as the overall result.
onArrayWithWidenedNumericProperty?: ArrayValue => void | T,
onIntrinsicDerivedObject?: ObjectValue => void | T,
};
// The emitter keeps track of a stack of what's currently being emitted.
@ -78,7 +77,7 @@ export class Emitter {
this._activeValues = new Set();
this._activeGeneratorStack = [this._mainBody];
this._finalized = false;
let mustWaitForValue = (val: AbstractValue | ArrayValue) => {
let mustWaitForValue = (val: AbstractValue | ObjectValue) => {
if (this.cannotDeclare()) return false;
if (this.hasBeenDeclared(val)) return false;
let activeOptimizedFunction = this.getActiveOptimizedFunction();
@ -95,7 +94,7 @@ export class Emitter {
},
onAbstractValueWithIdentifier: val =>
derivedIds.has(val.getIdentifier()) && mustWaitForValue(val) ? val : undefined,
onArrayWithWidenedNumericProperty: val => (mustWaitForValue(val) ? val : undefined),
onIntrinsicDerivedObject: val => (mustWaitForValue(val) ? val : undefined),
};
this._conditionalFeasibility = conditionalFeasibility;
}
@ -351,10 +350,8 @@ export class Emitter {
result = recurse(val.$Description);
if (result !== undefined) return result;
}
} else if (val instanceof ArrayValue && ArrayValue.isIntrinsicAndHasWidenedNumericProperty(val)) {
result = callbacks.onArrayWithWidenedNumericProperty
? callbacks.onArrayWithWidenedNumericProperty(val)
: undefined;
} else if (val instanceof ObjectValue && ObjectValue.isIntrinsicDerivedObject(val)) {
result = callbacks.onIntrinsicDerivedObject ? callbacks.onIntrinsicDerivedObject(val) : undefined;
if (result !== undefined) return result;
} else if (val instanceof ObjectValue) {
let kind = val.getKind();

View File

@ -940,11 +940,9 @@ export class ResidualHeapSerializer {
// which is related to one of the scopes this value is used by.
let notYetDoneBodies = new Set();
this.emitter.dependenciesVisitor(val, {
onArrayWithWidenedNumericProperty: dependency => {
onIntrinsicDerivedObject: dependency => {
if (trace) {
console.log(
` depending on array with widened numeric properties and an identifier ${dependency.intrinsicName || "?"}`
);
console.log(` depending on intrinsic derived object and an identifier ${dependency.intrinsicName || "?"}`);
}
invariant(
optimizedFunctionRoot === undefined || !!this.emitter.getActiveOptimizedFunction(),

View File

@ -1087,7 +1087,7 @@ export class ResidualHeapVisitor {
} else if (val.isIntrinsic()) {
// All intrinsic values exist from the beginning of time...
// ...except for a few that come into existence as templates for abstract objects via executable code.
if (val instanceof ObjectValue && val._isScopedTemplate) {
if (val instanceof ObjectValue && val.isScopedTemplate) {
this.preProcessValue(val);
this.postProcessValue(val);
} else

View File

@ -1067,7 +1067,7 @@ export class Generator {
let id = this.preludeGenerator.nameGenerator.generate("derived");
let value = buildValue(id);
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
value.isScopedTemplate = true; // because this object doesn't exist ahead of time, and the visitor would otherwise declare it in the common scope
invariant(value.intrinsicName === id);
this._addDerivedEntry({
isPure: optionalArgs ? optionalArgs.isPure : undefined,

View File

@ -242,7 +242,8 @@ export default class ArrayValue extends ObjectValue {
}
static isIntrinsicAndHasWidenedNumericProperty(obj: Value): boolean {
if (obj instanceof ArrayValue && obj.intrinsicName !== undefined) {
if (obj instanceof ArrayValue && obj.intrinsicName !== undefined && obj.isScopedTemplate !== undefined) {
invariant(ObjectValue.isIntrinsicDerivedObject(obj));
const prop = obj.unknownProperty;
if (prop !== undefined && prop.descriptor !== undefined) {
const desc = prop.descriptor.throwIfNotConcrete(obj.$Realm);

View File

@ -279,7 +279,7 @@ export default class ObjectValue extends ConcreteValue {
// Specifies whether the object is a template that needs to be created in a scope
// If set, this happened during object initialization and the value is never changed again, so not tracked.
_isScopedTemplate: void | true;
isScopedTemplate: void | true;
// If true, then unknown properties should return transitively simple abstract object values
_simplicityIsTransitive: AbstractValue | BooleanValue;
@ -718,4 +718,8 @@ export default class ObjectValue extends ConcreteValue {
if (pb.internalSlot && typeof pb.key === "string" && pb.key[0] === "_") return true;
return false;
}
static isIntrinsicDerivedObject(obj: Value): boolean {
return obj instanceof ObjectValue && obj.intrinsicName !== undefined && obj.isScopedTemplate !== undefined;
}
}