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. ...
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.
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: 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
Why aren't presentations and multimedia in HTML5? 2 years ago