Skip to content

Commit

Permalink
Enable custom call-effect detection per global
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed May 10, 2022
1 parent 47a4de2 commit 4bba49d
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 16 deletions.
31 changes: 23 additions & 8 deletions src/ast/nodes/shared/knownGlobals.ts
@@ -1,15 +1,14 @@
/* eslint sort-keys: "off" */

import { CallOptions } from '../../CallOptions';
import { HasEffectsContext } from '../../ExecutionContext';
import { UNKNOWN_NON_ACCESSOR_PATH } from '../../utils/PathTracker';
import type { ObjectPath } from '../../utils/PathTracker';

const ValueProperties = Symbol('Value Properties');

interface ValueDescription {
// Denotes a proper function except for the side effects listed explicitly
function: boolean;
// This assumes that mutation itself cannot have side effects and that this
// does not trigger setters or getters
mutatesArg1: boolean;
hasEffectsWhenCalled(callOptions: CallOptions, context: HasEffectsContext): boolean;
}

interface GlobalDescription {
Expand All @@ -18,8 +17,17 @@ interface GlobalDescription {
__proto__: null;
}

const PURE: ValueDescription = { function: true, mutatesArg1: false };
const IMPURE: ValueDescription = { function: false, mutatesArg1: false };
const PURE: ValueDescription = {
hasEffectsWhenCalled() {
return false;
}
};

const IMPURE: ValueDescription = {
hasEffectsWhenCalled() {
return true;
}
};

// We use shortened variables to reduce file size here
/* OBJECT */
Expand All @@ -37,7 +45,14 @@ const PF: GlobalDescription = {
/* FUNCTION THAT MUTATES FIRST ARG WITHOUT TRIGGERING ACCESSORS */
const MUTATES_ARG_WITHOUT_ACCESSOR: GlobalDescription = {
__proto__: null,
[ValueProperties]: { function: true, mutatesArg1: true }
[ValueProperties]: {
hasEffectsWhenCalled(callOptions, context) {
return (
!callOptions.args.length ||
callOptions.args[0].hasEffectsWhenAssignedAtPath(UNKNOWN_NON_ACCESSOR_PATH, context)
);
}
}
};

/* CONSTRUCTOR */
Expand Down
12 changes: 4 additions & 8 deletions src/ast/variables/GlobalVariable.ts
Expand Up @@ -2,14 +2,16 @@ import { CallOptions } from '../CallOptions';
import { HasEffectsContext } from '../ExecutionContext';
import { getGlobalAtPath } from '../nodes/shared/knownGlobals';
import type { ObjectPath } from '../utils/PathTracker';
import { UNKNOWN_NON_ACCESSOR_PATH } from '../utils/PathTracker';
import Variable from './Variable';

export default class GlobalVariable extends Variable {
// Ensure we use live-bindings for globals as we do not know if they have
// been reassigned
isReassigned = true;

hasEffectsWhenAccessedAtPath(path: ObjectPath): boolean {
if (path.length === 0) {
// Technically, "undefined" is a global variable of sorts
return this.name !== 'undefined' && getGlobalAtPath([this.name]) === null;
}
return getGlobalAtPath([this.name, ...path].slice(0, -1)) === null;
Expand All @@ -21,12 +23,6 @@ export default class GlobalVariable extends Variable {
context: HasEffectsContext
): boolean {
const globalAtPath = getGlobalAtPath([this.name, ...path]);
return (
globalAtPath === null ||
!globalAtPath.function ||
(globalAtPath.mutatesArg1 &&
(!callOptions.args.length ||
callOptions.args[0].hasEffectsWhenAssignedAtPath(UNKNOWN_NON_ACCESSOR_PATH, context)))
);
return globalAtPath === null || globalAtPath.hasEffectsWhenCalled(callOptions, context);
}
}

0 comments on commit 4bba49d

Please sign in to comment.