forked from mirrors/gecko-dev
Bug 1484496: Part 1 - Add support for symbol properties to XPIDL. r=nika
This patch allows us to define methods or getters/setters for any of the current set of well-known symbols. Those are defined by adding the [symbol] attribute to a method: [symbol] Iterator iterator(); which causes the method to define a property with the well-known symbol which matches its method name (Symbol.iterator, in this case). Due to the implementation details of the XPIDL parser, this currently does not support defining a non-symbol function with the same name as a symbol function: [symbol] Iterator iterator(); [binaryname(OtherIterator)] Thing iterator(in nsIDRef aIID); throws for a duplicate method name, even though there is no actual conflict. Differential Revision: https://phabricator.services.mozilla.com/D3724 --HG-- extra : rebase_source : 1385e2da93113306730f7c087fe7385dbe668e91 extra : histedit_source : 3afd9fe38e7cbddc5576c2bd1673496dd623e489
This commit is contained in:
parent
b219ce3bfc
commit
83db11134f
7 changed files with 97 additions and 15 deletions
|
|
@ -943,7 +943,6 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
|||
bool success;
|
||||
bool readyToDoTheCall = false;
|
||||
nsID param_iid;
|
||||
const char* name = info->GetName();
|
||||
bool foundDependentParam;
|
||||
|
||||
// We're about to call into script via an XPCWrappedJS, so we need an
|
||||
|
|
@ -962,6 +961,19 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
|||
if (!cx || !IsReflectable(methodIndex))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JS::RootedId id(cx);
|
||||
const char* name;
|
||||
nsAutoCString symbolName;
|
||||
if (info->IsSymbol()) {
|
||||
info->GetSymbolDescription(cx, symbolName);
|
||||
name = symbolName.get();
|
||||
id = SYMBOL_TO_JSID(info->GetSymbol(cx));
|
||||
} else {
|
||||
name = info->GetName();
|
||||
if (!AtomizeAndPinJSString(cx, id.get(), name))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// We passed the unwrapped object's global to AutoEntryScript so we now need
|
||||
// to enter the realm corresponding with the (maybe wrapper) object.
|
||||
RootedObject scope(cx, wrapper->GetJSObjectGlobal());
|
||||
|
|
@ -1030,7 +1042,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
|||
|
||||
fval = ObjectValue(*obj);
|
||||
if (!isFunction || JS_TypeOfValue(ccx, fval) != JSTYPE_FUNCTION) {
|
||||
if (!JS_GetProperty(cx, obj, name, &fval))
|
||||
if (!JS_GetPropertyById(cx, obj, id, &fval))
|
||||
goto pre_call_clean_up;
|
||||
// XXX We really want to factor out the error reporting better and
|
||||
// specifically report the failure to find a function with this name.
|
||||
|
|
|
|||
|
|
@ -87,7 +87,13 @@ XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
|
|||
callback = XPC_WN_GetterSetter;
|
||||
}
|
||||
|
||||
JSFunction* fun = js::NewFunctionByIdWithReserved(ccx, callback, argc, 0, GetName());
|
||||
JSFunction* fun;
|
||||
jsid name = GetName();
|
||||
if (JSID_IS_STRING(name)) {
|
||||
fun = js::NewFunctionByIdWithReserved(ccx, callback, argc, 0, GetName());
|
||||
} else {
|
||||
fun = js::NewFunctionWithReserved(ccx, callback, argc, 0, nullptr);
|
||||
}
|
||||
if (!fun)
|
||||
return false;
|
||||
|
||||
|
|
@ -292,13 +298,18 @@ XPCNativeInterface::NewInstance(const nsXPTInterfaceInfo* aInfo)
|
|||
if (!XPCConvert::IsMethodReflectable(*info))
|
||||
continue;
|
||||
|
||||
str = JS_AtomizeAndPinString(cx, info->GetName());
|
||||
if (!str) {
|
||||
NS_ERROR("bad method name");
|
||||
failed = true;
|
||||
break;
|
||||
jsid name;
|
||||
if (info->IsSymbol()) {
|
||||
name = SYMBOL_TO_JSID(info->GetSymbol(cx));
|
||||
} else {
|
||||
str = JS_AtomizeAndPinString(cx, info->GetName());
|
||||
if (!str) {
|
||||
NS_ERROR("bad method name");
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
name = INTERNED_STRING_TO_JSID(cx, str);
|
||||
}
|
||||
jsid name = INTERNED_STRING_TO_JSID(cx, str);
|
||||
|
||||
if (info->IsSetter()) {
|
||||
MOZ_ASSERT(realTotalCount,"bad setter");
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ def mk_param(type, in_=0, out=0, optional=0):
|
|||
|
||||
|
||||
def mk_method(name, params, getter=0, setter=0, notxpcom=0,
|
||||
hidden=0, optargc=0, context=0, hasretval=0):
|
||||
hidden=0, optargc=0, context=0, hasretval=0,
|
||||
symbol=0):
|
||||
return {
|
||||
'name': name,
|
||||
# NOTE: We don't include any return value information here, as we'll
|
||||
|
|
@ -138,6 +139,7 @@ def mk_method(name, params, getter=0, setter=0, notxpcom=0,
|
|||
('optargc', optargc),
|
||||
('jscontext', context),
|
||||
('hasretval', hasretval),
|
||||
('symbol', symbol),
|
||||
),
|
||||
}
|
||||
|
||||
|
|
@ -186,19 +188,21 @@ def build_interface(iface):
|
|||
methods.append(mk_method(
|
||||
m.name, params, notxpcom=m.notxpcom, hidden=m.noscript,
|
||||
optargc=m.optional_argc, context=m.implicit_jscontext,
|
||||
hasretval=hasretval))
|
||||
hasretval=hasretval, symbol=m.symbol))
|
||||
|
||||
def build_attr(a):
|
||||
# Write the getter
|
||||
param = mk_param(get_type(a.realtype, 'out'), out=1)
|
||||
methods.append(mk_method(a.name, [param], getter=1, hidden=a.noscript,
|
||||
context=a.implicit_jscontext, hasretval=1))
|
||||
context=a.implicit_jscontext, hasretval=1,
|
||||
symbol=a.symbol))
|
||||
|
||||
# And maybe the setter
|
||||
if not a.readonly:
|
||||
param = mk_param(get_type(a.realtype, 'in'), in_=1)
|
||||
methods.append(mk_method(a.name, [param], setter=1, hidden=a.noscript,
|
||||
context=a.implicit_jscontext))
|
||||
context=a.implicit_jscontext,
|
||||
symbol=a.symbol))
|
||||
|
||||
for member in iface.members:
|
||||
if isinstance(member, xpidl.ConstMember):
|
||||
|
|
|
|||
|
|
@ -912,6 +912,7 @@ class Attribute(object):
|
|||
kind = 'attribute'
|
||||
noscript = False
|
||||
readonly = False
|
||||
symbol = False
|
||||
implicit_jscontext = False
|
||||
nostdcall = False
|
||||
must_use = False
|
||||
|
|
@ -963,6 +964,8 @@ class Attribute(object):
|
|||
|
||||
if name == 'noscript':
|
||||
self.noscript = True
|
||||
elif name == 'symbol':
|
||||
self.symbol = True
|
||||
elif name == 'implicit_jscontext':
|
||||
self.implicit_jscontext = True
|
||||
elif name == 'nostdcall':
|
||||
|
|
@ -1019,6 +1022,7 @@ class Method(object):
|
|||
kind = 'method'
|
||||
noscript = False
|
||||
notxpcom = False
|
||||
symbol = False
|
||||
binaryname = None
|
||||
implicit_jscontext = False
|
||||
nostdcall = False
|
||||
|
|
@ -1050,6 +1054,8 @@ class Method(object):
|
|||
self.noscript = True
|
||||
elif name == 'notxpcom':
|
||||
self.notxpcom = True
|
||||
elif name == 'symbol':
|
||||
self.symbol = True
|
||||
elif name == 'implicit_jscontext':
|
||||
self.implicit_jscontext = True
|
||||
elif name == 'optional_argc':
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ nsXPTMethodInfo = mkstruct(
|
|||
"mOptArgc",
|
||||
"mContext",
|
||||
"mHasRetval",
|
||||
"mIsSymbol",
|
||||
)
|
||||
|
||||
##########################################################
|
||||
|
|
@ -244,6 +245,9 @@ def link_to_cpp(interfaces, fd):
|
|||
strings[s] = 0
|
||||
return strings[s]
|
||||
|
||||
def lower_symbol(s):
|
||||
return "uint32_t(JS::SymbolCode::%s)" % s
|
||||
|
||||
def lower_extra_type(type):
|
||||
key = describe_type(type)
|
||||
idx = type_cache.get(key)
|
||||
|
|
@ -315,10 +319,16 @@ def link_to_cpp(interfaces, fd):
|
|||
def lower_method(method, ifacename):
|
||||
methodname = "%s::%s" % (ifacename, method['name'])
|
||||
|
||||
isSymbol = 'symbol' in method['flags']
|
||||
|
||||
if 'notxpcom' in method['flags'] or 'hidden' in method['flags']:
|
||||
paramidx = name = numparams = 0 # hide parameters
|
||||
else:
|
||||
name = lower_string(method['name'])
|
||||
if isSymbol:
|
||||
name = lower_symbol(method['name'])
|
||||
else:
|
||||
name = lower_string(method['name'])
|
||||
|
||||
numparams = len(method['params'])
|
||||
|
||||
# Check cache for parameters
|
||||
|
|
@ -346,6 +356,7 @@ def link_to_cpp(interfaces, fd):
|
|||
mOptArgc='optargc' in method['flags'],
|
||||
mContext='jscontext' in method['flags'],
|
||||
mHasRetval='hasretval' in method['flags'],
|
||||
mIsSymbol=isSymbol,
|
||||
))
|
||||
|
||||
def lower_const(const, ifacename):
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include "mozilla/dom/DOMJSClass.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace xpt::detail;
|
||||
|
|
@ -168,3 +170,22 @@ nsXPTInterfaceInfo::IsMainProcessScriptableOnly(bool* aRetval) const
|
|||
*aRetval = IsMainProcessScriptableOnly();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
// nsXPTMethodInfo symbol helpers //
|
||||
////////////////////////////////////
|
||||
|
||||
void
|
||||
nsXPTMethodInfo::GetSymbolDescription(JSContext* aCx, nsACString& aID) const
|
||||
{
|
||||
JS::RootedSymbol symbol(aCx, GetSymbol(aCx));
|
||||
JSString* desc = JS::GetSymbolDescription(symbol);
|
||||
MOZ_ASSERT(JS_StringHasLatin1Chars(desc));
|
||||
|
||||
JS::AutoAssertNoGC nogc(aCx);
|
||||
size_t length;
|
||||
const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(
|
||||
aCx, nogc, desc, &length);
|
||||
|
||||
aID.AssignASCII(reinterpret_cast<const char*>(chars), length);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <stdint.h>
|
||||
#include "nsID.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/Value.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
|
@ -440,11 +441,13 @@ struct nsXPTMethodInfo
|
|||
bool IsSetter() const { return mSetter; }
|
||||
bool IsNotXPCOM() const { return mNotXPCOM; }
|
||||
bool IsHidden() const { return mHidden; }
|
||||
bool IsSymbol() const { return mIsSymbol; }
|
||||
bool WantsOptArgc() const { return mOptArgc; }
|
||||
bool WantsContext() const { return mContext; }
|
||||
uint8_t ParamCount() const { return mNumParams; }
|
||||
|
||||
const char* Name() const {
|
||||
MOZ_ASSERT(!IsSymbol());
|
||||
return xpt::detail::GetString(mName);
|
||||
}
|
||||
const nsXPTParamInfo& Param(uint8_t aIndex) const {
|
||||
|
|
@ -478,6 +481,20 @@ struct nsXPTMethodInfo
|
|||
/////////////////////////////////////////////
|
||||
|
||||
const char* GetName() const { return Name(); }
|
||||
|
||||
JS::SymbolCode GetSymbolCode() const
|
||||
{
|
||||
MOZ_ASSERT(IsSymbol());
|
||||
return JS::SymbolCode(mName);
|
||||
}
|
||||
|
||||
JS::Symbol* GetSymbol(JSContext* aCx) const
|
||||
{
|
||||
return JS::GetWellKnownSymbol(aCx, GetSymbolCode());
|
||||
}
|
||||
|
||||
void GetSymbolDescription(JSContext* aCx, nsACString& aID) const;
|
||||
|
||||
uint8_t GetParamCount() const { return ParamCount(); }
|
||||
const nsXPTParamInfo& GetParam(uint8_t aIndex) const {
|
||||
return Param(aIndex);
|
||||
|
|
@ -498,7 +515,7 @@ struct nsXPTMethodInfo
|
|||
uint8_t mOptArgc : 1;
|
||||
uint8_t mContext : 1;
|
||||
uint8_t mHasRetval : 1;
|
||||
// uint8_t unused : 1;
|
||||
uint8_t mIsSymbol : 1;
|
||||
};
|
||||
|
||||
// The fields in nsXPTMethodInfo were carefully ordered to minimize size.
|
||||
|
|
|
|||
Loading…
Reference in a new issue