diff -r 473a7faf544e js/src/jsproxy.cpp --- a/js/src/jsproxy.cpp Wed Aug 08 23:40:57 2012 +0200 +++ b/js/src/jsproxy.cpp Wed Aug 08 23:48:50 2012 +0200 @@ -2100,21 +2100,57 @@ ScriptedDirectProxyHandler::set(JSContex } } /* step 8 */ *vp = BooleanValue(success); return true; } +/* 15.2.3.14 Object.keys (O), step 2 */ bool -ScriptedDirectProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props) +ScriptedDirectProxyHandler::keys(JSContext *cx, JSObject *proxy_, AutoIdVector &props) { - JS_NOT_REACHED("not yet implemented"); - return false; + RootedObject proxy(cx, proxy_); + + /* step a */ + RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); + + /* step b */ + RootedObject target(cx, GetProxyTargetObject(proxy)); + + /* step c */ + RootedValue trap(cx); + if (!GetTrap(cx, handler, ATOM(keys), &trap)) + return false; + + /* step d */ + if (trap.isUndefined()) + return DirectProxyHandler::keys(cx, proxy_, props); + + /* step e */ + Value argv[] = { + ObjectOrNullValue(target) + }; + RootedValue trapResult(cx); + if (!Invoke(cx, ObjectValue(*handler), trap, 1, argv, trapResult.address())) + return false; + + /* step f */ + if (trapResult.isPrimitive()) { + JSAutoByteString bytes; + if (!js_AtomToPrintableString(cx, ATOM(keys), &bytes)) + return false; + js_ReportValueError2(cx, JSMSG_INVALID_TRAP_RESULT, JSDVG_SEARCH_STACK, + ObjectOrNullValue(proxy), NULL, bytes.ptr()); + return false; + } + + /* steps g-n are shared */ + return ArrayToIdVector(cx, proxy, target, trapResult, props, ATOM(keys)); } bool ScriptedDirectProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp) { JS_NOT_REACHED("not yet implemented"); return false; }