michael@0: /* michael@0: * Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/licenses/publicdomain/ michael@0: */ michael@0: michael@0: function make_watcher(name) { michael@0: return function (id, oldv, newv) { michael@0: print("watched " + name + "[0]"); michael@0: }; michael@0: } michael@0: michael@0: var o, p; michael@0: function f(flag) { michael@0: if (flag) { michael@0: o = arguments; michael@0: } else { michael@0: p = arguments; michael@0: o.watch(0, make_watcher('o')); michael@0: p.watch(0, make_watcher('p')); michael@0: michael@0: /* michael@0: * Previously, the watchpoint implementation actually substituted its magic setter michael@0: * functions for the setters of shared shapes, and then 1) carefully ignored calls michael@0: * to its magic setter from unrelated objects, and 2) avoided restoring the michael@0: * original setter until all watchpoints on that shape had been removed. michael@0: * michael@0: * However, when the watchpoint code began using JSObject::changeProperty and michael@0: * js_ChangeNativePropertyAttrs to change shapes' setters, the shape tree code michael@0: * became conscious of the presence of watchpoints, and shared shapes between michael@0: * objects only when their watchpoint nature coincided. Clearing the magic setter michael@0: * from one object's shape would not affect other objects, because the michael@0: * watchpointed and non-watchpointed shapes were distinct if they were shared. michael@0: * michael@0: * Thus, the first unwatch call must go ahead and fix p's shape, even though a michael@0: * watchpoint exists on the same shape in o. o's watchpoint's presence shouldn't michael@0: * cause 'unwatch' to leave p's magic setter in place. michael@0: */ michael@0: michael@0: /* DropWatchPointAndUnlock would see o's watchpoint, and not change p's property. */ michael@0: p.unwatch(0); michael@0: michael@0: /* DropWatchPointAndUnlock would fix o's property, but not p's; p's setter would be gone. */ michael@0: o.unwatch(0); michael@0: michael@0: /* This would fail to invoke the arguments object's setter. */ michael@0: p[0] = 4; michael@0: michael@0: /* And the formal parameter would not get updated. */ michael@0: assertEq(flag, 4); michael@0: } michael@0: } michael@0: michael@0: f(true); michael@0: f(false); michael@0: michael@0: reportCompare(true, true);