diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 24a552e2de6..75764cb33c9 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1296,6 +1296,8 @@ Class js::ArrayClass = { array_getGeneric, array_getProperty, array_getElement, + NULL, /* getElementIfPresent, because this is hard for now for + slow arrays */ array_getSpecial, array_setGeneric, array_setProperty, diff --git a/js/src/jsclass.h b/js/src/jsclass.h index a2a8a843041..674a4d8591a 100644 --- a/js/src/jsclass.h +++ b/js/src/jsclass.h @@ -208,6 +208,8 @@ typedef JSBool typedef JSBool (* ElementIdOp)(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp); typedef JSBool +(* ElementIfPresentOp)(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp, bool* present); +typedef JSBool (* SpecialIdOp)(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp); typedef JSBool (* StrictGenericIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); @@ -313,6 +315,7 @@ struct ObjectOps GenericIdOp getGeneric; PropertyIdOp getProperty; ElementIdOp getElement; + ElementIfPresentOp getElementIfPresent; /* can be null */ SpecialIdOp getSpecial; StrictGenericIdOp setGeneric; StrictPropertyIdOp setProperty; @@ -341,7 +344,7 @@ struct ObjectOps #define JS_NULL_OBJECT_OPS \ {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, \ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, \ - NULL,NULL,NULL,NULL,NULL} + NULL,NULL,NULL,NULL,NULL,NULL} struct Class { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 0842417808f..8b240da5a9b 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3457,6 +3457,7 @@ Class js::WithClass = { with_GetGeneric, with_GetProperty, with_GetElement, + NULL, /* getElementIfPresent */ with_GetSpecial, with_SetGeneric, with_SetProperty, diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 4e4ae74a239..1611a41b1e8 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1258,6 +1258,10 @@ inline JSBool JSObject::getElementIfPresent(JSContext *cx, JSObject *receiver, uint32 index, js::Value *vp, bool *present) { + js::ElementIfPresentOp op = getOps()->getElementIfPresent; + if (op) + return op(cx, this, receiver, index, vp, present); + /* For now, do the index-to-id conversion just once, then use * lookupGeneric/getGeneric. Once lookupElement and getElement stop both * doing index-to-id conversions, we can use those here. diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index bba8d71f48f..ad454c48a37 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -139,6 +139,24 @@ ProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, V return CallJSPropertyOp(cx, desc.getter, receiver, id, vp); } +bool +ProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32 index, Value *vp, bool *present) +{ + jsid id; + if (!IndexToId(cx, index, &id)) + return false; + + if (!has(cx, proxy, id, present)) + return false; + + if (!*present) { + Debug_SetValueRangeToCrashOnTouch(vp, 1); + return true; + } + + return get(cx, proxy, receiver, id, vp); +} + bool ProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp) @@ -809,6 +827,15 @@ Proxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *v return GetProxyHandler(proxy)->get(cx, proxy, receiver, id, vp); } +bool +Proxy::getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32 index, + Value *vp, bool *present) +{ + JS_CHECK_RECURSION(cx, return false); + AutoPendingProxyOperation pending(cx, proxy); + return GetProxyHandler(proxy)->getElementIfPresent(cx, proxy, receiver, index, vp, present); +} + bool Proxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp) { @@ -1017,6 +1044,13 @@ proxy_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, return proxy_GetGeneric(cx, obj, receiver, id, vp); } +static JSBool +proxy_GetElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, + Value *vp, bool *present) +{ + return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present); +} + static JSBool proxy_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp) { @@ -1251,6 +1285,7 @@ JS_FRIEND_DATA(Class) js::ObjectProxyClass = { proxy_GetGeneric, proxy_GetProperty, proxy_GetElement, + proxy_GetElementIfPresent, proxy_GetSpecial, proxy_SetGeneric, proxy_SetProperty, @@ -1312,6 +1347,7 @@ JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = { proxy_GetGeneric, proxy_GetProperty, proxy_GetElement, + proxy_GetElementIfPresent, proxy_GetSpecial, proxy_SetGeneric, proxy_SetProperty, @@ -1385,6 +1421,7 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = { proxy_GetGeneric, proxy_GetProperty, proxy_GetElement, + proxy_GetElementIfPresent, proxy_GetSpecial, proxy_SetGeneric, proxy_SetProperty, diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index 2fcf214d46d..2f3b374f3ba 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -88,6 +88,8 @@ class JS_FRIEND_API(ProxyHandler) { virtual bool defaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp); virtual void finalize(JSContext *cx, JSObject *proxy); virtual void trace(JSTracer *trc, JSObject *proxy); + virtual bool getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver, + uint32 index, Value *vp, bool *present); virtual bool isOuterWindow() { return false; @@ -120,6 +122,8 @@ class Proxy { static bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp); static bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp); static bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp); + static bool getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, + uint32 index, Value *vp, bool *present); static bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp); static bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props); diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 56b8a3c25fb..a63e036b632 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -2105,6 +2105,7 @@ Class js::ArrayBufferClass = { ArrayBuffer::obj_getGeneric, ArrayBuffer::obj_getProperty, ArrayBuffer::obj_getElement, + NULL, /* getElementIfPresent */ ArrayBuffer::obj_getSpecial, ArrayBuffer::obj_setGeneric, ArrayBuffer::obj_setProperty, @@ -2217,6 +2218,7 @@ JSFunctionSpec _typedArray::jsfuncs[] = { \ _typedArray::obj_getGeneric, \ _typedArray::obj_getProperty, \ _typedArray::obj_getElement, \ + NULL, /* getElementIfPresent */ \ _typedArray::obj_getSpecial, \ _typedArray::obj_setGeneric, \ _typedArray::obj_setProperty, \ diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 0dd1babcbf9..c9873505547 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -5361,6 +5361,7 @@ JS_FRIEND_DATA(Class) js::XMLClass = { xml_getGeneric, xml_getProperty, xml_getElement, + NULL, /* getElementIfPresent */ xml_getSpecial, xml_setGeneric, xml_setProperty, diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 4e185e5c317..b1e3864d2a5 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -866,6 +866,7 @@ js::Class XPC_WN_NoHelper_JSClass = { nsnull, // getGeneric nsnull, // getProperty nsnull, // getElement + nsnull, // getElementIfPresent nsnull, // getSpecial nsnull, // setGeneric nsnull, // setProperty diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index c006b7e4b7e..8bc15d22157 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -1407,6 +1407,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj); nsnull, /* getGeneric */ \ nsnull, /* getProperty */ \ nsnull, /* getElement */ \ + nsnull, /* getElementIfPresent */ \ nsnull, /* getSpecial */ \ nsnull, /* setGeneric */ \ nsnull, /* setProperty */ \ @@ -1444,6 +1445,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj); nsnull, /* getGeneric */ \ nsnull, /* getProperty */ \ nsnull, /* getElement */ \ + nsnull, /* getElementIfPresent */ \ nsnull, /* getSpecial */ \ nsnull, /* setGeneric */ \ nsnull, /* setProperty */ \