Home | History | Annotate | Download | only in es6
      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 // We change the stack size for the ARM64 simulator because at one point this
     29 // test enters an infinite recursion which goes through the runtime and we
     30 // overflow the system stack before the simulator stack.
     31 
     32 // Flags: --sim-stack-size=500 --allow-natives-syntax
     33 
     34 
     35 // Helper.
     36 
     37 function TestWithProxies(test, x, y, z) {
     38   // Separate function for nicer stack traces.
     39   TestWithObjectProxy(test, x, y, z);
     40   TestWithFunctionProxy(test, x, y, z);
     41 }
     42 
     43 function TestWithObjectProxy(test, x, y, z) {
     44   test((handler) => { return new Proxy({}, handler) }, x, y, z)
     45 
     46 }
     47 
     48 function TestWithFunctionProxy(test, x, y, z) {
     49   test((handler) => { return new Proxy(() => {}, handler) }, x, y, z)
     50 }
     51 
     52 // ---------------------------------------------------------------------------
     53 // Getting property descriptors (Object.getOwnPropertyDescriptor).
     54 
     55 var key
     56 
     57 function TestGetOwnProperty(handler) {
     58   TestWithProxies(TestGetOwnProperty2, handler)
     59 }
     60 
     61 function TestGetOwnProperty2(create, handler) {
     62   var p = create(handler)
     63   assertEquals(42, Object.getOwnPropertyDescriptor(p, "a").value)
     64   assertEquals("a", key)
     65   assertEquals(42, Object.getOwnPropertyDescriptor(p, 99).value)
     66   assertEquals("99", key)
     67 }
     68 
     69 TestGetOwnProperty({
     70   getOwnPropertyDescriptor(target, k) {
     71     key = k
     72     return {value: 42, configurable: true}
     73   }
     74 })
     75 
     76 TestGetOwnProperty({
     77   getOwnPropertyDescriptor(target, k) {
     78     return this.getOwnPropertyDescriptor2(k)
     79   },
     80   getOwnPropertyDescriptor2(k) {
     81     key = k
     82     return {value: 42, configurable: true}
     83   }
     84 })
     85 
     86 TestGetOwnProperty({
     87   getOwnPropertyDescriptor(target, k) {
     88     key = k
     89     return {get value() { return 42 }, get configurable() { return true }}
     90   }
     91 })
     92 
     93 TestGetOwnProperty(new Proxy({}, {
     94   get(target, pk, receiver) {
     95     return function(t, k) { key = k; return {value: 42, configurable: true} }
     96   }
     97 }))
     98 
     99 
    100 // ---------------------------------------------------------------------------
    101 function TestGetOwnPropertyThrow(handler) {
    102   TestWithProxies(TestGetOwnPropertyThrow2, handler)
    103 }
    104 
    105 function TestGetOwnPropertyThrow2(create, handler) {
    106   var p = create(handler)
    107   assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, "a"), "myexn")
    108   assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, 77), "myexn")
    109 }
    110 
    111 TestGetOwnPropertyThrow({
    112   getOwnPropertyDescriptor: function(k) { throw "myexn" }
    113 })
    114 
    115 TestGetOwnPropertyThrow({
    116   getOwnPropertyDescriptor: function(k) {
    117     return this.getOwnPropertyDescriptor2(k)
    118   },
    119   getOwnPropertyDescriptor2: function(k) { throw "myexn" }
    120 })
    121 
    122 TestGetOwnPropertyThrow({
    123   getOwnPropertyDescriptor: function(k) {
    124     return {get value() { throw "myexn" }}
    125   }
    126 })
    127 
    128 TestGetOwnPropertyThrow(new Proxy({}, {
    129   get: function(pr, pk) {
    130     return function(k) { throw "myexn" }
    131   }
    132 }))
    133 
    134 
    135 // ---------------------------------------------------------------------------
    136 // Getters (dot, brackets).
    137 
    138 var key
    139 
    140 function TestGet(handler) {
    141   TestWithProxies(TestGet2, handler)
    142 }
    143 
    144 function TestGet2(create, handler) {
    145   var p = create(handler)
    146   assertEquals(42, p.a)
    147   assertEquals("a", key)
    148   assertEquals(42, p["b"])
    149   assertEquals("b", key)
    150   assertEquals(42, p[99])
    151   assertEquals("99", key)
    152   assertEquals(42, (function(n) { return p[n] })("c"))
    153   assertEquals("c", key)
    154   assertEquals(42, (function(n) { return p[n] })(101))
    155   assertEquals("101", key)
    156 
    157   var o = Object.create(p, {x: {value: 88}})
    158   assertEquals(42, o.a)
    159   assertEquals("a", key)
    160   assertEquals(42, o["b"])
    161   assertEquals("b", key)
    162   assertEquals(42, o[99])
    163   assertEquals("99", key)
    164   assertEquals(88, o.x)
    165   assertEquals(88, o["x"])
    166   assertEquals(42, (function(n) { return o[n] })("c"))
    167   assertEquals("c", key)
    168   assertEquals(42, (function(n) { return o[n] })(101))
    169   assertEquals("101", key)
    170   assertEquals(88, (function(n) { return o[n] })("x"))
    171 }
    172 
    173 TestGet({
    174   get(t, k, r) { key = k; return 42 }
    175 })
    176 
    177 TestGet({
    178   get(t, k, r) { return this.get2(r, k) },
    179   get2(r, k) { key = k; return 42 }
    180 })
    181 
    182 TestGet(new Proxy({}, {
    183   get(pt, pk, pr) {
    184     return function(t, k, r) { key = k; return 42 }
    185   }
    186 }))
    187 
    188 
    189 // ---------------------------------------------------------------------------
    190 function TestGetCall(handler) {
    191   TestWithProxies(TestGetCall2, handler)
    192 }
    193 
    194 function TestGetCall2(create, handler) {
    195   var p = create(handler)
    196   assertEquals(55, p.f())
    197   assertEquals(55, p["f"]())
    198   assertEquals(55, p.f("unused", "arguments"))
    199   assertEquals(55, p.f.call(p))
    200   assertEquals(55, p["f"].call(p))
    201   assertEquals(55, p[101].call(p))
    202   assertEquals(55, p.withargs(45, 5))
    203   assertEquals(55, p.withargs.call(p, 11, 22))
    204   assertEquals(55, (function(n) { return p[n]() })("f"))
    205   assertEquals(55, (function(n) { return p[n].call(p) })("f"))
    206   assertEquals(55, (function(n) { return p[n](15, 20) })("withargs"))
    207   assertEquals(55, (function(n) { return p[n].call(p, 13, 21) })("withargs"))
    208   assertEquals("6655", "66" + p)  // calls p.toString
    209 
    210   var o = Object.create(p, {g: {value: function(x) { return x + 88 }}})
    211   assertEquals(55, o.f())
    212   assertEquals(55, o["f"]())
    213   assertEquals(55, o.f("unused", "arguments"))
    214   assertEquals(55, o.f.call(o))
    215   assertEquals(55, o.f.call(p))
    216   assertEquals(55, o["f"].call(p))
    217   assertEquals(55, o[101].call(p))
    218   assertEquals(55, o.withargs(45, 5))
    219   assertEquals(55, o.withargs.call(p, 11, 22))
    220   assertEquals(90, o.g(2))
    221   assertEquals(91, o.g.call(o, 3))
    222   assertEquals(92, o.g.call(p, 4))
    223   assertEquals(55, (function(n) { return o[n]() })("f"))
    224   assertEquals(55, (function(n) { return o[n].call(o) })("f"))
    225   assertEquals(55, (function(n) { return o[n](15, 20) })("withargs"))
    226   assertEquals(55, (function(n) { return o[n].call(o, 13, 21) })("withargs"))
    227   assertEquals(93, (function(n) { return o[n](5) })("g"))
    228   assertEquals(94, (function(n) { return o[n].call(o, 6) })("g"))
    229   assertEquals(95, (function(n) { return o[n].call(p, 7) })("g"))
    230   assertEquals("6655", "66" + o)  // calls o.toString
    231 }
    232 
    233 TestGetCall({
    234   get(t, k, r) { return () => { return 55 } }
    235 })
    236 
    237 TestGetCall({
    238   get(t, k, r)  { return this.get2(t, k, r) },
    239   get2(t, k, r) { return () => { return 55 } }
    240 })
    241 
    242 TestGetCall({
    243   get(t, k, r) {
    244     if (k == "gg") {
    245       return () => { return 55 }
    246     } else if (k == "withargs") {
    247       return (n, m) => { return n + m * 2 }
    248     } else {
    249       return () => { return r.gg() }
    250     }
    251   }
    252 })
    253 
    254 TestGetCall(new Proxy({}, {
    255   get(pt, pk, pr) {
    256     return (t, k, r) => { return () => { return 55 } }
    257   }
    258 }))
    259 
    260 
    261 // ---------------------------------------------------------------------------
    262 function TestGetThrow(handler) {
    263   TestWithProxies(TestGetThrow2, handler)
    264 }
    265 
    266 function TestGetThrow2(create, handler) {
    267   var p = create(handler)
    268   assertThrowsEquals(function(){ p.a }, "myexn")
    269   assertThrowsEquals(function(){ p["b"] }, "myexn")
    270   assertThrowsEquals(function(){ p[3] }, "myexn")
    271   assertThrowsEquals(function(){ (function(n) { p[n] })("c") }, "myexn")
    272   assertThrowsEquals(function(){ (function(n) { p[n] })(99) }, "myexn")
    273 
    274   var o = Object.create(p, {x: {value: 88}, '4': {value: 89}})
    275   assertThrowsEquals(function(){ o.a }, "myexn")
    276   assertThrowsEquals(function(){ o["b"] }, "myexn")
    277   assertThrowsEquals(function(){ o[3] }, "myexn")
    278   assertThrowsEquals(function(){ (function(n) { o[n] })("c") }, "myexn")
    279   assertThrowsEquals(function(){ (function(n) { o[n] })(99) }, "myexn")
    280 }
    281 
    282 TestGetThrow({
    283   get(r, k) { throw "myexn" }
    284 })
    285 
    286 TestGetThrow({
    287   get(r, k) { return this.get2(r, k) },
    288   get2(r, k) { throw "myexn" }
    289 })
    290 
    291 TestGetThrow(new Proxy({}, {
    292   get(pr, pk) { throw "myexn" }
    293 }))
    294 
    295 TestGetThrow(new Proxy({}, {
    296   get(pr, pk) {
    297     return function(r, k) { throw "myexn" }
    298   }
    299 }))
    300 
    301 
    302 // ---------------------------------------------------------------------------
    303 // Setters.
    304 
    305 var key
    306 var val
    307 
    308 function TestSet(handler) {
    309   TestWithProxies(TestSet2, handler)
    310 }
    311 
    312 function TestSet2(create, handler) {
    313   var p = create(handler)
    314   assertEquals(42, p.a = 42)
    315   assertEquals("a", key)
    316   assertEquals(42, val)
    317   assertEquals(43, p["b"] = 43)
    318   assertEquals("b", key)
    319   assertEquals(43, val)
    320   assertEquals(44, p[77] = 44)
    321   assertEquals("77", key)
    322   assertEquals(44, val)
    323 
    324   assertEquals(45, (function(n) { return p[n] = 45 })("c"))
    325   assertEquals("c", key)
    326   assertEquals(45, val)
    327   assertEquals(46, (function(n) { return p[n] = 46 })(99))
    328   assertEquals("99", key)
    329   assertEquals(46, val)
    330 
    331   assertEquals(47, p["0"] = 47)
    332   assertEquals("0", key)
    333   assertEquals(47, val)
    334 }
    335 
    336 TestSet({
    337   set: function(r, k, v) { key = k; val = v; return true }
    338 })
    339 
    340 TestSet({
    341   set: function(r, k, v) { return this.set2(r, k, v) },
    342   set2: function(r, k, v) { key = k; val = v; return true }
    343 })
    344 
    345 TestSet(new Proxy({}, {
    346   get(pk, pr) {
    347     return (r, k, v) => { key = k; val = v; return true }
    348   }
    349 }))
    350 
    351 
    352 // ---------------------------------------------------------------------------
    353 function TestSetThrow(handler) {
    354   TestWithProxies(TestSetThrow2, handler)
    355 }
    356 
    357 function TestSetThrow2(create, handler) {
    358   var p = create(handler)
    359   assertThrowsEquals(function(){ p.a = 42 }, "myexn")
    360   assertThrowsEquals(function(){ p["b"] = 42 }, "myexn")
    361   assertThrowsEquals(function(){ p[22] = 42 }, "myexn")
    362   assertThrowsEquals(function(){ (function(n) { p[n] = 45 })("c") }, "myexn")
    363   assertThrowsEquals(function(){ (function(n) { p[n] = 46 })(99) }, "myexn")
    364 }
    365 
    366 TestSetThrow({
    367   set: function(r, k, v) { throw "myexn" }
    368 })
    369 
    370 TestSetThrow({
    371   set: function(r, k, v) { return this.set2(r, k, v) },
    372   set2: function(r, k, v) { throw "myexn" }
    373 })
    374 
    375 TestSetThrow({
    376   getOwnPropertyDescriptor: function(k) { throw "myexn" },
    377   defineProperty: function(k, desc) { key = k; val = desc.value }
    378 })
    379 
    380 TestSetThrow({
    381   getOwnPropertyDescriptor: function(k) {
    382     return {configurable: true, writable: true}
    383   },
    384   defineProperty: function(k, desc) { throw "myexn" }
    385 })
    386 
    387 TestSetThrow({
    388   getOwnPropertyDescriptor: function(k) {
    389     return this.getOwnPropertyDescriptor2(k)
    390   },
    391   getOwnPropertyDescriptor2: function(k) { throw "myexn" },
    392   defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
    393   defineProperty2: function(k, desc) { key = k; val = desc.value }
    394 })
    395 
    396 TestSetThrow({
    397   getOwnPropertyDescriptor: function(k) {
    398     return this.getOwnPropertyDescriptor2(k)
    399   },
    400   getOwnPropertyDescriptor2: function(k) {
    401     return {configurable: true, writable: true}
    402   },
    403   defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
    404   defineProperty2: function(k, desc) { throw "myexn" }
    405 })
    406 
    407 TestSetThrow({
    408   getOwnPropertyDescriptor: function(k) { throw "myexn" },
    409   defineProperty: function(k, desc) { key = k; val = desc.value }
    410 })
    411 
    412 TestSetThrow({
    413   getOwnPropertyDescriptor: function(k) {
    414     return {
    415       get configurable() { return true },
    416       get writable() { return true }
    417     }
    418   },
    419   defineProperty: function(k, desc) { throw "myexn" }
    420 })
    421 
    422 TestSetThrow({
    423   getOwnPropertyDescriptor: function(k) { throw "myexn" }
    424 })
    425 
    426 TestSetThrow({
    427   getOwnPropertyDescriptor: function(k) { throw "myexn" },
    428   defineProperty: function(k, desc) { key = k; val = desc.value }
    429 })
    430 
    431 TestSetThrow(new Proxy({}, {
    432   get: function(pr, pk) { throw "myexn" }
    433 }))
    434 
    435 TestSetThrow(new Proxy({}, {
    436   get: function(pr, pk) {
    437     return function(r, k, v) { throw "myexn" }
    438   }
    439 }))
    440 
    441 // ---------------------------------------------------------------------------
    442 
    443 // Evil proxy-induced side-effects shouldn't crash.
    444 TestWithProxies(function(create) {
    445   var calls = 0
    446   var handler = {
    447     getPropertyDescriptor: function() {
    448       ++calls
    449       return (calls % 2 == 1)
    450         ? {get: function() { return 5 }, configurable: true}
    451         : {set: function() { return false }, configurable: true}
    452     }
    453   }
    454   var p = create(handler)
    455   var o = Object.create(p)
    456   // Make proxy prototype property read-only after CanPut check.
    457   try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
    458 })
    459 
    460 TestWithProxies(function(create) {
    461   var handler = {
    462     getPropertyDescriptor: function() {
    463       Object.defineProperty(o, "x", {get: function() { return 5 }});
    464       return {set: function() {}}
    465     }
    466   }
    467   var p = create(handler)
    468   var o = Object.create(p)
    469   // Make object property read-only after CanPut check.
    470   try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
    471 })
    472 
    473 
    474 // ---------------------------------------------------------------------------
    475 // Property definition (Object.defineProperty and Object.defineProperties).
    476 
    477 var key
    478 var desc
    479 
    480 function TestDefine(handler) {
    481   TestWithProxies(TestDefine2, handler)
    482 }
    483 
    484 function TestDefine2(create, handler) {
    485   var p = create(handler)
    486   assertEquals(p, Object.defineProperty(p, "a", {value: 44}))
    487   assertEquals("a", key)
    488   assertEquals(1, Object.getOwnPropertyNames(desc).length)
    489   assertEquals(44, desc.value)
    490 
    491   assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false}))
    492   assertEquals("b", key)
    493   assertEquals(2, Object.getOwnPropertyNames(desc).length)
    494   assertEquals(45, desc.value)
    495   assertEquals(false, desc.writable)
    496 
    497   assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false}))
    498   assertEquals("c", key)
    499   assertEquals(2, Object.getOwnPropertyNames(desc).length)
    500   assertEquals(46, desc.value)
    501   assertEquals(false, desc.enumerable)
    502 
    503   assertEquals(p, Object.defineProperty(p, 101, {value: 47, enumerable: false}))
    504   assertEquals("101", key)
    505   assertEquals(2, Object.getOwnPropertyNames(desc).length)
    506   assertEquals(47, desc.value)
    507   assertEquals(false, desc.enumerable)
    508 
    509   var attributes = {configurable: true, mine: 66, minetoo: 23}
    510   assertEquals(p, Object.defineProperty(p, "d", attributes))
    511   assertEquals("d", key);
    512   // Modifying the attributes object after the fact should have no effect.
    513   attributes.configurable = false
    514   attributes.mine = 77
    515   delete attributes.minetoo;
    516   assertEquals(1, Object.getOwnPropertyNames(desc).length)
    517   assertEquals(true, desc.configurable)
    518   assertEquals(undefined, desc.mine)
    519   assertEquals(undefined, desc.minetoo)
    520 
    521   assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }}))
    522   assertEquals("e", key)
    523   assertEquals(1, Object.getOwnPropertyNames(desc).length)
    524   assertEquals(5, desc.get())
    525 
    526   assertEquals(p, Object.defineProperty(p, "zzz", {}))
    527   assertEquals("zzz", key)
    528   assertEquals(0, Object.getOwnPropertyNames(desc).length)
    529 
    530   var props = {
    531     '11': {},
    532     blub: {get: function() { return true }},
    533     '': {get value() { return 20 }},
    534     last: {value: 21, configurable: true, mine: "eyes"}
    535   }
    536   Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false})
    537   assertEquals(p, Object.defineProperties(p, props))
    538   assertEquals("last", key)
    539   assertEquals(2, Object.getOwnPropertyNames(desc).length)
    540   assertEquals(21, desc.value)
    541   assertEquals(true, desc.configurable)
    542   assertEquals(undefined, desc.mine)  // Arguably a bug in the spec...
    543 
    544   var props = {bla: {get value() { throw "myexn" }}}
    545   assertThrowsEquals(function(){ Object.defineProperties(p, props) }, "myexn")
    546 }
    547 
    548 TestDefine({
    549   defineProperty(t, k, d) { key = k; desc = d; return true }
    550 })
    551 
    552 TestDefine({
    553   defineProperty(t, k, d) { return this.defineProperty2(k, d) },
    554   defineProperty2(k, d) { key = k; desc = d; return true }
    555 })
    556 
    557 
    558 // ---------------------------------------------------------------------------
    559 function TestDefineThrow(handler) {
    560   TestWithProxies(TestDefineThrow2, handler)
    561 }
    562 
    563 function TestDefineThrow2(create, handler) {
    564   var p = create(handler)
    565   assertThrowsEquals(() => Object.defineProperty(p, "a", {value: 44}), "myexn")
    566   assertThrowsEquals(() => Object.defineProperty(p, 0, {value: 44}), "myexn")
    567 
    568   var d1 = create({
    569     get: function(r, k) { throw "myexn" },
    570     getOwnPropertyNames: function() { return ["value"] }
    571   })
    572   assertThrowsEquals(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
    573   var d2 = create({
    574     get: function(r, k) { return 77 },
    575     getOwnPropertyNames: function() { throw "myexn" }
    576   })
    577   assertThrowsEquals(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
    578 
    579   var props = {bla: {get value() { throw "otherexn" }}}
    580   assertThrowsEquals(() => Object.defineProperties(p, props), "otherexn")
    581 }
    582 
    583 TestDefineThrow({
    584   defineProperty: function(k, d) { throw "myexn" }
    585 })
    586 
    587 TestDefineThrow({
    588   defineProperty: function(k, d) { return this.defineProperty2(k, d) },
    589   defineProperty2: function(k, d) { throw "myexn" }
    590 })
    591 
    592 TestDefineThrow(new Proxy({}, {
    593   get: function(pr, pk) { throw "myexn" }
    594 }))
    595 
    596 TestDefineThrow(new Proxy({}, {
    597   get: function(pr, pk) {
    598     return function(k, d) { throw "myexn" }
    599   }
    600 }))
    601 
    602 
    603 
    604 // ---------------------------------------------------------------------------
    605 // Property deletion (delete).
    606 
    607 var key
    608 
    609 function TestDelete(handler) {
    610   TestWithProxies(TestDelete2, handler)
    611 }
    612 
    613 function TestDelete2(create, handler) {
    614   var p = create(handler)
    615   assertEquals(true, delete p.a)
    616   assertEquals("a", key)
    617   assertEquals(true, delete p["b"])
    618   assertEquals("b", key)
    619   assertEquals(true, delete p[1])
    620   assertEquals("1", key)
    621 
    622   assertEquals(false, delete p.z1)
    623   assertEquals("z1", key)
    624   assertEquals(false, delete p["z2"])
    625   assertEquals("z2", key);
    626 
    627   (function() {
    628     "use strict"
    629     assertEquals(true, delete p.c)
    630     assertEquals("c", key)
    631     assertEquals(true, delete p["d"])
    632     assertEquals("d", key)
    633     assertEquals(true, delete p[2])
    634     assertEquals("2", key)
    635 
    636     assertThrows(function(){ delete p.z3 }, TypeError)
    637     assertEquals("z3", key)
    638     assertThrows(function(){ delete p["z4"] }, TypeError)
    639     assertEquals("z4", key)
    640   })()
    641 }
    642 
    643 TestDelete({
    644   deleteProperty(target, k) { key = k; return k < "z" }
    645 })
    646 
    647 TestDelete({
    648   deleteProperty(target, k) { return this.delete2(k) },
    649   delete2: function(k) { key = k; return k < "z" }
    650 })
    651 
    652 TestDelete(new Proxy({}, {
    653   get(pt, pk, pr) {
    654     return (target, k) => { key = k; return k < "z" }
    655   }
    656 }))
    657 
    658 
    659 // ---------------------------------------------------------------------------
    660 function TestDeleteThrow(handler) {
    661   TestWithProxies(TestDeleteThrow2, handler)
    662 }
    663 
    664 function TestDeleteThrow2(create, handler) {
    665   var p = create(handler)
    666   assertThrowsEquals(function(){ delete p.a }, "myexn")
    667   assertThrowsEquals(function(){ delete p["b"] }, "myexn");
    668   assertThrowsEquals(function(){ delete p[3] }, "myexn");
    669 
    670   (function() {
    671     "use strict"
    672     assertThrowsEquals(function(){ delete p.c }, "myexn")
    673     assertThrowsEquals(function(){ delete p["d"] }, "myexn")
    674     assertThrowsEquals(function(){ delete p[4] }, "myexn");
    675   })()
    676 }
    677 
    678 TestDeleteThrow({
    679   deleteProperty(t, k) { throw "myexn" }
    680 })
    681 
    682 TestDeleteThrow({
    683   deleteProperty(t, k) { return this.delete2(k) },
    684   delete2(k) { throw "myexn" }
    685 })
    686 
    687 TestDeleteThrow(new Proxy({}, {
    688   get(pt, pk, pr) { throw "myexn" }
    689 }))
    690 
    691 TestDeleteThrow(new Proxy({}, {
    692   get(pt, pk, pr) {
    693     return (k) => { throw "myexn" }
    694   }
    695 }))
    696 
    697 
    698 // ---------------------------------------------------------------------------
    699 // Property descriptors (Object.getOwnPropertyDescriptor).
    700 
    701 function TestDescriptor(handler) {
    702   TestWithProxies(TestDescriptor2, handler)
    703 }
    704 
    705 function TestDescriptor2(create, handler) {
    706   var p = create(handler)
    707   var descs = [
    708     {configurable: true},
    709     {value: 34, enumerable: true, configurable: true},
    710     {value: 3, writable: false, mine: "eyes", configurable: true},
    711     {get value() { return 20 }, get configurable() { return true }},
    712     {get: function() { "get" }, set: function() { "set" }, configurable: true}
    713   ]
    714   for (var i = 0; i < descs.length; ++i) {
    715     assertEquals(p, Object.defineProperty(p, i, descs[i]))
    716     var desc = Object.getOwnPropertyDescriptor(p, i)
    717     for (prop in descs[i]) {
    718       // TODO(rossberg): Ignore user attributes as long as the spec isn't
    719       // fixed suitably.
    720       if (prop != "mine") assertEquals(descs[i][prop], desc[prop])
    721     }
    722     assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent"))
    723   }
    724 }
    725 
    726 TestDescriptor({
    727   defineProperty(t, k, d) { this["__" + k] = d; return true },
    728   getOwnPropertyDescriptor(t, k) { return this["__" + k] }
    729 })
    730 
    731 TestDescriptor({
    732   defineProperty(t, k, d) { this["__" + k] = d; return true },
    733   getOwnPropertyDescriptor(t, k) {
    734     return this.getOwnPropertyDescriptor2(k)
    735   },
    736   getOwnPropertyDescriptor2: function(k) { return this["__" + k] }
    737 })
    738 
    739 
    740 // ---------------------------------------------------------------------------
    741 function TestDescriptorThrow(handler) {
    742   TestWithProxies(TestDescriptorThrow2, handler)
    743 }
    744 
    745 function TestDescriptorThrow2(create, handler) {
    746   var p = create(handler)
    747   assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, "a"), "myexn")
    748 }
    749 
    750 TestDescriptorThrow({
    751   getOwnPropertyDescriptor: function(k) { throw "myexn" }
    752 })
    753 
    754 TestDescriptorThrow({
    755   getOwnPropertyDescriptor: function(k) {
    756     return this.getOwnPropertyDescriptor2(k)
    757   },
    758   getOwnPropertyDescriptor2: function(k) { throw "myexn" }
    759 })
    760 
    761 
    762 
    763 // ---------------------------------------------------------------------------
    764 // Comparison.
    765 
    766 function TestComparison(eq) {
    767   TestWithProxies(TestComparison2, eq)
    768 }
    769 
    770 function TestComparison2(create, eq) {
    771   var p1 = create({})
    772   var p2 = create({})
    773 
    774   assertTrue(eq(p1, p1))
    775   assertTrue(eq(p2, p2))
    776   assertTrue(!eq(p1, p2))
    777   assertTrue(!eq(p1, {}))
    778   assertTrue(!eq({}, p2))
    779   assertTrue(!eq({}, {}))
    780 }
    781 
    782 TestComparison(function(o1, o2) { return o1 == o2 })
    783 TestComparison(function(o1, o2) { return o1 === o2 })
    784 TestComparison(function(o1, o2) { return !(o1 != o2) })
    785 TestComparison(function(o1, o2) { return !(o1 !== o2) })
    786 
    787 
    788 
    789 // Type (typeof).
    790 
    791 function TestTypeof() {
    792   assertEquals("object", typeof new Proxy({},{}))
    793   assertTrue(typeof new Proxy({}, {}) == "object")
    794   assertTrue("object" == typeof new Proxy({},{}))
    795 
    796   assertEquals("function", typeof new Proxy(function() {}, {}))
    797   assertTrue(typeof new Proxy(function() {}, {}) == "function")
    798   assertTrue("function" == typeof new Proxy(function() {},{}))
    799 }
    800 
    801 TestTypeof()
    802 
    803 
    804 
    805 // ---------------------------------------------------------------------------
    806 // Membership test (in).
    807 
    808 var key
    809 
    810 function TestIn(handler) {
    811   TestWithProxies(TestIn2, handler)
    812 }
    813 
    814 function TestIn2(create, handler) {
    815   var p = create(handler)
    816   assertTrue("a" in p)
    817   assertEquals("a", key)
    818   assertTrue(99 in p)
    819   assertEquals("99", key)
    820   assertFalse("z" in p)
    821   assertEquals("z", key)
    822 
    823   assertEquals(2, ("a" in p) ? 2 : 0)
    824   assertEquals(0, !("a" in p) ? 2 : 0)
    825   assertEquals(0, ("zzz" in p) ? 2 : 0)
    826   assertEquals(2, !("zzz" in p) ? 2 : 0)
    827 
    828   // Test compilation in conditionals.
    829   if ("b" in p) {
    830   } else {
    831     assertTrue(false)
    832   }
    833   assertEquals("b", key)
    834 
    835   if ("zz" in p) {
    836     assertTrue(false)
    837   }
    838   assertEquals("zz", key)
    839 
    840   if (!("c" in p)) {
    841     assertTrue(false)
    842   }
    843   assertEquals("c", key)
    844 
    845   if (!("zzz" in p)) {
    846   } else {
    847     assertTrue(false)
    848   }
    849   assertEquals("zzz", key)
    850 }
    851 
    852 TestIn({
    853   has(t, k) { key = k; return k < "z" }
    854 })
    855 
    856 TestIn({
    857   has(t, k) { return this.has2(k) },
    858   has2(k) { key = k; return k < "z" }
    859 })
    860 
    861 TestIn(new Proxy({},{
    862   get(pt, pk, pr) {
    863     return (t, k) => { key = k; return k < "z" }
    864   }
    865 }))
    866 
    867 
    868 // ---------------------------------------------------------------------------
    869 function TestInThrow(handler) {
    870   TestWithProxies(TestInThrow2, handler)
    871 }
    872 
    873 function TestInThrow2(create, handler) {
    874   var p = create(handler)
    875   assertThrowsEquals(function(){ return "a" in p }, "myexn")
    876   assertThrowsEquals(function(){ return 99 in p }, "myexn")
    877   assertThrowsEquals(function(){ return !("a" in p) }, "myexn")
    878   assertThrowsEquals(function(){ return ("a" in p) ? 2 : 3 }, "myexn")
    879   assertThrowsEquals(function(){ if ("b" in p) {} }, "myexn")
    880   assertThrowsEquals(function(){ if (!("b" in p)) {} }, "myexn")
    881   assertThrowsEquals(function(){ if ("zzz" in p) {} }, "myexn")
    882 }
    883 
    884 TestInThrow({
    885   has: function(k) { throw "myexn" }
    886 })
    887 
    888 TestInThrow({
    889   has: function(k) { return this.has2(k) },
    890   has2: function(k) { throw "myexn" }
    891 })
    892 
    893 TestInThrow(new Proxy({},{
    894   get: function(pr, pk) { throw "myexn" }
    895 }))
    896 
    897 TestInThrow(new Proxy({},{
    898   get: function(pr, pk) {
    899     return function(k) { throw "myexn" }
    900   }
    901 }))
    902 
    903 
    904 
    905 // ---------------------------------------------------------------------------
    906 // Own Properties (Object.prototype.hasOwnProperty).
    907 
    908 var key
    909 
    910 function TestHasOwn(handler) {
    911   TestWithProxies(TestHasOwn2, handler)
    912 }
    913 
    914 function TestHasOwn2(create, handler) {
    915   var p = create(handler)
    916   assertTrue(Object.prototype.hasOwnProperty.call(p, "a"))
    917   assertEquals("a", key)
    918   assertTrue(Object.prototype.hasOwnProperty.call(p, 99))
    919   assertEquals("99", key)
    920   assertFalse(Object.prototype.hasOwnProperty.call(p, "z"))
    921   assertEquals("z", key)
    922 }
    923 
    924 TestHasOwn({
    925   getOwnPropertyDescriptor(t, k) {
    926     key = k; if (k < "z") return {configurable: true}
    927   },
    928   has() { assertUnreachable() }
    929 })
    930 
    931 TestHasOwn({
    932   getOwnPropertyDescriptor(t, k) { return this.getOwnPropertyDescriptor2(k) },
    933   getOwnPropertyDescriptor2(k) {
    934     key = k; if (k < "z") return {configurable: true}
    935   }
    936 })
    937 
    938 
    939 
    940 // ---------------------------------------------------------------------------
    941 function TestHasOwnThrow(handler) {
    942   TestWithProxies(TestHasOwnThrow2, handler)
    943 }
    944 
    945 function TestHasOwnThrow2(create, handler) {
    946   var p = create(handler)
    947   assertThrowsEquals(function(){ Object.prototype.hasOwnProperty.call(p, "a")},
    948     "myexn")
    949   assertThrowsEquals(function(){ Object.prototype.hasOwnProperty.call(p, 99)},
    950     "myexn")
    951 }
    952 
    953 TestHasOwnThrow({
    954   getOwnPropertyDescriptor(t, k) { throw "myexn" }
    955 })
    956 
    957 TestHasOwnThrow({
    958   getOwnPropertyDescriptor(t, k) { return this.getOwnPropertyDescriptor2(k) },
    959   getOwnPropertyDescriptor2(k) { throw "myexn" }
    960 });
    961 
    962 
    963 // ---------------------------------------------------------------------------
    964 // Instanceof (instanceof)
    965 
    966 (function TestProxyInstanceof() {
    967   var o1 = {}
    968   var p1 = new Proxy({}, {})
    969   var p2 = new Proxy(o1, {})
    970   var p3 = new Proxy(p2, {})
    971   var o2 = Object.create(p2)
    972 
    973   var f0 = function() {}
    974   f0.prototype = o1
    975   var f1 = function() {}
    976   f1.prototype = p1
    977   var f2 = function() {}
    978   f2.prototype = p2
    979   var f3 = function() {}
    980   f3.prototype = o2
    981 
    982   assertTrue(o1 instanceof Object)
    983   assertFalse(o1 instanceof f0)
    984   assertFalse(o1 instanceof f1)
    985   assertFalse(o1 instanceof f2)
    986   assertFalse(o1 instanceof f3)
    987   assertTrue(p1 instanceof Object)
    988   assertFalse(p1 instanceof f0)
    989   assertFalse(p1 instanceof f1)
    990   assertFalse(p1 instanceof f2)
    991   assertFalse(p1 instanceof f3)
    992   assertTrue(p2 instanceof Object)
    993   assertFalse(p2 instanceof f0)
    994   assertFalse(p2 instanceof f1)
    995   assertFalse(p2 instanceof f2)
    996   assertFalse(p2 instanceof f3)
    997   assertTrue(p3 instanceof Object)
    998   assertFalse(p3 instanceof f0)
    999   assertFalse(p3 instanceof f1)
   1000   assertFalse(p3 instanceof f2)
   1001   assertFalse(p3 instanceof f3)
   1002   assertTrue(o2 instanceof Object)
   1003   assertFalse(o2 instanceof f0)
   1004   assertFalse(o2 instanceof f1)
   1005   assertTrue(o2 instanceof f2)
   1006   assertFalse(o2 instanceof f3)
   1007 
   1008   var f = new Proxy(function() {}, {})
   1009   assertTrue(f instanceof Function)
   1010 })();
   1011 
   1012 
   1013 (function TestInstanceofProxy() {
   1014   var o0 = Object.create(null)
   1015   var o1 = {}
   1016   var o2 = Object.create(o0)
   1017   var o3 = Object.create(o1)
   1018   var o4 = Object.create(o2)
   1019   var o5 = Object.create(o3)
   1020 
   1021   function handler(o) {
   1022     return {
   1023       get: function(r, p) {
   1024         // We want to test prototype lookup, so ensure the proxy
   1025         // offers OrdinaryHasInstance behavior.
   1026         if (p === Symbol.hasInstance) {
   1027           return undefined;
   1028         }
   1029         return o;
   1030       }
   1031     }
   1032   }
   1033 
   1034   var f0 = new Proxy(function() {}, handler(o0))
   1035   var f1 = new Proxy(function() {}, handler(o1))
   1036   var f2 = new Proxy(function() {}, handler(o2))
   1037   var f3 = new Proxy(function() {}, handler(o3))
   1038   var f4 = new Proxy(function() {}, handler(o4))
   1039   var f5 = new Proxy(function() {}, handler(o4))
   1040 
   1041   assertFalse(null instanceof f0)
   1042   assertFalse(o0 instanceof f0)
   1043   assertFalse(o0 instanceof f1)
   1044   assertFalse(o0 instanceof f2)
   1045   assertFalse(o0 instanceof f3)
   1046   assertFalse(o0 instanceof f4)
   1047   assertFalse(o0 instanceof f5)
   1048   assertFalse(o1 instanceof f0)
   1049   assertFalse(o1 instanceof f1)
   1050   assertFalse(o1 instanceof f2)
   1051   assertFalse(o1 instanceof f3)
   1052   assertFalse(o1 instanceof f4)
   1053   assertFalse(o1 instanceof f5)
   1054   assertTrue(o2 instanceof f0)
   1055   assertFalse(o2 instanceof f1)
   1056   assertFalse(o2 instanceof f2)
   1057   assertFalse(o2 instanceof f3)
   1058   assertFalse(o2 instanceof f4)
   1059   assertFalse(o2 instanceof f5)
   1060   assertFalse(o3 instanceof f0)
   1061   assertTrue(o3 instanceof f1)
   1062   assertFalse(o3 instanceof f2)
   1063   assertFalse(o3 instanceof f3)
   1064   assertFalse(o3 instanceof f4)
   1065   assertFalse(o3 instanceof f5)
   1066   assertTrue(o4 instanceof f0)
   1067   assertFalse(o4 instanceof f1)
   1068   assertTrue(o4 instanceof f2)
   1069   assertFalse(o4 instanceof f3)
   1070   assertFalse(o4 instanceof f4)
   1071   assertFalse(o4 instanceof f5)
   1072   assertFalse(o5 instanceof f0)
   1073   assertTrue(o5 instanceof f1)
   1074   assertFalse(o5 instanceof f2)
   1075   assertTrue(o5 instanceof f3)
   1076   assertFalse(o5 instanceof f4)
   1077   assertFalse(o5 instanceof f5)
   1078 
   1079   var f = new Proxy(function() {}, {})
   1080   var ff = new Proxy(function() {}, handler(Function))
   1081   assertTrue(f instanceof Function)
   1082   assertFalse(f instanceof ff)
   1083 })();
   1084 
   1085 
   1086 // ---------------------------------------------------------------------------
   1087 // Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf).
   1088 
   1089 (function TestPrototype() {
   1090   var o1 = {}
   1091   var p1 = new Proxy({}, {})
   1092   var p2 = new Proxy(o1, {})
   1093   var p3 = new Proxy(p2, {})
   1094   var o2 = Object.create(p3)
   1095 
   1096   assertSame(Object.getPrototypeOf(o1), Object.prototype)
   1097   assertSame(Object.getPrototypeOf(p1), Object.prototype)
   1098   assertSame(Object.getPrototypeOf(p2), Object.prototype)
   1099   assertSame(Object.getPrototypeOf(p3), Object.prototype)
   1100   assertSame(Object.getPrototypeOf(o2), p3)
   1101 
   1102   assertTrue(Object.prototype.isPrototypeOf(o1))
   1103   assertTrue(Object.prototype.isPrototypeOf(p1))
   1104   assertTrue(Object.prototype.isPrototypeOf(p2))
   1105   assertTrue(Object.prototype.isPrototypeOf(p3))
   1106   assertTrue(Object.prototype.isPrototypeOf(o2))
   1107   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o1))
   1108   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p1))
   1109   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2))
   1110   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3))
   1111   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o2))
   1112   assertFalse(Object.prototype.isPrototypeOf.call(o1, o1))
   1113   assertFalse(Object.prototype.isPrototypeOf.call(o1, p1))
   1114   assertFalse(Object.prototype.isPrototypeOf.call(o1, p2))
   1115   assertFalse(Object.prototype.isPrototypeOf.call(o1, p3))
   1116   assertFalse(Object.prototype.isPrototypeOf.call(o1, o2))
   1117   assertFalse(Object.prototype.isPrototypeOf.call(p1, p1))
   1118   assertFalse(Object.prototype.isPrototypeOf.call(p1, o1))
   1119   assertFalse(Object.prototype.isPrototypeOf.call(p1, p2))
   1120   assertFalse(Object.prototype.isPrototypeOf.call(p1, p3))
   1121   assertFalse(Object.prototype.isPrototypeOf.call(p1, o2))
   1122   assertFalse(Object.prototype.isPrototypeOf.call(p2, p1))
   1123   assertFalse(Object.prototype.isPrototypeOf.call(p2, p2))
   1124   assertFalse(Object.prototype.isPrototypeOf.call(p2, p3))
   1125   assertFalse(Object.prototype.isPrototypeOf.call(p2, o2))
   1126   assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
   1127   assertTrue(Object.prototype.isPrototypeOf.call(p3, o2))
   1128   assertFalse(Object.prototype.isPrototypeOf.call(o2, o1))
   1129   assertFalse(Object.prototype.isPrototypeOf.call(o2, p1))
   1130   assertFalse(Object.prototype.isPrototypeOf.call(o2, p2))
   1131   assertFalse(Object.prototype.isPrototypeOf.call(o2, p3))
   1132   assertFalse(Object.prototype.isPrototypeOf.call(o2, o2))
   1133 
   1134   var f = new Proxy(function() {}, {})
   1135   assertSame(Object.getPrototypeOf(f), Function.prototype)
   1136   assertTrue(Object.prototype.isPrototypeOf(f))
   1137   assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f))
   1138 })();
   1139 
   1140 
   1141 // ---------------------------------------------------------------------------
   1142 function TestPropertyNamesThrow(handler) {
   1143   TestWithProxies(TestPropertyNamesThrow2, handler)
   1144 }
   1145 
   1146 function TestPropertyNamesThrow2(create, handler) {
   1147   var p = create(handler)
   1148   assertThrowsEquals(function(){ Object.getOwnPropertyNames(p) }, "myexn")
   1149 }
   1150 
   1151 TestPropertyNamesThrow({
   1152   ownKeys() { throw "myexn" }
   1153 })
   1154 
   1155 TestPropertyNamesThrow({
   1156   ownKeys() { return this.getOwnPropertyNames2() },
   1157   getOwnPropertyNames2() { throw "myexn" }
   1158 })
   1159 
   1160 // ---------------------------------------------------------------------------
   1161 
   1162 function TestKeys(names, handler) {
   1163   var p = new Proxy({}, handler);
   1164   assertArrayEquals(names, Object.keys(p))
   1165 }
   1166 
   1167 TestKeys([], {
   1168   ownKeys() { return [] }
   1169 })
   1170 
   1171 TestKeys([], {
   1172   ownKeys() { return ["a", "zz", " ", "0", "toString"] }
   1173 })
   1174 
   1175 TestKeys(["a", "zz", " ", "0", "toString"], {
   1176   ownKeys() { return ["a", "zz", " ", "0", "toString"] },
   1177   getOwnPropertyDescriptor(t, p) {
   1178     return {configurable: true, enumerable: true}
   1179   }
   1180 })
   1181 
   1182 TestKeys([], {
   1183   ownKeys() { return this.keys2() },
   1184   keys2() { return ["throw", "function "] }
   1185 })
   1186 
   1187 TestKeys(["throw", "function "], {
   1188   ownKeys() { return this.keys2() },
   1189   keys2() { return ["throw", "function "] },
   1190   getOwnPropertyDescriptor(t, p) {
   1191     return {configurable: true, enumerable: true}
   1192   }
   1193 })
   1194 
   1195 TestKeys(["a", "0"], {
   1196   ownKeys() { return ["a", "23", "zz", "", "0"] },
   1197   getOwnPropertyDescriptor(t, k) {
   1198     return k == "" ?
   1199         undefined :
   1200         { configurable: true, enumerable: k.length == 1}
   1201   }
   1202 })
   1203 
   1204 TestKeys(["23", "zz", ""], {
   1205   ownKeys() { return this.getOwnPropertyNames2() },
   1206   getOwnPropertyNames2() { return ["a", "23", "zz", "", "0"] },
   1207   getOwnPropertyDescriptor(t, k) {
   1208     return this.getOwnPropertyDescriptor2(k)
   1209   },
   1210   getOwnPropertyDescriptor2(k) {
   1211     return {configurable: true, enumerable: k.length != 1 }
   1212   }
   1213 })
   1214 
   1215 TestKeys([], {
   1216   get ownKeys() {
   1217     return function() { return ["a", "b", "c"] }
   1218   },
   1219   getOwnPropertyDescriptor: function(k) { return {configurable: true} }
   1220 })
   1221 
   1222 
   1223 // ---------------------------------------------------------------------------
   1224 function TestKeysThrow(handler) {
   1225   TestWithProxies(TestKeysThrow2, handler)
   1226 }
   1227 
   1228 function TestKeysThrow2(create, handler) {
   1229   var p = create(handler);
   1230   assertThrowsEquals(function(){ Object.keys(p) }, "myexn");
   1231 }
   1232 
   1233 TestKeysThrow({
   1234   ownKeys() { throw "myexn" }
   1235 })
   1236 
   1237 TestKeysThrow({
   1238   ownKeys() { return this.keys2() },
   1239   keys2() { throw "myexn" }
   1240 })
   1241 
   1242 TestKeysThrow({
   1243   ownKeys() { return ['1'] },
   1244   getOwnPropertyDescriptor: function() { throw "myexn" },
   1245 })
   1246 
   1247 TestKeysThrow({
   1248   ownKeys() { return this.getOwnPropertyNames2() },
   1249   getOwnPropertyNames2() { return ['1', '2'] },
   1250   getOwnPropertyDescriptor(k) {
   1251     return this.getOwnPropertyDescriptor2(k)
   1252   },
   1253   getOwnPropertyDescriptor2(k) { throw "myexn" }
   1254 })
   1255 
   1256 TestKeysThrow({
   1257   get ownKeys() { throw "myexn" }
   1258 })
   1259 
   1260 TestKeysThrow({
   1261   get ownKeys() {
   1262     return function() { throw "myexn" }
   1263   },
   1264 })
   1265 
   1266 TestKeysThrow({
   1267   get ownKeys() {
   1268     return function() { return ['1', '2'] }
   1269   },
   1270   getOwnPropertyDescriptor(k) { throw "myexn" }
   1271 })
   1272 
   1273 
   1274 
   1275 // ---------------------------------------------------------------------------
   1276 // String conversion (Object.prototype.toString,
   1277 //                    Object.prototype.toLocaleString,
   1278 //                    Function.prototype.toString)
   1279 
   1280 var key
   1281 
   1282 function TestToString(handler) {
   1283   var p = new Proxy({}, handler)
   1284   key = ""
   1285   assertEquals("[object Object]", Object.prototype.toString.call(p))
   1286   assertEquals(Symbol.toStringTag, key)
   1287   assertEquals("my_proxy", Object.prototype.toLocaleString.call(p))
   1288   assertEquals("toString", key)
   1289 
   1290   var f = new Proxy(function() {}, handler)
   1291   key = ""
   1292   assertEquals("[object Function]", Object.prototype.toString.call(f))
   1293   assertEquals(Symbol.toStringTag, key)
   1294   assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
   1295   assertEquals("toString", key)
   1296   assertThrows(function(){ Function.prototype.toString.call(f) })
   1297 
   1298   var o = Object.create(p)
   1299   key = ""
   1300   assertEquals("[object Object]", Object.prototype.toString.call(o))
   1301   assertEquals(Symbol.toStringTag, key)
   1302   assertEquals("my_proxy", Object.prototype.toLocaleString.call(o))
   1303   assertEquals("toString", key)
   1304 }
   1305 
   1306 TestToString({
   1307   get: function(r, k) { key = k; return function() { return "my_proxy" } }
   1308 })
   1309 
   1310 TestToString({
   1311   get: function(r, k) { return this.get2(r, k) },
   1312   get2: function(r, k) { key = k; return function() { return "my_proxy" } }
   1313 })
   1314 
   1315 TestToString(new Proxy({}, {
   1316   get: function(pr, pk) {
   1317     return function(r, k) { key = k; return function() { return "my_proxy" } }
   1318   }
   1319 }))
   1320 
   1321 
   1322 function TestToStringThrow(handler) {
   1323   var p = new Proxy({}, handler)
   1324   assertThrowsEquals(() => Object.prototype.toString.call(p), "myexn")
   1325   assertThrowsEquals(() => Object.prototype.toLocaleString.call(p), "myexn")
   1326 
   1327   var f = new Proxy(function(){}, handler)
   1328   assertThrowsEquals(() => Object.prototype.toString.call(f), "myexn")
   1329   assertThrowsEquals(() => Object.prototype.toLocaleString.call(f), "myexn")
   1330 
   1331   var o = Object.create(p)
   1332   assertThrowsEquals(() => Object.prototype.toString.call(o), "myexn")
   1333   assertThrowsEquals(() => Object.prototype.toLocaleString.call(o), "myexn")
   1334 }
   1335 
   1336 TestToStringThrow({
   1337   get: function(r, k) { throw "myexn" }
   1338 })
   1339 
   1340 TestToStringThrow({
   1341   get: function(r, k) { return this.get2(r, k) },
   1342   get2: function(r, k) { throw "myexn" }
   1343 })
   1344 
   1345 TestToStringThrow(new Proxy({}, {
   1346   get: function(pr, pk) { throw "myexn" }
   1347 }))
   1348 
   1349 TestToStringThrow(new Proxy({}, {
   1350   get: function(pr, pk) {
   1351     return function(r, k) { throw "myexn" }
   1352   }
   1353 }))
   1354 
   1355 
   1356 // ---------------------------------------------------------------------------
   1357 // Value conversion (Object.prototype.toValue)
   1358 
   1359 function TestValueOf(handler) {
   1360   TestWithProxies(TestValueOf2, handler)
   1361 }
   1362 
   1363 function TestValueOf2(create, handler) {
   1364   var p = create(handler)
   1365   assertSame(p, Object.prototype.valueOf.call(p))
   1366 }
   1367 
   1368 TestValueOf({})
   1369 
   1370 
   1371 
   1372 // ---------------------------------------------------------------------------
   1373 // Enumerability (Object.prototype.propertyIsEnumerable)
   1374 
   1375 var key
   1376 
   1377 function TestIsEnumerable(handler) {
   1378   TestWithProxies(TestIsEnumerable2, handler)
   1379 }
   1380 
   1381 function TestIsEnumerable2(create, handler) {
   1382   var p = create(handler)
   1383   assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a"))
   1384   assertEquals("a", key)
   1385   assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2))
   1386   assertEquals("2", key)
   1387   assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z"))
   1388   assertEquals("z", key)
   1389 
   1390   var o = Object.create(p)
   1391   key = ""
   1392   assertFalse(Object.prototype.propertyIsEnumerable.call(o, "a"))
   1393   assertEquals("", key)  // trap not invoked
   1394 }
   1395 
   1396 TestIsEnumerable({
   1397   getOwnPropertyDescriptor(t, k) {
   1398     key = k;
   1399     return {enumerable: k < "z", configurable: true}
   1400   },
   1401 })
   1402 
   1403 TestIsEnumerable({
   1404   getOwnPropertyDescriptor: function(t, k) {
   1405     return this.getOwnPropertyDescriptor2(k)
   1406   },
   1407   getOwnPropertyDescriptor2: function(k) {
   1408     key = k;
   1409     return {enumerable: k < "z", configurable: true}
   1410   },
   1411 })
   1412 
   1413 TestIsEnumerable({
   1414   getOwnPropertyDescriptor: function(t, k) {
   1415     key = k;
   1416     return {get enumerable() { return k < "z" }, configurable: true}
   1417   },
   1418 })
   1419 
   1420 TestIsEnumerable(new Proxy({}, {
   1421   get: function(pt, pk, pr) {
   1422     return function(t, k) {
   1423       key = k;
   1424       return {enumerable: k < "z", configurable: true}
   1425     }
   1426   }
   1427 }))
   1428 
   1429 
   1430 // ---------------------------------------------------------------------------
   1431 function TestIsEnumerableThrow(handler) {
   1432   TestWithProxies(TestIsEnumerableThrow2, handler)
   1433 }
   1434 
   1435 function TestIsEnumerableThrow2(create, handler) {
   1436   var p = create(handler)
   1437   assertThrowsEquals(() => Object.prototype.propertyIsEnumerable.call(p, "a"),
   1438       "myexn")
   1439   assertThrowsEquals(() => Object.prototype.propertyIsEnumerable.call(p, 11),
   1440       "myexn")
   1441 }
   1442 
   1443 TestIsEnumerableThrow({
   1444   getOwnPropertyDescriptor: function(k) { throw "myexn" }
   1445 })
   1446 
   1447 TestIsEnumerableThrow({
   1448   getOwnPropertyDescriptor: function(k) {
   1449     return this.getOwnPropertyDescriptor2(k)
   1450   },
   1451   getOwnPropertyDescriptor2: function(k) { throw "myexn" }
   1452 })
   1453 
   1454 TestIsEnumerableThrow({
   1455   getOwnPropertyDescriptor: function(k) {
   1456     return {get enumerable() { throw "myexn" }, configurable: true}
   1457   },
   1458 })
   1459 
   1460 TestIsEnumerableThrow(new Proxy({}, {
   1461   get: function(pr, pk) { throw "myexn" }
   1462 }))
   1463 
   1464 TestIsEnumerableThrow(new Proxy({}, {
   1465   get: function(pr, pk) {
   1466     return function(k) { throw "myexn" }
   1467   }
   1468 }));
   1469 
   1470 
   1471 
   1472 // ---------------------------------------------------------------------------
   1473 // Constructor functions with proxy prototypes.
   1474 
   1475 (function TestConstructorWithProxyPrototype() {
   1476   TestWithProxies(TestConstructorWithProxyPrototype2, {})
   1477 })();
   1478 
   1479 function TestConstructorWithProxyPrototype2(create, handler) {
   1480   function C() {};
   1481   C.prototype = create(handler);
   1482 
   1483   var o = new C;
   1484   assertSame(C.prototype, Object.getPrototypeOf(o));
   1485 };
   1486 
   1487 
   1488 (function TestOptWithProxyPrototype() {
   1489   var handler = {
   1490     get(t, k) {
   1491       return 10;
   1492     }
   1493   };
   1494 
   1495   function C() {};
   1496   C.prototype = new Proxy({}, handler);
   1497   var o = new C();
   1498 
   1499   function f() {
   1500     return o.x;
   1501   }
   1502   assertEquals(10, f());
   1503   assertEquals(10, f());
   1504   %OptimizeFunctionOnNextCall(f);
   1505   assertEquals(10, f());
   1506 })();
   1507