Backed out changesets 22770b30545b, 0809370fabdb, 4ef4764c1b55, and bfe768b87464 (bug 697343) due to Gaia UI test bustage.

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2013-12-05 16:19:47 -05:00
Родитель b62e9cf287
Коммит 5c07e15985
22 изменённых файлов: 308 добавлений и 276 удалений

Просмотреть файл

@ -7572,13 +7572,8 @@ class CGProxySpecialOperation(CGPerSignatureCall):
"""
Base class for classes for calling an indexed or named special operation
(don't use this directly, use the derived classes below).
If checkFound is False, will just assert that the prop is found instead of
checking that it is before wrapping the value.
"""
def __init__(self, descriptor, operation, checkFound=True):
self.checkFound = checkFound;
def __init__(self, descriptor, operation):
nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
operation = descriptor.operations[operation]
assert len(operation.signatures()) == 1
@ -7624,26 +7619,15 @@ class CGProxySpecialOperation(CGPerSignatureCall):
return ""
wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
if self.checkFound:
wrap = CGIfWrapper(wrap, "found")
else:
wrap = CGList([CGGeneric("MOZ_ASSERT(found);"), wrap], "\n")
wrap = CGIfWrapper(wrap, "found")
return "\n" + wrap.define()
class CGProxyIndexedOperation(CGProxySpecialOperation):
"""
Class to generate a call to an indexed operation.
If doUnwrap is False, the caller is responsible for making sure a variable
named 'self' holds the C++ object somewhere where the code we generate
will see it.
If checkFound is False, will just assert that the prop is found instead of
checking that it is before wrapping the value.
"""
def __init__(self, descriptor, name, doUnwrap=True, checkFound=True):
self.doUnwrap = doUnwrap
CGProxySpecialOperation.__init__(self, descriptor, name, checkFound)
def __init__(self, descriptor, name):
CGProxySpecialOperation.__init__(self, descriptor, name)
def define(self):
# Our first argument is the id we're getting.
argName = self.arguments[0].identifier.name
@ -7652,30 +7636,18 @@ class CGProxyIndexedOperation(CGProxySpecialOperation):
setIndex = ""
else:
setIndex = "uint32_t %s = index;\n" % argName
if self.doUnwrap:
unwrap = "%s* self = UnwrapProxy(proxy);\n"
else:
unwrap = ""
return (setIndex + unwrap +
return (setIndex +
"%s* self = UnwrapProxy(proxy);\n" +
CGProxySpecialOperation.define(self))
class CGProxyIndexedGetter(CGProxyIndexedOperation):
"""
Class to generate a call to an indexed getter. If templateValues is not None
the returned value will be wrapped with wrapForType using templateValues.
If doUnwrap is False, the caller is responsible for making sure a variable
named 'self' holds the C++ object somewhere where the code we generate
will see it.
If checkFound is False, will just assert that the prop is found instead of
checking that it is before wrapping the value.
"""
def __init__(self, descriptor, templateValues=None, doUnwrap=True,
checkFound=True):
def __init__(self, descriptor, templateValues=None):
self.templateValues = templateValues
CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter',
doUnwrap, checkFound)
CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter')
class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter):
"""
@ -8312,55 +8284,65 @@ class CGDOMJSProxyHandler_finalize(ClassMethod):
return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") +
finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define())
class CGDOMJSProxyHandler_slice(ClassMethod):
class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod):
def __init__(self, descriptor):
assert descriptor.supportsIndexedProperties()
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'proxy'),
Argument('uint32_t', 'begin'),
Argument('uint32_t', 'end'),
Argument('JS::Handle<JSObject*>', 'array')]
ClassMethod.__init__(self, "slice", "bool", args)
Argument('JS::Handle<JSObject*>', 'receiver'),
Argument('uint32_t', 'index'),
Argument('JS::MutableHandle<JS::Value>', 'vp'),
Argument('bool*', 'present')]
ClassMethod.__init__(self, "getElementIfPresent", "bool", args)
self.descriptor = descriptor
def getBody(self):
# Just like getOwnPropertyNames we'll assume that we have no holes, so
# we have all properties from 0 to length. If that ever changes
# (unlikely), we'll need to do something a bit more clever with how we
# forward on to our ancestor.
header = CGGeneric(
'JS::Rooted<JS::Value> temp(cx);\n'
'MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n'
' "Should not have a XrayWrapper here");\n'
'\n'
'%s* self = UnwrapProxy(proxy);\n'
'uint32_t length = self->Length();\n'
"// Compute the end of the indices we'll get ourselves\n"
'uint32_t ourEnd = std::max(begin, std::min(end, length));' %
self.descriptor.nativeType)
successCode = ("js::UnsafeDefineElement(cx, array, index - begin, temp);\n"
"continue;")
templateValues = {'jsvalRef': 'temp', 'jsvalHandle': '&temp',
successCode = ("*present = found;\n"
"return true;")
templateValues = {'jsvalRef': 'vp', 'jsvalHandle': 'vp',
'obj': 'proxy', 'successCode': successCode}
get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False)
if self.descriptor.supportsIndexedProperties():
get = (CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n"
"// We skip the expando object and any named getters if\n"
"// there is an indexed getter.\n" +
"\n") % (self.descriptor.nativeType)
else:
if self.descriptor.supportsNamedProperties():
get = CGProxyNamedGetter(self.descriptor, templateValues,
"UINT_TO_JSVAL(index)").define()
get += """
getOurElements = CGWrapper(
CGIndenter(get),
pre="for (uint32_t index = begin; index < ourEnd; ++index) {\n",
post="\n}")
JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
if (expando) {
bool isPresent;
if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) {
return false;
}
if (isPresent) {
*present = true;
return true;
}
}
"""
getProtoElements = CGIfWrapper(
CGGeneric("JS::Rooted<JSObject*> proto(cx);\n"
"if (!js::GetObjectProto(cx, proxy, &proto)) {\n"
" return false;\n"
"}\n"
"return js::SliceSlowly(cx, proto, proxy, ourEnd, end, array);"),
"end > ourEnd")
return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
"Should not have a XrayWrapper here");
return CGList([header, getOurElements, getProtoElements,
CGGeneric("return true;")], "\n\n").define();
""" + get + """
JS::Rooted<JSObject*> proto(cx);
if (!js::GetObjectProto(cx, proxy, &proto)) {
return false;
}
if (proto) {
bool isPresent;
if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) {
return false;
}
*present = isPresent;
return true;
}
*present = false;
// Can't Debug_SetValueRangeToCrashOnTouch because it's not public
return true;"""
class CGDOMJSProxyHandler_getInstance(ClassMethod):
def __init__(self):
@ -8384,11 +8366,9 @@ class CGDOMJSProxyHandler(CGClass):
CGDOMJSProxyHandler_className(descriptor),
CGDOMJSProxyHandler_finalizeInBackground(descriptor),
CGDOMJSProxyHandler_finalize(descriptor),
CGDOMJSProxyHandler_getElementIfPresent(descriptor),
CGDOMJSProxyHandler_getInstance(),
CGDOMJSProxyHandler_delete(descriptor)]
if descriptor.supportsIndexedProperties():
methods.append(CGDOMJSProxyHandler_slice(descriptor))
CGClass.__init__(self, 'DOMProxyHandler',
bases=[ClassBase('mozilla::dom::DOMProxyHandler')],
constructors=constructors,

Просмотреть файл

@ -169,11 +169,7 @@ function expandPermissions(aPerms) {
aPerms.forEach(function(el) {
var access = permTable[el].access ? "readwrite" : null;
var expanded = SpecialPowers.unwrap(expand(el, access));
// COW arrays don't behave array-like enough, to allow
// using expanded.slice(0) here.
for (let i = 0; i < expanded.length; i++) {
perms.push(expanded[i]);
}
perms = perms.concat(expanded.slice(0));
});
return perms;

Просмотреть файл

@ -347,6 +347,9 @@ typedef bool
(* ElementIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t index,
JS::MutableHandleValue vp);
typedef bool
(* ElementIfPresentOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
uint32_t index, JS::MutableHandleValue vp, bool* present);
typedef bool
(* SpecialIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
HandleSpecialId sid, JS::MutableHandleValue vp);
typedef bool
@ -380,10 +383,6 @@ typedef bool
typedef bool
(* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
typedef bool
(* SliceOp)(JSContext *cx, JS::HandleObject obj, uint32_t begin, uint32_t end,
JS::HandleObject result); // result is actually preallocted.
typedef JSObject *
(* ObjectOp)(JSContext *cx, JS::HandleObject obj);
typedef void
@ -460,6 +459,7 @@ struct ObjectOps
GenericIdOp getGeneric;
PropertyIdOp getProperty;
ElementIdOp getElement;
ElementIfPresentOp getElementIfPresent; /* can be null */
SpecialIdOp getSpecial;
StrictGenericIdOp setGeneric;
StrictPropertyIdOp setProperty;
@ -472,7 +472,6 @@ struct ObjectOps
DeleteSpecialOp deleteSpecial;
WatchOp watch;
UnwatchOp unwatch;
SliceOp slice; // Optimized slice, can be null.
JSNewEnumerateOp enumerate;
ObjectOp thisObject;
@ -481,7 +480,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,nullptr,nullptr}
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
} // namespace js

Просмотреть файл

@ -2054,6 +2054,15 @@ TypedDatum::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiv
bool
TypedDatum::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp)
{
bool present;
return obj_getElementIfPresent(cx, obj, receiver, index, vp, &present);
}
bool
TypedDatum::obj_getElementIfPresent(JSContext *cx, HandleObject obj,
HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool *present)
{
RootedObject type(cx, GetType(*obj));
TypeRepresentation *typeRepr = typeRepresentation(*type);
@ -2066,6 +2075,7 @@ TypedDatum::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receive
break;
case TypeRepresentation::Array: {
*present = true;
ArrayTypeRepresentation *arrayTypeRepr = typeRepr->asArray();
if (index >= arrayTypeRepr->length()) {
@ -2081,11 +2091,12 @@ TypedDatum::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receive
RootedObject proto(cx, obj->getProto());
if (!proto) {
*present = false;
vp.setUndefined();
return true;
}
return JSObject::getElement(cx, proto, receiver, index, vp);
return JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present);
}
bool
@ -2450,6 +2461,7 @@ const Class TypedObject::class_ = {
TypedDatum::obj_getGeneric,
TypedDatum::obj_getProperty,
TypedDatum::obj_getElement,
TypedDatum::obj_getElementIfPresent,
TypedDatum::obj_getSpecial,
TypedDatum::obj_setGeneric,
TypedDatum::obj_setProperty,
@ -2461,7 +2473,6 @@ const Class TypedObject::class_ = {
TypedDatum::obj_deleteElement,
TypedDatum::obj_deleteSpecial,
nullptr, nullptr, // watch/unwatch
nullptr, // slice
TypedDatum::obj_enumerate,
nullptr, /* thisObject */
}
@ -2542,6 +2553,7 @@ const Class TypedHandle::class_ = {
TypedDatum::obj_getGeneric,
TypedDatum::obj_getProperty,
TypedDatum::obj_getElement,
TypedDatum::obj_getElementIfPresent,
TypedDatum::obj_getSpecial,
TypedDatum::obj_setGeneric,
TypedDatum::obj_setProperty,
@ -2553,7 +2565,6 @@ const Class TypedHandle::class_ = {
TypedDatum::obj_deleteElement,
TypedDatum::obj_deleteSpecial,
nullptr, nullptr, // watch/unwatch
nullptr, // slice
TypedDatum::obj_enumerate,
nullptr, /* thisObject */
}

Просмотреть файл

@ -268,6 +268,9 @@ class TypedDatum : public JSObject
static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleSpecialId sid, MutableHandleValue vp);
static bool obj_getElementIfPresent(JSContext *cx, HandleObject obj,
HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool *present);
static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, bool strict);
static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,

Просмотреть файл

@ -1,37 +0,0 @@
let invoked = false;
Object.defineProperty(Array.prototype, '0', {set: function () {
invoked = true;
}});
let result = [1, 2, 3].slice(1);
assertEq(invoked, false);
let proxy = new Proxy({}, {
get: function (target, name, proxy) {
switch (name) {
case "length":
return 2;
case "0":
return 15;
case "1":
// Should not invoke [[Get]] for this hole.
default:
assertEq(false, true);
}
},
has: function (target, name) {
switch (name) {
case "0":
return true;
case "1":
return false;
default:
assertEq(false, true);
}
}
})
result = Array.prototype.slice.call(proxy, 0);
assertEq(result.length, 2);
assertEq(0 in result, true);
assertEq(1 in result, false);
assertEq(result[0], 15);

Просмотреть файл

@ -3393,6 +3393,25 @@ JS_ForwardGetElementTo(JSContext *cx, JSObject *objArg, uint32_t index, JSObject
return JSObject::getElement(cx, obj, onBehalfOf, index, vp);
}
JS_PUBLIC_API(bool)
JS_GetElementIfPresent(JSContext *cx, JSObject *objArg, uint32_t index, JSObject *onBehalfOfArg,
MutableHandleValue vp, bool* present)
{
RootedObject obj(cx, objArg);
RootedObject onBehalfOf(cx, onBehalfOfArg);
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JSAutoResolveFlags rf(cx, 0);
bool isPresent;
if (!JSObject::getElementIfPresent(cx, obj, onBehalfOf, index, vp, &isPresent))
return false;
*present = isPresent;
return true;
}
JS_PUBLIC_API(bool)
JS_GetProperty(JSContext *cx, JSObject *objArg, const char *name, MutableHandleValue vp)
{

Просмотреть файл

@ -3040,6 +3040,15 @@ extern JS_PUBLIC_API(bool)
JS_ForwardGetElementTo(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf,
JS::MutableHandle<JS::Value> vp);
/*
* Get the property with name given by |index|, if it has one. If
* not, |*present| will be set to false and the value of |vp| must not
* be relied on.
*/
extern JS_PUBLIC_API(bool)
JS_GetElementIfPresent(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf,
JS::MutableHandle<JS::Value> vp, bool* present);
extern JS_PUBLIC_API(bool)
JS_SetElement(JSContext *cx, JSObject *obj, uint32_t index, JS::MutableHandle<JS::Value> vp);

Просмотреть файл

@ -134,7 +134,7 @@ js::StringIsArrayIndex(JSLinearString *str, uint32_t *indexp)
}
static bool
ToId(JSContext *cx, double index, MutableHandleId id)
DoubleIndexToId(JSContext *cx, double index, MutableHandleId id)
{
if (index == uint32_t(index))
return IndexToId(cx, uint32_t(index), id.address());
@ -143,26 +143,18 @@ ToId(JSContext *cx, double index, MutableHandleId id)
return ValueToId<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp), id);
}
static bool
ToId(JSContext *cx, uint32_t index, MutableHandleId id)
{
return IndexToId(cx, index, id.address());
}
/*
* If the property at the given index exists, get its value into location
* pointed by vp and set *hole to false. Otherwise set *hole to true and *vp
* to JSVAL_VOID. This function assumes that the location pointed by vp is
* properly rooted and can be used as GC-protected storage for temporaries.
*/
template<typename IndexType>
static inline bool
DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
IndexType index, bool *hole, MutableHandleValue vp)
DoGetElement(JSContext *cx, HandleObject obj, double index, bool *hole, MutableHandleValue vp)
{
RootedId id(cx);
if (!ToId(cx, index, &id))
if (!DoubleIndexToId(cx, index, &id))
return false;
RootedObject obj2(cx);
@ -174,13 +166,27 @@ DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
vp.setUndefined();
*hole = true;
} else {
if (!JSObject::getGeneric(cx, obj, receiver, id, vp))
if (!JSObject::getGeneric(cx, obj, obj, id, vp))
return false;
*hole = false;
}
return true;
}
static inline bool
DoGetElement(JSContext *cx, HandleObject obj, uint32_t index, bool *hole, MutableHandleValue vp)
{
bool present;
if (!JSObject::getElementIfPresent(cx, obj, obj, index, vp, &present))
return false;
*hole = !present;
if (*hole)
vp.setUndefined();
return true;
}
template<typename IndexType>
static void
AssertGreaterThanZero(IndexType index)
@ -197,8 +203,7 @@ AssertGreaterThanZero(uint32_t index)
template<typename IndexType>
static bool
GetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
IndexType index, bool *hole, MutableHandleValue vp)
GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp)
{
AssertGreaterThanZero(index);
if (obj->isNative() && index < obj->getDenseInitializedLength()) {
@ -215,14 +220,7 @@ GetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
}
}
return DoGetElement(cx, obj, receiver, index, hole, vp);
}
template<typename IndexType>
static inline bool
GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp)
{
return GetElement(cx, obj, obj, index, hole, vp);
return DoGetElement(cx, obj, index, hole, vp);
}
static bool
@ -298,7 +296,7 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, HandleValue v)
}
RootedId id(cx);
if (!ToId(cx, index, &id))
if (!DoubleIndexToId(cx, index, &id))
return false;
RootedValue tmp(cx, v);
@ -2682,18 +2680,20 @@ js::array_concat(JSContext *cx, unsigned argc, Value *vp)
static bool
array_slice(JSContext *cx, unsigned argc, Value *vp)
{
uint32_t length, begin, end, slot;
bool hole;
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
return false;
uint32_t length;
if (!GetLengthProperty(cx, obj, &length))
return false;
begin = 0;
end = length;
uint32_t begin = 0;
uint32_t end = length;
if (args.length() > 0) {
double d;
if (!ToInteger(cx, args[0], &d))
@ -2741,50 +2741,20 @@ array_slice(JSContext *cx, unsigned argc, Value *vp)
return true;
}
if (js::SliceOp op = obj->getOps()->slice) {
// Ensure that we have dense elements, so that DOM can use js::UnsafeDefineElement.
JSObject::EnsureDenseResult result = narr->ensureDenseElements(cx, 0, end - begin);
if (result == JSObject::ED_FAILED)
return false;
if (result == JSObject::ED_OK) {
if (!op(cx, obj, begin, end, narr))
return false;
args.rval().setObject(*narr);
return true;
RootedValue value(cx);
for (slot = begin; slot < end; slot++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetElement(cx, obj, slot, &hole, &value)) {
return false;
}
// Fallthrough
JS_ASSERT(result == JSObject::ED_SPARSE);
if (!hole && !SetArrayElement(cx, narr, slot - begin, value))
return false;
}
if (!SliceSlowly(cx, obj, obj, begin, end, narr))
return false;
args.rval().setObject(*narr);
return true;
}
JS_FRIEND_API(bool)
js::SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver,
uint32_t begin, uint32_t end, HandleObject result)
{
RootedValue value(cx);
for (uint32_t slot = begin; slot < end; slot++) {
bool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetElement(cx, obj, receiver, slot, &hole, &value))
{
return false;
}
if (!hole && !JSObject::defineElement(cx, result, slot - begin, value))
return false;
}
return true;
}
/* ES5 15.4.4.20. */
static bool
array_filter(JSContext *cx, unsigned argc, Value *vp)

Просмотреть файл

@ -1165,14 +1165,6 @@ js::GetObjectMetadata(JSObject *obj)
return obj->getMetadata();
}
JS_FRIEND_API(void)
js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value)
{
JS_ASSERT(obj->isNative());
JS_ASSERT(index < obj->getDenseInitializedLength());
obj->setDenseElementWithType(cx, index, value);
}
JS_FRIEND_API(bool)
js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg,
JS::Handle<js::PropertyDescriptor> descriptor, bool *bp)

Просмотреть файл

@ -1739,13 +1739,6 @@ SetObjectMetadata(JSContext *cx, JS::HandleObject obj, JS::HandleObject metadata
JS_FRIEND_API(JSObject *)
GetObjectMetadata(JSObject *obj);
JS_FRIEND_API(void)
UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value);
JS_FRIEND_API(bool)
SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver,
uint32_t begin, uint32_t end, JS::HandleObject result);
/* ES5 8.12.8. */
extern JS_FRIEND_API(bool)
DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp);

Просмотреть файл

@ -1030,6 +1030,12 @@ class JSObject : public js::ObjectImpl
static inline bool getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
uint32_t index, js::Value *vp);
/* If element is not present (e.g. array hole) *present is set to
false and the contents of *vp are unusable garbage. */
static inline bool getElementIfPresent(JSContext *cx, js::HandleObject obj,
js::HandleObject receiver, uint32_t index,
js::MutableHandleValue vp, bool *present);
static bool getSpecial(JSContext *cx, js::HandleObject obj,
js::HandleObject receiver, js::SpecialId sid,
js::MutableHandleValue vp)

Просмотреть файл

@ -583,6 +583,38 @@ JSObject::getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
return getGenericNoGC(cx, obj, receiver, id, vp);
}
/* static */ inline bool
JSObject::getElementIfPresent(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
uint32_t index, js::MutableHandleValue vp,
bool *present)
{
js::ElementIfPresentOp op = obj->getOps()->getElementIfPresent;
if (op)
return op(cx, obj, 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.
*/
JS::RootedId id(cx);
if (!js::IndexToId(cx, index, id.address()))
return false;
JS::RootedObject obj2(cx);
js::RootedShape prop(cx);
if (!lookupGeneric(cx, obj, id, &obj2, &prop))
return false;
if (!prop) {
*present = false;
return true;
}
*present = true;
return getGeneric(cx, obj, receiver, id, vp);
}
inline js::GlobalObject &
JSObject::global() const
{

Просмотреть файл

@ -151,6 +151,27 @@ BaseProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
return CallJSPropertyOp(cx, desc.getter(), receiver, id, vp);
}
bool
BaseProxyHandler::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present)
{
RootedId id(cx);
if (!IndexToId(cx, index, id.address()))
return false;
assertEnteredPolicy(cx, proxy, id);
if (!has(cx, proxy, id, present))
return false;
if (!*present) {
Debug_SetValueRangeToCrashOnTouch(vp.address(), 1);
return true;
}
return get(cx, proxy, receiver, id, vp);
}
bool
BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp)
@ -364,34 +385,6 @@ BaseProxyHandler::unwatch(JSContext *cx, HandleObject proxy, HandleId id)
return true;
}
bool
BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
RootedId id(cx);
RootedValue value(cx);
for (uint32_t index = begin; index < end; index++) {
if (!IndexToId(cx, index, id.address()))
return false;
bool present;
if (!Proxy::has(cx, proxy, id, &present))
return false;
if (present) {
if (!Proxy::get(cx, proxy, proxy, id, &value))
return false;
if (!JSObject::defineElement(cx, result, index - begin, value))
return false;
}
}
return true;
}
bool
DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc, unsigned flags)
@ -2526,6 +2519,41 @@ Proxy::callProp(JSContext *cx, HandleObject proxy, HandleObject receiver, Handle
return true;
}
bool
Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool *present)
{
JS_CHECK_RECURSION(cx, return false);
RootedId id(cx);
if (!IndexToId(cx, index, id.address()))
return false;
BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
if (!policy.allowed())
return policy.returnValue();
if (!handler->hasPrototype()) {
return handler->getElementIfPresent(cx, proxy, receiver, index,
vp, present);
}
bool hasOwn;
if (!handler->hasOwn(cx, proxy, id, &hasOwn))
return false;
if (hasOwn) {
*present = true;
return proxy->as<ProxyObject>().handler()->get(cx, proxy, receiver, id, vp);
}
*present = false;
INVOKE_ON_PROTOTYPE(cx, handler, proxy,
JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present));
}
bool
Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
MutableHandleValue vp)
@ -2748,18 +2776,6 @@ Proxy::unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id)
return proxy->as<ProxyObject>().handler()->unwatch(cx, proxy, id);
}
/* static */ bool
Proxy::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result)
{
JS_CHECK_RECURSION(cx, return false);
BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
if (!policy.allowed())
return policy.returnValue();
return handler->slice(cx, proxy, begin, end, result);
}
static JSObject *
proxy_innerObject(JSContext *cx, HandleObject obj)
{
@ -2875,6 +2891,13 @@ proxy_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_
return proxy_GetGeneric(cx, obj, receiver, id, vp);
}
static bool
proxy_GetElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool *present)
{
return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present);
}
static bool
proxy_GetSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid,
MutableHandleValue vp)
@ -3053,24 +3076,17 @@ proxy_Construct(JSContext *cx, unsigned argc, Value *vp)
}
static bool
proxy_Watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable)
proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable)
{
return Proxy::watch(cx, obj, id, callable);
}
static bool
proxy_Unwatch(JSContext *cx, HandleObject obj, HandleId id)
proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id)
{
return Proxy::unwatch(cx, obj, id);
}
static bool
proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result)
{
return Proxy::slice(cx, proxy, begin, end, result);
}
#define PROXY_CLASS_EXT \
{ \
nullptr, /* outerObject */ \
@ -3112,6 +3128,7 @@ proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
proxy_GetGeneric, \
proxy_GetProperty, \
proxy_GetElement, \
proxy_GetElementIfPresent, \
proxy_GetSpecial, \
proxy_SetGeneric, \
proxy_SetProperty, \
@ -3123,7 +3140,6 @@ proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
proxy_DeleteElement, \
proxy_DeleteSpecial, \
proxy_Watch, proxy_Unwatch, \
proxy_Slice, \
nullptr, /* enumerate */ \
nullptr, /* thisObject */ \
} \
@ -3170,6 +3186,7 @@ const Class js::OuterWindowProxyObject::class_ = {
proxy_GetGeneric,
proxy_GetProperty,
proxy_GetElement,
proxy_GetElementIfPresent,
proxy_GetSpecial,
proxy_SetGeneric,
proxy_SetProperty,
@ -3181,7 +3198,6 @@ const Class js::OuterWindowProxyObject::class_ = {
proxy_DeleteElement,
proxy_DeleteSpecial,
proxy_Watch, proxy_Unwatch,
proxy_Slice,
nullptr, /* enumerate */
nullptr, /* thisObject */
}

Просмотреть файл

@ -166,6 +166,8 @@ class JS_FRIEND_API(BaseProxyHandler)
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
virtual void finalize(JSFreeOp *fop, JSObject *proxy);
virtual bool getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present);
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
// These two hooks must be overridden, or not overridden, in tandem -- no
@ -174,9 +176,6 @@ class JS_FRIEND_API(BaseProxyHandler)
JS::HandleObject callable);
virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id);
virtual bool slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result);
/* See comment for weakmapKeyDelegateOp in js/Class.h. */
virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
virtual bool isScripted() { return false; }
@ -277,6 +276,8 @@ class Proxy
static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp);
static bool getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present);
static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp);
static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
@ -295,11 +296,9 @@ class Proxy
static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable);
static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id);
static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
HandleObject result);
static bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::HandleObject callable);
static bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id);
/* IC entry path for handling __noSuchMethod__ on access. */
static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,

Просмотреть файл

@ -839,6 +839,14 @@ DeadObjectProxy::defaultValue(JSContext *cx, HandleObject obj, JSType hint, Muta
return false;
}
bool
DeadObjectProxy::getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop)
{

Просмотреть файл

@ -208,6 +208,9 @@ class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
MutableHandleValue vp) MOZ_OVERRIDE;
virtual bool getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp,
bool *present) MOZ_OVERRIDE;
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
MutableHandleObject protop) MOZ_OVERRIDE;

Просмотреть файл

@ -557,6 +557,7 @@ const Class WithObject::class_ = {
with_GetGeneric,
with_GetProperty,
with_GetElement,
nullptr, /* getElementIfPresent */
with_GetSpecial,
with_SetGeneric,
with_SetProperty,
@ -567,8 +568,7 @@ const Class WithObject::class_ = {
with_DeleteProperty,
with_DeleteElement,
with_DeleteSpecial,
nullptr, nullptr, /* watch/unwatch */
nullptr, /* slice */
nullptr, nullptr, /* watch/unwatch */
with_Enumerate,
with_ThisObject,
}

Просмотреть файл

@ -1037,6 +1037,16 @@ ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj,
return baseops::GetElement(cx, delegate, receiver, index, vp);
}
bool
ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present)
{
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
if (!delegate)
return false;
return JSObject::getElementIfPresent(cx, delegate, receiver, index, vp, present);
}
bool
ArrayBufferObject::obj_getSpecial(JSContext *cx, HandleObject obj,
HandleObject receiver, HandleSpecialId sid,
@ -1484,6 +1494,27 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return obj_getProperty(cx, obj, receiver, name, vp);
}
static bool
obj_getElementIfPresent(JSContext *cx, HandleObject tarray, HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool *present)
{
// Fast-path the common case of index < length
if (index < tarray->as<TypedArrayObject>().length()) {
// this inline function is specialized for each type
copyIndexToValue(tarray, index, vp);
*present = true;
return true;
}
RootedObject proto(cx, tarray->getProto());
if (!proto) {
vp.setUndefined();
return true;
}
return JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present);
}
static bool
setElementTail(JSContext *cx, HandleObject tarray, uint32_t index,
MutableHandleValue vp, bool strict)
@ -3449,6 +3480,7 @@ const Class ArrayBufferObject::class_ = {
ArrayBufferObject::obj_getGeneric,
ArrayBufferObject::obj_getProperty,
ArrayBufferObject::obj_getElement,
ArrayBufferObject::obj_getElementIfPresent,
ArrayBufferObject::obj_getSpecial,
ArrayBufferObject::obj_setGeneric,
ArrayBufferObject::obj_setProperty,
@ -3460,9 +3492,8 @@ const Class ArrayBufferObject::class_ = {
ArrayBufferObject::obj_deleteElement,
ArrayBufferObject::obj_deleteSpecial,
nullptr, nullptr, /* watch/unwatch */
nullptr, /* slice */
ArrayBufferObject::obj_enumerate,
nullptr, /* thisObject */
nullptr, /* thisObject */
}
};
@ -3612,6 +3643,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
_typedArray##Object::obj_getGeneric, \
_typedArray##Object::obj_getProperty, \
_typedArray##Object::obj_getElement, \
_typedArray##Object::obj_getElementIfPresent, \
_typedArray##Object::obj_getSpecial, \
_typedArray##Object::obj_setGeneric, \
_typedArray##Object::obj_setProperty, \
@ -3623,9 +3655,8 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
_typedArray##Object::obj_deleteElement, \
_typedArray##Object::obj_deleteSpecial, \
nullptr, nullptr, /* watch/unwatch */ \
nullptr, /* slice */ \
_typedArray##Object::obj_enumerate, \
nullptr, /* thisObject */ \
nullptr, /* thisObject */ \
} \
}

Просмотреть файл

@ -107,6 +107,8 @@ class ArrayBufferObject : public JSObject
static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp);
static bool obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present);
static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleSpecialId sid, MutableHandleValue vp);

Просмотреть файл

@ -720,6 +720,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = {
nullptr, // getGeneric
nullptr, // getProperty
nullptr, // getElement
nullptr, // getElementIfPresent
nullptr, // getSpecial
nullptr, // setGeneric
nullptr, // setProperty
@ -731,7 +732,6 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = {
nullptr, // deleteElement
nullptr, // deleteSpecial
nullptr, nullptr, // watch/unwatch
nullptr, // slice
XPC_WN_JSOp_Enumerate,
XPC_WN_JSOp_ThisObject,
}

Просмотреть файл

@ -982,6 +982,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj);
nullptr, /* getGeneric */ \
nullptr, /* getProperty */ \
nullptr, /* getElement */ \
nullptr, /* getElementIfPresent */ \
nullptr, /* getSpecial */ \
nullptr, /* setGeneric */ \
nullptr, /* setProperty */ \
@ -993,7 +994,6 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj);
nullptr, /* deleteElement */ \
nullptr, /* deleteSpecial */ \
nullptr, nullptr, /* watch/unwatch */ \
nullptr, /* slice */ \
XPC_WN_JSOp_Enumerate, \
XPC_WN_JSOp_ThisObject, \
}
@ -1011,6 +1011,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj);
nullptr, /* getGeneric */ \
nullptr, /* getProperty */ \
nullptr, /* getElement */ \
nullptr, /* getElementIfPresent */ \
nullptr, /* getSpecial */ \
nullptr, /* setGeneric */ \
nullptr, /* setProperty */ \
@ -1022,7 +1023,6 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj);
nullptr, /* deleteElement */ \
nullptr, /* deleteSpecial */ \
nullptr, nullptr, /* watch/unwatch */ \
nullptr, /* slice */ \
XPC_WN_JSOp_Enumerate, \
XPC_WN_JSOp_ThisObject, \
}