mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-11-09 21:20:06 +03:00
Preserve residual funciton original ordering
Summary: Release Note: preserve residual functions' original source ordering. We serialize the residual functions in random order(based on the visitor's discovery of residual function order) which may result in very bad code locality in real world app. Add the feature to preserve residual functions' original source ordering. Note: 1. I did not make an option for this feature because I think it should do this by default. 2. To gain better perf, we may introduce some profiler guided optimization in future. Closes https://github.com/facebook/prepack/pull/1163 Differential Revision: D6437299 Pulled By: yinghuitan fbshipit-source-id: 9c0a93a10862b0d8c96bfccb38238c497e4012e7
This commit is contained in:
parent
10215dd8cc
commit
e03c61c29f
@ -9,6 +9,7 @@
|
||||
|
||||
/* @flow */
|
||||
|
||||
import invariant from "../lib/invariant.js";
|
||||
let FatalError = require("../lib/errors.js").FatalError;
|
||||
let prepackSources = require("../lib/prepack-node.js").prepackSources;
|
||||
|
||||
@ -231,6 +232,28 @@ function execInContext(code) {
|
||||
return (result + logOutput).trim();
|
||||
}
|
||||
|
||||
function parseFunctionOrderings(code: string): Array<number> {
|
||||
const orders = [];
|
||||
const functionOrderPattern = /Function ordering: (\d+)/g;
|
||||
let match;
|
||||
while ((match = functionOrderPattern.exec(code)) != null) {
|
||||
orders.push(match[1]);
|
||||
}
|
||||
return orders;
|
||||
}
|
||||
|
||||
function verifyFunctionOrderings(code: string): boolean {
|
||||
const orders = parseFunctionOrderings(code);
|
||||
for (let i = 1; i < orders.length; ++i) {
|
||||
invariant(orders[i] !== orders[i - 1]);
|
||||
if (orders[i] < orders[i - 1]) {
|
||||
console.log(chalk.red(`Funtion ordering is not preserved: function ${orders[i - 1]} is before ${orders[i]}`));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function runTest(name, code, options, args) {
|
||||
console.log(chalk.inverse(name) + " " + JSON.stringify(options));
|
||||
let compatibility = code.includes("// jsc") ? "jsc-600-1-4-17" : undefined;
|
||||
@ -420,6 +443,9 @@ function runTest(name, code, options, args) {
|
||||
console.log(chalk.red("Output mismatch!"));
|
||||
break;
|
||||
}
|
||||
if (!verifyFunctionOrderings(codeToRun)) {
|
||||
break;
|
||||
}
|
||||
// Test the number of clone functions generated with the inital prepack call
|
||||
if (i === 0 && functionCloneCountMatch) {
|
||||
let functionCount = parseInt(functionCloneCountMatch[1], 10);
|
||||
|
@ -27,6 +27,8 @@ export default function(
|
||||
let ConciseBody = ast.body;
|
||||
if (ConciseBody.type !== "BlockStatement") {
|
||||
ConciseBody = t.blockStatement([t.returnStatement(ConciseBody)]);
|
||||
// Use original array function's location for the new concise body.
|
||||
ConciseBody.loc = ast.body.loc;
|
||||
}
|
||||
|
||||
// 1. If the function code for this ArrowFunction is strict mode code, let strict be true. Otherwise let strict be false.
|
||||
@ -40,6 +42,7 @@ export default function(
|
||||
|
||||
// 4. Let closure be FunctionCreate(Arrow, parameters, ConciseBody, scope, strict).
|
||||
let closure = Functions.FunctionCreate(realm, "arrow", parameters, ConciseBody, scope, strict);
|
||||
closure.loc = ast.loc;
|
||||
|
||||
// 5. Return closure.
|
||||
return closure;
|
||||
|
@ -142,6 +142,7 @@ export default function(
|
||||
|
||||
// 3. Let closure be FunctionCreate(Normal, FormalParameters, FunctionBody, scope, strict).
|
||||
let closure = Functions.FunctionCreate(realm, "normal", ast.params, ast.body, scope, strict);
|
||||
closure.loc = ast.loc;
|
||||
|
||||
// 4. Perform MakeConstructor(closure).
|
||||
MakeConstructor(realm, closure);
|
||||
|
@ -169,6 +169,30 @@ export class ResidualFunctions {
|
||||
return factoryFunctionInfos;
|
||||
}
|
||||
|
||||
// Preserve residual functions' ordering from original source code.
|
||||
// This is necessary to prevent unexpected code locality issues.
|
||||
// [Algorithm] sort function based on following criterias:
|
||||
// 1. source file alphabetically.
|
||||
// 2. start line number.
|
||||
// 3. start column number.
|
||||
_sortFunctionByOriginalOrdering(functionEntries: Array<[BabelNodeBlockStatement, Array<FunctionInstance>]>): void {
|
||||
functionEntries.sort((funcA, funcB) => {
|
||||
const funcALocation = funcA[0].loc;
|
||||
const funcBLocation = funcB[0].loc;
|
||||
if (!funcALocation || !funcBLocation || !funcALocation.source || !funcBLocation.source) {
|
||||
// Preserve the current ordering if there is no source location information available.
|
||||
return -1;
|
||||
}
|
||||
if (funcALocation.source !== funcBLocation.source) {
|
||||
return funcALocation.source.localeCompare(funcBLocation.source);
|
||||
} else if (funcALocation.start.line !== funcBLocation.start.line) {
|
||||
return funcALocation.start.line - funcBLocation.start.line;
|
||||
} else {
|
||||
return funcALocation.start.column - funcBLocation.start.column;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
spliceFunctions(
|
||||
rewrittenAdditionalFunctions: Map<FunctionValue, Array<BabelNodeStatement>>
|
||||
): ResidualFunctionsResult {
|
||||
@ -200,6 +224,7 @@ export class ResidualFunctions {
|
||||
let functionEntries: Array<[BabelNodeBlockStatement, Array<FunctionInstance>]> = Array.from(
|
||||
this.functions.entries()
|
||||
);
|
||||
this._sortFunctionByOriginalOrdering(functionEntries);
|
||||
this.statistics.functions = functionEntries.length;
|
||||
let unstrictFunctionBodies = [];
|
||||
let strictFunctionBodies = [];
|
||||
|
14
test/serializer/basic/FunctionOrdering.js
Normal file
14
test/serializer/basic/FunctionOrdering.js
Normal file
@ -0,0 +1,14 @@
|
||||
(function () {
|
||||
first = function() {
|
||||
// Function ordering: 1
|
||||
second();
|
||||
return 10;
|
||||
}
|
||||
var second = function() {
|
||||
// Function ordering: 2
|
||||
return 20;
|
||||
};
|
||||
inspect = function() {
|
||||
return first() + second();
|
||||
}
|
||||
})();
|
Loading…
Reference in New Issue
Block a user