From 2b600a3d569b2d519a5e057783976b0e055a7761 Mon Sep 17 00:00:00 2001 From: Chris Blappert Date: Thu, 1 Mar 2018 15:47:59 -0800 Subject: [PATCH] Fix additional functions refactor Summary: Fix for bug NTillmann encountered with the additional functions refactor. Every function references itself through its `arguments`, so additional functions were recursively trying to visit themselves while visiting their arguments. It doesn't make sense to visit a function from its own scope, so we add a check to the visitor preventing this. Closes https://github.com/facebook/prepack/pull/1508 Differential Revision: D7130078 Pulled By: cblappert fbshipit-source-id: ecb0497456169f3ff41c89f2fcf17e3ae9670d96 --- src/serializer/ResidualHeapVisitor.js | 10 ++++++---- .../additional-functions/self_referential.js | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 test/serializer/additional-functions/self_referential.js diff --git a/src/serializer/ResidualHeapVisitor.js b/src/serializer/ResidualHeapVisitor.js index bdcb9aaa5..1488a9443 100644 --- a/src/serializer/ResidualHeapVisitor.js +++ b/src/serializer/ResidualHeapVisitor.js @@ -786,10 +786,12 @@ export class ResidualHeapVisitor { } else if (val instanceof FunctionValue) { // Function declarations should get hoisted in common scope so that instances only get allocated once let parentScope = this.scope; - this._withScope(this.commonScope, () => { - invariant(val instanceof FunctionValue); - if (this.preProcessValue(val)) this.visitValueFunction(val, parentScope); - }); + // Every function references itself through arguments, prevent the recursive double-visit + if (this.scope !== val && this.commonScope !== val) + this._withScope(this.commonScope, () => { + invariant(val instanceof FunctionValue); + if (this.preProcessValue(val)) this.visitValueFunction(val, parentScope); + }); } else if (val instanceof SymbolValue) { if (this.preProcessValue(val)) this.visitValueSymbol(val); } else { diff --git a/test/serializer/additional-functions/self_referential.js b/test/serializer/additional-functions/self_referential.js new file mode 100644 index 000000000..80f3fe1e5 --- /dev/null +++ b/test/serializer/additional-functions/self_referential.js @@ -0,0 +1,15 @@ +// does not contain:x = 5; + +function func1() { + let x = 5; + let z = [ func1 ]; + return z; +} + +if (global.__registerAdditionalFunctionToPrepack) { + __registerAdditionalFunctionToPrepack(func1); +} + +inspect = function() { + return func1()[0] === func1()[0]; +}