Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions src/system/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,37 @@ export default class Hash {
this._next = next;
}
chainGet(key: string): Expr | undefined {
if (this._store.hasOwnProperty(key)) {
return this._store[key];
} else if (this._next !== undefined) {
return this._next.chainGet(key);
// We switched from a recursive implementation to an iterative one.
// Recursion created extra call frames on deeply nested environments,
// hurting performance on benchmarks. Iteration avoids that overhead.
let env: Hash | undefined = this;
while (env !== undefined) {
if (Object.prototype.hasOwnProperty.call(env._store, key)) {
return env._store[key];
}
env = env._next;
}
return undefined;
}
get(key: string) {
if (this._store.hasOwnProperty(key)) {
return this._store[key];
}
}
chainSet(key: string, value: Expr): void {
if(this.get(key) !== undefined) {
this.set(key, value);
}
else {
if(this._next !== undefined) {
this._next.chainSet(key, value);
} else {
this._store[key] = value;
// Like chainGet, this function is now iterative to prevent deep
// recursion when walking parent environments.
let env: Hash | undefined = this;
let last: Hash = this;
while (env !== undefined) {
if (Object.prototype.hasOwnProperty.call(env._store, key)) {
env._store[key] = value;
return;
}
last = env;
env = env._next;
}
last._store[key] = value;
}
set(key: string, value: Expr): void {
this._store[key] = value;
Expand Down