From 42fd9bf2f0b81e2cbec47ebe1d7defc705be7297 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 18 Mar 2021 15:29:55 -0400 Subject: [PATCH 1/6] Remove lodash sortBy use This one `require` increases startup time by 100ms (coming from `loadOptions`). --- .../src/transformation/block-hoist-plugin.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/babel-core/src/transformation/block-hoist-plugin.js b/packages/babel-core/src/transformation/block-hoist-plugin.js index 477d2d5c3bfe..45f9eff13d4e 100644 --- a/packages/babel-core/src/transformation/block-hoist-plugin.js +++ b/packages/babel-core/src/transformation/block-hoist-plugin.js @@ -1,7 +1,5 @@ // @flow -import sortBy from "lodash/sortBy"; - import loadConfig, { type Plugin } from "../config"; let LOADED_PLUGIN: Plugin | void; @@ -22,6 +20,14 @@ export default function loadBlockHoistPlugin(): Plugin { return LOADED_PLUGIN; } +function priority(bodyNode) { + let priority = bodyNode?._blockHoist; + if (priority == null) priority = 1; + if (priority === true) priority = 2; + + // Higher priorities should move toward the top. + return -1 * priority; +} const blockHoistPlugin = { /** @@ -51,14 +57,8 @@ const blockHoistPlugin = { } if (!hasChange) return; - node.body = sortBy(node.body, function (bodyNode) { - let priority = bodyNode?._blockHoist; - if (priority == null) priority = 1; - if (priority === true) priority = 2; - - // Higher priorities should move toward the top. - return -1 * priority; - }); + // Sort in ascending order + node.body.sort((a, b) => priority(a) - priority(b)); }, }, }, From 0f4dc6a8c499e0a5f95f1171ed4c5b5527cabeff Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 18 Mar 2021 16:53:31 -0400 Subject: [PATCH 2/6] My kingdom for a stable sort! --- .../src/transformation/block-hoist-plugin.js | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/packages/babel-core/src/transformation/block-hoist-plugin.js b/packages/babel-core/src/transformation/block-hoist-plugin.js index 45f9eff13d4e..2028a9e0ee2b 100644 --- a/packages/babel-core/src/transformation/block-hoist-plugin.js +++ b/packages/babel-core/src/transformation/block-hoist-plugin.js @@ -26,7 +26,33 @@ function priority(bodyNode) { if (priority === true) priority = 2; // Higher priorities should move toward the top. - return -1 * priority; + return priority; +} + +function stableSort(body, index) { + // By default, we use priorities of 0-4. + const buckets = [[], [], [], [], []]; + + // By collecting into buckets, we can guarantee a stable sort. + for (let i = index; i < body.length; i++) { + const n = body[i]; + const p = priority(n); + + // In case some plugin is setting an unexpected priority. + (buckets[p] ??= []).push(n); + } + + // Highest priorities go first + for (let i = buckets.length - 1; i >= 0; i--) { + const bucket = buckets[i]; + + // In that unexpected priority caused a sparse array. + if (!bucket) continue; + + for (const n of bucket) { + body[index++] = n; + } + } } const blockHoistPlugin = { @@ -47,18 +73,18 @@ const blockHoistPlugin = { visitor: { Block: { exit({ node }) { - let hasChange = false; - for (let i = 0; i < node.body.length; i++) { - const bodyNode = node.body[i]; - if (bodyNode?._blockHoist != null) { - hasChange = true; + const { body } = node; + let i = 0; + for (; i < body.length; i++) { + const n = body[i]; + if (n?._blockHoist != null) { break; } } - if (!hasChange) return; + if (i === body.length) return; - // Sort in ascending order - node.body.sort((a, b) => priority(a) - priority(b)); + // My kingdom for a stable sort! + stableSort(body, i); }, }, }, From a4d25aa4b0088978a8292cc6196d719ab2801a35 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 18 Mar 2021 20:12:57 -0400 Subject: [PATCH 3/6] Create new array instance, and ensure we sort the full array --- .../src/transformation/block-hoist-plugin.js | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/babel-core/src/transformation/block-hoist-plugin.js b/packages/babel-core/src/transformation/block-hoist-plugin.js index 2028a9e0ee2b..42befbdca992 100644 --- a/packages/babel-core/src/transformation/block-hoist-plugin.js +++ b/packages/babel-core/src/transformation/block-hoist-plugin.js @@ -21,17 +21,16 @@ export default function loadBlockHoistPlugin(): Plugin { return LOADED_PLUGIN; } function priority(bodyNode) { - let priority = bodyNode?._blockHoist; - if (priority == null) priority = 1; - if (priority === true) priority = 2; - - // Higher priorities should move toward the top. + const priority = bodyNode?._blockHoist; + if (priority == null) return 1; + if (priority === true) return 2; return priority; } -function stableSort(body, index) { +function stableSort(body) { // By default, we use priorities of 0-4. const buckets = [[], [], [], [], []]; + let index = 0; // By collecting into buckets, we can guarantee a stable sort. for (let i = index; i < body.length; i++) { @@ -47,12 +46,13 @@ function stableSort(body, index) { const bucket = buckets[i]; // In that unexpected priority caused a sparse array. - if (!bucket) continue; + if (bucket == null) continue; for (const n of bucket) { body[index++] = n; } } + return body; } const blockHoistPlugin = { @@ -74,17 +74,18 @@ const blockHoistPlugin = { Block: { exit({ node }) { const { body } = node; - let i = 0; - for (; i < body.length; i++) { + let hasChange = false; + for (let i = 0; i < body.length; i++) { const n = body[i]; if (n?._blockHoist != null) { + hasChange = true; break; } } - if (i === body.length) return; + if (!hasChange) return; // My kingdom for a stable sort! - stableSort(body, i); + node.body = stableSort(body.slice()); }, }, }, From 87f8cfb4f63e852d1466f12110c7028fbe4d3ba4 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 18 Mar 2021 20:19:09 -0400 Subject: [PATCH 4/6] Only sort when needed --- .../babel-core/src/transformation/block-hoist-plugin.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/babel-core/src/transformation/block-hoist-plugin.js b/packages/babel-core/src/transformation/block-hoist-plugin.js index 42befbdca992..6091dad8a2f6 100644 --- a/packages/babel-core/src/transformation/block-hoist-plugin.js +++ b/packages/babel-core/src/transformation/block-hoist-plugin.js @@ -74,13 +74,18 @@ const blockHoistPlugin = { Block: { exit({ node }) { const { body } = node; + + // Largest SMI + let max = 2 ** 30 - 1; let hasChange = false; for (let i = 0; i < body.length; i++) { const n = body[i]; - if (n?._blockHoist != null) { + const p = priority(n); + if (p > max) { hasChange = true; break; } + max = p; } if (!hasChange) return; From 30d544c61e5466a07d13c52b9151cf2e8b97cbfc Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 18 Mar 2021 21:23:21 -0400 Subject: [PATCH 5/6] Apparently logical assignment or nullish coalescing isn't enabled --- packages/babel-core/src/transformation/block-hoist-plugin.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/babel-core/src/transformation/block-hoist-plugin.js b/packages/babel-core/src/transformation/block-hoist-plugin.js index 6091dad8a2f6..e25c3156b06b 100644 --- a/packages/babel-core/src/transformation/block-hoist-plugin.js +++ b/packages/babel-core/src/transformation/block-hoist-plugin.js @@ -38,7 +38,8 @@ function stableSort(body) { const p = priority(n); // In case some plugin is setting an unexpected priority. - (buckets[p] ??= []).push(n); + const bucket = buckets[p] || (buckets[p] = []); + bucket.push(n); } // Highest priorities go first From 23da89c8594088e486d1f1f5de508efa55ca72af Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 19 Mar 2021 22:42:55 -0400 Subject: [PATCH 6/6] Use object to bucket --- .../src/transformation/block-hoist-plugin.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/babel-core/src/transformation/block-hoist-plugin.js b/packages/babel-core/src/transformation/block-hoist-plugin.js index e25c3156b06b..788b0e0a35dc 100644 --- a/packages/babel-core/src/transformation/block-hoist-plugin.js +++ b/packages/babel-core/src/transformation/block-hoist-plugin.js @@ -29,11 +29,10 @@ function priority(bodyNode) { function stableSort(body) { // By default, we use priorities of 0-4. - const buckets = [[], [], [], [], []]; - let index = 0; + const buckets = Object.create(null); // By collecting into buckets, we can guarantee a stable sort. - for (let i = index; i < body.length; i++) { + for (let i = 0; i < body.length; i++) { const n = body[i]; const p = priority(n); @@ -42,13 +41,15 @@ function stableSort(body) { bucket.push(n); } - // Highest priorities go first - for (let i = buckets.length - 1; i >= 0; i--) { - const bucket = buckets[i]; - - // In that unexpected priority caused a sparse array. - if (bucket == null) continue; + // Sort our keys in descending order. Keys are unique, so we don't have to + // worry about stability. + const keys = Object.keys(buckets) + .map(k => +k) + .sort((a, b) => b - a); + let index = 0; + for (const key of keys) { + const bucket = buckets[key]; for (const n of bucket) { body[index++] = n; }