js/src/tests/js1_8_5/regress/regress-577648-1.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/tests/js1_8_5/regress/regress-577648-1.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,87 @@
     1.4 +/*
     1.5 + * Any copyright is dedicated to the Public Domain.
     1.6 + * http://creativecommons.org/licenses/publicdomain/
     1.7 + */
     1.8 +
     1.9 +var count = 0;
    1.10 +
    1.11 +function testCaller(obj) {
    1.12 +    switch (++count) {
    1.13 +      case 1:
    1.14 +      case 2:
    1.15 +        /*
    1.16 +         * The first two times, obj is objA. The first time, we reference
    1.17 +         * arguments.callee.caller before obj.go, so the caller getter must
    1.18 +         * force the joined function object in the stack frame to cross the
    1.19 +         * method read barrier. The second time, obj.go has been cloned and
    1.20 +         * it should match the new frame's callee from the get-go.
    1.21 +         */
    1.22 +        assertEq(obj, objA);
    1.23 +        break;
    1.24 +
    1.25 +      case 3: {
    1.26 +        assertEq(obj, objB);
    1.27 +
    1.28 +        /*
    1.29 +         * Store another clone of the joined function object before obj.go has
    1.30 +         * been read, but after it has been invoked via objB.go(objB).
    1.31 +         *
    1.32 +         * In this case, arguments.callee.caller must not lie and return what
    1.33 +         * is currently stored in objB.go, since that function object (objA.go)
    1.34 +         * was cloned earlier, when count was 1, and it is not the function
    1.35 +         * object that was truly invoked.
    1.36 +         *
    1.37 +         * But since the invocation of objB.go(objB) did not clone go, and the
    1.38 +         * following assignment overwrote the invoked value, leaving the only
    1.39 +         * reference to the joined function object for go in the stack frame's
    1.40 +         * callee (argv[-2]) member, the arguments.callee.caller reference must
    1.41 +         * clone a function object for the callee, store it as the callee, and
    1.42 +         * return it here.
    1.43 +         *
    1.44 +         * It won't equal obj.go, but (implementation detail) it should have
    1.45 +         * the same proto as obj.go
    1.46 +         */
    1.47 +        obj.go = objA.go;
    1.48 +
    1.49 +        let caller = arguments.callee.caller;
    1.50 +        let obj_go = obj.go;
    1.51 +        return caller != obj_go && caller.__proto__ == obj_go.__proto__;
    1.52 +      }
    1.53 +
    1.54 +      case 4: {
    1.55 +        assertEq(obj, objC);
    1.56 +
    1.57 +        let save = obj.go;
    1.58 +        delete obj.go;
    1.59 +        return arguments.callee.caller == save;
    1.60 +      }
    1.61 +
    1.62 +      case 5: {
    1.63 +        assertEq(obj, objD);
    1.64 +
    1.65 +        let read = obj.go;
    1.66 +        break;
    1.67 +      }
    1.68 +    }
    1.69 +
    1.70 +    return arguments.callee.caller == obj.go;
    1.71 +}
    1.72 +
    1.73 +function make() {
    1.74 +    return {
    1.75 +        go: function(obj) {
    1.76 +            return testCaller(obj);
    1.77 +        }
    1.78 +    };
    1.79 +}
    1.80 +
    1.81 +var objA = make(),
    1.82 +    objB = make(),
    1.83 +    objC = make(),
    1.84 +    objD = make();
    1.85 +
    1.86 +reportCompare(true, objA.go(objA), "1");
    1.87 +reportCompare(true, objA.go(objA), "2");
    1.88 +reportCompare(true, objB.go(objB), "3");
    1.89 +reportCompare(true, objC.go(objC), "4");
    1.90 +reportCompare(true, objD.go(objD), "5");

mercurial