Skip to content

Commit

Permalink
fix(performance): Eliminate use of ES6 generators (#4092)
Browse files Browse the repository at this point in the history
See: #4062 (comment)

Co-authored-by: @joeyparrish

Issue #4062
  • Loading branch information
Álvaro Velad Galván committed Apr 4, 2022
1 parent 8a3bed7 commit 57c7324
Show file tree
Hide file tree
Showing 32 changed files with 79 additions and 212 deletions.
13 changes: 13 additions & 0 deletions build/conformance.textproto
Expand Up @@ -320,3 +320,16 @@ requirement: {
"instead."
whitelist_regexp: "lib/net/http_fetch_plugin.js"
}

# Disallow the use of generators, which are a major performance issue. See
# https://github.com/shaka-project/shaka-player/issues/4062#issuecomment-1079428268
requirement: {
type: BANNED_CODE_PATTERN
value:
"/** @param {*} x */ "
"function *template(x) { yield x; }"
error_message:
"ES6 generators are a major performance issue! Find another solution. "
"See also https://bit.ly/3wAsoj5"
whitelist_regexp: "node_modules/"
}
8 changes: 5 additions & 3 deletions lib/cea/cea708_service.js
Expand Up @@ -300,17 +300,19 @@ shaka.cea.Cea708Service = class {
/**
* Yields each non-null window specified in the 8-bit bitmap.
* @param {number} bitmap 8 bits corresponding to each of the 8 windows.
* @return {!Iterable.<number>}
* @return {!Array.<number>}
* @private
*/
* getSpecifiedWindowIds_(bitmap) {
getSpecifiedWindowIds_(bitmap) {
const ids = [];
for (let i = 0; i < 8; i++) {
const windowSpecified = (bitmap & 0x01) === 0x01;
if (windowSpecified && this.windows_[i]) {
yield i;
ids.push(i);
}
bitmap >>= 1;
}
return ids;
}

/**
Expand Down
9 changes: 6 additions & 3 deletions lib/cea/sei_processor.js
Expand Up @@ -14,9 +14,10 @@ shaka.cea.SeiProcessor = class {
/**
* Processes supplemental enhancement information data.
* @param {!Uint8Array} naluData NALU from which SEI data is to be processed.
* @return {!Iterable.<!Uint8Array>}
* @return {!Array.<!Uint8Array>}
*/
* process(naluData) {
process(naluData) {
const seiPayloads = [];
const naluClone = this.removeEmu(naluData);

// The following is an implementation of section 7.3.2.3.1
Expand All @@ -41,10 +42,12 @@ shaka.cea.SeiProcessor = class {
// Payload type 4 is user_data_registered_itu_t_t35, as per the H.264
// spec. This payload type contains caption data.
if (payloadType == 0x04) {
yield naluClone.subarray(offset, offset + payloadSize);
seiPayloads.push(naluClone.subarray(offset, offset + payloadSize));
}
offset += payloadSize;
}

return seiPayloads;
}


Expand Down
3 changes: 1 addition & 2 deletions lib/dash/segment_list.js
Expand Up @@ -15,7 +15,6 @@ goog.require('shaka.media.SegmentIndex');
goog.require('shaka.media.SegmentReference');
goog.require('shaka.util.Error');
goog.require('shaka.util.Functional');
goog.require('shaka.util.Iterables');
goog.require('shaka.util.ManifestParserUtils');
goog.require('shaka.util.XmlUtils');
goog.requireType('shaka.dash.DashParser');
Expand Down Expand Up @@ -222,7 +221,7 @@ shaka.dash.SegmentList = class {
/** @type {!Array.<!shaka.media.SegmentReference>} */
const references = [];
let prevEndTime = info.startTime;
for (const i of shaka.util.Iterables.range(max)) {
for (let i = 0; i < max; i++) {
const segment = info.mediaSegments[i];
const mediaUri = ManifestParserUtils.resolveUris(
baseUris, [segment.mediaUri]);
Expand Down
12 changes: 7 additions & 5 deletions lib/hls/hls_parser.js
Expand Up @@ -30,7 +30,6 @@ goog.require('shaka.util.CmcdManager');
goog.require('shaka.util.Error');
goog.require('shaka.util.FakeEvent');
goog.require('shaka.util.Functional');
goog.require('shaka.util.Iterables');
goog.require('shaka.util.LanguageUtils');
goog.require('shaka.util.ManifestParserUtils');
goog.require('shaka.util.MimeUtils');
Expand Down Expand Up @@ -1869,8 +1868,8 @@ shaka.hls.HlsParser = class {
// Create SegmentReferences for the partial segments.
const partialSegmentRefs = [];
if (this.lowLatencyMode_ && hlsSegment.partialSegments.length) {
const enumerate = (it) => shaka.util.Iterables.enumerate(it);
for (const {i, item} of enumerate(hlsSegment.partialSegments)) {
for (let i = 0; i < hlsSegment.partialSegments.length; i++) {
const item = hlsSegment.partialSegments[i];
const pPreviousReference = i == 0 ?
previousReference : partialSegmentRefs[partialSegmentRefs.length - 1];
const pStartTime = (i == 0) ? startTime : pPreviousReference.endTime;
Expand All @@ -1891,6 +1890,9 @@ shaka.hls.HlsParser = class {
this.parseByteRange_(pPreviousReference, pByterange);
}
const pUri = item.getAttributeValue('URI');
if (!pUri) {
continue;
}
const pAbsoluteUri = shaka.hls.Utils.constructAbsoluteUri(
absoluteMediaPlaylistUri, pUri);

Expand Down Expand Up @@ -2066,8 +2068,8 @@ shaka.hls.HlsParser = class {
/** @type {!Array.<!shaka.media.SegmentReference>} */
const references = [];

const enumerate = (it) => shaka.util.Iterables.enumerate(it);
for (const {i, item} of enumerate(hlsSegments)) {
for (let i = 0; i < hlsSegments.length; i++) {
const item = hlsSegments[i];
const previousReference = references[references.length - 1];
const startTime =
(i == 0) ? firstStartTime : previousReference.endTime;
Expand Down
6 changes: 3 additions & 3 deletions lib/hls/manifest_text_parser.js
Expand Up @@ -13,7 +13,6 @@ goog.require('shaka.hls.Segment');
goog.require('shaka.hls.Tag');
goog.require('shaka.hls.Utils');
goog.require('shaka.util.Error');
goog.require('shaka.util.Iterables');
goog.require('shaka.util.StringUtils');
goog.require('shaka.util.TextParser');

Expand Down Expand Up @@ -82,8 +81,9 @@ shaka.hls.ManifestTextParser = class {
const tags = [];
// Initialize to "true" to skip the first element.
skip = true;
const enumerate = (it) => shaka.util.Iterables.enumerate(it);
for (const {i, item: line, next} of enumerate(lines)) {
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const next = lines[i + 1];
// Skip comments
if (shaka.hls.Utils.isComment(line) || skip) {
skip = false;
Expand Down
3 changes: 1 addition & 2 deletions lib/media/adaptation_set.js
Expand Up @@ -8,7 +8,6 @@ goog.provide('shaka.media.AdaptationSet');

goog.require('goog.asserts');
goog.require('shaka.log');
goog.require('shaka.util.Iterables');
goog.require('shaka.util.MimeUtils');


Expand Down Expand Up @@ -215,7 +214,7 @@ shaka.media.AdaptationSet = class {
codecsA.sort();
codecsB.sort();

for (const i of shaka.util.Iterables.range(codecsA.length)) {
for (let i = 0; i < codecsA.length; i++) {
if (codecsA[i] != codecsB[i]) {
return false;
}
Expand Down
5 changes: 1 addition & 4 deletions lib/media/mp4_segment_index_parser.js
Expand Up @@ -11,8 +11,6 @@ goog.require('shaka.log');
goog.require('shaka.media.InitSegmentReference');
goog.require('shaka.media.SegmentReference');
goog.require('shaka.util.Error');
goog.require('shaka.util.Functional');
goog.require('shaka.util.Iterables');
goog.require('shaka.util.Mp4Parser');


Expand Down Expand Up @@ -123,8 +121,7 @@ shaka.media.Mp4SegmentIndexParser = class {
let unscaledStartTime = earliestPresentationTime;
let startByte = sidxOffset + box.size + firstOffset;

for (const _ of shaka.util.Iterables.range(referenceCount)) {
shaka.util.Functional.ignored(_);
for (let i = 0; i < referenceCount; i++) {
// |chunk| is 1 bit for |referenceType|, and 31 bits for |referenceSize|.
const chunk = box.reader.readUint32();
const referenceType = (chunk & 0x80000000) >>> 31;
Expand Down
4 changes: 1 addition & 3 deletions lib/media/time_ranges_utils.js
Expand Up @@ -6,8 +6,6 @@

goog.provide('shaka.media.TimeRangesUtils');

goog.require('shaka.util.Iterables');


/**
* @summary A set of utility functions for dealing with TimeRanges objects.
Expand Down Expand Up @@ -157,7 +155,7 @@ shaka.media.TimeRangesUtils = class {
return [];
}
const ret = [];
for (const i of shaka.util.Iterables.range(b.length)) {
for (let i = 0; i < b.length; i++) {
ret.push({start: b.start(i), end: b.end(i)});
}
return ret;
Expand Down
5 changes: 2 additions & 3 deletions lib/polyfill/all.js
Expand Up @@ -7,7 +7,6 @@
goog.provide('shaka.polyfill');

goog.require('shaka.log');
goog.require('shaka.util.Iterables');


/**
Expand Down Expand Up @@ -40,8 +39,8 @@ shaka.polyfill = class {
*/
static register(polyfill, priority) {
const newItem = {priority: priority || 0, callback: polyfill};
const enumerate = (it) => shaka.util.Iterables.enumerate(it);
for (const {i, item} of enumerate(shaka.polyfill.polyfills_)) {
for (let i = 0; i < shaka.polyfill.polyfills_.length; i++) {
const item = shaka.polyfill.polyfills_[i];
if (item.priority < newItem.priority) {
shaka.polyfill.polyfills_.splice(i, 0, newItem);
return;
Expand Down
4 changes: 1 addition & 3 deletions lib/util/buffer_utils.js
Expand Up @@ -6,8 +6,6 @@

goog.provide('shaka.util.BufferUtils');

goog.require('shaka.util.Iterables');


/**
* @summary A set of BufferSource utility functions.
Expand Down Expand Up @@ -45,7 +43,7 @@ shaka.util.BufferUtils = class {

const uint8A = shaka.util.BufferUtils.toUint8(arr1);
const uint8B = shaka.util.BufferUtils.toUint8(arr2);
for (const i of shaka.util.Iterables.range(arr1.byteLength)) {
for (let i = 0; i < arr1.byteLength; i++) {
if (uint8A[i] != uint8B[i]) {
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/util/ebml_parser.js
Expand Up @@ -11,7 +11,6 @@ goog.require('goog.asserts');
goog.require('shaka.util.BufferUtils');
goog.require('shaka.util.DataViewReader');
goog.require('shaka.util.Error');
goog.require('shaka.util.Iterables');


/**
Expand Down Expand Up @@ -157,7 +156,8 @@ shaka.util.EbmlParser = class {
}

let value = 0;
for (const {item, i} of shaka.util.Iterables.enumerate(vint)) {
for (let i = 0; i < vint.length; i++) {
const item = vint[i];
if (i == 0) {
// Mask out the first few bits of |vint|'s first byte to get the most
// significant bits of |vint|'s value. If |vint| is 8 bytes wide then
Expand Down Expand Up @@ -267,7 +267,7 @@ shaka.util.EbmlElement = class {

let value = 0;

for (const i of shaka.util.Iterables.range(this.dataView_.byteLength)) {
for (let i = 0; i < this.dataView_.byteLength; i++) {
const chunk = this.dataView_.getUint8(i);
value = (256 * value) + chunk;
}
Expand Down
46 changes: 0 additions & 46 deletions lib/util/iterables.js
Expand Up @@ -75,50 +75,4 @@ shaka.util.Iterables = class {
}
return out;
}

/**
* Returns an iterable that contains numbers in the range [0, end).
*
* @param {number} end The exclusive end of the list.
* @return {!Iterable.<number>}
*/
static* range(end) {
for (let i = 0; i < end; i++) {
yield i;
}
}

/**
* Iterates over an iterable object and includes additional info about each
* item:
* - The zero-based index of the element.
* - The next item in the list, if it exists.
* - The previous item in the list, if it exists.
*
* @param {!Iterable.<T>} iterable
* @return {!Iterable.<
* {i: number, item: T, prev: (T|undefined), next: (T|undefined)}>}
* @template T
*/
static* enumerate(iterable) {
// Since we want the "next" item, we need to skip the first item and return
// elements one in the past. So as we iterate, we are getting the "next"
// element and yielding the one from the previous iteration.
let i = -1;
let prev = undefined;
let item = undefined;
for (const next of iterable) {
if (i >= 0) {
yield {i, item, prev, next};
}
i++;
prev = item;
item = next;
}
if (i != -1) {
// If it's still -1, there were no items. Otherwise we need to yield
// the last item.
yield {i, prev, item, next: undefined};
}
}
};
5 changes: 1 addition & 4 deletions lib/util/mp4_box_parsers.js
Expand Up @@ -7,8 +7,6 @@
goog.provide('shaka.util.Mp4BoxParsers');

goog.require('shaka.util.DataViewReader');
goog.require('shaka.util.Functional');
goog.require('shaka.util.Iterables');

shaka.util.Mp4BoxParsers = class {
/**
Expand Down Expand Up @@ -125,8 +123,7 @@ shaka.util.Mp4BoxParsers = class {
reader.skip(4);
}

for (const _ of shaka.util.Iterables.range(sampleCount)) {
shaka.util.Functional.ignored(_);
for (let i = 0; i < sampleCount; i++) {
/** @type {shaka.util.ParsedTRUNSample} */
const sample = {
sampleDuration: null,
Expand Down
5 changes: 1 addition & 4 deletions lib/util/mp4_parser.js
Expand Up @@ -9,8 +9,6 @@ goog.provide('shaka.util.Mp4Parser');
goog.require('goog.asserts');
goog.require('shaka.log');
goog.require('shaka.util.DataViewReader');
goog.require('shaka.util.Functional');
goog.require('shaka.util.Iterables');


/**
Expand Down Expand Up @@ -229,8 +227,7 @@ shaka.util.Mp4Parser = class {
// start position. The header size varies.
const headerSize = shaka.util.Mp4Parser.headerSize(box);
const count = box.reader.readUint32();
for (const _ of shaka.util.Iterables.range(count)) {
shaka.util.Functional.ignored(_);
for (let i = 0; i < count; i++) {
box.parser.parseNext(box.start + headerSize, box.reader, box.partialOkay);
if (box.parser.done_) {
break;
Expand Down

0 comments on commit 57c7324

Please sign in to comment.