From dea3c49818e59f7a97640a7b5be2735d2bc14d05 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Thu, 22 Jan 2015 17:17:26 +0100 Subject: [PATCH] Bug 1122552 - Introduce [[GetOwnProperty]] object op. r=jorendorff,bz --- dom/bindings/Codegen.py | 1 + dom/plugins/base/nsJSNPRuntime.cpp | 1 + js/public/Class.h | 8 ++- js/src/builtin/TypedObject.cpp | 61 +++++++++++++++++++ js/src/builtin/TypedObject.h | 3 + js/src/jsfriendapi.h | 4 ++ js/src/jsobj.cpp | 4 +- js/src/proxy/Proxy.cpp | 7 +++ .../TypedObject/structtypegetownproperty.js | 28 +++++++++ js/src/vm/ScopeObject.cpp | 18 ++++++ js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 1 + js/xpconnect/src/xpcprivate.h | 2 + 12 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 js/src/tests/ecma_7/TypedObject/structtypegetownproperty.js diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 19043289fae..3c3278afb3d 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -404,6 +404,7 @@ class CGDOMJSClass(CGThing): nullptr, /* setGeneric */ nullptr, /* setProperty */ nullptr, /* setElement */ + nullptr, /* getOwnPropertyDescriptor */ nullptr, /* getGenericAttributes */ nullptr, /* setGenericAttributes */ nullptr, /* deleteGeneric */ diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index c4c5186f3da..6ce77975cd2 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -234,6 +234,7 @@ const static js::Class sNPObjectJSWrapperClass = nullptr, // setGeneric nullptr, // setProperty nullptr, // setElement + nullptr, // getOwnPropertyDescriptor nullptr, // getGenericAttributes nullptr, // setGenericAttributes nullptr, // deleteGeneric diff --git a/js/public/Class.h b/js/public/Class.h index 69e54a7cec3..1bee6f50ffc 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -199,6 +199,9 @@ typedef bool (* StrictElementIdOp)(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp, bool strict); typedef bool +(* GetOwnPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle desc); +typedef bool (* GenericAttributesOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); typedef bool (* PropertyAttributesOp)(JSContext *cx, JS::HandleObject obj, JS::Handle name, @@ -378,6 +381,7 @@ struct ObjectOps StrictGenericIdOp setGeneric; StrictPropertyIdOp setProperty; StrictElementIdOp setElement; + GetOwnPropertyOp getOwnPropertyDescriptor; GenericAttributesOp getGenericAttributes; GenericAttributesOp setGenericAttributes; DeleteGenericOp deleteGeneric; @@ -391,7 +395,7 @@ struct ObjectOps #define JS_NULL_OBJECT_OPS \ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, \ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, \ - nullptr, nullptr, nullptr} + nullptr, nullptr, nullptr, nullptr} } // namespace js @@ -402,7 +406,7 @@ typedef void (*JSClassInternal)(); struct JSClass { JS_CLASS_MEMBERS(JSFinalizeOp); - void *reserved[32]; + void *reserved[33]; }; #define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index ad33631c3fe..8137d93e242 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -2003,6 +2003,66 @@ TypedObject::obj_setArrayElement(JSContext *cx, return ConvertAndCopyTo(cx, elementType, typedObj, offset, NullPtr(), vp); } +bool +TypedObject::obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, + MutableHandle desc) +{ + Rooted typedObj(cx, &obj->as()); + if (!typedObj->isAttached()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED); + return false; + } + + Rooted descr(cx, &typedObj->typeDescr()); + switch (descr->kind()) { + case type::Scalar: + case type::Reference: + case type::Simd: + break; + + case type::Array: + { + uint32_t index; + if (js_IdIsIndex(id, &index)) { + if (!obj_getArrayElement(cx, typedObj, descr, index, desc.value())) + return false; + desc.setAttributes(JSPROP_ENUMERATE | JSPROP_PERMANENT); + desc.object().set(obj); + return true; + } + + if (JSID_IS_ATOM(id, cx->names().length)) { + desc.value().setInt32(typedObj->length()); + desc.setAttributes(JSPROP_READONLY | JSPROP_PERMANENT); + desc.object().set(obj); + return true; + } + break; + } + + case type::Struct: + { + Rooted descr(cx, &typedObj->typeDescr().as()); + + size_t fieldIndex; + if (!descr->fieldIndex(id, &fieldIndex)) + break; + + size_t offset = descr->fieldOffset(fieldIndex); + Rooted fieldType(cx, &descr->fieldDescr(fieldIndex)); + if (!Reify(cx, fieldType, typedObj, offset, desc.value())) + return false; + + desc.setAttributes(JSPROP_ENUMERATE | JSPROP_PERMANENT); + desc.object().set(obj); + return true; + } + } + + desc.object().set(nullptr); + return true; +} + bool TypedObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp) @@ -2365,6 +2425,7 @@ LazyArrayBufferTable::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) TypedObject::obj_setGeneric, \ TypedObject::obj_setProperty, \ TypedObject::obj_setElement, \ + TypedObject::obj_getOwnPropertyDescriptor, \ TypedObject::obj_getGenericAttributes, \ TypedObject::obj_setGenericAttributes, \ TypedObject::obj_deleteGeneric, \ diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index c0ac8bfc400..2c2627fd076 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -564,6 +564,9 @@ class TypedObject : public JSObject static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp, bool strict); + static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, + MutableHandle desc); + static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp); static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj, diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 0634006a8ed..5f33604c23e 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -301,6 +301,7 @@ namespace js { js::proxy_SetGeneric, \ js::proxy_SetProperty, \ js::proxy_SetElement, \ + js::proxy_GetOwnPropertyDescriptor, \ js::proxy_GetGenericAttributes, \ js::proxy_SetGenericAttributes, \ js::proxy_DeleteGeneric, \ @@ -364,6 +365,9 @@ extern JS_FRIEND_API(bool) proxy_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp, bool strict); extern JS_FRIEND_API(bool) +proxy_GetOwnPropertyDescriptor(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle desc); +extern JS_FRIEND_API(bool) proxy_GetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); extern JS_FRIEND_API(bool) proxy_SetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 9dc13a923a6..ab87bd10d7c 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3196,8 +3196,8 @@ bool js::GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandle desc) { - if (obj->is()) - return Proxy::getOwnPropertyDescriptor(cx, obj, id, desc); + if (GetOwnPropertyOp op = obj->getOps()->getOwnPropertyDescriptor) + return op(cx, obj, id, desc); RootedObject pobj(cx); RootedShape shape(cx); diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 69d8e6de679..73b0b88cdf6 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -667,6 +667,13 @@ js::proxy_SetElement(JSContext *cx, HandleObject obj, uint32_t index, return proxy_SetGeneric(cx, obj, id, vp, strict); } +bool +js::proxy_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, + MutableHandle desc) +{ + return Proxy::getOwnPropertyDescriptor(cx, obj, id, desc); +} + bool js::proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp) { diff --git a/js/src/tests/ecma_7/TypedObject/structtypegetownproperty.js b/js/src/tests/ecma_7/TypedObject/structtypegetownproperty.js new file mode 100644 index 00000000000..aa790759537 --- /dev/null +++ b/js/src/tests/ecma_7/TypedObject/structtypegetownproperty.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 1122552; +var summary = 'Introduce [[GetOwnProperty]] object op'; + +var StructType = TypedObject.StructType; +var uint8 = TypedObject.uint8; + +function runTests() { + print(BUGNUMBER + ": " + summary); + + var PixelType = new StructType({x: uint8, y: uint8}); + var pixel = new PixelType({x: 15, y: 16}); + + var desc = Object.getOwnPropertyDescriptor(pixel, 'x'); + assertEq(typeof desc, "object"); + assertEq(desc.value, 15); + assertEq(desc.enumerable, true); + assertEq(desc.writable, true); + assertEq(desc.configurable, false); + + desc = Object.getOwnPropertyDescriptor(pixel, 'dummy'); + assertEq(typeof desc, "undefined"); + + reportCompare(true, true); + print("Tests complete"); +} + +runTests(); diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index a5359d26051..744c58da77f 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -562,6 +562,14 @@ with_SetElement(JSContext *cx, HandleObject obj, uint32_t index, return SetElement(cx, actual, actual, index, vp, strict); } +static bool +with_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, + MutableHandle desc) +{ + RootedObject actual(cx, &obj->as().object()); + return GetOwnPropertyDescriptor(cx, obj, id, desc); +} + static bool with_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp) { @@ -627,6 +635,7 @@ const Class DynamicWithObject::class_ = { with_SetGeneric, with_SetProperty, with_SetElement, + with_GetOwnPropertyDescriptor, with_GetGenericAttributes, with_SetGenericAttributes, with_DeleteGeneric, @@ -1064,6 +1073,14 @@ uninitialized_SetElement(JSContext *cx, HandleObject obj, uint32_t index, return uninitialized_SetGeneric(cx, obj, id, vp, strict); } +static bool +uninitialized_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, + MutableHandle desc) +{ + ReportUninitializedLexicalId(cx, id); + return false; +} + static bool uninitialized_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp) { @@ -1116,6 +1133,7 @@ const Class UninitializedLexicalObject::class_ = { uninitialized_SetGeneric, uninitialized_SetProperty, uninitialized_SetElement, + uninitialized_GetOwnPropertyDescriptor, uninitialized_GetGenericAttributes, uninitialized_SetGenericAttributes, uninitialized_DeleteGeneric, diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index fd7e2fe65d4..5d9a8a12505 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -693,6 +693,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { nullptr, // setGeneric nullptr, // setProperty nullptr, // setElement + nullptr, // getOwnPropertyDescriptor nullptr, // getGenericAttributes nullptr, // setGenericAttributes nullptr, // deleteGeneric diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 8a624016ea6..1e529ed0744 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -986,6 +986,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* setGeneric */ \ nullptr, /* setProperty */ \ nullptr, /* setElement */ \ + nullptr, /* getOwnPropertyDescriptor */ \ nullptr, /* getGenericAttributes */ \ nullptr, /* setGenericAttributes */ \ nullptr, /* deleteGeneric */ \ @@ -1009,6 +1010,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* setGeneric */ \ nullptr, /* setProperty */ \ nullptr, /* setElement */ \ + nullptr, /* getOwnPropertyDescriptor */ \ nullptr, /* getGenericAttributes */ \ nullptr, /* setGenericAttributes */ \ nullptr, /* deleteGeneric */ \