зеркало из https://github.com/mozilla/pjs.git
Implement ES Harmony Proxies (bug 546590, r=mrbkap).
This commit is contained in:
Родитель
9990eee027
Коммит
11fd8abaee
|
@ -152,6 +152,7 @@ CPPSRCS = \
|
||||||
json.cpp \
|
json.cpp \
|
||||||
jsopcode.cpp \
|
jsopcode.cpp \
|
||||||
jsparse.cpp \
|
jsparse.cpp \
|
||||||
|
jsproxy.cpp \
|
||||||
jsprf.cpp \
|
jsprf.cpp \
|
||||||
jspropertycache.cpp \
|
jspropertycache.cpp \
|
||||||
jspropertytree.cpp \
|
jspropertytree.cpp \
|
||||||
|
@ -208,6 +209,7 @@ INSTALLED_HEADERS = \
|
||||||
jsopcode.h \
|
jsopcode.h \
|
||||||
jsotypes.h \
|
jsotypes.h \
|
||||||
jsparse.h \
|
jsparse.h \
|
||||||
|
jsproxy.h \
|
||||||
jsprf.h \
|
jsprf.h \
|
||||||
jspropertycache.h \
|
jspropertycache.h \
|
||||||
jspropertycacheinlines.h \
|
jspropertycacheinlines.h \
|
||||||
|
|
|
@ -328,3 +328,4 @@ MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG, 245, 1, JSEXN_ERR, "argument {0} must be
|
||||||
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 246, 0, JSEXN_ERR, "invalid arguments")
|
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 246, 0, JSEXN_ERR, "invalid arguments")
|
||||||
MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 247, 0, JSEXN_ERR, "call to Function() blocked by CSP")
|
MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 247, 0, JSEXN_ERR, "call to Function() blocked by CSP")
|
||||||
MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 248, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
|
MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 248, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
|
||||||
|
MSG_DEF(JSMSG_BAD_PROXY_FIX, 249, 0, JSEXN_TYPEERR, "proxy was fixed while executing the handler")
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
#include "jsparse.h"
|
#include "jsparse.h"
|
||||||
|
#include "jsproxy.h"
|
||||||
#include "jsregexp.h"
|
#include "jsregexp.h"
|
||||||
#include "jsscan.h"
|
#include "jsscan.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
|
@ -1213,7 +1214,8 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
|
||||||
#if JS_HAS_GENERATORS
|
#if JS_HAS_GENERATORS
|
||||||
js_InitIteratorClasses(cx, obj) &&
|
js_InitIteratorClasses(cx, obj) &&
|
||||||
#endif
|
#endif
|
||||||
js_InitDateClass(cx, obj);
|
js_InitDateClass(cx, obj) &&
|
||||||
|
js_InitProxyClass(cx, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CLASP(name) (&js_##name##Class)
|
#define CLASP(name) (&js_##name##Class)
|
||||||
|
@ -1340,6 +1342,8 @@ static JSStdName standard_class_names[] = {
|
||||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), NULL},
|
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), NULL},
|
||||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray), NULL},
|
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray), NULL},
|
||||||
|
|
||||||
|
{js_InitProxyClass, EAGER_ATOM(Proxy), NULL},
|
||||||
|
|
||||||
{NULL, 0, NULL, NULL}
|
{NULL, 0, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1502,13 +1506,15 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSIdArray *
|
namespace js {
|
||||||
|
|
||||||
|
JSIdArray *
|
||||||
NewIdArray(JSContext *cx, jsint length)
|
NewIdArray(JSContext *cx, jsint length)
|
||||||
{
|
{
|
||||||
JSIdArray *ida;
|
JSIdArray *ida;
|
||||||
|
|
||||||
ida = (JSIdArray *)
|
ida = (JSIdArray *)
|
||||||
cx->malloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
|
cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
|
||||||
if (ida) {
|
if (ida) {
|
||||||
ida->self = ida;
|
ida->self = ida;
|
||||||
ida->length = length;
|
ida->length = length;
|
||||||
|
@ -1516,6 +1522,8 @@ NewIdArray(JSContext *cx, jsint length)
|
||||||
return ida;
|
return ida;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unlike realloc(3), this function frees ida on failure.
|
* Unlike realloc(3), this function frees ida on failure.
|
||||||
*/
|
*/
|
||||||
|
@ -1524,13 +1532,13 @@ SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
|
||||||
{
|
{
|
||||||
JSIdArray *rida;
|
JSIdArray *rida;
|
||||||
|
|
||||||
|
JS_ASSERT(ida->self == ida);
|
||||||
rida = (JSIdArray *)
|
rida = (JSIdArray *)
|
||||||
JS_realloc(cx, ida,
|
JS_realloc(cx, ida,
|
||||||
offsetof(JSIdArray, vector) + length * sizeof(jsval));
|
offsetof(JSIdArray, vector) + length * sizeof(jsval));
|
||||||
if (!rida) {
|
if (!rida) {
|
||||||
JS_DestroyIdArray(cx, ida);
|
JS_DestroyIdArray(cx, ida);
|
||||||
} else {
|
} else {
|
||||||
rida->self = rida;
|
|
||||||
rida->length = length;
|
rida->length = length;
|
||||||
}
|
}
|
||||||
return rida;
|
return rida;
|
||||||
|
@ -3120,6 +3128,12 @@ GetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||||
? obj2->lockedGetSlot(sprop->slot)
|
? obj2->lockedGetSlot(sprop->slot)
|
||||||
: JSVAL_VOID;
|
: JSVAL_VOID;
|
||||||
} else {
|
} else {
|
||||||
|
if (obj->isProxy()) {
|
||||||
|
JSAutoResolveFlags rf(cx, flags);
|
||||||
|
return own
|
||||||
|
? JSProxy::getOwnPropertyDescriptor(cx, obj, id, desc)
|
||||||
|
: JSProxy::getPropertyDescriptor(cx, obj, id, desc);
|
||||||
|
}
|
||||||
desc->getter = NULL;
|
desc->getter = NULL;
|
||||||
desc->setter = NULL;
|
desc->setter = NULL;
|
||||||
desc->value = JSVAL_VOID;
|
desc->value = JSVAL_VOID;
|
||||||
|
|
|
@ -284,6 +284,8 @@ BOOLEAN_TO_JSVAL(JSBool b)
|
||||||
object that delegates to a prototype
|
object that delegates to a prototype
|
||||||
containing this property */
|
containing this property */
|
||||||
#define JSPROP_INDEX 0x80 /* name is actually (jsint) index */
|
#define JSPROP_INDEX 0x80 /* name is actually (jsint) index */
|
||||||
|
#define JSPROP_SHORTID 0x100 /* set in JSPropertyDescriptor.attrs
|
||||||
|
if getters/setters use a shortid */
|
||||||
|
|
||||||
/* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */
|
/* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */
|
||||||
#define JSFUN_LAMBDA 0x08 /* expressed, not declared, function */
|
#define JSFUN_LAMBDA 0x08 /* expressed, not declared, function */
|
||||||
|
@ -1821,6 +1823,7 @@ struct JSPropertyDescriptor {
|
||||||
uintN attrs;
|
uintN attrs;
|
||||||
JSPropertyOp getter;
|
JSPropertyOp getter;
|
||||||
JSPropertyOp setter;
|
JSPropertyOp setter;
|
||||||
|
uintN shortid;
|
||||||
jsval value;
|
jsval value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,20 @@ const char *const js_common_atom_names[] = {
|
||||||
js_ExecutionContext_str, /* ExecutionContextAtom */
|
js_ExecutionContext_str, /* ExecutionContextAtom */
|
||||||
js_current_str, /* currentAtom */
|
js_current_str, /* currentAtom */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
"Proxy", /* ProxyAtom */
|
||||||
|
|
||||||
|
"getOwnPropertyDescriptor", /* getOwnPropertyDescriptorAtom */
|
||||||
|
"getPropertyDescriptor", /* getPropertyDescriptorAtom */
|
||||||
|
"defineProperty", /* definePropertyAtom */
|
||||||
|
"delete", /* deleteAtom */
|
||||||
|
"getOwnPropertyNames", /* getOwnPropertyNames */
|
||||||
|
"enumerate", /* enumerateAtom */
|
||||||
|
"fix",
|
||||||
|
|
||||||
|
"has", /* hasAtom */
|
||||||
|
"hasOwn", /* hasOwnAtom */
|
||||||
|
"enumerateOwn" /* enumerateOwnAtom */
|
||||||
};
|
};
|
||||||
|
|
||||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) ==
|
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) ==
|
||||||
|
|
|
@ -295,6 +295,20 @@ struct JSAtomState {
|
||||||
JSAtom *currentAtom;
|
JSAtom *currentAtom;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
JSAtom *ProxyAtom;
|
||||||
|
|
||||||
|
JSAtom *getOwnPropertyDescriptorAtom;
|
||||||
|
JSAtom *getPropertyDescriptorAtom;
|
||||||
|
JSAtom *definePropertyAtom;
|
||||||
|
JSAtom *deleteAtom;
|
||||||
|
JSAtom *getOwnPropertyNamesAtom;
|
||||||
|
JSAtom *enumerateAtom;
|
||||||
|
JSAtom *fixAtom;
|
||||||
|
|
||||||
|
JSAtom *hasAtom;
|
||||||
|
JSAtom *hasOwnAtom;
|
||||||
|
JSAtom *enumerateOwnAtom;
|
||||||
|
|
||||||
/* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
|
/* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
|
||||||
struct {
|
struct {
|
||||||
JSAtom *InfinityAtom;
|
JSAtom *InfinityAtom;
|
||||||
|
@ -325,6 +339,8 @@ struct JSAtomState {
|
||||||
} lazy;
|
} lazy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ATOM(name) cx->runtime->atomState.name##Atom
|
||||||
|
|
||||||
#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom)
|
#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom)
|
||||||
#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy)
|
#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy)
|
||||||
#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState))
|
#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState))
|
||||||
|
|
|
@ -2174,7 +2174,8 @@ class AutoGCRooter {
|
||||||
XML = -10, /* js::AutoXMLRooter */
|
XML = -10, /* js::AutoXMLRooter */
|
||||||
OBJECT = -11, /* js::AutoObjectRooter */
|
OBJECT = -11, /* js::AutoObjectRooter */
|
||||||
ID = -12, /* js::AutoIdRooter */
|
ID = -12, /* js::AutoIdRooter */
|
||||||
VECTOR = -13 /* js::AutoValueVector */
|
VECTOR = -13, /* js::AutoValueVector */
|
||||||
|
DESCRIPTOR = -14 /* js::AutoDescriptor */
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -2404,11 +2405,17 @@ class AutoIdArray : private AutoGCRooter {
|
||||||
|
|
||||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||||
|
|
||||||
|
JSIdArray *steal() {
|
||||||
|
JSIdArray *copy = idArray;
|
||||||
|
idArray = NULL;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline void trace(JSTracer *trc);
|
inline void trace(JSTracer *trc);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSIdArray * const idArray;
|
JSIdArray * idArray;
|
||||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||||
|
|
||||||
/* No copy or assignment semantics. */
|
/* No copy or assignment semantics. */
|
||||||
|
@ -3023,6 +3030,9 @@ class AutoValueVector : private AutoGCRooter
|
||||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
JSIdArray *
|
||||||
|
NewIdArray(JSContext *cx, jsint length);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
|
@ -235,6 +235,7 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||||
for (size_t i = 0, len = descriptors.length(); i < len; i++) {
|
for (size_t i = 0, len = descriptors.length(); i < len; i++) {
|
||||||
PropertyDescriptor &desc = descriptors[i];
|
PropertyDescriptor &desc = descriptors[i];
|
||||||
|
|
||||||
|
JS_CALL_VALUE_TRACER(trc, desc.pd, "PropertyDescriptor::pd");
|
||||||
JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value");
|
JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value");
|
||||||
JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get");
|
JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get");
|
||||||
JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set");
|
JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set");
|
||||||
|
@ -243,6 +244,17 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DESCRIPTOR : {
|
||||||
|
AutoDescriptor &desc = *static_cast<AutoDescriptor *>(this);
|
||||||
|
JS_CALL_OBJECT_TRACER(trc, desc.obj, "Descriptor::obj");
|
||||||
|
JS_CALL_VALUE_TRACER(trc, desc.value, "Descriptor::value");
|
||||||
|
if (desc.attrs & JSPROP_GETTER)
|
||||||
|
JS_CALL_VALUE_TRACER(trc, jsval(desc.getter), "Descriptor::get");
|
||||||
|
if (desc.attrs & JSPROP_SETTER)
|
||||||
|
JS_CALL_VALUE_TRACER(trc, jsval(desc.setter), "Descriptor::set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
case NAMESPACES: {
|
case NAMESPACES: {
|
||||||
JSXMLArray &array = static_cast<AutoNamespaces *>(this)->array;
|
JSXMLArray &array = static_cast<AutoNamespaces *>(this)->array;
|
||||||
TraceObjectVector(trc, reinterpret_cast<JSObject **>(array.vector), array.length);
|
TraceObjectVector(trc, reinterpret_cast<JSObject **>(array.vector), array.length);
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
#include "jsnum.h"
|
#include "jsnum.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsparse.h"
|
#include "jsparse.h"
|
||||||
|
#include "jsproxy.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
|
@ -2384,6 +2385,12 @@ FinalizeObject(JSContext *cx, JSObject *obj, unsigned thingKind)
|
||||||
static_cast<JSEmptyScope *>(scope)->dropFromGC(cx);
|
static_cast<JSEmptyScope *>(scope)->dropFromGC(cx);
|
||||||
else
|
else
|
||||||
scope->destroy(cx);
|
scope->destroy(cx);
|
||||||
|
} else {
|
||||||
|
if (obj->isProxy()) {
|
||||||
|
jsval handler = obj->getProxyHandler();
|
||||||
|
if (JSVAL_IS_PRIMITIVE(handler))
|
||||||
|
((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->finalize(cx, obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (obj->hasSlotsArray())
|
if (obj->hasSlotsArray())
|
||||||
obj->freeSlotsArray(cx);
|
obj->freeSlotsArray(cx);
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#include "jsnum.h"
|
#include "jsnum.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
|
#include "jsproxy.h"
|
||||||
#include "jsscan.h"
|
#include "jsscan.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
|
@ -163,7 +164,7 @@ Enumerate(JSContext *cx, JSObject *obj, JSObject *pobj, jsid id,
|
||||||
if (pobj->getProto() && !ht.add(p, id))
|
if (pobj->getProto() && !ht.add(p, id))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (enumerable) {
|
if (enumerable || (flags & JSITER_HIDDEN)) {
|
||||||
if (!vec.append(ID_TO_VALUE(id))) {
|
if (!vec.append(ID_TO_VALUE(id))) {
|
||||||
JS_ReportOutOfMemory(cx);
|
JS_ReportOutOfMemory(cx);
|
||||||
return false;
|
return false;
|
||||||
|
@ -232,6 +233,32 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
MakeNativeIterator(JSContext *cx, uintN flags, uint32 *sarray, uint32 slength, uint32 key,
|
||||||
|
jsval *parray, uint32 plength, NativeIterator **nip)
|
||||||
|
{
|
||||||
|
NativeIterator *ni = (NativeIterator *)
|
||||||
|
cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsval) + slength * sizeof(uint32));
|
||||||
|
if (!ni) {
|
||||||
|
JS_ReportOutOfMemory(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ni->props_array = ni->props_cursor = (jsval *) (ni + 1);
|
||||||
|
ni->props_end = ni->props_array + plength;
|
||||||
|
if (plength)
|
||||||
|
memcpy(ni->props_array, parray, plength * sizeof(jsval));
|
||||||
|
ni->shapes_array = (uint32 *) ni->props_end;
|
||||||
|
ni->shapes_length = slength;
|
||||||
|
ni->shapes_key = key;
|
||||||
|
ni->flags = flags;
|
||||||
|
if (slength)
|
||||||
|
memcpy(ni->shapes_array, sarray, slength * sizeof(uint32));
|
||||||
|
|
||||||
|
*nip = ni;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, uint32 slength,
|
InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, uint32 slength,
|
||||||
uint32 key, NativeIterator **nip)
|
uint32 key, NativeIterator **nip)
|
||||||
|
@ -256,6 +283,23 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
|
||||||
if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props))
|
if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
if (pobj->isProxy()) {
|
||||||
|
JSIdArray *ida;
|
||||||
|
if (flags & JSITER_OWNONLY) {
|
||||||
|
if (!JSProxy::enumerateOwn(cx, pobj, &ida))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (!JSProxy::enumerate(cx, pobj, &ida))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AutoIdArray idar(cx, ida);
|
||||||
|
for (size_t n = 0; n < size_t(ida->length); ++n) {
|
||||||
|
if (!Enumerate(cx, obj, pobj, ida->vector[n], true, flags, ht, props))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Proxy objects enumerate the prototype on their own, so we are done here. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
jsval state;
|
jsval state;
|
||||||
if (!pobj->enumerate(cx, JSENUMERATE_INIT, &state, NULL))
|
if (!pobj->enumerate(cx, JSENUMERATE_INIT, &state, NULL))
|
||||||
return false;
|
return false;
|
||||||
|
@ -281,37 +325,12 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
|
||||||
pobj = pobj->getProto();
|
pobj = pobj->getProto();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t plength = props.length();
|
return MakeNativeIterator(cx, flags, sarray, slength, key, props.begin(), props.length(), nip);
|
||||||
|
|
||||||
NativeIterator *ni = (NativeIterator *)
|
|
||||||
cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsval) + slength * sizeof(uint32));
|
|
||||||
if (!ni) {
|
|
||||||
JS_ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ni->props_array = ni->props_cursor = (jsval *) (ni + 1);
|
|
||||||
ni->props_end = ni->props_array + plength;
|
|
||||||
if (plength)
|
|
||||||
memcpy(ni->props_array, props.begin(), plength * sizeof(jsval));
|
|
||||||
ni->shapes_array = (uint32 *) ni->props_end;
|
|
||||||
ni->shapes_length = slength;
|
|
||||||
ni->shapes_key = key;
|
|
||||||
ni->flags = flags;
|
|
||||||
if (slength)
|
|
||||||
memcpy(ni->shapes_array, sarray, slength * sizeof(uint32));
|
|
||||||
|
|
||||||
*nip = ni;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
EnumerateOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
NativeIteratorToJSIdArray(JSContext *cx, NativeIterator *ni, JSIdArray **idap)
|
||||||
{
|
{
|
||||||
NativeIterator *ni;
|
|
||||||
if (!InitNativeIterator(cx, obj, JSITER_OWNONLY, NULL, 0, true, &ni))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Morph the NativeIterator into a JSIdArray. The caller will deallocate it. */
|
/* Morph the NativeIterator into a JSIdArray. The caller will deallocate it. */
|
||||||
JS_ASSERT(sizeof(NativeIterator) > sizeof(JSIdArray));
|
JS_ASSERT(sizeof(NativeIterator) > sizeof(JSIdArray));
|
||||||
JS_ASSERT(ni->props_array == (jsid *) (ni + 1));
|
JS_ASSERT(ni->props_array == (jsid *) (ni + 1));
|
||||||
|
@ -324,6 +343,33 @@ EnumerateOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
EnumerateOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
||||||
|
{
|
||||||
|
NativeIterator *ni;
|
||||||
|
if (!InitNativeIterator(cx, obj, JSITER_OWNONLY, NULL, 0, true, &ni))
|
||||||
|
return false;
|
||||||
|
return NativeIteratorToJSIdArray(cx, ni, idap);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
EnumerateAllProperties(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
||||||
|
{
|
||||||
|
NativeIterator *ni;
|
||||||
|
if (!InitNativeIterator(cx, obj, 0, NULL, 0, true, &ni))
|
||||||
|
return false;
|
||||||
|
return NativeIteratorToJSIdArray(cx, ni, idap);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
GetOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
||||||
|
{
|
||||||
|
NativeIterator *ni;
|
||||||
|
if (!InitNativeIterator(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, NULL, 0, true, &ni))
|
||||||
|
return false;
|
||||||
|
return NativeIteratorToJSIdArray(cx, ni, idap);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp)
|
GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp)
|
||||||
{
|
{
|
||||||
|
@ -418,10 +464,12 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
miss:
|
miss:
|
||||||
if (!GetCustomIterator(cx, obj, flags, vp))
|
if (!obj->isProxy()) {
|
||||||
return false;
|
if (!GetCustomIterator(cx, obj, flags, vp))
|
||||||
if (*vp != JSVAL_VOID)
|
return false;
|
||||||
return true;
|
if (*vp != JSVAL_VOID)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *iterobj = escaping
|
JSObject *iterobj = escaping
|
||||||
|
|
|
@ -58,6 +58,7 @@ JS_BEGIN_EXTERN_C
|
||||||
#define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */
|
#define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */
|
||||||
#define JSITER_KEYVALUE 0x4 /* destructuring for-in wants [key, value] */
|
#define JSITER_KEYVALUE 0x4 /* destructuring for-in wants [key, value] */
|
||||||
#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */
|
#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */
|
||||||
|
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */
|
||||||
|
|
||||||
struct NativeIterator {
|
struct NativeIterator {
|
||||||
jsval *props_array;
|
jsval *props_array;
|
||||||
|
@ -82,6 +83,12 @@ static const jsval JSVAL_NATIVE_ENUMERATE_COOKIE = SPECIAL_TO_JSVAL(0x220576);
|
||||||
bool
|
bool
|
||||||
EnumerateOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap);
|
EnumerateOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap);
|
||||||
|
|
||||||
|
bool
|
||||||
|
EnumerateAllProperties(JSContext *cx, JSObject *obj, JSIdArray **idap);
|
||||||
|
|
||||||
|
bool
|
||||||
|
GetOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert the value stored in *vp to its iteration object. The flags should
|
* Convert the value stored in *vp to its iteration object. The flags should
|
||||||
* contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating
|
* contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating
|
||||||
|
|
212
js/src/jsobj.cpp
212
js/src/jsobj.cpp
|
@ -69,6 +69,7 @@
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
#include "jsparse.h"
|
#include "jsparse.h"
|
||||||
|
#include "jsproxy.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
|
@ -871,8 +872,13 @@ obj_toString(JSContext *cx, uintN argc, jsval *vp)
|
||||||
obj = JS_THIS_OBJECT(cx, vp);
|
obj = JS_THIS_OBJECT(cx, vp);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
obj = js_GetWrappedObject(cx, obj);
|
if (obj->isProxy()) {
|
||||||
clazz = obj->getClass()->name;
|
if (!JS_GetProxyObjectClass(cx, obj, &clazz))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
obj = js_GetWrappedObject(cx, obj);
|
||||||
|
clazz = obj->getClass()->name;
|
||||||
|
}
|
||||||
nchars = 9 + strlen(clazz); /* 9 for "[object ]" */
|
nchars = 9 + strlen(clazz); /* 9 for "[object ]" */
|
||||||
chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar));
|
chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar));
|
||||||
if (!chars)
|
if (!chars)
|
||||||
|
@ -1472,7 +1478,16 @@ js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc,
|
||||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||||
JSObject *obj2;
|
JSObject *obj2;
|
||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
if (!obj || !js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
|
if (!obj)
|
||||||
|
return false;
|
||||||
|
if (obj->isProxy()) {
|
||||||
|
bool has;
|
||||||
|
if (!JSProxy::hasOwn(cx, obj, id, &has))
|
||||||
|
return false;
|
||||||
|
*vp = BOOLEAN_TO_JSVAL(has);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (prop) {
|
if (prop) {
|
||||||
*vp = JSVAL_TRUE;
|
*vp = JSVAL_TRUE;
|
||||||
|
@ -1755,9 +1770,49 @@ obj_getPrototypeOf(JSContext *cx, uintN argc, jsval *vp)
|
||||||
JSACC_PROTO, vp, &attrs);
|
JSACC_PROTO, vp, &attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern JSBool
|
||||||
|
js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, jsval getter, jsval setter, jsval value, jsval *vp)
|
||||||
|
{
|
||||||
|
/* We have our own property, so start creating the descriptor. */
|
||||||
|
JSObject *desc = NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||||
|
if (!desc)
|
||||||
|
return false;
|
||||||
|
*vp = OBJECT_TO_JSVAL(desc); /* Root and return. */
|
||||||
|
|
||||||
|
const JSAtomState &atomState = cx->runtime->atomState;
|
||||||
|
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
||||||
|
if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.getAtom), getter,
|
||||||
|
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) ||
|
||||||
|
!desc->defineProperty(cx, ATOM_TO_JSID(atomState.setAtom), setter,
|
||||||
|
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.valueAtom), value,
|
||||||
|
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) ||
|
||||||
|
!desc->defineProperty(cx, ATOM_TO_JSID(atomState.writableAtom),
|
||||||
|
BOOLEAN_TO_JSVAL((attrs & JSPROP_READONLY) == 0),
|
||||||
|
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc->defineProperty(cx, ATOM_TO_JSID(atomState.enumerableAtom),
|
||||||
|
BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0),
|
||||||
|
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) &&
|
||||||
|
desc->defineProperty(cx, ATOM_TO_JSID(atomState.configurableAtom),
|
||||||
|
BOOLEAN_TO_JSVAL((attrs & JSPROP_PERMANENT) == 0),
|
||||||
|
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE);
|
||||||
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||||
{
|
{
|
||||||
|
if (obj->isProxy()) {
|
||||||
|
if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, vp))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
JSObject *pobj;
|
JSObject *pobj;
|
||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &pobj, &prop))
|
if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &pobj, &prop))
|
||||||
|
@ -1773,7 +1828,7 @@ js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsval roots[] = { JSVAL_VOID, JSVAL_VOID };
|
jsval roots[] = { JSVAL_VOID, JSVAL_VOID, JSVAL_VOID };
|
||||||
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
|
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
|
||||||
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
||||||
if (obj->isNative()) {
|
if (obj->isNative()) {
|
||||||
|
@ -1788,41 +1843,16 @@ js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||||
} else {
|
} else {
|
||||||
pobj->dropProperty(cx, prop);
|
pobj->dropProperty(cx, prop);
|
||||||
|
|
||||||
if (!obj->getProperty(cx, id, &roots[0]))
|
if (!obj->getProperty(cx, id, &roots[2]))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return js_NewPropertyDescriptorObject(cx, id,
|
||||||
/* We have our own property, so start creating the descriptor. */
|
attrs,
|
||||||
JSObject *desc = NewObject(cx, &js_ObjectClass, NULL, NULL);
|
roots[0], /* getter */
|
||||||
if (!desc)
|
roots[1], /* setter */
|
||||||
return false;
|
roots[2], /* value */
|
||||||
*vp = OBJECT_TO_JSVAL(desc); /* Root and return. */
|
vp);
|
||||||
|
|
||||||
const JSAtomState &atomState = cx->runtime->atomState;
|
|
||||||
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
|
||||||
if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.getAtom), roots[0],
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) ||
|
|
||||||
!desc->defineProperty(cx, ATOM_TO_JSID(atomState.setAtom), roots[1],
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.valueAtom), roots[0],
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) ||
|
|
||||||
!desc->defineProperty(cx, ATOM_TO_JSID(atomState.writableAtom),
|
|
||||||
BOOLEAN_TO_JSVAL((attrs & JSPROP_READONLY) == 0),
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc->defineProperty(cx, ATOM_TO_JSID(atomState.enumerableAtom),
|
|
||||||
BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0),
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) &&
|
|
||||||
desc->defineProperty(cx, ATOM_TO_JSID(atomState.configurableAtom),
|
|
||||||
BOOLEAN_TO_JSVAL((attrs & JSPROP_PERMANENT) == 0),
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
|
@ -1849,6 +1879,7 @@ obj_keys(JSContext *cx, uintN argc, jsval *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *obj = JSVAL_TO_OBJECT(v);
|
JSObject *obj = JSVAL_TO_OBJECT(v);
|
||||||
|
|
||||||
AutoIdArray ida(cx, JS_Enumerate(cx, obj));
|
AutoIdArray ida(cx, JS_Enumerate(cx, obj));
|
||||||
if (!ida)
|
if (!ida)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -1902,7 +1933,8 @@ HasProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp, JSBool* answerp)
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyDescriptor::PropertyDescriptor()
|
PropertyDescriptor::PropertyDescriptor()
|
||||||
: id(INT_JSVAL_TO_JSID(JSVAL_ZERO)),
|
: pd(JSVAL_VOID),
|
||||||
|
id(INT_JSVAL_TO_JSID(JSVAL_ZERO)),
|
||||||
value(JSVAL_VOID),
|
value(JSVAL_VOID),
|
||||||
get(JSVAL_VOID),
|
get(JSVAL_VOID),
|
||||||
set(JSVAL_VOID),
|
set(JSVAL_VOID),
|
||||||
|
@ -1928,6 +1960,9 @@ PropertyDescriptor::initialize(JSContext* cx, jsid id, jsval v)
|
||||||
}
|
}
|
||||||
JSObject* desc = JSVAL_TO_OBJECT(v);
|
JSObject* desc = JSVAL_TO_OBJECT(v);
|
||||||
|
|
||||||
|
/* Make a copy of the descriptor. We might need it later. */
|
||||||
|
pd = v;
|
||||||
|
|
||||||
/* Start with the proper defaults. */
|
/* Start with the proper defaults. */
|
||||||
attrs = JSPROP_PERMANENT | JSPROP_READONLY;
|
attrs = JSPROP_PERMANENT | JSPROP_READONLY;
|
||||||
|
|
||||||
|
@ -2375,8 +2410,11 @@ DefineProperty(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc, boo
|
||||||
if (obj->isArray())
|
if (obj->isArray())
|
||||||
return DefinePropertyOnArray(cx, obj, desc, throwError, rval);
|
return DefinePropertyOnArray(cx, obj, desc, throwError, rval);
|
||||||
|
|
||||||
if (obj->map->ops->lookupProperty != js_LookupProperty)
|
if (obj->map->ops->lookupProperty != js_LookupProperty) {
|
||||||
|
if (obj->isProxy())
|
||||||
|
return JSProxy::defineProperty(cx, obj, desc.id, desc.pd);
|
||||||
return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
|
return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
|
||||||
|
}
|
||||||
|
|
||||||
return DefinePropertyOnObject(cx, obj, desc, throwError, rval);
|
return DefinePropertyOnObject(cx, obj, desc, throwError, rval);
|
||||||
}
|
}
|
||||||
|
@ -2422,6 +2460,41 @@ obj_defineProperty(JSContext* cx, uintN argc, jsval* vp)
|
||||||
return js_DefineOwnProperty(cx, obj, nameidr.id(), descval, &junk);
|
return js_DefineOwnProperty(cx, obj, nameidr.id(), descval, &junk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
DefineProperties(JSContext *cx, JSObject *obj, JSObject *props)
|
||||||
|
{
|
||||||
|
AutoIdArray ida(cx, JS_Enumerate(cx, props));
|
||||||
|
if (!ida)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AutoDescriptorArray descs(cx);
|
||||||
|
size_t len = ida.length();
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
jsid id = ida[i];
|
||||||
|
PropertyDescriptor* desc = descs.append();
|
||||||
|
AutoValueRooter tvr(cx);
|
||||||
|
if (!desc ||
|
||||||
|
!JS_GetPropertyById(cx, props, id, tvr.addr()) ||
|
||||||
|
!desc->initialize(cx, id, tvr.value())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dummy;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
if (!DefineProperty(cx, obj, descs[i], true, &dummy))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern JSBool
|
||||||
|
js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props)
|
||||||
|
{
|
||||||
|
return DefineProperties(cx, newborn, props);
|
||||||
|
}
|
||||||
|
|
||||||
/* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
|
/* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
|
||||||
static JSBool
|
static JSBool
|
||||||
obj_defineProperties(JSContext* cx, uintN argc, jsval* vp)
|
obj_defineProperties(JSContext* cx, uintN argc, jsval* vp)
|
||||||
|
@ -2430,43 +2503,23 @@ obj_defineProperties(JSContext* cx, uintN argc, jsval* vp)
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||||
"Object.defineProperties", "0", "s");
|
"Object.defineProperties", "0", "s");
|
||||||
return JS_FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*vp = vp[2];
|
*vp = vp[2];
|
||||||
if (JSVAL_IS_PRIMITIVE(vp[2])) {
|
if (JSVAL_IS_PRIMITIVE(vp[2])) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
|
||||||
return JS_FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* props = js_ValueToNonNullObject(cx, vp[3]);
|
JSObject* props = js_ValueToNonNullObject(cx, vp[3]);
|
||||||
if (!props)
|
if (!props)
|
||||||
return JS_FALSE;
|
return false;
|
||||||
vp[3] = OBJECT_TO_JSVAL(props);
|
vp[3] = OBJECT_TO_JSVAL(props);
|
||||||
|
|
||||||
AutoIdArray ida(cx, JS_Enumerate(cx, props));
|
|
||||||
if (!ida)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
AutoDescriptorArray descs(cx);
|
|
||||||
size_t len = ida.length();
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
jsid id = ida[i];
|
|
||||||
PropertyDescriptor* desc = descs.append();
|
|
||||||
if (!desc || !JS_GetPropertyById(cx, props, id, &vp[1]) ||
|
|
||||||
!desc->initialize(cx, id, vp[1])) {
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject *obj = JSVAL_TO_OBJECT(*vp);
|
JSObject *obj = JSVAL_TO_OBJECT(*vp);
|
||||||
bool dummy;
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
if (!DefineProperty(cx, obj, descs[i], true, &dummy))
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return JS_TRUE;
|
return DefineProperties(cx, obj, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ES5 15.2.3.5: Object.create(O [, Properties]) */
|
/* ES5 15.2.3.5: Object.create(O [, Properties]) */
|
||||||
|
@ -3127,6 +3180,32 @@ js_DefineBlockVariable(JSContext *cx, JSObject *obj, jsid id, intN index)
|
||||||
JSScopeProperty::HAS_SHORTID, index, NULL);
|
JSScopeProperty::HAS_SHORTID, index, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use this method with extreme caution. It trades the guts of two objects and updates
|
||||||
|
* scope ownership. This operation is not thread-safe, just as fast array to slow array
|
||||||
|
* transitions are inherently not thread-safe. Don't perform a swap operation on objects
|
||||||
|
* shared across threads or, or bad things will happen. You have been warned.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
JSObject::swap(JSObject *other)
|
||||||
|
{
|
||||||
|
/* For both objects determine whether they own their respective scopes. */
|
||||||
|
bool thisOwns = this->isNative() && scope()->object == this;
|
||||||
|
bool otherOwns = other->isNative() && other->scope()->object == other;
|
||||||
|
|
||||||
|
/* Trade the guts of the objects. */
|
||||||
|
JSObject tmp;
|
||||||
|
memcpy(&tmp, this, sizeof(JSObject));
|
||||||
|
memcpy(this, other, sizeof(JSObject));
|
||||||
|
memcpy(other, &tmp, sizeof(JSObject));
|
||||||
|
|
||||||
|
/* Fixup scope ownerships. */
|
||||||
|
if (otherOwns)
|
||||||
|
scope()->object = this;
|
||||||
|
if (thisOwns)
|
||||||
|
other->scope()->object = other;
|
||||||
|
}
|
||||||
|
|
||||||
#if JS_HAS_XDR
|
#if JS_HAS_XDR
|
||||||
|
|
||||||
#define NO_PARENT_INDEX ((uint32)-1)
|
#define NO_PARENT_INDEX ((uint32)-1)
|
||||||
|
@ -6166,15 +6245,6 @@ JSObject::getGlobal()
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
JSObject::isCallable()
|
|
||||||
{
|
|
||||||
if (isNative())
|
|
||||||
return isFunction() || getClass()->call;
|
|
||||||
|
|
||||||
return !!map->ops->call;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_ReportGetterOnlyAssignment(JSContext *cx)
|
js_ReportGetterOnlyAssignment(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,10 +62,9 @@ namespace js { class AutoDescriptorArray; }
|
||||||
struct PropertyDescriptor {
|
struct PropertyDescriptor {
|
||||||
friend class js::AutoDescriptorArray;
|
friend class js::AutoDescriptorArray;
|
||||||
|
|
||||||
private:
|
|
||||||
PropertyDescriptor();
|
PropertyDescriptor();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* 8.10.5 ToPropertyDescriptor(Obj) */
|
/* 8.10.5 ToPropertyDescriptor(Obj) */
|
||||||
bool initialize(JSContext* cx, jsid id, jsval v);
|
bool initialize(JSContext* cx, jsid id, jsval v);
|
||||||
|
|
||||||
|
@ -120,6 +119,7 @@ struct PropertyDescriptor {
|
||||||
static void traceDescriptorArray(JSTracer* trc, JSObject* obj);
|
static void traceDescriptorArray(JSTracer* trc, JSObject* obj);
|
||||||
static void finalizeDescriptorArray(JSContext* cx, JSObject* obj);
|
static void finalizeDescriptorArray(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
jsval pd;
|
||||||
jsid id;
|
jsid id;
|
||||||
jsval value, get, set;
|
jsval value, get, set;
|
||||||
|
|
||||||
|
@ -578,11 +578,19 @@ struct JSObject {
|
||||||
inline jsval getQNameLocalName() const;
|
inline jsval getQNameLocalName() const;
|
||||||
inline void setQNameLocalName(jsval decl);
|
inline void setQNameLocalName(jsval decl);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Proxy-specific getters and setters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline jsval getProxyHandler() const;
|
||||||
|
inline jsval getProxyPrivate() const;
|
||||||
|
inline void setProxyPrivate(jsval priv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Back to generic stuff.
|
* Back to generic stuff.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool isCallable();
|
inline bool isCallable();
|
||||||
|
|
||||||
/* The map field is not initialized here and should be set separately. */
|
/* The map field is not initialized here and should be set separately. */
|
||||||
void init(JSClass *clasp, JSObject *proto, JSObject *parent,
|
void init(JSClass *clasp, JSObject *proto, JSObject *parent,
|
||||||
|
@ -678,6 +686,8 @@ struct JSObject {
|
||||||
map->ops->dropProperty(cx, this, prop);
|
map->ops->dropProperty(cx, this, prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void swap(JSObject *obj);
|
||||||
|
|
||||||
inline bool isArguments() const;
|
inline bool isArguments() const;
|
||||||
inline bool isArray() const;
|
inline bool isArray() const;
|
||||||
inline bool isDenseArray() const;
|
inline bool isDenseArray() const;
|
||||||
|
@ -693,6 +703,10 @@ struct JSObject {
|
||||||
inline bool isNamespace() const;
|
inline bool isNamespace() const;
|
||||||
inline bool isQName() const;
|
inline bool isQName() const;
|
||||||
|
|
||||||
|
inline bool isProxy() const;
|
||||||
|
inline bool isObjectProxy() const;
|
||||||
|
inline bool isFunctionProxy() const;
|
||||||
|
|
||||||
inline bool unbrand(JSContext *cx);
|
inline bool unbrand(JSContext *cx);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -867,6 +881,9 @@ extern JSBool
|
||||||
js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id,
|
js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id,
|
||||||
JSObject **objp, JSProperty **propp);
|
JSObject **objp, JSProperty **propp);
|
||||||
|
|
||||||
|
extern JSBool
|
||||||
|
js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, jsval getter, jsval setter, jsval value, jsval *vp);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
||||||
|
|
||||||
|
@ -919,6 +936,9 @@ extern JSObject*
|
||||||
js_NewObjectWithClassProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
js_NewObjectWithClassProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||||
jsval privateSlotValue);
|
jsval privateSlotValue);
|
||||||
|
|
||||||
|
extern JSBool
|
||||||
|
js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fast access to immutable standard objects (constructors and prototypes).
|
* Fast access to immutable standard objects (constructors and prototypes).
|
||||||
*/
|
*/
|
||||||
|
@ -1281,11 +1301,6 @@ extern const char *
|
||||||
js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
||||||
JSPrincipals *principals, uintN *linenop);
|
JSPrincipals *principals, uintN *linenop);
|
||||||
|
|
||||||
static inline bool
|
|
||||||
js_IsCallable(jsval v) {
|
|
||||||
return !JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isCallable();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_ReportGetterOnlyAssignment(JSContext *cx);
|
js_ReportGetterOnlyAssignment(JSContext *cx);
|
||||||
|
|
||||||
|
|
|
@ -500,6 +500,21 @@ JSObject::unbrand(JSContext *cx)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
JSObject::isCallable()
|
||||||
|
{
|
||||||
|
if (isNative())
|
||||||
|
return isFunction() || getClass()->call;
|
||||||
|
|
||||||
|
return !!map->ops->call;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
js_IsCallable(jsval v)
|
||||||
|
{
|
||||||
|
return !JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isCallable();
|
||||||
|
}
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
typedef Vector<PropertyDescriptor, 1> PropertyDescriptorArray;
|
typedef Vector<PropertyDescriptor, 1> PropertyDescriptorArray;
|
||||||
|
@ -528,6 +543,19 @@ class AutoDescriptorArray : private AutoGCRooter
|
||||||
PropertyDescriptorArray descriptors;
|
PropertyDescriptorArray descriptors;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AutoDescriptor : private AutoGCRooter, public JSPropertyDescriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AutoDescriptor(JSContext *cx) : AutoGCRooter(cx, DESCRIPTOR) {
|
||||||
|
obj = NULL;
|
||||||
|
attrs = 0;
|
||||||
|
getter = setter = (JSPropertyOp) NULL;
|
||||||
|
value = JSVAL_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||||
|
};
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
InitScopeForObject(JSContext* cx, JSObject* obj, JSClass *clasp, JSObject* proto, JSObjectOps* ops)
|
InitScopeForObject(JSContext* cx, JSObject* obj, JSClass *clasp, JSObject* proto, JSObjectOps* ops)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "jspropertytree.h"
|
#include "jspropertytree.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
|
|
||||||
|
#include "jsnum.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,232 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim: set ts=4 sw=4 et tw=99:
|
||||||
|
*
|
||||||
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||||
|
* May 28, 2008.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Foundation
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Andreas Gal <gal@mozilla.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#ifndef jsproxy_h___
|
||||||
|
#define jsproxy_h___
|
||||||
|
|
||||||
|
#include "jsapi.h"
|
||||||
|
#include "jsobj.h"
|
||||||
|
|
||||||
|
/* Base class for all C++ proxy handlers. */
|
||||||
|
class JSProxyHandler {
|
||||||
|
public:
|
||||||
|
virtual ~JSProxyHandler();
|
||||||
|
|
||||||
|
/* ES5 Harmony fundamental proxy traps. */
|
||||||
|
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) = 0;
|
||||||
|
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) = 0;
|
||||||
|
virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) = 0;
|
||||||
|
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap) = 0;
|
||||||
|
virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) = 0;
|
||||||
|
virtual bool enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap) = 0;
|
||||||
|
virtual bool fix(JSContext *cx, JSObject *proxy, jsval *vp) = 0;
|
||||||
|
|
||||||
|
/* ES5 Harmony derived proxy traps. */
|
||||||
|
virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||||
|
virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||||
|
virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||||
|
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||||
|
virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap);
|
||||||
|
|
||||||
|
/* Spidermonkey extensions. */
|
||||||
|
virtual void finalize(JSContext *cx, JSObject *proxy);
|
||||||
|
virtual void *family() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* No-op wrapper handler base class. */
|
||||||
|
class JSNoopProxyHandler {
|
||||||
|
JSObject *mWrappedObject;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
JS_FRIEND_API(JSNoopProxyHandler(JSObject *));
|
||||||
|
|
||||||
|
public:
|
||||||
|
JS_FRIEND_API(virtual ~JSNoopProxyHandler());
|
||||||
|
|
||||||
|
/* ES5 Harmony fundamental proxy traps. */
|
||||||
|
virtual JS_FRIEND_API(bool) getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc);
|
||||||
|
virtual JS_FRIEND_API(bool) getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc);
|
||||||
|
virtual JS_FRIEND_API(bool) defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc);
|
||||||
|
virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap);
|
||||||
|
virtual JS_FRIEND_API(bool) delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||||
|
virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap);
|
||||||
|
virtual JS_FRIEND_API(bool) fix(JSContext *cx, JSObject *proxy, jsval *vp);
|
||||||
|
|
||||||
|
/* ES5 Harmony derived proxy traps. */
|
||||||
|
virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||||
|
virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||||
|
virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||||
|
virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||||
|
virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap);
|
||||||
|
|
||||||
|
/* Spidermonkey extensions. */
|
||||||
|
virtual JS_FRIEND_API(void) finalize(JSContext *cx, JSObject *proxy);
|
||||||
|
virtual JS_FRIEND_API(void) *family();
|
||||||
|
|
||||||
|
static JSNoopProxyHandler singleton;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static JSObject *wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, JSString *className);
|
||||||
|
|
||||||
|
inline JSObject *wrappedObject(JSObject *proxy) {
|
||||||
|
return mWrappedObject ? mWrappedObject : JSVAL_TO_OBJECT(proxy->getProxyPrivate());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Dispatch point for handlers that executes the appropriate C++ or scripted traps. */
|
||||||
|
class JSProxy {
|
||||||
|
public:
|
||||||
|
/* ES5 Harmony fundamental proxy traps. */
|
||||||
|
static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc);
|
||||||
|
static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp);
|
||||||
|
static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc);
|
||||||
|
static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp);
|
||||||
|
static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc);
|
||||||
|
static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, jsval v);
|
||||||
|
static bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap);
|
||||||
|
static bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||||
|
static bool enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap);
|
||||||
|
static bool fix(JSContext *cx, JSObject *proxy, jsval *vp);
|
||||||
|
|
||||||
|
/* ES5 Harmony derived proxy traps. */
|
||||||
|
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, jsval *vp);
|
||||||
|
static bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||||
|
static bool enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Shared between object and function proxies. */
|
||||||
|
const uint32 JSSLOT_PROXY_HANDLER = JSSLOT_PRIVATE + 0;
|
||||||
|
/* Object proxies only. */
|
||||||
|
const uint32 JSSLOT_PROXY_CLASS = JSSLOT_PRIVATE + 1;
|
||||||
|
const uint32 JSSLOT_PROXY_PRIVATE = JSSLOT_PRIVATE + 2;
|
||||||
|
/* Function proxies only. */
|
||||||
|
const uint32 JSSLOT_PROXY_CALL = JSSLOT_PRIVATE + 1;
|
||||||
|
const uint32 JSSLOT_PROXY_CONSTRUCT = JSSLOT_PRIVATE + 2;
|
||||||
|
|
||||||
|
extern JS_FRIEND_API(JSClass) js_ObjectProxyClass;
|
||||||
|
extern JS_FRIEND_API(JSClass) js_FunctionProxyClass;
|
||||||
|
extern JSClass js_CallableObjectClass;
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
JSObject::isObjectProxy() const
|
||||||
|
{
|
||||||
|
return getClass() == &js_ObjectProxyClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
JSObject::isFunctionProxy() const
|
||||||
|
{
|
||||||
|
return getClass() == &js_FunctionProxyClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
JSObject::isProxy() const
|
||||||
|
{
|
||||||
|
return isObjectProxy() || isFunctionProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline jsval
|
||||||
|
JSObject::getProxyHandler() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(isProxy());
|
||||||
|
jsval handler = fslots[JSSLOT_PROXY_HANDLER];
|
||||||
|
JS_ASSERT(JSVAL_IS_OBJECT(handler) || JSVAL_IS_INT(handler));
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline jsval
|
||||||
|
JSObject::getProxyPrivate() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(isObjectProxy());
|
||||||
|
return fslots[JSSLOT_PROXY_PRIVATE];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSObject::setProxyPrivate(jsval priv)
|
||||||
|
{
|
||||||
|
JS_ASSERT(isObjectProxy());
|
||||||
|
fslots[JSSLOT_PROXY_PRIVATE] = priv;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSObject *)
|
||||||
|
JS_NewObjectProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSString *className);
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSObject *)
|
||||||
|
JS_NewFunctionProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSObject *call, JSObject *construct);
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSBool)
|
||||||
|
JS_GetProxyObjectClass(JSContext *cx, JSObject *proxy, const char **namep);
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSBool)
|
||||||
|
JS_FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp);
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JSBool)
|
||||||
|
JS_Becomes(JSContext *cx, JSObject *obj, JSObject *obj2);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
JSObject *
|
||||||
|
JSNoopProxyHandler::wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, JSString *className)
|
||||||
|
{
|
||||||
|
if (obj->isCallable()) {
|
||||||
|
JSNoopProxyHandler *handler = new T(obj);
|
||||||
|
if (!handler)
|
||||||
|
return NULL;
|
||||||
|
JSObject *wrapper = JS_NewFunctionProxy(cx, PRIVATE_TO_JSVAL(handler), proto, parent, obj, NULL);
|
||||||
|
if (!wrapper)
|
||||||
|
delete handler;
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
JSObject *wrapper = JS_NewObjectProxy(cx, PRIVATE_TO_JSVAL(&T::singleton), proto, parent, className);
|
||||||
|
if (wrapper)
|
||||||
|
wrapper->setProxyPrivate(OBJECT_TO_JSVAL(obj));
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_BEGIN_EXTERN_C
|
||||||
|
|
||||||
|
extern JS_FRIEND_API(JSObject *)
|
||||||
|
js_InitProxyClass(JSContext *cx, JSObject *obj);
|
||||||
|
|
||||||
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
|
#endif
|
|
@ -675,13 +675,7 @@ struct JSScopeProperty {
|
||||||
};
|
};
|
||||||
|
|
||||||
JSScopeProperty(jsid id, JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
|
JSScopeProperty(jsid id, JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
|
||||||
uintN attrs, uintN flags, intN shortid)
|
uintN attrs, uintN flags, intN shortid);
|
||||||
: id(id), rawGetter(getter), rawSetter(setter), slot(slot), attrs(uint8(attrs)),
|
|
||||||
flags(uint8(flags)), shortid(int16(shortid))
|
|
||||||
{
|
|
||||||
JS_ASSERT_IF(getter && (attrs & JSPROP_GETTER), getterObj->isCallable());
|
|
||||||
JS_ASSERT_IF(setter && (attrs & JSPROP_SETTER), setterObj->isCallable());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool marked() const { return (flags & MARK) != 0; }
|
bool marked() const { return (flags & MARK) != 0; }
|
||||||
void mark() { flags |= MARK; }
|
void mark() { flags |= MARK; }
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
|
|
||||||
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
inline JSEmptyScope *
|
inline JSEmptyScope *
|
||||||
JSScope::createEmptyScope(JSContext *cx, JSClass *clasp)
|
JSScope::createEmptyScope(JSContext *cx, JSClass *clasp)
|
||||||
{
|
{
|
||||||
|
@ -209,6 +211,16 @@ JSScope::trace(JSTracer *trc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
JSScopeProperty::JSScopeProperty(jsid id, JSPropertyOp getter, JSPropertyOp setter,
|
||||||
|
uint32 slot, uintN attrs, uintN flags, intN shortid)
|
||||||
|
: id(id), rawGetter(getter), rawSetter(setter), slot(slot), attrs(uint8(attrs)),
|
||||||
|
flags(uint8(flags)), shortid(int16(shortid))
|
||||||
|
{
|
||||||
|
JS_ASSERT_IF(getter && (attrs & JSPROP_GETTER), getterObj->isCallable());
|
||||||
|
JS_ASSERT_IF(setter && (attrs & JSPROP_SETTER), setterObj->isCallable());
|
||||||
|
}
|
||||||
|
|
||||||
inline JSDHashNumber
|
inline JSDHashNumber
|
||||||
JSScopeProperty::hash() const
|
JSScopeProperty::hash() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include "jsxdrapi.h"
|
#include "jsxdrapi.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "jsobjinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
|
|
@ -54,6 +54,8 @@
|
||||||
#include "jsstr.h"
|
#include "jsstr.h"
|
||||||
#include "jsxdrapi.h"
|
#include "jsxdrapi.h"
|
||||||
|
|
||||||
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define DBG(x) x
|
#define DBG(x) x
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "jsarena.h"
|
#include "jsarena.h"
|
||||||
#include "jsutil.h"
|
#include "jsutil.h"
|
||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
|
#include "jsproxy.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jsarray.h"
|
#include "jsarray.h"
|
||||||
#include "jsatom.h"
|
#include "jsatom.h"
|
||||||
|
@ -86,6 +87,8 @@
|
||||||
|
|
||||||
#include "jsworkers.h"
|
#include "jsworkers.h"
|
||||||
|
|
||||||
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
#ifdef XP_UNIX
|
#ifdef XP_UNIX
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -3858,6 +3861,23 @@ Snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSBool
|
||||||
|
Wrap(JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
jsval v = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
|
||||||
|
if (JSVAL_IS_PRIMITIVE(v)) {
|
||||||
|
JS_SET_RVAL(cx, vp, v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject *wrapped = JSNoopProxyHandler::wrap<JSNoopProxyHandler>(cx, JSVAL_TO_OBJECT(v), NULL, NULL, NULL);
|
||||||
|
if (!wrapped)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(wrapped));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* We use a mix of JS_FS and JS_FN to test both kinds of natives. */
|
/* We use a mix of JS_FS and JS_FN to test both kinds of natives. */
|
||||||
static JSFunctionSpec shell_functions[] = {
|
static JSFunctionSpec shell_functions[] = {
|
||||||
JS_FS("version", Version, 0,0,0),
|
JS_FS("version", Version, 0,0,0),
|
||||||
|
@ -3942,6 +3962,7 @@ static JSFunctionSpec shell_functions[] = {
|
||||||
JS_FN("timeout", Timeout, 1,0),
|
JS_FN("timeout", Timeout, 1,0),
|
||||||
JS_FN("elapsed", Elapsed, 0,0),
|
JS_FN("elapsed", Elapsed, 0,0),
|
||||||
JS_FN("parent", Parent, 1,0),
|
JS_FN("parent", Parent, 1,0),
|
||||||
|
JS_FN("wrap", Wrap, 1,0),
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4051,6 +4072,7 @@ static const char *const shell_help_messages[] = {
|
||||||
" A negative value (default) means that the execution time is unlimited.",
|
" A negative value (default) means that the execution time is unlimited.",
|
||||||
"elapsed() Execution time elapsed for the current context.",
|
"elapsed() Execution time elapsed for the current context.",
|
||||||
"parent(obj) Returns the parent of obj.\n",
|
"parent(obj) Returns the parent of obj.\n",
|
||||||
|
"wrap(obj) Wrap an object into a noop wrapper.\n"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Help messages must match shell functions. */
|
/* Help messages must match shell functions. */
|
||||||
|
|
|
@ -14,3 +14,4 @@ include js1_7/jstests.list
|
||||||
include js1_8/jstests.list
|
include js1_8/jstests.list
|
||||||
include js1_8_1/jstests.list
|
include js1_8_1/jstests.list
|
||||||
include js1_8_5/jstests.list
|
include js1_8_5/jstests.list
|
||||||
|
include proxies/jstests.list
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
url-prefix ../../jsreftest.html?test=proxies/
|
||||||
|
script scripted.js
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/
|
||||||
|
* Contributor: Andreas Gal
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Test object proxies. */
|
||||||
|
|
||||||
|
function noopHandlerMaker(obj) {
|
||||||
|
return {
|
||||||
|
getOwnPropertyDescriptor: function(name) {
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(obj);
|
||||||
|
// a trapping proxy's properties must always be configurable
|
||||||
|
desc.configurable = true;
|
||||||
|
return desc;
|
||||||
|
},
|
||||||
|
getPropertyDescriptor: function(name) {
|
||||||
|
var desc = Object.getPropertyDescriptor(obj); // assumed
|
||||||
|
// a trapping proxy's properties must always be configurable
|
||||||
|
desc.configurable = true;
|
||||||
|
return desc;
|
||||||
|
},
|
||||||
|
getOwnPropertyNames: function() {
|
||||||
|
return Object.getOwnPropertyNames(obj);
|
||||||
|
},
|
||||||
|
defineProperty: function(name, desc) {
|
||||||
|
return Object.defineProperty(obj, name, desc);
|
||||||
|
},
|
||||||
|
delete: function(name) { return delete obj[name]; },
|
||||||
|
fix: function() {
|
||||||
|
// As long as obj is not frozen, the proxy won't allow itself to be fixed
|
||||||
|
// if (!Object.isFrozen(obj)) [not implemented in SpiderMonkey]
|
||||||
|
// return undefined;
|
||||||
|
// return Object.getOwnProperties(obj); // assumed [not implemented in SpiderMonkey]
|
||||||
|
var props = {};
|
||||||
|
for (x in obj)
|
||||||
|
props[x] = Object.getOwnPropertyDescriptor(obj, x);
|
||||||
|
return props;
|
||||||
|
},
|
||||||
|
has: function(name) { return name in obj; },
|
||||||
|
hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
|
||||||
|
get: function(receiver, name) { return obj[name]; },
|
||||||
|
set: function(receiver, name, val) { obj[name] = val; return true; }, // bad behavior when set fails in non-strict mode
|
||||||
|
enumerate: function() {
|
||||||
|
var result = [];
|
||||||
|
for (name in obj) { result.push(name); };
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
enumerateOwn: function() { return Object.keys(obj); }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function testNoopHandler(obj, proxy) {
|
||||||
|
/* Check that both objects see the same properties. */
|
||||||
|
for (x in obj)
|
||||||
|
assertEq(obj[x], proxy[x]);
|
||||||
|
for (x in proxy)
|
||||||
|
assertEq(obj[x], proxy[x]);
|
||||||
|
/* Check that the iteration order is the same. */
|
||||||
|
var a = [], b = [];
|
||||||
|
for (x in obj)
|
||||||
|
a.push(x);
|
||||||
|
for (x in proxy)
|
||||||
|
b.push(x);
|
||||||
|
assertEq(uneval(a), uneval(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testObj(obj) {
|
||||||
|
var proxy = Proxy.create(noopHandlerMaker(obj));
|
||||||
|
testNoopHandler(obj, proxy);
|
||||||
|
assertEq(typeof proxy, "object");
|
||||||
|
if ("isTrapping" in Proxy) {
|
||||||
|
assertEq(Proxy.isTrapping(proxy), true);
|
||||||
|
assertEq(Proxy.fix(proxy), true);
|
||||||
|
assertEq(Proxy.isTrapping(proxy), false);
|
||||||
|
assertEq(typeof proxy, "object");
|
||||||
|
testNoopHandler(obj, proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testObj({ foo: 1, bar: 2 });
|
||||||
|
testObj({ 1: 2, 3: 4 });
|
||||||
|
testObj([ 1, 2, 3 ]);
|
||||||
|
testObj(new Date());
|
||||||
|
testObj(new Array());
|
||||||
|
testObj(new RegExp());
|
||||||
|
testObj(Date);
|
||||||
|
testObj(Array);
|
||||||
|
testObj(RegExp);
|
||||||
|
|
||||||
|
reportCompare(0, 0, "Proxies: Object proxies.");
|
||||||
|
|
||||||
|
/* Test function proxies. */
|
||||||
|
|
||||||
|
var proxy = Proxy.createFunction({
|
||||||
|
get: function(obj,name) { return Function.prototype[name]; },
|
||||||
|
fix: function() {
|
||||||
|
return ({});
|
||||||
|
}
|
||||||
|
}, function() { return "call"; });
|
||||||
|
|
||||||
|
assertEq(proxy(), "call");
|
||||||
|
assertEq(typeof proxy, "function");
|
||||||
|
if ("isTrapping" in Proxy) {
|
||||||
|
assertEq(Proxy.isTrapping(proxy), true);
|
||||||
|
assertEq(Proxy.fix(proxy), true);
|
||||||
|
assertEq(Proxy.isTrapping(proxy), false);
|
||||||
|
assertEq(typeof proxy, "function");
|
||||||
|
assertEq(proxy(), "call");
|
||||||
|
}
|
||||||
|
|
||||||
|
reportCompare(0, 0, "Proxies: Function proxies.");
|
||||||
|
|
||||||
|
/* Test function proxies as constructors. */
|
||||||
|
|
||||||
|
var proxy = Proxy.createFunction({
|
||||||
|
get: function(obj, name) { return Function.prototype[name]; },
|
||||||
|
fix: function() { return ({}); }
|
||||||
|
},
|
||||||
|
function() { var x = {}; x.origin = "call"; return x; },
|
||||||
|
function() { var x = {}; x.origin = "new"; return x; })
|
||||||
|
|
||||||
|
assertEq(proxy().origin, "call");
|
||||||
|
assertEq((new proxy()).origin, "new");
|
||||||
|
if ("fix" in Proxy) {
|
||||||
|
assertEq(Proxy.fix(proxy), true);
|
||||||
|
assertEq(proxy().origin, "call");
|
||||||
|
assertEq((new proxy()).origin, "new");
|
||||||
|
}
|
||||||
|
|
||||||
|
reportCompare(0, 0, "Proxies: Function proxies as constructor.");
|
||||||
|
|
||||||
|
/* Test fallback on call if no construct trap was given. */
|
||||||
|
|
||||||
|
var proxy = Proxy.createFunction({
|
||||||
|
get: function(obj, name) { return Function.prototype[name]; },
|
||||||
|
fix: function() { return ({}); }
|
||||||
|
},
|
||||||
|
function() { this.origin = "new"; return "new-ret"; });
|
||||||
|
|
||||||
|
assertEq((new proxy()).origin, "new");
|
||||||
|
if ("fix" in Proxy) {
|
||||||
|
assertEq(Proxy.fix(proxy), true);
|
||||||
|
assertEq((new proxy()).origin, "new");
|
||||||
|
}
|
||||||
|
|
||||||
|
reportCompare(0, 0, "Proxies: No constructor trap supplied.");
|
||||||
|
|
||||||
|
/* Test invoke. */
|
||||||
|
|
||||||
|
var proxy = Proxy.create({ get: function(obj,name) { return function(a,b,c) { return name + uneval([a,b,c]); } }});
|
||||||
|
assertEq(proxy.foo(1,2,3), "foo[1, 2, 3]");
|
||||||
|
|
||||||
|
reportCompare(0, 0, "Proxies: Test invoke.");
|
Загрузка…
Ссылка в новой задаче