SlideShare a Scribd company logo
Proxies
                              are Awesome!
                                    Brendan Eich
                          (w/ Mark Miller & Tom Van Cutsem)




Tuesday, September 28, 2010
ECMAScript 5 (ES5)



Tuesday, September 28, 2010
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
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
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
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
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
ES-Harmony Proxies



Tuesday, September 28, 2010
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
Example w/ just ES5: logging
   function makePoint(x, y) {
     return {
        x: x,
        y: y,
        ...
     };
   }




Tuesday, September 28, 2010
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
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
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
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
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
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
Stratified API
            var proxy = Proxy.create(handler, proto);



                                                                handler


                                                                          meta
          base




                                                        proxy




Tuesday, September 28, 2010
Stratified API
            var proxy = Proxy.create(handler, proto);


            handler.get(proxy, ‘foo’)
                                                                handler


                                                                          meta
          base
                    proxy.foo



                                                        proxy




Tuesday, September 28, 2010
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
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
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
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
Not just property accesses
            var proxy = Proxy.create(handler, proto);




                                                                handler



                                                                          meta
          base




                                                        proxy




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

              handler.has(‘foo’)



                                                                handler



                                                                          meta
          base

              ‘foo’ in proxy

                                                        proxy




Tuesday, September 28, 2010
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
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
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
But not quite everything, either
            var proxy = Proxy.create(handler, proto);




                                                                handler



                                                                          meta
          base




                                                        proxy




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




                                                                handler



                                                                          meta
          base

              proxy === obj

                                                        proxy




Tuesday, September 28, 2010
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
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
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
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
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
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
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
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
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
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
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
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
Selective Interception




                                                       meta
                 base




                                   object




Tuesday, September 28, 2010
Selective Interception

                   VM territory (C++)



                                                             meta
                 base




                                   object

                                            JavaScript territory


Tuesday, September 28, 2010
Selective Interception

                   VM territory (C++)
                                      VM handler


                                                                    meta
                 base




                                   object

                                                   JavaScript territory


Tuesday, September 28, 2010
Selective Interception

                   VM territory (C++)
                              VM handler   VM handler


                                                                         meta
                 base




                 host object           object

                                                        JavaScript territory


Tuesday, September 28, 2010
Selective Interception

                   VM territory (C++)
                              VM handler   VM handler              handler


                                                                             meta
                 base




                 host object           object              proxy

                                                        JavaScript territory


Tuesday, September 28, 2010
Selective Interception

                   VM territory (C++)
                              VM handler   VM handler              handler


                                                                             meta
                 base




                 host object           object              proxy

                                                        JavaScript territory


Tuesday, September 28, 2010
Selective Interception

                   VM territory (C++)                      Self-hosted
                              VM handler   VM handler              handler


                                                                             meta
                 base




                 host object           object              proxy

                                                        JavaScript territory


Tuesday, September 28, 2010
Selective Interception

                   VM territory (C++)                      Self-hosted
                              VM handler   VM handler              handler


                                                                             meta
                 base




                 host object           object              proxy

                                                        JavaScript territory


Tuesday, September 28, 2010
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
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
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
Fixing a Proxy
            var proxy = Proxy.create(handler, proto);



                                                                handler


                                                                          meta
          base




                                                        proxy




Tuesday, September 28, 2010
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Example: Membranes
          function makeSimpleMembrane(initTarget) {
            var enabled = true;




          }

Tuesday, September 28, 2010
Example: Membranes
          function makeSimpleMembrane(initTarget) {
            var enabled = true;




            return {
               wrapper: wrap(initTarget),
               revoke: function() { enabled = false; }
            };
          }

Tuesday, September 28, 2010
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
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
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
Prior Work



                        handler


                                               meta
   base



              proxy




Tuesday, September 28, 2010
Prior Work



                        handler            mirror     ProxyHandler   InvocationHandler


                                                                                   meta
   base



              proxy               mirage            proxy      java.lang.reflect.Proxy




Tuesday, September 28, 2010
Prior Work



                        handler             mirror     ProxyHandler   InvocationHandler


                                                                                     meta
   base



              proxy                mirage            proxy       java.lang.reflect.Proxy

 # traps                      13             30              3               1

Tuesday, September 28, 2010
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
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
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
Micro-benchmark Results




Tuesday, September 28, 2010
Micro-benchmark: Overhead




Tuesday, September 28, 2010
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
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

More Related Content

PDF
Golang and Eco-System Introduction / Overview
Markus Schneider
 
PPTX
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Domenic Denicola
 
ODP
ES6 PPT FOR 2016
Manoj Kumar
 
PDF
One Monad to Rule Them All
John De Goes
 
PPT
Hibernate
Sunil OS
 
PPT
JavaScript Event Loop
Thomas Hunter II
 
PDF
Introduction To Appium With Robotframework
Syam Sasi
 
PDF
Introduction to python
Ahmed Salama
 
Golang and Eco-System Introduction / Overview
Markus Schneider
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Domenic Denicola
 
ES6 PPT FOR 2016
Manoj Kumar
 
One Monad to Rule Them All
John De Goes
 
Hibernate
Sunil OS
 
JavaScript Event Loop
Thomas Hunter II
 
Introduction To Appium With Robotframework
Syam Sasi
 
Introduction to python
Ahmed Salama
 

What's hot (20)

PPTX
C programming - Pointers
Wingston
 
PPTX
Pointer in c program
Rumman Ansari
 
PPT
Java. Инкапсуляция.
Unguryan Vitaliy
 
PPTX
Javascript this keyword
Pham Huy Tung
 
PPTX
Functional Programming In JS
Damian Łabas
 
PPTX
C program language tutorial pattern printing
Sourav Ganguly
 
PDF
GraphQL IN Golang
Bo-Yi Wu
 
PPTX
Introduction to Kafka with Spring Integration
Borislav Markov
 
PPTX
Notasi algoritmik & programming style
Tenia Wahyuningrum
 
PDF
Domain Modeling with FP (DDD Europe 2020)
Scott Wlaschin
 
PDF
Error Management: Future vs ZIO
John De Goes
 
PDF
Beginner's Python Cheat Sheet.pdf
AkhileshKumar436707
 
PDF
Sequence and Traverse - Part 1
Philip Schwarz
 
PPTX
Analisis Semantik - P 6 Teknik Kompilasi
ahmad haidaroh
 
PDF
Modul Praktikum Pemrograman Berorientasi Objek (Chap.1-6)
Debby Ummul
 
PDF
Sagas Middleware Architecture
Mateusz Bosek
 
PDF
Idiomatic Kotlin
intelliyole
 
PDF
JavaScript Patterns
Stoyan Stefanov
 
PDF
JUnit & Mockito, first steps
Renato Primavera
 
PPT
Function in C Language
programmings guru
 
C programming - Pointers
Wingston
 
Pointer in c program
Rumman Ansari
 
Java. Инкапсуляция.
Unguryan Vitaliy
 
Javascript this keyword
Pham Huy Tung
 
Functional Programming In JS
Damian Łabas
 
C program language tutorial pattern printing
Sourav Ganguly
 
GraphQL IN Golang
Bo-Yi Wu
 
Introduction to Kafka with Spring Integration
Borislav Markov
 
Notasi algoritmik & programming style
Tenia Wahyuningrum
 
Domain Modeling with FP (DDD Europe 2020)
Scott Wlaschin
 
Error Management: Future vs ZIO
John De Goes
 
Beginner's Python Cheat Sheet.pdf
AkhileshKumar436707
 
Sequence and Traverse - Part 1
Philip Schwarz
 
Analisis Semantik - P 6 Teknik Kompilasi
ahmad haidaroh
 
Modul Praktikum Pemrograman Berorientasi Objek (Chap.1-6)
Debby Ummul
 
Sagas Middleware Architecture
Mateusz Bosek
 
Idiomatic Kotlin
intelliyole
 
JavaScript Patterns
Stoyan Stefanov
 
JUnit & Mockito, first steps
Renato Primavera
 
Function in C Language
programmings guru
 
Ad

Similar to Proxies are Awesome! (20)

PDF
FalsyValues. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 
PDF
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 
PPTX
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Tim Chaplin
 
PDF
Metaprogramming in JavaScript
Mehdi Valikhani
 
PDF
ES6 metaprogramming unleashed
Javier Arias Losada
 
PPTX
ECMA5 approach to building JavaScript frameworks with Anzor Bashkhaz
FITC
 
KEY
JavaScript Growing Up
David Padbury
 
PDF
ES6: The future is now
Sebastiano Armeli
 
PDF
OSCON - ES6 metaprogramming unleashed
Javier Arias Losada
 
PPTX
Object Oriented JavaScript
Julie Iskander
 
KEY
Say Hello To Ecmascript 5
Juriy Zaytsev
 
KEY
Txjs
Peter Higgins
 
PDF
EcmaScript 6 - The future is here
Sebastiano Armeli
 
PPTX
JavsScript OOP
LearningTech
 
PPTX
Metaprogramming in ES6
Héctor Pablos López
 
PPTX
Awesomeness of JavaScript…almost
Quinton Sheppard
 
PDF
JavaScript Proxy (ES6)
Aries Cs
 
PDF
JavaScript Core
François Sarradin
 
PPTX
ES6 is Nigh
Domenic Denicola
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Tim Chaplin
 
Metaprogramming in JavaScript
Mehdi Valikhani
 
ES6 metaprogramming unleashed
Javier Arias Losada
 
ECMA5 approach to building JavaScript frameworks with Anzor Bashkhaz
FITC
 
JavaScript Growing Up
David Padbury
 
ES6: The future is now
Sebastiano Armeli
 
OSCON - ES6 metaprogramming unleashed
Javier Arias Losada
 
Object Oriented JavaScript
Julie Iskander
 
Say Hello To Ecmascript 5
Juriy Zaytsev
 
EcmaScript 6 - The future is here
Sebastiano Armeli
 
JavsScript OOP
LearningTech
 
Metaprogramming in ES6
Héctor Pablos López
 
Awesomeness of JavaScript…almost
Quinton Sheppard
 
JavaScript Proxy (ES6)
Aries Cs
 
JavaScript Core
François Sarradin
 
ES6 is Nigh
Domenic Denicola
 
Ad

More from Brendan Eich (20)

PDF
Int64
Brendan Eich
 
PDF
Always bet on JS - Finjs.io NYC 2016
Brendan Eich
 
PDF
dotJS 2015
Brendan Eich
 
PDF
Extensible Operators and Literals for JavaScript
Brendan Eich
 
PDF
Fluent15
Brendan Eich
 
PDF
The Same-Origin Saga
Brendan Eich
 
PDF
Taysom seminar
Brendan Eich
 
PDF
Fluent14
Brendan Eich
 
PDF
Value Objects, Full Throttle (to be updated for spring TC39 meetings)
Brendan Eich
 
PDF
My dotJS Talk
Brendan Eich
 
PDF
Web futures
Brendan Eich
 
PDF
JS Responsibilities
Brendan Eich
 
PDF
Value objects in JS - an ES7 work in progress
Brendan Eich
 
PDF
Mozilla Research Party Talk
Brendan Eich
 
PDF
Splash
Brendan Eich
 
PDF
JSLOL
Brendan Eich
 
PDF
Capitol js
Brendan Eich
 
PDF
Paren free
Brendan Eich
 
PDF
Txjs talk
Brendan Eich
 
PDF
Mozilla's NodeConf talk
Brendan Eich
 
Always bet on JS - Finjs.io NYC 2016
Brendan Eich
 
dotJS 2015
Brendan Eich
 
Extensible Operators and Literals for JavaScript
Brendan Eich
 
Fluent15
Brendan Eich
 
The Same-Origin Saga
Brendan Eich
 
Taysom seminar
Brendan Eich
 
Fluent14
Brendan Eich
 
Value Objects, Full Throttle (to be updated for spring TC39 meetings)
Brendan Eich
 
My dotJS Talk
Brendan Eich
 
Web futures
Brendan Eich
 
JS Responsibilities
Brendan Eich
 
Value objects in JS - an ES7 work in progress
Brendan Eich
 
Mozilla Research Party Talk
Brendan Eich
 
Splash
Brendan Eich
 
Capitol js
Brendan Eich
 
Paren free
Brendan Eich
 
Txjs talk
Brendan Eich
 
Mozilla's NodeConf talk
Brendan Eich
 

Recently uploaded (20)

PDF
Tea4chat - another LLM Project by Kerem Atam
a0m0rajab1
 
PPTX
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
PDF
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
PDF
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
PPTX
Dev Dives: Automate, test, and deploy in one place—with Unified Developer Exp...
AndreeaTom
 
PDF
Responsible AI and AI Ethics - By Sylvester Ebhonu
Sylvester Ebhonu
 
PDF
Security features in Dell, HP, and Lenovo PC systems: A research-based compar...
Principled Technologies
 
PDF
The Future of Artificial Intelligence (AI)
Mukul
 
PDF
Automating ArcGIS Content Discovery with FME: A Real World Use Case
Safe Software
 
PPTX
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
PDF
Unlocking the Future- AI Agents Meet Oracle Database 23ai - AIOUG Yatra 2025.pdf
Sandesh Rao
 
PPTX
What-is-the-World-Wide-Web -- Introduction
tonifi9488
 
PDF
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
Artjoker Software Development Company
 
PDF
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
PDF
NewMind AI Weekly Chronicles - July'25 - Week IV
NewMind AI
 
PPTX
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
PDF
Presentation about Hardware and Software in Computer
snehamodhawadiya
 
PDF
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
PDF
AI-Cloud-Business-Management-Platforms-The-Key-to-Efficiency-Growth.pdf
Artjoker Software Development Company
 
PPTX
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
Tea4chat - another LLM Project by Kerem Atam
a0m0rajab1
 
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
Dev Dives: Automate, test, and deploy in one place—with Unified Developer Exp...
AndreeaTom
 
Responsible AI and AI Ethics - By Sylvester Ebhonu
Sylvester Ebhonu
 
Security features in Dell, HP, and Lenovo PC systems: A research-based compar...
Principled Technologies
 
The Future of Artificial Intelligence (AI)
Mukul
 
Automating ArcGIS Content Discovery with FME: A Real World Use Case
Safe Software
 
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
Unlocking the Future- AI Agents Meet Oracle Database 23ai - AIOUG Yatra 2025.pdf
Sandesh Rao
 
What-is-the-World-Wide-Web -- Introduction
tonifi9488
 
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
Artjoker Software Development Company
 
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
NewMind AI Weekly Chronicles - July'25 - Week IV
NewMind AI
 
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
Presentation about Hardware and Software in Computer
snehamodhawadiya
 
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
AI-Cloud-Business-Management-Platforms-The-Key-to-Efficiency-Growth.pdf
Artjoker Software Development Company
 
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 

Proxies are Awesome!

  • 1. Proxies are Awesome! Brendan Eich (w/ Mark Miller & Tom Van Cutsem) Tuesday, September 28, 2010
  • 2. ECMAScript 5 (ES5) Tuesday, September 28, 2010
  • 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. 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. 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. 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. 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
  • 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. Example w/ just ES5: logging function makePoint(x, y) { return { x: x, y: y, ... }; } Tuesday, September 28, 2010
  • 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. 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. 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. 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. 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. 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. Stratified API var proxy = Proxy.create(handler, proto); handler meta base proxy Tuesday, September 28, 2010
  • 18. Stratified API var proxy = Proxy.create(handler, proto); handler.get(proxy, ‘foo’) handler meta base proxy.foo proxy Tuesday, September 28, 2010
  • 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. 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. 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. 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. Not just property accesses var proxy = Proxy.create(handler, proto); handler meta base proxy Tuesday, September 28, 2010
  • 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. 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. 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. 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. But not quite everything, either var proxy = Proxy.create(handler, proto); handler meta base proxy Tuesday, September 28, 2010
  • 29. But not quite everything, either var proxy = Proxy.create(handler, proto); handler meta base proxy === obj proxy Tuesday, September 28, 2010
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Selective Interception meta base object Tuesday, September 28, 2010
  • 43. Selective Interception VM territory (C++) meta base object JavaScript territory Tuesday, September 28, 2010
  • 44. Selective Interception VM territory (C++) VM handler meta base object JavaScript territory Tuesday, September 28, 2010
  • 45. Selective Interception VM territory (C++) VM handler VM handler meta base host object object JavaScript territory Tuesday, September 28, 2010
  • 46. Selective Interception VM territory (C++) VM handler VM handler handler meta base host object object proxy JavaScript territory Tuesday, September 28, 2010
  • 47. Selective Interception VM territory (C++) VM handler VM handler handler meta base host object object proxy JavaScript territory Tuesday, September 28, 2010
  • 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. 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. 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. 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. 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. Fixing a Proxy var proxy = Proxy.create(handler, proto); handler meta base proxy Tuesday, September 28, 2010
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Example: Membranes function makeSimpleMembrane(initTarget) {   var enabled = true; } Tuesday, September 28, 2010
  • 75. Example: Membranes function makeSimpleMembrane(initTarget) {   var enabled = true;   return { wrapper: wrap(initTarget), revoke: function() { enabled = false; } }; } Tuesday, September 28, 2010
  • 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. 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. 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. Prior Work handler meta base proxy Tuesday, September 28, 2010
  • 80. Prior Work handler mirror ProxyHandler InvocationHandler meta base proxy mirage proxy java.lang.reflect.Proxy Tuesday, September 28, 2010
  • 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. 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. 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. 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
  • 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. 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