Table of Contents
History
- Originally built for this use case #799 with some specific constraints:
- optimized functions would only ever be called once
- they would only be called after global initialization
- they would use disjoint sets of state
- they can assume that state is as it was at the end of global initialization
Current Assumptions
Purity
We default to all __optimized
functions being pure. In this case, the assumptions below about mutation are no longer an issue. __optimized
functions marked as pure check their purity and emit compiler diagnostics PP1003 and PP1007.
It is possible to specify non-pure optimized functions, but they likely will not work as expected in most cases.
Mutation
For any mutation that results in a concrete value, it is okay to emit code assigning that concrete value to its binding/property
let x = 5;
function residual() { x++; }
function foo() {
// Some expensive computation
return x;
}
__optimize(foo);
gets transformed to
var residual, foo;
let x;
(function () {
var _$0 = this;
var _1 = function () {
return 5;
};
var _0 = function () {
x++;
};
_$0.residual = _0;
_$0.foo = _1;
x = 5;
}).call(this);
Note that the optimized foo
function returns 5
and not x
.
To solve this, use-cases like the react compiler automatically turn captured mutable values into AbstractValue
s. For any mutation that results in an abstract value, any interactions with the value will be recorded in the generator so code will be emitted correctly.
let x = __abstract("number", "x");
function residual() { x++; }
function foo() {
// Some expensive computation
return x;
}
__optimize(foo);
Gets transformed into
var residual, foo;
let x;
(function () {
var _$0 = this;
var _1 = function () {
return _2;
};
var _0 = function () {
x++;
};
_$0.residual = _0;
var _2 = x;
_$0.foo = _1;
x = _2;
}).call(this);
Bindings
Mutations to bindings should only be serialized when the bindings are reachable (used by a rewritten optimized function or in the global scope)
See test/serializer/additional-functions/precise_captures.js
function Bar() {
return 123;
}
function Foo() {
return Bar();
}
if (global.__optimize) __optimize(Foo);
global.Foo = Foo;
transforms to
var _$0 = this;
var _0 = function () {
return 123;
};
_$0.Foo = _0;
Bar
gets eliminated even though Foo
originally captured it because the value is no longer needed by the new body of Foo