Proxies are Awesome!

88
Proxies are Awesome! Brendan Eich (w/ Mark Miller & Tom Van Cutsem) Tuesday, September 28, 2010

description

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.

Transcript of Proxies are Awesome!

Page 1: Proxies are Awesome!

Proxiesare Awesome!

Brendan Eich(w/ Mark Miller & Tom Van Cutsem)

Tuesday, September 28, 2010

Page 2: Proxies are Awesome!

ECMAScript 5 (ES5)

Tuesday, September 28, 2010

Page 3: Proxies are Awesome!

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

Page 4: Proxies are Awesome!

ES5 Property Descriptors• Data vs. accessor properties

• Property attributes

Object.getOwnPropertyDescriptor(point, ‘x’);

Object.getOwnPropertyDescriptor(point, ‘r’);

{ value: 5, writable: true, enumerable: true, configurable: true }

{ get: function () { return Math.sqrt(this.x*this.x + ...); }, set: undefined, enumerable: true, configurable: true }

var point = { x: 5, y: 8, get r() { return Math.sqrt(this.x*this.x + this.y*this.y); } };

Tuesday, September 28, 2010

Page 5: Proxies are Awesome!

var point = Object.create( Object.prototype, { x: { value: 5, ... }, y: { value: 8, ... }, r: { get: function() {...}, enumerable: true, ... }, z: { value: 0, enumerable: true, ... } });

Property Descriptor Mapsvar 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 });

Tuesday, September 28, 2010

Page 6: Proxies are Awesome!

var point = Object.create( Object.prototype, { x: { value: 5, ... }, y: { value: 8, ... }, r: { get: function() {...}, enumerable: true, ... }, z: { value: 0, enumerable: true, ... } });

Property Descriptor Mapsvar 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 });

name pdx {...}

y {...}

r {...}

z {...}

Tuesday, September 28, 2010

Page 7: Proxies are Awesome!

Tamper-proofing Objectsvar point = { x: 5, y: 8, get r() { return Math.sqrt(this.x*this.x + this.y*this.y); } };

Object.freeze(point);point.x = 7; // can’t assign properties

Object.seal(point);delete point.x; // can’t delete properties

Object.preventExtensions(point);point.z = 0; // can’t add new properties

Tuesday, September 28, 2010

Page 8: Proxies are Awesome!

ES-Harmony Proxies

Tuesday, September 28, 2010

Page 9: Proxies are Awesome!

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

Page 10: Proxies are Awesome!

Example w/ just ES5: loggingfunction makePoint(x, y) { return { x: x, y: y, ... };}

Tuesday, September 28, 2010

Page 11: Proxies are Awesome!

Example w/ just ES5: loggingfunction 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

Page 12: Proxies are Awesome!

Example w/ just ES5: loggingfunction 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));

Too ad hoc. What about:• logging other data types• profiling, persistence, access control, ...

Tuesday, September 28, 2010

Page 13: Proxies are Awesome!

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

Page 14: Proxies are Awesome!

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;}

• proxy doesn’t reflect structural changes made to ‘obj’• structural changes made to proxy are not reflected in ‘obj’• structural changes: • add/delete properties• change property attributes

Tuesday, September 28, 2010

Page 15: Proxies are Awesome!

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

Page 16: Proxies are Awesome!

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;}

meta

base

proxy

handler

Tuesday, September 28, 2010

Page 17: Proxies are Awesome!

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

meta

base

proxy

handler

Tuesday, September 28, 2010

Page 18: Proxies are Awesome!

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

meta

base

proxy

handler

proxy.foo

handler.get(proxy, ‘foo’)

Tuesday, September 28, 2010

Page 19: Proxies are Awesome!

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

meta

base

proxy

handler

proxy.foo

handler.get(proxy, ‘foo’)

proxy.foo = 42

handler.set(proxy, ‘foo’, 42)

Tuesday, September 28, 2010

Page 20: Proxies are Awesome!

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

meta

base

proxy

handler

proxy.foo

handler.get(proxy, ‘foo’)

proxy.foo = 42

handler.set(proxy, ‘foo’, 42)

proxy.foo(1,2,3)

handler.get(proxy, ‘foo’).apply(proxy,[1,2,3])

Tuesday, September 28, 2010

Page 21: Proxies are Awesome!

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

meta

base

proxy

handler

proxy.foo

handler.get(proxy, ‘foo’)

proxy.foo = 42

handler.set(proxy, ‘foo’, 42)

proxy.get

handler.get(proxy, ‘get’)

proxy.foo(1,2,3)

handler.get(proxy, ‘foo’).apply(proxy,[1,2,3])

Tuesday, September 28, 2010

Page 22: Proxies are Awesome!

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

meta

base

proxy

handler

proxy.foo

handler.get(proxy, ‘foo’)

proxy.foo = 42

handler.set(proxy, ‘foo’, 42)

proxy.get

handler.get(proxy, ‘get’)

proxy.foo(1,2,3)

handler.get(proxy, ‘foo’).apply(proxy,[1,2,3])

proto

Tuesday, September 28, 2010

Page 23: Proxies are Awesome!

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

meta

base

proxy

handler

Tuesday, September 28, 2010

Page 24: Proxies are Awesome!

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

meta

base

proxy

handler

‘foo’ in proxy

handler.has(‘foo’)

Tuesday, September 28, 2010

Page 25: Proxies are Awesome!

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

meta

base

proxy

handler

‘foo’ in proxy

handler.has(‘foo’)

delete proxy.foo

handler.delete(‘foo’)

Tuesday, September 28, 2010

Page 26: Proxies are Awesome!

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

meta

base

proxy

handler

‘foo’ in proxy

handler.has(‘foo’)

delete proxy.foo

handler.delete(‘foo’)

for (var prop in proxy) { ... }

var props = handler.enumerate();for (var i=0;i<props.length;i++) { var prop = props[i]; ...}

Tuesday, September 28, 2010

Page 27: Proxies are Awesome!

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

meta

base

proxy

handler

‘foo’ in proxy

handler.has(‘foo’)

delete proxy.foo

handler.delete(‘foo’)

for (var prop in proxy) { ... }

var props = handler.enumerate();for (var i=0;i<props.length;i++) { var prop = props[i]; ...}handler.defineProperty(‘foo’, pd)

Object.defineProperty(proxy,‘foo’, pd)

Tuesday, September 28, 2010

Page 28: Proxies are Awesome!

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

meta

base

proxy

handler

Tuesday, September 28, 2010

Page 29: Proxies are Awesome!

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

meta

base

proxy

handler

proxy === obj

Tuesday, September 28, 2010

Page 30: Proxies are Awesome!

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

meta

base

proxy

handler

proxy === obj

Object.getPrototypeOf(proxy) => proto proto

Tuesday, September 28, 2010

Page 31: Proxies are Awesome!

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

meta

base

proxy

handler

proxy instanceof SomeFunction

proxy === obj

Object.getPrototypeOf(proxy) => proto proto

Tuesday, September 28, 2010

Page 32: Proxies are Awesome!

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

meta

base

proxy

handler

typeof proxy => “object”

proxy instanceof SomeFunction

proxy === obj

Object.getPrototypeOf(proxy) => proto proto

Tuesday, September 28, 2010

Page 33: Proxies are Awesome!

Full Handler API

handler.getOwnPropertyDescriptor(name)handler.getPropertyDescriptor(name)handler.defineProperty(name, pd)handler.getOwnPropertyNames()handler.delete(name) handler.enumerate()handler.fix()handler.has(name)handler.hasOwn(name)handler.get(receiver, name)handler.set(receiver, name, val)handler.keys()handler.iterate()

Object.getOwnPropertyDescriptor(proxy)Object.getPropertyDescriptor(proxy)

Object.defineProperty(proxy,name,pd)Object.getOwnPropertyNames(proxy) 

delete proxy.namefor (name in proxy) { ... } 

Object.{freeze|seal|...}(proxy)name in proxy

({}).hasOwnProperty.call(proxy, name)receiver.name

receiver.name = valObject.keys(proxy)

for (name in proxy) { ... }

proxy

handler

Tuesday, September 28, 2010

Page 34: Proxies are Awesome!

Fundamental vs Derived Traps

handler.getOwnPropertyDescriptor(name)handler.getPropertyDescriptor(name)handler.defineProperty(name, pd)handler.getOwnPropertyNames()handler.delete(name) handler.enumerate() -> [string]handler.fix()

handler.has(name)handler.hasOwn(name)handler.get(receiver, name)handler.set(receiver, name, val)handler.keys()handler.iterate() -> iterator

Object.getOwnPropertyDescriptor(proxy)Object.getPropertyDescriptor(proxy)

Object.defineProperty(proxy,name,pd)Object.getOwnPropertyNames(proxy) 

delete proxy.namefor (name in proxy) { ... } 

Object.{freeze|seal|...}(proxy)

name in proxy({}).hasOwnProperty.call(proxy, name)

receiver.namereceiver.name = valObject.keys(proxy)

for (name in proxy) { ... }

proxy

handler

Fundamental traps

Derived traps

Tuesday, September 28, 2010

Page 35: Proxies are Awesome!

Function ProxiesJavaScript functions are objects. Additionally, they are also callable and constructible

var call = function() { ... };var construct = function() { ... };var funproxy = Proxy.createFunction(handler, call, construct);

funproxy

handlercall construct

Tuesday, September 28, 2010

Page 36: Proxies are Awesome!

Function ProxiesJavaScript functions are objects. Additionally, they are also callable and constructible

var call = function() { ... };var construct = function() { ... };var funproxy = Proxy.createFunction(handler, call, construct);

funproxy

handlercall construct

funproxy(1,2,3)

call(1,2,3)

Tuesday, September 28, 2010

Page 37: Proxies are Awesome!

Function ProxiesJavaScript functions are objects. Additionally, they are also callable and constructible

var call = function() { ... };var construct = function() { ... };var funproxy = Proxy.createFunction(handler, call, construct);

funproxy

handlercall construct

funproxy(1,2,3)

call(1,2,3)

new funproxy(1,2,3)

construct(1,2,3)

Tuesday, September 28, 2010

Page 38: Proxies are Awesome!

Function ProxiesJavaScript functions are objects. Additionally, they are also callable and constructible

var call = function() { ... };var construct = function() { ... };var funproxy = Proxy.createFunction(handler, call, construct);

funproxy

handlercall construct

funproxy(1,2,3)

call(1,2,3)

new funproxy(1,2,3)

construct(1,2,3)

funproxy.prototype

handler.get(funproxy,‘prototype’)

Tuesday, September 28, 2010

Page 39: Proxies are Awesome!

Function ProxiesJavaScript functions are objects. Additionally, they are also callable and constructible

var call = function() { ... };var construct = function() { ... };var funproxy = Proxy.createFunction(handler, call, construct);

funproxy

handlercall construct

funproxy(1,2,3)

call(1,2,3)

new funproxy(1,2,3)

construct(1,2,3)

funproxy.prototype

handler.get(funproxy,‘prototype’)

typeof funproxy => “function”

Tuesday, September 28, 2010

Page 40: Proxies are Awesome!

Function ProxiesJavaScript functions are objects. Additionally, they are also callable and constructible

var call = function() { ... };var construct = function() { ... };var funproxy = Proxy.createFunction(handler, call, construct);

funproxy

handlercall construct

funproxy(1,2,3)

call(1,2,3)

new funproxy(1,2,3)

construct(1,2,3)

funproxy.prototype

handler.get(funproxy,‘prototype’)

typeof funproxy => “function”Object.getPrototypeOf(funproxy) => Function.prototype

Tuesday, September 28, 2010

Page 41: Proxies are Awesome!

Dilemma: Invoke vs Get+Call• Fundamental vs derived traps = tradeoff in

performance (method allocation or caching) vs. consistency

• 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()

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])

Tuesday, September 28, 2010

Page 42: Proxies are Awesome!

Selective Interception

meta

base

object

Tuesday, September 28, 2010

Page 43: Proxies are Awesome!

Selective Interception

meta

base

object

VM territory (C++)

JavaScript territory

Tuesday, September 28, 2010

Page 44: Proxies are Awesome!

Selective Interception

meta

base

object

VM territory (C++)

JavaScript territory

VM handler

Tuesday, September 28, 2010

Page 45: Proxies are Awesome!

Selective Interception

meta

base

object

VM territory (C++)

JavaScript territory

host object

VM handler VM handler

Tuesday, September 28, 2010

Page 46: Proxies are Awesome!

Selective Interception

meta

base

object

VM territory (C++)

JavaScript territory

host object

VM handler VM handler

proxy

handler

Tuesday, September 28, 2010

Page 47: Proxies are Awesome!

Selective Interception

meta

base

object

VM territory (C++)

JavaScript territory

host object

VM handler VM handler

proxy

handler

Tuesday, September 28, 2010

Page 48: Proxies are Awesome!

Selective Interception

meta

base

object

VM territory (C++)

JavaScript territory

Self-hosted

host object

VM handler VM handler

proxy

handler

Tuesday, September 28, 2010

Page 49: Proxies are Awesome!

Selective Interception

meta

base

object

VM territory (C++)

JavaScript territory

Self-hosted

host object

VM handler VM handler

proxy

handler

Tuesday, September 28, 2010

Page 50: Proxies are Awesome!

Example: no-op forwarding proxy

function ForwardingHandler(obj) { this.target = obj;}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));

proxy

handler

target

Tuesday, September 28, 2010

Page 51: Proxies are Awesome!

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

Page 52: Proxies are Awesome!

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

Page 53: Proxies are Awesome!

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

meta

base

proxy

handler

Tuesday, September 28, 2010

Page 54: Proxies are Awesome!

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

meta

base

proxy

handler

Object.freeze(proxy)

Object.seal(proxy)

Object.preventExtensions(proxy)

Tuesday, September 28, 2010

Page 55: Proxies are Awesome!

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

meta

base

proxy

handlervar pdmap = handler.fix();if (pdmap === undefined) throw TypeError();become(proxy, Object.freeze( Object.create(proto, pdmap)));

Object.freeze(proxy)

Object.seal(proxy)

Object.preventExtensions(proxy)

Tuesday, September 28, 2010

Page 56: Proxies are Awesome!

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

meta

base

proxy

handlervar pdmap = handler.fix();if (pdmap === undefined) throw TypeError();become(proxy, Object.freeze( Object.create(proto, pdmap)));

Object.freeze(proxy)

Object.seal(proxy)

Object.preventExtensions(proxy)

Trapping Fixedfix

Tuesday, September 28, 2010

Page 57: Proxies are Awesome!

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

meta

base

proxy

var pdmap = handler.fix();if (pdmap === undefined) throw TypeError();become(proxy, Object.freeze( Object.create(proto, pdmap)));

Object.freeze(proxy)

Object.seal(proxy)

Object.preventExtensions(proxy)

Trapping Fixedfix

Tuesday, September 28, 2010

Page 58: Proxies are Awesome!

Meta-level Shifting

handler.getOwnPropertyDescriptor(name)handler.getPropertyDescriptor(name)handler.defineProperty(name, pd)handler.getOwnPropertyNames()handler.delete(name) handler.enumerate()handler.fix()handler.has(name)handler.hasOwn(name)handler.get(receiver, name)handler.set(receiver, name, val)handler.keys()handler.iterate()

Object.getOwnPropertyDescriptor(proxy)Object.getPropertyDescriptor(proxy)

Object.defineProperty(proxy,name,pd)Object.getOwnPropertyNames(proxy) 

delete proxy.namefor (name in proxy) { ... } 

Object.{freeze|seal|...}(proxy)name in proxy

({}).hasOwnProperty.call(proxy, name)receiver.name

receiver.name = valObject.keys(proxy)

for (name in proxy) { ... } 

base-level: many operations on objects

meta-level: all operations reified as invocations of traps

proxy

handler

Tuesday, September 28, 2010

Page 59: Proxies are Awesome!

Meta-level Shifting

meta-level: all operations reified as invocations of traps

meta-meta-level: all operations reified as invocations of ‘get’ trap

handler

μhandler

handler.getOwnPropertyDescriptor(name)handler.getPropertyDescriptor(name)handler.defineOwnProperty(name, pd)handler.delete(name) handler.getOwnPropertyNames()handler.enumerate()handler.fix()handler.has(name)handler.hasOwn(name)handler.get(receiver, name)handler.set(receiver, name, val)handler.keys()handler.iterate()

μhandler.get(handler, ‘getOwnP..’)(name)μhandler.get(handler, ‘getProp..’)(name)μhandler.get(handler, ‘define...’)(name,pd)μhandler.get(handler, ‘delete’)(name)μhandler.get(handler, ‘getOwnP..’)()μhandler.get(handler, ‘enumerate’)()μhandler.get(handler, ‘fix’)()μhandler.get(handler, ‘has’)(name)μhandler.get(handler, ‘hasOwn’)(name)μhandler.get(handler, ‘get’)(receiver,name)μhandler.get(handler, ‘set’)(receiver,name,val)μhandler.get(handler, ‘keys’)()μhandler.get(handler, ‘iterate’)()

a proxy whose handler is a proxy

Tuesday, September 28, 2010

Page 60: Proxies are Awesome!

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

Page 61: Proxies are Awesome!

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

Page 62: Proxies are Awesome!

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

Page 63: Proxies are Awesome!

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

Page 64: Proxies are Awesome!

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

Page 65: Proxies are Awesome!

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

Page 66: Proxies are Awesome!

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

Page 67: Proxies are Awesome!

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

Page 68: Proxies are Awesome!

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

Page 69: Proxies are Awesome!

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

Page 70: Proxies are Awesome!

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

Page 71: Proxies are Awesome!

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

Page 72: Proxies are Awesome!

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

Page 73: Proxies are Awesome!

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

Page 74: Proxies are Awesome!

function makeSimpleMembrane(initTarget) {  var enabled = true;

}

Example: Membranes

Tuesday, September 28, 2010

Page 75: Proxies are Awesome!

function makeSimpleMembrane(initTarget) {  var enabled = true;

}

Example: Membranes

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

Tuesday, September 28, 2010

Page 76: Proxies are Awesome!

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]); }    });

  }

Example: Membranes

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

Tuesday, September 28, 2010

Page 77: Proxies are Awesome!

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]); }    });

  }

Example: Membranes

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

if (typeof target === “function”) { return Proxy.createFunction(revokeHandler, wrapFunction(target)); }    return Proxy.create(revokeHandler, wrap(Object.getPrototypeOf(target)));

Tuesday, September 28, 2010

Page 78: Proxies are Awesome!

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]); }    });

  }

Example: Membranes

function wrapFunction(f) {    return function() { // variable-argument function if (!enabled) { throw new Error("revoked"); }     return wrap(f.apply(wrap(this), arguments.map(wrap))); } }

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

if (typeof target === “function”) { return Proxy.createFunction(revokeHandler, wrapFunction(target)); }    return Proxy.create(revokeHandler, wrap(Object.getPrototypeOf(target)));

Tuesday, September 28, 2010

Page 79: Proxies are Awesome!

Prior Work

meta

base

proxy

handler

Tuesday, September 28, 2010

Page 80: Proxies are Awesome!

Prior Work

meta

base

java.lang.reflect.Proxy

InvocationHandler

proxy

ProxyHandler

mirage

mirror

proxy

handler

Tuesday, September 28, 2010

Page 81: Proxies are Awesome!

Prior Work

meta

base

java.lang.reflect.Proxy

InvocationHandler

proxy

ProxyHandler

mirage

mirror

proxy

handler

# traps 13 3 130

Tuesday, September 28, 2010

Page 82: Proxies are Awesome!

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

Page 83: Proxies are Awesome!

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

Page 84: Proxies are Awesome!

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

Page 85: Proxies are Awesome!

Micro-benchmark Results

Tuesday, September 28, 2010

Page 86: Proxies are Awesome!

Micro-benchmark: Overhead

Tuesday, September 28, 2010

Page 87: Proxies are Awesome!

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

Page 88: Proxies are Awesome!

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