-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Eval a fast property memoizer to microoptimize property access for ca…
…ched views This implements a better performing getter function for readonly instances. Before this, we used the same definition of the getter function for all views, which ended up megamorphic, because it accessed a very wide variety of properties for every instance! Instead, this evals a monomorphic getter for each one. I also changed the object that stores the memos to have a fixed shape from birth by evaling it out as well. I also changed us to use one object to store all the memoized values, instead of two. We were previously using two in order to implement memoization of undefined and null correctly, but with the new strategy to initialize an object with slots for every memo from the start, we can populate it with a `$notYetMemoized` symbol that indicates if we have memoized or not.
- Loading branch information
Showing
4 changed files
with
85 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import type { PropertyMetadata, ViewMetadata } from "./class-model"; | ||
import { getPropertyDescriptor } from "./class-model"; | ||
import { RegistrationError } from "./errors"; | ||
import { $memos, $notYetMemoized, $readOnly } from "./symbols"; | ||
|
||
/** Assemble a function for getting the value of a readonly instance very quickly with static dispatch to properties */ | ||
|
||
export class FastGetBuilder { | ||
memoizableProperties: string[]; | ||
|
||
constructor( | ||
metadatas: PropertyMetadata[], | ||
readonly klass: { new (...args: any[]): any }, | ||
) { | ||
this.memoizableProperties = metadatas | ||
.filter((metadata): metadata is ViewMetadata => { | ||
if (metadata.type !== "view") return false; | ||
const property = metadata.property; | ||
const descriptor = getPropertyDescriptor(klass.prototype, property); | ||
if (!descriptor) { | ||
throw new RegistrationError(`Property ${property} not found on ${klass} prototype, can't register view for class model`); | ||
} | ||
return descriptor.get !== undefined; | ||
}) | ||
.map((metadata) => metadata.property); | ||
} | ||
|
||
constructorStatements() { | ||
return ` | ||
this[$memos] = {${this.memoizableProperties.map((property) => `${property}: $notYetMemoized`).join(",")}}; | ||
`; | ||
} | ||
|
||
buildGetter(property: string, descriptor: PropertyDescriptor) { | ||
const builder = eval(` | ||
( | ||
function build({ $readOnly, $memos, $notYetMemoized, getValue }) { | ||
return function get${property}(model, imports) { | ||
if (!this[$readOnly]) return getValue.call(this); | ||
let value = this[$memos].${property}; | ||
if (value != $notYetMemoized) { | ||
return value; | ||
} | ||
value = getValue.call(this); | ||
this[$memos].${property} = value; | ||
return value; | ||
} | ||
} | ||
) | ||
//# sourceURL=mqt-eval/dynamic/${this.klass.name}-${property}-get.js | ||
`); | ||
|
||
return builder({ $readOnly, $memos, $notYetMemoized, getValue: descriptor.get }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters