Closed Bug 625141 Opened 15 years ago Closed 15 years ago

JM: incorrect result for test case involving typed arrays

Categories

(Core :: JavaScript Engine, defect)

x86
Windows XP
defect
Not set
normal

Tracking

()

RESOLVED FIXED
Tracking Status
blocking2.0 --- betaN+

People

(Reporter: jandem, Assigned: paul.biggar)

References

Details

(Whiteboard: [hardblocker][fixed-in-tracemonkey][has patch])

Attachments

(1 file, 3 obsolete files)

Consider this test case: --- function f() { var arr = new Int32Array(10); for (var i = 0; i < ({y: function() { return arr.length; }}).y(); i++) { arr[i] = i; } assertEq(arr[5], 5); } f(); --- This fails on 32-bit with -m: Error: Assertion failed: got 0, expected 5
Blocks: Jaeger
blocking2.0: --- → ?
Assignee: general → pbiggar
The general misbehavior here is pretty bad, but it seems that the weird loop condition is required to trigger the bug.
blocking2.0: ? → betaN+
Whiteboard: softblocker
Blocks: 594247
dvander on IRC: probably a good place to look is that the key and RHS are botht he same value, so mayeb some register fiddling edge case is misbehaving
blocking2.0: betaN+ → ?
(In reply to comment #1) > The general misbehavior here is pretty bad, but it seems that the weird loop > condition is required to trigger the bug. I can cause it with a simpler loop condition too: function f() { var arr = new Int32Array(10); function x() { return arr.length; }; for (var i = 0; i < x(); i++) { arr[i] = i; } assertEq(arr[5], 5); } f();
Hrm, simpler loop condition says this should probably still block. Calls flush register state so that's suspicious.
blocking2.0: ? → betaN+
Attached patch WIP (obsolete) — Splinter Review
Patch fixes it, but I think there are larger issues. So the problem seems to be that in the register-swap edge case, we don't restore typereg before address is used, which is bad if typereg is a component of the address. I solved this by restoring the type in time, but I'm not sure about the whole swapping thing. It doesn't look safe here: vr = ValueRemat::FromRegisters(vr.typeReg(), newReg); Why are we swapping the registers anyway? What does that get us?
Attachment #505295 - Flags: feedback?(danderson)
(In reply to comment #4) > Hrm, simpler loop condition says this should probably still block. Dunno how I managed to set the flag back to ?, but I blame bugzilla.
(In reply to comment #5) > So the problem seems to be that in the register-swap edge case, we don't > restore typereg before address is used, which is bad if typereg is a component > of the address. Nice catch. > Why are we swapping the registers anyway? What does that get us? Trying to page this in since this code kind of looks like clownshoes to me now. There are potentially four registers in play: objReg, keyReg (these two form the LHS reference), typeReg, dataReg (these two form the RHS). The following conditions will always be true entering into StoreToTypedArray(): * objReg != any other register (obj[obj] won't IC) * typeReg != any other register (all other regs are payload regs) The RHS might need conversion, in which case we need a register that is free upon leaving the opcode (so we don't clobber anything live). The hard part is if there aren't any, we need to pick one and preserve it. We can't just pick anything, because if it's an Int8Array, we can *only* use (eax, ecx, edx). This is an x86 restriction. We try to grab a register that's not in (objReg, typeReg, keyReg). We can't easily clobber objReg or keyReg, and the conversion process needs typeReg. So if all three of those registers take up the entire class suitable for Int8Array, we're in trouble. The swap trick is because we know typeReg will be in the correct class and dataReg is not. But as you've found, this doesn't correctly handle the case where (keyReg == dataReg). If all that is correct, then I think your patch is correct. We could try to simplify it but it seems like no matter what you need a special case for colliding with the LHS and shuffling. However, it's weird we hit this for the Int32Array case, where there are no register class restrictions. Would be good to fix that here too, all you need to do is change the two places where we restrict ourselves to C-ABI temporary regs. (1) In Compiler::jsop_setelem, volatileMask should *not* start with "& Registers::TempRegs". (2) In StoreToTypedArray, allowMask should start out as AvailRegs, *not* TempRegs.
blocking2.0: betaN+ → ---
OS: Mac OS X → Windows XP
Whiteboard: softblocker → hardblocker
Attachment #505295 - Flags: feedback?(danderson) → feedback+
Looks like the blocking flag got reset accidentally.
blocking2.0: --- → betaN+
Attached patch Tidy up (obsolete) — Splinter Review
THis is as above, except that it has better comments, adds the test and includes the jsop_setelem and allowMask fixes, and folds in some JaegerSpew fixes I did when trying to resolve FIXMEs.
Attachment #505295 - Attachment is obsolete: true
Attachment #507270 - Flags: review?(dvander)
Comment on attachment 507270 [details] [diff] [review] Tidy up > PreserveRegisters saveRHS(masm); >+ PreserveRegisters saveType(masm); Nit: maybe saveLHS? > GenConversionForIntArray(masm, tarray, vr, saveMask); >+ // |GenConversionForIntArray| can overwrite |typeReg|, but >+ // |typeReg| might be a component of |address|. >+ saveType.restore(); Nit: house style wants a newline between the comment and GenConversion Can you include another test case, identical to the first except using Int8Array instead of Int32Array? r=me with that, thanks!
Attachment #507270 - Flags: review?(dvander) → review+
Attached file A proper fix this time (obsolete) —
My fix was broken, in enough ways to make it seem like it was working, and the test you suggested for the 8bit typed arrays picked it up. The behaviour we want is to write the result of GenConversionForIntArray into |address|. So we need to restore all of the components of |address| which we're overwriting. GenConversionForArray stores and restores the registers in saveMask, but it may store the wrong one if we've gone down the register-swapping route. The last patch worked by pure luck. I was trying to save typeReg, but forgot to mask the register, so it was randomly saving ecx - which happened to be the register I needed to save - rather than eax. This patch does it properly. In addition, it doesn't save registers more than once, if the same register is required. (We could be duplicating the saves in saveLHS, saveRHS, and via saveMask). So this is optimal, AFAICT. While working on this patch, I got hit by a few problems: - preserve() accepts unmasked registers. Can we use a bit of strong typing to avoid this? - I pushed and popped in the wrong order. Is there a checking mode where PreserveRegisters or the assembler checks this? Just one more thing: why can vr.typeReg() also be part of the address? Copy propagation?
Attachment #507270 - Attachment is obsolete: true
Attachment #507375 - Flags: review?(dvander)
Whoops, forgot to qrefresh.
Attachment #507375 - Attachment is obsolete: true
Attachment #507377 - Flags: review?(dvander)
Attachment #507375 - Flags: review?(dvander)
Whiteboard: hardblocker → [hardblocker][has patch]
Comment on attachment 507377 [details] [diff] [review] With dvander's suggestions Argh, nice catch. Yeah, maybe in a separate bug we should make a RegisterMask struct or something, since RegisterID implicitly coerces to an integer. > I pushed and popped in the wrong order. Is there a checking mode where PreserveRegisters or the assembler checks this? Nope, not yet.
Attachment #507377 - Flags: review?(dvander) → review+
Whiteboard: [hardblocker][has patch] → [hardblocker][fixed-in-tracemonkey]
Whiteboard: [hardblocker][fixed-in-tracemonkey] → [hardblocker][fixed-in-tracemonkey][has patch]
> asa@mozilla.org: Whiteboard: [hardblocker][fixed-in-tracemonkey] ⇒ [hardblocker][fixed-in-tracemonkey][has patch] I'm not terribly familiar with [has-patch]. Why did we add it back once it was [fixed-in-tracemonkey]?
Paul, I was trying to make easier tracking of the things that are no longer waiting on patches that still need to land in m-c for Firefox 4 beta and final.
(In reply to comment #17) > Paul, I was trying to make easier tracking of the things that are no longer > waiting on patches that still need to land in m-c for Firefox 4 beta and final. Cool, thanks (wasn't a problem - I just didn't know the workflow :) ).
Status: NEW → RESOLVED
Closed: 15 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: