Backed out changeset 7b2b90efe57d -- the patch was landed against a tree with a lot of orange. This will hinder the orange resolution.
Backed out changeset 7b2b90efe57d -- the patch was landed against a tree with a lot of orange. This will hinder the orange resolution.
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2412,17 +2412,21 @@ nsScriptSecurityManager::doGetObjectPrin
do {
// Note: jsClass is set before this loop, and also at the
// *end* of this loop.
// NOTE: These class and equality hook checks better match
// what IS_WRAPPER_CLASS() does in xpconnect!
- if (jsClass->ext.equality == js::Valueify(sXPCWrappedNativeEqualityOps)) {
+ JSEqualityOp op =
+ (jsClass->flags & JSCLASS_IS_EXTENDED) ?
+ reinterpret_cast<const JSExtendedClass*>(jsClass)->equality :
+ nsnull;
+ if (op == sXPCWrappedNativeEqualityOps) {
result = sXPConnect->GetPrincipal(aObj,
#ifdef DEBUG
aAllowShortCircuit
#else
PR_TRUE
#endif
);
if (result) {
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5698,18 +5698,21 @@ CloneSimpleValues(JSContext* cx,
// Do we support FileList?
// Function objects don't get cloned.
if (JS_ObjectIsFunction(cx, obj)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
// Security wrapped objects are not allowed either.
- if (obj->getClass()->ext.wrappedObject)
+ JSClass* clasp = JS_GET_CLASS(cx, obj);
+ if ((clasp->flags & JSCLASS_IS_EXTENDED) &&
+ ((JSExtendedClass*)clasp)->wrappedObject) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+ }
// See if this JSObject is backed by some C++ object. If it is then we assume
// that it is inappropriate to clone.
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper));
if (wrapper) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -67,18 +67,16 @@
#include "nsLayoutUtils.h"
#include "nsComputedDOMStyle.h"
#if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#endif
-#include "jsobj.h"
-
static PRBool IsUniversalXPConnectCapable()
{
PRBool hasCap = PR_FALSE;
nsresult rv = nsContentUtils::GetSecurityManager()->
IsCapabilityEnabled("UniversalXPConnect", &hasCap);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
return hasCap;
}
@@ -1344,20 +1342,24 @@ nsDOMWindowUtils::GetParent()
// first argument must be an object
if(JSVAL_IS_PRIMITIVE(argv[0]))
return NS_ERROR_XPC_BAD_CONVERT_JS;
JSObject *parent = JS_GetParent(cx, JSVAL_TO_OBJECT(argv[0]));
*rval = OBJECT_TO_JSVAL(parent);
- // Outerize if necessary.
+ // Outerize if necessary. Embrace the ugliness!
if (parent) {
- if (JSObjectOp outerize = parent->getClass()->ext.outerObject)
- *rval = OBJECT_TO_JSVAL(outerize(cx, parent));
+ JSClass* clasp = JS_GET_CLASS(cx, parent);
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ JSExtendedClass* xclasp = reinterpret_cast<JSExtendedClass*>(clasp);
+ if (JSObjectOp outerize = xclasp->outerObject)
+ *rval = OBJECT_TO_JSVAL(outerize(cx, parent));
+ }
}
cc->SetReturnValueWasSet(PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetOuterWindowID(PRUint64 *aWindowID)
--- a/js/ipc/ObjectWrapperParent.cpp
+++ b/js/ipc/ObjectWrapperParent.cpp
@@ -164,42 +164,46 @@ with_error(JSContext* cx,
RType rval,
const char* error = NULL)
{
if (!JS_IsExceptionPending(cx))
JS_ReportError(cx, error ? error : "Unspecified CPOW error");
return rval;
}
-const js::Class ObjectWrapperParent::sCPOW_JSClass = {
- "CrossProcessObjectWrapper",
- JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE |
+const JSExtendedClass ObjectWrapperParent::sCPOW_JSClass = {
+ // JSClass (JSExtendedClass.base) initialization
+ { "CrossProcessObjectWrapper",
+ JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(sNumSlots),
- js::Valueify(ObjectWrapperParent::CPOW_AddProperty),
- js::Valueify(ObjectWrapperParent::CPOW_DelProperty),
- js::Valueify(ObjectWrapperParent::CPOW_GetProperty),
- js::Valueify(ObjectWrapperParent::CPOW_SetProperty),
+ ObjectWrapperParent::CPOW_AddProperty,
+ ObjectWrapperParent::CPOW_DelProperty,
+ ObjectWrapperParent::CPOW_GetProperty,
+ ObjectWrapperParent::CPOW_SetProperty,
(JSEnumerateOp) ObjectWrapperParent::CPOW_NewEnumerate,
- (JSResolveOp) ObjectWrapperParent::CPOW_NewResolve,
- js::Valueify(ObjectWrapperParent::CPOW_Convert),
+ (JSResolveOp) ObjectWrapperParent::CPOW_NewResolve,
+ ObjectWrapperParent::CPOW_Convert,
ObjectWrapperParent::CPOW_Finalize,
- nsnull, // reserved1
+ nsnull, // getObjectOps
nsnull, // checkAccess
- js::Valueify(ObjectWrapperParent::CPOW_Call),
- js::Valueify(ObjectWrapperParent::CPOW_Construct),
+ ObjectWrapperParent::CPOW_Call,
+ ObjectWrapperParent::CPOW_Construct,
nsnull, // xdrObject
- js::Valueify(ObjectWrapperParent::CPOW_HasInstance),
+ ObjectWrapperParent::CPOW_HasInstance,
nsnull, // mark
- {
- js::Valueify(ObjectWrapperParent::CPOW_Equality),
- nsnull, // outerObject
- nsnull, // innerObject
- nsnull, // iteratorObject
- nsnull, // wrappedObject
- }
+ nsnull, // reserveSlots
+ },
+
+ // JSExtendedClass initialization
+ ObjectWrapperParent::CPOW_Equality,
+ nsnull, // outerObject
+ nsnull, // innerObject
+ nsnull, // iterator
+ nsnull, // wrappedObject
+ JSCLASS_NO_RESERVED_MEMBERS
};
void
ObjectWrapperParent::ActorDestroy(ActorDestroyReason)
{
if (mObj) {
mObj->setPrivate(NULL);
mObj = NULL;
@@ -211,28 +215,28 @@ ObjectWrapperParent::Manager()
{
PContextWrapperParent* pcwp = PObjectWrapperParent::Manager();
return static_cast<ContextWrapperParent*>(pcwp);
}
JSObject*
ObjectWrapperParent::GetJSObject(JSContext* cx) const
{
- js::Class *clasp = const_cast<js::Class *>(&ObjectWrapperParent::sCPOW_JSClass);
- if (!mObj && (mObj = JS_NewObject(cx, js::Jsvalify(clasp), NULL, NULL))) {
+ JSClass* clasp = const_cast<JSClass*>(&ObjectWrapperParent::sCPOW_JSClass.base);
+ if (!mObj && (mObj = JS_NewObject(cx, clasp, NULL, NULL))) {
JS_SetPrivate(cx, mObj, (void*)this);
JS_SetReservedSlot(cx, mObj, sFlagsSlot, JSVAL_ZERO);
}
return mObj;
}
static ObjectWrapperParent*
Unwrap(JSContext* cx, JSObject* obj)
{
- while (obj->getClass() != &ObjectWrapperParent::sCPOW_JSClass)
+ while (obj->getJSClass() != &ObjectWrapperParent::sCPOW_JSClass.base)
if (!(obj = obj->getProto()))
return NULL;
ObjectWrapperParent* self =
static_cast<ObjectWrapperParent*>(JS_GetPrivate(cx, obj));
NS_ASSERTION(!self || self->GetJSObject(cx) == obj,
"Wrapper and wrapped object disagree?");
--- a/js/ipc/ObjectWrapperParent.h
+++ b/js/ipc/ObjectWrapperParent.h
@@ -38,17 +38,16 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_jsipc_ObjectWrapperParent_h__
#define mozilla_jsipc_ObjectWrapperParent_h__
#include "mozilla/jsipc/PObjectWrapperParent.h"
#include "jsapi.h"
-#include "jsvalue.h"
#include "nsAutoJSValHolder.h"
namespace mozilla {
namespace jsipc {
class ContextWrapperParent;
class OperationChecker {
@@ -71,17 +70,17 @@ public:
jsval GetJSVal(JSContext* cx) const {
return OBJECT_TO_JSVAL(GetJSObject(cx));
}
void CheckOperation(JSContext* cx,
OperationStatus* status);
- static const js::Class sCPOW_JSClass;
+ static const JSExtendedClass sCPOW_JSClass;
protected:
void ActorDestroy(ActorDestroyReason why);
ContextWrapperParent* Manager();
private:
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -37,17 +37,30 @@
/*
* JavaScript Debugging support - Value and Property support
*/
#include "jsd.h"
#include "jsapi.h"
#include "jspubtd.h"
-#include "jsprvtd.h"
+
+/*
+ * Lifted with slight modification from jsobj.h
+ */
+
+#define OBJ_TO_OUTER_OBJECT(cx, obj) \
+do { \
+ JSClass *clasp_ = JS_GetClass(cx, obj); \
+ if (clasp_->flags & JSCLASS_IS_EXTENDED) { \
+ JSExtendedClass *xclasp_ = (JSExtendedClass*) clasp_; \
+ if (xclasp_->outerObject) \
+ obj = xclasp_->outerObject(cx, obj); \
+ } \
+} while(0)
#ifdef DEBUG
void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
{
JS_ASSERT(jsdval);
JS_ASSERT(jsdval->nref > 0);
if(!JS_CLIST_IS_EMPTY(&jsdval->props))
{
@@ -296,17 +309,18 @@ jsd_DropValue(JSDContext* jsdc, JSDValue
jsval
jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
{
JSObject* obj;
JSContext* cx;
jsval val = jsdval->val;
if (!JSVAL_IS_PRIMITIVE(val)) {
cx = JSD_GetDefaultJSContext(jsdc);
- obj = js_ObjectToOuterObject(cx, JSVAL_TO_OBJECT(val));
+ obj = JSVAL_TO_OBJECT(val);
+ OBJ_TO_OUTER_OBJECT(cx, obj);
if (!obj)
{
JS_ClearPendingException(cx);
val = JSVAL_NULL;
}
else
val = OBJECT_TO_JSVAL(obj);
}
--- a/js/src/jsapi-tests/testExtendedEq.cpp
+++ b/js/src/jsapi-tests/testExtendedEq.cpp
@@ -1,56 +1,42 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*
* This tests user-specified (via JSExtendedClass) equality operations on
* trace.
*/
#include "tests.h"
-#include "jsobj.h"
static JSBool
my_Equality(JSContext *cx, JSObject *obj, const jsval *, JSBool *bp)
{
*bp = JS_TRUE;
return JS_TRUE;
}
-js::Class TestExtendedEq_JSClass = {
- "TestExtendedEq",
- 0,
- js::PropertyStub, /* addProperty */
- js::PropertyStub, /* delProperty */
- js::PropertyStub, /* getProperty */
- js::PropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- NULL, /* convert */
- NULL, /* finalize */
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- NULL, /* mark */
- {
- js::Valueify(my_Equality),
- NULL, /* outerObject */
- NULL, /* innerObject */
- NULL, /* iteratorObject */
- NULL, /* wrappedObject */
- }
+JSExtendedClass TestExtendedEq_JSClass = {
+ { "TestExtendedEq",
+ JSCLASS_IS_EXTENDED,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+ },
+ // JSExtendedClass initialization
+ my_Equality,
+ NULL, NULL, NULL, NULL, JSCLASS_NO_RESERVED_MEMBERS
};
BEGIN_TEST(testExtendedEq_bug530489)
{
JSClass *clasp = (JSClass *) &TestExtendedEq_JSClass;
+ JSObject *global = JS_GetGlobalObject(cx);
CHECK(JS_InitClass(cx, global, global, clasp, NULL, 0, NULL, NULL, NULL, NULL));
CHECK(JS_DefineObject(cx, global, "obj1", clasp, NULL, 0));
CHECK(JS_DefineObject(cx, global, "obj2", clasp, NULL, 0));
jsval v;
EVAL("(function() { var r; for (var i = 0; i < 10; ++i) r = obj1 == obj2; return r; })()", &v);
CHECK_SAME(v, JSVAL_TRUE);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1337,20 +1337,21 @@ JS_InitStandardClasses(JSContext *cx, JS
#if JS_HAS_GENERATORS
js_InitIteratorClasses(cx, obj) &&
#endif
js_InitDateClass(cx, obj) &&
js_InitProxyClass(cx, obj);
}
#define CLASP(name) (&js_##name##Class)
-#define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type])
+#define XCLASP(name) (&js_##name##Class.base)
#define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
#define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
#define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
+#define EAGER_ATOM_AND_XCLASP(name) EAGER_CLASS_ATOM(name), XCLASP(name)
#define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
typedef struct JSStdName {
JSObjectOp init;
size_t atomOffset; /* offset of atom pointer in JSAtomState */
const char *name; /* null if atom is pre-pinned, else name */
Class *clasp;
} JSStdName;
@@ -1386,18 +1387,18 @@ static JSStdName standard_class_atoms[]
{js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
{js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
{js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
{js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
{js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
{js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
#if JS_HAS_XML_SUPPORT
{js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
- {js_InitNamespaceClass, EAGER_ATOM_AND_CLASP(Namespace)},
- {js_InitQNameClass, EAGER_ATOM_AND_CLASP(QName)},
+ {js_InitNamespaceClass, EAGER_ATOM_AND_XCLASP(Namespace)},
+ {js_InitQNameClass, EAGER_ATOM_AND_XCLASP(QName)},
#endif
#if JS_HAS_GENERATORS
{js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
#endif
{js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
{NULL, 0, NULL, NULL}
};
@@ -1442,32 +1443,31 @@ static JSStdName standard_class_names[]
#if JS_HAS_XML_SUPPORT
{js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)},
{js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
{js_InitXMLClass, LAZY_ATOM(XMLList), CLASP(XML)},
{js_InitXMLClass, LAZY_ATOM(isXMLName), CLASP(XML)},
#endif
#if JS_HAS_GENERATORS
- {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
- {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
+ {js_InitIteratorClasses, EAGER_ATOM_AND_XCLASP(Iterator)},
+ {js_InitIteratorClasses, EAGER_ATOM_AND_XCLASP(Generator)},
#endif
/* Typed Arrays */
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), TYPED_ARRAY_CLASP(TYPE_UINT16)},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), TYPED_ARRAY_CLASP(TYPE_INT32)},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), TYPED_ARRAY_CLASP(TYPE_UINT32)},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
- {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
- TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), &TypedArray::fastClasses[TypedArray::TYPE_INT8]},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), &TypedArray::fastClasses[TypedArray::TYPE_UINT8]},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), &TypedArray::fastClasses[TypedArray::TYPE_INT16]},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), &TypedArray::fastClasses[TypedArray::TYPE_UINT16]},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), &TypedArray::fastClasses[TypedArray::TYPE_INT32]},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), &TypedArray::fastClasses[TypedArray::TYPE_UINT32]},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), &TypedArray::fastClasses[TypedArray::TYPE_FLOAT32]},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), &TypedArray::fastClasses[TypedArray::TYPE_FLOAT64]},
+ {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray), &TypedArray::fastClasses[TypedArray::TYPE_UINT8_CLAMPED]},
{js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
{NULL, 0, NULL, NULL}
};
static JSStdName object_prototype_names[] = {
/* Object.prototype properties (global delegates to Object.prototype). */
@@ -3702,22 +3702,18 @@ JS_DeleteProperty(JSContext *cx, JSObjec
}
JS_PUBLIC_API(void)
JS_ClearScope(JSContext *cx, JSObject *obj)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
- JSFinalizeOp clearOp = obj->getOps()->clear;
- if (clearOp)
- clearOp(cx, obj);
-
- if (obj->isNative())
- js_ClearNative(cx, obj);
+ if (obj->map->ops->clear)
+ obj->map->ops->clear(cx, obj);
/* Clear cached class objects on the global object. */
if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
int key;
for (key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
}
@@ -3780,31 +3776,20 @@ prop_iter_trace(JSTracer *trc, JSObject
MarkIdRange(trc, ida->length, ida->vector, "prop iter");
}
}
static Class prop_iter_class = {
"PropertyIterator",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
JSCLASS_MARK_IS_TRACE,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- prop_iter_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- JS_CLASS_TRACE(prop_iter_trace)
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, prop_iter_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, JS_CLASS_TRACE(prop_iter_trace), NULL
};
JS_PUBLIC_API(JSObject *)
JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
{
JSObject *iterobj;
JSScope *scope;
void *pdata;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1590,44 +1590,55 @@ JS_SetScriptStackQuota(JSContext *cx, si
#define JS_DEFAULT_SCRIPT_STACK_QUOTA ((size_t) 0x2000000)
/************************************************************************/
/*
* Classes, objects, and properties.
*/
-typedef void (*JSClassInternal)();
/* For detailed comments on the function pointer types, see jspubtd.h. */
struct JSClass {
- const char *name; \
- uint32 flags; \
- \
- /* Mandatory non-null function pointer members. */ \
- JSPropertyOp addProperty; \
- JSPropertyOp delProperty; \
- JSPropertyOp getProperty; \
- JSPropertyOp setProperty; \
- JSEnumerateOp enumerate; \
- JSResolveOp resolve; \
- JSConvertOp convert; \
- JSFinalizeOp finalize; \
- \
- /* Optionally non-null members start here. */ \
- JSClassInternal reserved0; \
- JSCheckAccessOp checkAccess; \
- JSNative call; \
- JSNative construct; \
- JSXDRObjectOp xdrObject; \
- JSHasInstanceOp hasInstance; \
+ const char *name;
+ uint32 flags;
+
+ /* Mandatory non-null function pointer members. */
+ JSPropertyOp addProperty;
+ JSPropertyOp delProperty;
+ JSPropertyOp getProperty;
+ JSPropertyOp setProperty;
+ JSEnumerateOp enumerate;
+ JSResolveOp resolve;
+ JSConvertOp convert;
+ JSFinalizeOp finalize;
+
+ /* Optionally non-null members start here. */
+ JSGetObjectOps getObjectOps;
+ JSCheckAccessOp checkAccess;
+ JSNative call;
+ JSNative construct;
+ JSXDRObjectOp xdrObject;
+ JSHasInstanceOp hasInstance;
JSMarkOp mark;
-
- JSClassInternal reserved1;
- void *reserved[19];
+ void (*reserved0)(void);
+};
+
+struct JSExtendedClass {
+ JSClass base;
+ JSEqualityOp equality;
+ JSObjectOp outerObject;
+ JSObjectOp innerObject;
+ JSIteratorOp iteratorObject;
+ JSObjectOp wrappedObject; /* NB: infallible, null
+ returns are treated as
+ the original object */
+ void (*reserved0)(void);
+ void (*reserved1)(void);
+ void (*reserved2)(void);
};
#define JSCLASS_HAS_PRIVATE (1<<0) /* objects have private slot */
#define JSCLASS_NEW_ENUMERATE (1<<1) /* has JSNewEnumerateOp hook */
#define JSCLASS_NEW_RESOLVE (1<<2) /* has JSNewResolveOp hook */
#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) /* private is (nsISupports *) */
/* (1<<4) was JSCLASS_SHARE_ALL_PROPERTIES, now obsolete. See bug 527805. */
#define JSCLASS_NEW_RESOLVE_GETS_START (1<<5) /* JSNewResolveOp gets starting
@@ -1650,23 +1661,25 @@ struct JSClass {
<< JSCLASS_RESERVED_SLOTS_SHIFT)
#define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \
>> JSCLASS_RESERVED_SLOTS_SHIFT) \
& JSCLASS_RESERVED_SLOTS_MASK)
#define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \
JSCLASS_RESERVED_SLOTS_WIDTH)
-#define JSCLASS_INTERNAL_FLAG1 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
+/* True if JSClass is really a JSExtendedClass. */
+#define JSCLASS_IS_EXTENDED (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
#define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1))
#define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2))
/* Indicates that JSClass.mark is a tracer with JSTraceOp type. */
#define JSCLASS_MARK_IS_TRACE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
-#define JSCLASS_INTERNAL_FLAG2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4))
+
+#define JSCLASS_LAST_API_FLAG_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT+3)
/*
* ECMA-262 requires that most constructors used internally create objects
* with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
* member initial value. The "original ... value" verbiage is there because
* in ECMA-262, global properties naming class objects are read/write and
* deleteable, for the most part.
*
@@ -1686,18 +1699,18 @@ struct JSClass {
#define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH)
#define JSCLASS_HAS_CACHED_PROTO(key) ((key) << JSCLASS_CACHED_PROTO_SHIFT)
#define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \
(((clasp)->flags \
>> JSCLASS_CACHED_PROTO_SHIFT) \
& JSCLASS_CACHED_PROTO_MASK))
/* Initializer for unused members of statically initialized JSClass structs. */
-#define JSCLASS_NO_INTERNAL_MEMBERS 0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
-#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
+#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0
+#define JSCLASS_NO_RESERVED_MEMBERS 0,0,0
struct JSIdArray {
jsint length;
jsid vector[1]; /* actually, length jsid words */
};
extern JS_PUBLIC_API(void)
JS_DestroyIdArray(JSContext *cx, JSIdArray *ida);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -999,63 +999,59 @@ array_trace(JSTracer *trc, JSObject *obj
}
if (IS_GC_MARKING_TRACER(trc) && holes > MIN_SPARSE_INDEX && holes > capacity / 4 * 3) {
/* This might fail, in which case we don't slowify it. */
static_cast<GCMarker *>(trc)->arraysToSlowify.append(obj);
}
}
+extern JSObjectOps js_ArrayObjectOps;
+
+static const JSObjectMap SharedArrayMap(&js_ArrayObjectOps, JSObjectMap::SHAPELESS);
+
+JSObjectOps js_ArrayObjectOps = {
+ &SharedArrayMap,
+ array_lookupProperty,
+ array_defineProperty,
+ array_getProperty,
+ array_setProperty,
+ array_getAttributes,
+ array_setAttributes,
+ array_deleteProperty,
+ js_Enumerate,
+ array_typeOf,
+ array_trace,
+ NULL, /* thisObject */
+ NULL /* clear */
+};
+
+static JSObjectOps *
+array_getObjectOps(JSContext *cx, Class *clasp)
+{
+ return &js_ArrayObjectOps;
+}
+
Class js_ArrayClass = {
"Array",
- Class::NON_NATIVE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DENSE_ARRAY_FIXED_RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- js_TryValueOf,
- array_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- NULL, /* mark */
- JS_NULL_CLASS_EXT,
- {
- array_lookupProperty,
- array_defineProperty,
- array_getProperty,
- array_setProperty,
- array_getAttributes,
- array_setAttributes,
- array_deleteProperty,
- NULL, /* enumerate */
- array_typeOf,
- array_trace,
- NULL, /* thisObject */
- NULL, /* clear */
- }
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, js_TryValueOf, array_finalize,
+ array_getObjectOps, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
};
Class js_SlowArrayClass = {
"Array",
- JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
- slowarray_addProperty,
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- js_TryValueOf
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
+ slowarray_addProperty, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, js_TryValueOf, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
/*
* Convert an array object from fast-and-dense to slow-and-flexible.
*/
JSBool
JSObject::makeDenseArraySlow(JSContext *cx)
{
@@ -1071,17 +1067,17 @@ JSObject::makeDenseArraySlow(JSContext *
if (arrayProto->getClass() == &js_ObjectClass) {
/* obj is Array.prototype. */
emptyShape = js_GenerateShape(cx, false);
} else {
/* arrayProto is Array.prototype. */
JS_ASSERT(arrayProto->getClass() == &js_SlowArrayClass);
emptyShape = arrayProto->scope()->emptyScope->shape;
}
- JSScope *scope = JSScope::create(cx, &js_SlowArrayClass, obj, emptyShape);
+ JSScope *scope = JSScope::create(cx, &js_ObjectOps, &js_SlowArrayClass, obj, emptyShape);
if (!scope)
return JS_FALSE;
uint32 capacity = obj->getDenseArrayCapacity();
/* For a brief moment the object has NULL dslots until we slowify it during construction. */
if (obj->dslots)
obj->dslots[-1].setPrivateUint32(JS_INITIAL_NSLOTS + capacity);
@@ -2990,17 +2986,17 @@ js_NewEmptyArray(JSContext* cx, JSObject
JS_ASSERT(proto->isArray());
JSObject* obj = js_NewGCObject(cx);
if (!obj)
return NULL;
/* Initialize all fields of JSObject. */
- obj->map = const_cast<JSObjectMap *>(&JSObjectMap::sharedNonNative);
+ obj->map = const_cast<JSObjectMap *>(&SharedArrayMap);
obj->init(&js_ArrayClass, proto, proto->getParent(), NullValue());
obj->setArrayLength(len);
obj->setDenseArrayCapacity(0);
return obj;
}
#ifdef JS_TRACER
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewEmptyArray, CONTEXT, OBJECT, INT32, 0,
nanojit::ACCSET_STORE_ANY)
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -51,28 +51,25 @@
#include "jslock.h"
#include "jsnum.h"
#include "jsobj.h"
#include "jsstr.h"
#include "jsvector.h"
#include "jsobjinlines.h"
+
using namespace js;
Class js_BooleanClass = {
"Boolean",
JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
#if JS_HAS_TOSOURCE
#include "jsprf.h"
static JSBool
bool_toSource(JSContext *cx, uintN argc, Value *vp)
{
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -251,17 +251,17 @@ js_AddAtomProperty(JSContext* cx, JSObje
JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddAtomProperty, CONTEXT, OBJECT, SCOPEPROP,
0, ACCSET_STORE_ANY)
static JSBool
HasProperty(JSContext* cx, JSObject* obj, jsid id)
{
// Check that we know how the lookup op will behave.
for (JSObject* pobj = obj; pobj; pobj = pobj->getProto()) {
- if (pobj->getOps()->lookupProperty)
+ if (pobj->map->ops->lookupProperty != js_LookupProperty)
return JS_NEITHER;
Class* clasp = pobj->getClass();
if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass)
return JS_NEITHER;
}
JSObject* obj2;
JSProperty* prop;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -480,23 +480,19 @@ msFromTime(jsdouble t)
/*
* Other Support routines and definitions
*/
Class js_DateClass = {
js_Date_str,
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_FIXED_RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
/* for use by date_parse */
static const char* wtb[] = {
"am", "pm",
"monday", "tuesday", "wednesday", "thursday", "friday",
"saturday", "sunday",
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -83,31 +83,20 @@ exn_enumerate(JSContext *cx, JSObject *o
static JSBool
exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSObject **objp);
Class js_ErrorClass = {
js_Error_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_MARK_IS_TRACE |
JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- exn_enumerate,
- (JSResolveOp)exn_resolve,
- ConvertStub,
- exn_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- Exception, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- JS_CLASS_TRACE(exn_trace)
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ exn_enumerate, (JSResolveOp)exn_resolve, ConvertStub, exn_finalize,
+ NULL, NULL, NULL, Exception,
+ NULL, NULL, JS_CLASS_TRACE(exn_trace), NULL
};
typedef struct JSStackTraceElem {
JSString *funName;
size_t argc;
const char *filename;
uintN ulineno;
} JSStackTraceElem;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -676,51 +676,40 @@ args_or_call_trace(JSTracer *trc, JSObje
* in a JSStackFrame with their corresponding property values in the frame's
* arguments object.
*/
Class js_ArgumentsClass = {
"Arguments",
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_FIXED_RESERVED_SLOTS) |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
- PropertyStub, /* addProperty */
- args_delProperty,
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- args_enumerate,
- (JSResolveOp) args_resolve,
- ConvertStub,
- NULL, /* finalize */
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- JS_CLASS_TRACE(args_or_call_trace)
+ PropertyStub, args_delProperty,
+ PropertyStub, PropertyStub,
+ args_enumerate, (JSResolveOp) args_resolve,
+ ConvertStub, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ JS_CLASS_TRACE(args_or_call_trace), NULL
};
const uint32 JSSLOT_CALLEE = JSSLOT_PRIVATE + 1;
const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS = 2;
/*
* A Declarative Environment object stores its active JSStackFrame pointer in
* its private slot, just as Call and Arguments objects do.
*/
Class js_DeclEnvClass = {
js_Object_str,
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
static JSBool
CheckForEscapingClosure(JSContext *cx, JSObject *obj, Value *vp)
{
JS_ASSERT(obj->getClass() == &js_CallClass ||
obj->getClass() == &js_DeclEnvClass);
@@ -1268,31 +1257,24 @@ call_resolve(JSContext *cx, JSObject *ob
return JS_TRUE;
}
JS_PUBLIC_DATA(Class) js_CallClass = {
"Call",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS) |
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- call_enumerate,
- (JSResolveOp)call_resolve,
- NULL, /* convert */
- NULL, /* finalize */
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- JS_CLASS_TRACE(args_or_call_trace)
+ PropertyStub, PropertyStub,
+ PropertyStub, PropertyStub,
+ call_enumerate, (JSResolveOp)call_resolve,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ JS_CLASS_TRACE(args_or_call_trace), NULL
};
bool
JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
{
if (!fun) {
*vp = argv ? argv[-2] : UndefinedValue();
return true;
@@ -1918,31 +1900,24 @@ JSFunction::countInterpretedReservedSlot
* does not bloat every instance, only those on which reserved slots are set,
* and those on which ad-hoc properties are defined.
*/
JS_PUBLIC_DATA(Class) js_FunctionClass = {
js_Function_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::FUN_FIXED_RESERVED_SLOTS) |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- fun_enumerate,
- (JSResolveOp)fun_resolve,
- ConvertStub,
- fun_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- js_XDRFunctionObject,
- fun_hasInstance,
- JS_CLASS_TRACE(fun_trace)
+ PropertyStub, PropertyStub,
+ PropertyStub, PropertyStub,
+ fun_enumerate, (JSResolveOp)fun_resolve,
+ ConvertStub, fun_finalize,
+ NULL, NULL,
+ NULL, NULL,
+ js_XDRFunctionObject, fun_hasInstance,
+ JS_CLASS_TRACE(fun_trace), NULL
};
namespace js {
JSString *
fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent)
{
if (!obj->isFunction()) {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1850,18 +1850,17 @@ JS_PUBLIC_API(void)
JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
{
switch (kind) {
case JSTRACE_OBJECT: {
/* If obj has no map, it must be a newborn. */
JSObject *obj = (JSObject *) thing;
if (!obj->map)
break;
- JSTraceOp op = obj->getOps()->trace;
- (op ? op : js_TraceObject)(trc, obj);
+ obj->map->ops->trace(trc, obj);
break;
}
case JSTRACE_STRING: {
JSString *str = (JSString *) thing;
if (str->isDependent())
JS_CALL_STRING_TRACER(trc, str->dependentBase(), "base");
else if (str->isRope()) {
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -331,23 +331,19 @@ ComputeThisFromArgv(JSContext *cx, Value
#if JS_HAS_NO_SUCH_METHOD
const uint32 JSSLOT_FOUND_FUNCTION = JSSLOT_PRIVATE;
const uint32 JSSLOT_SAVED_ID = JSSLOT_PRIVATE + 1;
Class js_NoSuchMethodClass = {
"NoSuchMethod",
JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
/*
* When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
* the base object, we search for the __noSuchMethod__ method in the base.
* If it exists, we store the method and the property's id into an object of
* NoSuchMethod class and store this object into the callee's stack slot.
* Later, js_Invoke will recognise such an object and transfer control to
@@ -619,17 +615,17 @@ DoSlowCall(JSContext *cx, uintN argc, Va
JSStackFrame *fp = cx->fp;
JSObject *obj = fp->getThisObject(cx);
if (!obj)
return false;
JS_ASSERT(ObjectValue(*obj) == fp->thisv);
JSObject *callee = &JS_CALLEE(cx, vp).toObject();
Class *clasp = callee->getClass();
- JS_ASSERT(!(clasp->flags & Class::CALL_IS_FAST));
+ JS_ASSERT(!(clasp->flags & CLASS_CALL_IS_FAST));
if (!clasp->call) {
js_ReportIsNotFunction(cx, &vp[0], 0);
return JS_FALSE;
}
AutoValueRooter rval(cx);
JSBool ok = clasp->call(cx, obj, argc, JS_ARGV(cx, vp), rval.addr());
if (ok)
JS_SET_RVAL(cx, vp, rval.value());
@@ -722,17 +718,17 @@ Invoke(JSContext *cx, const InvokeArgsGu
/* Try a call or construct native object op. */
if (flags & JSINVOKE_CONSTRUCT) {
if (!vp[1].isObjectOrNull()) {
if (!js_PrimitiveToObject(cx, &vp[1]))
return false;
}
return InvokeCommon(cx, NULL, NULL, DoConstruct, args, flags);
}
- CallOp callOp = (clasp->flags & Class::CALL_IS_FAST) ? (CallOp) clasp->call : DoSlowCall;
+ CallOp callOp = (clasp->flags & CLASS_CALL_IS_FAST) ? (CallOp) clasp->call : DoSlowCall;
return InvokeCommon(cx, NULL, NULL, callOp, args, flags);
}
extern JS_REQUIRES_STACK JS_FRIEND_API(bool)
InvokeFriendAPI(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
{
return Invoke(cx, args, flags);
}
@@ -872,17 +868,17 @@ Execute(JSContext *cx, JSObject *chain,
if (!innerizedChain)
return false;
fp->scopeChain = innerizedChain;
initialVarObj = (cx->options & JSOPTION_VAROBJFIX)
? chain->getGlobal()
: chain;
}
- JS_ASSERT(!initialVarObj->getOps()->defineProperty);
+ JS_ASSERT(initialVarObj->map->ops->defineProperty == js_DefineProperty);
fp->script = script;
fp->imacpc = NULL;
fp->rval.setUndefined();
fp->blockChain = NULL;
/* Initialize regs. */
regs.pc = script->code;
@@ -1111,17 +1107,17 @@ TypeOfValue(JSContext *cx, const Value &
return JSTYPE_NUMBER;
if (v.isString())
return JSTYPE_STRING;
if (v.isNull())
return JSTYPE_OBJECT;
if (v.isUndefined())
return JSTYPE_VOID;
if (v.isObject())
- return v.toObject().typeOf(cx);
+ return v.toObject().map->ops->typeOf(cx, &v.toObject());
JS_ASSERT(v.isBoolean());
return JSTYPE_BOOLEAN;
}
bool
InstanceOfSlow(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
{
JS_ASSERT(!obj || obj->getClass() != clasp);
@@ -2023,31 +2019,31 @@ JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH ==
/*
* Inline fast paths for iteration. js_IteratorMore and js_IteratorNext handle
* all cases, but we inline the most frequently taken paths here.
*/
static inline bool
IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval)
{
- if (iterobj->getClass() == &js_IteratorClass) {
+ if (iterobj->getClass() == &js_IteratorClass.base) {
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
*cond = (ni->props_cursor < ni->props_end);
} else {
if (!js_IteratorMore(cx, iterobj, rval))
return false;
*cond = rval->isTrue();
}
return true;
}
static inline bool
IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
{
- if (iterobj->getClass() == &js_IteratorClass) {
+ if (iterobj->getClass() == &js_IteratorClass.base) {
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
JS_ASSERT(ni->props_cursor < ni->props_end);
if (ni->isKeyIter()) {
jsid id = *ni->currentKey();
if (JSID_IS_ATOM(id)) {
rval->setString(JSID_TO_STRING(id));
ni->incKeyCursor();
return true;
@@ -3213,28 +3209,30 @@ END_CASE(JSOP_BITAND)
if ((lval.isObject() && lval.toObject().isXML()) || \
(rval.isObject() && rval.toObject().isXML())) { \
if (!js_TestXMLEquality(cx, lval, rval, &cond)) \
goto error; \
cond = cond OP JS_TRUE; \
} else
#define EXTENDED_EQUALITY_OP(OP) \
- if (EqualityOp eq = l->getClass()->ext.equality) { \
- if (!eq(cx, l, &rval, &cond)) \
+ if (((clasp = l->getClass())->flags & JSCLASS_IS_EXTENDED) && \
+ ((ExtendedClass *)clasp)->equality) { \
+ if (!((ExtendedClass *)clasp)->equality(cx, l, &rval, &cond)) \
goto error; \
cond = cond OP JS_TRUE; \
} else
#else
#define XML_EQUALITY_OP(OP) /* nothing */
#define EXTENDED_EQUALITY_OP(OP) /* nothing */
#endif
#define EQUALITY_OP(OP, IFNAN) \
JS_BEGIN_MACRO \
+ Class *clasp; \
JSBool cond; \
Value rval = regs.sp[-1]; \
Value lval = regs.sp[-2]; \
XML_EQUALITY_OP(OP) \
if (SameType(lval, rval)) { \
if (lval.isString()) { \
JSString *l = lval.toString(), *r = rval.toString(); \
cond = js_EqualStrings(l, r) OP JS_TRUE; \
@@ -4043,17 +4041,17 @@ BEGIN_CASE(JSOP_GETXPROP)
NATIVE_GET(cx, obj, obj2, sprop,
fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
&rval);
}
break;
}
jsid id = ATOM_TO_JSID(atom);
- if (JS_LIKELY(!aobj->getOps()->getProperty)
+ if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
? !js_GetPropertyHelper(cx, obj, id,
(fp->imacpc ||
regs.pc[JSOP_GETPROP_LENGTH + i] == JSOP_IFEQ)
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
: JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
&rval)
: !obj->getProperty(cx, id, &rval)) {
goto error;
@@ -4147,26 +4145,26 @@ BEGIN_CASE(JSOP_CALLPROP)
* PropertyCache::test.
*/
jsid id;
id = ATOM_TO_JSID(atom);
PUSH_NULL();
if (lval.isObject()) {
if (!js_GetMethod(cx, &objv.toObject(), id,
- JS_LIKELY(!aobj->getOps()->getProperty)
+ JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
: JSGET_NO_METHOD_BARRIER,
&rval)) {
goto error;
}
regs.sp[-1] = objv;
regs.sp[-2] = rval;
} else {
- JS_ASSERT(!objv.toObject().getOps()->getProperty);
+ JS_ASSERT(objv.toObject().map->ops->getProperty == js_GetProperty);
if (!js_GetPropertyHelper(cx, &objv.toObject(), id,
JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER,
&rval)) {
goto error;
}
regs.sp[-1] = lval;
regs.sp[-2] = rval;
}
@@ -4380,17 +4378,17 @@ BEGIN_CASE(JSOP_SETMETHOD)
}
if (sprop)
break;
}
if (!atom)
LOAD_ATOM(0, atom);
jsid id = ATOM_TO_JSID(atom);
- if (entry && JS_LIKELY(!obj->getOps()->setProperty)) {
+ if (entry && JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) {
uintN defineHow;
if (op == JSOP_SETMETHOD)
defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD;
else if (op == JSOP_SETNAME)
defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED;
else
defineHow = JSDNP_CACHE_RESULT;
if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval))
@@ -5354,17 +5352,17 @@ BEGIN_CASE(JSOP_DEFVAR)
JSAtom *atom = atoms[index];
/*
* index is relative to atoms at this point but for global var
* code below we need the absolute value.
*/
index += atoms - script->atomMap.vector;
JSObject *obj = fp->varobj(cx);
- JS_ASSERT(!obj->getOps()->defineProperty);
+ JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty);
uintN attrs = JSPROP_ENUMERATE;
if (!(fp->flags & JSFRAME_EVAL))
attrs |= JSPROP_PERMANENT;
if (op == JSOP_DEFCONST)
attrs |= JSPROP_READONLY;
/* Lookup id in order to check for redeclaration problems. */
jsid id = ATOM_TO_JSID(atom);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -80,41 +80,29 @@
#include "jsstrinlines.h"
using namespace js;
static void iterator_finalize(JSContext *cx, JSObject *obj);
static void iterator_trace(JSTracer *trc, JSObject *obj);
static JSObject *iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
-Class js_IteratorClass = {
- "Iterator",
- JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) | JSCLASS_MARK_IS_TRACE,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- iterator_finalize,
- NULL, /* reserved */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- JS_CLASS_TRACE(iterator_trace),
- {
- NULL, /* equality */
- NULL, /* outerObject */
- NULL, /* innerObject */
- iterator_iterator,
- NULL /* wrappedObject */
- }
+ExtendedClass js_IteratorClass = {
+ { "Iterator",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) |
+ JSCLASS_MARK_IS_TRACE |
+ JSCLASS_IS_EXTENDED,
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, iterator_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, JS_CLASS_TRACE(iterator_trace), NULL },
+ NULL, NULL, NULL, iterator_iterator,
+ NULL,
+ JSCLASS_NO_RESERVED_MEMBERS
};
void
NativeIterator::mark(JSTracer *trc)
{
if (isKeyIter())
MarkIdRange(trc, beginKey(), endKey(), "props");
else
@@ -125,17 +113,17 @@ NativeIterator::mark(JSTracer *trc)
/*
* Shared code to close iterator's state either through an explicit call or
* when GC detects that the iterator is no longer reachable.
*/
static void
iterator_finalize(JSContext *cx, JSObject *obj)
{
- JS_ASSERT(obj->getClass() == &js_IteratorClass);
+ JS_ASSERT(obj->getClass() == &js_IteratorClass.base);
/* Avoid double work if the iterator was closed by JSOP_ENDITER. */
NativeIterator *ni = obj->getNativeIterator();
if (ni) {
cx->free(ni);
obj->setNativeIterator(NULL);
}
}
@@ -315,17 +303,17 @@ Snapshot(JSContext *cx, JSObject *obj, u
IdSet ht(cx);
if (!ht.init(32))
return NULL;
JSObject *pobj = obj;
do {
Class *clasp = pobj->getClass();
if (pobj->isNative() &&
- !pobj->getOps()->enumerate &&
+ pobj->map->ops->enumerate == js_Enumerate &&
!(clasp->flags & JSCLASS_NEW_ENUMERATE)) {
if (!clasp->enumerate(cx, pobj))
return false;
if (!EnumerateNativeProperties<EnumPolicy>(cx, obj, pobj, flags, ht, props))
return false;
} else if (pobj->isDenseArray()) {
if (!EnumerateDenseArrayProperties<EnumPolicy>(cx, obj, pobj, flags, ht, props))
return false;
@@ -456,21 +444,21 @@ NewIteratorObject(JSContext *cx, uintN f
* are not stillborn, with the exception of "NoSuchMethod" internal
* helper objects) expect it to have a non-null map pointer, so we
* share an empty Enumerator scope in the runtime.
*/
JSObject *obj = js_NewGCObject(cx);
if (!obj)
return false;
obj->map = cx->runtime->emptyEnumeratorScope->hold();
- obj->init(&js_IteratorClass, NULL, NULL, NullValue());
+ obj->init(&js_IteratorClass.base, NULL, NULL, NullValue());
return obj;
}
- return NewBuiltinClassInstance(cx, &js_IteratorClass);
+ return NewBuiltinClassInstance(cx, &js_IteratorClass.base);
}
NativeIterator *
NativeIterator::allocateKeyIterator(JSContext *cx, uint32 slength, const AutoIdVector &props)
{
size_t plength = props.length();
NativeIterator *ni = (NativeIterator *)
cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(uint32));
@@ -617,17 +605,17 @@ GetIterator(JSContext *cx, JSObject *obj
* The iterator object for JSITER_ENUMERATE never escapes, so we
* don't care for the proper parent/proto to be set. This also
* allows us to re-use a previous iterator object that was freed
* by JSOP_ENDITER.
*/
JSObject *pobj = obj;
do {
if (!pobj->isNative() ||
- obj->getOps()->enumerate ||
+ obj->map->ops->enumerate != js_Enumerate ||
pobj->getClass()->enumerate != JS_EnumerateStub) {
shapes.clear();
goto miss;
}
uint32 shape = pobj->shape();
key = (key + (key << 16)) ^ shape;
if (!shapes.append(shape))
return false;
@@ -705,17 +693,17 @@ js_ThrowStopIteration(JSContext *cx)
}
static JSBool
iterator_next(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj;
obj = ComputeThisFromVp(cx, vp);
- if (!InstanceOf(cx, obj, &js_IteratorClass, vp + 2))
+ if (!InstanceOf(cx, obj, &js_IteratorClass.base, vp + 2))
return false;
if (!js_IteratorMore(cx, obj, vp))
return false;
if (!vp->toBoolean()) {
js_ThrowStopIteration(cx);
return false;
}
@@ -767,41 +755,45 @@ js_ValueToIterator(JSContext *cx, uintN
obj = js_ValueToNonNullObject(cx, *vp);
if (!obj)
return false;
}
}
AutoObjectRooter tvr(cx, obj);
- /* Enumerate Iterator.prototype directly. */
- JSIteratorOp op = obj->getClass()->ext.iteratorObject;
- if (op && (obj->getClass() != &js_IteratorClass || obj->getNativeIterator())) {
- JSObject *iterobj = op(cx, obj, !(flags & JSITER_FOREACH));
- if (!iterobj)
- return false;
- vp->setObject(*iterobj);
- return true;
+ Class *clasp = obj->getClass();
+ ExtendedClass *xclasp;
+ if ((clasp->flags & JSCLASS_IS_EXTENDED) &&
+ (xclasp = (ExtendedClass *) clasp)->iteratorObject) {
+ /* Enumerate Iterator.prototype directly. */
+ if (clasp != &js_IteratorClass.base || obj->getNativeIterator()) {
+ JSObject *iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH));
+ if (!iterobj)
+ return false;
+ vp->setObject(*iterobj);
+ return true;
+ }
}
return GetIterator(cx, obj, flags, vp);
}
#if JS_HAS_GENERATORS
static JS_REQUIRES_STACK JSBool
CloseGenerator(JSContext *cx, JSObject *genobj);
#endif
JS_FRIEND_API(JSBool)
js_CloseIterator(JSContext *cx, JSObject *obj)
{
cx->iterValue.setMagic(JS_NO_ITER_VALUE);
Class *clasp = obj->getClass();
- if (clasp == &js_IteratorClass) {
+ if (clasp == &js_IteratorClass.base) {
/* Remove enumerators from the active list, which is a stack. */
NativeIterator *ni = obj->getNativeIterator();
if (ni->flags & JSITER_ENUMERATE) {
JS_ASSERT(cx->enumerators == obj);
cx->enumerators = ni->next;
}
/* Cache the iterator object if possible. */
@@ -811,17 +803,17 @@ js_CloseIterator(JSContext *cx, JSObject
ni->props_cursor = ni->props_array;
ni->next = *hp;
*hp = obj;
} else {
iterator_finalize(cx, obj);
}
}
#if JS_HAS_GENERATORS
- else if (clasp == &js_GeneratorClass) {
+ else if (clasp == &js_GeneratorClass.base) {
return CloseGenerator(cx, obj);
}
#endif
return JS_TRUE;
}
/*
* Suppress enumeration of deleted properties. We maintain a list of all active
@@ -896,17 +888,17 @@ js_SuppressDeletedProperty(JSContext *cx
}
return true;
}
JSBool
js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
{
/* Fast path for native iterators */
- if (iterobj->getClass() == &js_IteratorClass) {
+ if (iterobj->getClass() == &js_IteratorClass.base) {
/*
* Implement next directly as all the methods of native iterator are
* read-only and permanent.
*/
NativeIterator *ni = iterobj->getNativeIterator();
rval->setBoolean(ni->props_cursor < ni->props_end);
return true;
}
@@ -940,17 +932,17 @@ js_IteratorMore(JSContext *cx, JSObject
rval->setBoolean(true);
return true;
}
JSBool
js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
{
/* Fast path for native iterators */
- if (iterobj->getClass() == &js_IteratorClass) {
+ if (iterobj->getClass() == &js_IteratorClass.base) {
/*
* Implement next directly as all the methods of the native iterator are
* read-only and permanent.
*/
NativeIterator *ni = iterobj->getNativeIterator();
JS_ASSERT(ni->props_cursor < ni->props_end);
if (ni->isKeyIter()) {
*rval = IdToValue(*ni->currentKey());
@@ -989,30 +981,24 @@ stopiter_hasInstance(JSContext *cx, JSOb
{
*bp = js_ValueIsStopIteration(*v);
return JS_TRUE;
}
Class js_StopIterationClass = {
js_StopIteration_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- NULL, /* finalize */
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- stopiter_hasInstance
+ PropertyStub, PropertyStub,
+ PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub,
+ ConvertStub, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, stopiter_hasInstance,
+ NULL, NULL
};
#if JS_HAS_GENERATORS
static void
generator_finalize(JSContext *cx, JSObject *obj)
{
JSGenerator *gen = (JSGenerator *) obj->getPrivate();
@@ -1045,56 +1031,44 @@ generator_trace(JSTracer *trc, JSObject
JSStackFrame *fp = gen->getFloatingFrame();
JS_ASSERT(gen->getLiveFrame() == fp);
MarkValueRange(trc, gen->floatingStack, fp->argEnd(), "generator slots");
js_TraceStackFrame(trc, fp);
MarkValueRange(trc, fp->slots(), gen->savedRegs.sp, "generator slots");
}
-Class js_GeneratorClass = {
- js_Generator_str,
- JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) |
- JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- generator_finalize,
- NULL, /* reserved */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- JS_CLASS_TRACE(generator_trace),
- {
- NULL, /* equality */
- NULL, /* outerObject */
- NULL, /* innerObject */
- iterator_iterator,
- NULL, /* wrappedObject */
- }
+ExtendedClass js_GeneratorClass = {
+ { js_Generator_str,
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) |
+ JSCLASS_IS_ANONYMOUS |
+ JSCLASS_MARK_IS_TRACE |
+ JSCLASS_IS_EXTENDED,
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, generator_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, JS_CLASS_TRACE(generator_trace), NULL },
+ NULL, NULL, NULL, iterator_iterator,
+ NULL,
+ JSCLASS_NO_RESERVED_MEMBERS
};
/*
* Called from the JSOP_GENERATOR case in the interpreter, with fp referring
* to the frame by which the generator function was activated. Create a new
* JSGenerator object, which contains its own JSStackFrame that we populate
* from *fp. We know that upon return, the JSOP_GENERATOR opcode will return
* from the activation in fp, so we can steal away fp->callobj and fp->argsobj
* if they are non-null.
*/
JS_REQUIRES_STACK JSObject *
js_NewGenerator(JSContext *cx)
{
- JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass);
+ JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass.base);
if (!obj)
return NULL;
/* Load and compute stack slot counts. */
JSStackFrame *fp = cx->fp;
uintN argc = fp->argc;
uintN nargs = JS_MAX(argc, fp->fun->nargs);
uintN vplen = 2 + nargs;
@@ -1326,17 +1300,17 @@ SendToGenerator(JSContext *cx, JSGenerat
* Propagate the condition to the caller.
*/
return JS_FALSE;
}
static JS_REQUIRES_STACK JSBool
CloseGenerator(JSContext *cx, JSObject *obj)
{
- JS_ASSERT(obj->getClass() == &js_GeneratorClass);
+ JS_ASSERT(obj->getClass() == &js_GeneratorClass.base);
JSGenerator *gen = (JSGenerator *) obj->getPrivate();
if (!gen) {
/* Generator prototype object. */
return JS_TRUE;
}
if (gen->state == JSGEN_CLOSED)
@@ -1350,17 +1324,17 @@ CloseGenerator(JSContext *cx, JSObject *
*/
static JSBool
generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
{
JSObject *obj;
LeaveTrace(cx);
obj = ComputeThisFromVp(cx, vp);
- if (!InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))
+ if (!InstanceOf(cx, obj, &js_GeneratorClass.base, vp + 2))
return JS_FALSE;
JSGenerator *gen = (JSGenerator *) obj->getPrivate();
if (!gen) {
/* This happens when obj is the generator prototype. See bug 352885. */
goto closed_generator;
}
@@ -1445,24 +1419,24 @@ js_InitIteratorClasses(JSContext *cx, JS
JSObject *proto, *stop;
/* Idempotency required: we initialize several things, possibly lazily. */
if (!js_GetClassObject(cx, obj, JSProto_StopIteration, &stop))
return NULL;
if (stop)
return stop;
- proto = js_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2,
+ proto = js_InitClass(cx, obj, NULL, &js_IteratorClass.base, Iterator, 2,
NULL, iterator_methods, NULL, NULL);
if (!proto)
return NULL;
#if JS_HAS_GENERATORS
/* Initialize the generator internals if configured. */
- if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass, NULL, 0,
+ if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass.base, NULL, 0,
NULL, generator_methods, NULL, NULL)) {
return NULL;
}
#endif
return js_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0,
NULL, NULL, NULL, NULL);
}
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -244,19 +244,19 @@ js_LiveFrameIfGenerator(JSStackFrame *fp
{
if (fp->flags & JSFRAME_GENERATOR)
return js_FloatingFrameToGenerator(fp)->getLiveFrame();
return fp;
}
#endif
-extern js::Class js_GeneratorClass;
-extern js::Class js_IteratorClass;
-extern js::Class js_StopIterationClass;
+extern js::ExtendedClass js_GeneratorClass;
+extern js::ExtendedClass js_IteratorClass;
+extern js::Class js_StopIterationClass;
static inline bool
js_ValueIsStopIteration(const js::Value &v)
{
return v.isObject() && v.toObject().getClass() == &js_StopIterationClass;
}
extern JSObject *
--- a/js/src/jslock.h
+++ b/js/src/jslock.h
@@ -145,17 +145,19 @@ struct JSTitle {
#define JS_UNLOCK(cx, tl) js_Unlock(cx, tl)
#define JS_LOCK_RUNTIME(rt) js_LockRuntime(rt)
#define JS_UNLOCK_RUNTIME(rt) js_UnlockRuntime(rt)
/*
* NB: The JS_LOCK_OBJ and JS_UNLOCK_OBJ macros work *only* on native objects
* (objects for which obj->isNative() returns true). All uses of these macros in
- * the engine are predicated on obj->isNative or equivalent checks.
+ * the engine are predicated on obj->isNative or equivalent checks. These uses
+ * are for optimizations above the JSObjectOps layer, under which object locks
+ * normally hide.
*/
#define CX_OWNS_SCOPE_TITLE(cx,scope) ((scope)->title.ownercx == (cx))
#define JS_LOCK_OBJ(cx,obj) \
JS_BEGIN_MACRO \
JSObject *obj_ = (obj); \
if (!CX_OWNS_SCOPE_TITLE(cx, obj_->scope())) { \
js_LockObj(cx, obj_); \
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -92,23 +92,19 @@ static JSConstDoubleSpec math_constants[
{M_SQRT2, "SQRT2", 0, {0,0,0}},
{M_SQRT1_2, "SQRT1_2", 0, {0,0,0}},
{0,0,0,{0,0,0}}
};
Class js_MathClass = {
js_Math_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
static JSBool
math_abs(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -266,23 +266,19 @@ static JSFunctionSpec number_functions[]
JS_TN(js_parseFloat_str, num_parseFloat, 1,0, &num_parseFloat_trcinfo),
JS_TN(js_parseInt_str, num_parseInt, 2,0, &num_parseInt_trcinfo),
JS_FS_END
};
Class js_NumberClass = {
js_Number_str,
JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
static JSBool
Number(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
{
if (argc != 0) {
if (!ValueToNumber(cx, &argv[0]))
return JS_FALSE;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -97,37 +97,40 @@
#include "jsatominlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#include "jsautooplen.h"
using namespace js;
-JS_FRIEND_DATA(const JSObjectMap) JSObjectMap::sharedNonNative(JSObjectMap::SHAPELESS);
+JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
+ NULL,
+ js_LookupProperty,
+ js_DefineProperty,
+ js_GetProperty,
+ js_SetProperty,
+ js_GetAttributes,
+ js_SetAttributes,
+ js_DeleteProperty,
+ js_Enumerate,
+ js_TypeOf,
+ js_TraceObject,
+ NULL, /* thisObject */
+ js_Clear
+};
Class js_ObjectClass = {
js_Object_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
-JS_FRIEND_API(JSObject *)
-js_ObjectToOuterObject(JSContext *cx, JSObject *obj)
-{
- OBJ_TO_OUTER_OBJECT(cx, obj);
- return obj;
-}
-
#if JS_HAS_OBJ_PROTO_PROP
static JSBool
obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp);
static JSBool
obj_setProto(JSContext *cx, JSObject *obj, jsid id, Value *vp);
@@ -909,31 +912,40 @@ js_CheckPrincipalsAccess(JSContext *cx,
}
}
return JS_TRUE;
}
JSObject *
js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller)
{
+ Class *clasp;
+ JSExtendedClass *xclasp;
JSObject *inner;
if (!scopeobj)
goto bad;
OBJ_TO_INNER_OBJECT(cx, scopeobj);
if (!scopeobj)
return NULL;
+ inner = scopeobj;
+
/* XXX This is an awful gross hack. */
- inner = scopeobj;
while (scopeobj) {
- JSObjectOp op = scopeobj->getClass()->ext.innerObject;
- if (op && op(cx, scopeobj) != scopeobj)
- goto bad;
+ clasp = scopeobj->getClass();
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ xclasp = (JSExtendedClass*)clasp;
+ if (xclasp->innerObject &&
+ xclasp->innerObject(cx, scopeobj) != scopeobj) {
+ goto bad;
+ }
+ }
+
scopeobj = scopeobj->getParent();
}
return inner;
bad:
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_INDIRECT_CALL, caller);
@@ -1350,17 +1362,17 @@ obj_unwatch(JSContext *cx, uintN argc, V
*/
/* Proposed ECMA 15.2.4.5. */
static JSBool
obj_hasOwnProperty(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj = ComputeThisFromVp(cx, vp);
return obj &&
- js_HasOwnPropertyHelper(cx, obj->getOps()->lookupProperty, argc, vp);
+ js_HasOwnPropertyHelper(cx, obj->map->ops->lookupProperty, argc, vp);
}
JSBool
js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc,
Value *vp)
{
jsid id;
if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
@@ -1389,28 +1401,32 @@ js_HasOwnPropertyHelper(JSContext *cx, J
return JS_TRUE;
}
JSBool
js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id,
JSObject **objp, JSProperty **propp)
{
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
- if (!(lookup ? lookup : js_LookupProperty)(cx, obj, id, objp, propp))
+ if (!lookup(cx, obj, id, objp, propp))
return false;
if (!*propp)
return true;
if (*objp == obj)
return true;
+ JSExtendedClass *xclasp;
+ JSObject *outer;
Class *clasp = (*objp)->getClass();
- JSObject *outer = NULL;
- if (JSObjectOp op = (*objp)->getClass()->ext.outerObject) {
- outer = op(cx, *objp);
+ if (!(clasp->flags & JSCLASS_IS_EXTENDED) ||
+ !(xclasp = (JSExtendedClass *) clasp)->outerObject) {
+ outer = NULL;
+ } else {
+ outer = xclasp->outerObject(cx, *objp);
if (!outer)
return false;
}
if (outer != *objp) {
if ((*objp)->isNative() && obj->getClass() == clasp) {
/*
* The combination of JSPROP_SHARED and JSPROP_PERMANENT in a
@@ -1686,17 +1702,17 @@ js_GetOwnPropertyDescriptor(JSContext *c
{
if (obj->isProxy()) {
if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, vp))
return false;
}
JSObject *pobj;
JSProperty *prop;
- if (!js_HasOwnProperty(cx, obj->getOps()->lookupProperty, obj, id, &pobj, &prop))
+ if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &pobj, &prop))
return false;
if (!prop) {
vp->setUndefined();
return true;
}
Value roots[] = { UndefinedValue(), UndefinedValue(), UndefinedValue() };
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
@@ -1962,32 +1978,32 @@ Reject(JSContext *cx, JSObject *obj, JSP
static JSBool
DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
bool throwError, bool *rval)
{
/* 8.12.9 step 1. */
JSProperty *current;
JSObject *obj2;
- JS_ASSERT(!obj->getOps()->lookupProperty);
- if (!js_HasOwnProperty(cx, NULL, obj, desc.id, &obj2, ¤t))
+ JS_ASSERT(obj->map->ops->lookupProperty == js_LookupProperty);
+ if (!js_HasOwnProperty(cx, js_LookupProperty, obj, desc.id, &obj2, ¤t))
return JS_FALSE;
- JS_ASSERT(!obj->getOps()->defineProperty);
+ JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty);
/* 8.12.9 steps 2-4. */
JSScope *scope = obj->scope();
if (!current) {
if (scope->sealed())
return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
*rval = true;
if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
- JS_ASSERT(!obj->getOps()->defineProperty);
+ JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty);
return js_DefineProperty(cx, obj, desc.id, &desc.value,
PropertyStub, PropertyStub, desc.attrs);
}
JS_ASSERT(desc.isAccessorDescriptor());
/*
* Getters and setters are just like watchpoints from an access
@@ -2282,17 +2298,17 @@ DefinePropertyOnArray(JSContext *cx, JSO
static JSBool
DefineProperty(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwError,
bool *rval)
{
if (obj->isArray())
return DefinePropertyOnArray(cx, obj, desc, throwError, rval);
- if (obj->getOps()->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 DefinePropertyOnObject(cx, obj, desc, throwError, rval);
}
@@ -2563,17 +2579,18 @@ js_Object(JSContext *cx, JSObject *obj,
}
#ifdef JS_TRACER
JSObject*
js_NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
const Value &privateSlotValue)
{
- JS_ASSERT(clasp->isNative());
+ JS_ASSERT(!clasp->getObjectOps);
+ JS_ASSERT(proto->map->ops == &js_ObjectOps);
JSObject* obj = js_NewGCObject(cx);
if (!obj)
return NULL;
obj->initSharingEmptyScope(clasp, proto, proto->getParent(), privateSlotValue);
return obj;
}
@@ -2843,49 +2860,45 @@ with_TypeOf(JSContext *cx, JSObject *obj
}
static JSObject *
with_ThisObject(JSContext *cx, JSObject *obj)
{
return obj->getWithThis();
}
+JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
+ NULL,
+ with_LookupProperty,
+ js_DefineProperty,
+ with_GetProperty,
+ with_SetProperty,
+ with_GetAttributes,
+ with_SetAttributes,
+ with_DeleteProperty,
+ with_Enumerate,
+ with_TypeOf,
+ js_TraceObject,
+ with_ThisObject,
+ js_Clear
+};
+
+static JSObjectOps *
+with_getObjectOps(JSContext *cx, Class *clasp)
+{
+ return &js_WithObjectOps;
+}
+
Class js_WithClass = {
"With",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- NULL, /* finalize */
- NULL, /* reserved */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- NULL, /* mark */
- JS_NULL_CLASS_EXT,
- {
- with_LookupProperty,
- NULL, /* defineProperty */
- with_GetProperty,
- with_SetProperty,
- with_GetAttributes,
- with_SetAttributes,
- with_DeleteProperty,
- with_Enumerate,
- with_TypeOf,
- NULL, /* trace */
- with_ThisObject,
- NULL, /* clear */
- }
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ with_getObjectOps,
+ 0,0,0,0,0,0,0
};
JS_REQUIRES_STACK JSObject *
js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
{
JSObject *obj;
obj = js_NewGCObject(cx);
@@ -3222,23 +3235,19 @@ js_XDRBlockObject(JSXDRState *xdr, JSObj
return true;
}
#endif
Class js_BlockClass = {
"Block",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
JSObject *
js_InitObjectClass(JSContext *cx, JSObject *obj)
{
JSObject *proto = js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1,
object_props, object_methods, NULL, object_static_methods);
if (!proto)
@@ -4457,17 +4466,17 @@ js_FindPropertyHelper(JSContext *cx, jsi
/* Scan entries on the scope chain that we can cache across. */
entry = JS_NO_PROP_CACHE_FILL;
obj = scopeChain;
parent = obj->getParent();
for (scopeIndex = 0;
parent
? js_IsCacheableNonGlobalScope(obj)
- : !obj->getOps()->lookupProperty;
+ : obj->map->ops->lookupProperty == js_LookupProperty;
++scopeIndex) {
protoIndex =
js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
&pobj, &prop);
if (protoIndex < 0)
return NULL;
if (prop) {
@@ -4838,29 +4847,26 @@ js_GetProperty(JSContext *cx, JSObject *
return js_GetPropertyHelper(cx, obj, id, JSGET_METHOD_BARRIER, vp);
}
JSBool
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, Value *vp)
{
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
- PropertyIdOp op = obj->getOps()->getProperty;
- if (!op) {
-#if JS_HAS_XML_SUPPORT
- JS_ASSERT(!obj->isXML());
-#endif
+ if (obj->map->ops == &js_ObjectOps ||
+ obj->map->ops->getProperty == js_GetProperty) {
return js_GetPropertyHelper(cx, obj, id, getHow, vp);
}
JS_ASSERT_IF(getHow & JSGET_CACHE_RESULT, obj->isDenseArray());
#if JS_HAS_XML_SUPPORT
if (obj->isXML())
return js_GetXMLMethod(cx, obj, id, vp);
#endif
- return op(cx, obj, id, vp);
+ return obj->getProperty(cx, id, vp);
}
JS_FRIEND_API(bool)
js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
{
JSStackFrame *const fp = js_GetTopStackFrame(cx);
if (!fp)
return true;
@@ -5370,17 +5376,17 @@ DefaultValue(JSContext *cx, JSObject *ob
return JS_FALSE;
}
*vp = v;
return JS_TRUE;
}
} /* namespace js */
-JS_FRIEND_API(JSBool)
+JSBool
js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, Value *statep, jsid *idp)
{
/* If the class has a custom JSCLASS_NEW_ENUMERATE hook, call it. */
Class *clasp = obj->getClass();
JSEnumerateOp enumerate = clasp->enumerate;
if (clasp->flags & JSCLASS_NEW_ENUMERATE) {
JS_ASSERT(enumerate != JS_EnumerateStub);
return ((NewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
@@ -5948,17 +5954,17 @@ js_TraceObject(JSTracer *trc, JSObject *
for (uint32 i = JSSLOT_START(clasp); i != nslots; ++i) {
const Value &v = obj->getSlot(i);
JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
MarkValueRaw(trc, v);
}
}
void
-js_ClearNative(JSContext *cx, JSObject *obj)
+js_Clear(JSContext *cx, JSObject *obj)
{
JSScope *scope;
uint32 i, n;
/*
* Clear our scope and the property cache of all obj's properties only if
* obj owns the scope (i.e., not if obj is sharing another object's scope).
* NB: we do not clear any reserved slots lying below JSSLOT_FREE(clasp).
@@ -6037,19 +6043,22 @@ js_SetReservedSlot(JSContext *cx, JSObje
GC_POKE(cx, JS_NULL);
JS_UNLOCK_SCOPE(cx, scope);
return true;
}
JSObject *
JSObject::wrappedObject(JSContext *cx) const
{
- if (JSObjectOp op = getClass()->ext.wrappedObject) {
- if (JSObject *obj = op(cx, const_cast<JSObject *>(this)))
- return obj;
+ Class *clasp = getClass();
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ if (JSObjectOp wrappedObject = reinterpret_cast<JSExtendedClass *>(clasp)->wrappedObject) {
+ if (JSObject *obj = wrappedObject(cx, const_cast<JSObject *>(this)))
+ return obj;
+ }
}
return const_cast<JSObject *>(this);
}
JSObject *
JSObject::getGlobal()
{
JSObject *obj = this;
@@ -6075,17 +6084,17 @@ JSObject::getCompartment(JSContext *cx)
Class *clasp = obj->getClass();
if (!(clasp->flags & JSCLASS_IS_GLOBAL)) {
// The magic AnyName object is runtime-wide.
if (clasp == &js_AnyNameClass)
return cx->runtime->defaultCompartment;
// The magic function namespace object is runtime-wide.
- if (clasp == &js_NamespaceClass &&
+ if (clasp == &js_NamespaceClass.base &&
obj->getNameURI() == ATOM_TO_JSVAL(cx->runtime->atomState.lazy.functionNamespaceURIAtom)) {
return cx->runtime->defaultCompartment;
}
// Compile-time Function, Block, and RegExp objects are not parented.
if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass) {
// This is a bogus answer, but it'll do for now.
return cx->runtime->defaultCompartment;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -165,72 +165,83 @@ struct PropDesc {
bool hasEnumerable : 1;
bool hasConfigurable : 1;
};
namespace js {
typedef Vector<PropDesc, 1> PropDescArray;
+/*
+ * Flag and type-safe cast helper to denote that Class::call is a fast native.
+ */
+const uint32 CLASS_CALL_IS_FAST = uint32(1) << (JSCLASS_LAST_API_FLAG_SHIFT + 1);
+
+inline Native CastCallOpAsNative(CallOp op)
+{
+ return reinterpret_cast<Native>(op);
+}
+
} /* namespace js */
+/* For detailed comments on these function pointer types, see jsprvtd.h. */
+struct JSObjectOps {
+ /*
+ * Custom shared object map for non-native objects. For native objects
+ * this should be null indicating, that JSObject.map is an instance of
+ * JSScope.
+ */
+ const JSObjectMap *objectMap;
+
+ /* Mandatory non-null function pointer members. */
+ JSLookupPropOp lookupProperty;
+ js::DefinePropOp defineProperty;
+ js::PropertyIdOp getProperty;
+ js::PropertyIdOp setProperty;
+ JSAttributesOp getAttributes;
+ JSAttributesOp setAttributes;
+ js::PropertyIdOp deleteProperty;
+ js::NewEnumerateOp enumerate;
+ JSTypeOfOp typeOf;
+ JSTraceOp trace;
+
+ /* Optionally non-null members start here. */
+ JSObjectOp thisObject;
+ JSFinalizeOp clear;
+
+ bool inline isNative() const;
+};
+
+extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
+extern JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps;
+
+/*
+ * Test whether the ops is native. FIXME bug 492938: consider how it would
+ * affect the performance to do just the !objectMap check.
+ */
+inline bool
+JSObjectOps::isNative() const
+{
+ return JS_LIKELY(this == &js_ObjectOps) || !objectMap;
+}
+
struct JSObjectMap {
- static JS_FRIEND_DATA(const JSObjectMap) sharedNonNative;
-
+ const JSObjectOps * const ops; /* high level object operation vtable */
uint32 shape; /* shape identifier */
- explicit JSObjectMap(uint32 shape) : shape(shape) {}
+ explicit JSObjectMap(const JSObjectOps *ops, uint32 shape) : ops(ops), shape(shape) {}
enum { SHAPELESS = 0xffffffff };
- bool isNative() const { return this != &sharedNonNative; }
-
- private:
+private:
/* No copy or assignment semantics. */
JSObjectMap(JSObjectMap &);
void operator=(JSObjectMap &);
};
-/*
- * Unlike js_DefineNativeProperty, propp must be non-null. On success, and if
- * id was found, return true with *objp non-null and locked, and with a held
- * property stored in *propp. If successful but id was not found, return true
- * with both *objp and *propp null. Therefore all callers who receive a
- * non-null *propp must later call (*objp)->dropProperty(cx, *propp).
- */
-extern JS_FRIEND_API(JSBool)
-js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
- JSProperty **propp);
-
-extern JSBool
-js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value,
- js::PropertyOp getter, js::PropertyOp setter, uintN attrs);
-
-extern JSBool
-js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
-
-extern JSBool
-js_SetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
-
-extern JSBool
-js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
-
-extern JSBool
-js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
-
-extern JSBool
-js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *rval);
-
-extern JS_FRIEND_API(JSBool)
-js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
- js::Value *statep, jsid *idp);
-
-extern JSType
-js_TypeOf(JSContext *cx, JSObject *obj);
-
struct NativeIterator;
const uint32 JS_INITIAL_NSLOTS = 4;
const uint32 JSSLOT_PARENT = 0;
/*
* The first available slot to store generic value. For JSCLASS_HAS_PRIVATE
@@ -286,36 +297,30 @@ struct JSObject {
// TODO: this is needed to pad out fslots. alternatively, clasp could be
// merged with flags and the padding removed, but I think the upcoming
// removal of JSScope will change this all anyway so I will leave this
// here for now.
uint32 padding;
#endif
js::Value fslots[JS_INITIAL_NSLOTS]; /* small number of fixed slots */
- bool isNative() const {
- return map->isNative();
- }
+ bool isNative() const { return map->ops->isNative(); }
js::Class *getClass() const {
return clasp;
}
JSClass *getJSClass() const {
return Jsvalify(clasp);
}
bool hasClass(const js::Class *c) const {
return c == clasp;
}
- const js::ObjectOps *getOps() const {
- return &getClass()->ops;
- }
-
inline JSScope *scope() const;
inline uint32 shape() const;
bool isDelegate() const {
return (flags & jsuword(1)) != jsuword(0);
}
void setDelegate() {
@@ -677,72 +682,63 @@ struct JSObject {
JSObject *parent,
const js::Value &privateSlotValue);
inline bool hasSlotsArray() const { return !!dslots; }
/* This method can only be called when hasSlotsArray() returns true. */
inline void freeSlotsArray(JSContext *cx);
- JSBool lookupProperty(JSContext *cx, jsid id, JSObject **objp, JSProperty **propp) {
- JSLookupPropOp op = getOps()->lookupProperty;
- return (op ? op : js_LookupProperty)(cx, this, id, objp, propp);
+ JSBool lookupProperty(JSContext *cx, jsid id,
+ JSObject **objp, JSProperty **propp) {
+ return map->ops->lookupProperty(cx, this, id, objp, propp);
}
JSBool defineProperty(JSContext *cx, jsid id, const js::Value &value,
js::PropertyOp getter = js::PropertyStub,
js::PropertyOp setter = js::PropertyStub,
uintN attrs = JSPROP_ENUMERATE) {
- js::DefinePropOp op = getOps()->defineProperty;
- return (op ? op : js_DefineProperty)(cx, this, id, &value, getter, setter, attrs);
+ return map->ops->defineProperty(cx, this, id, &value, getter, setter, attrs);
}
JSBool getProperty(JSContext *cx, jsid id, js::Value *vp) {
- js::PropertyIdOp op = getOps()->getProperty;
- return (op ? op : js_GetProperty)(cx, this, id, vp);
+ return map->ops->getProperty(cx, this, id, vp);
}
JSBool setProperty(JSContext *cx, jsid id, js::Value *vp) {
- js::PropertyIdOp op = getOps()->setProperty;
- return (op ? op : js_SetProperty)(cx, this, id, vp);
+ return map->ops->setProperty(cx, this, id, vp);
}
JSBool getAttributes(JSContext *cx, jsid id, uintN *attrsp) {
- JSAttributesOp op = getOps()->getAttributes;
- return (op ? op : js_GetAttributes)(cx, this, id, attrsp);
+ return map->ops->getAttributes(cx, this, id, attrsp);
}
JSBool setAttributes(JSContext *cx, jsid id, uintN *attrsp) {
- JSAttributesOp op = getOps()->setAttributes;
- return (op ? op : js_SetAttributes)(cx, this, id, attrsp);
+ return map->ops->setAttributes(cx, this, id, attrsp);
}
JSBool deleteProperty(JSContext *cx, jsid id, js::Value *rval) {
- js::PropertyIdOp op = getOps()->deleteProperty;
- return (op ? op : js_DeleteProperty)(cx, this, id, rval);
+ return map->ops->deleteProperty(cx, this, id, rval);
}
- JSBool enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp) {
- js::NewEnumerateOp op = getOps()->enumerate;
- return (op ? op : js_Enumerate)(cx, this, iterop, statep, idp);
+ JSBool enumerate(JSContext *cx, JSIterateOp op, js::Value *statep,
+ jsid *idp) {
+ return map->ops->enumerate(cx, this, op, statep, idp);
}
JSType typeOf(JSContext *cx) {
- JSTypeOfOp op = getOps()->typeOf;
- return (op ? op : js_TypeOf)(cx, this);
+ return map->ops->typeOf(cx, this);
}
JSObject *wrappedObject(JSContext *cx) const;
/* These four are time-optimized to avoid stub calls. */
JSObject *thisObject(JSContext *cx) {
- JSObjectOp op = getOps()->thisObject;
- return op ? op(cx, this) : this;
+ return map->ops->thisObject ? map->ops->thisObject(cx, this) : this;
}
-
static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
inline void dropProperty(JSContext *cx, JSProperty *prop);
JS_FRIEND_API(JSCompartment *) getCompartment(JSContext *cx);
void swap(JSObject *obj);
@@ -813,29 +809,37 @@ JS_STATIC_ASSERT(sizeof(JSObject) % JS_G
#define CX_THREAD_IS_RUNNING_GC(cx) \
THREAD_IS_RUNNING_GC((cx)->runtime, (cx)->thread)
#endif /* JS_THREADSAFE */
inline void
OBJ_TO_INNER_OBJECT(JSContext *cx, JSObject *&obj)
{
- if (JSObjectOp op = obj->getClass()->ext.innerObject)
- obj = op(cx, obj);
+ js::Class *clasp = obj->getClass();
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ js::ExtendedClass *xclasp = (js::ExtendedClass *) clasp;
+ if (xclasp->innerObject)
+ obj = xclasp->innerObject(cx, obj);
+ }
}
/*
* The following function has been copied to jsd/jsd_val.c. If making changes to
* OBJ_TO_OUTER_OBJECT, please update jsd/jsd_val.c as well.
*/
inline void
OBJ_TO_OUTER_OBJECT(JSContext *cx, JSObject *&obj)
{
- if (JSObjectOp op = obj->getClass()->ext.outerObject)
- obj = op(cx, obj);
+ js::Class *clasp = obj->getClass();
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ js::ExtendedClass *xclasp = (js::ExtendedClass *) clasp;
+ if (xclasp->outerObject)
+ obj = xclasp->outerObject(cx, obj);
+ }
}
class JSValueArray {
public:
jsval *array;
size_t length;
JSValueArray(jsval *v, size_t c) : array(v), length(c) {}
@@ -1067,22 +1071,24 @@ js_CheckForStringIndex(jsid id);
* js_PurgeScopeChain does nothing if obj is not itself a prototype or parent
* scope, else it reshapes the scope and prototype chains it links. It calls
* js_PurgeScopeChainHelper, which asserts that obj is flagged as a delegate
* (i.e., obj has ever been on a prototype or parent chain).
*/
extern void
js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id);
-inline void
+#ifdef __cplusplus /* Aargh, libgjs, bug 492720. */
+static JS_INLINE void
js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)
{
if (obj->isDelegate())
js_PurgeScopeChainHelper(cx, obj, id);
}
+#endif
/*
* Find or create a property named by id in obj's scope, with the given getter
* and setter, slot, attributes, and other members.
*/
extern JSScopeProperty *
js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
js::PropertyOp getter, js::PropertyOp setter, uint32 slot,
@@ -1094,16 +1100,20 @@ js_AddNativeProperty(JSContext *cx, JSOb
* or identical property.
*/
extern JSScopeProperty *
js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
JSScopeProperty *sprop, uintN attrs, uintN mask,
js::PropertyOp getter, js::PropertyOp setter);
extern JSBool
+js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value,
+ js::PropertyOp getter, js::PropertyOp setter, uintN attrs);
+
+extern JSBool
js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id,
const js::Value &descriptor, JSBool *bp);
/*
* Flags for the defineHow parameter of js_DefineNativeProperty.
*/
const uintN JSDNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
const uintN JSDNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
@@ -1123,43 +1133,54 @@ const uintN JSDNP_UNQUALIFIED = 8; /* U
*/
extern JSBool
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value &value,
js::PropertyOp getter, js::PropertyOp setter, uintN attrs,
uintN flags, intN shortid, JSProperty **propp,
uintN defineHow = 0);
/*
+ * Unlike js_DefineNativeProperty, propp must be non-null. On success, and if
+ * id was found, return true with *objp non-null and locked, and with a held
+ * property stored in *propp. If successful but id was not found, return true
+ * with both *objp and *propp null. Therefore all callers who receive a
+ * non-null *propp must later call (*objp)->dropProperty(cx, *propp).
+ */
+extern JS_FRIEND_API(JSBool)
+js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+ JSProperty **propp);
+
+/*
* Specialized subroutine that allows caller to preset JSRESOLVE_* flags and
* returns the index along the prototype chain in which *propp was found, or
* the last index if not found, or -1 on error.
*/
extern int
js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSObject **objp, JSProperty **propp);
/*
* We cache name lookup results only for the global object or for native
* non-global objects without prototype or with prototype that never mutates,
* see bug 462734 and bug 487039.
*/
-inline bool
+static inline bool
js_IsCacheableNonGlobalScope(JSObject *obj)
{
extern JS_FRIEND_DATA(js::Class) js_CallClass;
extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass;
JS_ASSERT(obj->getParent());
js::Class *clasp = obj->getClass();
bool cacheable = (clasp == &js_CallClass ||
clasp == &js_BlockClass ||
clasp == &js_DeclEnvClass);
- JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
+ JS_ASSERT_IF(cacheable, obj->map->ops->lookupProperty == js_LookupProperty);
return cacheable;
}
/*
* If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
*/
extern js::PropertyCacheEntry *
js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
@@ -1210,16 +1231,19 @@ extern JSBool
js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added,
js::Value *vp);
extern JSBool
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
js::Value *vp);
extern JSBool
+js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
+
+extern JSBool
js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
extern JSBool
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, js::Value *vp);
/*
* Check whether it is OK to assign an undeclared property with name
* propname of the global object in the current script on cx. Reports
@@ -1228,34 +1252,57 @@ js_GetMethod(JSContext *cx, JSObject *ob
*/
extern JS_FRIEND_API(bool)
js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname);
extern JSBool
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
js::Value *vp);
+extern JSBool
+js_SetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
+
+extern JSBool
+js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
+
+extern JSBool
+js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
+
/*
* Change attributes for the given native property. The caller must ensure
* that obj is locked and this function always unlocks obj on return.
*/
extern JSBool
js_SetNativeAttributes(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
uintN attrs);
+extern JSBool
+js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *rval);
+
namespace js {
extern JSBool
DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
+}
+
+extern JSBool
+js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
+ js::Value *statep, jsid *idp);
+
+namespace js {
+
extern JSBool
CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
js::Value *vp, uintN *attrsp);
-} /* namespace js */
+}
+
+extern JSType
+js_TypeOf(JSContext *cx, JSObject *obj);
extern bool
js_IsDelegate(JSContext *cx, JSObject *obj, const js::Value &v);
/*
* If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
* JSProto_Null, clasp must non-null.
*/
@@ -1300,17 +1347,17 @@ js_XDRObject(JSXDRState *xdr, JSObject *
extern void
js_TraceObject(JSTracer *trc, JSObject *obj);
extern void
js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
extern void
-js_ClearNative(JSContext *cx, JSObject *obj);
+js_Clear(JSContext *cx, JSObject *obj);
extern bool
js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, js::Value *vp);
extern bool
js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, const js::Value &v);
/*
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -488,41 +488,41 @@ class AutoPropertyDescriptorRooter : pri
setter = desc->setter;
value = desc->value;
}
friend void AutoGCRooter::trace(JSTracer *trc);
};
static inline bool
-InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto)
+InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto, JSObjectOps* ops)
{
- JS_ASSERT(clasp->isNative());
+ JS_ASSERT(ops->isNative());
JS_ASSERT(proto == obj->getProto());
/* Share proto's emptyScope only if obj is similar to proto. */
JSScope *scope = NULL;
if (proto && proto->isNative()) {
JS_LOCK_OBJ(cx, proto);
scope = proto->scope();
- if (scope->canProvideEmptyScope(clasp)) {
+ if (scope->canProvideEmptyScope(ops, clasp)) {
JSScope *emptyScope = scope->getEmptyScope(cx, clasp);
JS_UNLOCK_SCOPE(cx, scope);
if (!emptyScope)
goto bad;
scope = emptyScope;
} else {
JS_UNLOCK_SCOPE(cx, scope);
scope = NULL;
}
}
if (!scope) {
- scope = JSScope::create(cx, clasp, obj, js_GenerateShape(cx, false));
+ scope = JSScope::create(cx, ops, clasp, obj, js_GenerateShape(cx, false));
if (!scope)
goto bad;
uint32 freeslot = JSSLOT_FREE(clasp);
JS_ASSERT(freeslot >= scope->freeslot);
if (freeslot > JS_INITIAL_NSLOTS && !obj->allocSlots(cx, freeslot))
goto bad;
scope->freeslot = freeslot;
#ifdef DEBUG
@@ -565,17 +565,17 @@ NewNativeClassInstance(JSContext *cx, Cl
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->init(clasp, proto, parent, JSObject::defaultPrivate(clasp));
JS_LOCK_OBJ(cx, proto);
JSScope *scope = proto->scope();
- JS_ASSERT(scope->canProvideEmptyScope(clasp));
+ JS_ASSERT(scope->canProvideEmptyScope(&js_ObjectOps, clasp));
scope = scope->getEmptyScope(cx, clasp);
JS_UNLOCK_OBJ(cx, proto);
if (!scope) {
obj = NULL;
} else {
obj->map = scope;
}
@@ -633,16 +633,21 @@ NewBuiltinClassInstance(JSContext *cx, C
* proto->getParent() if proto is non-null (else to null). NB: only this helper
* and NewObject can be used to construct full-sized JSFunction instances.
*/
static inline JSObject *
NewObjectWithGivenProto(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
{
DTrace::ObjectCreationScope objectCreationScope(cx, cx->fp, clasp);
+ /* Always call the class's getObjectOps hook if it has one. */
+ JSObjectOps *ops = clasp->getObjectOps
+ ? clasp->getObjectOps(cx, clasp)
+ : &js_ObjectOps;
+
/*
* Allocate an object from the GC heap and initialize all its fields before
* doing any operation that can potentially trigger GC. Functions have a
* larger non-standard allocation size.
*/
JSObject* obj;
if (clasp == &js_FunctionClass) {
obj = (JSObject*) js_NewGCFunction(cx);
@@ -662,23 +667,24 @@ NewObjectWithGivenProto(JSContext *cx, C
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->init(clasp,
proto,
(!parent && proto) ? proto->getParent() : parent,
JSObject::defaultPrivate(clasp));
- if (clasp->isNative()) {
- if (!InitScopeForObject(cx, obj, clasp, proto)) {
+ if (ops->isNative()) {
+ if (!InitScopeForObject(cx, obj, clasp, proto, ops)) {
obj = NULL;
goto out;
}
} else {
- obj->map = const_cast<JSObjectMap *>(&JSObjectMap::sharedNonNative);
+ JS_ASSERT(ops->objectMap->ops == ops);
+ obj->map = const_cast<JSObjectMap *>(ops->objectMap);
}
out:
objectCreationScope.handleCreation(obj);
return obj;
}
static inline JSProtoKey
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -94,23 +94,19 @@ struct JSONParser
#ifdef _MSC_VER
#pragma warning(pop)
#endif
Class js_JSONClass = {
js_JSON_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_JSON),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
JSBool
js_json_parse(JSContext *cx, uintN argc, Value *vp)
{
JSString *s = NULL;
Value *argv = vp + 2;
AutoValueRooter reviver(cx);
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -900,57 +900,75 @@ proxy_TraceObject(JSTracer *trc, JSObjec
obj->getProxyHandler()->trace(trc, obj);
MarkValue(trc, obj->getProxyPrivate(), "private");
if (obj->isFunctionProxy()) {
MarkValue(trc, GetCall(obj), "call");
MarkValue(trc, GetConstruct(obj), "construct");
}
}
+static JSType
+proxy_TypeOf_obj(JSContext *cx, JSObject *obj)
+{
+ return JSTYPE_OBJECT;
+}
+
void
proxy_Finalize(JSContext *cx, JSObject *obj)
{
JS_ASSERT(obj->isProxy());
if (!obj->getSlot(JSSLOT_PROXY_HANDLER).isUndefined())
obj->getProxyHandler()->finalize(cx, obj);
}
+extern JSObjectOps js_ObjectProxyObjectOps;
+
+static const JSObjectMap SharedObjectProxyMap(&js_ObjectProxyObjectOps, JSObjectMap::SHAPELESS);
+
+JSObjectOps js_ObjectProxyObjectOps = {
+ &SharedObjectProxyMap,
+ proxy_LookupProperty,
+ proxy_DefineProperty,
+ proxy_GetProperty,
+ proxy_SetProperty,
+ proxy_GetAttributes,
+ proxy_SetAttributes,
+ proxy_DeleteProperty,
+ js_Enumerate,
+ proxy_TypeOf_obj,
+ proxy_TraceObject,
+ NULL, /* thisObject */
+ proxy_Finalize
+};
+
+static JSObjectOps *
+obj_proxy_getObjectOps(JSContext *cx, Class *clasp)
+{
+ return &js_ObjectProxyObjectOps;
+}
+
JS_FRIEND_API(Class) ObjectProxyClass = {
"Proxy",
- Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(2),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
+ JSCLASS_HAS_RESERVED_SLOTS(2),
+ PropertyStub,
+ PropertyStub,
+ PropertyStub,
+ PropertyStub,
EnumerateStub,
ResolveStub,
ConvertStub,
- NULL, /* finalize */
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- NULL, /* mark */
- JS_NULL_CLASS_EXT,
- {
- proxy_LookupProperty,
- proxy_DefineProperty,
- proxy_GetProperty,
- proxy_SetProperty,
- proxy_GetAttributes,
- proxy_SetAttributes,
- proxy_DeleteProperty,
- NULL, /* enumerate */
- NULL, /* typeof */
- proxy_TraceObject,
- NULL, /* thisObject */
- proxy_Finalize, /* clear */
- }
+ NULL,
+ obj_proxy_getObjectOps,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
};
JSBool
proxy_Call(JSContext *cx, uintN argc, Value *vp)
{
JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
JS_ASSERT(proxy->isProxy());
return JSProxy::call(cx, proxy, argc, vp);
@@ -965,51 +983,63 @@ proxy_Construct(JSContext *cx, JSObject
}
static JSType
proxy_TypeOf_fun(JSContext *cx, JSObject *obj)
{
return JSTYPE_FUNCTION;
}
+extern JSObjectOps js_FunctionProxyObjectOps;
+
+static const JSObjectMap SharedFunctionProxyMap(&js_FunctionProxyObjectOps, JSObjectMap::SHAPELESS);
+
#define proxy_HasInstance js_FunctionClass.hasInstance
+JSObjectOps js_FunctionProxyObjectOps = {
+ &SharedFunctionProxyMap,
+ proxy_LookupProperty,
+ proxy_DefineProperty,
+ proxy_GetProperty,
+ proxy_SetProperty,
+ proxy_GetAttributes,
+ proxy_SetAttributes,
+ proxy_DeleteProperty,
+ js_Enumerate,
+ proxy_TypeOf_fun,
+ proxy_TraceObject,
+ NULL, /* thisObject */
+ NULL /* clear */
+};
+
+static JSObjectOps *
+fun_proxy_getObjectOps(JSContext *cx, Class *clasp)
+{
+ return &js_FunctionProxyObjectOps;
+}
+
JS_FRIEND_API(Class) FunctionProxyClass = {
"Proxy",
- Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(4) | Class::CALL_IS_FAST,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
+ JSCLASS_HAS_RESERVED_SLOTS(4) | CLASS_CALL_IS_FAST,
+ PropertyStub,
+ PropertyStub,
+ PropertyStub,
+ PropertyStub,
EnumerateStub,
ResolveStub,
ConvertStub,
- NULL, /* finalize */
- NULL, /* reserved0 */
- NULL, /* checkAccess */
+ NULL,
+ fun_proxy_getObjectOps,
+ NULL,
CastCallOpAsNative(proxy_Call),
proxy_Construct,
- NULL, /* xdrObject */
+ NULL,
proxy_HasInstance,
- NULL, /* mark */
- JS_NULL_CLASS_EXT,
- {
- proxy_LookupProperty,
- proxy_DefineProperty,
- proxy_GetProperty,
- proxy_SetProperty,
- proxy_GetAttributes,
- proxy_SetAttributes,
- proxy_DeleteProperty,
- NULL, /* enumerate */
- proxy_TypeOf_fun,
- proxy_TraceObject,
- NULL, /* thisObject */
- NULL, /* clear */
- }
+ NULL,
+ NULL
};
JS_FRIEND_API(JSObject *)
NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObject *proto,
JSObject *parent, JSObject *call, JSObject *construct)
{
bool fun = call || construct;
Class *clasp = fun ? &FunctionProxyClass : &ObjectProxyClass;
@@ -1208,28 +1238,20 @@ callable_Construct(JSContext *cx, JSObje
return true;
}
return InternalCall(cx, obj, fval, argc, argv, rval);
}
Class CallableObjectClass = {
"Function",
JSCLASS_HAS_RESERVED_SLOTS(2),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- NULL, /* finalize */
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- callable_Call,
- callable_Construct,
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ NULL, NULL, callable_Call, callable_Construct,
+ NULL, NULL, NULL, NULL
};
JS_FRIEND_API(JSBool)
FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
{
AutoValueRooter tvr(cx);
if (!JSProxy::fix(cx, proxy, tvr.addr()))
return false;
@@ -1277,23 +1299,19 @@ FixProxy(JSContext *cx, JSObject *proxy,
return true;
}
}
Class js_ProxyClass = {
"Proxy",
JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
JS_FRIEND_API(JSObject *)
js_InitProxyClass(JSContext *cx, JSObject *obj)
{
JSObject *module = NewObject(cx, &js_ProxyClass, NULL, obj);
if (!module)
return NULL;
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -341,41 +341,20 @@ typedef JSBool
* The type of ops->call. Same argument types as JSFastNative, but a different
* contract. A JSCallOp expects a dummy stack frame with the caller's
* scopeChain.
*/
typedef JSBool
(* JSCallOp)(JSContext *cx, uintN argc, jsval *vp);
/*
- * A generic type for functions mapping an object to another object, or null
- * if an error or exception was thrown on cx.
- */
-typedef JSObject *
-(* JSObjectOp)(JSContext *cx, JSObject *obj);
-
-/*
- * Hook that creates an iterator object for a given object. Returns the
- * iterator object or null if an error or exception was thrown on cx.
- */
-typedef JSObject *
-(* JSIteratorOp)(JSContext *cx, JSObject *obj, JSBool keysonly);
-
-/*
* The following determines whether JS_EncodeCharacters and JS_DecodeBytes
* treat char[] as utf-8 or simply as bytes that need to be inflated/deflated.
*/
#ifdef JS_C_STRINGS_ARE_UTF8
# define js_CStringsAreUTF8 JS_TRUE
#else
extern JSBool js_CStringsAreUTF8;
#endif
-/*
- * Hack to expose obj->getOps()->outer to the C implementation of the debugger
- * interface.
- */
-extern JS_FRIEND_API(JSObject *)
-js_ObjectToOuterObject(JSContext *cx, JSObject *obj);
-
JS_END_EXTERN_C
#endif /* jsprvtd_h___ */
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -102,17 +102,17 @@ typedef enum JSType {
/* Dense index into cached prototypes and class atoms for standard objects. */
typedef enum JSProtoKey {
#define JS_PROTO(name,code,init) JSProto_##name = code,
#include "jsproto.tbl"
#undef JS_PROTO
JSProto_LIMIT
} JSProtoKey;
-/* js_CheckAccess mode enumeration. */
+/* JSObjectOps.checkAccess mode enumeration. */
typedef enum JSAccessMode {
JSACC_PROTO = 0, /* XXXbe redundant w.r.t. id */
JSACC_PARENT = 1, /* XXXbe redundant w.r.t. id */
/*
* enum value #2 formerly called JSACC_IMPORT,
* gap preserved for ABI compatibility.
*/
@@ -140,26 +140,28 @@ typedef enum JSIterateOp {
JSENUMERATE_NEXT,
/* Destroy iterator state. */
JSENUMERATE_DESTROY
} JSIterateOp;
/* Struct typedefs. */
typedef struct JSClass JSClass;
+typedef struct JSExtendedClass JSExtendedClass;
typedef struct JSConstDoubleSpec JSConstDoubleSpec;
typedef struct JSContext JSContext;
typedef struct JSErrorReport JSErrorReport;
typedef struct JSFunction JSFunction;
typedef struct JSFunctionSpec JSFunctionSpec;
typedef struct JSTracer JSTracer;
typedef struct JSIdArray JSIdArray;
typedef struct JSPropertyDescriptor JSPropertyDescriptor;
typedef struct JSPropertySpec JSPropertySpec;
typedef struct JSObjectMap JSObjectMap;
+typedef struct JSObjectOps JSObjectOps;
typedef struct JSRuntime JSRuntime;
typedef struct JSScript JSScript;
typedef struct JSStackFrame JSStackFrame;
typedef struct JSXDRState JSXDRState;
typedef struct JSExceptionState JSExceptionState;
typedef struct JSLocaleCallbacks JSLocaleCallbacks;
typedef struct JSSecurityCallbacks JSSecurityCallbacks;
typedef struct JSONParser JSONParser;
@@ -297,16 +299,39 @@ typedef void
/*
* Used by JS_AddExternalStringFinalizer and JS_RemoveExternalStringFinalizer
* to extend and reduce the set of string types finalized by the GC.
*/
typedef void
(* JSStringFinalizeOp)(JSContext *cx, JSString *str);
/*
+ * The signature for JSClass.getObjectOps, used by JS_NewObject's internals
+ * to discover the set of high-level object operations to use for new objects
+ * of the given class. All native objects have a JSClass, which is stored as
+ * a private (int-tagged) pointer in obj slots. In contrast, all native and
+ * host objects have a JSObjectMap at obj->map, which may be shared among a
+ * number of objects, and which contains the JSObjectOps *ops pointer used to
+ * dispatch object operations from API calls.
+ *
+ * Thus JSClass (which pre-dates JSObjectOps in the API) provides a low-level
+ * interface to class-specific code and data, while JSObjectOps allows for a
+ * higher level of operation, which does not use the object's class except to
+ * find the class's JSObjectOps struct, by calling clasp->getObjectOps, and to
+ * finalize the object.
+ *
+ * If this seems backwards, that's because it is! API compatibility requires
+ * a JSClass *clasp parameter to JS_NewObject, etc. Most host objects do not
+ * need to implement the larger JSObjectOps, and can share the common JSScope
+ * code and data used by the native (js_ObjectOps, see jsobj.c) ops.
+ */
+typedef JSObjectOps *
+(* JSGetObjectOps)(JSContext *cx, JSClass *clasp);
+
+/*
* JSClass.checkAccess type: check whether obj[id] may be accessed per mode,
* returning false on error/exception, true on success with obj[id]'s last-got
* value in *vp, and its attributes in *attrsp. As for JSPropertyOp above, id
* is either a string or an int jsval.
*/
typedef JSBool
(* JSCheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
jsval *vp);
@@ -388,19 +413,36 @@ typedef void
/*
* DEBUG only callback that JSTraceOp implementation can provide to return
* a string describing the reference traced with JS_CallTracer.
*/
typedef void
(* JSTraceNamePrinter)(JSTracer *trc, char *buf, size_t bufsize);
+/* JSExtendedClass function pointer typedefs. */
+
typedef JSBool
(* JSEqualityOp)(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp);
+/*
+ * A generic type for functions mapping an object to another object, or null
+ * if an error or exception was thrown on cx. Used by JSObjectOps.thisObject
+ * at present.
+ */
+typedef JSObject *
+(* JSObjectOp)(JSContext *cx, JSObject *obj);
+
+/*
+ * Hook that creates an iterator object for a given object. Returns the
+ * iterator object or null if an error or exception was thrown on cx.
+ */
+typedef JSObject *
+(* JSIteratorOp)(JSContext *cx, JSObject *obj, JSBool keysonly);
+
/* Typedef for native functions called by the JS VM. */
typedef JSBool
(* JSNative)(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
/* See jsapi.h, the JS_CALLEE, JS_THIS, etc. macros. */
typedef JSBool
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -5412,31 +5412,24 @@ regexp_trace(JSTracer *trc, JSObject *ob
JS_CALL_STRING_TRACER(trc, re->source, "source");
}
Class js_RegExpClass = {
js_RegExp_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::REGEXP_FIXED_RESERVED_SLOTS) |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- regexp_enumerate,
- reinterpret_cast<JSResolveOp>(regexp_resolve),
- ConvertStub,
- regexp_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- regexp_call,
- NULL, /* construct */
- js_XDRRegExpObject,
- NULL, /* hasInstance */
- JS_CLASS_TRACE(regexp_trace)
+ PropertyStub, PropertyStub,
+ PropertyStub, PropertyStub,
+ regexp_enumerate, reinterpret_cast<JSResolveOp>(regexp_resolve),
+ ConvertStub, regexp_finalize,
+ NULL, NULL,
+ regexp_call, NULL,
+ js_XDRRegExpObject, NULL,
+ JS_CLASS_TRACE(regexp_trace), 0
};
static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0};
JSBool
js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
{
JSRegExp *re;
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -94,17 +94,17 @@ js_GenerateShape(JSContext *cx, bool gcL
JSScope *
js_GetMutableScope(JSContext *cx, JSObject *obj)
{
JSScope *scope = obj->scope();
JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
if (!scope->isSharedEmpty())
return scope;
- JSScope *newscope = JSScope::create(cx, obj->getClass(), obj, scope->shape);
+ JSScope *newscope = JSScope::create(cx, scope->ops, obj->getClass(), obj, scope->shape);
if (!newscope)
return NULL;
/* The newly allocated scope is single-threaded and, as such, is locked. */
JS_ASSERT(CX_OWNS_SCOPE_TITLE(cx, newscope));
JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, newscope));
obj->map = newscope;
@@ -206,38 +206,41 @@ JSScope::createTable(JSContext *cx, bool
for (sprop = lastProp; sprop; sprop = sprop->parent) {
spp = search(sprop->id, true);
SPROP_STORE_PRESERVING_COLLISION(spp, sprop);
}
return true;
}
JSScope *
-JSScope::create(JSContext *cx, Class *clasp, JSObject *obj, uint32 shape)
+JSScope::create(JSContext *cx, const JSObjectOps *ops, Class *clasp,
+ JSObject *obj, uint32 shape)
{
+ JS_ASSERT(ops->isNative());
JS_ASSERT(obj);
- JSScope *scope = cx->create<JSScope>(obj);
+ JSScope *scope = cx->create<JSScope>(ops, obj);
if (!scope)
return NULL;
scope->freeslot = JSSLOT_START(clasp);
scope->flags = cx->runtime->gcRegenShapesScopeFlag;
scope->initMinimal(cx, shape);
#ifdef JS_THREADSAFE
js_InitTitle(cx, &scope->title);
#endif
JS_RUNTIME_METER(cx->runtime, liveScopes);
JS_RUNTIME_METER(cx->runtime, totalScopes);
return scope;
}
-JSEmptyScope::JSEmptyScope(JSContext *cx, Class *clasp)
- : JSScope(NULL), clasp(clasp)
+JSEmptyScope::JSEmptyScope(JSContext *cx, const JSObjectOps *ops,
+ Class *clasp)
+ : JSScope(ops, NULL), clasp(clasp)
{
/*
* This scope holds a reference to the new empty scope. Our only caller,
* getEmptyScope, also promises to incref on behalf of its caller.
*/
nrefs = 2;
freeslot = JSSLOT_START(clasp);
flags = OWN_SHAPE | cx->runtime->gcRegenShapesScopeFlag;
@@ -282,24 +285,24 @@ JSScope::destroy(JSContext *cx)
bool
JSScope::initRuntimeState(JSContext *cx)
{
JSRuntime *rt = cx->runtime;
#define SCOPE(Name) rt->empty##Name##Scope
#define CLASP(Name) &js_##Name##Class
-#define INIT_EMPTY_SCOPE(Name,NAME) \
- INIT_EMPTY_SCOPE_WITH_CLASS(Name, NAME, CLASP(Name))
+#define INIT_EMPTY_SCOPE(Name,NAME,ops) \
+ INIT_EMPTY_SCOPE_WITH_CLASS(Name, NAME, ops, CLASP(Name))
-#define INIT_EMPTY_SCOPE_WITH_CLASS(Name,NAME,clasp) \
- INIT_EMPTY_SCOPE_WITH_FREESLOT(Name, NAME, clasp, JSSLOT_FREE(clasp))
+#define INIT_EMPTY_SCOPE_WITH_CLASS(Name,NAME,ops,clasp) \
+ INIT_EMPTY_SCOPE_WITH_FREESLOT(Name, NAME, ops, clasp, JSSLOT_FREE(clasp))
-#define INIT_EMPTY_SCOPE_WITH_FREESLOT(Name,NAME,clasp,slot) \
- SCOPE(Name) = cx->create<JSEmptyScope>(cx, clasp); \
+#define INIT_EMPTY_SCOPE_WITH_FREESLOT(Name,NAME,ops,clasp,slot) \
+ SCOPE(Name) = cx->create<JSEmptyScope>(cx, ops, clasp); \
if (!SCOPE(Name)) \
return false; \
JS_ASSERT(SCOPE(Name)->shape == JSScope::EMPTY_##NAME##_SHAPE); \
JS_ASSERT(SCOPE(Name)->nrefs == 2); \
SCOPE(Name)->nrefs = 1; \
SCOPE(Name)->freeslot = slot
/*
@@ -315,39 +318,39 @@ JSScope::initRuntimeState(JSContext *cx)
* is less than freeslot to succeed. As the shared emptyArgumentsScope is
* never mutated, it's safe to pretend to have all the slots possible.
*
* Note how the fast paths in jsinterp.cpp for JSOP_LENGTH and JSOP_GETELEM
* bypass resolution of scope properties for length and element indices on
* arguments objects. This helps ensure that any arguments object needing
* its own mutable scope (with unique shape) is a rare event.
*/
- INIT_EMPTY_SCOPE_WITH_FREESLOT(Arguments, ARGUMENTS, CLASP(Arguments),
+ INIT_EMPTY_SCOPE_WITH_FREESLOT(Arguments, ARGUMENTS, &js_ObjectOps, CLASP(Arguments),
JS_INITIAL_NSLOTS + JS_ARGS_LENGTH_MAX);
- INIT_EMPTY_SCOPE(Block, BLOCK);
+ INIT_EMPTY_SCOPE(Block, BLOCK, &js_ObjectOps);
/*
* Initialize the shared scope for all empty Call objects so gets for args
* and vars do not force the creation of a mutable scope for the particular
* call object being accessed.
*
* See comment above for rt->emptyArgumentsScope->freeslot initialization.
*/
- INIT_EMPTY_SCOPE_WITH_FREESLOT(Call, CALL, CLASP(Call),
+ INIT_EMPTY_SCOPE_WITH_FREESLOT(Call, CALL, &js_ObjectOps, CLASP(Call),
JS_INITIAL_NSLOTS + JSFunction::MAX_ARGS_AND_VARS);
/* A DeclEnv object holds the name binding for a named function expression. */
- INIT_EMPTY_SCOPE(DeclEnv, DECL_ENV);
+ INIT_EMPTY_SCOPE(DeclEnv, DECL_ENV, &js_ObjectOps);
/* Non-escaping native enumerator objects share this empty scope. */
- INIT_EMPTY_SCOPE_WITH_CLASS(Enumerator, ENUMERATOR, &js_IteratorClass);
+ INIT_EMPTY_SCOPE_WITH_CLASS(Enumerator, ENUMERATOR, &js_ObjectOps, &js_IteratorClass.base);
/* Same drill for With objects. */
- INIT_EMPTY_SCOPE_WITH_CLASS(With, WITH, &js_WithClass);
+ INIT_EMPTY_SCOPE(With, WITH, &js_WithObjectOps);
#undef SCOPE
#undef CLASP
#undef INIT_EMPTY_SCOPE
#undef INIT_EMPTY_SCOPE_WITH_CLASS
#undef INIT_EMPTY_SCOPE_WITH_FREESLOT
return true;
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -289,36 +289,37 @@ struct JSScope : public JSObjectMap
JSScopeProperty *addPropertyHelper(JSContext *cx, jsid id,
js::PropertyOp getter, js::PropertyOp setter,
uint32 slot, uintN attrs,
uintN flags, intN shortid,
JSScopeProperty **spp);
public:
- JSScope(JSObject *obj)
- : JSObjectMap(0), object(obj) {}
+ JSScope(const JSObjectOps *ops, JSObject *obj)
+ : JSObjectMap(ops, 0), object(obj) {}
/* Create a mutable, owned, empty scope. */
- static JSScope *create(JSContext *cx, js::Class *clasp, JSObject *obj, uint32 shape);
+ static JSScope *create(JSContext *cx, const JSObjectOps *ops,
+ js::Class *clasp, JSObject *obj, uint32 shape);
void destroy(JSContext *cx);
/*
* Return an immutable, shareable, empty scope with the same ops as this
* and the same freeslot as this had when empty.
*
* If |this| is the scope of an object |proto|, the resulting scope can be
* used as the scope of a new object whose prototype is |proto|.
*/
inline JSEmptyScope *getEmptyScope(JSContext *cx, js::Class *clasp);
inline bool ensureEmptyScope(JSContext *cx, js::Class *clasp);
- inline bool canProvideEmptyScope(js::Class *clasp);
+ inline bool canProvideEmptyScope(JSObjectOps *ops, js::Class *clasp);
JSScopeProperty *lookup(jsid id);
inline bool hasProperty(jsid id) { return lookup(id) != NULL; }
inline bool hasProperty(JSScopeProperty *sprop);
/* Add a property whose id is not yet in this scope. */
JSScopeProperty *addProperty(JSContext *cx, jsid id,
@@ -522,17 +523,17 @@ struct JSScope : public JSObjectMap
};
};
struct JSEmptyScope : public JSScope
{
js::Class * const clasp;
jsrefcount nrefs; /* count of all referencing objects */
- JSEmptyScope(JSContext *cx, js::Class *clasp);
+ JSEmptyScope(JSContext *cx, const JSObjectOps *ops, js::Class *clasp);
JSEmptyScope *hold() {
/* The method is only called for already held objects. */
JS_ASSERT(nrefs >= 1);
JS_ATOMIC_INCREMENT(&nrefs);
return this;
}
@@ -954,25 +955,25 @@ JSScope::search(jsid id, bool adding)
return spp;
}
return searchTable(id, adding);
}
#undef METER
inline bool
-JSScope::canProvideEmptyScope(js::Class *clasp)
+JSScope::canProvideEmptyScope(JSObjectOps *ops, js::Class *clasp)
{
/*
* An empty scope cannot provide another empty scope, or wrongful two-level
* prototype shape sharing ensues -- see bug 497789.
*/
if (!object)
return false;
- return !emptyScope || emptyScope->clasp == clasp;
+ return this->ops == ops && (!emptyScope || emptyScope->clasp == clasp);
}
inline bool
JSScopeProperty::isSharedPermanent() const
{
return (~attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0;
}
--- a/js/src/jsscopeinlines.h
+++ b/js/src/jsscopeinlines.h
@@ -48,17 +48,17 @@
#include "jscntxtinlines.h"
inline JSEmptyScope *
JSScope::createEmptyScope(JSContext *cx, js::Class *clasp)
{
JS_ASSERT(!isSharedEmpty());
JS_ASSERT(!emptyScope);
- emptyScope = cx->create<JSEmptyScope>(cx, clasp);
+ emptyScope = cx->create<JSEmptyScope>(cx, ops, clasp);
return emptyScope;
}
inline JSEmptyScope *
JSScope::getEmptyScope(JSContext *cx, js::Class *clasp)
{
if (emptyScope) {
JS_ASSERT(clasp == emptyScope->clasp);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -408,31 +408,20 @@ script_trace(JSTracer *trc, JSObject *ob
if (script)
js_TraceScript(trc, script);
}
Class js_ScriptClass = {
"Script",
JSCLASS_HAS_PRIVATE |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- script_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- JS_CLASS_TRACE(script_trace)
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, script_finalize,
+ NULL, NULL, NULL, NULL,/*XXXbe xdr*/
+ NULL, NULL, JS_CLASS_TRACE(script_trace), NULL
};
/*
* Shared script filename management.
*/
static int
js_compare_strings(const void *k1, const void *k2)
{
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -801,23 +801,19 @@ str_resolve(JSContext *cx, JSObject *obj
}
return JS_TRUE;
}
Class js_StringClass = {
js_String_str,
JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE |
JSCLASS_HAS_CACHED_PROTO(JSProto_String),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- str_getProperty,
- PropertyStub, /* setProperty */
- str_enumerate,
- (JSResolveOp)str_resolve,
- ConvertStub
+ PropertyStub, PropertyStub, str_getProperty, PropertyStub,
+ str_enumerate, (JSResolveOp)str_resolve, ConvertStub, NULL,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
#define NORMALIZE_THIS(cx,vp,str) \
JS_BEGIN_MACRO \
if (vp[1].isString()) { \
str = vp[1].toString(); \
} else { \
str = NormalizeThis(cx, vp); \
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -2906,17 +2906,17 @@ NativeToValue(JSContext* cx, Value& v, J
}
case JSVAL_TYPE_STRORNULL:
debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)v.toString());
break;
case JSVAL_TYPE_OBJORNULL:
debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)&v.toObject());
break;
case JSVAL_TYPE_BOXED:
- debug_only_printf(LC_TMTracer, "box<%llx> ", (unsigned long long)v.asRawBits());
+ debug_only_printf(LC_TMTracer, "box<%llx> ", v.asRawBits());
break;
default:
JS_NOT_REACHED("unexpected type");
break;
}
#endif
}
@@ -8967,17 +8967,18 @@ TraceRecorder::equalityHelper(Value& l,
*/
if (getPromotedType(l) == getPromotedType(r)) {
if (l.isUndefined() || l.isNull()) {
cond = true;
if (l.isNull())
op = LIR_eqp;
} else if (l.isObject()) {
- if (l.toObject().getClass()->ext.equality)
+ Class *clasp = l.toObject().getClass();
+ if ((clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*) clasp)->equality)
RETURN_STOP_A("Can't trace extended class equality operator");
op = LIR_eqp;
cond = (l == r);
} else if (l.isBoolean()) {
JS_ASSERT(r.isBoolean());
cond = (l == r);
} else if (l.isString()) {
args[0] = r_ins, args[1] = l_ins;
@@ -9377,16 +9378,18 @@ void
TraceRecorder::forgetGuardedShapes()
{
#if defined DEBUG_notme && defined XP_UNIX
dumpGuardedShapes("forget-all");
#endif
guardedShapeTable.clear();
}
+JS_STATIC_ASSERT(offsetof(JSObjectOps, objectMap) == 0);
+
inline LIns*
TraceRecorder::map(LIns* obj_ins)
{
return addName(lir->insLoad(LIR_ldp, obj_ins, (int) offsetof(JSObject, map), ACCSET_OTHER), "map");
}
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, PCVal& pcval)
@@ -11377,17 +11380,17 @@ TraceRecorder::callNative(uintN argc, JS
JS_ASSERT(((jsuword) clasp & 3) == 0);
// Abort on |new Function|. js_NewInstance would allocate a regular-
// sized JSObject, not a Function-sized one. (The Function ctor would
// deep-bail anyway but let's not go there.)
if (clasp == &js_FunctionClass)
RETURN_STOP("new Function");
- if (!clasp->isNative())
+ if (clasp->getObjectOps)
RETURN_STOP("new with non-native ops");
args[0] = INS_CONSTOBJ(funobj);
args[1] = INS_CONSTPTR(clasp);
args[2] = cx_ins;
newobj_ins = lir->insCall(&js_NewInstance_ci, args);
guard(false, lir->insEqP_0(newobj_ins), OOM_EXIT);
this_ins = newobj_ins;
@@ -11805,17 +11808,17 @@ TraceRecorder::record_JSOP_GETPROP()
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_SETPROP()
{
Value& l = stackval(-2);
if (l.isPrimitive())
RETURN_STOP_A("primitive this for SETPROP");
JSObject* obj = &l.toObject();
- if (obj->getOps()->setProperty)
+ if (obj->map->ops->setProperty != js_SetProperty)
RETURN_STOP_A("non-native JSObjectOps::setProperty");
return ARECORD_CONTINUE;
}
/* Emit a specialized, inlined copy of js_NativeSet. */
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop,
const Value &v, LIns* v_ins)
@@ -13508,17 +13511,17 @@ TraceRecorder::prop(JSObject* obj, LIns*
{
/*
* Insist that obj have js_SetProperty as its set object-op. This suffices
* to prevent a rogue obj from being used on-trace (loaded via obj_ins),
* because we will guard on shape (or else global object identity) and any
* object not having the same op must have a different class, and therefore
* must differ in its shape (or not be the global object).
*/
- if (!obj->isDenseArray() && obj->getOps()->getProperty)
+ if (!obj->isDenseArray() && obj->map->ops->getProperty != js_GetProperty)
RETURN_STOP_A("non-dense-array, non-native JSObjectOps::getProperty");
JS_ASSERT((slotp && v_insp && !outp) || (!slotp && !v_insp && outp));
/*
* Property cache ensures that we are dealing with an existing property,
* and guards the shape for us.
*/
@@ -14191,34 +14194,34 @@ TraceRecorder::record_JSOP_MOREITER()
RETURN_IF_XML_A(iterobj_val);
JSObject* iterobj = &iterobj_val.toObject();
LIns* iterobj_ins = get(&iterobj_val);
bool cond;
LIns* cond_ins;
/* JSOP_FOR* already guards on this, but in certain rare cases we might record misformed loop traces. */
- if (iterobj->hasClass(&js_IteratorClass)) {
- guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+ if (iterobj->hasClass(&js_IteratorClass.base)) {
+ guardClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), LOAD_NORMAL);
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
void *cursor = ni->props_cursor;
void *end = ni->props_end;
LIns *ni_ins = stobj_get_const_private_ptr(iterobj_ins);
LIns *cursor_ins =
addName(lir->insLoad(LIR_ldp, ni_ins,
offsetof(NativeIterator, props_cursor), ACCSET_OTHER), "cursor");
LIns *end_ins = addName(lir->insLoad(LIR_ldp, ni_ins, offsetof(NativeIterator, props_end),
ACCSET_OTHER), "end");
/* Figure out whether the native iterator contains more values. */
cond = cursor < end;
cond_ins = lir->ins2(LIR_ltp, cursor_ins, end_ins);
} else {
- guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+ guardNotClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), LOAD_NORMAL);
enterDeepBailCall();
LIns* vp_ins = lir->insAlloc(sizeof(Value));
LIns* args[] = { vp_ins, iterobj_ins, cx_ins };
LIns* ok_ins = lir->insCall(&IteratorMore_ci, args);
/*
@@ -14306,18 +14309,18 @@ TraceRecorder::storeMagic(JSWhyMagic why
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::unboxNextValue(LIns* &v_ins)
{
Value &iterobj_val = stackval(-1);
JSObject *iterobj = &iterobj_val.toObject();
LIns* iterobj_ins = get(&iterobj_val);
- if (iterobj->hasClass(&js_IteratorClass)) {
- guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+ if (iterobj->hasClass(&js_IteratorClass.base)) {
+ guardClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), LOAD_NORMAL);
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
LIns *ni_ins = stobj_get_const_private_ptr(iterobj_ins);
LIns *cursor_ins = addName(lir->insLoad(LIR_ldp, ni_ins, offsetof(NativeIterator, props_cursor), ACCSET_OTHER), "cursor");
/* Emit code to stringify the id if necessary. */
if (!(((NativeIterator *) iterobj->getPrivate())->flags & JSITER_FOREACH)) {
/* Read the next id from the iterator. */
@@ -14347,20 +14350,19 @@ TraceRecorder::unboxNextValue(LIns* &v_i
/* Read the next value from the iterator. */
Value v = *ni->currentValue();
v_ins = unbox_value(v, cursor_ins, 0, snapshot(BRANCH_EXIT));
/* Increment the cursor by one Value and store it back. */
cursor_ins = lir->ins2(LIR_addp, cursor_ins, INS_CONSTWORD(sizeof(Value)));
}
- lir->insStore(LIR_stp, cursor_ins, ni_ins, offsetof(NativeIterator, props_cursor),
- ACCSET_OTHER);
- } else {
- guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+ lir->insStore(LIR_stp, cursor_ins, ni_ins, offsetof(NativeIterator, props_cursor), ACCSET_OTHER);
+ } else {
+ guardNotClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), LOAD_NORMAL);
v_ins = unbox_value(cx->iterValue, cx_ins, offsetof(JSContext, iterValue),
snapshot(BRANCH_EXIT));
storeMagic(JS_NO_ITER_VALUE, cx_ins, offsetof(JSContext, iterValue), ACCSET_OTHER);
}
return ARECORD_CONTINUE;
}
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -488,28 +488,36 @@ class TypedArrayTemplate
: public TypedArray
{
public:
typedef TypedArrayTemplate<NativeType> ThisTypeArray;
static const int ArrayTypeID() { return TypeIDOfType<NativeType>(); }
static const bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
static const bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
+ static JSObjectOps fastObjectOps;
+ static JSObjectMap fastObjectMap;
+
static JSFunctionSpec jsfuncs[];
static inline Class *slowClass()
{
return &TypedArray::slowClasses[ArrayTypeID()];
}
static inline Class *fastClass()
{
return &TypedArray::fastClasses[ArrayTypeID()];
}
+ static JSObjectOps *getObjectOps(JSContext *cx, Class *clasp)
+ {
+ return &fastObjectOps;
+ }
+
static JSBool
obj_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
JS_ASSERT(tarray);
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
vp->setNumber(tarray->length);
@@ -913,17 +921,17 @@ class TypedArrayTemplate
// helper used by both the constructor and Slice()
static void
makeFastWithPrivate(JSContext *cx, JSObject *obj, ThisTypeArray *tarray)
{
JS_ASSERT(obj->getClass() == slowClass());
obj->setPrivate(tarray);
obj->clasp = fastClass();
- obj->map = const_cast<JSObjectMap *>(&JSObjectMap::sharedNonNative);
+ obj->map = &fastObjectMap;
}
public:
TypedArrayTemplate() { }
bool
init(JSContext *cx, uint32 len)
{
@@ -1251,24 +1259,19 @@ TypedArrayTemplate<double>::copyIndexToV
/*
* ArrayBuffer (base)
*/
Class ArrayBuffer::jsclass = {
"ArrayBuffer",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- ArrayBuffer::class_finalize,
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, ArrayBuffer::class_finalize,
+ JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec ArrayBuffer::jsprops[] = {
{ "byteLength",
-1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
Jsvalify(ArrayBuffer::prop_getByteLength), Jsvalify(ArrayBuffer::prop_getByteLength) },
{0,0,0,0,0}
};
@@ -1293,69 +1296,56 @@ JSPropertySpec TypedArray::jsprops[] = {
{0,0,0,0,0}
};
/*
* TypedArray boilerplate
*/
#define IMPL_TYPED_ARRAY_STATICS(_typedArray) \
+template<> JSObjectMap _typedArray::fastObjectMap(&_typedArray::fastObjectOps, \
+ JSObjectMap::SHAPELESS); \
+template<> JSObjectOps _typedArray::fastObjectOps = { \
+ &_typedArray::fastObjectMap, \
+ _typedArray::obj_lookupProperty, \
+ _typedArray::obj_defineProperty, \
+ _typedArray::obj_getProperty, \
+ _typedArray::obj_setProperty, \
+ _typedArray::obj_getAttributes, \
+ _typedArray::obj_setAttributes, \
+ _typedArray::obj_deleteProperty, \
+ _typedArray::obj_enumerate, \
+ _typedArray::obj_typeOf, \
+ _typedArray::obj_trace, \
+ NULL, /* thisObject */ \
+ NULL /* clear */ \
+}; \
template<> JSFunctionSpec _typedArray::jsfuncs[] = { \
JS_FN("slice", _typedArray::fun_slice, 2, 0), \
JS_FS_END \
}
#define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray) \
{ \
#_typedArray, \
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \
- PropertyStub, /* addProperty */ \
- PropertyStub, /* delProperty */ \
- PropertyStub, /* getProperty */ \
- PropertyStub, /* setProperty */ \
- EnumerateStub, \
- ResolveStub, \
- ConvertStub, \
- FinalizeStub \
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub, \
+ EnumerateStub, ResolveStub, ConvertStub, FinalizeStub, \
+ JSCLASS_NO_OPTIONAL_MEMBERS \
}
#define IMPL_TYPED_ARRAY_FAST_CLASS(_typedArray) \
{ \
#_typedArray, \
- Class::NON_NATIVE | JSCLASS_HAS_PRIVATE, \
- PropertyStub, /* addProperty */ \
- PropertyStub, /* delProperty */ \
- PropertyStub, /* getProperty */ \
- PropertyStub, /* setProperty */ \
- EnumerateStub, \
- ResolveStub, \
- ConvertStub, \
+ JSCLASS_HAS_PRIVATE, \
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub, \
+ EnumerateStub, ResolveStub, ConvertStub, \
_typedArray::class_finalize, \
- NULL, /* reserved0 */ \
- NULL, /* checkAccess */ \
- NULL, /* call */ \
- NULL, /* construct */ \
- NULL, /* xdrObject */ \
- NULL, /* hasInstance */ \
- NULL, /* mark */ \
- JS_NULL_CLASS_EXT, \
- { \
- _typedArray::obj_lookupProperty, \
- _typedArray::obj_defineProperty, \
- _typedArray::obj_getProperty, \
- _typedArray::obj_setProperty, \
- _typedArray::obj_getAttributes, \
- _typedArray::obj_setAttributes, \
- _typedArray::obj_deleteProperty, \
- _typedArray::obj_enumerate, \
- _typedArray::obj_typeOf, \
- _typedArray::obj_trace, \
- NULL, /* thisObject */ \
- NULL, /* clear */ \
- } \
+ _typedArray::getObjectOps, NULL, NULL, NULL, \
+ NULL, NULL, NULL, NULL \
}
#define INIT_TYPED_ARRAY_CLASS(_typedArray,_type) \
do { \
proto = js_InitClass(cx, obj, NULL, \
&TypedArray::slowClasses[TypedArray::_type], \
_typedArray::class_constructor, 3, \
_typedArray::jsprops, \
--- a/js/src/jsvalue.h
+++ b/js/src/jsvalue.h
@@ -774,16 +774,18 @@ typedef JSBool
typedef JSBool
(* NewEnumerateOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
Value *statep, jsid *idp);
typedef JSBool
(* HasInstanceOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
typedef JSBool
(* CheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
Value *vp);
+typedef JSObjectOps *
+(* GetObjectOps)(JSContext *cx, Class *clasp);
typedef JSBool
(* EqualityOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
typedef JSBool
(* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value,
PropertyOp getter, PropertyOp setter, uintN attrs);
typedef JSBool
(* PropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp);
typedef JSBool
@@ -798,135 +800,101 @@ static inline JSPropertyOp Jsvalify
static inline ConvertOp Valueify(JSConvertOp f) { return (ConvertOp)f; }
static inline JSConvertOp Jsvalify(ConvertOp f) { return (JSConvertOp)f; }
static inline NewEnumerateOp Valueify(JSNewEnumerateOp f) { return (NewEnumerateOp)f; }
static inline JSNewEnumerateOp Jsvalify(NewEnumerateOp f) { return (JSNewEnumerateOp)f; }
static inline HasInstanceOp Valueify(JSHasInstanceOp f) { return (HasInstanceOp)f; }
static inline JSHasInstanceOp Jsvalify(HasInstanceOp f) { return (JSHasInstanceOp)f; }
static inline CheckAccessOp Valueify(JSCheckAccessOp f) { return (CheckAccessOp)f; }
static inline JSCheckAccessOp Jsvalify(CheckAccessOp f) { return (JSCheckAccessOp)f; }
+static inline GetObjectOps Valueify(JSGetObjectOps f) { return (GetObjectOps)f; }
+static inline JSGetObjectOps Jsvalify(GetObjectOps f) { return (JSGetObjectOps)f; }
static inline EqualityOp Valueify(JSEqualityOp f); /* Same type as JSHasInstanceOp */
static inline JSEqualityOp Jsvalify(EqualityOp f); /* Same type as HasInstanceOp */
static inline DefinePropOp Valueify(JSDefinePropOp f) { return (DefinePropOp)f; }
static inline JSDefinePropOp Jsvalify(DefinePropOp f) { return (JSDefinePropOp)f; }
static inline PropertyIdOp Valueify(JSPropertyIdOp f); /* Same type as JSPropertyOp */
static inline JSPropertyIdOp Jsvalify(PropertyIdOp f); /* Same type as PropertyOp */
static inline CallOp Valueify(JSCallOp f); /* Same type as JSFastNative */
static inline JSCallOp Jsvalify(CallOp f); /* Same type as FastNative */
static const PropertyOp PropertyStub = (PropertyOp)JS_PropertyStub;
static const JSEnumerateOp EnumerateStub = JS_EnumerateStub;
static const JSResolveOp ResolveStub = JS_ResolveStub;
static const ConvertOp ConvertStub = (ConvertOp)JS_ConvertStub;
static const JSFinalizeOp FinalizeStub = JS_FinalizeStub;
-#define JS_CLASS_MEMBERS \
- const char *name; \
- uint32 flags; \
- \
- /* Mandatory non-null function pointer members. */ \
- PropertyOp addProperty; \
- PropertyOp delProperty; \
- PropertyOp getProperty; \
- PropertyOp setProperty; \
- JSEnumerateOp enumerate; \
- JSResolveOp resolve; \
- ConvertOp convert; \
- JSFinalizeOp finalize; \
- \
- /* Optionally non-null members start here. */ \
- JSClassInternal reserved0; \
- CheckAccessOp checkAccess; \
- Native call; \
- Native construct; \
- JSXDRObjectOp xdrObject; \
- HasInstanceOp hasInstance; \
- JSMarkOp mark
-
-
-/*
- * The helper struct to measure the size of JS_CLASS_MEMBERS to know how much
- * we have to padd js::Class to match the size of JSClass;
- */
-struct ClassSizeMeasurement {
- JS_CLASS_MEMBERS;
-};
-
-struct ClassExtension {
- EqualityOp equality;
- JSObjectOp outerObject;
- JSObjectOp innerObject;
- JSIteratorOp iteratorObject;
- JSObjectOp wrappedObject; /* NB: infallible, null returns are
- treated as the original object */
-};
-
-#define JS_NULL_CLASS_EXT {NULL,NULL,NULL,NULL,NULL}
+struct Class {
+ const char *name;
+ uint32 flags;
-struct ObjectOps {
- JSLookupPropOp lookupProperty;
- js::DefinePropOp defineProperty;
- js::PropertyIdOp getProperty;
- js::PropertyIdOp setProperty;
- JSAttributesOp getAttributes;
- JSAttributesOp setAttributes;
- js::PropertyIdOp deleteProperty;
- js::NewEnumerateOp enumerate;
- JSTypeOfOp typeOf;
- JSTraceOp trace;
- JSObjectOp thisObject;
- JSFinalizeOp clear;
-};
-
-#define JS_NULL_OBJECT_OPS {NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL}
+ /* Mandatory non-null function pointer members. */
+ PropertyOp addProperty;
+ PropertyOp delProperty;
+ PropertyOp getProperty;
+ PropertyOp setProperty;
+ JSEnumerateOp enumerate;
+ JSResolveOp resolve;
+ ConvertOp convert;
+ JSFinalizeOp finalize;
-struct Class {
- JS_CLASS_MEMBERS;
- ClassExtension ext;
- ObjectOps ops;
- uint8 pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) -
- sizeof(ClassExtension) - sizeof(ObjectOps)];
-
- /* Flag indicating that Class::call is a fast native. */
- static const uint32 CALL_IS_FAST = JSCLASS_INTERNAL_FLAG1;
-
- /* Class is not native and its map is not a scope. */
- static const uint32 NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
-
- bool isNative() const {
- return !(flags & NON_NATIVE);
- }
+ /* Optionally non-null members start here. */
+ GetObjectOps getObjectOps;
+ CheckAccessOp checkAccess;
+ Native call;
+ Native construct;
+ JSXDRObjectOp xdrObject;
+ HasInstanceOp hasInstance;
+ JSMarkOp mark;
+ void (*reserved0)(void);
};
-
-/* Helper to initialize Class::call when Class::CALL_IS_FAST. */
-inline Native
-CastCallOpAsNative(CallOp op)
-{
- return reinterpret_cast<Native>(op);
-}
-
JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name));
JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags));
JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty));
JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty));
JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty));
JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty));
JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate));
JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve));
JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert));
JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize));
-JS_STATIC_ASSERT(offsetof(JSClass, reserved0) == offsetof(Class, reserved0));
+JS_STATIC_ASSERT(offsetof(JSClass, getObjectOps) == offsetof(Class, getObjectOps));
JS_STATIC_ASSERT(offsetof(JSClass, checkAccess) == offsetof(Class, checkAccess));
JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call));
JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct));
JS_STATIC_ASSERT(offsetof(JSClass, xdrObject) == offsetof(Class, xdrObject));
JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance));
JS_STATIC_ASSERT(offsetof(JSClass, mark) == offsetof(Class, mark));
+JS_STATIC_ASSERT(offsetof(JSClass, reserved0) == offsetof(Class, reserved0));
JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class));
+struct ExtendedClass {
+ Class base;
+ EqualityOp equality;
+ JSObjectOp outerObject;
+ JSObjectOp innerObject;
+ JSIteratorOp iteratorObject;
+ JSObjectOp wrappedObject; /* NB: infallible, null
+ returns are treated as
+ the original object */
+ void (*reserved0)(void);
+ void (*reserved1)(void);
+ void (*reserved2)(void);
+};
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, base) == offsetof(ExtendedClass, base));
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, equality) == offsetof(ExtendedClass, equality));
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, outerObject) == offsetof(ExtendedClass, outerObject));
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, innerObject) == offsetof(ExtendedClass, innerObject));
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, iteratorObject) == offsetof(ExtendedClass, iteratorObject));
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, wrappedObject) == offsetof(ExtendedClass, wrappedObject));
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved0) == offsetof(ExtendedClass, reserved0));
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved1) == offsetof(ExtendedClass, reserved1));
+JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved2) == offsetof(ExtendedClass, reserved2));
+JS_STATIC_ASSERT(sizeof(JSExtendedClass) == sizeof(ExtendedClass));
+
struct PropertyDescriptor {
JSObject *obj;
uintN attrs;
PropertyOp getter;
PropertyOp setter;
Value value;
uintN shortid;
};
@@ -935,16 +903,18 @@ JS_STATIC_ASSERT(offsetof(JSPropertyDesc
JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, getter) == offsetof(PropertyDescriptor, getter));
JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, setter) == offsetof(PropertyDescriptor, setter));
JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, value) == offsetof(PropertyDescriptor, value));
JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, shortid) == offsetof(PropertyDescriptor, shortid));
JS_STATIC_ASSERT(sizeof(JSPropertyDescriptor) == sizeof(PropertyDescriptor));
static JS_ALWAYS_INLINE JSClass * Jsvalify(Class *c) { return (JSClass *)c; }
static JS_ALWAYS_INLINE Class * Valueify(JSClass *c) { return (Class *)c; }
+static JS_ALWAYS_INLINE JSExtendedClass * Jsvalify(ExtendedClass *c) { return (JSExtendedClass *)c; }
+static JS_ALWAYS_INLINE ExtendedClass * Valueify(JSExtendedClass *c) { return (ExtendedClass *)c; }
static JS_ALWAYS_INLINE JSPropertyDescriptor * Jsvalify(PropertyDescriptor *p) { return (JSPropertyDescriptor *) p; }
static JS_ALWAYS_INLINE PropertyDescriptor * Valueify(JSPropertyDescriptor *p) { return (PropertyDescriptor *) p; }
/******************************************************************************/
/*
* In some cases (quickstubs) we want to take a value in whatever manner is
* appropriate for the architecture and normalize to a const js::Value &. On
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -679,17 +679,17 @@ JSCrossCompartmentWrapper::enumerateOwn(
* We can reify non-escaping iterator objects instead of having to wrap them. This
* allows fast iteration over objects across a compartment boundary.
*/
static bool
CanReify(Value *vp)
{
JSObject *obj;
return vp->isObject() &&
- (obj = &vp->toObject())->getClass() == &js_IteratorClass &&
+ (obj = &vp->toObject())->getClass() == &js_IteratorClass.base &&
(obj->getNativeIterator()->flags & JSITER_ENUMERATE);
}
static bool
Reify(JSContext *cx, JSCompartment *origin, Value *vp)
{
JSObject *iterObj = &vp->toObject();
NativeIterator *ni = iterObj->getNativeIterator();
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -185,17 +185,17 @@ GetLocalName(const JSObject *obj)
return JSVAL_TO_STRING(v);
}
static JSBool
IsDeclared(const JSObject *obj)
{
jsval v;
- JS_ASSERT(obj->getClass() == &js_NamespaceClass);
+ JS_ASSERT(obj->getClass() == &js_NamespaceClass.base);
v = obj->getNamespaceDeclared();
JS_ASSERT(JSVAL_IS_VOID(v) || v == JSVAL_TRUE);
return v == JSVAL_TRUE;
}
static JSBool
xml_isXMLName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
@@ -219,67 +219,51 @@ AppendString(JSCharBuffer &cb, JSString
code; \
return true; \
}
/*
* Namespace class and library functions.
*/
DEFINE_GETTER(NamePrefix_getter,
- if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNamePrefix())
+ if (obj->getClass() == &js_NamespaceClass.base) *vp = obj->getNamePrefix())
DEFINE_GETTER(NameURI_getter,
- if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNameURI())
+ if (obj->getClass() == &js_NamespaceClass.base) *vp = obj->getNameURI())
static void
namespace_finalize(JSContext *cx, JSObject *obj)
{
if (cx->runtime->functionNamespaceObject == obj)
cx->runtime->functionNamespaceObject = NULL;
}
static JSBool
namespace_equality(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
{
JSObject *obj2;
JS_ASSERT(v->isObjectOrNull());
obj2 = v->toObjectOrNull();
- *bp = (!obj2 || obj2->getClass() != &js_NamespaceClass)
+ *bp = (!obj2 || obj2->getClass() != &js_NamespaceClass.base)
? JS_FALSE
: js_EqualStrings(GetURI(obj), GetURI(obj2));
return JS_TRUE;
}
-JS_FRIEND_DATA(Class) js_NamespaceClass = {
- "Namespace",
- JSCLASS_CONSTRUCT_PROTOTYPE |
+JS_FRIEND_DATA(ExtendedClass) js_NamespaceClass = {
+ { "Namespace",
+ JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::NAMESPACE_FIXED_RESERVED_SLOTS) |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- namespace_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- NULL, /* mark */
- {
- namespace_equality,
- NULL, /* outerObject */
- NULL, /* innerObject */
- NULL, /* iteratorObject */
- NULL, /* wrappedObject */
- }
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, namespace_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL },
+ namespace_equality,NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
};
#define NAMESPACE_ATTRS \
(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED)
static JSPropertySpec namespace_props[] = {
{js_prefix_str, 0, NAMESPACE_ATTRS, NamePrefix_getter, 0},
{js_uri_str, 0, NAMESPACE_ATTRS, NameURI_getter, 0},
@@ -287,33 +271,33 @@ static JSPropertySpec namespace_props[]
};
static JSBool
namespace_toString(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *obj;
obj = JS_THIS_OBJECT(cx, vp);
- if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass), vp + 2))
+ if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass.base), vp + 2))
return JS_FALSE;
*vp = obj->getNameURI();
return JS_TRUE;
}
static JSFunctionSpec namespace_methods[] = {
JS_FN(js_toString_str, namespace_toString, 0,0),
JS_FS_END
};
static JSObject *
NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri, JSBool declared)
{
JSObject *obj;
- obj = NewBuiltinClassInstance(cx, &js_NamespaceClass);
+ obj = NewBuiltinClassInstance(cx, &js_NamespaceClass.base);
if (!obj)
return JS_FALSE;
JS_ASSERT(JSVAL_IS_VOID(obj->getNamePrefix()));
JS_ASSERT(JSVAL_IS_VOID(obj->getNameURI()));
JS_ASSERT(JSVAL_IS_VOID(obj->getNamespaceDeclared()));
if (prefix)
obj->setNamePrefix(STRING_TO_JSVAL(prefix));
if (uri)
@@ -323,20 +307,20 @@ NewXMLNamespace(JSContext *cx, JSString
METER(xml_stats.xmlnamespace);
return obj;
}
/*
* QName class and library functions.
*/
DEFINE_GETTER(QNameNameURI_getter,
- if (obj->getClass() == &js_QNameClass)
+ if (obj->getClass() == &js_QNameClass.base)
*vp = JSVAL_IS_VOID(obj->getNameURI()) ? JSVAL_NULL : obj->getNameURI())
DEFINE_GETTER(QNameLocalName_getter,
- if (obj->getClass() == &js_QNameClass)
+ if (obj->getClass() == &js_QNameClass.base)
*vp = obj->getQNameLocalName())
static void
anyname_finalize(JSContext* cx, JSObject* obj)
{
/* Make sure the next call to js_GetAnyName doesn't try to use obj. */
if (cx->runtime->anynameObject == obj)
cx->runtime->anynameObject = NULL;
@@ -356,87 +340,65 @@ qname_identity(JSObject *qna, JSObject *
}
static JSBool
qname_equality(JSContext *cx, JSObject *qn, const Value *v, JSBool *bp)
{
JSObject *obj2;
obj2 = v->toObjectOrNull();
- *bp = (!obj2 || obj2->getClass() != &js_QNameClass)
+ *bp = (!obj2 || obj2->getClass() != &js_QNameClass.base)
? JS_FALSE
: qname_identity(qn, obj2);
return JS_TRUE;
}
-JS_FRIEND_DATA(Class) js_QNameClass = {
- "QName",
- JSCLASS_CONSTRUCT_PROTOTYPE |
+JS_FRIEND_DATA(ExtendedClass) js_QNameClass = {
+ { "QName",
+ JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_QName),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- FinalizeStub,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- NULL, /* mark */
- {
- qname_equality,
- NULL, /* outerObject */
- NULL, /* innerObject */
- NULL, /* iteratorObject */
- NULL, /* wrappedObject */
- }
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL },
+ qname_equality, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
};
/*
* Classes for the ECMA-357-internal types AttributeName and AnyName, which
* are like QName, except that they have no property getters. They share the
* qname_toString method, and therefore are exposed as constructable objects
* in this implementation.
*/
JS_FRIEND_DATA(Class) js_AttributeNameClass = {
js_AttributeName_str,
JSCLASS_CONSTRUCT_PROTOTYPE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AttributeName),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
};
JS_FRIEND_DATA(Class) js_AnyNameClass = {
js_AnyName_str,
JSCLASS_CONSTRUCT_PROTOTYPE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AnyName),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- anyname_finalize
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, anyname_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
};
-#define QNAME_ATTRS (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED)
+#define QNAME_ATTRS \
+ (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED)
static JSPropertySpec qname_props[] = {
{js_uri_str, 0, QNAME_ATTRS, QNameNameURI_getter, 0},
{js_localName_str, 0, QNAME_ATTRS, QNameLocalName_getter, 0},
{0,0,0,0,0}
};
static JSBool
@@ -449,17 +411,17 @@ qname_toString(JSContext *cx, uintN argc
jschar *chars;
obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
clasp = obj->getClass();
if (clasp != &js_AttributeNameClass &&
clasp != &js_AnyNameClass &&
- !JS_InstanceOf(cx, obj, Jsvalify(&js_QNameClass), vp + 2)) {
+ !JS_InstanceOf(cx, obj, Jsvalify(&js_QNameClass.base), vp + 2)) {
return JS_FALSE;
}
uri = GetURI(obj);
if (!uri) {
/* No uri means wildcard qualifier. */
str = ATOM_TO_STRING(cx->runtime->atomState.starQualifierAtom);
} else if (uri->empty()) {
@@ -512,17 +474,17 @@ InitXMLQName(JSObject *obj, JSString *ur
if (prefix)
obj->setNamePrefix(STRING_TO_JSVAL(prefix));
if (localName)
obj->setQNameLocalName(STRING_TO_JSVAL(localName));
}
static JSObject *
NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, JSString *localName,
- Class *clasp = &js_QNameClass)
+ Class *clasp = &js_QNameClass.base)
{
JSObject *obj = NewBuiltinClassInstance(cx, clasp);
if (!obj)
return NULL;
JS_ASSERT(obj->isQName());
InitXMLQName(obj, uri, prefix, localName);
METER(xml_stats.qname);
return obj;
@@ -540,17 +502,17 @@ js_ConstructXMLQNameObject(JSContext *cx
*/
if (nsval.isObject() &&
nsval.toObject().getClass() == &js_AnyNameClass) {
argv[0].setNull();
} else {
argv[0] = nsval;
}
argv[1] = lnval;
- return js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, argv);
+ return js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, argv);
}
static JSBool
IsXMLName(const jschar *cp, size_t n)
{
JSBool rv;
jschar c;
@@ -614,30 +576,30 @@ NamespaceHelper(JSContext *cx, JSObject
#endif
if (argc <= 0) {
urival = JSVAL_VOID;
} else {
urival = argv[argc > 1];
if (!JSVAL_IS_PRIMITIVE(urival)) {
uriobj = JSVAL_TO_OBJECT(urival);
clasp = uriobj->getClass();
- isNamespace = (clasp == &js_NamespaceClass);
- isQName = (clasp == &js_QNameClass);
+ isNamespace = (clasp == &js_NamespaceClass.base);
+ isQName = (clasp == &js_QNameClass.base);
}
}
if (!obj) {
/* Namespace called as function. */
if (argc == 1 && isNamespace) {
/* Namespace called with one Namespace argument is identity. */
*rval = urival;
return JS_TRUE;
}
- obj = NewBuiltinClassInstance(cx, &js_NamespaceClass);
+ obj = NewBuiltinClassInstance(cx, &js_NamespaceClass.base);
if (!obj)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
}
METER(xml_stats.xmlnamespace);
empty = cx->runtime->emptyString;
obj->setNamePrefix(STRING_TO_JSVAL(empty));
@@ -710,26 +672,26 @@ QNameHelper(JSContext *cx, JSObject *obj
jsval *argv, jsval *rval)
{
jsval nameval, nsval;
JSBool isQName, isNamespace;
JSObject *qn;
JSString *uri, *prefix, *name;
JSObject *obj2;
- JS_ASSERT(clasp == &js_QNameClass ||
+ JS_ASSERT(clasp == &js_QNameClass.base ||
clasp == &js_AttributeNameClass);
if (argc <= 0) {
nameval = JSVAL_VOID;
isQName = JS_FALSE;
} else {
nameval = argv[argc > 1];
isQName =
!JSVAL_IS_PRIMITIVE(nameval) &&
- JSVAL_TO_OBJECT(nameval)->getClass() == &js_QNameClass;
+ JSVAL_TO_OBJECT(nameval)->getClass() == &js_QNameClass.base;
}
if (!obj) {
/* QName called as function. */
if (argc == 1 && isQName) {
/* QName called with one QName argument is identity. */
*rval = nameval;
return JS_TRUE;
@@ -775,17 +737,17 @@ QNameHelper(JSContext *cx, JSObject *obj
nsval = argv[0];
} else if (IS_STAR(name)) {
nsval = JSVAL_NULL;
} else {
if (!js_GetDefaultXMLNamespace(cx, &nsval))
return JS_FALSE;
JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval));
JS_ASSERT(JSVAL_TO_OBJECT(nsval)->getClass() ==
- &js_NamespaceClass);
+ &js_NamespaceClass.base);
}
if (JSVAL_IS_NULL(nsval)) {
/* NULL prefix represents *undefined* in ECMA-357 13.3.2 5(a). */
uri = prefix = NULL;
} else {
/*
* Inline specialization of the Namespace constructor called with
@@ -793,18 +755,18 @@ QNameHelper(JSContext *cx, JSObject *obj
* for the constructed namespace, without actually allocating the
* object or computing other members. See ECMA-357 13.3.2 6(a) and
* 13.2.2.
*/
isNamespace = isQName = JS_FALSE;
if (!JSVAL_IS_PRIMITIVE(nsval)) {
obj2 = JSVAL_TO_OBJECT(nsval);
clasp = obj2->getClass();
- isNamespace = (clasp == &js_NamespaceClass);
- isQName = (clasp == &js_QNameClass);
+ isNamespace = (clasp == &js_NamespaceClass.base);
+ isQName = (clasp == &js_QNameClass.base);
}
#ifdef __GNUC__ /* suppress bogus gcc warnings */
else obj2 = NULL;
#endif
if (isNamespace) {
uri = GetURI(obj2);
prefix = GetPrefix(obj2);
@@ -827,17 +789,17 @@ out:
InitXMLQName(obj, uri, prefix, name);
return JS_TRUE;
}
static JSBool
QName(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
{
return QNameHelper(cx, cx->isConstructing() ? obj : NULL,
- &js_QNameClass, argc, Jsvalify(argv), Jsvalify(rval));
+ &js_QNameClass.base, argc, Jsvalify(argv), Jsvalify(rval));
}
static JSBool
AttributeName(JSContext *cx, JSObject *obj, uintN argc, Value *argv,
Value *rval)
{
return QNameHelper(cx, cx->isConstructing() ? obj : NULL,
&js_AttributeNameClass, argc, Jsvalify(argv), Jsvalify(rval));
@@ -2192,17 +2154,17 @@ GetNamespace(JSContext *cx, JSObject *qn
}
}
}
/* If we didn't match, make a new namespace from qn. */
if (!match) {
argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID;
argv[1] = STRING_TO_JSVAL(uri);
- ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL,
+ ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL,
2, Valueify(argv));
if (!ns)
return NULL;
match = ns;
}
return match;
}
@@ -2747,17 +2709,17 @@ ToAttributeName(JSContext *cx, jsval v)
return NULL;
}
obj = JSVAL_TO_OBJECT(v);
clasp = obj->getClass();
if (clasp == &js_AttributeNameClass)
return obj;
- if (clasp == &js_QNameClass) {
+ if (clasp == &js_QNameClass.base) {
qn = obj;
uri = GetURI(qn);
prefix = GetPrefix(qn);
name = GetLocalName(qn);
} else {
if (clasp == &js_AnyNameClass) {
name = ATOM_TO_STRING(cx->runtime->atomState.starAtom);
} else {
@@ -2796,17 +2758,17 @@ IsFunctionQName(JSContext *cx, JSObject
}
*funidp = JSID_VOID;
return JS_TRUE;
}
JSBool
js_IsFunctionQName(JSContext *cx, JSObject *obj, jsid *funidp)
{
- if (obj->getClass() == &js_QNameClass)
+ if (obj->getClass() == &js_QNameClass.base)
return IsFunctionQName(cx, obj, funidp);
*funidp = JSID_VOID;
return JS_TRUE;
}
static JSObject *
ToXMLName(JSContext *cx, jsval v, jsid *funidp)
{
@@ -2821,17 +2783,17 @@ ToXMLName(JSContext *cx, jsval v, jsid *
} else {
if (JSVAL_IS_PRIMITIVE(v)) {
ReportBadXMLName(cx, Valueify(v));
return NULL;
}
obj = JSVAL_TO_OBJECT(v);
clasp = obj->getClass();
- if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass)
+ if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass.base)
goto out;
if (clasp == &js_AnyNameClass) {
name = ATOM_TO_STRING(cx->runtime->atomState.starAtom);
goto construct;
}
name = js_ValueToString(cx, Valueify(v));
if (!name)
return NULL;
@@ -2862,17 +2824,17 @@ ToXMLName(JSContext *cx, jsval v, jsid *
if (!name)
return NULL;
*funidp = JSID_VOID;
return ToAttributeName(cx, STRING_TO_JSVAL(name));
}
construct:
v = STRING_TO_JSVAL(name);
- obj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&v));
+ obj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, Valueify(&v));
if (!obj)
return NULL;
out:
if (!IsFunctionQName(cx, obj, funidp))
return NULL;
return obj;
@@ -4634,23 +4596,23 @@ xml_trace_vector(JSTracer *trc, JSXML **
if (xml) {
JS_SET_TRACING_INDEX(trc, "xml_vector", i);
Mark(trc, xml, JSTRACE_XML);
}
}
}
/*
- * XML objects are native. Thus xml_lookupProperty must return a valid
- * JSScopeProperty pointer parameter via *propp to signify "property found".
- * Since the only call to xml_lookupProperty is via JSObject::lookupProperty,
- * and then only from js_FindProperty (in jsobj.c, called from jsinterp.c) or
- * from JSOP_IN case in the interpreter, the only time we add a
- * JSScopeProperty here is when an unqualified name is being accessed or when
- * "name in xml" is called.
+ * js_XMLObjectOps.newObjectMap is null, so XML objects appear to be native.
+ * Thus xml_lookupProperty must return a valid JSScopeProperty pointer
+ * parameter via *propp to signify "property found". Since the only call to
+ * xml_lookupProperty is via JSObject::lookupProperty, and then only from
+ * js_FindProperty (in jsobj.c, called from jsinterp.c) or from JSOP_IN case
+ * in the interpreter, the only time we add a JSScopeProperty here is when an
+ * unqualified name is being accessed or when "name in xml" is called.
*
* This scope property keeps the JSOP_NAME code in js_Interpret happy by
* giving it an sprop with (getter, setter) == (GetProperty, PutProperty).
*
* NB: xml_deleteProperty must take care to remove any property added here.
*
* FIXME This clashes with the function namespace implementation which also
* uses native properties. Effectively after xml_lookupProperty any property
@@ -5063,49 +5025,47 @@ js_ConcatenateXML(JSContext *cx, JSObjec
goto out;
vp->setObject(*listobj);
out:
js_LeaveLocalRootScopeWithResult(cx, *vp);
return ok;
}
+/* Use NULL for objectMap so XML objects satisfy obj->isNative() tests. */
+JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = {
+ NULL,
+ xml_lookupProperty,
+ xml_defineProperty,
+ xml_getProperty,
+ xml_setProperty,
+ xml_getAttributes,
+ xml_setAttributes,
+ xml_deleteProperty,
+ xml_enumerate,
+ xml_typeOf,
+ js_TraceObject,
+ NULL, /* thisObject */
+ xml_clear
+};
+
+static JSObjectOps *
+xml_getObjectOps(JSContext *cx, Class *clasp)
+{
+ return &js_XMLObjectOps;
+}
+
JS_FRIEND_DATA(Class) js_XMLClass = {
js_XML_str,
- JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_XML),
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- xml_convert,
- xml_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- xml_hasInstance,
- JS_CLASS_TRACE(xml_trace),
- JS_NULL_CLASS_EXT,
- {
- xml_lookupProperty,
- xml_defineProperty,
- xml_getProperty,
- xml_setProperty,
- xml_getAttributes,
- xml_setAttributes,
- xml_deleteProperty,
- xml_enumerate,
- xml_typeOf,
- NULL, /* trace */
- NULL, /* thisObject */
- xml_clear
- }
+ JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_XML),
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, xml_convert, xml_finalize,
+ xml_getObjectOps, NULL, NULL, NULL,
+ NULL, xml_hasInstance, JS_CLASS_TRACE(xml_trace), NULL
};
static JSXML *
StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
{
JSXML *xml;
JSFunction *fun;
char numBuf[12];
@@ -6289,17 +6249,17 @@ xml_replace(JSContext *cx, uintN argc, j
if (!xml)
return JS_FALSE;
if (argc == 0 || !js_IdValIsIndex(vp[2], &index)) {
/*
* Call function QName per spec, not ToXMLName, to avoid attribute
* names.
*/
- if (!QNameHelper(cx, NULL, &js_QNameClass, argc == 0 ? -1 : 1,
+ if (!QNameHelper(cx, NULL, &js_QNameClass.base, argc == 0 ? -1 : 1,
vp + 2, vp)) {
return JS_FALSE;
}
JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp));
nameqn = JSVAL_TO_OBJECT(*vp);
i = xml->xml_kids.length;
index = XML_NOT_FOUND;
@@ -6352,17 +6312,17 @@ xml_setLocalName(JSContext *cx, uintN ar
if (!JSXML_HAS_NAME(xml))
return JS_TRUE;
if (argc == 0) {
namestr = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
} else {
name = vp[2];
if (!JSVAL_IS_PRIMITIVE(name) &&
- JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass) {
+ JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass.base) {
nameqn = JSVAL_TO_OBJECT(name);
namestr = GetLocalName(nameqn);
} else {
if (!JS_ConvertValue(cx, name, JSTYPE_STRING, &vp[2]))
return JS_FALSE;
name = vp[2];
namestr = JSVAL_TO_STRING(name);
}
@@ -6389,23 +6349,23 @@ xml_setName(JSContext *cx, uintN argc, j
if (!JSXML_HAS_NAME(xml))
return JS_TRUE;
if (argc == 0) {
name = ATOM_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
} else {
name = vp[2];
if (!JSVAL_IS_PRIMITIVE(name) &&
- JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass &&
+ JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass.base &&
!GetURI(nameqn = JSVAL_TO_OBJECT(name))) {
name = vp[2] = nameqn->getQNameLocalName();
}
}
- nameqn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&name));
+ nameqn = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, Valueify(&name));
if (!nameqn)
return JS_FALSE;
/* ECMA-357 13.4.4.35 Step 4. */
if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION)
nameqn->setNameURI(STRING_TO_JSVAL(cx->runtime->emptyString));
xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
@@ -6494,26 +6454,26 @@ xml_setNamespace(JSContext *cx, uintN ar
NON_LIST_XML_METHOD_PROLOG;
if (!JSXML_HAS_NAME(xml))
return JS_TRUE;
xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
if (!xml)
return JS_FALSE;
- ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj,
+ ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj,
argc == 0 ? 0 : 1, Valueify(vp + 2));
if (!ns)
return JS_FALSE;
vp[0] = OBJECT_TO_JSVAL(ns);
ns->setNamespaceDeclared(JSVAL_TRUE);
qnargv[0] = vp[2] = OBJECT_TO_JSVAL(ns);
qnargv[1] = OBJECT_TO_JSVAL(xml->name);
- qn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, Valueify(qnargv));
+ qn = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, Valueify(qnargv));
if (!qn)
return JS_FALSE;
xml->name = qn;
/*
* Erratum: the spec fails to update the governing in-scope namespaces.
* See the erratum noted in xml_setName, above.
@@ -7030,24 +6990,24 @@ js_GetXMLObject(JSContext *cx, JSXML *xm
return NULL;
xml->object = obj;
return obj;
}
JSObject *
js_InitNamespaceClass(JSContext *cx, JSObject *obj)
{
- return js_InitClass(cx, obj, NULL, &js_NamespaceClass, Namespace, 2,
+ return js_InitClass(cx, obj, NULL, &js_NamespaceClass.base, Namespace, 2,
namespace_props, namespace_methods, NULL, NULL);
}
JSObject *
js_InitQNameClass(JSContext *cx, JSObject *obj)
{
- return js_InitClass(cx, obj, NULL, &js_QNameClass, QName, 2,
+ return js_InitClass(cx, obj, NULL, &js_QNameClass.base, QName, 2,
qname_props, qname_methods, NULL, NULL);
}
JSObject *
js_InitAttributeNameClass(JSContext *cx, JSObject *obj)
{
return js_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2,
qname_props, qname_methods, NULL, NULL);
@@ -7233,17 +7193,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
return JS_FALSE;
if (!JSVAL_IS_PRIMITIVE(v)) {
*vp = v;
return JS_TRUE;
}
obj = tmp;
}
- ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, 0, NULL);
+ ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, 0, NULL);
if (!ns)
return JS_FALSE;
v = OBJECT_TO_JSVAL(ns);
if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(v),
PropertyStub, PropertyStub, JSPROP_PERMANENT)) {
return JS_FALSE;
}
*vp = v;
@@ -7254,17 +7214,17 @@ JSBool
js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
{
Value argv[2];
JSObject *ns, *varobj;
JSStackFrame *fp;
argv[0].setString(cx->runtime->emptyString);
argv[1] = v;
- ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv);
+ ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL, 2, argv);
if (!ns)
return JS_FALSE;
fp = js_GetTopStackFrame(cx);
varobj = fp->varobj(cx);
if (!varobj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
PropertyStub, PropertyStub, JSPROP_PERMANENT)) {
return JS_FALSE;
@@ -7420,23 +7380,23 @@ js_FindXMLProperty(JSContext *cx, const
JSBool found;
JSProperty *prop;
const char *printable;
JS_ASSERT(nameval.isObject());
nameobj = &nameval.toObject();
if (nameobj->getClass() == &js_AnyNameClass) {
v = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom);
- nameobj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1,
+ nameobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1,
Valueify(&v));
if (!nameobj)
return JS_FALSE;
} else {
JS_ASSERT(nameobj->getClass() == &js_AttributeNameClass ||
- nameobj->getClass() == &js_QNameClass);
+ nameobj->getClass() == &js_QNameClass.base);
}
qn = nameobj;
if (!IsFunctionQName(cx, qn, &funid))
return JS_FALSE;
obj = js_GetTopStackFrame(cx)->scopeChain;
do {
@@ -7601,31 +7561,20 @@ xmlfilter_finalize(JSContext *cx, JSObje
return;
cx->destroy(filter);
}
Class js_XMLFilterClass = {
"XMLFilter",
JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
- PropertyStub, /* addProperty */
- PropertyStub, /* delProperty */
- PropertyStub, /* getProperty */
- PropertyStub, /* setProperty */
- EnumerateStub,
- ResolveStub,
- ConvertStub,
- xmlfilter_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- JS_CLASS_TRACE(xmlfilter_trace)
+ PropertyStub, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, ConvertStub, xmlfilter_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, JS_CLASS_TRACE(xmlfilter_trace), NULL
};
JSBool
js_StepXMLListFilter(JSContext *cx, JSBool initialized)
{
jsval *sp;
JSObject *obj, *filterobj, *resobj, *kidobj;
JSXML *xml, *list;
--- a/js/src/jsxml.h
+++ b/js/src/jsxml.h
@@ -211,54 +211,55 @@ extern void
js_FinalizeXML(JSContext *cx, JSXML *xml);
extern JSObject *
js_NewXMLObject(JSContext *cx, JSXMLClass xml_class);
extern JSObject *
js_GetXMLObject(JSContext *cx, JSXML *xml);
-extern JS_FRIEND_DATA(js::Class) js_XMLClass;
-extern JS_FRIEND_DATA(js::Class) js_NamespaceClass;
-extern JS_FRIEND_DATA(js::Class) js_QNameClass;
-extern JS_FRIEND_DATA(js::Class) js_AttributeNameClass;
-extern JS_FRIEND_DATA(js::Class) js_AnyNameClass;
-extern js::Class js_XMLFilterClass;
+extern JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps;
+extern JS_FRIEND_DATA(js::Class) js_XMLClass;
+extern JS_FRIEND_DATA(js::ExtendedClass) js_NamespaceClass;
+extern JS_FRIEND_DATA(js::ExtendedClass) js_QNameClass;
+extern JS_FRIEND_DATA(js::Class) js_AttributeNameClass;
+extern JS_FRIEND_DATA(js::Class) js_AnyNameClass;
+extern js::Class js_XMLFilterClass;
/*
* Methods to test whether an object or a value is of type "xml" (per typeof).
*/
inline bool
JSObject::isXML() const
{
- return getClass() == &js_XMLClass;
+ return map->ops == &js_XMLObjectOps;
}
inline bool
JSObject::isXMLId() const
{
js::Class *clasp = getClass();
- return clasp == &js_QNameClass ||
+ return clasp == &js_QNameClass.base ||
clasp == &js_AttributeNameClass ||
clasp == &js_AnyNameClass;
}
#define VALUE_IS_XML(v) (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isXML())
inline bool
JSObject::isNamespace() const
{
- return getClass() == &js_NamespaceClass;
+ return getClass() == &js_NamespaceClass.base;
}
inline bool
JSObject::isQName() const
{
js::Class* clasp = getClass();
- return clasp == &js_QNameClass ||
+ return clasp == &js_QNameClass.base ||
clasp == &js_AttributeNameClass ||
clasp == &js_AnyNameClass;
}
static inline bool
IsXML(const js::Value &v)
{
return v.isObject() && v.toObject().isXML();
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1388,17 +1388,17 @@ ValueToScript(JSContext *cx, jsval v)
JSFunction *fun;
if (!JSVAL_IS_PRIMITIVE(v)) {
JSObject *obj = JSVAL_TO_OBJECT(v);
JSClass *clasp = JS_GET_CLASS(cx, obj);
if (clasp == Jsvalify(&js_ScriptClass)) {
script = (JSScript *) JS_GetPrivate(cx, obj);
- } else if (clasp == Jsvalify(&js_GeneratorClass)) {
+ } else if (clasp == Jsvalify(&js_GeneratorClass.base)) {
JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
fun = gen->getFloatingFrame()->fun;
script = FUN_SCRIPT(fun);
}
}
if (!script) {
fun = JS_ValueToFunction(cx, v);
@@ -2738,16 +2738,28 @@ static JSObject *
split_thisObject(JSContext *cx, JSObject *obj)
{
OBJ_TO_OUTER_OBJECT(cx, obj);
if (!obj)
return NULL;
return obj;
}
+static JSObjectOps split_objectops;
+
+static JSObjectOps *
+split_getObjectOps(JSContext *cx, JSClass *clasp)
+{
+ if (!split_objectops.thisObject) {
+ memcpy(&split_objectops, &js_ObjectOps, sizeof split_objectops);
+ split_objectops.thisObject = split_thisObject;
+ }
+
+ return &split_objectops;
+}
static JSBool
split_equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp);
static JSObject *
split_innerObject(JSContext *cx, JSObject *obj)
{
ComplexObject *cpx;
@@ -2755,66 +2767,40 @@ split_innerObject(JSContext *cx, JSObjec
cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
if (cpx->frozen) {
JS_ASSERT(!cpx->isInner);
return obj;
}
return !cpx->isInner ? cpx->inner : obj;
}
-static Class split_global_class = {
- "split_global",
- JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_PRIVATE | JSCLASS_GLOBAL_FLAGS,
- Valueify(split_addProperty),
- Valueify(split_delProperty),
- Valueify(split_getProperty),
- Valueify(split_setProperty),
+static JSExtendedClass split_global_class = {
+ {"split_global",
+ JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_PRIVATE |
+ JSCLASS_GLOBAL_FLAGS | JSCLASS_IS_EXTENDED,
+ split_addProperty, split_delProperty,
+ split_getProperty, split_setProperty,
(JSEnumerateOp)split_enumerate,
(JSResolveOp)split_resolve,
- ConvertStub,
- split_finalize,
- NULL, /* reserved0 */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* construct */
- NULL, /* xdrObject */
- NULL, /* hasInstance */
- split_mark,
- {
- Valueify(split_equality),
- split_outerObject,
- split_innerObject,
- NULL, /* iteratorObject */
- NULL, /* wrappedObject */
- },
- {
- NULL, /* lookupProperty */
- NULL, /* defineProperty */
- NULL, /* getProperty */
- NULL, /* setProperty */
- NULL, /* getAttributes */
- NULL, /* setAttributes */
- NULL, /* deleteProperty */
- NULL, /* enumerate */
- NULL, /* typeOf */
- NULL, /* trace */
- split_thisObject,
- NULL, /* clear */
- },
+ JS_ConvertStub, split_finalize,
+ split_getObjectOps, NULL, NULL, NULL, NULL, NULL,
+ split_mark, NULL},
+ split_equality, split_outerObject, split_innerObject,
+ NULL, NULL, NULL, NULL, NULL
};
static JSBool
split_equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp)
{
*bp = JS_FALSE;
if (JSVAL_IS_PRIMITIVE(*v))
return JS_TRUE;
JSObject *obj2 = JSVAL_TO_OBJECT(*v);
- if (obj2->getClass() != &split_global_class)
+ if (JS_GET_CLASS(cx, obj2) != &split_global_class.base)
return JS_TRUE;
ComplexObject *cpx = (ComplexObject *) JS_GetPrivate(cx, obj2);
JS_ASSERT(!cpx->isInner);
ComplexObject *ourCpx = (ComplexObject *) JS_GetPrivate(cx, obj);
JS_ASSERT(!ourCpx->isInner);
@@ -2831,17 +2817,17 @@ split_create_outer(JSContext *cx)
cpx = (ComplexObject *) JS_malloc(cx, sizeof *obj);
if (!cpx)
return NULL;
cpx->isInner = JS_FALSE;
cpx->frozen = JS_TRUE;
cpx->inner = NULL;
cpx->outer = NULL;
- obj = JS_NewGlobalObject(cx, Jsvalify(&split_global_class));
+ obj = JS_NewGlobalObject(cx, &split_global_class.base);
if (!obj || !JS_SetParent(cx, obj, NULL)) {
JS_free(cx, cpx);
return NULL;
}
if (!JS_SetPrivate(cx, obj, cpx)) {
JS_free(cx, cpx);
return NULL;
@@ -2851,44 +2837,44 @@ split_create_outer(JSContext *cx)
}
static JSObject *
split_create_inner(JSContext *cx, JSObject *outer)
{
ComplexObject *cpx, *outercpx;
JSObject *obj;
- JS_ASSERT(outer->getClass() == &split_global_class);
+ JS_ASSERT(JS_GET_CLASS(cx, outer) == &split_global_class.base);
cpx = (ComplexObject *) JS_malloc(cx, sizeof *cpx);
if (!cpx)
return NULL;
cpx->isInner = JS_TRUE;
cpx->frozen = JS_FALSE;
cpx->inner = NULL;
cpx->outer = outer;
- obj = JS_NewGlobalObject(cx, Jsvalify(&split_global_class));
+ obj = JS_NewGlobalObject(cx, &split_global_class.base);
if (!obj || !JS_SetParent(cx, obj, NULL) || !JS_SetPrivate(cx, obj, cpx)) {
JS_free(cx, cpx);
return NULL;
}
outercpx = (ComplexObject *) JS_GetPrivate(cx, outer);
outercpx->inner = obj;
outercpx->frozen = JS_FALSE;
return obj;
}
static ComplexObject *
split_get_private(JSContext *cx, JSObject *obj)
{
do {
- if (obj->getClass() == &split_global_class)
+ if (JS_GET_CLASS(cx, obj) == &split_global_class.base)
return (ComplexObject *) JS_GetPrivate(cx, obj);
obj = JS_GetParent(cx, obj);
} while (obj);
return NULL;
}
static JSBool
@@ -3663,18 +3649,22 @@ Parent(JSContext *cx, uintN argc, jsval
return JS_FALSE;
}
JSObject *parent = JS_GetParent(cx, JSVAL_TO_OBJECT(v));
*vp = OBJECT_TO_JSVAL(parent);
/* Outerize if necessary. Embrace the ugliness! */
if (parent) {
- if (JSObjectOp op = parent->getClass()->ext.outerObject)
- *vp = OBJECT_TO_JSVAL(op(cx, parent));
+ JSClass *clasp = JS_GET_CLASS(cx, parent);
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ JSExtendedClass *xclasp = reinterpret_cast<JSExtendedClass *>(clasp);
+ if (JSObjectOp outerize = xclasp->outerObject)
+ *vp = OBJECT_TO_JSVAL(outerize(cx, parent));
+ }
}
return JS_TRUE;
}
#ifdef XP_UNIX
#include <fcntl.h>
--- a/js/src/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -54,17 +54,16 @@
#include "nsDependentString.h"
#include "nsAutoPtr.h"
#include "nsNetUtil.h"
#include "nsIProtocolHandler.h"
#include "nsIFileURL.h"
#include "jsapi.h"
#include "jsdbgapi.h"
-#include "jsobj.h"
#include "mozilla/FunctionTimer.h"
/* load() error msgs, XXX localize? */
#define LOAD_ERROR_NOSERVICE "Error creating IO Service."
#define LOAD_ERROR_NOURI "Error creating URI (invalid URL scheme?)"
#define LOAD_ERROR_NOSCHEME "Failed to get URI scheme. This is bad."
#define LOAD_ERROR_URI_NOT_LOCAL "Trying to load a non-local URI."
@@ -200,23 +199,28 @@ mozJSSubScriptLoader::LoadSubScript (con
}
#ifdef DEBUG_rginda
fprintf (stderr, "\n");
#endif
}
// Innerize the target_obj so that we compile the loaded script in the
// correct (inner) scope.
- if (JSObjectOp op = target_obj->getClass()->ext.innerObject)
+ JSClass *target_class = JS_GET_CLASS(cx, target_obj);
+ if (target_class->flags & JSCLASS_IS_EXTENDED)
{
- target_obj = op(cx, target_obj);
- if (!target_obj) return NS_ERROR_FAILURE;
+ JSExtendedClass *extended = (JSExtendedClass*)target_class;
+ if (extended->innerObject)
+ {
+ target_obj = extended->innerObject(cx, target_obj);
+ if (!target_obj) return NS_ERROR_FAILURE;
#ifdef DEBUG_rginda
- fprintf (stderr, "Final global: %p\n", target_obj);
+ fprintf (stderr, "Final global: %p\n", target_obj);
#endif
+ }
}
/* load up the url. From here on, failures are reflected as ``custom''
* js exceptions */
PRInt32 len = -1;
PRUint32 readcount = 0; // Total amount of data read
PRUint32 lastReadCount = 0; // Amount of data read in last Read() call
nsAutoArrayPtr<char> buf;
--- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
@@ -246,55 +246,49 @@ XPC_COW_WrappedObject(JSContext *cx, JSO
static JSBool
WrapFunction(JSContext *cx, JSObject *scope, JSObject *funobj, jsval *vp);
using namespace XPCWrapper;
namespace ChromeObjectWrapper {
-js::Class COWClass = {
- "ChromeObjectWrapper",
- JSCLASS_NEW_RESOLVE |
+JSExtendedClass COWClass = {
+ // JSClass (JSExtendedClass.base) initialization
+ { "ChromeObjectWrapper",
+ JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots + 1),
- js::Valueify(XPC_COW_AddProperty),
- js::Valueify(XPC_COW_DelProperty),
- js::Valueify(XPC_COW_GetProperty),
- js::Valueify(XPC_COW_SetProperty),
- XPC_COW_Enumerate,
- (JSResolveOp)XPC_COW_NewResolve,
- js::Valueify(XPC_COW_Convert),
- JS_FinalizeStub,
- nsnull, // reserved0
- js::Valueify(XPC_COW_CheckAccess),
- nsnull, // call
- nsnull, // construct
- nsnull, // xdrObject
- nsnull, // hasInstance
- nsnull, // mark
+ XPC_COW_AddProperty, XPC_COW_DelProperty,
+ XPC_COW_GetProperty, XPC_COW_SetProperty,
+ XPC_COW_Enumerate, (JSResolveOp)XPC_COW_NewResolve,
+ XPC_COW_Convert, JS_FinalizeStub,
+ nsnull, XPC_COW_CheckAccess,
+ nsnull, nsnull,
+ nsnull, nsnull,
+ nsnull, nsnull
+ },
- // ClassExtension
- {
- js::Valueify(XPC_COW_Equality),
- nsnull, // outerObject
- nsnull, // innerObject
- XPC_COW_Iterator,
- XPC_COW_WrappedObject
- }
+ // JSExtendedClass initialization
+ XPC_COW_Equality,
+ nsnull, // outerObject
+ nsnull, // innerObject
+ XPC_COW_Iterator,
+ XPC_COW_WrappedObject,
+ JSCLASS_NO_RESERVED_MEMBERS
};
JSBool
WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp)
{
if (JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v))) {
return WrapFunction(cx, parent, JSVAL_TO_OBJECT(v), vp);
}
JSObject *wrapperObj =
- JS_NewObjectWithGivenProto(cx, js::Jsvalify(&COWClass), NULL, parent);
+ JS_NewObjectWithGivenProto(cx, &COWClass.base, NULL, parent);
if (!wrapperObj) {
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(wrapperObj);
js::AutoValueRooter exposedProps(cx);
@@ -324,36 +318,41 @@ ThrowException(nsresult rv, JSContext *c
}
// Like GetWrappedObject, but works on other types of wrappers, too.
// See also JSObject::wrappedObject in jsobj.cpp.
// TODO Move to XPCWrapper?
static inline JSObject *
GetWrappedJSObject(JSContext *cx, JSObject *obj)
{
- JSObjectOp op = obj->getClass()->ext.wrappedObject;
- if (!op) {
+ JSClass *clasp = obj->getJSClass();
+ if (!(clasp->flags & JSCLASS_IS_EXTENDED)) {
+ return obj;
+ }
+
+ JSExtendedClass *xclasp = (JSExtendedClass *)clasp;
+ if (!xclasp->wrappedObject) {
if (XPCNativeWrapper::IsNativeWrapper(obj)) {
XPCWrappedNative *wn = XPCNativeWrapper::SafeGetWrappedNative(obj);
return wn ? wn->GetFlatJSObject() : nsnull;
}
return obj;
}
- return op(cx, obj);
+ return xclasp->wrappedObject(cx, obj);
}
// Get the (possibly nonexistent) COW off of an object
// TODO Move to XPCWrapper and share with other wrappers.
static inline
JSObject *
GetWrapper(JSObject *obj)
{
- while (obj->getClass() != &COWClass) {
+ while (obj->getJSClass() != &COWClass.base) {
obj = obj->getProto();
if (!obj) {
break;
}
}
return obj;
}
@@ -744,17 +743,18 @@ XPC_COW_Equality(JSContext *cx, JSObject
*bp = JS_FALSE;
return JS_TRUE;
}
XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
obj = me->GetFlatJSObject();
test = other->GetFlatJSObject();
jsval testVal = OBJECT_TO_JSVAL(test);
- return js::Jsvalify(obj->getClass()->ext.equality)(cx, obj, &testVal, bp);
+ return ((JSExtendedClass *)obj->getJSClass())->
+ equality(cx, obj, &testVal, bp);
}
static JSObject *
XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
{
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
ThrowException(NS_ERROR_INVALID_ARG, cx);
--- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
+++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
@@ -120,17 +120,17 @@ ThrowException(nsresult ex, JSContext *c
return JS_FALSE;
}
// Get the (possibly nonexistent) XOW off of an object
static inline
JSObject *
GetWrapper(JSObject *obj)
{
- while (obj->getClass() != &XPCCrossOriginWrapper::XOWClass) {
+ while (obj->getJSClass() != &XPCCrossOriginWrapper::XOWClass.base) {
obj = obj->getProto();
if (!obj) {
break;
}
}
return obj;
}
@@ -151,44 +151,38 @@ XPC_XOW_FunctionWrapper(JSContext *cx, J
static const PRUint32 FLAG_IS_UXPC_OBJECT = XPCWrapper::LAST_FLAG << 1;
// This flag is set on objects that have to clear their wrapped native's XOW
// cache when they get finalized.
static const PRUint32 FLAG_IS_CACHED = XPCWrapper::LAST_FLAG << 2;
namespace XPCCrossOriginWrapper {
-js::Class XOWClass = {
- "XPCCrossOriginWrapper",
- JSCLASS_NEW_RESOLVE |
+JSExtendedClass XOWClass = {
+ // JSClass (JSExtendedClass.base) initialization
+ { "XPCCrossOriginWrapper",
+ JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots + 2),
- js::Valueify(XPC_XOW_AddProperty),
- js::Valueify(XPC_XOW_DelProperty),
- js::Valueify(XPC_XOW_GetProperty),
- js::Valueify(XPC_XOW_SetProperty),
- XPC_XOW_Enumerate,
- (JSResolveOp)XPC_XOW_NewResolve,
- js::Valueify(XPC_XOW_Convert),
- XPC_XOW_Finalize,
- nsnull, // reserved0
- js::Valueify(XPC_XOW_CheckAccess),
- js::Valueify(XPC_XOW_Call),
- js::Valueify(XPC_XOW_Construct),
- nsnull, // xdrObject
- js::Valueify(XPC_XOW_HasInstance),
- nsnull, // mark
+ XPC_XOW_AddProperty, XPC_XOW_DelProperty,
+ XPC_XOW_GetProperty, XPC_XOW_SetProperty,
+ XPC_XOW_Enumerate, (JSResolveOp)XPC_XOW_NewResolve,
+ XPC_XOW_Convert, XPC_XOW_Finalize,
+ nsnull, XPC_XOW_CheckAccess,
+ XPC_XOW_Call, XPC_XOW_Construct,
+ nsnull, XPC_XOW_HasInstance,
+ nsnull, nsnull
+ },
- // ClassExtension
- {
- js::Valueify(XPC_XOW_Equality),
- nsnull, // outerObject
- nsnull, // innerObject
- XPC_XOW_Iterator,
- XPC_XOW_WrappedObject
- }
+ // JSExtendedClass initialization
+ XPC_XOW_Equality,
+ nsnull, // outerObject
+ nsnull, // innerObject
+ XPC_XOW_Iterator,
+ XPC_XOW_WrappedObject,
+ JSCLASS_NO_RESERVED_MEMBERS
};
JSBool
WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
XPCWrappedNativeScope *newScope)
{
typedef WrappedNative2WrapperMap::Link Link;
XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
@@ -377,17 +371,17 @@ RewrapIfNeeded(JSContext *cx, JSObject *
JSObject *obj = JSVAL_TO_OBJECT(*vp);
if (JS_ObjectIsFunction(cx, obj)) {
return WrapFunction(cx, outerObj, obj, vp);
}
XPCWrappedNative *wn = nsnull;
- if (obj->getClass() == &XOWClass &&
+ if (obj->getJSClass() == &XOWClass.base &&
outerObj->getParent() != obj->getParent()) {
*vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj));
} else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) {
return JS_TRUE;
}
return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp, wn);
}
@@ -398,17 +392,17 @@ WrapObject(JSContext *cx, JSObject *pare
NS_ASSERTION(XPCPerThreadData::IsMainThread(cx),
"Can't do this off the main thread!");
// Our argument should be a wrapped native object, but the caller may have
// passed it in as an optimization.
JSObject *wrappedObj;
if (JSVAL_IS_PRIMITIVE(*vp) ||
!(wrappedObj = JSVAL_TO_OBJECT(*vp)) ||
- wrappedObj->getClass() == &XOWClass) {
+ wrappedObj->getJSClass() == &XOWClass.base) {
return JS_TRUE;
}
if (!wn &&
!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, wrappedObj))) {
return JS_TRUE;
}
@@ -446,30 +440,30 @@ WrapObject(JSContext *cx, JSObject *pare
parentScope = XPCWrappedNativeScope::FindInJSObjectScope(cx, parent);
}
JSObject *outerObj = nsnull;
WrappedNative2WrapperMap *map = parentScope->GetWrapperMap();
outerObj = map->Find(wrappedObj);
if (outerObj) {
- NS_ASSERTION(outerObj->getClass() == &XOWClass,
+ NS_ASSERTION(outerObj->getJSClass() == &XOWClass.base,
"What crazy object are we getting here?");
*vp = OBJECT_TO_JSVAL(outerObj);
if (wnxow) {
// NB: wnxow->GetXOW() must have returned false.
SetFlags(cx, outerObj, AddFlags(GetFlags(cx, outerObj), FLAG_IS_CACHED));
wnxow->SetXOW(outerObj);
}
return JS_TRUE;
}
- outerObj = JS_NewObjectWithGivenProto(cx, js::Jsvalify(&XOWClass), nsnull,
+ outerObj = JS_NewObjectWithGivenProto(cx, &XOWClass.base, nsnull,
parent);
if (!outerObj) {
return JS_FALSE;
}
jsval flags = INT_TO_JSVAL(wnxow ? FLAG_IS_CACHED : 0);
if (!JS_SetReservedSlot(cx, outerObj, sWrappedObjSlot, *vp) ||
!JS_SetReservedSlot(cx, outerObj, sFlagsSlot, flags) ||
@@ -591,24 +585,24 @@ WrapSameOriginProp(JSContext *cx, JSObje
{
// Don't call RewrapIfNeeded for same origin properties. We only
// need to wrap window, document and location.
if (JSVAL_IS_PRIMITIVE(*vp)) {
return JS_TRUE;
}
JSObject *wrappedObj = JSVAL_TO_OBJECT(*vp);
- js::Class *clasp = wrappedObj->getClass();
+ JSClass *clasp = wrappedObj->getJSClass();
if (ClassNeedsXOW(clasp->name)) {
return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp);
}
// Check if wrappedObj is an XOW. If so, verify that it's from the
// right scope.
- if (clasp == &XOWClass &&
+ if (clasp == &XOWClass.base &&
wrappedObj->getParent() != outerObj->getParent()) {
*vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, wrappedObj));
return WrapObject(cx, outerObj->getParent(), vp);
}
return JS_TRUE;
}
@@ -621,17 +615,17 @@ XPC_XOW_AddProperty(JSContext *cx, JSObj
obj = GetWrapper(obj);
jsval resolving;
if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &resolving)) {
return JS_FALSE;
}
if (!JSVAL_IS_PRIMITIVE(*vp)) {
JSObject *addedObj = JSVAL_TO_OBJECT(*vp);
- if (addedObj->getClass() == &XOWClass &&
+ if (addedObj->getJSClass() == &XOWClass.base &&
addedObj->getParent() != obj->getParent()) {
*vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, addedObj));
if (!WrapObject(cx, obj->getParent(), vp, nsnull)) {
return JS_FALSE;
}
}
}
@@ -843,17 +837,17 @@ XPC_XOW_Enumerate(JSContext *cx, JSObjec
// UXPCObject (which is just a XOW for the same object). This causes the JS
// engine to do all of its work on another object, not polluting the main
// object. However, if the get results in calling a setter, the engine still
// uses the regular object as 'this', ensuring that the UXPCObject doesn't
// leak to script.
static JSObject *
GetUXPCObject(JSContext *cx, JSObject *obj)
{
- NS_ASSERTION(obj->getClass() == &XOWClass, "wrong object");
+ NS_ASSERTION(obj->getJSClass() == &XOWClass.base, "wrong object");
jsval v;
if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &v)) {
return nsnull;
}
if (HAS_FLAGS(v, FLAG_IS_UXPC_OBJECT)) {
return obj;
@@ -863,18 +857,17 @@ GetUXPCObject(JSContext *cx, JSObject *o
return nsnull;
}
if (JSVAL_IS_OBJECT(v)) {
return JSVAL_TO_OBJECT(v);
}
JSObject *uxpco =
- JS_NewObjectWithGivenProto(cx, js::Jsvalify(&XOWClass), nsnull,
- obj->getParent());
+ JS_NewObjectWithGivenProto(cx, &XOWClass.base, nsnull, obj->getParent());
if (!uxpco) {
return nsnull;
}
js::AutoObjectRooter tvr(cx, uxpco);
jsval wrappedObj, parentScope;
if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) ||
@@ -1183,17 +1176,17 @@ XPC_XOW_Equality(JSContext *cx, JSObject
// Convert both sides to XPCWrappedNative and see if they match.
if (JSVAL_IS_PRIMITIVE(v)) {
*bp = JS_FALSE;
return JS_TRUE;
}
JSObject *test = JSVAL_TO_OBJECT(v);
- if (test->getClass() == &XOWClass) {
+ if (test->getJSClass() == &XOWClass.base) {
if (!JS_GetReservedSlot(cx, test, sWrappedObjSlot, &v)) {
return JS_FALSE;
}
if (JSVAL_IS_PRIMITIVE(v)) {
*bp = JS_FALSE;
return JS_TRUE;
}
@@ -1211,17 +1204,18 @@ XPC_XOW_Equality(JSContext *cx, JSObject
*bp = JS_FALSE;
return JS_TRUE;
}
XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
obj = me->GetFlatJSObject();
test = other->GetFlatJSObject();
jsval testVal = OBJECT_TO_JSVAL(test);
- return js::Jsvalify(obj->getClass()->ext.equality)(cx, obj, &testVal, bp);
+ return ((JSExtendedClass *)obj->getJSClass())->
+ equality(cx, obj, &testVal, bp);
}
static JSObject *
XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
{
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
ThrowException(NS_ERROR_INVALID_ARG, cx);
@@ -1241,17 +1235,17 @@ XPC_XOW_Iterator(JSContext *cx, JSObject
ThrowException(rv, cx);
return nsnull;
}
ThrowException(NS_ERROR_FAILURE, cx);
return nsnull;
}
- JSObject *wrapperIter = JS_NewObject(cx, js::Jsvalify(&XOWClass), nsnull,
+ JSObject *wrapperIter = JS_NewObject(cx, &XOWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) {
return nsnull;
}
js::AutoObjectRooter tvr(cx, wrapperIter);
// Initialize our XOW.
--- a/js/src/xpconnect/src/XPCNativeWrapper.cpp
+++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp
@@ -104,78 +104,66 @@ using namespace XPCWrapper;
// not have expando properties set on implicit native wrappers.
static const PRUint32 FLAG_EXPLICIT = XPCWrapper::LAST_FLAG << 1;
namespace XPCNativeWrapper { namespace internal {
// JS class for XPCNativeWrapper (and this doubles as the constructor
// for XPCNativeWrapper for the moment too...)
-js::Class NW_NoCall_Class = {
- "XPCNativeWrapper",
+JSExtendedClass NW_NoCall_Class = {
+ // JSClass (JSExtendedClass.base) initialization
+ { "XPCNativeWrapper",
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
// Our one reserved slot holds a jsint of flag bits
JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
- JSCLASS_MARK_IS_TRACE | JSCLASS_CONSTRUCT_PROTOTYPE,
- js::Valueify(XPC_NW_AddProperty),
- js::Valueify(XPC_NW_DelProperty),
- js::Valueify(XPC_NW_GetProperty),
- js::Valueify(XPC_NW_SetProperty),
- XPC_NW_Enumerate,
- (JSResolveOp)XPC_NW_NewResolve,
- js::Valueify(XPC_NW_Convert),
- XPC_NW_Finalize,
- nsnull, // reserved0
- js::Valueify(XPC_NW_CheckAccess),
- nsnull, // call
- js::Valueify(XPC_NW_Construct),
- nsnull, // xdrObject
- js::Valueify(XPC_NW_HasInstance),
- JS_CLASS_TRACE(XPC_NW_Trace),
+ JSCLASS_MARK_IS_TRACE | JSCLASS_IS_EXTENDED | JSCLASS_CONSTRUCT_PROTOTYPE,
+ XPC_NW_AddProperty, XPC_NW_DelProperty,
+ XPC_NW_GetProperty, XPC_NW_SetProperty,
+ XPC_NW_Enumerate, (JSResolveOp)XPC_NW_NewResolve,
+ XPC_NW_Convert, XPC_NW_Finalize,
+ nsnull, XPC_NW_CheckAccess,
+ nsnull, XPC_NW_Construct,
+ nsnull, XPC_NW_HasInstance,
+ JS_CLASS_TRACE(XPC_NW_Trace), nsnull
+ },
- // ClassExtension
- {
- js::Valueify(XPC_NW_Equality),
- nsnull, // outerObject
- nsnull, // innerObject
- XPC_NW_Iterator,
- nsnull, // wrappedObject
- }
+ // JSExtendedClass initialization
+ XPC_NW_Equality,
+ nsnull, // outerObject
+ nsnull, // innerObject
+ XPC_NW_Iterator,
+ nsnull, // wrappedObject
+ JSCLASS_NO_RESERVED_MEMBERS
};
-js::Class NW_Call_Class = {
- "XPCNativeWrapper",
+JSExtendedClass NW_Call_Class = {
+ // JSClass (JSExtendedClass.base) initialization
+ { "XPCNativeWrapper",
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
// Our one reserved slot holds a jsint of flag bits
JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
- JSCLASS_MARK_IS_TRACE | JSCLASS_CONSTRUCT_PROTOTYPE,
- js::Valueify(XPC_NW_AddProperty),
- js::Valueify(XPC_NW_DelProperty),
- js::Valueify(XPC_NW_GetProperty),
- js::Valueify(XPC_NW_SetProperty),
- XPC_NW_Enumerate,
- (JSResolveOp)XPC_NW_NewResolve,
- js::Valueify(XPC_NW_Convert),
- XPC_NW_Finalize,
- nsnull, // reserved0
- js::Valueify(XPC_NW_CheckAccess),
- js::Valueify(XPC_NW_Call),
- js::Valueify(XPC_NW_Construct),
- nsnull, // xdrObject
- js::Valueify(XPC_NW_HasInstance),
- JS_CLASS_TRACE(XPC_NW_Trace),
+ JSCLASS_MARK_IS_TRACE | JSCLASS_IS_EXTENDED | JSCLASS_CONSTRUCT_PROTOTYPE,
+ XPC_NW_AddProperty, XPC_NW_DelProperty,
+ XPC_NW_GetProperty, XPC_NW_SetProperty,
+ XPC_NW_Enumerate, (JSResolveOp)XPC_NW_NewResolve,
+ XPC_NW_Convert, XPC_NW_Finalize,
+ nsnull, XPC_NW_CheckAccess,
+ XPC_NW_Call, XPC_NW_Construct,
+ nsnull, XPC_NW_HasInstance,
+ JS_CLASS_TRACE(XPC_NW_Trace), nsnull
+ },
- // ClassExtension
- {
- js::Valueify(XPC_NW_Equality),
- nsnull, // outerObject
- nsnull, // innerObject
- XPC_NW_Iterator,
- nsnull, // wrappedObject
- }
+ // JSExtendedClass initialization
+ XPC_NW_Equality,
+ nsnull, // outerObject
+ nsnull, // innerObject
+ XPC_NW_Iterator,
+ nsnull, // wrappedObject
+ JSCLASS_NO_RESERVED_MEMBERS
};
} // namespace internal
JSBool
GetWrappedNative(JSContext *cx, JSObject *obj,
XPCWrappedNative **aWrappedNative)
{
@@ -1035,18 +1023,17 @@ static JSFunctionSpec static_functions[]
};
// static
PRBool
XPCNativeWrapper::AttachNewConstructorObject(XPCCallContext &ccx,
JSObject *aGlobalObject)
{
JSObject *class_obj =
- ::JS_InitClass(ccx, aGlobalObject, nsnull,
- js::Jsvalify(&internal::NW_Call_Class),
+ ::JS_InitClass(ccx, aGlobalObject, nsnull, &internal::NW_Call_Class.base,
XPCNativeWrapperCtor, 0, nsnull, nsnull,
nsnull, static_functions);
if (!class_obj) {
NS_WARNING("can't initialize the XPCNativeWrapper class");
return PR_FALSE;
}
// Make sure our prototype chain is empty and that people can't mess
@@ -1054,17 +1041,17 @@ XPCNativeWrapper::AttachNewConstructorOb
::JS_SetPrototype(ccx, class_obj, nsnull);
if (!::JS_SealObject(ccx, class_obj, JS_FALSE)) {
NS_WARNING("Failed to seal XPCNativeWrapper.prototype");
return PR_FALSE;
}
JSBool found;
return ::JS_SetPropertyAttributes(ccx, aGlobalObject,
- internal::NW_Call_Class.name,
+ internal::NW_Call_Class.base.name,
JSPROP_READONLY | JSPROP_PERMANENT,
&found);
}
// static
JSObject *
XPCNativeWrapper::GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper,
JSObject *scope, nsIPrincipal *aObjectPrincipal)
--- a/js/src/xpconnect/src/XPCNativeWrapper.h
+++ b/js/src/xpconnect/src/XPCNativeWrapper.h
@@ -40,40 +40,40 @@
#include "nscore.h"
#include "jsapi.h"
class nsIPrincipal;
namespace XPCNativeWrapper {
namespace internal {
-extern js::Class NW_NoCall_Class;
-extern js::Class NW_Call_Class;
+ extern JSExtendedClass NW_NoCall_Class;
+ extern JSExtendedClass NW_Call_Class;
}
PRBool
AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject);
JSObject *
GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper,
JSObject *scope, nsIPrincipal *aObjectPrincipal);
JSBool
CreateExplicitWrapper(JSContext *cx, XPCWrappedNative *wrapper, jsval *rval);
inline PRBool
-IsNativeWrapperClass(js::Class *clazz)
+IsNativeWrapperClass(JSClass *clazz)
{
- return clazz == &internal::NW_NoCall_Class ||
- clazz == &internal::NW_Call_Class;
+ return clazz == &internal::NW_NoCall_Class.base ||
+ clazz == &internal::NW_Call_Class.base;
}
inline PRBool
IsNativeWrapper(JSObject *obj)
{
- return IsNativeWrapperClass(obj->getClass());
+ return IsNativeWrapperClass(obj->getJSClass());
}
JSBool
GetWrappedNative(JSContext *cx, JSObject *obj,
XPCWrappedNative **aWrappedNative);
// NB: Use the following carefully.
inline XPCWrappedNative *
@@ -81,16 +81,16 @@ SafeGetWrappedNative(JSObject *obj)
{
return static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
}
inline JSClass *
GetJSClass(bool call)
{
return call
- ? js::Jsvalify(&internal::NW_Call_Class)
- : js::Jsvalify(&internal::NW_NoCall_Class);
+ ? &internal::NW_Call_Class.base
+ : &internal::NW_NoCall_Class.base;
}
void
ClearWrappedNativeScopes(JSContext* cx, XPCWrappedNative* wrapper);
}
--- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
@@ -228,17 +228,17 @@ FindObjectPrincipals(JSContext *cx, JSOb
// The wrapper owns the principal now.
return objPrincipal.forget().get();
}
static inline JSObject *
FindSafeObject(JSObject *obj)
{
- while (obj->getClass() != &SJOWClass) {
+ while (obj->getJSClass() != &SJOWClass.base) {
obj = obj->getProto();
if (!obj) {
break;
}
}
return obj;
@@ -248,44 +248,37 @@ static JSBool
XPC_SJOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
namespace XPCSafeJSObjectWrapper {
// JS class for XPCSafeJSObjectWrapper (and this doubles as the
// constructor for XPCSafeJSObjectWrapper for the moment too...)
-js::Class SJOWClass = {
- "XPCSafeJSObjectWrapper",
- JSCLASS_NEW_RESOLVE |
+JSExtendedClass SJOWClass = {
+ // JSClass (JSExtendedClass.base) initialization
+ { "XPCSafeJSObjectWrapper",
+ JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_RESERVED_SLOTS(sSJOWSlots),
- js::Valueify(XPC_SJOW_AddProperty),
- js::Valueify(XPC_SJOW_DelProperty),
- js::Valueify(XPC_SJOW_GetProperty),
- js::Valueify(XPC_SJOW_SetProperty),
- XPC_SJOW_Enumerate,
- (JSResolveOp)XPC_SJOW_NewResolve,
- js::Valueify(XPC_SJOW_Convert),
- XPC_SJOW_Finalize,
- nsnull, // reserved0
- js::Valueify(XPC_SJOW_CheckAccess),
- js::Valueify(XPC_SJOW_Call),
- js::Valueify(XPC_SJOW_Create),
- nsnull, // xdrObject
- nsnull, // hasInstance
- nsnull, // mark
-
- // ClassExtension
- {
- js::Valueify(XPC_SJOW_Equality),
- nsnull, // outerObject
- nsnull, // innerObject
- XPC_SJOW_Iterator,
- XPC_SJOW_WrappedObject
- }
+ XPC_SJOW_AddProperty, XPC_SJOW_DelProperty,
+ XPC_SJOW_GetProperty, XPC_SJOW_SetProperty,
+ XPC_SJOW_Enumerate, (JSResolveOp)XPC_SJOW_NewResolve,
+ XPC_SJOW_Convert, XPC_SJOW_Finalize,
+ nsnull, XPC_SJOW_CheckAccess,
+ XPC_SJOW_Call, XPC_SJOW_Create,
+ nsnull, nsnull,
+ nsnull, nsnull
+ },
+ // JSExtendedClass initialization
+ XPC_SJOW_Equality,
+ nsnull, // outerObject
+ nsnull, // innerObject
+ XPC_SJOW_Iterator,
+ XPC_SJOW_WrappedObject,
+ JSCLASS_NO_RESERVED_MEMBERS
};
JSBool
WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp)
{
// This might be redundant if called from XPC_SJOW_Construct, but it should
// be cheap in that case.
JSObject *objToWrap = UnsafeUnwrapSecurityWrapper(cx, JSVAL_TO_OBJECT(v));
@@ -320,17 +313,17 @@ WrapObject(JSContext *cx, JSObject *scop
}
SLIM_LOG_WILL_MORPH(cx, objToWrap);
if (IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) {
return ThrowException(NS_ERROR_FAILURE, cx);
}
JSObject *wrapperObj =
- JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SJOWClass), nsnull, scope);
+ JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull, scope);
if (!wrapperObj) {
// JS_NewObjectWithGivenProto already threw.
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(wrapperObj);
if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot,
@@ -348,17 +341,17 @@ AttachNewConstructorObject(XPCCallContex
// Initialize sEvalNative the first time we attach a constructor.
// NB: This always happens before any cross origin wrappers are
// created, so it's OK to do this here.
if (!XPCWrapper::FindEval(ccx, aGlobalObject)) {
return PR_FALSE;
}
JSObject *class_obj =
- ::JS_InitClass(ccx, aGlobalObject, nsnull, js::Jsvalify(&SJOWClass),
+ ::JS_InitClass(ccx, aGlobalObject, nsnull, &SJOWClass.base,
XPC_SJOW_Construct, 0, nsnull, nsnull, nsnull, nsnull);
if (!class_obj) {
NS_WARNING("can't initialize the XPCSafeJSObjectWrapper class");
return PR_FALSE;
}
if (!::JS_DefineFunction(ccx, class_obj, "toString", XPC_SJOW_toString,
0, 0)) {
@@ -370,17 +363,17 @@ AttachNewConstructorObject(XPCCallContex
::JS_SetPrototype(ccx, class_obj, nsnull);
if (!::JS_SealObject(ccx, class_obj, JS_FALSE)) {
NS_WARNING("Failed to seal XPCSafeJSObjectWrapper.prototype");
return PR_FALSE;
}
JSBool found;
return ::JS_SetPropertyAttributes(ccx, aGlobalObject,
- SJOWClass.name,
+ SJOWClass.base.name,
JSPROP_READONLY | JSPROP_PERMANENT,
&found);
}
JSObject *
GetUnsafeObject(JSContext *cx, JSObject *obj)
{
obj = FindSafeObject(obj);
@@ -448,17 +441,17 @@ WrapJSValue(JSContext *cx, JSObject *obj
if (!RewrapObject(cx, obj->getParent(), JSVAL_TO_OBJECT(val), SJOW,
rval)) {
return JS_FALSE;
}
// Construct a new safe wrapper. Note that it doesn't matter what
// parent we pass in here, the construct hook will ensure we get
// the right parent for the wrapper.
JSObject *safeObj = JSVAL_TO_OBJECT(*rval);
- if (safeObj->getClass() == &SJOWClass &&
+ if (safeObj->getJSClass() == &SJOWClass.base &&
JS_GetGlobalForObject(cx, obj) != JS_GetGlobalForObject(cx, safeObj)) {
// Check to see if the new object we just wrapped is accessible
// from the unsafe object we got the new object through. If not,
// force the new wrapper to use the principal of the unsafe
// object we got the new object from.
nsCOMPtr<nsIPrincipal> srcObjPrincipal;
nsCOMPtr<nsIPrincipal> subjPrincipal;
nsCOMPtr<nsIPrincipal> valObjPrincipal;
@@ -1032,17 +1025,17 @@ XPC_SJOW_Iterator(JSContext *cx, JSObjec
// Check that the caller can access the unsafe object.
if (!CanCallerAccess(cx, obj, unsafeObj)) {
// CanCallerAccess() already threw for us.
return nsnull;
}
// Create our dummy SJOW.
JSObject *wrapperIter =
- JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SJOWClass), nsnull,
+ JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) {
return nsnull;
}
if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot,
OBJECT_TO_JSVAL(unsafeObj)) ||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot,
--- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
@@ -93,58 +93,52 @@ ThrowException(nsresult rv, JSContext *c
{
return DoThrowException(rv, cx);
}
static const char prefix[] = "chrome://global/";
namespace SystemOnlyWrapper {
-js::Class SOWClass = {
- "SystemOnlyWrapper",
- JSCLASS_NEW_RESOLVE |
+JSExtendedClass SOWClass = {
+ // JSClass (JSExtendedClass.base) initialization
+ { "SystemOnlyWrapper",
+ JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots),
- js::Valueify(XPC_SOW_AddProperty),
- js::Valueify(XPC_SOW_DelProperty),
- js::Valueify(XPC_SOW_GetProperty),
- js::Valueify(XPC_SOW_SetProperty),
- XPC_SOW_Enumerate,
- (JSResolveOp)XPC_SOW_NewResolve,
- js::Valueify(XPC_SOW_Convert),
- nsnull, // finalize
- nsnull, // reserved0
- js::Valueify(XPC_SOW_CheckAccess),
- nsnull, // call
- nsnull, // construct
- nsnull, // xdrObject
- js::Valueify(XPC_SOW_HasInstance),
- nsnull, // mark
+ XPC_SOW_AddProperty, XPC_SOW_DelProperty,
+ XPC_SOW_GetProperty, XPC_SOW_SetProperty,
+ XPC_SOW_Enumerate, (JSResolveOp)XPC_SOW_NewResolve,
+ XPC_SOW_Convert, nsnull,
+ nsnull, XPC_SOW_CheckAccess,
+ nsnull, nsnull,
+ nsnull, XPC_SOW_HasInstance,
+ nsnull, nsnull
+ },
- // ClassExtension
- {
- js::Valueify(XPC_SOW_Equality),
- nsnull, // outerObject
- nsnull, // innerObject
- XPC_SOW_Iterator,
- XPC_SOW_WrappedObject
- }
+ // JSExtendedClass initialization
+ XPC_SOW_Equality,
+ nsnull, // outerObject
+ nsnull, // innerObject
+ XPC_SOW_Iterator,
+ XPC_SOW_WrappedObject,
+ JSCLASS_NO_RESERVED_MEMBERS
};
JSBool
WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp)
{
// Slim wrappers don't expect to be wrapped, so morph them to fat wrappers
// if we're about to wrap one.
JSObject *innerObj = JSVAL_TO_OBJECT(v);
if (IS_SLIM_WRAPPER(innerObj) && !MorphSlimWrapper(cx, innerObj)) {
return ThrowException(NS_ERROR_FAILURE, cx);
}
JSObject *wrapperObj =
- JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SOWClass), NULL, parent);
+ JS_NewObjectWithGivenProto(cx, &SOWClass.base, NULL, parent);
if (!wrapperObj) {
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(wrapperObj);
js::AutoObjectRooter tvr(cx, wrapperObj);
if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) ||
@@ -155,19 +149,19 @@ WrapObject(JSContext *cx, JSObject *pare
return JS_TRUE;
}
JSBool
MakeSOW(JSContext *cx, JSObject *obj)
{
#ifdef DEBUG
{
- js::Class *clasp = obj->getClass();
- NS_ASSERTION(clasp != &SystemOnlyWrapper::SOWClass &&
- clasp != &XPCCrossOriginWrapper::XOWClass,
+ JSClass *clasp = obj->getJSClass();
+ NS_ASSERTION(clasp != &SystemOnlyWrapper::SOWClass.base &&
+ clasp != &XPCCrossOriginWrapper::XOWClass.base,
"bad call");
}
#endif
jsval flags;
return JS_GetReservedSlot(cx, obj, sFlagsSlot, &flags) &&
JS_SetReservedSlot(cx, obj, sFlagsSlot,
INT_TO_JSVAL(JSVAL_TO_INT(flags) | FLAG_SOW));
@@ -269,27 +263,35 @@ CheckFilename(JSContext *cx, jsid id, JS
using namespace SystemOnlyWrapper;
// Like GetWrappedObject, but works on other types of wrappers, too.
// TODO Move to XPCWrapper?
static inline JSObject *
GetWrappedJSObject(JSContext *cx, JSObject *obj)
{
- if (JSObjectOp op = obj->getClass()->ext.wrappedObject)
- return op(cx, obj);
- return obj;
+ JSClass *clasp = obj->getJSClass();
+ if (!(clasp->flags & JSCLASS_IS_EXTENDED)) {
+ return obj;
+ }
+
+ JSExtendedClass *xclasp = (JSExtendedClass *)clasp;
+ if (!xclasp->wrappedObject) {
+ return obj;
+ }
+
+ return xclasp->wrappedObject(cx, obj);
}
// Get the (possibly nonexistent) SOW off of an object
static inline
JSObject *
GetWrapper(JSObject *obj)
{
- while (obj->getClass() != &SOWClass) {
+ while (obj->getJSClass() != &SOWClass.base) {
obj = obj->getProto();
if (!obj) {
break;
}
}
return obj;
}
@@ -398,17 +400,17 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObj
return JS_FALSE;
}
obj = JSVAL_TO_OBJECT(v);
}
return XPC_SOW_WrapFunction(cx, wrapperObj, obj, vp);
}
- if (obj->getClass() == &SOWClass) {
+ if (obj->getJSClass() == &SOWClass.base) {
// We are extra careful about content-polluted wrappers here. I don't know
// if it's possible to reach them through objects that we wrap, but figuring
// that out is more expensive (and harder) than simply checking and
// rewrapping here.
if (wrapperObj->getParent() == obj->getParent()) {
// Already wrapped.
return JS_TRUE;
}
@@ -423,17 +425,17 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObj
}
return WrapObject(cx, wrapperObj->getParent(), v, vp);
}
static JSBool
XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
- NS_ASSERTION(obj->getClass() == &SOWClass, "Wrong object");
+ NS_ASSERTION(obj->getJSClass() == &SOWClass.base, "Wrong object");
jsval resolving;
if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &resolving)) {
return JS_FALSE;
}
if (HAS_FLAGS(resolving, FLAG_RESOLVING)) {
// Allow us to define a property on ourselves.
@@ -646,42 +648,49 @@ XPC_SOW_Equality(JSContext *cx, JSObject
JSObject *lhs = GetWrappedObject(cx, obj);
JSObject *rhs = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v));
if (lhs == rhs) {
*bp = JS_TRUE;
return JS_TRUE;
}
if (lhs) {
- if (JSEqualityOp op = js::Jsvalify(lhs->getClass()->ext.equality)) {
+ // Delegate to our wrapped object if we can.
+ JSClass *clasp = lhs->getJSClass();
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ JSExtendedClass *xclasp = (JSExtendedClass *) clasp;
+ // NB: JSExtendedClass.equality is a required field.
jsval rhsVal = OBJECT_TO_JSVAL(rhs);
- return op(cx, lhs, &rhsVal, bp);
+ return xclasp->equality(cx, lhs, &rhsVal, bp);
}
}
// We know rhs is non-null.
- if (JSEqualityOp op = js::Jsvalify(rhs->getClass()->ext.equality)) {
+ JSClass *clasp = rhs->getJSClass();
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ JSExtendedClass *xclasp = (JSExtendedClass *) clasp;
+ // NB: JSExtendedClass.equality is a required field.
jsval lhsVal = OBJECT_TO_JSVAL(lhs);
- return op(cx, rhs, &lhsVal, bp);
+ return xclasp->equality(cx, rhs, &lhsVal, bp);
}
*bp = JS_FALSE;
return JS_TRUE;
}
static JSObject *
XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
{
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
ThrowException(NS_ERROR_INVALID_ARG, cx);
return nsnull;
}
- JSObject *wrapperIter = JS_NewObject(cx, js::Jsvalify(&SOWClass), nsnull,
+ JSObject *wrapperIter = JS_NewObject(cx, &SOWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) {
return nsnull;
}
js::AutoObjectRooter tvr(cx, wrapperIter);
// Initialize our SOW.
--- a/js/src/xpconnect/src/XPCWrapper.cpp
+++ b/js/src/xpconnect/src/XPCWrapper.cpp
@@ -55,48 +55,48 @@ const PRUint32 FLAG_SOW = 0x2;
const PRUint32 LAST_FLAG = FLAG_SOW;
const PRUint32 sSecMgrSetProp = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
const PRUint32 sSecMgrGetProp = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
JSObject *
Unwrap(JSContext *cx, JSObject *wrapper)
{
- js::Class *clasp = wrapper->getClass();
- if (clasp == &XPCCrossOriginWrapper::XOWClass) {
+ JSClass *clasp = wrapper->getJSClass();
+ if (clasp == &XPCCrossOriginWrapper::XOWClass.base) {
return UnwrapXOW(cx, wrapper);
}
if (XPCNativeWrapper::IsNativeWrapperClass(clasp)) {
XPCWrappedNative *wrappedObj;
if (!XPCNativeWrapper::GetWrappedNative(cx, wrapper, &wrappedObj) ||
!wrappedObj) {
return nsnull;
}
return wrappedObj->GetFlatJSObject();
}
- if (clasp == &XPCSafeJSObjectWrapper::SJOWClass) {
+ if (clasp == &XPCSafeJSObjectWrapper::SJOWClass.base) {
JSObject *wrappedObj =
XPCSafeJSObjectWrapper::GetUnsafeObject(cx, wrapper);
if (NS_FAILED(XPCCrossOriginWrapper::CanAccessWrapper(cx, nsnull, wrappedObj, nsnull))) {
JS_ClearPendingException(cx);
return nsnull;
}
return wrappedObj;
}
- if (clasp == &SystemOnlyWrapper::SOWClass) {
+ if (clasp == &SystemOnlyWrapper::SOWClass.base) {
return UnwrapSOW(cx, wrapper);
}
- if (clasp == &ChromeObjectWrapper::COWClass) {
+ if (clasp == &ChromeObjectWrapper::COWClass.base) {
return UnwrapCOW(cx, wrapper);
}
return nsnull;
}
static void
IteratorFinalize(JSContext *cx, JSObject *obj)
@@ -155,43 +155,32 @@ IteratorNext(JSContext *cx, uintN argc,
}
static JSObject *
IteratorIterator(JSContext *, JSObject *obj, JSBool)
{
return obj;
}
-static js::Class IteratorClass = {
- "Wrapper iterator",
- JSCLASS_HAS_RESERVED_SLOTS(3),
- js::PropertyStub, // addProperty
- js::PropertyStub, // delProperty
- js::PropertyStub, // getProperty
- js::PropertyStub, // setProperty
- JS_EnumerateStub,
- JS_ResolveStub,
- js::ConvertStub,
- IteratorFinalize,
- nsnull, // reserved0
- nsnull, // checkAccess
- nsnull, // call
- nsnull, // construct
- nsnull, // xdrObject
- nsnull, // hasInstance
- nsnull, // mark
+static JSExtendedClass IteratorClass = {
+ { "Wrapper iterator",
+ JSCLASS_HAS_RESERVED_SLOTS(3) | JSCLASS_IS_EXTENDED,
+ JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub,
+ JS_ConvertStub, IteratorFinalize,
- // ClassExtension
- {
- nsnull, // equality
- nsnull, // outerObject
- nsnull, // innerObject
- IteratorIterator,
- nsnull, // wrappedObject
- }
+ JSCLASS_NO_OPTIONAL_MEMBERS
+ },
+
+ nsnull, // equality
+ nsnull, nsnull, // innerObject/outerObject
+ IteratorIterator,
+ nsnull, // wrappedObject
+ JSCLASS_NO_RESERVED_MEMBERS
};
JSBool
RewrapObject(JSContext *cx, JSObject *scope, JSObject *obj, WrapperType hint,
jsval *vp)
{
obj = UnsafeUnwrapSecurityWrapper(cx, obj);
if (!obj) {
@@ -337,17 +326,17 @@ CreateIteratorObj(JSContext *cx, JSObjec
{
// This is rather ugly: we want to use the trick seen in Enumerate,
// where we use our wrapper's resolve hook to determine if we should
// enumerate a given property. However, we don't want to pollute the
// identifiers with a next method, so we create an object that
// delegates (via the __proto__ link) to the wrapper.
JSObject *iterObj =
- JS_NewObjectWithGivenProto(cx, js::Jsvalify(&IteratorClass), tempWrapper, wrapperObj);
+ JS_NewObjectWithGivenProto(cx, &IteratorClass.base, tempWrapper, wrapperObj);
if (!iterObj) {
return nsnull;
}
js::AutoObjectRooter tvr(cx, iterObj);
// Do this sooner rather than later to avoid complications in
// IteratorFinalize.
@@ -400,17 +389,17 @@ SimpleEnumerate(JSContext *cx, JSObject
return JS_TRUE;
}
JSObject *
CreateSimpleIterator(JSContext *cx, JSObject *scope, JSBool keysonly,
JSObject *propertyContainer)
{
- JSObject *iterObj = JS_NewObjectWithGivenProto(cx, js::Jsvalify(&IteratorClass),
+ JSObject *iterObj = JS_NewObjectWithGivenProto(cx, &IteratorClass.base,
propertyContainer, scope);
if (!iterObj) {
return nsnull;
}
js::AutoObjectRooter tvr(cx, iterObj);
if (!propertyContainer) {
if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(nsnull)) ||
--- a/js/src/xpconnect/src/XPCWrapper.h
+++ b/js/src/xpconnect/src/XPCWrapper.h
@@ -157,20 +157,20 @@ MakeSOW(JSContext *cx, JSObject *obj);
JSBool
AllowedToAct(JSContext *cx, jsid id);
JSBool
CheckFilename(JSContext *cx, jsid id, JSStackFrame *fp);
}
-namespace ChromeObjectWrapper { extern js::Class COWClass; }
-namespace XPCSafeJSObjectWrapper { extern js::Class SJOWClass; }
-namespace SystemOnlyWrapper { extern js::Class SOWClass; }
-namespace XPCCrossOriginWrapper { extern js::Class XOWClass; }
+namespace ChromeObjectWrapper { extern JSExtendedClass COWClass; }
+namespace XPCSafeJSObjectWrapper { extern JSExtendedClass SJOWClass; }
+namespace SystemOnlyWrapper { extern JSExtendedClass SOWClass; }
+namespace XPCCrossOriginWrapper { extern JSExtendedClass XOWClass; }
extern nsIScriptSecurityManager *gScriptSecurityManager;
// This namespace wraps some common functionality between the three existing
// wrappers. Its main purpose is to allow XPCCrossOriginWrapper to act both
// as an XPCSafeJSObjectWrapper and as an XPCNativeWrapper when required to
// do so (the decision is based on the principals of the wrapper and wrapped
// objects).
@@ -316,17 +316,19 @@ MaybePreserveWrapper(JSContext *cx, XPCW
ci->PreserveWrapper(wn->Native());
}
}
}
inline JSBool
IsSecurityWrapper(JSObject *wrapper)
{
- return !!wrapper->getClass()->ext.wrappedObject;
+ JSClass *clasp = wrapper->getJSClass();
+ return (clasp->flags & JSCLASS_IS_EXTENDED) &&
+ ((JSExtendedClass*)clasp)->wrappedObject;
}
/**
* Given an arbitrary object, Unwrap will return the wrapped object if the
* passed-in object is a wrapper that Unwrap knows about *and* the
* currently running code has permission to access both the wrapper and
* wrapped object.
*
@@ -336,19 +338,19 @@ IsSecurityWrapper(JSObject *wrapper)
*/
JSObject *
Unwrap(JSContext *cx, JSObject *wrapper);
/**
* Unwraps objects whose class is |xclasp|.
*/
inline JSObject *
-UnwrapGeneric(JSContext *cx, const js::Class *xclasp, JSObject *wrapper)
+UnwrapGeneric(JSContext *cx, const JSExtendedClass *xclasp, JSObject *wrapper)
{
- if (wrapper->getClass() != xclasp) {
+ if (wrapper->getJSClass() != &xclasp->base) {
return nsnull;
}
jsval v;
if (!JS_GetReservedSlot(cx, wrapper, XPCWrapper::sWrappedObjSlot, &v)) {
JS_ClearPendingException(cx);
return nsnull;
}
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -622,30 +622,30 @@ nsXPConnect::IsGray(void *thing)
NS_IMETHODIMP
nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
{
JSContext *cx = mCycleCollectionContext->GetJSContext();
uint32 traceKind = js_GetGCThingTraceKind(p);
JSObject *obj;
- js::Class *clazz;
+ JSClass *clazz;
// We do not want to add wrappers to the cycle collector if they're not
// explicitly marked as main thread only, because the cycle collector isn't
// able to deal with objects that might be used off of the main thread. We
// do want to explicitly mark them for cycle collection if the wrapper has
// an external reference, because the wrapper would mark the JS object if
// we did add the wrapper to the cycle collector.
JSBool dontTraverse = PR_FALSE;
JSBool markJSObject = PR_FALSE;
if(traceKind == JSTRACE_OBJECT)
{
obj = static_cast<JSObject*>(p);
- clazz = obj->getClass();
+ clazz = obj->getJSClass();
if(clazz == &XPC_WN_Tearoff_JSClass)
{
XPCWrappedNative *wrapper =
(XPCWrappedNative*)xpc_GetJSPrivate(obj->getParent());
dontTraverse = WrapperIsNotMainThreadOnly(wrapper);
}
else if(IS_WRAPPER_CLASS(clazz) && IS_WN_WRAPPER_OBJECT(obj))
@@ -684,17 +684,17 @@ nsXPConnect::Traverse(void *p, nsCycleCo
type = !markJSObject && IsGray(p) ? GCUnmarked : GCMarked;
}
if (cb.WantDebugInfo()) {
char name[72];
if(traceKind == JSTRACE_OBJECT)
{
JSObject *obj = static_cast<JSObject*>(p);
- js::Class *clazz = obj->getClass();
+ JSClass *clazz = obj->getJSClass();
if(XPCNativeWrapper::IsNativeWrapperClass(clazz))
{
XPCWrappedNative* wn;
if(XPCNativeWrapper::GetWrappedNative(cx, obj, &wn) && wn)
{
XPCNativeScriptableInfo* si = wn->GetScriptableInfo();
if(si)
{
@@ -744,31 +744,31 @@ nsXPConnect::Traverse(void *p, nsCycleCo
(XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
si = p->GetScriptableInfo();
}
if(si)
{
JS_snprintf(name, sizeof(name), "JS Object (%s - %s)",
clazz->name, si->GetJSClass()->name);
}
- else if(clazz == &js_ScriptClass)
+ else if(clazz == Jsvalify(&js_ScriptClass))
{
JSScript* script = (JSScript*) xpc_GetJSPrivate(obj);
if(script->filename)
{
JS_snprintf(name, sizeof(name),
"JS Object (Script - %s)",
script->filename);
}
else
{
JS_snprintf(name, sizeof(name), "JS Object (Script)");
}
}
- else if(clazz == &js_FunctionClass)
+ else if(clazz == Jsvalify(&js_FunctionClass))
{
JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj);
JSString* str = JS_GetFunctionId(fun);
if(str)
{
NS_ConvertUTF16toUTF8
fname(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)));
JS_snprintf(name, sizeof(name),
@@ -1011,16 +1011,19 @@ nsXPConnect::InitClasses(JSContext * aJS
// Nest frame chain save/restore in request created by XPCCallContext.
XPCCallContext ccx(NATIVE_CALLER, aJSContext);
if(!ccx.IsValid())
return UnexpectedFailure(NS_ERROR_FAILURE);
SaveFrame sf(aJSContext);
xpc_InitJSxIDClassObjects();
+ if(!xpc_InitWrappedNativeJSOps())
+ return UnexpectedFailure(NS_ERROR_FAILURE);
+
XPCWrappedNativeScope* scope =
XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj);
if(!scope)
return UnexpectedFailure(NS_ERROR_FAILURE);
scope->RemoveWrappedNativeProtos();
@@ -1909,17 +1912,17 @@ nsXPConnect::RestoreWrappedNativePrototy
if(!aClassInfo || !aPrototype)
return UnexpectedFailure(NS_ERROR_INVALID_ARG);
JSObject *protoJSObject;
nsresult rv = aPrototype->GetJSObject(&protoJSObject);
if(NS_FAILED(rv))
return UnexpectedFailure(rv);
- if(!IS_PROTO_CLASS(protoJSObject->getClass()))
+ if(!IS_PROTO_CLASS(protoJSObject->getJSClass()))
return UnexpectedFailure(NS_ERROR_INVALID_ARG);
XPCWrappedNativeScope* scope =
XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
if(!scope)
return UnexpectedFailure(NS_ERROR_FAILURE);
XPCWrappedNativeProto *proto =
--- a/js/src/xpconnect/src/xpcJSWeakReference.cpp
+++ b/js/src/xpconnect/src/xpcJSWeakReference.cpp
@@ -129,18 +129,18 @@ xpcJSWeakReference::Get()
// Most users of XPCWrappedJS don't need to worry about
// re-wrapping because things are implicitly rewrapped by
// xpcconvert. However, because we're doing this directly
// through the native call context, we need to call
// nsXPConnect::GetWrapperForObject. But it takes a lot of
// arguments! It turns out that the thisObject hook on XPConnect
// objects does the right thing though, so...
- if (obj->getOps()->thisObject &&
- !(obj = obj->getOps()->thisObject(cx, obj)))
+ if (obj->map->ops->thisObject &&
+ !(obj = obj->map->ops->thisObject(cx, obj)))
{
return NS_ERROR_FAILURE;
}
*retval = OBJECT_TO_JSVAL(obj);
}
}
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -3112,17 +3112,17 @@ static JSBool
sandbox_setProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
if (!JSVAL_IS_OBJECT(*vp)) {
return JS_TRUE;
}
JSObject *pobj = JSVAL_TO_OBJECT(*vp);
if (pobj) {
- if (pobj->getClass() == &XPCCrossOriginWrapper::XOWClass &&
+ if (pobj->getJSClass() == &XPCCrossOriginWrapper::XOWClass.base &&
!XPCWrapper::RewrapObject(cx, obj, pobj,
XPCWrapper::XPCNW_EXPLICIT, vp)) {
return JS_FALSE;
}
}
return JS_SetPrototype(cx, obj, JSVAL_TO_OBJECT(*vp));
}
@@ -3820,19 +3820,23 @@ nsXPCComponents_Utils::GetGlobalForObjec
// first argument must be an object
if(JSVAL_IS_PRIMITIVE(argv[0]))
return NS_ERROR_XPC_BAD_CONVERT_JS;
JSObject *obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(argv[0]));
*rval = OBJECT_TO_JSVAL(obj);
- // Outerize if necessary.
- if (JSObjectOp outerize = obj->getClass()->ext.outerObject)
+ // Outerize if necessary. Embrace the ugliness!
+ JSClass *clasp = JS_GetClass(cx, obj);
+ if (clasp->flags & JSCLASS_IS_EXTENDED) {
+ JSExtendedClass *xclasp = reinterpret_cast<JSExtendedClass *>(clasp);
+ if (JSObjectOp outerize = xclasp->outerObject)
*rval = OBJECT_TO_JSVAL(outerize(cx, obj));
+ }
cc->SetReturnValueWasSet(PR_TRUE);
return NS_OK;
}
#ifdef XPC_USE_SECURITY_CHECKED_COMPONENT
/* string canCreateWrapper (in nsIIDPtr iid); */
NS_IMETHODIMP
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -1262,102 +1262,60 @@ private:
* Core classes for wrapped native objects for use from JavaScript...
*
****************************************************************************
***************************************************************************/
// These are the various JSClasses and callbacks whose use that required
// visibility from more than one .cpp file.
-extern js::Class XPC_WN_NoHelper_JSClass;
-extern js::Class XPC_WN_NoMods_WithCall_Proto_JSClass;
-extern js::Class XPC_WN_NoMods_NoCall_Proto_JSClass;
-extern js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass;
-extern js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
-extern js::Class XPC_WN_Tearoff_JSClass;
-extern js::Class XPC_WN_NoHelper_Proto_JSClass;
+extern JSExtendedClass XPC_WN_NoHelper_JSClass;
+extern JSClass XPC_WN_NoMods_WithCall_Proto_JSClass;
+extern JSClass XPC_WN_NoMods_NoCall_Proto_JSClass;
+extern JSClass XPC_WN_ModsAllowed_WithCall_Proto_JSClass;
+extern JSClass XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
+extern JSClass XPC_WN_Tearoff_JSClass;
+extern JSClass XPC_WN_NoHelper_Proto_JSClass;
extern JSBool
XPC_WN_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp);
+extern JSObjectOps *
+XPC_WN_Proto_GetObjectOps(JSContext *cx, JSClass *clazz);
+
extern JSBool
XPC_WN_CallMethod(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *vp);
extern JSBool
XPC_WN_GetterSetter(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *vp);
extern JSBool
-XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
- jsval *statep, jsid *idp);
-
-extern JSType
-XPC_WN_JSOp_TypeOf_Object(JSContext *cx, JSObject *obj);
-
-extern JSType
-XPC_WN_JSOp_TypeOf_Function(JSContext *cx, JSObject *obj);
-
-extern void
-XPC_WN_JSOp_Clear(JSContext *cx, JSObject *obj);
-
-extern JSObject*
-XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj);
-
-// Macros to initialize Object or Function like XPC_WN classes
-#define XPC_WN_WithCall_ObjectOps \
- { \
- nsnull, /* lookupProperty */ \
- nsnull, /* defineProperty */ \
- nsnull, /* getProperty */ \
- nsnull, /* setProperty */ \
- nsnull, /* getAttributes */ \
- nsnull, /* setAttributes */ \
- nsnull, /* deleteProperty */ \
- js::Valueify(XPC_WN_JSOp_Enumerate), \
- XPC_WN_JSOp_TypeOf_Function, \
- nsnull, /* trace */ \
- XPC_WN_JSOp_ThisObject, \
- XPC_WN_JSOp_Clear \
- }
-
-#define XPC_WN_NoCall_ObjectOps \
- { \
- nsnull, /* lookupProperty */ \
- nsnull, /* defineProperty */ \
- nsnull, /* getProperty */ \
- nsnull, /* setProperty */ \
- nsnull, /* getAttributes */ \
- nsnull, /* setAttributes */ \
- nsnull, /* deleteProperty */ \
- js::Valueify(XPC_WN_JSOp_Enumerate), \
- XPC_WN_JSOp_TypeOf_Object, \
- nsnull, /* trace */ \
- XPC_WN_JSOp_ThisObject, \
- XPC_WN_JSOp_Clear \
- }
+xpc_InitWrappedNativeJSOps();
// Maybe this macro should check for class->enumerate ==
// XPC_WN_Shared_Proto_Enumerate or something rather than checking for
// 4 classes?
#define IS_PROTO_CLASS(clazz) \
- ((clazz) == &XPC_WN_NoMods_WithCall_Proto_JSClass || \
- (clazz) == &XPC_WN_NoMods_NoCall_Proto_JSClass || \
- (clazz) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass || \
- (clazz) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass)
+ ((clazz) == &XPC_WN_NoMods_WithCall_Proto_JSClass || \
+ (clazz) == &XPC_WN_NoMods_NoCall_Proto_JSClass || \
+ (clazz) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass || \
+ (clazz) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass)
// NOTE!!!
//
// If this ever changes,
// nsScriptSecurityManager::doGetObjectPrincipal() *must* be updated
// also!
//
// NOTE!!!
#define IS_WRAPPER_CLASS(clazz) \
- (clazz->ext.equality == js::Valueify(XPC_WN_Equality))
+ (((clazz)->flags & JSCLASS_IS_EXTENDED) && \
+ reinterpret_cast<JSExtendedClass*>(clazz)->equality == XPC_WN_Equality)
inline JSBool
DebugCheckWrapperClass(JSObject* obj)
{
NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()),
"Forgot to check if this is a wrapper?");
return JS_TRUE;
}
@@ -1952,30 +1910,28 @@ public:
// XPCNativeScriptableShared is used to hold the JSClass and the
// associated scriptable flags for XPCWrappedNatives. These are shared across
// the runtime and are garbage collected by xpconnect. We *used* to just store
// this inside the XPCNativeScriptableInfo (usually owned by instances of
// XPCWrappedNativeProto. This had two problems... It was wasteful, and it
// was a big problem when wrappers are reparented to different scopes (and
// thus different protos (the DOM does this).
-struct XPCNativeScriptableSharedJSClass
+struct XPCNativeScriptableSharedJSClass : public JSExtendedClass
{
- js::Class base;
PRUint32 interfacesBitmap;
};
class XPCNativeScriptableShared
{
public:
const XPCNativeScriptableFlags& GetFlags() const {return mFlags;}
PRUint32 GetInterfacesBitmap() const
{return mJSClass.interfacesBitmap;}
- JSClass* GetJSClass()
- {return js::Jsvalify(&mJSClass.base);}
+ JSClass* GetJSClass() {return &mJSClass.base;}
JSClass* GetSlimJSClass()
{if(mCanBeSlim) return GetJSClass(); return nsnull;}
XPCNativeScriptableShared(JSUint32 aFlags, char* aName,
PRUint32 interfacesBitmap)
: mFlags(aFlags),
mCanBeSlim(JS_FALSE)
{memset(&mJSClass, 0, sizeof(mJSClass));
--- a/js/src/xpconnect/src/xpcquickstubs.cpp
+++ b/js/src/xpconnect/src/xpcquickstubs.cpp
@@ -291,17 +291,17 @@ LookupGetterOrSetter(JSContext *cx, JSBo
// ensuring that we have an XPConnect prototype object ensures that
// we are only going to expose quickstubbed properties to script.
// Also be careful not to overwrite existing properties!
const char *name = JSVAL_IS_STRING(idval)
? JS_GetStringBytes(JSVAL_TO_STRING(idval))
: nsnull;
if(!name ||
- !IS_PROTO_CLASS(desc.obj->getClass()) ||
+ !IS_PROTO_CLASS(desc.obj->getJSClass()) ||
(desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
!(desc.getter || desc.setter) ||
desc.setter == desc.obj->getJSClass()->setProperty)
{
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
@@ -358,17 +358,17 @@ DefineGetterOrSetter(JSContext *cx, uint
&found, &getter, &setter)))
return JS_FALSE;
// The property didn't exist, already has a getter or setter, or is not
// our property, then just forward now.
if(!obj2 ||
(attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
!(getter || setter) ||
- !IS_PROTO_CLASS(obj2->getClass()))
+ !IS_PROTO_CLASS(obj2->getJSClass()))
return forward(cx, argc, vp);
// Reify the getter and setter...
if(!ReifyPropertyOps(cx, obj, id, interned_id, name, getter, setter,
nsnull, nsnull))
return JS_FALSE;
return forward(cx, argc, vp);
@@ -499,18 +499,18 @@ GetMemberInfo(JSObject *obj,
{
// Get the interface name. From DefinePropertyIfFound (in
// xpcwrappednativejsops.cpp) and XPCThrower::Verbosify.
//
// We could instead make the quick stub could pass in its interface name,
// but this code often produces a more specific error message, e.g.
*ifaceName = "Unknown";
- NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()) ||
- obj->getClass() == &XPC_WN_Tearoff_JSClass,
+ NS_ASSERTION(IS_WRAPPER_CLASS(obj->getJSClass()) ||
+ obj->getJSClass() == &XPC_WN_Tearoff_JSClass,
"obj must be a wrapper");
XPCWrappedNativeProto *proto;
if(IS_SLIM_WRAPPER(obj))
{
proto = GetSlimWrapperProto(obj);
}
else
{
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -1119,19 +1119,17 @@ XPCWrappedNative::Init(XPCCallContext& c
if(HasProto() && !HasSharedProto())
GetProto()->SetScriptableInfo(mScriptableInfo);
}
}
XPCNativeScriptableInfo* si = mScriptableInfo;
// create our flatJSObject
- js::Class* jsclazz = si
- ? js::Valueify(si->GetJSClass())
- : &XPC_WN_NoHelper_JSClass;
+ JSClass* jsclazz = si ? si->GetJSClass() : &XPC_WN_NoHelper_JSClass.base;
if(isGlobal)
{
// Resolving a global object's class can cause us to create a global's
// JS class without the proper global flags. Notice that here and fix
// the problem.
if(!(jsclazz->flags & JSCLASS_IS_GLOBAL))
jsclazz->flags |= JSCLASS_GLOBAL_FLAGS;
@@ -1155,18 +1153,18 @@ XPCWrappedNative::Init(XPCCallContext& c
JSObject* protoJSObject = HasProto() ?
GetProto()->GetJSProtoObject() :
GetScope()->GetPrototypeNoHelper(ccx);
if (!protoJSObject) {
return JS_FALSE;
}
- mFlatJSObject = xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(jsclazz),
- protoJSObject, parent);
+ mFlatJSObject = xpc_NewSystemInheritingJSObject(ccx, jsclazz, protoJSObject,
+ parent);
if(!mFlatJSObject)
return JS_FALSE;
return FinishInit(ccx);
}
JSBool
XPCWrappedNative::Init(XPCCallContext &ccx, JSObject *existingJSObject)
@@ -1680,17 +1678,17 @@ XPCWrappedNative::GetWrappedNativeOfJSOb
// If we were passed a function object then we need to find the correct
// wrapper out of those that might be in the callee obj's proto chain.
if(funobj)
{
JSObject* funObjParent = funobj->getParent();
NS_ASSERTION(funObjParent, "funobj has no parent");
- js::Class* funObjParentClass = funObjParent->getClass();
+ JSClass* funObjParentClass = funObjParent->getJSClass();
if(IS_PROTO_CLASS(funObjParentClass))
{
NS_ASSERTION(funObjParent->getParent(), "funobj's parent (proto) is global");
proto = (XPCWrappedNativeProto*) xpc_GetJSPrivate(funObjParent);
if(proto)
protoClassInfo = proto->GetClassInfo();
}
@@ -1710,18 +1708,18 @@ XPCWrappedNative::GetWrappedNativeOfJSOb
NS_ERROR("function object has parent of unknown class!");
return nsnull;
}
}
for(cur = obj; cur; cur = cur->getProto())
{
// this is on two lines to make the compiler happy given the goto.
- js::Class* clazz;
- clazz = cur->getClass();
+ JSClass* clazz;
+ clazz = cur->getJSClass();
if(IS_WRAPPER_CLASS(clazz))
{
return_wrapper:
JSBool isWN = IS_WN_WRAPPER_OBJECT(cur);
XPCWrappedNative* wrapper =
isWN ? (XPCWrappedNative*) xpc_GetJSPrivate(cur) : nsnull;
if(proto)
@@ -1768,19 +1766,22 @@ return_tearoff:
if((unsafeObj = XPCWrapper::Unwrap(cx, cur)))
return GetWrappedNativeOfJSObject(cx, unsafeObj, funobj, pobj2,
pTearOff);
}
// If we didn't find a wrapper using the given funobj and obj, try
// again with obj's outer object, if it's got one.
- if(JSObjectOp op = obj->getClass()->ext.outerObject)
+ JSClass *clazz = obj->getJSClass();
+
+ if((clazz->flags & JSCLASS_IS_EXTENDED) &&
+ ((JSExtendedClass*)clazz)->outerObject)
{
- JSObject *outer = op(cx, obj);
+ JSObject *outer = ((JSExtendedClass*)clazz)->outerObject(cx, obj);
if(outer && outer != obj)
return GetWrappedNativeOfJSObject(cx, outer, funobj, pobj2,
pTearOff);
}
if(pobj2)
*pobj2 = nsnull;
return nsnull;
@@ -2112,17 +2113,17 @@ XPCWrappedNative::InitTearOff(XPCCallCon
JSBool
XPCWrappedNative::InitTearOffJSObject(XPCCallContext& ccx,
XPCWrappedNativeTearOff* to)
{
// This is only called while locked (during XPCWrappedNative::FindTearOff).
JSObject* obj =
- xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(&XPC_WN_Tearoff_JSClass),
+ xpc_NewSystemInheritingJSObject(ccx, &XPC_WN_Tearoff_JSClass,
GetScope()->GetPrototypeJSObject(),
mFlatJSObject);
if(!obj || !JS_SetPrivate(ccx, obj, to))
return JS_FALSE;
to->SetJSObject(obj);
return JS_TRUE;
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -808,17 +808,17 @@ XPC_WN_Equality(JSContext *cx, JSObject
XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
if(si && si->GetFlags().WantEquality())
{
nsresult rv = si->GetCallback()->Equality(wrapper, cx, obj, v, bp);
if(NS_FAILED(rv))
return Throw(rv, cx);
if(!*bp && !JSVAL_IS_PRIMITIVE(v) &&
- JSVAL_TO_OBJECT(v)->getClass() == &XPCSafeJSObjectWrapper::SJOWClass)
+ JSVAL_TO_OBJECT(v)->getJSClass() == &XPCSafeJSObjectWrapper::SJOWClass.base)
{
v = OBJECT_TO_JSVAL(XPCSafeJSObjectWrapper::GetUnsafeObject(cx, JSVAL_TO_OBJECT(v)));
rv = si->GetCallback()->Equality(wrapper, cx, obj, v, bp);
if(NS_FAILED(rv))
return Throw(rv, cx);
}
}
@@ -907,66 +907,51 @@ XPC_WN_InnerObject(JSContext *cx, JSObje
}
obj = newThis;
}
return obj;
}
-js::Class XPC_WN_NoHelper_JSClass = {
- "XPCWrappedNative_NoHelper", // name;
- WRAPPER_SLOTS |
- JSCLASS_PRIVATE_IS_NSISUPPORTS |
- JSCLASS_MARK_IS_TRACE, // flags;
+JSObjectOps *XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz);
+
+JSExtendedClass XPC_WN_NoHelper_JSClass = {
+ {
+ "XPCWrappedNative_NoHelper", // name;
+ WRAPPER_SLOTS |
+ JSCLASS_PRIVATE_IS_NSISUPPORTS |
+ JSCLASS_MARK_IS_TRACE |
+ JSCLASS_IS_EXTENDED, // flags;
+
+ /* Mandatory non-null function pointer members. */
+ XPC_WN_OnlyIWrite_PropertyStub, // addProperty;
+ XPC_WN_CannotModifyPropertyStub,// delProperty;
+ JS_PropertyStub, // getProperty;
+ XPC_WN_OnlyIWrite_PropertyStub, // setProperty;
- /* Mandatory non-null function pointer members. */
- js::Valueify(XPC_WN_OnlyIWrite_PropertyStub), // addProperty
- js::Valueify(XPC_WN_CannotModifyPropertyStub),// delProperty
- js::PropertyStub, // getProperty
- js::Valueify(XPC_WN_OnlyIWrite_PropertyStub), // setProperty
-
- XPC_WN_Shared_Enumerate, // enumerate
- XPC_WN_NoHelper_Resolve, // resolve
- js::Valueify(XPC_WN_Shared_Convert), // convert
- XPC_WN_NoHelper_Finalize, // finalize
-
- /* Optionally non-null members start here. */
- nsnull, // reserved0
- nsnull, // checkAccess
- nsnull, // call
- nsnull, // construct
- nsnull, // xdrObject;
- nsnull, // hasInstance
- JS_CLASS_TRACE(XPC_WN_Shared_Trace), // mark/trace
+ XPC_WN_Shared_Enumerate, // enumerate;
+ XPC_WN_NoHelper_Resolve, // resolve;
+ XPC_WN_Shared_Convert, // convert;
+ XPC_WN_NoHelper_Finalize, // finalize;
- // ClassExtension
- {
- js::Valueify(XPC_WN_Equality),
- XPC_WN_OuterObject,
- XPC_WN_InnerObject,
- nsnull, // iteratorObject
- nsnull, // wrappedObject
+ /* Optionally non-null members start here. */
+ XPC_WN_GetObjectOpsNoCall, // getObjectOps;
+ nsnull, // checkAccess;
+ nsnull, // call;
+ nsnull, // construct;
+ nsnull, // xdrObject;
+ nsnull, // hasInstance;
+ JS_CLASS_TRACE(XPC_WN_Shared_Trace), // mark/trace;
+ nsnull // spare;
},
-
- // ObjectOps
- {
- nsnull, // lookupProperty
- nsnull, // defineProperty
- nsnull, // getProperty
- nsnull, // setProperty
- nsnull, // getAttributes
- nsnull, // setAttributes
- nsnull, // deleteProperty
- js::Valueify(XPC_WN_JSOp_Enumerate),
- XPC_WN_JSOp_TypeOf_Object,
- nsnull, // trace
- XPC_WN_JSOp_ThisObject,
- XPC_WN_JSOp_Clear
- }
+ XPC_WN_Equality,
+ XPC_WN_OuterObject,
+ XPC_WN_InnerObject,
+ nsnull,nsnull,nsnull,nsnull,nsnull
};
/***************************************************************************/
static JSBool
XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
@@ -1248,16 +1233,21 @@ XPC_WN_Helper_NewResolve(JSContext *cx,
}
}
return retval;
}
/***************************************************************************/
+extern JS_IMPORT_DATA(JSObjectOps) js_ObjectOps;
+
+static JSObjectOps XPC_WN_WithCall_JSOps;
+static JSObjectOps XPC_WN_NoCall_JSOps;
+
/*
Here are the enumerator cases:
set jsclass enumerate to stub (unless noted otherwise)
if( helper wants new enumerate )
if( DONT_ENUM_STATICS )
forward to scriptable enumerate
@@ -1283,28 +1273,28 @@ XPC_WN_Helper_NewResolve(JSContext *cx,
else //... if( helper wants NO enumerate )
if( DONT_ENUM_STATICS )
use enumerate stub - don't use this JSOp thing at all
else
do shared enumerate - don't use this JSOp thing at all
*/
-JSBool
+static JSBool
XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp)
{
- js::Class *clazz = obj->getClass();
- if(!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass)
+ JSClass *clazz = obj->getJSClass();
+ if(!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base)
{
// obj must be a prototype object or a wrapper w/o a
- // helper. Short circuit this call to the default
- // implementation.
+ // helper. Short circuit this call to
+ // js_ObjectOps.enumerate().
- return js_Enumerate(cx, obj, enum_op, js::Valueify(statep), idp);
+ return js_ObjectOps.enumerate(cx, obj, enum_op, js::Valueify(statep), idp);
}
MORPH_SLIM_WRAPPER(cx, obj);
XPCCallContext ccx(JS_CALLER, cx, obj);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@@ -1361,38 +1351,38 @@ XPC_WN_JSOp_Enumerate(JSContext *cx, JSO
if(NS_FAILED(rv) || !retval)
*statep = JSVAL_NULL;
if(NS_FAILED(rv))
return Throw(rv, cx);
if(!retval)
return JS_FALSE;
- // Then fall through and call the default implementation...
+ // Then fall through and call js_ObjectOps.enumerate...
}
}
// else call js_ObjectOps.enumerate...
- return js_Enumerate(cx, obj, enum_op, js::Valueify(statep), idp);
+ return js_ObjectOps.enumerate(cx, obj, enum_op, js::Valueify(statep), idp);
}
-JSType
+static JSType
XPC_WN_JSOp_TypeOf_Object(JSContext *cx, JSObject *obj)
{
return JSTYPE_OBJECT;
}
-JSType
+static JSType
XPC_WN_JSOp_TypeOf_Function(JSContext *cx, JSObject *obj)
{
return JSTYPE_FUNCTION;
}
-void
+static void
XPC_WN_JSOp_Clear(JSContext *cx, JSObject *obj)
{
// We're likely to enter this JSOp with a wrapper prototype
// object. In that case we won't find a wrapper, so we'll just
// call into js_ObjectOps.clear(), which is exactly what we want.
// If our scope is cleared, make sure we clear the scope of our
// native wrapper as well.
@@ -1401,16 +1391,18 @@ XPC_WN_JSOp_Clear(JSContext *cx, JSObjec
if(wrapper && wrapper->IsValid())
{
XPCNativeWrapper::ClearWrappedNativeScopes(cx, wrapper);
nsXPConnect* xpc = nsXPConnect::GetXPConnect();
xpc->UpdateXOWs(cx, wrapper, nsIXPConnect::XPC_XOW_CLEARSCOPE);
}
+
+ js_ObjectOps.clear(cx, obj);
}
namespace {
NS_STACK_CLASS class AutoPopJSContext
{
public:
AutoPopJSContext(XPCJSContextStack *stack)
@@ -1439,17 +1431,17 @@ public:
private:
JSContext *mCx;
XPCJSContextStack *mStack;
};
} // namespace
-JSObject*
+static JSObject*
XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj)
{
// None of the wrappers we could potentially hand out are threadsafe so
// just hand out the given object.
if(!XPCPerThreadData::IsMainThread(cx))
return obj;
OBJ_TO_OUTER_OBJECT(cx, obj);
@@ -1536,16 +1528,47 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
XPCThrower::Throw(rv, cx);
return nsnull;
}
}
return JSVAL_TO_OBJECT(retval.jsval_value());
}
+JSObjectOps *
+XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz)
+{
+ return &XPC_WN_NoCall_JSOps;
+}
+
+JSObjectOps *
+XPC_WN_GetObjectOpsWithCall(JSContext *cx, JSClass *clazz)
+{
+ return &XPC_WN_WithCall_JSOps;
+}
+
+JSBool xpc_InitWrappedNativeJSOps()
+{
+ if(!XPC_WN_NoCall_JSOps.lookupProperty)
+ {
+ memcpy(&XPC_WN_NoCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps));
+ XPC_WN_NoCall_JSOps.enumerate = js::Valueify(XPC_WN_JSOp_Enumerate);
+ XPC_WN_NoCall_JSOps.typeOf = XPC_WN_JSOp_TypeOf_Object;
+ XPC_WN_NoCall_JSOps.clear = XPC_WN_JSOp_Clear;
+ XPC_WN_NoCall_JSOps.thisObject = XPC_WN_JSOp_ThisObject;
+
+ memcpy(&XPC_WN_WithCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps));
+ XPC_WN_WithCall_JSOps.enumerate = js::Valueify(XPC_WN_JSOp_Enumerate);
+ XPC_WN_WithCall_JSOps.typeOf = XPC_WN_JSOp_TypeOf_Function;
+ XPC_WN_WithCall_JSOps.clear = XPC_WN_JSOp_Clear;
+ XPC_WN_WithCall_JSOps.thisObject = XPC_WN_JSOp_ThisObject;
+ }
+ return JS_TRUE;
+}
+
/***************************************************************************/
// static
XPCNativeScriptableInfo*
XPCNativeScriptableInfo::Construct(XPCCallContext& ccx,
JSBool isGlobal,
const XPCNativeScriptableCreateInfo* sci)
{
@@ -1586,122 +1609,117 @@ XPCNativeScriptableInfo::Construct(XPCCa
void
XPCNativeScriptableShared::PopulateJSClass(JSBool isGlobal)
{
NS_ASSERTION(mJSClass.base.name, "bad state!");
mJSClass.base.flags = WRAPPER_SLOTS |
JSCLASS_PRIVATE_IS_NSISUPPORTS |
JSCLASS_NEW_RESOLVE |
- JSCLASS_MARK_IS_TRACE;
+ JSCLASS_MARK_IS_TRACE |
+ JSCLASS_IS_EXTENDED;
if(isGlobal)
mJSClass.base.flags |= JSCLASS_GLOBAL_FLAGS;
- JSPropertyOp addProperty;
if(mFlags.WantAddProperty())
- addProperty = XPC_WN_Helper_AddProperty;
+ mJSClass.base.addProperty = XPC_WN_Helper_AddProperty;
else if(mFlags.UseJSStubForAddProperty())
- addProperty = JS_PropertyStub;
+ mJSClass.base.addProperty = JS_PropertyStub;
else if(mFlags.AllowPropModsDuringResolve())
- addProperty = XPC_WN_MaybeResolvingPropertyStub;
+ mJSClass.base.addProperty = XPC_WN_MaybeResolvingPropertyStub;
else
- addProperty = XPC_WN_CannotModifyPropertyStub;
- mJSClass.base.addProperty = js::Valueify(addProperty);
+ mJSClass.base.addProperty = XPC_WN_CannotModifyPropertyStub;
- JSPropertyOp delProperty;
if(mFlags.WantDelProperty())
- delProperty = XPC_WN_Helper_DelProperty;
+ mJSClass.base.delProperty = XPC_WN_Helper_DelProperty;
else if(mFlags.UseJSStubForDelProperty())
- delProperty = JS_PropertyStub;
+ mJSClass.base.delProperty = JS_PropertyStub;
else if(mFlags.AllowPropModsDuringResolve())
- delProperty = XPC_WN_MaybeResolvingPropertyStub;
+ mJSClass.base.delProperty = XPC_WN_MaybeResolvingPropertyStub;
else
- delProperty = XPC_WN_CannotModifyPropertyStub;
- mJSClass.base.delProperty = js::Valueify(delProperty);
+ mJSClass.base.delProperty = XPC_WN_CannotModifyPropertyStub;
if(mFlags.WantGetProperty())
- mJSClass.base.getProperty = js::Valueify(XPC_WN_Helper_GetProperty);
+ mJSClass.base.getProperty = XPC_WN_Helper_GetProperty;
else
- mJSClass.base.getProperty = js::PropertyStub;
+ mJSClass.base.getProperty = JS_PropertyStub;
- JSPropertyOp setProperty;
if(mFlags.WantSetProperty())
- setProperty = XPC_WN_Helper_SetProperty;
+ mJSClass.base.setProperty = XPC_WN_Helper_SetProperty;
else if(mFlags.UseJSStubForSetProperty())
- setProperty = JS_PropertyStub;
+ mJSClass.base.setProperty = JS_PropertyStub;
else if(mFlags.AllowPropModsDuringResolve())
- setProperty = XPC_WN_MaybeResolvingPropertyStub;
+ mJSClass.base.setProperty = XPC_WN_MaybeResolvingPropertyStub;
else
- setProperty = XPC_WN_CannotModifyPropertyStub;
- mJSClass.base.setProperty = js::Valueify(setProperty);
+ mJSClass.base.setProperty = XPC_WN_CannotModifyPropertyStub;
// We figure out most of the enumerate strategy at call time.
if(mFlags.WantNewEnumerate() || mFlags.WantEnumerate() ||
mFlags.DontEnumStaticProps())
- mJSClass.base.enumerate = js::EnumerateStub;
+ mJSClass.base.enumerate = JS_EnumerateStub;
else
mJSClass.base.enumerate = XPC_WN_Shared_Enumerate;
// We have to figure out resolve strategy at call time
mJSClass.base.resolve = (JSResolveOp) XPC_WN_Helper_NewResolve;
if(mFlags.WantConvert())
- mJSClass.base.convert = js::Valueify(XPC_WN_Helper_Convert);
+ mJSClass.base.convert = XPC_WN_Helper_Convert;
else
- mJSClass.base.convert = js::Valueify(XPC_WN_Shared_Convert);
+ mJSClass.base.convert = XPC_WN_Shared_Convert;
if(mFlags.WantFinalize())
mJSClass.base.finalize = XPC_WN_Helper_Finalize;
else
mJSClass.base.finalize = XPC_WN_NoHelper_Finalize;
// We let the rest default to nsnull unless the helper wants them...
if(mFlags.WantCheckAccess())
- mJSClass.base.checkAccess = js::Valueify(XPC_WN_Helper_CheckAccess);
+ mJSClass.base.checkAccess = XPC_WN_Helper_CheckAccess;
- // Note that we *must* set the ObjectOps (even for the cases were it does
- // not do much) because with these dynamically generated JSClasses, the
- // code in XPCWrappedNative::GetWrappedNativeOfJSObject() needs to look
- // for that these callback pointers in order to identify that a given
+ // Note that we *must* set
+ // mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsNoCall
+ // or
+ // mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsWithCall
+ // (even for the cases were it does not do much) because with these
+ // dynamically generated JSClasses, the code in
+ // XPCWrappedNative::GetWrappedNativeOfJSObject() needs to look for
+ // that this callback pointer in order to identify that a given
// JSObject represents a wrapper.
- js::ObjectOps *ops = &mJSClass.base.ops;
- ops->enumerate = js::Valueify(XPC_WN_JSOp_Enumerate);
- ops->clear = XPC_WN_JSOp_Clear;
- ops->thisObject = XPC_WN_JSOp_ThisObject;
if(mFlags.WantCall() || mFlags.WantConstruct())
{
- ops->typeOf = XPC_WN_JSOp_TypeOf_Function;
+ mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsWithCall;
if(mFlags.WantCall())
- mJSClass.base.call = js::Valueify(XPC_WN_Helper_Call);
+ mJSClass.base.call = XPC_WN_Helper_Call;
if(mFlags.WantConstruct())
- mJSClass.base.construct = js::Valueify(XPC_WN_Helper_Construct);
+ mJSClass.base.construct = XPC_WN_Helper_Construct;
}
else
{
- ops->typeOf = XPC_WN_JSOp_TypeOf_Object;
+ mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsNoCall;
}
- // Equality is a required hook.
- mJSClass.base.ext.equality = js::Valueify(XPC_WN_Equality);
-
if(mFlags.WantHasInstance())
- mJSClass.base.hasInstance = js::Valueify(XPC_WN_Helper_HasInstance);
+ mJSClass.base.hasInstance = XPC_WN_Helper_HasInstance;
if(mFlags.WantTrace())
mJSClass.base.mark = JS_CLASS_TRACE(XPC_WN_Helper_Trace);
else
mJSClass.base.mark = JS_CLASS_TRACE(XPC_WN_Shared_Trace);
+ // Equality is a required hook.
+ mJSClass.equality = XPC_WN_Equality;
+
if(mFlags.WantOuterObject())
- mJSClass.base.ext.outerObject = XPC_WN_OuterObject;
+ mJSClass.outerObject = XPC_WN_OuterObject;
if(mFlags.WantInnerObject())
- mJSClass.base.ext.innerObject = XPC_WN_InnerObject;
+ mJSClass.innerObject = XPC_WN_InnerObject;
if(!(mFlags & (nsIXPCScriptable::WANT_OUTER_OBJECT |
nsIXPCScriptable::WANT_INNER_OBJECT)))
mCanBeSlim = JS_TRUE;
}
/***************************************************************************/
/***************************************************************************/
@@ -1783,20 +1801,22 @@ XPC_WN_GetterSetter(JSContext *cx, JSObj
}
/***************************************************************************/
static JSBool
XPC_WN_Shared_Proto_Enumerate(JSContext *cx, JSObject *obj)
{
NS_ASSERTION(
- obj->getClass() == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
- obj->getClass() == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass ||
- obj->getClass() == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
- obj->getClass() == &XPC_WN_NoMods_NoCall_Proto_JSClass,
+ JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_WithCall_Proto_JSClass,
+ nsnull) ||
+ JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_NoCall_Proto_JSClass,
+ nsnull) ||
+ JS_InstanceOf(cx, obj, &XPC_WN_NoMods_WithCall_Proto_JSClass, nsnull) ||
+ JS_InstanceOf(cx, obj, &XPC_WN_NoMods_NoCall_Proto_JSClass, nsnull),
"bad proto");
XPCWrappedNativeProto* self =
(XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
if(!self)
return JS_FALSE;
if(self->GetScriptableInfo() &&
self->GetScriptableInfo()->GetFlags().DontEnumStaticProps())
@@ -1854,19 +1874,21 @@ XPC_WN_Shared_Proto_Trace(JSTracer *trc,
}
/*****************************************************/
static JSBool
XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, JSObject *obj, jsid id)
{
NS_ASSERTION(
- obj->getClass() == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
- obj->getClass() == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass,
- "bad proto");
+ JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_WithCall_Proto_JSClass,
+ nsnull) ||
+ JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_NoCall_Proto_JSClass,
+ nsnull),
+ "bad proto");
XPCWrappedNativeProto* self =
(XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
if(!self)
return JS_FALSE;
XPCCallContext ccx(JS_CALLER, cx);
if(!ccx.IsValid())
@@ -1878,77 +1900,103 @@ XPC_WN_ModsAllowed_Proto_Resolve(JSConte
return DefinePropertyIfFound(ccx, obj, id,
self->GetSet(), nsnull, nsnull,
self->GetScope(),
JS_TRUE, nsnull, nsnull, si,
enumFlag, nsnull);
}
-js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
+// Give our proto classes object ops that match the respective
+// wrappers so that the JS engine can share scope (maps) among
+// wrappers. This essentially duplicates the number of JSClasses we
+// use for prototype objects (from 2 to 4), but the scope sharing
+// benefit is well worth it.
+JSObjectOps *
+XPC_WN_Proto_GetObjectOps(JSContext *cx, JSClass *clazz)
+{
+ // Protos for wrappers that want calls to their call() hooks get
+ // jsops with a call hook, others get jsops w/o a call hook.
+
+ if(clazz == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
+ clazz == &XPC_WN_NoMods_WithCall_Proto_JSClass)
+ return &XPC_WN_WithCall_JSOps;
+
+ NS_ASSERTION(clazz == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass ||
+ clazz == &XPC_WN_NoMods_NoCall_Proto_JSClass ||
+ clazz == &XPC_WN_NoHelper_Proto_JSClass,
+ "bad proto");
+
+ return &XPC_WN_NoCall_JSOps;
+}
+
+JSClass XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
"XPC_WN_ModsAllowed_WithCall_Proto_JSClass", // name;
WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
/* Mandatory non-null function pointer members. */
- js::PropertyStub, // addProperty;
- js::PropertyStub, // delProperty;
- js::PropertyStub, // getProperty;
- js::PropertyStub, // setProperty;
- XPC_WN_Shared_Proto_Enumerate, // enumerate;
- XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
- js::Valueify(XPC_WN_Shared_Proto_Convert), // convert;
- XPC_WN_Shared_Proto_Finalize, // finalize;
+ JS_PropertyStub, // addProperty;
+ JS_PropertyStub, // delProperty;
+ JS_PropertyStub, // getProperty;
+ JS_PropertyStub, // setProperty;
+ XPC_WN_Shared_Proto_Enumerate, // enumerate;
+ XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
+ XPC_WN_Shared_Proto_Convert, // convert;
+ XPC_WN_Shared_Proto_Finalize, // finalize;
/* Optionally non-null members start here. */
- nsnull, // reserved0;
+ XPC_WN_Proto_GetObjectOps, // getObjectOps;
nsnull, // checkAccess;
nsnull, // call;
nsnull, // construct;
nsnull, // xdrObject;
nsnull, // hasInstance;
JS_CLASS_TRACE(XPC_WN_Shared_Proto_Trace), // mark/trace;
-
- JS_NULL_CLASS_EXT,
- XPC_WN_WithCall_ObjectOps
+ nsnull // spare;
};
-js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = {
+JSObjectOps *
+XPC_WN_ModsAllowedProto_NoCall_GetObjectOps(JSContext *cx, JSClass *clazz)
+{
+ return &XPC_WN_NoCall_JSOps;
+}
+
+JSClass XPC_WN_ModsAllowed_NoCall_Proto_JSClass = {
"XPC_WN_ModsAllowed_NoCall_Proto_JSClass", // name;
WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
/* Mandatory non-null function pointer members. */
- js::PropertyStub, // addProperty;
- js::PropertyStub, // delProperty;
- js::PropertyStub, // getProperty;
- js::PropertyStub, // setProperty;
- XPC_WN_Shared_Proto_Enumerate, // enumerate;
- XPC_WN_ModsAllowed_Proto_Resolve,// resolve;
- js::Valueify(XPC_WN_Shared_Proto_Convert), // convert;
- XPC_WN_Shared_Proto_Finalize, // finalize;
+ JS_PropertyStub, // addProperty;
+ JS_PropertyStub, // delProperty;
+ JS_PropertyStub, // getProperty;
+ JS_PropertyStub, // setProperty;
+ XPC_WN_Shared_Proto_Enumerate, // enumerate;
+ XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
+ XPC_WN_Shared_Proto_Convert, // convert;
+ XPC_WN_Shared_Proto_Finalize, // finalize;
/* Optionally non-null members start here. */
- nsnull, // reserved0;
+ XPC_WN_Proto_GetObjectOps, // getObjectOps;
nsnull, // checkAccess;
nsnull, // call;
nsnull, // construct;
nsnull, // xdrObject;
nsnull, // hasInstance;
JS_CLASS_TRACE(XPC_WN_Shared_Proto_Trace), // mark/trace;
-
- JS_NULL_CLASS_EXT,
- XPC_WN_NoCall_ObjectOps
+ nsnull // spare;
};
/***************************************************************************/
static JSBool
XPC_WN_OnlyIWrite_Proto_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
- NS_ASSERTION(obj->getClass() == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
- obj->getClass() == &XPC_WN_NoMods_NoCall_Proto_JSClass,
+ NS_ASSERTION(
+ JS_InstanceOf(cx, obj, &XPC_WN_NoMods_WithCall_Proto_JSClass, nsnull) ||
+ JS_InstanceOf(cx, obj, &XPC_WN_NoMods_NoCall_Proto_JSClass, nsnull),
"bad proto");
XPCWrappedNativeProto* self =
(XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
if(!self)
return JS_FALSE;
XPCCallContext ccx(JS_CALLER, cx);
@@ -1960,18 +2008,19 @@ XPC_WN_OnlyIWrite_Proto_PropertyStub(JSC
return JS_TRUE;
return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
}
static JSBool
XPC_WN_NoMods_Proto_Resolve(JSContext *cx, JSObject *obj, jsid id)
{
- NS_ASSERTION(obj->getClass() == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
- obj->getClass() == &XPC_WN_NoMods_NoCall_Proto_JSClass,
+ NS_ASSERTION(
+ JS_InstanceOf(cx, obj, &XPC_WN_NoMods_WithCall_Proto_JSClass, nsnull) ||
+ JS_InstanceOf(cx, obj, &XPC_WN_NoMods_NoCall_Proto_JSClass, nsnull),
"bad proto");
XPCWrappedNativeProto* self =
(XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
if(!self)
return JS_FALSE;
XPCCallContext ccx(JS_CALLER, cx);
@@ -1986,68 +2035,64 @@ XPC_WN_NoMods_Proto_Resolve(JSContext *c
self->GetSet(), nsnull, nsnull,
self->GetScope(),
JS_TRUE, nsnull, nsnull, si,
JSPROP_READONLY |
JSPROP_PERMANENT |
enumFlag, nsnull);
}
-js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = {
+JSClass XPC_WN_NoMods_WithCall_Proto_JSClass = {
"XPC_WN_NoMods_WithCall_Proto_JSClass", // name;
WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
/* Mandatory non-null function pointer members. */
- js::Valueify(XPC_WN_OnlyIWrite_Proto_PropertyStub), // addProperty;
- js::Valueify(XPC_WN_CannotModifyPropertyStub), // delProperty;
- js::PropertyStub, // getProperty;
- js::Valueify(XPC_WN_OnlyIWrite_Proto_PropertyStub), // setProperty;
- XPC_WN_Shared_Proto_Enumerate, // enumerate;
- XPC_WN_NoMods_Proto_Resolve, // resolve;
- js::Valueify(XPC_WN_Shared_Proto_Convert), // convert;
- XPC_WN_Shared_Proto_Finalize, // finalize;
+ XPC_WN_OnlyIWrite_Proto_PropertyStub, // addProperty;
+ XPC_WN_CannotModifyPropertyStub, // delProperty;
+ JS_PropertyStub, // getProperty;
+ XPC_WN_OnlyIWrite_Proto_PropertyStub, // setProperty;
+ XPC_WN_Shared_Proto_Enumerate, // enumerate;
+ XPC_WN_NoMods_Proto_Resolve, // resolve;
+ XPC_WN_Shared_Proto_Convert, // convert;
+ XPC_WN_Shared_Proto_Finalize, // finalize;
/* Optionally non-null members start here. */
- nsnull, // reserved0;
+ XPC_WN_Proto_GetObjectOps, // getObjectOps;
nsnull, // checkAccess;
nsnull, // call;
nsnull, // construct;
nsnull, // xdrObject;
nsnull, // hasInstance;
JS_CLASS_TRACE(XPC_WN_Shared_Proto_Trace), // mark/trace;
-
- JS_NULL_CLASS_EXT,
- XPC_WN_WithCall_ObjectOps
+ nsnull // spare;
};
-js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = {
- "XPC_WN_NoMods_NoCall_Proto_JSClass", // name;
- WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
+JSClass XPC_WN_NoMods_NoCall_Proto_JSClass = {
+ "XPC_WN_NoMods_NoCall_Proto_JSClass", // name;
+ WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
/* Mandatory non-null function pointer members. */
- js::Valueify(XPC_WN_OnlyIWrite_Proto_PropertyStub), // addProperty;
- js::Valueify(XPC_WN_CannotModifyPropertyStub), // delProperty;
- js::PropertyStub, // getProperty;
- js::Valueify(XPC_WN_OnlyIWrite_Proto_PropertyStub), // setProperty;
- XPC_WN_Shared_Proto_Enumerate, // enumerate;
- XPC_WN_NoMods_Proto_Resolve, // resolve;
- js::Valueify(XPC_WN_Shared_Proto_Convert), // convert;
- XPC_WN_Shared_Proto_Finalize, // finalize;
+ XPC_WN_OnlyIWrite_Proto_PropertyStub, // addProperty;
+ XPC_WN_CannotModifyPropertyStub, // delProperty;
+ JS_PropertyStub, // getProperty;
+ XPC_WN_OnlyIWrite_Proto_PropertyStub, // setProperty;
+ XPC_WN_Shared_Proto_Enumerate, // enumerate;
+ XPC_WN_NoMods_Proto_Resolve, // resolve;
+ XPC_WN_Shared_Proto_Convert, // convert;
+ XPC_WN_Shared_Proto_Finalize, // finalize;
/* Optionally non-null members start here. */
- nsnull, // reserved0;
+ XPC_WN_Proto_GetObjectOps, // getObjectOps;
nsnull, // checkAccess;
nsnull, // call;
nsnull, // construct;
nsnull, // xdrObject;
nsnull, // hasInstance;
JS_CLASS_TRACE(XPC_WN_Shared_Proto_Trace), // mark/trace;
-
- JS_NULL_CLASS_EXT,
- XPC_WN_NoCall_ObjectOps
+ nsnull // spare;
};
/***************************************************************************/
static JSBool
XPC_WN_TearOff_Enumerate(JSContext *cx, JSObject *obj)
{
MORPH_SLIM_WRAPPER(cx, obj);
@@ -2098,21 +2143,32 @@ XPC_WN_TearOff_Finalize(JSContext *cx, J
{
XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
xpc_GetJSPrivate(obj);
if(!p)
return;
p->JSObjectFinalized();
}
-js::Class XPC_WN_Tearoff_JSClass = {
- "WrappedNative_TearOff", // name;
- WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
+JSClass XPC_WN_Tearoff_JSClass = {
+ "WrappedNative_TearOff", // name;
+ WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
- js::Valueify(XPC_WN_OnlyIWrite_PropertyStub), // addProperty;
- js::Valueify(XPC_WN_CannotModifyPropertyStub), // delProperty;
- js::PropertyStub, // getProperty;
- js::Valueify(XPC_WN_OnlyIWrite_PropertyStub), // setProperty;
- XPC_WN_TearOff_Enumerate, // enumerate;
- XPC_WN_TearOff_Resolve, // resolve;
- js::Valueify(XPC_WN_Shared_Convert), // convert;
- XPC_WN_TearOff_Finalize // finalize;
+ /* Mandatory non-null function pointer members. */
+ XPC_WN_OnlyIWrite_PropertyStub, // addProperty;
+ XPC_WN_CannotModifyPropertyStub, // delProperty;
+ JS_PropertyStub, // getProperty;
+ XPC_WN_OnlyIWrite_PropertyStub, // setProperty;
+ XPC_WN_TearOff_Enumerate, // enumerate;
+ XPC_WN_TearOff_Resolve, // resolve;
+ XPC_WN_Shared_Convert, // convert;
+ XPC_WN_TearOff_Finalize, // finalize;
+
+ /* Optionally non-null members start here. */
+ nsnull, // getObjectOps;
+ nsnull, // checkAccess;
+ nsnull, // call;
+ nsnull, // construct;
+ nsnull, // xdrObject;
+ nsnull, // hasInstance;
+ nsnull, // mark/trace;
+ nsnull // spare;
};
--- a/js/src/xpconnect/src/xpcwrappednativeproto.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativeproto.cpp
@@ -99,17 +99,17 @@ XPCWrappedNativeProto::Init(
if(callback)
{
mScriptableInfo =
XPCNativeScriptableInfo::Construct(ccx, isGlobal, scriptableCreateInfo);
if(!mScriptableInfo)
return JS_FALSE;
}
- js::Class* jsclazz;
+ JSClass* jsclazz;
if(mScriptableInfo)
{
const XPCNativeScriptableFlags& flags(mScriptableInfo->GetFlags());
if(flags.AllowPropModsToPrototype())
{
@@ -127,17 +127,17 @@ XPCWrappedNativeProto::Init(
else
{
jsclazz = &XPC_WN_NoMods_NoCall_Proto_JSClass;
}
JSObject *parent = mScope->GetGlobalJSObject();
mJSProtoObject =
- xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(jsclazz),
+ xpc_NewSystemInheritingJSObject(ccx, jsclazz,
mScope->GetPrototypeJSObject(),
parent);
JSBool ok = mJSProtoObject && JS_SetPrivate(ccx, mJSProtoObject, this);
if(ok && callback)
{
nsresult rv = callback->PostCreatePrototype(ccx, mJSProtoObject);
--- a/js/src/xpconnect/src/xpcwrappednativescope.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp
@@ -199,41 +199,39 @@ XPCWrappedNativeScope::SetComponents(nsX
// scopes. By doing this we avoid allocating a new scope for every
// wrapper on creation of the wrapper, and most wrappers won't need
// their own scope at all for the lifetime of the wrapper.
// WRAPPER_SLOTS is key here (even though there's never anything
// in the private data slot in these prototypes), as the number of
// reserved slots in this class needs to match that of the wrappers
// for the JS engine to share scopes.
-js::Class XPC_WN_NoHelper_Proto_JSClass = {
+JSClass XPC_WN_NoHelper_Proto_JSClass = {
"XPC_WN_NoHelper_Proto_JSClass",// name;
WRAPPER_SLOTS, // flags;
/* Mandatory non-null function pointer members. */
- js::PropertyStub, // addProperty;
- js::PropertyStub, // delProperty;
- js::PropertyStub, // getProperty;
- js::PropertyStub, // setProperty;
- js::EnumerateStub, // enumerate;
+ JS_PropertyStub, // addProperty;
+ JS_PropertyStub, // delProperty;
+ JS_PropertyStub, // getProperty;
+ JS_PropertyStub, // setProperty;
+ JS_EnumerateStub, // enumerate;
JS_ResolveStub, // resolve;
- js::ConvertStub, // convert;
+ JS_ConvertStub, // convert;
nsnull, // finalize;
/* Optionally non-null members start here. */
- nsnull, // reserved0;
+ XPC_WN_Proto_GetObjectOps, // getObjectOps;
nsnull, // checkAccess;
nsnull, // call;
nsnull, // construct;
nsnull, // xdrObject;
nsnull, // hasInstance;
nsnull, // mark/trace;
-
- JS_NULL_CLASS_EXT,
- XPC_WN_NoCall_ObjectOps
+ nsnull // spare;
};
void
XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal)
{
// We allow for calling this more than once. This feature is used by
// nsXPConnect::InitClassesWithNewWrappedGlobal.
@@ -347,18 +345,17 @@ JSObject *
XPCWrappedNativeScope::GetPrototypeNoHelper(XPCCallContext& ccx)
{
// We could create this prototype in SetGlobal(), but all scopes
// don't need one, so we save ourselves a bit of space if we
// create these when they're needed.
if(!mPrototypeNoHelper)
{
mPrototypeNoHelper =
- xpc_NewSystemInheritingJSObject(ccx,
- js::Jsvalify(&XPC_WN_NoHelper_Proto_JSClass),
+ xpc_NewSystemInheritingJSObject(ccx, &XPC_WN_NoHelper_Proto_JSClass,
mPrototypeJSObject,
mGlobalJSObject);
NS_ASSERTION(mPrototypeNoHelper,
"Failed to create prototype for wrappers w/o a helper");
}
return mPrototypeNoHelper;
@@ -723,17 +720,17 @@ XPCWrappedNativeScope::SystemIsBeingShut
/***************************************************************************/
static
XPCWrappedNativeScope*
GetScopeOfObject(JSObject* obj)
{
nsISupports* supports;
- js::Class* clazz = obj->getClass();
+ JSClass* clazz = obj->getJSClass();
JSBool isWrapper = IS_WRAPPER_CLASS(clazz);
if(isWrapper && IS_SLIM_WRAPPER_OBJECT(obj))
return GetSlimWrapperProto(obj)->GetScope();
if(!isWrapper || !(supports = (nsISupports*) xpc_GetJSPrivate(obj)))
{
#ifdef DEBUG