I'm writing a compiler in JavaScript, and for the optimizer I'm following the usual pattern where a list of optimizations is run repeatedly until nothing happens. The obvious way to detect the 'nothing happens' condition is to have each optimization set a flag if it successfully does something. I'm wondering if there's a more elegant way to go about it.
In the abstract, the problem can be phrased like this: given a complex object (with many levels of subobjects including arrays with circular references etc.), run it through a possible transformation then detect whether anything has changed. So the question is whether there is a simple way to detect changes in a complex object.
Watch.js provides ways to detect changes in an object, but only at top level, and will trigger if a field is changed even if it is subsequently returned to its original value.
Another approach would be to make a deep copy of the object and then deep compare with the original. However, from other questions here, deep copy looks like a nontrivial operation and deep compare has challenges of its own.
Is there an elegant trick I'm missing, or should I just stick to letting each optimization pass do its own bit of bookkeeping?