~ubuntu-branches/ubuntu/trusty/libv8/trusty

« back to all changes in this revision

Viewing changes to test/mjsunit/harmony/proxies-example-membrane.js

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2012-02-20 14:08:17 UTC
  • mfrom: (15.1.24 sid)
  • Revision ID: package-import@ubuntu.com-20120220140817-bsvmeoa4sxsj5hbz
Tags: 3.7.12.22-3
Fix mipsel build, allow test debug-step-3 to fail (non-crucial)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
29
 
 
30
 
 
31
// A simple no-op handler. Adapted from:
 
32
// http://wiki.ecmascript.org/doku.php?id=harmony:proxies#examplea_no-op_forwarding_proxy
 
33
 
 
34
function createHandler(obj) {
 
35
  return {
 
36
    getOwnPropertyDescriptor: function(name) {
 
37
      var desc = Object.getOwnPropertyDescriptor(obj, name);
 
38
      if (desc !== undefined) desc.configurable = true;
 
39
      return desc;
 
40
    },
 
41
    getPropertyDescriptor: function(name) {
 
42
      var desc = Object.getOwnPropertyDescriptor(obj, name);
 
43
      //var desc = Object.getPropertyDescriptor(obj, name);  // not in ES5
 
44
      if (desc !== undefined) desc.configurable = true;
 
45
      return desc;
 
46
    },
 
47
    getOwnPropertyNames: function() {
 
48
      return Object.getOwnPropertyNames(obj);
 
49
    },
 
50
    getPropertyNames: function() {
 
51
      return Object.getOwnPropertyNames(obj);
 
52
      //return Object.getPropertyNames(obj);  // not in ES5
 
53
    },
 
54
    defineProperty: function(name, desc) {
 
55
      Object.defineProperty(obj, name, desc);
 
56
    },
 
57
    delete: function(name) {
 
58
      return delete obj[name];
 
59
    },
 
60
    fix: function() {
 
61
      if (Object.isFrozen(obj)) {
 
62
        var result = {};
 
63
        Object.getOwnPropertyNames(obj).forEach(function(name) {
 
64
          result[name] = Object.getOwnPropertyDescriptor(obj, name);
 
65
        });
 
66
        return result;
 
67
      }
 
68
      // As long as obj is not frozen, the proxy won't allow itself to be fixed
 
69
      return undefined; // will cause a TypeError to be thrown
 
70
    },
 
71
    has: function(name) { return name in obj; },
 
72
    hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
 
73
    get: function(receiver, name) { return obj[name]; },
 
74
    set: function(receiver, name, val) {
 
75
      obj[name] = val;  // bad behavior when set fails in non-strict mode
 
76
      return true;
 
77
    },
 
78
    enumerate: function() {
 
79
      var result = [];
 
80
      for (var name in obj) { result.push(name); };
 
81
      return result;
 
82
    },
 
83
    keys: function() { return Object.keys(obj); }
 
84
  };
 
85
}
 
86
 
 
87
 
 
88
 
 
89
// Auxiliary definitions enabling tracking of object identity in output.
 
90
 
 
91
var objectMap = new WeakMap;
 
92
var objectCounter = 0;
 
93
 
 
94
function registerObject(x, s) {
 
95
  if (x === Object(x) && !objectMap.has(x))
 
96
    objectMap.set(x, ++objectCounter + (s == undefined ? "" : ":" + s));
 
97
}
 
98
 
 
99
registerObject(this, "global");
 
100
registerObject(Object.prototype, "Object.prototype");
 
101
 
 
102
function str(x) {
 
103
  if (x === Object(x)) return "[" + typeof x + " " + objectMap.get(x) + "]";
 
104
  if (typeof x == "string") return "\"" + x + "\"";
 
105
  return "" + x;
 
106
}
 
107
 
 
108
 
 
109
 
 
110
// A simple membrane. Adapted from:
 
111
// http://wiki.ecmascript.org/doku.php?id=harmony:proxies#a_simple_membrane
 
112
 
 
113
function createSimpleMembrane(target) {
 
114
  var enabled = true;
 
115
 
 
116
  function wrap(obj) {
 
117
    registerObject(obj);
 
118
    print("wrap enter", str(obj));
 
119
    try {
 
120
      var x = wrap2(obj);
 
121
      registerObject(x, "wrapped");
 
122
      print("wrap exit", str(obj), "as", str(x));
 
123
      return x;
 
124
    } catch(e) {
 
125
      print("wrap exception", str(e));
 
126
      throw e;
 
127
    }
 
128
  }
 
129
 
 
130
  function wrap2(obj) {
 
131
    if (obj !== Object(obj)) {
 
132
      return obj;
 
133
    }
 
134
 
 
135
    function wrapCall(fun, that, args) {
 
136
      registerObject(that);
 
137
      print("wrapCall enter", fun, str(that));
 
138
      try {
 
139
        var x = wrapCall2(fun, that, args);
 
140
        print("wrapCall exit", fun, str(that), "returning", str(x));
 
141
        return x;
 
142
      } catch(e) {
 
143
        print("wrapCall exception", fun, str(that), str(e));
 
144
        throw e;
 
145
      }
 
146
    }
 
147
 
 
148
    function wrapCall2(fun, that, args) {
 
149
      if (!enabled) { throw new Error("disabled"); }
 
150
      try {
 
151
        return wrap(fun.apply(that, Array.prototype.map.call(args, wrap)));
 
152
      } catch (e) {
 
153
        throw wrap(e);
 
154
      }
 
155
    }
 
156
 
 
157
    var baseHandler = createHandler(obj);
 
158
    var handler = Proxy.create(Object.freeze({
 
159
      get: function(receiver, name) {
 
160
        return function() {
 
161
          var arg = (name === "get" || name == "set") ? arguments[1] : "";
 
162
          print("handler enter", name, arg);
 
163
          var x = wrapCall(baseHandler[name], baseHandler, arguments);
 
164
          print("handler exit", name, arg, "returning", str(x));
 
165
          return x;
 
166
        }
 
167
      }
 
168
    }));
 
169
    registerObject(baseHandler, "basehandler");
 
170
    registerObject(handler, "handler");
 
171
 
 
172
    if (typeof obj === "function") {
 
173
      function callTrap() {
 
174
        print("call trap enter", str(obj), str(this));
 
175
        var x = wrapCall(obj, wrap(this), arguments);
 
176
        print("call trap exit", str(obj), str(this), "returning", str(x));
 
177
        return x;
 
178
      }
 
179
      function constructTrap() {
 
180
        if (!enabled) { throw new Error("disabled"); }
 
181
        try {
 
182
          function forward(args) { return obj.apply(this, args) }
 
183
          return wrap(new forward(Array.prototype.map.call(arguments, wrap)));
 
184
        } catch (e) {
 
185
          throw wrap(e);
 
186
        }
 
187
      }
 
188
      return Proxy.createFunction(handler, callTrap, constructTrap);
 
189
    } else {
 
190
      var prototype = wrap(Object.getPrototypeOf(obj));
 
191
      return Proxy.create(handler, prototype);
 
192
    }
 
193
  }
 
194
 
 
195
  var gate = Object.freeze({
 
196
    enable: function() { enabled = true; },
 
197
    disable: function() { enabled = false; }
 
198
  });
 
199
 
 
200
  return Object.freeze({
 
201
    wrapper: wrap(target),
 
202
    gate: gate
 
203
  });
 
204
}
 
205
 
 
206
 
 
207
var o = {
 
208
  a: 6,
 
209
  b: {bb: 8},
 
210
  f: function(x) { return x },
 
211
  g: function(x) { return x.a },
 
212
  h: function(x) { this.q = x }
 
213
};
 
214
o[2] = {c: 7};
 
215
var m = createSimpleMembrane(o);
 
216
var w = m.wrapper;
 
217
print("o =", str(o))
 
218
print("w =", str(w));
 
219
 
 
220
var f = w.f;
 
221
var x = f(66);
 
222
var x = f({a: 1});
 
223
var x = w.f({a: 1});
 
224
var a = x.a;
 
225
assertEquals(6, w.a);
 
226
assertEquals(8, w.b.bb);
 
227
assertEquals(7, w[2]["c"]);
 
228
assertEquals(undefined, w.c);
 
229
assertEquals(1, w.f(1));
 
230
assertEquals(1, w.f({a: 1}).a);
 
231
assertEquals(2, w.g({a: 2}));
 
232
assertEquals(3, (w.r = {a: 3}).a);
 
233
assertEquals(3, w.r.a);
 
234
assertEquals(3, o.r.a);
 
235
w.h(3);
 
236
assertEquals(3, w.q);
 
237
assertEquals(3, o.q);
 
238
assertEquals(4, (new w.h(4)).q);
 
239
 
 
240
var wb = w.b;
 
241
var wr = w.r;
 
242
var wf = w.f;
 
243
var wf3 = w.f(3);
 
244
var wfx = w.f({a: 6});
 
245
var wgx = w.g({a: {aa: 7}});
 
246
var wh4 = new w.h(4);
 
247
m.gate.disable();
 
248
assertEquals(3, wf3);
 
249
assertThrows(function() { w.a }, Error);
 
250
assertThrows(function() { w.r }, Error);
 
251
assertThrows(function() { w.r = {a: 4} }, Error);
 
252
assertThrows(function() { o.r.a }, Error);
 
253
assertEquals("object", typeof o.r);
 
254
assertEquals(5, (o.r = {a: 5}).a);
 
255
assertEquals(5, o.r.a);
 
256
assertThrows(function() { w[1] }, Error);
 
257
assertThrows(function() { w.c }, Error);
 
258
assertThrows(function() { wb.bb }, Error);
 
259
assertThrows(function() { wr.a }, Error);
 
260
assertThrows(function() { wf(4) }, Error);
 
261
assertThrows(function() { wfx.a }, Error);
 
262
assertThrows(function() { wgx.aa }, Error);
 
263
assertThrows(function() { wh4.q }, Error);
 
264
 
 
265
m.gate.enable();
 
266
assertEquals(6, w.a);
 
267
assertEquals(5, w.r.a);
 
268
assertEquals(5, o.r.a);
 
269
assertEquals(7, w.r = 7);
 
270
assertEquals(7, w.r);
 
271
assertEquals(7, o.r);
 
272
assertEquals(8, w.b.bb);
 
273
assertEquals(7, w[2]["c"]);
 
274
assertEquals(undefined, w.c);
 
275
assertEquals(8, wb.bb);
 
276
assertEquals(3, wr.a);
 
277
assertEquals(4, wf(4));
 
278
assertEquals(3, wf3);
 
279
assertEquals(6, wfx.a);
 
280
assertEquals(7, wgx.aa);
 
281
assertEquals(4, wh4.q);
 
282
 
 
283
 
 
284
// An identity-preserving membrane. Adapted from:
 
285
// http://wiki.ecmascript.org/doku.php?id=harmony:proxies#an_identity-preserving_membrane
 
286
 
 
287
function createMembrane(wetTarget) {
 
288
  var wet2dry = WeakMap();
 
289
  var dry2wet = WeakMap();
 
290
 
 
291
  function asDry(obj) {
 
292
    registerObject(obj)
 
293
    print("asDry enter", str(obj))
 
294
    try {
 
295
      var x = asDry2(obj);
 
296
      registerObject(x, "dry");
 
297
      print("asDry exit", str(obj), "as", str(x));
 
298
      return x;
 
299
    } catch(e) {
 
300
      print("asDry exception", str(e));
 
301
      throw e;
 
302
    }
 
303
  }
 
304
  function asDry2(wet) {
 
305
    if (wet !== Object(wet)) {
 
306
      // primitives provide only irrevocable knowledge, so don't
 
307
      // bother wrapping it.
 
308
      return wet;
 
309
    }
 
310
    var dryResult = wet2dry.get(wet);
 
311
    if (dryResult) { return dryResult; }
 
312
 
 
313
    var wetHandler = createHandler(wet);
 
314
    var dryRevokeHandler = Proxy.create(Object.freeze({
 
315
      get: function(receiver, name) {
 
316
        return function() {
 
317
          var arg = (name === "get" || name == "set") ? arguments[1] : "";
 
318
          print("dry handler enter", name, arg);
 
319
          var optWetHandler = dry2wet.get(dryRevokeHandler);
 
320
          try {
 
321
            var x = asDry(optWetHandler[name].apply(
 
322
              optWetHandler, Array.prototype.map.call(arguments, asWet)));
 
323
            print("dry handler exit", name, arg, "returning", str(x));
 
324
            return x;
 
325
          } catch (eWet) {
 
326
            var x = asDry(eWet);
 
327
            print("dry handler exception", name, arg, "throwing", str(x));
 
328
            throw x;
 
329
          }
 
330
        };
 
331
      }
 
332
    }));
 
333
    dry2wet.set(dryRevokeHandler, wetHandler);
 
334
 
 
335
    if (typeof wet === "function") {
 
336
      function callTrap() {
 
337
        print("dry call trap enter", str(this));
 
338
        var x = asDry(wet.apply(
 
339
          asWet(this), Array.prototype.map.call(arguments, asWet)));
 
340
        print("dry call trap exit", str(this), "returning", str(x));
 
341
        return x;
 
342
      }
 
343
      function constructTrap() {
 
344
        function forward(args) { return wet.apply(this, args) }
 
345
        return asDry(new forward(Array.prototype.map.call(arguments, asWet)));
 
346
      }
 
347
      dryResult =
 
348
        Proxy.createFunction(dryRevokeHandler, callTrap, constructTrap);
 
349
    } else {
 
350
      dryResult =
 
351
        Proxy.create(dryRevokeHandler, asDry(Object.getPrototypeOf(wet)));
 
352
    }
 
353
    wet2dry.set(wet, dryResult);
 
354
    dry2wet.set(dryResult, wet);
 
355
    return dryResult;
 
356
  }
 
357
 
 
358
  function asWet(obj) {
 
359
    registerObject(obj)
 
360
    print("asWet enter", str(obj))
 
361
    try {
 
362
      var x = asWet2(obj)
 
363
      registerObject(x, "wet")
 
364
      print("asWet exit", str(obj), "as", str(x))
 
365
      return x
 
366
    } catch(e) {
 
367
      print("asWet exception", str(e))
 
368
      throw e
 
369
    }
 
370
  }
 
371
  function asWet2(dry) {
 
372
    if (dry !== Object(dry)) {
 
373
      // primitives provide only irrevocable knowledge, so don't
 
374
      // bother wrapping it.
 
375
      return dry;
 
376
    }
 
377
    var wetResult = dry2wet.get(dry);
 
378
    if (wetResult) { return wetResult; }
 
379
 
 
380
    var dryHandler = createHandler(dry);
 
381
    var wetRevokeHandler = Proxy.create(Object.freeze({
 
382
      get: function(receiver, name) {
 
383
        return function() {
 
384
          var arg = (name === "get" || name == "set") ? arguments[1] : "";
 
385
          print("wet handler enter", name, arg);
 
386
          var optDryHandler = wet2dry.get(wetRevokeHandler);
 
387
          try {
 
388
            var x = asWet(optDryHandler[name].apply(
 
389
              optDryHandler, Array.prototype.map.call(arguments, asDry)));
 
390
            print("wet handler exit", name, arg, "returning", str(x));
 
391
            return x;
 
392
          } catch (eDry) {
 
393
            var x = asWet(eDry);
 
394
            print("wet handler exception", name, arg, "throwing", str(x));
 
395
            throw x;
 
396
          }
 
397
        };
 
398
      }
 
399
    }));
 
400
    wet2dry.set(wetRevokeHandler, dryHandler);
 
401
 
 
402
    if (typeof dry === "function") {
 
403
      function callTrap() {
 
404
        print("wet call trap enter", str(this));
 
405
        var x = asWet(dry.apply(
 
406
          asDry(this), Array.prototype.map.call(arguments, asDry)));
 
407
        print("wet call trap exit", str(this), "returning", str(x));
 
408
        return x;
 
409
      }
 
410
      function constructTrap() {
 
411
        function forward(args) { return dry.apply(this, args) }
 
412
        return asWet(new forward(Array.prototype.map.call(arguments, asDry)));
 
413
      }
 
414
      wetResult =
 
415
        Proxy.createFunction(wetRevokeHandler, callTrap, constructTrap);
 
416
    } else {
 
417
      wetResult =
 
418
        Proxy.create(wetRevokeHandler, asWet(Object.getPrototypeOf(dry)));
 
419
    }
 
420
    dry2wet.set(dry, wetResult);
 
421
    wet2dry.set(wetResult, dry);
 
422
    return wetResult;
 
423
  }
 
424
 
 
425
  var gate = Object.freeze({
 
426
    revoke: function() {
 
427
      dry2wet = wet2dry = Object.freeze({
 
428
        get: function(key) { throw new Error("revoked"); },
 
429
        set: function(key, val) { throw new Error("revoked"); }
 
430
      });
 
431
    }
 
432
  });
 
433
 
 
434
  return Object.freeze({ wrapper: asDry(wetTarget), gate: gate });
 
435
}
 
436
 
 
437
 
 
438
var receiver
 
439
var argument
 
440
var o = {
 
441
  a: 6,
 
442
  b: {bb: 8},
 
443
  f: function(x) { receiver = this; argument = x; return x },
 
444
  g: function(x) { receiver = this; argument = x; return x.a },
 
445
  h: function(x) { receiver = this; argument = x; this.q = x },
 
446
  s: function(x) { receiver = this; argument = x; this.x = {y: x}; return this }
 
447
}
 
448
o[2] = {c: 7}
 
449
var m = createMembrane(o)
 
450
var w = m.wrapper
 
451
print("o =", str(o))
 
452
print("w =", str(w))
 
453
 
 
454
var f = w.f
 
455
var x = f(66)
 
456
var x = f({a: 1})
 
457
var x = w.f({a: 1})
 
458
var a = x.a
 
459
assertEquals(6, w.a)
 
460
assertEquals(8, w.b.bb)
 
461
assertEquals(7, w[2]["c"])
 
462
assertEquals(undefined, w.c)
 
463
assertEquals(1, w.f(1))
 
464
assertSame(o, receiver)
 
465
assertEquals(1, w.f({a: 1}).a)
 
466
assertSame(o, receiver)
 
467
assertEquals(2, w.g({a: 2}))
 
468
assertSame(o, receiver)
 
469
assertSame(w, w.f(w))
 
470
assertSame(o, receiver)
 
471
assertSame(o, argument)
 
472
assertSame(o, w.f(o))
 
473
assertSame(o, receiver)
 
474
// Note that argument !== o, since o isn't dry, so gets wrapped wet again.
 
475
assertEquals(3, (w.r = {a: 3}).a)
 
476
assertEquals(3, w.r.a)
 
477
assertEquals(3, o.r.a)
 
478
w.h(3)
 
479
assertEquals(3, w.q)
 
480
assertEquals(3, o.q)
 
481
assertEquals(4, (new w.h(4)).q)
 
482
assertEquals(5, w.s(5).x.y)
 
483
assertSame(o, receiver)
 
484
 
 
485
var wb = w.b
 
486
var wr = w.r
 
487
var wf = w.f
 
488
var wf3 = w.f(3)
 
489
var wfx = w.f({a: 6})
 
490
var wgx = w.g({a: {aa: 7}})
 
491
var wh4 = new w.h(4)
 
492
var ws5 = w.s(5)
 
493
var ws5x = ws5.x
 
494
m.gate.revoke()
 
495
assertEquals(3, wf3)
 
496
assertThrows(function() { w.a }, Error)
 
497
assertThrows(function() { w.r }, Error)
 
498
assertThrows(function() { w.r = {a: 4} }, Error)
 
499
assertThrows(function() { o.r.a }, Error)
 
500
assertEquals("object", typeof o.r)
 
501
assertEquals(5, (o.r = {a: 5}).a)
 
502
assertEquals(5, o.r.a)
 
503
assertThrows(function() { w[1] }, Error)
 
504
assertThrows(function() { w.c }, Error)
 
505
assertThrows(function() { wb.bb }, Error)
 
506
assertEquals(3, wr.a)
 
507
assertThrows(function() { wf(4) }, Error)
 
508
assertEquals(6, wfx.a)
 
509
assertEquals(7, wgx.aa)
 
510
assertThrows(function() { wh4.q }, Error)
 
511
assertThrows(function() { ws5.x }, Error)
 
512
assertThrows(function() { ws5x.y }, Error)