Bug 792215 part 1. Convert quickstubs to using JSNative getters and setters. r=peterv

This commit is contained in:
Boris Zbarsky 2012-09-25 14:44:40 -04:00
Родитель ba16ebc540
Коммит 9b67eb7d78
5 изменённых файлов: 161 добавлений и 278 удалений

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

@ -63,26 +63,26 @@ XPCOMUtils.defineLazyGetter(window, "gFindBar", function() {
return findbar; return findbar;
}); });
__defineGetter__("gPrefService", function() { this.__defineGetter__("gPrefService", function() {
delete this.gPrefService; delete this.gPrefService;
return this.gPrefService = Services.prefs; return this.gPrefService = Services.prefs;
}); });
__defineGetter__("AddonManager", function() { this.__defineGetter__("AddonManager", function() {
let tmp = {}; let tmp = {};
Cu.import("resource://gre/modules/AddonManager.jsm", tmp); Cu.import("resource://gre/modules/AddonManager.jsm", tmp);
return this.AddonManager = tmp.AddonManager; return this.AddonManager = tmp.AddonManager;
}); });
__defineSetter__("AddonManager", function (val) { this.__defineSetter__("AddonManager", function (val) {
delete this.AddonManager; delete this.AddonManager;
return this.AddonManager = val; return this.AddonManager = val;
}); });
__defineGetter__("PluralForm", function() { this.__defineGetter__("PluralForm", function() {
Cu.import("resource://gre/modules/PluralForm.jsm"); Cu.import("resource://gre/modules/PluralForm.jsm");
return this.PluralForm; return this.PluralForm;
}); });
__defineSetter__("PluralForm", function (val) { this.__defineSetter__("PluralForm", function (val) {
delete this.PluralForm; delete this.PluralForm;
return this.PluralForm = val; return this.PluralForm = val;
}); });
@ -1539,7 +1539,7 @@ var gBrowserInit = {
if (!gStartupRan) if (!gStartupRan)
return; return;
if (!__lookupGetter__("InspectorUI")) if (!window.__lookupGetter__("InspectorUI"))
InspectorUI.destroy(); InspectorUI.destroy();
// First clean up services initialized in gBrowserInit.onLoad (or those whose // First clean up services initialized in gBrowserInit.onLoad (or those whose
@ -3614,7 +3614,7 @@ function BrowserToolboxCustomizeDone(aToolboxChanged) {
// Hacky: update the PopupNotifications' object's reference to the iconBox, // Hacky: update the PopupNotifications' object's reference to the iconBox,
// if it already exists, since it may have changed if the URL bar was // if it already exists, since it may have changed if the URL bar was
// added/removed. // added/removed.
if (!__lookupGetter__("PopupNotifications")) if (!window.__lookupGetter__("PopupNotifications"))
PopupNotifications.iconBox = document.getElementById("notification-popup-box"); PopupNotifications.iconBox = document.getElementById("notification-popup-box");
} }
@ -4073,7 +4073,7 @@ var XULBrowserWindow = {
// Only need to call locationChange if the PopupNotifications object // Only need to call locationChange if the PopupNotifications object
// for this window has already been initialized (i.e. its getter no // for this window has already been initialized (i.e. its getter no
// longer exists) // longer exists)
if (!__lookupGetter__("PopupNotifications")) if (!window.__lookupGetter__("PopupNotifications"))
PopupNotifications.locationChange(); PopupNotifications.locationChange();
} }
} }

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

@ -18,19 +18,25 @@ typedef NS_STDCALL_FUNCPROTO(nsresult, CanvasStyleGetterType, nsIDOMCanvasRender
GetStrokeStyle_multi, (nsAString &, nsISupports **, int32_t *)); GetStrokeStyle_multi, (nsAString &, nsISupports **, int32_t *));
static JSBool static JSBool
Canvas2D_SetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleValue vp, Canvas2D_SetStyleHelper(JSContext *cx, unsigned argc, JS::Value *vp,
CanvasStyleSetterType setfunc) const char* propName, CanvasStyleSetterType setfunc)
{ {
XPC_QS_ASSERT_CONTEXT_OK(cx); XPC_QS_ASSERT_CONTEXT_OK(cx);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsIDOMCanvasRenderingContext2D *self; nsIDOMCanvasRenderingContext2D *self;
xpc_qsSelfRef selfref; xpc_qsSelfRef selfref;
JS::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, &vp[1], nullptr))
if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, tvr.jsval_addr(), nullptr))
return JS_FALSE; return JS_FALSE;
if (argc < 1)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
nsresult rv = NS_OK; nsresult rv = NS_OK;
if (JSVAL_IS_STRING(vp)) { if (JSVAL_IS_STRING(argv[0])) {
xpc_qsDOMString arg0(cx, vp, vp.address(), xpc_qsDOMString arg0(cx, argv[0], &argv[0],
xpc_qsDOMString::eDefaultNullBehavior, xpc_qsDOMString::eDefaultNullBehavior,
xpc_qsDOMString::eDefaultUndefinedBehavior); xpc_qsDOMString::eDefaultUndefinedBehavior);
if (!arg0.IsValid()) if (!arg0.IsValid())
@ -40,9 +46,9 @@ Canvas2D_SetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleVa
} else { } else {
nsISupports *arg0; nsISupports *arg0;
xpc_qsSelfRef arg0ref; xpc_qsSelfRef arg0ref;
rv = xpc_qsUnwrapArg<nsISupports>(cx, vp, &arg0, &arg0ref.ptr, vp.address()); rv = xpc_qsUnwrapArg<nsISupports>(cx, argv[0], &arg0, &arg0ref.ptr, &argv[0]);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
xpc_qsThrowBadSetterValue(cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id); xpc_qsThrowBadSetterValue(cx, rv, JSVAL_TO_OBJECT(vp[1]), propName);
return JS_FALSE; return JS_FALSE;
} }
@ -50,20 +56,24 @@ Canvas2D_SetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleVa
} }
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id); return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(vp[1]),
propName);
return JS_TRUE; return JS_TRUE;
} }
static JSBool static JSBool
Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleValue vp, Canvas2D_GetStyleHelper(JSContext *cx, unsigned argc, JS::Value *vp,
CanvasStyleGetterType getfunc) const char* propName, CanvasStyleGetterType getfunc)
{ {
XPC_QS_ASSERT_CONTEXT_OK(cx); XPC_QS_ASSERT_CONTEXT_OK(cx);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsIDOMCanvasRenderingContext2D *self; nsIDOMCanvasRenderingContext2D *self;
xpc_qsSelfRef selfref; xpc_qsSelfRef selfref;
XPCLazyCallContext lccx(JS_CALLER, cx, obj); XPCLazyCallContext lccx(JS_CALLER, cx, obj);
if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, vp.address(), &lccx)) if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, &vp[1], &lccx))
return JS_FALSE; return JS_FALSE;
nsresult rv; nsresult rv;
@ -72,11 +82,12 @@ Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleVa
int32_t resultType; int32_t resultType;
rv = (self->*getfunc)(resultString, getter_AddRefs(resultInterface), &resultType); rv = (self->*getfunc)(resultString, getter_AddRefs(resultInterface), &resultType);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(vp), id); return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(vp[1]),
propName);
switch (resultType) { switch (resultType) {
case nsIDOMCanvasRenderingContext2D::CMG_STYLE_STRING: case nsIDOMCanvasRenderingContext2D::CMG_STYLE_STRING:
return xpc::StringToJsval(cx, resultString, vp.address()); return xpc::StringToJsval(cx, resultString, vp);
case nsIDOMCanvasRenderingContext2D::CMG_STYLE_PATTERN: case nsIDOMCanvasRenderingContext2D::CMG_STYLE_PATTERN:
{ {
@ -84,7 +95,7 @@ Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleVa
xpc_qsGetWrapperCache(resultInterface)); xpc_qsGetWrapperCache(resultInterface));
return xpc_qsXPCOMObjectToJsval(lccx, helper, return xpc_qsXPCOMObjectToJsval(lccx, helper,
&NS_GET_IID(nsIDOMCanvasPattern), &NS_GET_IID(nsIDOMCanvasPattern),
&interfaces[k_nsIDOMCanvasPattern], vp.address()); &interfaces[k_nsIDOMCanvasPattern], vp);
} }
case nsIDOMCanvasRenderingContext2D::CMG_STYLE_GRADIENT: case nsIDOMCanvasRenderingContext2D::CMG_STYLE_GRADIENT:
{ {
@ -92,35 +103,40 @@ Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleVa
xpc_qsGetWrapperCache(resultInterface)); xpc_qsGetWrapperCache(resultInterface));
return xpc_qsXPCOMObjectToJsval(lccx, helper, return xpc_qsXPCOMObjectToJsval(lccx, helper,
&NS_GET_IID(nsIDOMCanvasGradient), &NS_GET_IID(nsIDOMCanvasGradient),
&interfaces[k_nsIDOMCanvasGradient], vp.address()); &interfaces[k_nsIDOMCanvasGradient], vp);
} }
default: default:
return xpc_qsThrowGetterSetterFailed(cx, NS_ERROR_FAILURE, JSVAL_TO_OBJECT(vp), id); return xpc_qsThrowGetterSetterFailed(cx, NS_ERROR_FAILURE,
JSVAL_TO_OBJECT(vp[1]), propName);
} }
} }
static JSBool static JSBool
nsIDOMCanvasRenderingContext2D_SetStrokeStyle(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp) nsIDOMCanvasRenderingContext2D_SetStrokeStyle(JSContext *cx, unsigned argc, JS::Value *vp)
{ {
return Canvas2D_SetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::SetStrokeStyle_multi); return Canvas2D_SetStyleHelper(cx, argc, vp, "strokeStyle",
&nsIDOMCanvasRenderingContext2D::SetStrokeStyle_multi);
} }
static JSBool static JSBool
nsIDOMCanvasRenderingContext2D_GetStrokeStyle(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) nsIDOMCanvasRenderingContext2D_GetStrokeStyle(JSContext *cx, unsigned argc, JS::Value *vp)
{ {
return Canvas2D_GetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::GetStrokeStyle_multi); return Canvas2D_GetStyleHelper(cx, argc, vp, "strokeStyle",
&nsIDOMCanvasRenderingContext2D::GetStrokeStyle_multi);
} }
static JSBool static JSBool
nsIDOMCanvasRenderingContext2D_SetFillStyle(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp) nsIDOMCanvasRenderingContext2D_SetFillStyle(JSContext *cx, unsigned argc, JS::Value *vp)
{ {
return Canvas2D_SetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::SetFillStyle_multi); return Canvas2D_SetStyleHelper(cx, argc, vp, "fillStyle",
&nsIDOMCanvasRenderingContext2D::SetFillStyle_multi);
} }
static JSBool static JSBool
nsIDOMCanvasRenderingContext2D_GetFillStyle(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) nsIDOMCanvasRenderingContext2D_GetFillStyle(JSContext *cx, unsigned argc, JS::Value *vp)
{ {
return Canvas2D_GetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::GetFillStyle_multi); return Canvas2D_GetStyleHelper(cx, argc, vp, "fillStyle",
&nsIDOMCanvasRenderingContext2D::GetFillStyle_multi);
} }
static bool static bool

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

@ -16,6 +16,8 @@
using namespace mozilla; using namespace mozilla;
extern const char* xpc_qsStringTable;
static inline QITableEntry * static inline QITableEntry *
GetOffsets(nsISupports *identity, XPCWrappedNativeProto* proto) GetOffsets(nsISupports *identity, XPCWrappedNativeProto* proto)
{ {
@ -97,182 +99,6 @@ PointerHolderClass = {
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PointerFinalize JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PointerFinalize
}; };
static JSBool
ReifyPropertyOps(JSContext *cx, JSObject *obj, jsid id, unsigned orig_attrs,
JSPropertyOp getter, JSStrictPropertyOp setter,
JSObject **getterobjp, JSObject **setterobjp)
{
// Generate both getter and setter and stash them in the prototype.
jsval roots[2] = { JSVAL_NULL, JSVAL_NULL };
JS::AutoArrayRooter tvr(cx, ArrayLength(roots), roots);
unsigned attrs = JSPROP_SHARED | (orig_attrs & JSPROP_ENUMERATE);
JSObject *getterobj;
if (getter) {
getterobj = GeneratePropertyOp(cx, obj, id, 0, getter);
if (!getterobj)
return false;
roots[0] = OBJECT_TO_JSVAL(getterobj);
attrs |= JSPROP_GETTER;
} else
getterobj = nullptr;
JSObject *setterobj;
if (setter) {
setterobj = GeneratePropertyOp(cx, obj, id, 1, setter);
if (!setterobj)
return false;
roots[1] = OBJECT_TO_JSVAL(setterobj);
attrs |= JSPROP_SETTER;
} else
setterobj = nullptr;
if (getterobjp)
*getterobjp = getterobj;
if (setterobjp)
*setterobjp = setterobj;
return JS_DefinePropertyById(cx, obj, id, JSVAL_VOID,
JS_DATA_TO_FUNC_PTR(JSPropertyOp, getterobj),
JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setterobj),
attrs);
}
static JSBool
LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, unsigned argc, jsval *vp)
{
XPC_QS_ASSERT_CONTEXT_OK(cx);
if (argc == 0) {
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return true;
}
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return false;
jsval idval = JS_ARGV(cx, vp)[0];
jsid id;
JSPropertyDescriptor desc;
if (!JS_ValueToId(cx, idval, &id) ||
!JS_GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, &desc))
return false;
// No property at all means no getters or setters possible.
if (!desc.obj) {
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return true;
}
// Inline obj_lookup[GS]etter here.
if (wantGetter) {
if (desc.attrs & JSPROP_GETTER) {
JS_SET_RVAL(cx, vp,
OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, desc.getter)));
return true;
}
} else {
if (desc.attrs & JSPROP_SETTER) {
JS_SET_RVAL(cx, vp,
OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, desc.setter)));
return true;
}
}
// Since XPConnect doesn't use JSPropertyOps in any other contexts,
// 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!
if (!JSID_IS_STRING(id) ||
!IS_PROTO_CLASS(js::GetObjectClass(desc.obj)) ||
(desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
!(desc.getter || desc.setter) ||
desc.setter == js::GetObjectJSClass(desc.obj)->setProperty) {
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return true;
}
JSObject *getterobj, *setterobj;
if (!ReifyPropertyOps(cx, desc.obj, id, desc.attrs, desc.getter, desc.setter,
&getterobj, &setterobj)) {
return false;
}
JSObject *wantedobj = wantGetter ? getterobj : setterobj;
jsval v = wantedobj ? OBJECT_TO_JSVAL(wantedobj) : JSVAL_VOID;
JS_SET_RVAL(cx, vp, v);
return true;
}
static JSBool
SharedLookupGetter(JSContext *cx, unsigned argc, jsval *vp)
{
return LookupGetterOrSetter(cx, true, argc, vp);
}
static JSBool
SharedLookupSetter(JSContext *cx, unsigned argc, jsval *vp)
{
return LookupGetterOrSetter(cx, false, argc, vp);
}
static JSBool
DefineGetterOrSetter(JSContext *cx, unsigned argc, JSBool wantGetter, jsval *vp)
{
unsigned attrs;
JSBool found;
JSPropertyOp getter;
JSStrictPropertyOp setter;
JSObject *obj2;
jsval v;
jsid id;
XPC_QS_ASSERT_CONTEXT_OK(cx);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return false;
JSNative forward = wantGetter ? js::obj_defineGetter : js::obj_defineSetter;
jsval idval = (argc >= 1) ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
if (!JSVAL_IS_STRING(idval))
return forward(cx, argc, vp);
if (!JS_ValueToId(cx, idval, &id) ||
!JS_LookupPropertyWithFlagsById(cx, obj, id,
JSRESOLVE_QUALIFIED, &obj2, &v) ||
(obj2 &&
!JS_GetPropertyAttrsGetterAndSetterById(cx, obj2, id, &attrs,
&found, &getter, &setter)))
return 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(js::GetObjectClass(obj2)))
return forward(cx, argc, vp);
// Reify the getter and setter...
if (!ReifyPropertyOps(cx, obj2, id, attrs, getter, setter, nullptr, nullptr))
return false;
return forward(cx, argc, vp);
}
static JSBool
SharedDefineGetter(JSContext *cx, unsigned argc, jsval *vp)
{
return DefineGetterOrSetter(cx, argc, true, vp);
}
static JSBool
SharedDefineSetter(JSContext *cx, unsigned argc, jsval *vp)
{
return DefineGetterOrSetter(cx, argc, false, vp);
}
JSBool JSBool
xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned flags, xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned flags,
uint32_t ifacec, const nsIID **interfaces, uint32_t ifacec, const nsIID **interfaces,
@ -304,8 +130,10 @@ xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned flags,
definedProperty = true; definedProperty = true;
if (!JS_DefineProperty(cx, proto, if (!JS_DefineProperty(cx, proto,
stringTable + ps->name_index, stringTable + ps->name_index,
JSVAL_VOID, ps->getter, ps->setter, JSVAL_VOID,
flags | JSPROP_SHARED)) (JSPropertyOp)ps->getter,
(JSStrictPropertyOp)ps->setter,
flags | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS))
return false; return false;
} }
@ -329,17 +157,6 @@ xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned flags,
} }
} }
static JSFunctionSpec getterfns[] = {
JS_FN("__lookupGetter__", SharedLookupGetter, 1, 0),
JS_FN("__lookupSetter__", SharedLookupSetter, 1, 0),
JS_FN("__defineGetter__", SharedDefineGetter, 2, 0),
JS_FN("__defineSetter__", SharedDefineSetter, 2, 0),
JS_FS_END
};
if (definedProperty && !JS_DefineFunctions(cx, proto, getterfns))
return false;
return true; return true;
} }
@ -463,6 +280,26 @@ xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj,
return ThrowCallFailed(cx, rv, ifaceName, memberId, NULL); return ThrowCallFailed(cx, rv, ifaceName, memberId, NULL);
} }
JSBool
xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj,
const char* memberName)
{
JSString *str = JS_InternString(cx, memberName);
if (!str) {
return false;
}
return xpc_qsThrowGetterSetterFailed(cx, rv, obj,
INTERNED_STRING_TO_JSID(cx, str));
}
JSBool
xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj,
uint16_t memberIndex)
{
return xpc_qsThrowGetterSetterFailed(cx, rv, obj,
xpc_qsStringTable + memberIndex);
}
JSBool JSBool
xpc_qsThrowMethodFailed(JSContext *cx, nsresult rv, jsval *vp) xpc_qsThrowMethodFailed(JSContext *cx, nsresult rv, jsval *vp)
{ {
@ -547,6 +384,24 @@ xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv,
ThrowBadArg(cx, rv, ifaceName, propId, NULL, 0); ThrowBadArg(cx, rv, ifaceName, propId, NULL, 0);
} }
void
xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv,
JSObject *obj, const char* propName)
{
JSString *str = JS_InternString(cx, propName);
if (!str) {
return;
}
xpc_qsThrowBadSetterValue(cx, rv, obj, INTERNED_STRING_TO_JSID(cx, str));
}
void
xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj,
uint16_t name_index)
{
xpc_qsThrowBadSetterValue(cx, rv, obj, xpc_qsStringTable + name_index);
}
JSBool JSBool
xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict,
JSMutableHandleValue vp) JSMutableHandleValue vp)
@ -558,6 +413,16 @@ xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, J
JSMSG_GETTER_ONLY); JSMSG_GETTER_ONLY);
} }
JSBool
xpc_qsGetterOnlyNativeStub(JSContext *cx, unsigned argc, jsval *vp)
{
return JS_ReportErrorFlagsAndNumber(cx,
JSREPORT_WARNING | JSREPORT_STRICT |
JSREPORT_STRICT_MODE_ERROR,
js_GetErrorMessage, NULL,
JSMSG_GETTER_ONLY);
}
xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval, xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
StringificationBehavior nullBehavior, StringificationBehavior nullBehavior,
StringificationBehavior undefinedBehavior) StringificationBehavior undefinedBehavior)

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

@ -19,8 +19,8 @@ class XPCCallContext;
struct xpc_qsPropertySpec { struct xpc_qsPropertySpec {
uint16_t name_index; uint16_t name_index;
JSPropertyOp getter; JSNative getter;
JSStrictPropertyOp setter; JSNative setter;
}; };
struct xpc_qsFunctionSpec { struct xpc_qsFunctionSpec {
@ -70,6 +70,13 @@ xpc_qsThrow(JSContext *cx, nsresult rv);
JSBool JSBool
xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv,
JSObject *obj, jsid memberId); JSObject *obj, jsid memberId);
// And variants using strings and string tables
JSBool
xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv,
JSObject *obj, const char* memberName);
JSBool
xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv,
JSObject *obj, uint16_t memberIndex);
/** /**
* Fail after an XPCOM method returned rv. * Fail after an XPCOM method returned rv.
@ -110,11 +117,21 @@ xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, unsigned paramnum,
void void
xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj, xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj,
jsid propId); jsid propId);
// And variants using strings and string tables
void
xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj,
const char* propName);
void
xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj,
uint16_t name_index);
JSBool JSBool
xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp); xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp);
JSBool
xpc_qsGetterOnlyNativeStub(JSContext *cx, unsigned argc, jsval *vp);
/* Functions for converting values between COM and JS. */ /* Functions for converting values between COM and JS. */
inline JSBool inline JSBool

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

@ -385,6 +385,7 @@ class StringTable:
% (offset, explodeToCharArray(string))) % (offset, explodeToCharArray(string)))
f.write(" /* %5d */ %s, '\\0' };\n\n" f.write(" /* %5d */ %s, '\\0' };\n\n"
% (entries[-1][1], explodeToCharArray(entries[-1][0]))) % (entries[-1][1], explodeToCharArray(entries[-1][0])))
f.write("const char* xpc_qsStringTable = %s;\n\n" % name);
def substitute(template, vals): def substitute(template, vals):
""" Simple replacement for string.Template, which isn't in Python 2.3. """ """ Simple replacement for string.Template, which isn't in Python 2.3. """
@ -491,10 +492,11 @@ argumentUnboxingTemplates = {
# however, defaults to 'undefined'. # however, defaults to 'undefined'.
# #
def writeArgumentUnboxing(f, i, name, type, optional, rvdeclared, def writeArgumentUnboxing(f, i, name, type, optional, rvdeclared,
nullBehavior, undefinedBehavior): nullBehavior, undefinedBehavior,
propIndex=None):
# f - file to write to # f - file to write to
# i - int or None - Indicates the source jsval. If i is an int, the source # i - int or None - Indicates the source jsval. If i is an int, the source
# jsval is argv[i]; otherwise it is *vp. But if Python i >= C++ argc, # jsval is argv[i]; otherwise it is argv[0]. But if Python i >= C++ argc,
# which can only happen if optional is True, the argument is missing; # which can only happen if optional is True, the argument is missing;
# use JSVAL_NULL as the source jsval instead. # use JSVAL_NULL as the source jsval instead.
# name - str - name of the native C++ variable to create. # name - str - name of the native C++ variable to create.
@ -507,8 +509,8 @@ def writeArgumentUnboxing(f, i, name, type, optional, rvdeclared,
isSetter = (i is None) isSetter = (i is None)
if isSetter: if isSetter:
argPtr = "vp" argPtr = "argv"
argVal = "*vp" argVal = "argv[0]"
elif optional: elif optional:
if typeName == "[jsval]": if typeName == "[jsval]":
val = "JSVAL_VOID" val = "JSVAL_VOID"
@ -559,8 +561,9 @@ def writeArgumentUnboxing(f, i, name, type, optional, rvdeclared,
% (type.name, argVal, name, name, argPtr)) % (type.name, argVal, name, name, argPtr))
f.write(" if (NS_FAILED(rv)) {\n") f.write(" if (NS_FAILED(rv)) {\n")
if isSetter: if isSetter:
f.write(" xpc_qsThrowBadSetterValue(" assert(propIndex is not None)
"cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id);\n") f.write(" xpc_qsThrowBadSetterValue(cx, rv, JSVAL_TO_OBJECT(vp[1]), (uint16_t)%s);\n" %
propIndex)
else: else:
f.write(" xpc_qsThrowBadArg(cx, rv, vp, %d);\n" % i) f.write(" xpc_qsThrowBadArg(cx, rv, vp, %d);\n" % i)
f.write(" return JS_FALSE;\n" f.write(" return JS_FALSE;\n"
@ -569,7 +572,7 @@ def writeArgumentUnboxing(f, i, name, type, optional, rvdeclared,
warn("Unable to unbox argument of type %s (native type %s)" % (type.name, typeName)) warn("Unable to unbox argument of type %s (native type %s)" % (type.name, typeName))
if i is None: if i is None:
src = '*vp' src = 'argv[0]'
else: else:
src = 'argv[%d]' % i src = 'argv[%d]' % i
f.write(" !; // TODO - Unbox argument %s = %s\n" % (name, src)) f.write(" !; // TODO - Unbox argument %s = %s\n" % (name, src))
@ -741,7 +744,8 @@ def validateParam(member, param):
if param.const or param.array or param.shared: if param.const or param.array or param.shared:
pfail("I am a simple caveman.") pfail("I am a simple caveman.")
def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): def writeQuickStub(f, customMethodCalls, stringtable, member, stubName,
isSetter=False):
""" Write a single quick stub (a custom SpiderMonkey getter/setter/method) """ Write a single quick stub (a custom SpiderMonkey getter/setter/method)
for the specified XPCOM interface-member. for the specified XPCOM interface-member.
""" """
@ -750,16 +754,8 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
assert isAttr or isMethod assert isAttr or isMethod
isGetter = isAttr and not isSetter isGetter = isAttr and not isSetter
signature = "static JSBool\n" signature = ("static JSBool\n" +
if isAttr: "%s(JSContext *cx, unsigned argc,%s jsval *vp)\n")
# JSPropertyOp signature.
if isSetter:
signature += "%s(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict,%s JSMutableHandleValue vp_)\n"
else:
signature += "%s(JSContext *cx, JSHandleObject obj, JSHandleId id,%s JSMutableHandleValue vp_)\n"
else:
# JSFastNative.
signature += "%s(JSContext *cx, unsigned argc,%s jsval *vp)\n"
customMethodCall = customMethodCalls.get(stubName, None) customMethodCall = customMethodCalls.get(stubName, None)
@ -792,12 +788,8 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
or header.firstCap(member.name)) or header.firstCap(member.name))
argumentValues = (customMethodCall['additionalArgumentValues'] argumentValues = (customMethodCall['additionalArgumentValues']
% nativeName) % nativeName)
if isAttr: callTemplate += (" return %s(cx, argc, %s, vp);\n"
callTemplate += (" return %s(cx, obj, id%s, %s, vp_);\n" % (templateName, argumentValues))
% (templateName, ", strict" if isSetter else "", argumentValues))
else:
callTemplate += (" return %s(cx, argc, %s, vp);\n"
% (templateName, argumentValues))
callTemplate += "}\n\n" callTemplate += "}\n\n"
# Fall through and create the template function stub called from the # Fall through and create the template function stub called from the
@ -833,15 +825,10 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
f.write("{\n") f.write("{\n")
f.write(" XPC_QS_ASSERT_CONTEXT_OK(cx);\n") f.write(" XPC_QS_ASSERT_CONTEXT_OK(cx);\n")
# Convert JSMutableHandleValue to jsval* # Compute "this".
if isAttr: f.write(" JSObject *obj = JS_THIS_OBJECT(cx, vp);\n"
f.write(" jsval *vp = vp_.address();\n") " if (!obj)\n"
" return JS_FALSE;\n")
# For methods, compute "this".
if isMethod:
f.write(" JSObject *obj = JS_THIS_OBJECT(cx, vp);\n"
" if (!obj)\n"
" return JS_FALSE;\n")
# Get the 'self' pointer. # Get the 'self' pointer.
if customMethodCall is None or not 'thisType' in customMethodCall: if customMethodCall is None or not 'thisType' in customMethodCall:
@ -849,13 +836,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
else: else:
f.write(" %s *self;\n" % customMethodCall['thisType']) f.write(" %s *self;\n" % customMethodCall['thisType'])
f.write(" xpc_qsSelfRef selfref;\n") f.write(" xpc_qsSelfRef selfref;\n")
if isGetter: pthisval = '&vp[1]' # as above, ok to overwrite vp[1]
pthisval = 'vp'
elif isSetter:
f.write(" JS::AutoValueRooter tvr(cx);\n")
pthisval = 'tvr.jsval_addr()'
else:
pthisval = '&vp[1]' # as above, ok to overwrite vp[1]
if unwrapThisFailureFatal: if unwrapThisFailureFatal:
unwrapFatalArg = "true" unwrapFatalArg = "true"
@ -883,10 +864,14 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
requiredArgs = len(member.params) requiredArgs = len(member.params)
while requiredArgs and member.params[requiredArgs-1].optional: while requiredArgs and member.params[requiredArgs-1].optional:
requiredArgs -= 1 requiredArgs -= 1
if requiredArgs: elif isSetter:
f.write(" if (argc < %d)\n" % requiredArgs) requiredArgs = 1
f.write(" return xpc_qsThrow(cx, " else:
"NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n") requiredArgs = 0
if requiredArgs:
f.write(" if (argc < %d)\n" % requiredArgs)
f.write(" return xpc_qsThrow(cx, "
"NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")
# Convert in-parameters. # Convert in-parameters.
rvdeclared = False rvdeclared = False
@ -910,11 +895,13 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
nullBehavior=param.null, nullBehavior=param.null,
undefinedBehavior=param.undefined) undefinedBehavior=param.undefined)
elif isSetter: elif isSetter:
f.write(" jsval *argv = JS_ARGV(cx, vp);\n")
rvdeclared = writeArgumentUnboxing(f, None, 'arg0', member.realtype, rvdeclared = writeArgumentUnboxing(f, None, 'arg0', member.realtype,
optional=False, optional=False,
rvdeclared=rvdeclared, rvdeclared=rvdeclared,
nullBehavior=member.null, nullBehavior=member.null,
undefinedBehavior=member.undefined) undefinedBehavior=member.undefined,
propIndex=stringtable.stringIndex(member.name))
canFail = customMethodCall is None or customMethodCall.get('canFail', True) canFail = customMethodCall is None or customMethodCall.get('canFail', True)
if canFail and not rvdeclared: if canFail and not rvdeclared:
@ -987,12 +974,9 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
f.write(" return xpc_qsThrowMethodFailed(" f.write(" return xpc_qsThrowMethodFailed("
"cx, rv, vp);\n") "cx, rv, vp);\n")
else: else:
if isGetter:
thisval = '*vp'
else:
thisval = '*tvr.jsval_addr()'
f.write(" return xpc_qsThrowGetterSetterFailed(cx, rv, " + f.write(" return xpc_qsThrowGetterSetterFailed(cx, rv, " +
"JSVAL_TO_OBJECT(%s), id);\n" % thisval) "JSVAL_TO_OBJECT(vp[1]), (uint16_t)%d);\n" %
stringtable.stringIndex(member.name))
# Convert the return value. # Convert the return value.
if isMethod or isGetter: if isMethod or isGetter:
@ -1014,14 +998,15 @@ def writeAttrStubs(f, customMethodCalls, stringtable, attr):
getterName = (attr.iface.name + '_' getterName = (attr.iface.name + '_'
+ header.attributeNativeName(attr, True)) + header.attributeNativeName(attr, True))
if not custom: if not custom:
writeQuickStub(f, customMethodCalls, attr, getterName) writeQuickStub(f, customMethodCalls, stringtable, attr, getterName)
if attr.readonly: if attr.readonly:
setterName = 'xpc_qsGetterOnlyPropertyStub' setterName = 'xpc_qsGetterOnlyNativeStub'
else: else:
setterName = (attr.iface.name + '_' setterName = (attr.iface.name + '_'
+ header.attributeNativeName(attr, False)) + header.attributeNativeName(attr, False))
if not custom: if not custom:
writeQuickStub(f, customMethodCalls, attr, setterName, isSetter=True) writeQuickStub(f, customMethodCalls, stringtable, attr, setterName,
isSetter=True)
ps = ('{%d, %s, %s}' ps = ('{%d, %s, %s}'
% (stringtable.stringIndex(attr.name), getterName, setterName)) % (stringtable.stringIndex(attr.name), getterName, setterName))
@ -1035,7 +1020,7 @@ def writeMethodStub(f, customMethodCalls, stringtable, method):
stubName = method.iface.name + '_' + header.methodNativeName(method) stubName = method.iface.name + '_' + header.methodNativeName(method)
if not custom: if not custom:
writeQuickStub(f, customMethodCalls, method, stubName) writeQuickStub(f, customMethodCalls, stringtable, method, stubName)
fs = '{%d, %d, %s}' % (stringtable.stringIndex(method.name), fs = '{%d, %d, %s}' % (stringtable.stringIndex(method.name),
len(method.params), stubName) len(method.params), stubName)
return fs return fs