Skip to content

Commit

Permalink
Merge pull request #1122 from glimmerjs/perf/deduped-index-of-constants
Browse files Browse the repository at this point in the history
[Refactor] Use a map to dedupe constants instead of indexOf
  • Loading branch information
rwjblue authored Jul 30, 2020
2 parents dbc99c4 + 11659c1 commit 3ae94e0
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 123 deletions.
10 changes: 5 additions & 5 deletions packages/@glimmer/bundle-compiler/lib/debug-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { RuntimeConstants } from '@glimmer/interfaces';

export default class DebugConstants extends WriteOnlyConstants implements RuntimeConstants {
getNumber(value: number): number {
return this.numbers[value];
return this.values[value] as number;
}

getString(value: number): string {
return this.strings[value];
return this.values[value] as string;
}

getStringArray(value: number): string[] {
Expand All @@ -24,7 +24,7 @@ export default class DebugConstants extends WriteOnlyConstants implements Runtim
}

getArray(value: number): number[] {
return (this.arrays as number[][])[value];
return this.values[value] as number[];
}

resolveHandle<T>(s: number): T {
Expand All @@ -33,14 +33,14 @@ export default class DebugConstants extends WriteOnlyConstants implements Runtim
}

getSerializable(s: number): unknown {
return JSON.parse(this.strings[s]);
return JSON.parse(this.values[s] as string);
}

getTemplateMeta(m: number): unknown {
return this.getSerializable(m);
}

getOther(s: number): unknown {
return this.others[s];
return this.values[s];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ export class BundleCompilerEmberTests extends EmberishComponentTests {
module: 'ui/components/main',
name: 'default',
});
let { strings } = this.delegate.getConstants();
this.assert.equal(strings.indexOf(ALocator), -1);
this.assert.equal(strings.indexOf(MainLocator), -1);
let values = this.delegate.getConstants();
this.assert.equal(values.indexOf(ALocator), -1);
this.assert.equal(values.indexOf(MainLocator), -1);
this.assertHTML('B 1 B 2 B 3 B 4');
this.assertStableRerender();
}
Expand All @@ -39,9 +39,9 @@ export class BundleCompilerEmberTests extends EmberishComponentTests {
let MainLocator = JSON.stringify({
locator: { module: 'ui/components/main', name: 'default' },
});
let { strings } = this.delegate.constants!.toPool();
this.assert.equal(strings.indexOf(ALocator), -1);
this.assert.equal(strings.indexOf(MainLocator), -1);
let values = this.delegate.constants!.toPool();
this.assert.equal(values.indexOf(ALocator), -1);
this.assert.equal(values.indexOf(MainLocator), -1);
this.assertHTML('B 1 B 1');
this.assertStableRerender();
}
Expand All @@ -56,9 +56,9 @@ export class BundleCompilerEmberTests extends EmberishComponentTests {
module: 'ui/components/main',
name: 'default',
});
let { strings } = this.delegate.constants!.toPool();
this.assert.ok(strings.indexOf(ALocator) > -1, 'Has locator for "A"');
this.assert.equal(strings.indexOf(MainLocator), -1);
let values = this.delegate.constants!.toPool();
this.assert.ok(values.indexOf(ALocator) > -1, 'Has locator for "A"');
this.assert.equal(values.indexOf(MainLocator), -1);
this.assertHTML('B 1');
this.assertStableRerender();
}
Expand Down
7 changes: 1 addition & 6 deletions packages/@glimmer/interfaces/lib/program.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,7 @@ export interface TemplateCompilationContext {

export type EMPTY_ARRAY = Array<ReadonlyArray<never>>;

export interface ConstantPool {
strings: string[];
arrays: number[][] | EMPTY_ARRAY;
handles: number[];
numbers: number[];
}
export type ConstantPool = unknown[];

/**
* Constants are interned values that are referenced as numbers in the program.
Expand Down
147 changes: 51 additions & 96 deletions packages/@glimmer/program/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,32 @@
import {
SymbolTable,
CompileTimeConstants,
EMPTY_ARRAY,
ConstantPool,
RuntimeConstants,
} from '@glimmer/interfaces';

const UNRESOLVED = {};
import { CompileTimeConstants, ConstantPool, RuntimeConstants } from '@glimmer/interfaces';

export const WELL_KNOWN_EMPTY_ARRAY_POSITION = 0;
const WELL_KNOW_EMPTY_ARRAY = Object.freeze([]);

export class WriteOnlyConstants implements CompileTimeConstants {
// `0` means NULL

protected strings: string[] = [];
protected arrays: number[][] | EMPTY_ARRAY = [WELL_KNOW_EMPTY_ARRAY];
protected tables: SymbolTable[] = [];
protected handles: number[] = [];
protected resolved: unknown[] = [];
protected numbers: number[] = [];
protected others: unknown[] = [];
protected values: unknown[] = [WELL_KNOW_EMPTY_ARRAY];
protected indexMap: Map<unknown, number> = new Map();

protected value(value: unknown) {
let indexMap = this.indexMap;
let index = indexMap.get(value);

if (index === undefined) {
index = this.values.push(value) - 1;
indexMap.set(value, index);
}

return index;
}

other(other: unknown): number {
return this.others.push(other) - 1;
return this.value(other);
}

string(value: string): number {
let index = this.strings.indexOf(value);

if (index > -1) {
return index;
}

return this.strings.push(value) - 1;
return this.value(value);
}

stringArray(strings: string[]): number {
Expand All @@ -51,70 +44,41 @@ export class WriteOnlyConstants implements CompileTimeConstants {
return WELL_KNOWN_EMPTY_ARRAY_POSITION;
}

let index = (this.arrays as number[][]).indexOf(values);

if (index > -1) {
return index;
}

return (this.arrays as number[][]).push(values) - 1;
return this.value(values);
}

serializable(value: unknown): number {
let str = JSON.stringify(value);
let index = this.strings.indexOf(str);
if (index > -1) {
return index;
}

return this.strings.push(str) - 1;
return this.value(str);
}

templateMeta(value: unknown): number {
return this.serializable(value);
}

number(number: number): number {
let index = this.numbers.indexOf(number);

if (index > -1) {
return index;
}

return this.numbers.push(number) - 1;
return this.value(number);
}

toPool(): ConstantPool {
return {
strings: this.strings,
arrays: this.arrays,
handles: this.handles,
numbers: this.numbers,
};
return this.values;
}
}

export class RuntimeConstantsImpl implements RuntimeConstants {
protected strings: string[];
protected arrays: number[][] | EMPTY_ARRAY;
protected handles: number[];
protected numbers: number[];
protected others: unknown[];
protected values: unknown[];

constructor(pool: ConstantPool) {
this.strings = pool.strings;
this.arrays = pool.arrays;
this.handles = pool.handles;
this.numbers = pool.numbers;
this.others = [];
this.values = pool;
}

getString(value: number): string {
return this.strings[value];
return this.values[value] as string;
}

getNumber(value: number): number {
return this.numbers[value];
return this.values[value] as number;
}

getStringArray(value: number): string[] {
Expand All @@ -130,81 +94,72 @@ export class RuntimeConstantsImpl implements RuntimeConstants {
}

getArray(value: number): number[] {
return (this.arrays as number[][])[value];
return this.values[value] as number[];
}

getSerializable<T>(s: number): T {
return JSON.parse(this.strings[s]) as T;
return JSON.parse(this.values[s] as string) as T;
}

getTemplateMeta<T>(m: number): T {
return this.getSerializable(m);
}

getOther<T>(value: number): T {
return this.others[value] as T;
return this.values[value] as T;
}
}

export class JitConstants extends WriteOnlyConstants implements RuntimeConstants {
protected metas: unknown[] = [];

constructor(pool?: ConstantPool) {
super();

if (pool) {
this.strings = pool.strings;
this.arrays = pool.arrays;
this.handles = pool.handles;
this.resolved = this.handles.map(() => UNRESOLVED);
this.numbers = pool.numbers;
}

this.others = [];
}
protected reifiedStringArrs: string[][] = [WELL_KNOW_EMPTY_ARRAY as any];

templateMeta(meta: unknown): number {
let index = this.metas.indexOf(meta);
if (index > -1) {
return index;
}
return this.value(meta);
}

return this.metas.push(meta) - 1;
getValue<T>(index: number) {
return this.values[index] as T;
}

getNumber(value: number): number {
return this.numbers[value];
return this.getValue(value);
}

getString(value: number): string {
return this.strings[value];
return this.getValue(value);
}

getStringArray(value: number): string[] {
let names = this.getArray(value);
let _names: string[] = new Array(names.length);
let reifiedStringArrs = this.reifiedStringArrs;
let reified = reifiedStringArrs[value];

for (let i = 0; i < names.length; i++) {
let n = names[i];
_names[i] = this.getString(n);
if (reified === undefined) {
let names = this.getArray(value);
reified = new Array(names.length);

for (let i = 0; i < names.length; i++) {
reified[i] = this.getValue(names[i]);
}

reifiedStringArrs[value] = reified;
}

return _names;
return reified;
}

getArray(value: number): number[] {
return (this.arrays as number[][])[value];
return this.getValue(value);
}

getSerializable<T>(s: number): T {
return JSON.parse(this.strings[s]) as T;
return JSON.parse(this.getValue(s)) as T;
}

getTemplateMeta<T>(m: number): T {
return this.metas[m] as T;
return this.getValue(m);
}

getOther<T>(value: number): T {
return this.others[value] as T;
return this.getValue(value);
}
}
11 changes: 4 additions & 7 deletions packages/@glimmer/runtime/lib/vm/arguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,24 +360,21 @@ export class NamedArgumentsImpl implements NamedArguments {
if (extras > 0) {
let { names, length, stack } = this;
let { names: extraNames } = other;

if (Object.isFrozen(names) && names.length === 0) {
names = [];
}
let newNames = names.slice();

for (let i = 0; i < extras; i++) {
let name = extraNames[i];
let idx = names.indexOf(name);
let idx = newNames.indexOf(name);

if (idx === -1) {
length = names.push(name);
length = newNames.push(name);
stack.push(other.references[i]);
}
}

this.length = length;
this._references = null;
this._names = names;
this._names = newNames;
this._atNames = null;
}
}
Expand Down

0 comments on commit 3ae94e0

Please sign in to comment.