prepack
prepack copied to clipboard
Leaking bindings stops tracking their values
Prepacking this...
(function () {
function f(g) {
let x = 23;
function f() { return x; }
g(f); // <- this leaks x
x = 1;
x = 2;
x = 3;
x = 4;
x = 5;
return x;
}
global.__optimize && __optimize(f);
global.inspect = function() { return f(g => g()); }
})();
results in the following (at least after #2010 lands):
(function () {
var _$2 = this;
var _1 = function (g) {
var __scope_0 = new Array(1);
var __scope_1 = function (__selector) {
var __captured;
switch (__selector) {
case 0:
__captured = [void 0];
break;
default:
throw new Error("Unknown scope selector");
}
__scope_0[__selector] = __captured;
return __captured;
};
var _A = function () {
var __captured__scope_2 = __scope_0[0] || __scope_1(0);
return __captured__scope_2[0];
};
(__scope_0[0] || __scope_1(0))[0] = 23;
var _$0 = g(_A);
(__scope_0[0] || __scope_1(0))[0] = 1;
(__scope_0[0] || __scope_1(0))[0] = 2;
(__scope_0[0] || __scope_1(0))[0] = 3;
(__scope_0[0] || __scope_1(0))[0] = 4;
(__scope_0[0] || __scope_1(0))[0] = 5;
var _$1 = (__scope_0[0] || __scope_1(0))[0];
return _$1;
};
var _0 = function () {
return _1(g => g());
};
_$2.inspect = _0;
}).call(this);
Ignoring the whole (__scope_0[0] || __scope_1(0))[0]
verbosity, this is not great because, because after havocing...
- Prepack emits every single binding update as a generator entry; it should only be necessary to emit the last one before the next call to an unknown function and at function exit.
- Prepack doesn't even know internally any more what the last value actually is; that's why the
return x
results in code that actually reads the memory location. And worse, this lack of knowledge might cause the code to run into other prepack limitations, and suppress further optimization potential.
#2031 made the situation a bit better for bindings, as at least for final objects the leaked final descriptor is kept around and used.