Closed Bug 1131996 Opened 10 years ago Closed 3 years ago

Handle out-of-bounds accesses on lazy arguments better

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
96 Branch
Tracking Status
firefox96 --- fixed

People

(Reporter: jandem, Assigned: anba)

References

(Blocks 2 open bugs)

Details

Attachments

(5 files)

Traceur (see bug 729376) has two functions that look like this:

    eatId_: function() {
      var expected = arguments[0];
      ...
      if (expected)

The first argument is optional. Problem is that our lazy arguments optimization doesn't handle this pattern: if argc == 0, arguments[0] will be out-of-bounds and we call argumentsOptimizationFailed.

I think we should be able to do a pure lookup on the prototype, if we see an indexed property or getter we call argumentsOptimizationFailed, else we can just return undefined.

Note that V8 has a similar issue, but the difference is smaller for them:

SM:

In bounds: 3
Out of bounds: 3985

V8:

In bounds: 13
Out of bounds: 894

function g1() { x1 = arguments[0]; }
function g2() { x2 = arguments[0]; }
var count = 10000000;
function f1() {
    var t = new Date;
    for (var i=0; i<count; i++)
        g1(i);
    print("In bounds:", new Date - t);
}
f1();
function f2() {
    var t = new Date;
    for (var i=0; i<count; i++)
        g2();
    print("Out of bounds:", new Date - t);
}
f2();
Note: for that Traceur benchmark this is not our biggest issue, it costs us ~5% or so but it will be more after we fix the more serious problems. Also fixing this will reduce GC pressure, so the win might be bigger.

And it likely affects more JS code.
Blocks: six-speed
This pattern is actually pretty common, Babel does something like this for a default argument like foo = 1:

  var foo = arguments[0] === undefined ? 1 : arguments[0];

While we could ask them to use arguments.length or something, this seems like a pretty reasonable pattern and I'm sure Traceur and Babel are not the only ones.

Will try to fix this soon.
(In reply to Jan de Mooij [:jandem] from comment #2)
> While we could ask them to use arguments.length or something, this seems
> like a pretty reasonable pattern and I'm sure Traceur and Babel are not the
> only ones.
> 

Note that using arguments.length wouldn't be correct: the default value must be used if the argument is `undefined`, not only if it's really missing.
(In reply to Till Schneidereit [:till] from comment #3)
> Note that using arguments.length wouldn't be correct: the default value must
> be used if the argument is `undefined`, not only if it's really missing.

Ah, fair enough.

They could check arguments.length and *then* check if it's undefined but that's a bit unfortunate.
Luckily they updated Babel and now they check arguments.length first: https://github.com/babel/babel/issues/1845. Hopefully they are going to update six-speed soon.
We should fix this sometime.

Moves ClassCanHaveExtraProperties and CanAttachDenseElementHole in preparation
for the next part

Assignee: nobody → andrebargull
Status: NEW → ASSIGNED

The ELEMENT_OVERRIDDEN_BIT flag is set whenever any element is defined on an
arguments object, irrespective of whether the element is in-bounds or out-of-bounds.
That means that flag can also be used to determine if an arguments object has any
elements besides the frame arguments.

When reading a possible out-of-bounds index, we can therefore use the following
approach:

  1. Fail whenever ELEMENT_OVERRIDDEN_BIT is set.
  2. If the index is in-bounds:
    a. Return the in-bounds element unless it's FORWARD_TO_CALL_SLOT.
  3. Else,
    a. Fail if the index is less than zero.
    b. Return undefined.

Plus a prototype guard check to ensure the element isn't present on any object
of the prototype chain.

Depends on D129619

Transpile the CacheIR operation from part 2.

Depends on D129620

The follows the existing implementations of MGetInlinedArgument and
MGetFrameArgument. There are only two differences:

  1. A bailout occurs when the index is negative. This implies both instructions
    must be guards.
  2. Undefined is returned when the index is larger than the arguments length.

Depends on D129621

Use scoped enums for CanAttachDenseElementHole to improve the readibility
compared to using three plain bool parameters.

Depends on D129622

Pushed by andre.bargull@gmail.com:
https://hg.mozilla.org/integration/autoland/rev/2c8232344e98
Part 1: Move ClassCanHaveExtraProperties and CanAttachDenseElementHole. r=iain
https://hg.mozilla.org/integration/autoland/rev/c31e81d4c5c9
Part 2: Support out-of-bounds read access on arguments objects in CacheIR. r=iain
https://hg.mozilla.org/integration/autoland/rev/cdc0ba4d147b
Part 3: Support out-of-bounds read access on arguments objects in Warp. r=iain
https://hg.mozilla.org/integration/autoland/rev/f7cb0f166402
Part 4: Support scalar replacement for arguments objects with out-of-bounds read access. r=iain
https://hg.mozilla.org/integration/autoland/rev/0cf5997d55ea
Part 5: Use scoped enums for CanAttachDenseElementHole. r=iain
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: