1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Flags: --harmony-proxies --allow-natives-syntax
29
30
31// Helper.
32
33function CreateFrozen(handler, callTrap, constructTrap) {
34  if (handler.fix === undefined) handler.fix = function() { return {} }
35  var f = Proxy.createFunction(handler, callTrap, constructTrap)
36  Object.freeze(f)
37  return f
38}
39
40
41// Ensures that checking the "length" property of a function proxy doesn't
42// crash due to lack of a [[Get]] method.
43var handler = {
44  get : function(r, n) { return n == "length" ? 2 : undefined }
45}
46
47
48// Calling (call, Function.prototype.call, Function.prototype.apply,
49//          Function.prototype.bind).
50
51var global_object = this
52var receiver
53
54function TestCall(isStrict, callTrap) {
55  assertEquals(42, callTrap(5, 37))
56  assertSame(isStrict ? undefined : global_object, receiver)
57
58  var handler = {
59    get: function(r, k) {
60      return k == "length" ? 2 : Function.prototype[k]
61    }
62  }
63  var f = Proxy.createFunction(handler, callTrap)
64  var o = {f: f}
65  global_object.f = f
66
67  receiver = 333
68  assertEquals(42, f(11, 31))
69  assertSame(isStrict ? undefined : global_object, receiver)
70  receiver = 333
71  assertEquals(42, o.f(10, 32))
72  assertSame(o, receiver)
73  receiver = 333
74  assertEquals(42, o["f"](9, 33))
75  assertSame(o, receiver)
76  receiver = 333
77  assertEquals(42, (1, o).f(8, 34))
78  assertSame(o, receiver)
79  receiver = 333
80  assertEquals(42, (1, o)["f"](7, 35))
81  assertSame(o, receiver)
82  receiver = 333
83  assertEquals(42, f.call(o, 32, 10))
84  assertSame(o, receiver)
85  receiver = 333
86  assertEquals(42, f.call(undefined, 33, 9))
87  assertSame(isStrict ? undefined : global_object, receiver)
88  receiver = 333
89  assertEquals(42, f.call(null, 33, 9))
90  assertSame(isStrict ? null : global_object, receiver)
91  receiver = 333
92  assertEquals(44, f.call(2, 21, 23))
93  assertSame(2, receiver.valueOf())
94  receiver = 333
95  assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
96  assertSame(o, receiver)
97  receiver = 333
98  assertEquals(43, Function.prototype.call.call(f, null, 20, 23))
99  assertSame(isStrict ? null : global_object, receiver)
100  assertEquals(44, Function.prototype.call.call(f, 2, 21, 23))
101  assertEquals(2, receiver.valueOf())
102  receiver = 333
103  assertEquals(32, f.apply(o, [16, 16]))
104  assertSame(o, receiver)
105  receiver = 333
106  assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
107  assertSame(o, receiver)
108  receiver = 333
109  assertEquals(42, %Call(o, 11, 31, f))
110  assertSame(o, receiver)
111  receiver = 333
112  assertEquals(42, %Call(null, 11, 31, f))
113  assertSame(isStrict ? null : global_object, receiver)
114  receiver = 333
115  assertEquals(42, %Apply(f, o, [11, 31], 0, 2))
116  assertSame(o, receiver)
117  receiver = 333
118  assertEquals(42, %Apply(f, null, [11, 31], 0, 2))
119  assertSame(isStrict ? null : global_object, receiver)
120  receiver = 333
121  assertEquals(42, %_CallFunction(o, 11, 31, f))
122  assertSame(o, receiver)
123  receiver = 333
124  assertEquals(42, %_CallFunction(null, 11, 31, f))
125  assertSame(isStrict ? null : global_object, receiver)
126
127  var ff = Function.prototype.bind.call(f, o, 12)
128  assertTrue(ff.length <= 1)  // TODO(rossberg): Not spec'ed yet, be lax.
129  receiver = 333
130  assertEquals(42, ff(30))
131  assertSame(o, receiver)
132  receiver = 333
133  assertEquals(33, Function.prototype.call.call(ff, {}, 21))
134  assertSame(o, receiver)
135  receiver = 333
136  assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
137  assertSame(o, receiver)
138  receiver = 333
139  assertEquals(23, %Call({}, 11, ff))
140  assertSame(o, receiver)
141  receiver = 333
142  assertEquals(23, %Call({}, 11, 3, ff))
143  assertSame(o, receiver)
144  receiver = 333
145  assertEquals(24, %Apply(ff, {}, [12, 13], 0, 1))
146  assertSame(o, receiver)
147  receiver = 333
148  assertEquals(24, %Apply(ff, {}, [12, 13], 0, 2))
149  assertSame(o, receiver)
150  receiver = 333
151  assertEquals(34, %_CallFunction({}, 22, ff))
152  assertSame(o, receiver)
153  receiver = 333
154  assertEquals(34, %_CallFunction({}, 22, 3, ff))
155  assertSame(o, receiver)
156
157  var fff = Function.prototype.bind.call(ff, o, 30)
158  assertEquals(0, fff.length)
159  receiver = 333
160  assertEquals(42, fff())
161  assertSame(o, receiver)
162  receiver = 333
163  assertEquals(42, Function.prototype.call.call(fff, {}))
164  assertSame(o, receiver)
165  receiver = 333
166  assertEquals(42, Function.prototype.apply.call(fff, {}))
167  assertSame(o, receiver)
168  receiver = 333
169  assertEquals(42, %Call({}, fff))
170  assertSame(o, receiver)
171  receiver = 333
172  assertEquals(42, %Call({}, 11, 3, fff))
173  assertSame(o, receiver)
174  receiver = 333
175  assertEquals(42, %Apply(fff, {}, [], 0, 0))
176  assertSame(o, receiver)
177  receiver = 333
178  assertEquals(42, %Apply(fff, {}, [12, 13], 0, 0))
179  assertSame(o, receiver)
180  receiver = 333
181  assertEquals(42, %Apply(fff, {}, [12, 13], 0, 2))
182  assertSame(o, receiver)
183  receiver = 333
184  assertEquals(42, %_CallFunction({}, fff))
185  assertSame(o, receiver)
186  receiver = 333
187  assertEquals(42, %_CallFunction({}, 3, 4, 5, fff))
188  assertSame(o, receiver)
189
190  var f = CreateFrozen({}, callTrap)
191  receiver = 333
192  assertEquals(42, f(11, 31))
193  assertSame(isStrict ? undefined : global_object, receiver)
194  var o = {f: f}
195  receiver = 333
196  assertEquals(42, o.f(10, 32))
197  assertSame(o, receiver)
198  receiver = 333
199  assertEquals(42, o["f"](9, 33))
200  assertSame(o, receiver)
201  receiver = 333
202  assertEquals(42, (1, o).f(8, 34))
203  assertSame(o, receiver)
204  receiver = 333
205  assertEquals(42, (1, o)["f"](7, 35))
206  assertSame(o, receiver)
207  receiver = 333
208  assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
209  assertSame(o, receiver)
210  receiver = 333
211  assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
212  assertSame(o, receiver)
213  receiver = 333
214  assertEquals(23, %Call(o, 11, 12, f))
215  assertSame(o, receiver)
216  receiver = 333
217  assertEquals(27, %Apply(f, o, [12, 13, 14], 1, 2))
218  assertSame(o, receiver)
219  receiver = 333
220  assertEquals(42, %_CallFunction(o, 18, 24, f))
221  assertSame(o, receiver)
222}
223
224TestCall(false, function(x, y) {
225  receiver = this
226  return x + y
227})
228
229TestCall(true, function(x, y) {
230  "use strict"
231  receiver = this
232  return x + y
233})
234
235TestCall(false, function() {
236  receiver = this
237  return arguments[0] + arguments[1]
238})
239
240TestCall(false, Proxy.createFunction(handler, function(x, y) {
241  receiver = this
242  return x + y
243}))
244
245TestCall(true, Proxy.createFunction(handler, function(x, y) {
246  "use strict"
247  receiver = this
248  return x + y
249}))
250
251TestCall(false, CreateFrozen(handler, function(x, y) {
252  receiver = this
253  return x + y
254}))
255
256
257
258// Using intrinsics as call traps.
259
260function TestCallIntrinsic(type, callTrap) {
261  var f = Proxy.createFunction({}, callTrap)
262  var x = f()
263  assertTrue(typeof x == type)
264}
265
266TestCallIntrinsic("boolean", Boolean)
267TestCallIntrinsic("number", Number)
268TestCallIntrinsic("string", String)
269TestCallIntrinsic("object", Object)
270TestCallIntrinsic("function", Function)
271
272
273
274// Throwing from call trap.
275
276function TestCallThrow(callTrap) {
277  var f = Proxy.createFunction({}, callTrap)
278  assertThrows(function(){ f(11) }, "myexn")
279  assertThrows(function(){ ({x: f}).x(11) }, "myexn")
280  assertThrows(function(){ ({x: f})["x"](11) }, "myexn")
281  assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
282  assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
283  assertThrows(function(){ %Call({}, f) }, "myexn")
284  assertThrows(function(){ %Call({}, 1, 2, f) }, "myexn")
285  assertThrows(function(){ %Apply({}, f, [], 3, 0) }, "myexn")
286  assertThrows(function(){ %Apply({}, f, [3, 4], 0, 1) }, "myexn")
287  assertThrows(function(){ %_CallFunction({}, f) }, "myexn")
288  assertThrows(function(){ %_CallFunction({}, 1, 2, f) }, "myexn")
289
290  var f = CreateFrozen({}, callTrap)
291  assertThrows(function(){ f(11) }, "myexn")
292  assertThrows(function(){ ({x: f}).x(11) }, "myexn")
293  assertThrows(function(){ ({x: f})["x"](11) }, "myexn")
294  assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
295  assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
296  assertThrows(function(){ %Call({}, f) }, "myexn")
297  assertThrows(function(){ %Call({}, 1, 2, f) }, "myexn")
298  assertThrows(function(){ %Apply({}, f, [], 3, 0) }, "myexn")
299  assertThrows(function(){ %Apply({}, f, [3, 4], 0, 1) }, "myexn")
300  assertThrows(function(){ %_CallFunction({}, f) }, "myexn")
301  assertThrows(function(){ %_CallFunction({}, 1, 2, f) }, "myexn")
302}
303
304TestCallThrow(function() { throw "myexn" })
305TestCallThrow(Proxy.createFunction({}, function() { throw "myexn" }))
306TestCallThrow(CreateFrozen({}, function() { throw "myexn" }))
307
308
309
310// Construction (new).
311
312var prototype = {myprop: 0}
313var receiver
314
315var handlerWithPrototype = {
316  fix: function() { return { prototype: { value: prototype } }; },
317  get: function(r, n) {
318    if (n == "length") return 2;
319    assertEquals("prototype", n);
320    return prototype;
321  }
322}
323
324var handlerSansPrototype = {
325  fix: function() { return { length: { value: 2 } } },
326  get: function(r, n) {
327    if (n == "length") return 2;
328    assertEquals("prototype", n);
329    return undefined;
330  }
331}
332
333function ReturnUndef(x, y) {
334  "use strict";
335  receiver = this;
336  this.sum = x + y;
337}
338
339function ReturnThis(x, y) {
340  "use strict";
341  receiver = this;
342  this.sum = x + y;
343  return this;
344}
345
346function ReturnNew(x, y) {
347  "use strict";
348  receiver = this;
349  return {sum: x + y};
350}
351
352function ReturnNewWithProto(x, y) {
353  "use strict";
354  receiver = this;
355  var result = Object.create(prototype);
356  result.sum = x + y;
357  return result;
358}
359
360function TestConstruct(proto, constructTrap) {
361  TestConstruct2(proto, constructTrap, handlerWithPrototype)
362  TestConstruct2(proto, constructTrap, handlerSansPrototype)
363}
364
365function TestConstruct2(proto, constructTrap, handler) {
366  var f = Proxy.createFunction(handler, function() {}, constructTrap)
367  var o = new f(11, 31)
368  assertEquals(undefined, receiver)
369  assertEquals(42, o.sum)
370  assertSame(proto, Object.getPrototypeOf(o))
371
372  var f = CreateFrozen(handler, function() {}, constructTrap)
373  var o = new f(11, 32)
374  assertEquals(undefined, receiver)
375  assertEquals(43, o.sum)
376  assertSame(proto, Object.getPrototypeOf(o))
377}
378
379TestConstruct(Object.prototype, ReturnNew)
380TestConstruct(prototype, ReturnNewWithProto)
381
382TestConstruct(Object.prototype, Proxy.createFunction(handler, ReturnNew))
383TestConstruct(prototype, Proxy.createFunction(handler, ReturnNewWithProto))
384
385TestConstruct(Object.prototype, CreateFrozen(handler, ReturnNew))
386TestConstruct(prototype, CreateFrozen(handler, ReturnNewWithProto))
387
388
389
390// Construction with derived construct trap.
391
392function TestConstructFromCall(proto, returnsThis, callTrap) {
393  TestConstructFromCall2(prototype, returnsThis, callTrap, handlerWithPrototype)
394  TestConstructFromCall2(proto, returnsThis, callTrap, handlerSansPrototype)
395}
396
397function TestConstructFromCall2(proto, returnsThis, callTrap, handler) {
398  // TODO(rossberg): handling of prototype for derived construct trap will be
399  // fixed in a separate change. Commenting out checks below for now.
400  var f = Proxy.createFunction(handler, callTrap)
401  var o = new f(11, 31)
402  if (returnsThis) assertEquals(o, receiver)
403  assertEquals(42, o.sum)
404  // assertSame(proto, Object.getPrototypeOf(o))
405
406  var g = CreateFrozen(handler, callTrap)
407  // assertSame(f.prototype, g.prototype)
408  var o = new g(11, 32)
409  if (returnsThis) assertEquals(o, receiver)
410  assertEquals(43, o.sum)
411  // assertSame(proto, Object.getPrototypeOf(o))
412}
413
414TestConstructFromCall(Object.prototype, true, ReturnUndef)
415TestConstructFromCall(Object.prototype, true, ReturnThis)
416TestConstructFromCall(Object.prototype, false, ReturnNew)
417TestConstructFromCall(prototype, false, ReturnNewWithProto)
418
419TestConstructFromCall(Object.prototype, true,
420                      Proxy.createFunction(handler, ReturnUndef))
421TestConstructFromCall(Object.prototype, true,
422                      Proxy.createFunction(handler, ReturnThis))
423TestConstructFromCall(Object.prototype, false,
424                      Proxy.createFunction(handler, ReturnNew))
425TestConstructFromCall(prototype, false,
426                      Proxy.createFunction(handler, ReturnNewWithProto))
427
428TestConstructFromCall(Object.prototype, true, CreateFrozen({}, ReturnUndef))
429TestConstructFromCall(Object.prototype, true, CreateFrozen({}, ReturnThis))
430TestConstructFromCall(Object.prototype, false, CreateFrozen({}, ReturnNew))
431TestConstructFromCall(prototype, false, CreateFrozen({}, ReturnNewWithProto))
432
433ReturnUndef.prototype = prototype
434ReturnThis.prototype = prototype
435ReturnNew.prototype = prototype
436ReturnNewWithProto.prototype = prototype
437
438TestConstructFromCall(prototype, true, ReturnUndef)
439TestConstructFromCall(prototype, true, ReturnThis)
440TestConstructFromCall(Object.prototype, false, ReturnNew)
441TestConstructFromCall(prototype, false, ReturnNewWithProto)
442
443TestConstructFromCall(Object.prototype, true,
444                      Proxy.createFunction(handler, ReturnUndef))
445TestConstructFromCall(Object.prototype, true,
446                      Proxy.createFunction(handler, ReturnThis))
447TestConstructFromCall(Object.prototype, false,
448                      Proxy.createFunction(handler, ReturnNew))
449TestConstructFromCall(prototype, false,
450                      Proxy.createFunction(handler, ReturnNewWithProto))
451
452TestConstructFromCall(prototype, true,
453                      Proxy.createFunction(handlerWithPrototype, ReturnUndef))
454TestConstructFromCall(prototype, true,
455                      Proxy.createFunction(handlerWithPrototype, ReturnThis))
456TestConstructFromCall(Object.prototype, false,
457                      Proxy.createFunction(handlerWithPrototype, ReturnNew))
458TestConstructFromCall(prototype, false,
459                      Proxy.createFunction(handlerWithPrototype,
460                                           ReturnNewWithProto))
461
462TestConstructFromCall(prototype, true,
463                      CreateFrozen(handlerWithPrototype, ReturnUndef))
464TestConstructFromCall(prototype, true,
465                      CreateFrozen(handlerWithPrototype, ReturnThis))
466TestConstructFromCall(Object.prototype, false,
467                      CreateFrozen(handlerWithPrototype, ReturnNew))
468TestConstructFromCall(prototype, false,
469                      CreateFrozen(handlerWithPrototype, ReturnNewWithProto))
470
471
472
473// Throwing from the construct trap.
474
475function TestConstructThrow(trap) {
476  TestConstructThrow2(Proxy.createFunction({ fix: function() {return {};} },
477                                           trap))
478  TestConstructThrow2(Proxy.createFunction({ fix: function() {return {};} },
479                                           function() {},
480                                           trap))
481}
482
483function TestConstructThrow2(f) {
484  assertThrows(function(){ new f(11) }, "myexn")
485  Object.freeze(f)
486  assertThrows(function(){ new f(11) }, "myexn")
487}
488
489TestConstructThrow(function() { throw "myexn" })
490TestConstructThrow(Proxy.createFunction({}, function() { throw "myexn" }))
491TestConstructThrow(CreateFrozen({}, function() { throw "myexn" }))
492
493
494
495// Using function proxies as getters and setters.
496
497var value
498var receiver
499
500function TestAccessorCall(getterCallTrap, setterCallTrap) {
501  var handler = { fix: function() { return {} } }
502  var pgetter = Proxy.createFunction(handler, getterCallTrap)
503  var psetter = Proxy.createFunction(handler, setterCallTrap)
504
505  var o = {}
506  var oo = Object.create(o)
507  Object.defineProperty(o, "a", {get: pgetter, set: psetter})
508  Object.defineProperty(o, "b", {get: pgetter})
509  Object.defineProperty(o, "c", {set: psetter})
510  Object.defineProperty(o, "3", {get: pgetter, set: psetter})
511  Object.defineProperty(oo, "a", {value: 43})
512
513  receiver = ""
514  assertEquals(42, o.a)
515  assertSame(o, receiver)
516  receiver = ""
517  assertEquals(42, o.b)
518  assertSame(o, receiver)
519  receiver = ""
520  assertEquals(undefined, o.c)
521  assertEquals("", receiver)
522  receiver = ""
523  assertEquals(42, o["a"])
524  assertSame(o, receiver)
525  receiver = ""
526  assertEquals(42, o[3])
527  assertSame(o, receiver)
528
529  receiver = ""
530  assertEquals(43, oo.a)
531  assertEquals("", receiver)
532  receiver = ""
533  assertEquals(42, oo.b)
534  assertSame(oo, receiver)
535  receiver = ""
536  assertEquals(undefined, oo.c)
537  assertEquals("", receiver)
538  receiver = ""
539  assertEquals(43, oo["a"])
540  assertEquals("", receiver)
541  receiver = ""
542  assertEquals(42, oo[3])
543  assertSame(oo, receiver)
544
545  receiver = ""
546  assertEquals(50, o.a = 50)
547  assertSame(o, receiver)
548  assertEquals(50, value)
549  receiver = ""
550  assertEquals(51, o.b = 51)
551  assertEquals("", receiver)
552  assertEquals(50, value)  // no setter
553  assertThrows(function() { "use strict"; o.b = 51 }, TypeError)
554  receiver = ""
555  assertEquals(52, o.c = 52)
556  assertSame(o, receiver)
557  assertEquals(52, value)
558  receiver = ""
559  assertEquals(53, o["a"] = 53)
560  assertSame(o, receiver)
561  assertEquals(53, value)
562  receiver = ""
563  assertEquals(54, o[3] = 54)
564  assertSame(o, receiver)
565  assertEquals(54, value)
566
567  value = 0
568  receiver = ""
569  assertEquals(60, oo.a = 60)
570  assertEquals("", receiver)
571  assertEquals(0, value)  // oo has own 'a'
572  assertEquals(61, oo.b = 61)
573  assertSame("", receiver)
574  assertEquals(0, value)  // no setter
575  assertThrows(function() { "use strict"; oo.b = 61 }, TypeError)
576  receiver = ""
577  assertEquals(62, oo.c = 62)
578  assertSame(oo, receiver)
579  assertEquals(62, value)
580  receiver = ""
581  assertEquals(63, oo["c"] = 63)
582  assertSame(oo, receiver)
583  assertEquals(63, value)
584  receiver = ""
585  assertEquals(64, oo[3] = 64)
586  assertSame(oo, receiver)
587  assertEquals(64, value)
588}
589
590TestAccessorCall(
591  function() { receiver = this; return 42 },
592  function(x) { receiver = this; value = x }
593)
594
595TestAccessorCall(
596  function() { "use strict"; receiver = this; return 42 },
597  function(x) { "use strict"; receiver = this; value = x }
598)
599
600TestAccessorCall(
601  Proxy.createFunction({}, function() { receiver = this; return 42 }),
602  Proxy.createFunction({}, function(x) { receiver = this; value = x })
603)
604
605TestAccessorCall(
606  CreateFrozen({}, function() { receiver = this; return 42 }),
607  CreateFrozen({}, function(x) { receiver = this; value = x })
608)
609
610
611
612// Passing a proxy function to higher-order library functions.
613
614function TestHigherOrder(f) {
615  assertEquals(6, [6, 2].map(f)[0])
616  assertEquals(4, [5, 2].reduce(f, 4))
617  assertTrue([1, 2].some(f))
618  assertEquals("a.b.c", "a.b.c".replace(".", f))
619}
620
621TestHigherOrder(function(x) { return x })
622TestHigherOrder(function(x) { "use strict"; return x })
623TestHigherOrder(Proxy.createFunction({}, function(x) { return x }))
624TestHigherOrder(CreateFrozen({}, function(x) { return x }))
625
626
627
628// TODO(rossberg): Ultimately, I want to have the following test function
629// run through, but it currently fails on so many cases (some not even
630// involving proxies), that I leave that for later...
631/*
632function TestCalls() {
633  var handler = {
634    get: function(r, k) {
635      return k == "length" ? 2 : Function.prototype[k]
636    }
637  }
638  var bind = Function.prototype.bind
639  var o = {}
640
641  var traps = [
642    function(x, y) {
643      return {receiver: this, result: x + y, strict: false}
644    },
645    function(x, y) { "use strict";
646      return {receiver: this, result: x + y, strict: true}
647    },
648    function() {
649      var x = arguments[0], y = arguments[1]
650      return {receiver: this, result: x + y, strict: false}
651    },
652    Proxy.createFunction(handler, function(x, y) {
653      return {receiver: this, result: x + y, strict: false}
654    }),
655    Proxy.createFunction(handler, function() {
656      var x = arguments[0], y = arguments[1]
657      return {receiver: this, result: x + y, strict: false}
658    }),
659    Proxy.createFunction(handler, function(x, y) { "use strict"
660      return {receiver: this, result: x + y, strict: true}
661    }),
662    CreateFrozen(handler, function(x, y) {
663      return {receiver: this, result: x + y, strict: false}
664    }),
665    CreateFrozen(handler, function(x, y) { "use strict"
666      return {receiver: this, result: x + y, strict: true}
667    }),
668  ]
669  var creates = [
670    function(trap) { return trap },
671    function(trap) { return CreateFrozen({}, callTrap) },
672    function(trap) { return Proxy.createFunction(handler, callTrap) },
673    function(trap) {
674      return Proxy.createFunction(handler, CreateFrozen({}, callTrap))
675    },
676    function(trap) {
677      return Proxy.createFunction(handler, Proxy.createFunction(handler, callTrap))
678    },
679  ]
680  var binds = [
681    function(f, o, x, y) { return f },
682    function(f, o, x, y) { return bind.call(f, o) },
683    function(f, o, x, y) { return bind.call(f, o, x) },
684    function(f, o, x, y) { return bind.call(f, o, x, y) },
685    function(f, o, x, y) { return bind.call(f, o, x, y, 5) },
686    function(f, o, x, y) { return bind.call(bind.call(f, o), {}, x, y) },
687    function(f, o, x, y) { return bind.call(bind.call(f, o, x), {}, y) },
688    function(f, o, x, y) { return bind.call(bind.call(f, o, x, y), {}, 5) },
689  ]
690  var calls = [
691    function(f, x, y) { return f(x, y) },
692    function(f, x, y) { var g = f; return g(x, y) },
693    function(f, x, y) { with ({}) return f(x, y) },
694    function(f, x, y) { var g = f; with ({}) return g(x, y) },
695    function(f, x, y, o) { with (o) return f(x, y) },
696    function(f, x, y, o) { return f.call(o, x, y) },
697    function(f, x, y, o) { return f.apply(o, [x, y]) },
698    function(f, x, y, o) { return Function.prototype.call.call(f, o, x, y) },
699    function(f, x, y, o) { return Function.prototype.apply.call(f, o, [x, y]) },
700    function(f, x, y, o) { return %_CallFunction(o, x, y, f) },
701    function(f, x, y, o) { return %Call(o, x, y, f) },
702    function(f, x, y, o) { return %Apply(f, o, [null, x, y, null], 1, 2) },
703    function(f, x, y, o) { return %Apply(f, o, arguments, 2, 2) },
704    function(f, x, y, o) { if (typeof o == "object") return o.f(x, y) },
705    function(f, x, y, o) { if (typeof o == "object") return o["f"](x, y) },
706    function(f, x, y, o) { if (typeof o == "object") return (1, o).f(x, y) },
707    function(f, x, y, o) { if (typeof o == "object") return (1, o)["f"](x, y) },
708  ]
709  var receivers = [o, global_object, undefined, null, 2, "bla", true]
710  var expectedSloppies = [o, global_object, global_object, global_object]
711
712  for (var t = 0; t < traps.length; ++t) {
713    for (var i = 0; i < creates.length; ++i) {
714      for (var j = 0; j < binds.length; ++j) {
715        for (var k = 0; k < calls.length; ++k) {
716          for (var m = 0; m < receivers.length; ++m) {
717            for (var n = 0; n < receivers.length; ++n) {
718              var bound = receivers[m]
719              var receiver = receivers[n]
720              var func = binds[j](creates[i](traps[t]), bound, 31, 11)
721              var expected = j > 0 ? bound : receiver
722              var expectedSloppy = expectedSloppies[j > 0 ? m : n]
723              o.f = func
724              global_object.f = func
725              var x = calls[k](func, 11, 31, receiver)
726              if (x !== undefined) {
727                assertEquals(42, x.result)
728                if (calls[k].length < 4)
729                  assertSame(x.strict ? undefined : global_object, x.receiver)
730                else if (x.strict)
731                  assertSame(expected, x.receiver)
732                else if (expectedSloppy === undefined)
733                  assertSame(expected, x.receiver.valueOf())
734                else
735                  assertSame(expectedSloppy, x.receiver)
736              }
737            }
738          }
739        }
740      }
741    }
742  }
743}
744
745TestCalls()
746*/
747
748var realms = [Realm.create(), Realm.create()];
749Realm.shared = {};
750
751Realm.eval(realms[0], "function f() { return this; };");
752Realm.eval(realms[0], "Realm.shared.f = f;");
753Realm.eval(realms[0], "Realm.shared.fg = this;");
754Realm.eval(realms[1], "function g() { return this; };");
755Realm.eval(realms[1], "Realm.shared.g = g;");
756Realm.eval(realms[1], "Realm.shared.gg = this;");
757
758var fp = Proxy.createFunction({}, Realm.shared.f);
759var gp = Proxy.createFunction({}, Realm.shared.g);
760
761for (var i = 0; i < 10; i++) {
762  assertEquals(Realm.shared.fg, fp());
763  assertEquals(Realm.shared.gg, gp());
764
765  with (this) {
766    assertEquals(this, fp());
767    assertEquals(this, gp());
768  }
769
770  with ({}) {
771    assertEquals(Realm.shared.fg, fp());
772    assertEquals(Realm.shared.gg, gp());
773  }
774}
775