Closed
Bug 435345
Opened 16 years ago
Closed 16 years ago
Cannot accurately watch the 'length' property of arrays
Categories
(Core :: JavaScript Engine, defect)
Tracking
()
RESOLVED
FIXED
People
(Reporter: cyology, Assigned: crowderbt)
References
Details
(Keywords: regression, verified1.9.0.2)
Attachments
(4 files)
2.64 KB,
patch
|
shaver
:
review+
|
Details | Diff | Splinter Review |
5.72 KB,
patch
|
samuel.sidler+old
:
approval1.9.0.2+
|
Details | Diff | Splinter Review |
3.63 KB,
text/plain
|
crowderbt
:
review+
|
Details |
3.31 KB,
patch
|
Details | Diff | Splinter Review |
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9) Gecko/2008051202 Firefox/3.0 Build Identifier: In trying to update a library I wrote for observable arrays (i.e. some callback is called when items are added or removed from the array) for FF3, I've encountered a regression. I add a watcher to the length property (among other things). This now doesn't work due to the latest Array optimizations initially: var arr = [ ] arr.watch('length', function() { /* do something */}) // TypeError: can't watch non-native objects of class Array I know Brendan mentioned the optimization should be invisible to users, so this might be a bug in itself. However, this can be worked around by forcing the array to lose whatever these optimizations are if we want to observe it: arr.__defineSetter__('dummy', function(){}) arr.dummy = 5 arr.watch('length', function(_,b,a) { return a; }) // called, but incorrectly In prior versions of FF, this pseudo-worked (it would be double called but this could be worked around.) Now its not double called, but two problems: 1. b is always undefined (it should be the previous length). Another thing that can be worked around by keeping the previous length in some other variable. 2. This watcher seems to be accurately triggered most of the time: arr.push(5) // ok arr.pop() // ok arr.length++ // ok However, if you directly set an out of bounds index, it isn't called (and it was in Firefox 2): arr[arr.length] = 5 // no callback; note that this is a common optimization people use The only real workaround is to keep a watch on arr[arr.length] at all times and hope that nothing does strange things like arr[arr.length + 3] = 50, but I don't want to be forced to hope other peoples code doesn't do strange things. This is currently being used in a production library for some intranet applications that would possibly prevent an upgrade to FF3 for users. Reproducible: Always
Sigh, watch. I guess we need to fault to slow when a watch is set, for now -- complicating the SETELEM cases with watchpoint checks is not my idea of a good time. That still leaves the setting of length, which I suspect is a separate but also straightforward fix. Crowder, you up for these? Bounce back to me if not.
Assignee: general → crowder
Status: UNCONFIRMED → NEW
Ever confirmed: true
Assignee | ||
Comment 2•16 years ago
|
||
Some suckiness about this patch: * All objects pay for the IS_DENSE check. S'ok, hopefully, since presumably obj_watch won't happen all that often. * unwatch doesn't restore denseness. * Means that the use of watch will result in performance penalty for JS programmers. (is this a doc-needed thing? evangelism?) * Made MakeArraySlow no longer static to jsarray.cpp
Assignee | ||
Comment 3•16 years ago
|
||
Comment on attachment 324368 [details] [diff] [review] fallback to slow array on watch jsobj.cpp changes are the interesting part; the rest is s/MakeArraySlow>/js_MakeArraySlow/
Attachment #324368 -
Flags: review?(shaver)
Assignee | ||
Comment 4•16 years ago
|
||
Review-ping.
Comment on attachment 324368 [details] [diff] [review] fallback to slow array on watch r=shaver. sort of icky coupling, but we were already including jsarray.h in jsobj.cpp, so whatever!
Attachment #324368 -
Flags: review?(shaver) → review+
Assignee | ||
Updated•16 years ago
|
Flags: wanted1.9.0.x?
Assignee | ||
Updated•16 years ago
|
Attachment #324368 -
Flags: approval1.9.0.2?
Assignee | ||
Comment 6•16 years ago
|
||
changeset: 15602:9443787a6ee6
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
Updated•16 years ago
|
Keywords: regression
Version: unspecified → 1.9.0 Branch
Assignee | ||
Comment 7•16 years ago
|
||
Assignee | ||
Updated•16 years ago
|
Attachment #324368 -
Flags: approval1.9.0.2?
Assignee | ||
Updated•16 years ago
|
Attachment #329520 -
Flags: approval1.9.0.2?
Comment 9•16 years ago
|
||
(In reply to comment #8) > Can we get a test for this before landing in 1.9.0? > sure, coming right up.
Comment 10•16 years ago
|
||
passes 1.8.1 on mac, but fails with oldval=undefined on 1.9.1/mozilla-central
Attachment #330508 -
Flags: review?
Updated•16 years ago
|
Attachment #330508 -
Flags: review? → review?(crowder)
Assignee | ||
Comment 11•16 years ago
|
||
Comment on attachment 330508 [details]
js1_5/extensions/regress-435345-01.js
Looks great, thanks bc!
Attachment #330508 -
Flags: review?(crowder) → review+
Comment 12•16 years ago
|
||
crowder, the double call to the watcher in ": 2" on the 1.8.1 branch is expected? Reopen for the trunk for the oldval undefined errors or file a new bug?
Assignee | ||
Comment 13•16 years ago
|
||
1.8.1 does not have shavarrays, so bugs there are different. Lemme check out the other errors before we proceed.
Assignee | ||
Comment 14•16 years ago
|
||
It may be that when we fault to a slow array, we need to reify the length property on the new slow array, so that the later "length" get doesn't fail. Did that ever work for slow arrays?
Comment 15•16 years ago
|
||
Comment on attachment 329520 [details] [diff] [review] applied to 1.9 branch Approved for 1.9.0.2 on the condition that the test is landed where it needs to go as well. a=ss
Attachment #329520 -
Flags: approval1.9.0.2? → approval1.9.0.2+
Comment 16•16 years ago
|
||
crowder, is this really fixed on mozilla-central given the failures on getting oldval? Is the patch really ready for 1.9.0 as is?
Assignee | ||
Comment 17•16 years ago
|
||
bclary: Yeah, we can open those as another bug. Does that happen on 1.8?
Comment 18•16 years ago
|
||
crowder: 1.8.1 passes the existing test case as is including the double call to the watcher in ": 2" and does not exhibit the oldval=undefined problem. Before I check the test in and enshrine the double call as expected behavior, can I consider that a bug in 1.8.1 and modify test accordingly? I'll file a new bug on m-c for the oldval=undefined problem and block this.
Comment 19•16 years ago
|
||
crowder, on mozilla-central this test case gives the following valgrind error: ==28877== Conditional jump or move depends on uninitialised value(s) ==28877== at 0x47BA71: obj_watch(JSContext*, unsigned, long*) (jsobj.cpp:1437) ==28877== by 0x4FFD67: js_Interpret (jsinterp.cpp:4928) ==28877== by 0x466F5E: js_Execute (jsinterp.cpp:1553) ==28877== by 0x40EDA8: JS_ExecuteScript (jsapi.cpp:4926) ==28877== by 0x40A590: Process(JSContext*, JSObject*, char*, int) (js.cpp:272) ==28877== by 0x40AD32: ProcessArgs(JSContext*, JSObject*, char**, int) (js.cpp:500) ==28877== by 0x40B0AC: main (js.cpp:3967) Is it meaningful?
Comment 20•16 years ago
|
||
filed Bug 449152
Comment 21•16 years ago
|
||
/cvsroot/mozilla/js/tests/js1_5/extensions/regress-435345-01.js,v <-- regress-435345-01.js initial revision: 1.1 mozilla-central: changeset: 16472:7b75a88e0d51
Flags: in-testsuite?
Flags: in-testsuite+
Flags: in-litmus-
Assignee | ||
Comment 22•16 years ago
|
||
As bc correctly reports, we still aren't reporting the "old" watched value correctly for arrays. Faulting to slow-arrays doesn't solve that problem, because even for slow arrays, we often set "length" by accessing the slot directly rather than calling js_SetLengthProperty. This is good for efficiency. However, the penalty we pay for this is that, by the time js_SetLengthProperty /is/ called, the "old value" is usually the same as the new. With the patch attached here: js> a = [ ]; a.watch('length', function (x, a, b) { print(Array.prototype.slice.call(arguments)); return b }); js> a.push(0) length,1,1 1 js> a.push(1) length,2,2 2 js> a.push(2) length,3,3 3 js> a.pop() length,3,2 2 js> a.pop() length,2,1 1 Notice that pop() works correctly, because DeleteArrayElement does not muck with the length notion maintained internal to the array. SetArrayElement eventually calls slowarray_addProperty, however, which /does/ increment the internal length -- all well before the watch is ever invoked. I think we should punt on making this perfect, and leave things as they are. Thoughts?
Updated•16 years ago
|
Flags: wanted1.9.0.x? → wanted1.9.0.x+
Assignee | ||
Comment 23•16 years ago
|
||
No one (shaver or Brendan) ever replied to comment #22? I'd like to hear those thoughts before I push the 1.9.0.2 patch.
Comment 24•16 years ago
|
||
Please a followup bug on what's left in comment 22. What was fixed here, even if incomplete, is progress that we should ship. /be
Assignee | ||
Comment 25•16 years ago
|
||
Landed attachment 329520 [details] [diff] [review] in cvs: Checking in jsarray.c; /cvsroot/mozilla/js/src/jsarray.c,v <-- jsarray.c new revision: 3.178; previous revision: 3.177 done Checking in jsarray.h; /cvsroot/mozilla/js/src/jsarray.h,v <-- jsarray.h new revision: 3.26; previous revision: 3.25 done Checking in jsobj.c; /cvsroot/mozilla/js/src/jsobj.c,v <-- jsobj.c new revision: 3.476; previous revision: 3.475 done
Keywords: fixed1.9.0.2
Assignee | ||
Comment 26•16 years ago
|
||
446634 is the follow-up bug, fwiw.
Comment 27•16 years ago
|
||
verified 1.9.0 modulo errors in bug 446634.
Keywords: fixed1.9.0.2 → verified1.9.0.2
You need to log in
before you can comment on or make changes to this bug.
Description
•