Proxies
                              are Awesome!
                                    Brendan Eich
                      ...
ECMAScript 5 (ES5)



Tuesday, September 28, 2010
ES5 Review
           • Array extras
           • JSON (based on json2.js)
           • Strict Mode (“use strict”)
       ...
ES5 Property Descriptors
  • Data vs. accessor properties
  • Property attributes
      var point =
        { x: 5,
      ...
Property Descriptor Maps
  var point =
    { x: 5,
      y: 8,
      get r() { return Math.sqrt(this.x*this.x + this.y*thi...
Property Descriptor Maps
  var point =
    { x: 5,
      y: 8,
      get r() { return Math.sqrt(this.x*this.x + this.y*thi...
Tamper-proofing Objects
          var point =
            { x: 5,
              y: 8,
              get r() { return Math.s...
ES-Harmony Proxies



Tuesday, September 28, 2010
Dynamic Proxies

         •    Generic handling of property access:

             •     Generic wrappers: security, aspect...
Example w/ just ES5: logging
   function makePoint(x, y) {
     return {
        x: x,
        y: y,
        ...
     };
 ...
Example w/ just ES5: logging
   function makePoint(x, y) {
     return {
        x: x,
        y: y,
        ...
     };
 ...
Example w/ just ES5: logging
   function makePoint(x, y) {
     return {
        x: x,
        y: y,
        ...
     };
 ...
Logging: static ES5 “proxies”
function makeLogger(obj) {
  var proxy = Object.create(Object.getProtoypeOf(obj), {});
  Obj...
Logging: static ES5 “proxies”
function makeLogger(obj) {
  var proxy = Object.create(Object.getProtoypeOf(obj), {});
  Obj...
Logging: dynamic (harmony) proxies
   function makeLogger(obj) {
     var proxy = Proxy.create({
       get: function(rcvr...
Logging: dynamic (harmony) proxies
   function makeLogger(obj) {
     var proxy = Proxy.create({
       get: function(rcvr...
Stratified API
            var proxy = Proxy.create(handler, proto);



                                                   ...
Stratified API
            var proxy = Proxy.create(handler, proto);


            handler.get(proxy, ‘foo’)
              ...
Stratified API
            var proxy = Proxy.create(handler, proto);


            handler.get(proxy, ‘foo’)
              ...
Stratified API
            var proxy = Proxy.create(handler, proto);


            handler.get(proxy, ‘foo’)
              ...
Stratified API
            var proxy = Proxy.create(handler, proto);


            handler.get(proxy, ‘foo’)
              ...
Stratified API
            var proxy = Proxy.create(handler, proto);


            handler.get(proxy, ‘foo’)
              ...
Not just property accesses
            var proxy = Proxy.create(handler, proto);




                                     ...
Not just property accesses
            var proxy = Proxy.create(handler, proto);

              handler.has(‘foo’)



    ...
Not just property accesses
            var proxy = Proxy.create(handler, proto);

              handler.has(‘foo’)

      ...
Not just property accesses
            var proxy = Proxy.create(handler, proto);

              handler.has(‘foo’)

      ...
Not just property accesses
            var proxy = Proxy.create(handler, proto);

              handler.has(‘foo’)

      ...
But not quite everything, either
            var proxy = Proxy.create(handler, proto);




                               ...
But not quite everything, either
            var proxy = Proxy.create(handler, proto);




                               ...
But not quite everything, either
            var proxy = Proxy.create(handler, proto);




                               ...
But not quite everything, either
            var proxy = Proxy.create(handler, proto);




                               ...
But not quite everything, either
            var proxy = Proxy.create(handler, proto);




                               ...
Full Handler API
                                                            handler


                                pro...
Fundamental vs Derived Traps
                                                         handler


                          ...
Function Proxies
        JavaScript functions are objects. Additionally,
        they are also callable and constructible
...
Function Proxies
        JavaScript functions are objects. Additionally,
        they are also callable and constructible
...
Function Proxies
        JavaScript functions are objects. Additionally,
        they are also callable and constructible
...
Function Proxies
        JavaScript functions are objects. Additionally,
        they are also callable and constructible
...
Function Proxies
        JavaScript functions are objects. Additionally,
        they are also callable and constructible
...
Function Proxies
        JavaScript functions are objects. Additionally,
        they are also callable and constructible
...
Dilemma: Invoke vs Get+Call
               • Fundamental vs derived traps = tradeoff in
                     performance (...
Selective Interception




                                                       meta
                 base




         ...
Selective Interception

                   VM territory (C++)



                                                         ...
Selective Interception

                   VM territory (C++)
                                      VM handler


         ...
Selective Interception

                   VM territory (C++)
                              VM handler   VM handler


    ...
Selective Interception

                   VM territory (C++)
                              VM handler   VM handler       ...
Selective Interception

                   VM territory (C++)
                              VM handler   VM handler       ...
Selective Interception

                   VM territory (C++)                      Self-hosted
                           ...
Selective Interception

                   VM territory (C++)                      Self-hosted
                           ...
Example: no-op forwarding proxy
                                                     handler

    function ForwardingHandl...
Example: counting property access
            function makeSimpleProfiler(target) {
              var forwarder = new Forw...
Example: counting property access
            function makeSimpleProfiler(target) {
              var forwarder = new Forw...
Fixing a Proxy
            var proxy = Proxy.create(handler, proto);



                                                  ...
Fixing a Proxy
            var proxy = Proxy.create(handler, proto);



                                                  ...
Fixing a Proxy
            var proxy = Proxy.create(handler, proto);


           var pdmap = handler.fix();
           if...
Fixing a Proxy
            var proxy = Proxy.create(handler, proto);


           var pdmap = handler.fix();
           if...
Fixing a Proxy
            var proxy = Proxy.create(handler, proto);


           var pdmap = handler.fix();
           if...
Meta-level Shifting
                                                        handler


                              proxy
...
Meta-level Shifting
 a proxy whose                                           μhandler

handler is a proxy
                ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          • Firefox security wrappers (anti-XSS, XUL, etc.)
          • Google Caja: capability-secure ...
Example: Membranes
          function makeSimpleMembrane(initTarget) {
            var enabled = true;




          }

Tu...
Example: Membranes
          function makeSimpleMembrane(initTarget) {
            var enabled = true;




            ret...
Example: Membranes
          function makeSimpleMembrane(initTarget) {
            var enabled = true;




            fun...
Example: Membranes
          function makeSimpleMembrane(initTarget) {
            var enabled = true;




            fun...
Example: Membranes
          function makeSimpleMembrane(initTarget) {
            var enabled = true;
            functio...
Prior Work



                        handler


                                               meta
   base



           ...
Prior Work



                        handler            mirror     ProxyHandler   InvocationHandler


                   ...
Prior Work



                        handler             mirror     ProxyHandler   InvocationHandler


                  ...
Making JavaScript Extensible


          • Extending JavaScript today: “Host objects”
                (the IE DOM; anythin...
Status

         • Presented at ECMA TC-39 meetings
         • Approved for inclusion in ES-Harmony
         • http://wiki...
Lessons for Web Standards
           • Standards need savvy academic research
           • Standards must evolve quickly o...
Micro-benchmark Results




Tuesday, September 28, 2010
Micro-benchmark: Overhead




Tuesday, September 28, 2010
Proxies: Summary

         •    Proxies enable:

             •     Generic wrappers: access control, profiling,
          ...
Conclusions

               • ES5 provides new meta-programming APIs
               • ES-Harmony Proxies: robust dynamic m...
Upcoming SlideShare
Loading in...5
×

Proxies are Awesome!

53,950

Published on

My JSConf.eu talk about next-gen JavaScript metaprogramming features, starting with ES5's new Object APIs and then focusing on the forthcoming Proxy object, approved for the next ECMA-262 Edition. This is beautiful work from Tom Van Cutsem and Mark Miller, with Andreas Gal helping on the implementation front -- proxies are already shipping in Firefox 4 betas.

Published in: Technology
1 Comment
23 Likes
Statistics
Notes
  • Slides 60-73 need a soundtrack :-)
    Why aren't presentations and multimedia in HTML5?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
53,950
On Slideshare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
160
Comments
1
Likes
23
Embeds 0
No embeds

No notes for slide

Transcript of "Proxies are Awesome!"

  1. 1. Proxies are Awesome! Brendan Eich (w/ Mark Miller & Tom Van Cutsem) Tuesday, September 28, 2010
  2. 2. ECMAScript 5 (ES5) Tuesday, September 28, 2010
  3. 3. ES5 Review • Array extras • JSON (based on json2.js) • Strict Mode (“use strict”) • Object meta-programming API • accessor properties (getters & setters) • mutability and enumerability controls • “javascript.lang.reflect” • In Firefox 4, IE9 (w/o strict?), WebKit nightlies Tuesday, September 28, 2010
  4. 4. ES5 Property Descriptors • Data vs. accessor properties • Property attributes var point = { x: 5, y: 8, get r() { return Math.sqrt(this.x*this.x + this.y*this.y); } }; Object.getOwnPropertyDescriptor(point, ‘x’); { value: 5, writable: true, enumerable: true, configurable: true } Object.getOwnPropertyDescriptor(point, ‘r’); { get: function () { return Math.sqrt(this.x*this.x + ...); }, set: undefined, enumerable: true, configurable: true } Tuesday, September 28, 2010
  5. 5. Property Descriptor Maps var point = { x: 5, y: 8, get r() { return Math.sqrt(this.x*this.x + this.y*this.y); } }; Object.defineProperty(point, ‘z’, { value: 0, enumerable: true, writable: false, configurable: false }); var point = Object.create( Object.prototype, { x: { value: 5, ... }, y: { value: 8, ... }, r: { get: function() {...}, enumerable: true, ... }, z: { value: 0, enumerable: true, ... } }); Tuesday, September 28, 2010
  6. 6. Property Descriptor Maps var point = { x: 5, y: 8, get r() { return Math.sqrt(this.x*this.x + this.y*this.y); } }; Object.defineProperty(point, ‘z’, { value: 0, enumerable: true, writable: false, name pd configurable: false }); x {...} y {...} r {...} var point = Object.create( z {...} Object.prototype, { x: { value: 5, ... }, y: { value: 8, ... }, r: { get: function() {...}, enumerable: true, ... }, z: { value: 0, enumerable: true, ... } }); Tuesday, September 28, 2010
  7. 7. Tamper-proofing Objects var point = { x: 5, y: 8, get r() { return Math.sqrt(this.x*this.x + this.y*this.y); } }; Object.preventExtensions(point); point.z = 0; // can’t add new properties Object.seal(point); delete point.x; // can’t delete properties Object.freeze(point); point.x = 7; // can’t assign properties Tuesday, September 28, 2010
  8. 8. ES-Harmony Proxies Tuesday, September 28, 2010
  9. 9. Dynamic Proxies • Generic handling of property access: • Generic wrappers: security, aspects, logging, profiling, ... • Stratified form of SpiderMonkey’s __noSuchMethod__ js> o = {__noSuchMethod__: function (id, args) { print(id, args); }} ({__noSuchMethod__:(function (id, args) {print(id, args);})}) js> o.m(1,2,3) m 1,2,3 • Generic handling of other operations applicable to objects: • Virtual objects: persistent objects, remote objects, ... • Emulate the dreaded “host objects” Tuesday, September 28, 2010
  10. 10. Example w/ just ES5: logging function makePoint(x, y) { return { x: x, y: y, ... }; } Tuesday, September 28, 2010
  11. 11. Example w/ just ES5: logging function makePoint(x, y) { return { x: x, y: y, ... }; } function makeLoggedPoint(p) { return { get x() { log(‘get’,‘x’,p); return p.x; }, set x(v) { log(‘set’,‘x’,p,v); p.x = v; }, // get y, set y, ... }; } var lp = makeLoggedPoint(makePoint(1,2)); Tuesday, September 28, 2010
  12. 12. Example w/ just ES5: logging function makePoint(x, y) { return { x: x, y: y, ... }; } function makeLoggedPoint(p) { return { Too ad hoc. What about: get x() { • logging other data types }, log(‘get’,‘x’,p); return p.x; • profiling, persistence, set x(v) { access control, ... log(‘set’,‘x’,p,v); p.x = v; }, // get y, set y, ... }; } var lp = makeLoggedPoint(makePoint(1,2)); Tuesday, September 28, 2010
  13. 13. Logging: static ES5 “proxies” function makeLogger(obj) { var proxy = Object.create(Object.getProtoypeOf(obj), {}); Object.getOwnPropertyNames(obj).forEach(function(name) { var pd = Object.getOwnPropertyDescriptor(obj, name); Object.defineProperty(proxy, name, { get: function() { log(‘get’, name, obj); return obj[name]; }, set: function(v) { log(‘set’, name, obj, v); obj[name] = v; }, // copy attributes from pd }); }); return proxy; } Tuesday, September 28, 2010
  14. 14. Logging: static ES5 “proxies” function makeLogger(obj) { var proxy = Object.create(Object.getProtoypeOf(obj), {}); Object.getOwnPropertyNames(obj).forEach(function(name) { var pd = Object.getOwnPropertyDescriptor(obj, name); Object.defineProperty(proxy, name, { get: function() { log(‘get’, name, obj); }, return obj[name]; • proxy doesn’t reflect set: function(v) { structural changes made to ‘obj’ log(‘set’, name, obj, v); obj[name] = v; • structural changes made to }, proxy are not reflected in ‘obj’ // copy attributes from pd • structural changes: }); }); • add/delete properties return proxy; • change property attributes } Tuesday, September 28, 2010
  15. 15. Logging: dynamic (harmony) proxies function makeLogger(obj) { var proxy = Proxy.create({ get: function(rcvr, name) { log(‘get’, name, obj); return obj[name]; }, set: function(rcvr, name, val) { log(‘set’, name, obj, val); obj[name] = val; return true; }, ... }, Object.getPrototypeOf(obj)); return proxy; } Tuesday, September 28, 2010
  16. 16. Logging: dynamic (harmony) proxies function makeLogger(obj) { var proxy = Proxy.create({ get: function(rcvr, name) { log(‘get’, name, obj); handler return obj[name]; }, set: function(rcvr, name, val) { meta log(‘set’, name, obj, val); base obj[name] = val; return true; }, ... proxy }, Object.getPrototypeOf(obj)); return proxy; } Tuesday, September 28, 2010
  17. 17. Stratified API var proxy = Proxy.create(handler, proto); handler meta base proxy Tuesday, September 28, 2010
  18. 18. Stratified API var proxy = Proxy.create(handler, proto); handler.get(proxy, ‘foo’) handler meta base proxy.foo proxy Tuesday, September 28, 2010
  19. 19. Stratified API var proxy = Proxy.create(handler, proto); handler.get(proxy, ‘foo’) handler handler.set(proxy, ‘foo’, 42) meta base proxy.foo proxy.foo = 42 proxy Tuesday, September 28, 2010
  20. 20. Stratified API var proxy = Proxy.create(handler, proto); handler.get(proxy, ‘foo’) handler handler.set(proxy, ‘foo’, 42) handler.get(proxy, ‘foo’).apply(proxy,[1,2,3]) meta base proxy.foo proxy.foo = 42 proxy.foo(1,2,3) proxy Tuesday, September 28, 2010
  21. 21. Stratified API var proxy = Proxy.create(handler, proto); handler.get(proxy, ‘foo’) handler handler.set(proxy, ‘foo’, 42) handler.get(proxy, ‘foo’).apply(proxy,[1,2,3]) handler.get(proxy, ‘get’) meta base proxy.foo proxy.foo = 42 proxy.foo(1,2,3) proxy proxy.get Tuesday, September 28, 2010
  22. 22. Stratified API var proxy = Proxy.create(handler, proto); handler.get(proxy, ‘foo’) handler handler.set(proxy, ‘foo’, 42) handler.get(proxy, ‘foo’).apply(proxy,[1,2,3]) handler.get(proxy, ‘get’) meta base proxy.foo proxy.foo = 42 proxy.foo(1,2,3) proxy proto proxy.get Tuesday, September 28, 2010
  23. 23. Not just property accesses var proxy = Proxy.create(handler, proto); handler meta base proxy Tuesday, September 28, 2010
  24. 24. Not just property accesses var proxy = Proxy.create(handler, proto); handler.has(‘foo’) handler meta base ‘foo’ in proxy proxy Tuesday, September 28, 2010
  25. 25. Not just property accesses var proxy = Proxy.create(handler, proto); handler.has(‘foo’) handler.delete(‘foo’) handler meta base ‘foo’ in proxy delete proxy.foo proxy Tuesday, September 28, 2010
  26. 26. Not just property accesses var proxy = Proxy.create(handler, proto); handler.has(‘foo’) handler.delete(‘foo’) var props = handler.enumerate(); handler for (var i=0;i<props.length;i++) { var prop = props[i]; ... } meta base ‘foo’ in proxy delete proxy.foo proxy for (var prop in proxy) { ... } Tuesday, September 28, 2010
  27. 27. Not just property accesses var proxy = Proxy.create(handler, proto); handler.has(‘foo’) handler.delete(‘foo’) var props = handler.enumerate(); handler for (var i=0;i<props.length;i++) { var prop = props[i]; ... } handler.defineProperty(‘foo’, pd) meta base ‘foo’ in proxy delete proxy.foo proxy for (var prop in proxy) { ... } Object.defineProperty(proxy,‘foo’, pd) Tuesday, September 28, 2010
  28. 28. But not quite everything, either var proxy = Proxy.create(handler, proto); handler meta base proxy Tuesday, September 28, 2010
  29. 29. But not quite everything, either var proxy = Proxy.create(handler, proto); handler meta base proxy === obj proxy Tuesday, September 28, 2010
  30. 30. But not quite everything, either var proxy = Proxy.create(handler, proto); handler meta base proxy === obj Object.getPrototypeOf(proxy) => proto proxy proto Tuesday, September 28, 2010
  31. 31. But not quite everything, either var proxy = Proxy.create(handler, proto); handler meta base proxy === obj Object.getPrototypeOf(proxy) => proto proxy proto proxy instanceof SomeFunction Tuesday, September 28, 2010
  32. 32. But not quite everything, either var proxy = Proxy.create(handler, proto); handler meta base proxy === obj Object.getPrototypeOf(proxy) => proto proxy proto proxy instanceof SomeFunction typeof proxy => “object” Tuesday, September 28, 2010
  33. 33. Full Handler API handler proxy Object.getOwnPropertyDescriptor(proxy) handler.getOwnPropertyDescriptor(name) Object.getPropertyDescriptor(proxy) handler.getPropertyDescriptor(name) Object.defineProperty(proxy,name,pd) handler.defineProperty(name, pd) Object.getOwnPropertyNames(proxy)  handler.getOwnPropertyNames() delete proxy.name handler.delete(name)  for (name in proxy) { ... }  handler.enumerate() Object.{freeze|seal|...}(proxy) handler.fix() name in proxy handler.has(name) ({}).hasOwnProperty.call(proxy, name) handler.hasOwn(name) receiver.name handler.get(receiver, name) receiver.name = val handler.set(receiver, name, val) Object.keys(proxy) handler.keys() for (name in proxy) { ... } handler.iterate() Tuesday, September 28, 2010
  34. 34. Fundamental vs Derived Traps handler proxy Fundamental traps Object.getOwnPropertyDescriptor(proxy) handler.getOwnPropertyDescriptor(name) Object.getPropertyDescriptor(proxy) handler.getPropertyDescriptor(name) Object.defineProperty(proxy,name,pd) handler.defineProperty(name, pd) Object.getOwnPropertyNames(proxy)  handler.getOwnPropertyNames() delete proxy.name handler.delete(name)  for (name in proxy) { ... }  handler.enumerate() -> [string] Object.{freeze|seal|...}(proxy) handler.fix() Derived traps name in proxy handler.has(name) ({}).hasOwnProperty.call(proxy, name) handler.hasOwn(name) receiver.name handler.get(receiver, name) receiver.name = val handler.set(receiver, name, val) Object.keys(proxy) handler.keys() for (name in proxy) { ... } handler.iterate() -> iterator Tuesday, September 28, 2010
  35. 35. Function Proxies JavaScript functions are objects. Additionally, they are also callable and constructible var call = function() { ... }; var construct = function() { ... }; var funproxy = Proxy.createFunction(handler, call, construct); handler call construct funproxy Tuesday, September 28, 2010
  36. 36. Function Proxies JavaScript functions are objects. Additionally, they are also callable and constructible var call = function() { ... }; var construct = function() { ... }; var funproxy = Proxy.createFunction(handler, call, construct); call(1,2,3) handler call construct funproxy(1,2,3) funproxy Tuesday, September 28, 2010
  37. 37. Function Proxies JavaScript functions are objects. Additionally, they are also callable and constructible var call = function() { ... }; var construct = function() { ... }; var funproxy = Proxy.createFunction(handler, call, construct); call(1,2,3) handler call construct construct(1,2,3) funproxy(1,2,3) new funproxy(1,2,3) funproxy Tuesday, September 28, 2010
  38. 38. Function Proxies JavaScript functions are objects. Additionally, they are also callable and constructible var call = function() { ... }; var construct = function() { ... }; var funproxy = Proxy.createFunction(handler, call, construct); call(1,2,3) handler call construct construct(1,2,3) handler.get(funproxy,‘prototype’) funproxy(1,2,3) new funproxy(1,2,3) funproxy.prototype funproxy Tuesday, September 28, 2010
  39. 39. Function Proxies JavaScript functions are objects. Additionally, they are also callable and constructible var call = function() { ... }; var construct = function() { ... }; var funproxy = Proxy.createFunction(handler, call, construct); call(1,2,3) handler call construct construct(1,2,3) handler.get(funproxy,‘prototype’) funproxy(1,2,3) new funproxy(1,2,3) funproxy.prototype funproxy typeof funproxy => “function” Tuesday, September 28, 2010
  40. 40. Function Proxies JavaScript functions are objects. Additionally, they are also callable and constructible var call = function() { ... }; var construct = function() { ... }; var funproxy = Proxy.createFunction(handler, call, construct); call(1,2,3) handler call construct construct(1,2,3) handler.get(funproxy,‘prototype’) funproxy(1,2,3) new funproxy(1,2,3) funproxy.prototype funproxy typeof funproxy => “function” Object.getPrototypeOf(funproxy) => Function.prototype Tuesday, September 28, 2010
  41. 41. Dilemma: Invoke vs Get+Call • Fundamental vs derived traps = tradeoff in performance (method allocation or caching) vs. consistency var p = Proxy.create({   get:    function(receiver, name) { ... },   invoke: function(receiver, name, args) { ... },   ... }); p.x; // get(p,'x') p.m(a); // invoke(p, 'm', [a]) • invoke can intercept arguments • but notably, JS methods can be extracted as functions and called later (functional FTW!) • breaks invariant o.m.call(o) <=> o.m() Tuesday, September 28, 2010
  42. 42. Selective Interception meta base object Tuesday, September 28, 2010
  43. 43. Selective Interception VM territory (C++) meta base object JavaScript territory Tuesday, September 28, 2010
  44. 44. Selective Interception VM territory (C++) VM handler meta base object JavaScript territory Tuesday, September 28, 2010
  45. 45. Selective Interception VM territory (C++) VM handler VM handler meta base host object object JavaScript territory Tuesday, September 28, 2010
  46. 46. Selective Interception VM territory (C++) VM handler VM handler handler meta base host object object proxy JavaScript territory Tuesday, September 28, 2010
  47. 47. Selective Interception VM territory (C++) VM handler VM handler handler meta base host object object proxy JavaScript territory Tuesday, September 28, 2010
  48. 48. Selective Interception VM territory (C++) Self-hosted VM handler VM handler handler meta base host object object proxy JavaScript territory Tuesday, September 28, 2010
  49. 49. Selective Interception VM territory (C++) Self-hosted VM handler VM handler handler meta base host object object proxy JavaScript territory Tuesday, September 28, 2010
  50. 50. Example: no-op forwarding proxy handler function ForwardingHandler(obj) { this.target = obj; proxy target } ForwardingHandler.prototype = {   has: function(name) { return name in this.target; },   get: function(rcvr,name) { return this.target[name]; },   set: function(rcvr,name,val) { this.target[name]=val;return true; },   delete: function(name) { return delete this.target[name]; }   enumerate: function() {     var props = []; for (name in this.target) { props.push(name); }; return props;   }, ... } var proxy = Proxy.create(new ForwardingHandler(o),                          Object.getPrototypeOf(o)); Tuesday, September 28, 2010
  51. 51. Example: counting property access function makeSimpleProfiler(target) { var forwarder = new ForwardingHandler(target); var count = Object.create(null); forwarder.get = function(rcvr, name) { count[name] = (count[name] || 0) + 1; return this.target[name]; }; return { proxy: Proxy.create(forwarder, Object.getPrototypeOf(target)), get stats() { return count; } } } Tuesday, September 28, 2010
  52. 52. Example: counting property access function makeSimpleProfiler(target) { var forwarder = new ForwardingHandler(target); var count = Object.create(null); forwarder.get = function(rcvr, name) { count[name] = (count[name] || 0) + 1; return this.target[name]; }; return { proxy: Proxy.create(forwarder, Object.getPrototypeOf(target)), get stats() { return count; } } } var subject = { ... }; var profiler = makeSimpleProfiler(subject); runApp(profiler.proxy); display(profiler.stats); Tuesday, September 28, 2010
  53. 53. Fixing a Proxy var proxy = Proxy.create(handler, proto); handler meta base proxy Tuesday, September 28, 2010
  54. 54. Fixing a Proxy var proxy = Proxy.create(handler, proto); handler meta base Object.freeze(proxy) Object.seal(proxy) proxy Object.preventExtensions(proxy) Tuesday, September 28, 2010
  55. 55. Fixing a Proxy var proxy = Proxy.create(handler, proto); var pdmap = handler.fix(); if (pdmap === undefined) throw TypeError(); handler become(proxy, Object.freeze( Object.create(proto, pdmap))); meta base Object.freeze(proxy) Object.seal(proxy) proxy Object.preventExtensions(proxy) Tuesday, September 28, 2010
  56. 56. Fixing a Proxy var proxy = Proxy.create(handler, proto); var pdmap = handler.fix(); if (pdmap === undefined) throw TypeError(); handler become(proxy, Object.freeze( Object.create(proto, pdmap))); meta base Object.freeze(proxy) Object.seal(proxy) proxy Object.preventExtensions(proxy) fix Trapping Fixed Tuesday, September 28, 2010
  57. 57. Fixing a Proxy var proxy = Proxy.create(handler, proto); var pdmap = handler.fix(); if (pdmap === undefined) throw TypeError(); become(proxy, Object.freeze( Object.create(proto, pdmap))); meta base Object.freeze(proxy) Object.seal(proxy) proxy Object.preventExtensions(proxy) fix Trapping Fixed Tuesday, September 28, 2010
  58. 58. Meta-level Shifting handler proxy Object.getOwnPropertyDescriptor(proxy) handler.getOwnPropertyDescriptor(name) Object.getPropertyDescriptor(proxy) handler.getPropertyDescriptor(name) Object.defineProperty(proxy,name,pd) handler.defineProperty(name, pd) Object.getOwnPropertyNames(proxy)  handler.getOwnPropertyNames() delete proxy.name handler.delete(name)  for (name in proxy) { ... }  handler.enumerate() Object.{freeze|seal|...}(proxy) handler.fix() name in proxy handler.has(name) ({}).hasOwnProperty.call(proxy, name) handler.hasOwn(name) receiver.name handler.get(receiver, name) receiver.name = val handler.set(receiver, name, val) Object.keys(proxy) handler.keys() for (name in proxy) { ... }  handler.iterate() base-level: many operations meta-level: all operations reified as on objects invocations of traps Tuesday, September 28, 2010
  59. 59. Meta-level Shifting a proxy whose μhandler handler is a proxy handler handler.getOwnPropertyDescriptor(name) μhandler.get(handler, ‘getOwnP..’)(name) handler.getPropertyDescriptor(name) μhandler.get(handler, ‘getProp..’)(name) handler.defineOwnProperty(name, pd) μhandler.get(handler, ‘define...’)(name,pd) handler.delete(name)  μhandler.get(handler, ‘delete’)(name) handler.getOwnPropertyNames() μhandler.get(handler, ‘getOwnP..’)() handler.enumerate() μhandler.get(handler, ‘enumerate’)() handler.fix() μhandler.get(handler, ‘fix’)() handler.has(name) μhandler.get(handler, ‘has’)(name) handler.hasOwn(name) μhandler.get(handler, ‘hasOwn’)(name) handler.get(receiver, name) μhandler.get(handler, ‘get’)(receiver,name) handler.set(receiver, name, val) μhandler.get(handler, ‘set’)(receiver,name,val) handler.keys() μhandler.get(handler, ‘keys’)() handler.iterate() μhandler.get(handler, ‘iterate’)() meta-level: all operations reified as meta-meta-level: all operations invocations of traps reified as invocations of ‘get’ trap Tuesday, September 28, 2010
  60. 60. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  61. 61. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  62. 62. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  63. 63. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  64. 64. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  65. 65. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  66. 66. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  67. 67. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  68. 68. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  69. 69. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  70. 70. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  71. 71. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  72. 72. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  73. 73. Example: Membranes • Firefox security wrappers (anti-XSS, XUL, etc.) • Google Caja: capability-secure subset • Object-capability model: an object is powerless unless given a reference to other objects • References can be made revocable through a membrane Tuesday, September 28, 2010
  74. 74. Example: Membranes function makeSimpleMembrane(initTarget) {   var enabled = true; } Tuesday, September 28, 2010
  75. 75. Example: Membranes function makeSimpleMembrane(initTarget) {   var enabled = true;   return { wrapper: wrap(initTarget), revoke: function() { enabled = false; } }; } Tuesday, September 28, 2010
  76. 76. Example: Membranes function makeSimpleMembrane(initTarget) {   var enabled = true;   function wrap(target) {     if (Object.isPrimitive(target)) { return target; }     var baseHandler = new ForwardingHandler(target);     var revokeHandler = Proxy.create({       get: function(rcvr, name) { return wrapFunction(baseHandler[name]); }     });   }   return { wrapper: wrap(initTarget), revoke: function() { enabled = false; } }; } Tuesday, September 28, 2010
  77. 77. Example: Membranes function makeSimpleMembrane(initTarget) {   var enabled = true;   function wrap(target) {     if (Object.isPrimitive(target)) { return target; }     var baseHandler = new ForwardingHandler(target);     var revokeHandler = Proxy.create({       get: function(rcvr, name) { return wrapFunction(baseHandler[name]); }     }); if (typeof target === “function”) { return Proxy.createFunction(revokeHandler, wrapFunction(target)); }     return Proxy.create(revokeHandler, wrap(Object.getPrototypeOf(target)));   }   return { wrapper: wrap(initTarget), revoke: function() { enabled = false; } }; } Tuesday, September 28, 2010
  78. 78. Example: Membranes function makeSimpleMembrane(initTarget) {   var enabled = true; function wrapFunction(f) {     return function() { // variable-argument function if (!enabled) { throw new Error("revoked"); }      return wrap(f.apply(wrap(this), arguments.map(wrap))); } }   function wrap(target) {     if (Object.isPrimitive(target)) { return target; }     var baseHandler = new ForwardingHandler(target);     var revokeHandler = Proxy.create({       get: function(rcvr, name) { return wrapFunction(baseHandler[name]); }     }); if (typeof target === “function”) { return Proxy.createFunction(revokeHandler, wrapFunction(target)); }     return Proxy.create(revokeHandler, wrap(Object.getPrototypeOf(target)));   }   return { wrapper: wrap(initTarget), revoke: function() { enabled = false; } }; } Tuesday, September 28, 2010
  79. 79. Prior Work handler meta base proxy Tuesday, September 28, 2010
  80. 80. Prior Work handler mirror ProxyHandler InvocationHandler meta base proxy mirage proxy java.lang.reflect.Proxy Tuesday, September 28, 2010
  81. 81. Prior Work handler mirror ProxyHandler InvocationHandler meta base proxy mirage proxy java.lang.reflect.Proxy # traps 13 30 3 1 Tuesday, September 28, 2010
  82. 82. Making JavaScript Extensible • Extending JavaScript today: “Host objects” (the IE DOM; anything implemented in C++) • Proxies are sufficiently powerful to emulate most of the behavior of host objects in JavaScript itself • Two possible avenues to close the gap: • Make proxies even more powerful • Make host objects only as powerful as proxies Tuesday, September 28, 2010
  83. 83. Status • Presented at ECMA TC-39 meetings • Approved for inclusion in ES-Harmony • http://wiki.ecmascript.org/doku.php? id=harmony:proxies • In Firefox 4 already, thanks to Andreas Gal! • The basis of all of Gecko’s security wrappers • Used by Zaphod (Narcissus as JS engine add-on, source at http://github.com/taustin/Zaphod/) Tuesday, September 28, 2010
  84. 84. Lessons for Web Standards • Standards need savvy academic research • Standards must evolve quickly on the Web • They can’t evolve without prototype trials • These experiments need tons of user-testing • To reach users at scale, prototypes must ship • Ecma TC39 committed to prototyping specs before finalizing standards • Committee members work together, no blind-siding, to uphold Harmony (it’s social!) Tuesday, September 28, 2010
  85. 85. Micro-benchmark Results Tuesday, September 28, 2010
  86. 86. Micro-benchmark: Overhead Tuesday, September 28, 2010
  87. 87. Proxies: Summary • Proxies enable: • Generic wrappers: access control, profiling, adaptors, test injection, etc. • Virtual objects: persistent objects, remote objects, emulated host objects, ... • API: • Robust: stratified, not all operations intercepted • Secure: can’t trap non-proxy or fixed objects • Performance: no overhead for non-proxy objects Tuesday, September 28, 2010
  88. 88. Conclusions • ES5 provides new meta-programming APIs • ES-Harmony Proxies: robust dynamic meta- programming for virtual objects, wrappers • Proxies help put developers in control of extending JavaScript, instead of Ecma TC39 • JavaScript: the Revenge of Smalltalk! Tuesday, September 28, 2010
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×