perf: don't create holey arrays (#32155)
Don't use `Array` constructor with the size value (ex. `new Array(5)`) - this will create a `HOLEY_ELEMENTS` array (even if this array is filled in later on!); https://v8.dev/blog/elements-kinds https://stackoverflow.com/questions/32054170/how-to-resize-an-array PR Close #32155
This commit is contained in:

committed by
Andrew Kushnir

parent
c957dfc167
commit
64770571b2
@ -14,7 +14,6 @@ import {MessageBundle} from '../i18n/message_bundle';
|
||||
import {Identifiers, createTokenForExternalReference} from '../identifiers';
|
||||
import {InjectableCompiler} from '../injectable_compiler';
|
||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
||||
import * as html from '../ml_parser/ast';
|
||||
import {HtmlParser} from '../ml_parser/html_parser';
|
||||
import {removeWhitespaces} from '../ml_parser/html_whitespaces';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../ml_parser/interpolation_config';
|
||||
@ -32,7 +31,7 @@ import {SummaryResolver} from '../summary_resolver';
|
||||
import {BindingParser} from '../template_parser/binding_parser';
|
||||
import {TemplateAst} from '../template_parser/template_ast';
|
||||
import {TemplateParser} from '../template_parser/template_parser';
|
||||
import {OutputContext, ValueVisitor, error, syntaxError, visitValue} from '../util';
|
||||
import {OutputContext, ValueVisitor, error, newArray, syntaxError, visitValue} from '../util';
|
||||
import {TypeCheckCompiler} from '../view_compiler/type_check_compiler';
|
||||
import {ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
|
||||
|
||||
@ -690,7 +689,7 @@ export class AotCompiler {
|
||||
const suppliedTypeParams = typeParams || [];
|
||||
const missingTypeParamsCount = arity - suppliedTypeParams.length;
|
||||
const allTypeParams =
|
||||
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
|
||||
suppliedTypeParams.concat(newArray(missingTypeParamsCount, o.DYNAMIC_TYPE));
|
||||
return members.reduce(
|
||||
(expr, memberName) => expr.prop(memberName),
|
||||
<o.Expression>o.importExpr(
|
||||
|
@ -436,7 +436,7 @@ export class AstTransformer implements AstVisitor {
|
||||
}
|
||||
|
||||
visitAll(asts: any[]): any[] {
|
||||
const res = new Array(asts.length);
|
||||
const res = [];
|
||||
for (let i = 0; i < asts.length; ++i) {
|
||||
res[i] = asts[i].visit(this);
|
||||
}
|
||||
@ -598,7 +598,7 @@ export class AstMemoryEfficientTransformer implements AstVisitor {
|
||||
}
|
||||
|
||||
visitAll(asts: any[]): any[] {
|
||||
const res = new Array(asts.length);
|
||||
const res = [];
|
||||
let modified = false;
|
||||
for (let i = 0; i < asts.length; ++i) {
|
||||
const original = asts[i];
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {utf8Encode} from '../util';
|
||||
import {newArray, utf8Encode} from '../util';
|
||||
|
||||
import * as i18n from './i18n_ast';
|
||||
|
||||
@ -93,7 +93,7 @@ export function sha1(str: string): string {
|
||||
const words32 = stringToWords32(utf8, Endian.Big);
|
||||
const len = utf8.length * 8;
|
||||
|
||||
const w = new Array(80);
|
||||
const w = newArray(80);
|
||||
let [a, b, c, d, e]: number[] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
|
||||
|
||||
words32[len >> 5] |= 0x80 << (24 - len % 32);
|
||||
@ -247,9 +247,10 @@ function rol64([hi, lo]: [number, number], count: number): [number, number] {
|
||||
}
|
||||
|
||||
function stringToWords32(str: string, endian: Endian): number[] {
|
||||
const words32 = Array((str.length + 3) >>> 2);
|
||||
const size = (str.length + 3) >>> 2;
|
||||
const words32 = [];
|
||||
|
||||
for (let i = 0; i < words32.length; i++) {
|
||||
for (let i = 0; i < size; i++) {
|
||||
words32[i] = wordAt(str, i * 4, endian);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ import {ProviderElementContext, ProviderViewContext} from '../provider_analyzer'
|
||||
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
||||
import {CssSelector, SelectorMatcher} from '../selector';
|
||||
import {isStyleUrlResolvable} from '../style_url_resolver';
|
||||
import {Console, syntaxError} from '../util';
|
||||
import {Console, newArray, syntaxError} from '../util';
|
||||
|
||||
import {BindingParser} from './binding_parser';
|
||||
import * as t from './template_ast';
|
||||
@ -528,7 +528,7 @@ class TemplateParseVisitor implements html.Visitor {
|
||||
// Need to sort the directives so that we get consistent results throughout,
|
||||
// as selectorMatcher uses Maps inside.
|
||||
// Also deduplicate directives as they might match more than one time!
|
||||
const directives = new Array(this.directivesIndex.size);
|
||||
const directives = newArray(this.directivesIndex.size);
|
||||
// Whether any directive selector matches on the element name
|
||||
let matchElement = false;
|
||||
|
||||
|
@ -253,3 +253,13 @@ const __global = typeof global !== 'undefined' && global;
|
||||
// should be __global in that case.
|
||||
const _global: {[name: string]: any} = __global || __window || __self;
|
||||
export {_global as global};
|
||||
|
||||
export function newArray<T = any>(size: number): T[];
|
||||
export function newArray<T>(size: number, value: T): T[];
|
||||
export function newArray<T>(size: number, value?: T): T[] {
|
||||
const list: T[] = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
list.push(value !);
|
||||
}
|
||||
return list;
|
||||
}
|
@ -10,6 +10,7 @@ import {AotCompilerHost, AotCompilerOptions, GeneratedFile, createAotCompiler, t
|
||||
import {MetadataBundlerHost} from '@angular/compiler-cli/src/metadata/bundler';
|
||||
import {MetadataCollector} from '@angular/compiler-cli/src/metadata/collector';
|
||||
import {ModuleMetadata} from '@angular/compiler-cli/src/metadata/index';
|
||||
import {newArray} from '@angular/compiler/src/util';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
@ -686,7 +687,7 @@ export function expectNoDiagnostics(program: ts.Program) {
|
||||
return '';
|
||||
}
|
||||
|
||||
function chars(len: number, ch: string): string { return new Array(len).fill(ch).join(''); }
|
||||
function chars(len: number, ch: string): string { return newArray(len, ch).join(''); }
|
||||
|
||||
function lineNoOf(offset: number, text: string): number {
|
||||
let result = 1;
|
||||
|
@ -9,6 +9,7 @@
|
||||
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
|
||||
import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter';
|
||||
import * as o from '@angular/compiler/src/output/output_ast';
|
||||
import {newArray} from '@angular/compiler/src/util';
|
||||
|
||||
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
|
||||
|
||||
@ -108,7 +109,7 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some
|
||||
});
|
||||
|
||||
it('should break expressions into multiple lines if they are too long', () => {
|
||||
const values: o.Expression[] = new Array(100);
|
||||
const values: o.Expression[] = newArray(100);
|
||||
values.fill(o.literal(1));
|
||||
values.splice(50, 0, o.fn([], [new o.ReturnStatement(o.literal(1))]));
|
||||
expect(emitStmt(o.variable('fn').callFn(values).toStmt())).toEqual([
|
||||
|
@ -10,6 +10,7 @@ import {EmitterVisitorContext} from '@angular/compiler/src/output/abstract_emitt
|
||||
import * as o from '@angular/compiler/src/output/output_ast';
|
||||
import {JitEmitterVisitor, JitEvaluator} from '@angular/compiler/src/output/output_jit';
|
||||
import {R3JitReflector} from '@angular/compiler/src/render3/r3_jit';
|
||||
import {newArray} from '@angular/compiler/src/util';
|
||||
import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_reflector';
|
||||
|
||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||
@ -18,10 +19,10 @@ const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||
describe('Output JIT', () => {
|
||||
describe('regression', () => {
|
||||
it('should generate unique argument names', () => {
|
||||
const externalIds = new Array(10).fill(1).map(
|
||||
const externalIds = newArray(10, 1).map(
|
||||
(_, index) =>
|
||||
new o.ExternalReference(anotherModuleUrl, `id_${index}_`, {name: `id_${index}_`}));
|
||||
const externalIds1 = new Array(10).fill(1).map(
|
||||
const externalIds1 = newArray(10, 1).map(
|
||||
(_, index) => new o.ExternalReference(
|
||||
anotherModuleUrl, `id_${index}_1`, {name: `id_${index}_1`}));
|
||||
const ctx = EmitterVisitorContext.createRoot();
|
||||
|
@ -10,6 +10,8 @@ import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
|
||||
import * as o from '@angular/compiler/src/output/output_ast';
|
||||
import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter';
|
||||
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '@angular/compiler/src/parse_util';
|
||||
import {newArray} from '@angular/compiler/src/util';
|
||||
|
||||
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
|
||||
|
||||
const someGenFilePath = 'somePackage/someGenFile';
|
||||
@ -160,7 +162,7 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some
|
||||
});
|
||||
|
||||
it('should break expressions into multiple lines if they are too long', () => {
|
||||
const values: o.Expression[] = new Array(100);
|
||||
const values: o.Expression[] = newArray(100);
|
||||
values.fill(o.literal(1));
|
||||
values.splice(50, 0, o.fn([], [new o.ReturnStatement(o.literal(1))]));
|
||||
expect(emitStmt(o.variable('fn').callFn(values).toStmt())).toEqual([
|
||||
|
@ -19,7 +19,7 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle
|
||||
import {CompileEntryComponentMetadata, CompileStylesheetMetadata} from '../../src/compile_metadata';
|
||||
import {Identifiers, createTokenForExternalReference, createTokenForReference} from '../../src/identifiers';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../src/ml_parser/interpolation_config';
|
||||
import {noUndefined} from '../../src/util';
|
||||
import {newArray, noUndefined} from '../../src/util';
|
||||
import {MockSchemaRegistry} from '../../testing';
|
||||
import {unparse} from '../expression_parser/utils/unparser';
|
||||
import {TEST_COMPILER_PROVIDERS} from '../test_bindings';
|
||||
@ -481,7 +481,7 @@ class ArrayConsole implements Console {
|
||||
new BoundDirectivePropertyAst('foo', 'bar', null !, null !)
|
||||
];
|
||||
const result = templateVisitAll(visitor, nodes, null);
|
||||
expect(result).toEqual(new Array(nodes.length).fill(true));
|
||||
expect(result).toEqual(newArray(nodes.length).fill(true));
|
||||
});
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user