Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / tests / js1_8_5 / regress / regress-577648-1.js
1 /*
2  * Any copyright is dedicated to the Public Domain.
3  * http://creativecommons.org/licenses/publicdomain/
4  */
5
6 var count = 0;
7
8 function testCaller(obj) {
9     switch (++count) {
10       case 1:
11       case 2:
12         /*
13          * The first two times, obj is objA. The first time, we reference
14          * arguments.callee.caller before obj.go, so the caller getter must
15          * force the joined function object in the stack frame to cross the
16          * method read barrier. The second time, obj.go has been cloned and
17          * it should match the new frame's callee from the get-go.
18          */
19         assertEq(obj, objA);
20         break;
21
22       case 3: {
23         assertEq(obj, objB);
24
25         /*
26          * Store another clone of the joined function object before obj.go has
27          * been read, but after it has been invoked via objB.go(objB).
28          *
29          * In this case, arguments.callee.caller must not lie and return what
30          * is currently stored in objB.go, since that function object (objA.go)
31          * was cloned earlier, when count was 1, and it is not the function
32          * object that was truly invoked.
33          *
34          * But since the invocation of objB.go(objB) did not clone go, and the
35          * following assignment overwrote the invoked value, leaving the only
36          * reference to the joined function object for go in the stack frame's
37          * callee (argv[-2]) member, the arguments.callee.caller reference must
38          * clone a function object for the callee, store it as the callee, and
39          * return it here.
40          *
41          * It won't equal obj.go, but (implementation detail) it should have
42          * the same proto as obj.go
43          */
44         obj.go = objA.go;
45
46         let caller = arguments.callee.caller;
47         let obj_go = obj.go;
48         return caller != obj_go && caller.__proto__ == obj_go.__proto__;
49       }
50
51       case 4: {
52         assertEq(obj, objC);
53
54         let save = obj.go;
55         delete obj.go;
56         return arguments.callee.caller == save;
57       }
58
59       case 5: {
60         assertEq(obj, objD);
61
62         let read = obj.go;
63         break;
64       }
65     }
66
67     return arguments.callee.caller == obj.go;
68 }
69
70 function make() {
71     return {
72         go: function(obj) {
73             return testCaller(obj);
74         }
75     };
76 }
77
78 var objA = make(),
79     objB = make(),
80     objC = make(),
81     objD = make();
82
83 reportCompare(true, objA.go(objA), "1");
84 reportCompare(true, objA.go(objA), "2");
85 reportCompare(true, objB.go(objB), "3");
86 reportCompare(true, objC.go(objC), "4");
87 reportCompare(true, objD.go(objD), "5");