diff options
author | Corey Farwell <coreyf@rwell.org> | 2015-07-09 07:09:52 +0900 |
---|---|---|
committer | Corey Farwell <coreyf@rwell.org> | 2015-07-09 07:25:14 +0900 |
commit | 1ce089abf47e9aa62e862c9e1d875727c4297c07 (patch) | |
tree | e37d94ca816b35e5015515b7efb86968a9270bba /components/script/dom | |
parent | 805232a85e401f1a07635da894c8e7d05fed4ce9 (diff) | |
download | servo-1ce089abf47e9aa62e862c9e1d875727c4297c07.tar.gz servo-1ce089abf47e9aa62e862c9e1d875727c4297c07.zip |
Remove unused files in 'script/dom/bindings/'
As per this conversation:
https://github.com/servo/servo/pull/6580
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/BindingUtils.cpp | 633 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/BindingUtils.h | 1151 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/Codegen.py | 5788 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/DOMJSClass.h | 114 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/DOMJSProxyHandler.cpp | 247 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/DOMJSProxyHandler.h | 109 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/ErrorResult.h | 59 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/GlobalGen.py | 2 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/Nullable.h | 68 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/PrimitiveConversions.h | 350 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/RegisterBindings.h | 14 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/TypedArray.h | 121 |
12 files changed, 0 insertions, 8656 deletions
diff --git a/components/script/dom/bindings/codegen/BindingUtils.cpp b/components/script/dom/bindings/codegen/BindingUtils.cpp deleted file mode 100644 index 27ac92e3596..00000000000 --- a/components/script/dom/bindings/codegen/BindingUtils.cpp +++ /dev/null @@ -1,633 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* vim: set ts=2 sw=2 et tw=79: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <stdarg.h> - -#include "BindingUtils.h" - -#include "WrapperFactory.h" -#include "xpcprivate.h" -#include "XPCQuickStubs.h" - -namespace mozilla { -namespace dom { - -JSErrorFormatString ErrorFormatString[] = { -#define MSG_DEF(_name, _argc, _str) \ - { _str, _argc, JSEXN_TYPEERR }, -#include "mozilla/dom/Errors.msg" -#undef MSG_DEF -}; - -const JSErrorFormatString* -GetErrorMessage(void* aUserRef, const char* aLocale, - const unsigned aErrorNumber) -{ - MOZ_ASSERT(aErrorNumber < ArrayLength(ErrorFormatString)); - return &ErrorFormatString[aErrorNumber]; -} - -bool -ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...) -{ - va_list ap; - va_start(ap, aErrorNumber); - JS_ReportErrorNumberVA(aCx, GetErrorMessage, NULL, - static_cast<const unsigned>(aErrorNumber), ap); - va_end(ap); - return false; -} - -bool -DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs) -{ - for (; cs->name; ++cs) { - JSBool ok = - JS_DefineProperty(cx, obj, cs->name, cs->value, NULL, NULL, - JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); - if (!ok) { - return false; - } - } - return true; -} - -static inline bool -Define(JSContext* cx, JSObject* obj, JSFunctionSpec* spec) { - return JS_DefineFunctions(cx, obj, spec); -} -static inline bool -Define(JSContext* cx, JSObject* obj, JSPropertySpec* spec) { - return JS_DefineProperties(cx, obj, spec); -} -static inline bool -Define(JSContext* cx, JSObject* obj, ConstantSpec* spec) { - return DefineConstants(cx, obj, spec); -} - -template<typename T> -bool -DefinePrefable(JSContext* cx, JSObject* obj, Prefable<T>* props) -{ - MOZ_ASSERT(props); - MOZ_ASSERT(props->specs); - do { - // Define if enabled - if (props->enabled) { - if (!Define(cx, obj, props->specs)) { - return false; - } - } - } while ((++props)->specs); - return true; -} - -// We should use JSFunction objects for interface objects, but we need a custom -// hasInstance hook because we have new interface objects on prototype chains of -// old (XPConnect-based) bindings. Because Function.prototype.toString throws if -// passed a non-Function object we also need to provide our own toString method -// for interface objects. - -enum { - TOSTRING_CLASS_RESERVED_SLOT = 0, - TOSTRING_NAME_RESERVED_SLOT = 1 -}; - -JSBool -InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp) -{ - JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); - - JSObject* obj = JS_THIS_OBJECT(cx, vp); - if (!obj) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO, - "null", "object"); - return false; - } - - jsval v = js::GetFunctionNativeReserved(callee, TOSTRING_CLASS_RESERVED_SLOT); - JSClass* clasp = static_cast<JSClass*>(JSVAL_TO_PRIVATE(v)); - - v = js::GetFunctionNativeReserved(callee, TOSTRING_NAME_RESERVED_SLOT); - JSString* jsname = static_cast<JSString*>(JSVAL_TO_STRING(v)); - size_t length; - const jschar* name = JS_GetInternedStringCharsAndLength(jsname, &length); - - if (js::GetObjectJSClass(obj) != clasp) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, - NS_ConvertUTF16toUTF8(name).get(), "toString", - "object"); - return false; - } - - nsString str; - str.AppendLiteral("function "); - str.Append(name, length); - str.AppendLiteral("() {"); - str.Append('\n'); - str.AppendLiteral(" [native code]"); - str.Append('\n'); - str.AppendLiteral("}"); - - return xpc::NonVoidStringToJsval(cx, str, vp); -} - -static JSObject* -CreateInterfaceObject(JSContext* cx, JSObject* global, JSObject* receiver, - JSClass* constructorClass, JSNative constructorNative, - unsigned ctorNargs, JSObject* proto, - Prefable<JSFunctionSpec>* staticMethods, - Prefable<ConstantSpec>* constants, - const char* name) -{ - JSObject* constructor; - if (constructorClass) { - JSObject* functionProto = JS_GetFunctionPrototype(cx, global); - if (!functionProto) { - return NULL; - } - constructor = JS_NewObject(cx, constructorClass, functionProto, global); - } else { - MOZ_ASSERT(constructorNative); - JSFunction* fun = JS_NewFunction(cx, constructorNative, ctorNargs, - JSFUN_CONSTRUCTOR, global, name); - if (!fun) { - return NULL; - } - constructor = JS_GetFunctionObject(fun); - } - if (!constructor) { - return NULL; - } - - if (staticMethods && !DefinePrefable(cx, constructor, staticMethods)) { - return NULL; - } - - if (constructorClass) { - JSFunction* toString = js::DefineFunctionWithReserved(cx, constructor, - "toString", - InterfaceObjectToString, - 0, 0); - if (!toString) { - return NULL; - } - - JSObject* toStringObj = JS_GetFunctionObject(toString); - js::SetFunctionNativeReserved(toStringObj, TOSTRING_CLASS_RESERVED_SLOT, - PRIVATE_TO_JSVAL(constructorClass)); - - JSString *str = ::JS_InternString(cx, name); - if (!str) { - return NULL; - } - js::SetFunctionNativeReserved(toStringObj, TOSTRING_NAME_RESERVED_SLOT, - STRING_TO_JSVAL(str)); - } - - if (constants && !DefinePrefable(cx, constructor, constants)) { - return NULL; - } - - if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) { - return NULL; - } - - JSBool alreadyDefined; - if (!JS_AlreadyHasOwnProperty(cx, receiver, name, &alreadyDefined)) { - return NULL; - } - - // This is Enumerable: False per spec. - if (!alreadyDefined && - !JS_DefineProperty(cx, receiver, name, OBJECT_TO_JSVAL(constructor), NULL, - NULL, 0)) { - return NULL; - } - - return constructor; -} - -static JSObject* -CreateInterfacePrototypeObject(JSContext* cx, JSObject* global, - JSObject* parentProto, JSClass* protoClass, - Prefable<JSFunctionSpec>* methods, - Prefable<JSPropertySpec>* properties, - Prefable<ConstantSpec>* constants) -{ - JSObject* ourProto = JS_NewObjectWithUniqueType(cx, protoClass, parentProto, - global); - if (!ourProto) { - return NULL; - } - - if (methods && !DefinePrefable(cx, ourProto, methods)) { - return NULL; - } - - if (properties && !DefinePrefable(cx, ourProto, properties)) { - return NULL; - } - - if (constants && !DefinePrefable(cx, ourProto, constants)) { - return NULL; - } - - return ourProto; -} - -JSObject* -CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver, - JSObject* protoProto, JSClass* protoClass, - JSClass* constructorClass, JSNative constructor, - unsigned ctorNargs, const DOMClass* domClass, - Prefable<JSFunctionSpec>* methods, - Prefable<JSPropertySpec>* properties, - Prefable<ConstantSpec>* constants, - Prefable<JSFunctionSpec>* staticMethods, const char* name) -{ - MOZ_ASSERT(protoClass || constructorClass || constructor, - "Need at least one class or a constructor!"); - MOZ_ASSERT(!(methods || properties) || protoClass, - "Methods or properties but no protoClass!"); - MOZ_ASSERT(!staticMethods || constructorClass || constructor, - "Static methods but no constructorClass or constructor!"); - MOZ_ASSERT(bool(name) == bool(constructorClass || constructor), - "Must have name precisely when we have an interface object"); - MOZ_ASSERT(!constructorClass || !constructor); - - JSObject* proto; - if (protoClass) { - proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass, - methods, properties, constants); - if (!proto) { - return NULL; - } - - js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT, - JS::PrivateValue(const_cast<DOMClass*>(domClass))); - } - else { - proto = NULL; - } - - JSObject* interface; - if (constructorClass || constructor) { - interface = CreateInterfaceObject(cx, global, receiver, constructorClass, - constructor, ctorNargs, proto, - staticMethods, constants, name); - if (!interface) { - return NULL; - } - } - - return protoClass ? proto : interface; -} - -static bool -NativeInterface2JSObjectAndThrowIfFailed(XPCLazyCallContext& aLccx, - JSContext* aCx, - JS::Value* aRetval, - xpcObjectHelper& aHelper, - const nsIID* aIID, - bool aAllowNativeWrapper) -{ - nsresult rv; - if (!XPCConvert::NativeInterface2JSObject(aLccx, aRetval, NULL, aHelper, aIID, - NULL, aAllowNativeWrapper, &rv)) { - // I can't tell if NativeInterface2JSObject throws JS exceptions - // or not. This is a sloppy stab at the right semantics; the - // method really ought to be fixed to behave consistently. - if (!JS_IsExceptionPending(aCx)) { - Throw<true>(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED); - } - return false; - } - return true; -} - -bool -DoHandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope, - nsISupports* value, JS::Value* vp) -{ - if (JS_IsExceptionPending(cx)) { - return false; - } - - XPCLazyCallContext lccx(JS_CALLER, cx, scope); - - if (value) { - xpcObjectHelper helper(value); - return NativeInterface2JSObjectAndThrowIfFailed(lccx, cx, vp, helper, NULL, - true); - } - - return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS); -} - -// Can only be called with the immediate prototype of the instance object. Can -// only be called on the prototype of an object known to be a DOM instance. -JSBool -InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID, - uint32_t depth) -{ - const DOMClass* domClass = static_cast<DOMClass*>( - js::GetReservedSlot(protoObject, DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate()); - return (uint32_t)domClass->mInterfaceChain[depth] == protoID; -} - -// Only set allowNativeWrapper to false if you really know you need it, if in -// doubt use true. Setting it to false disables security wrappers. -bool -XPCOMObjectToJsval(JSContext* cx, JSObject* scope, xpcObjectHelper &helper, - const nsIID* iid, bool allowNativeWrapper, JS::Value* rval) -{ - XPCLazyCallContext lccx(JS_CALLER, cx, scope); - - if (!NativeInterface2JSObjectAndThrowIfFailed(lccx, cx, rval, helper, iid, - allowNativeWrapper)) { - return false; - } - -#ifdef DEBUG - JSObject* jsobj = JSVAL_TO_OBJECT(*rval); - if (jsobj && !js::GetObjectParent(jsobj)) - NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL, - "Why did we recreate this wrapper?"); -#endif - - return true; -} - -JSBool -QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp) -{ - JS::Value thisv = JS_THIS(cx, vp); - if (thisv == JSVAL_NULL) - return false; - - // Get the object. It might be a security wrapper, in which case we do a checked - // unwrap. - JSObject* origObj = JSVAL_TO_OBJECT(thisv); - JSObject* obj = js::UnwrapObjectChecked(cx, origObj); - if (!obj) - return false; - - nsISupports* native; - if (!UnwrapDOMObjectToISupports(obj, native)) { - return Throw<true>(cx, NS_ERROR_FAILURE); - } - - if (argc < 1) { - return Throw<true>(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS); - } - - JS::Value* argv = JS_ARGV(cx, vp); - if (!argv[0].isObject()) { - return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS); - } - - nsIJSIID* iid; - xpc_qsSelfRef iidRef; - if (NS_FAILED(xpc_qsUnwrapArg<nsIJSIID>(cx, argv[0], &iid, &iidRef.ptr, - &argv[0]))) { - return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS); - } - MOZ_ASSERT(iid); - - if (iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))) { - nsresult rv; - nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv); - if (NS_FAILED(rv)) { - return Throw<true>(cx, rv); - } - - return WrapObject(cx, origObj, ci, &NS_GET_IID(nsIClassInfo), vp); - } - - // Lie, otherwise we need to check classinfo or QI - *vp = thisv; - return true; -} - -JSBool -ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp) -{ - return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR); -} - -bool -XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id, - JSPropertyDescriptor* desc, - // And the things we need to determine the descriptor - Prefable<JSFunctionSpec>* methods, - jsid* methodIds, - JSFunctionSpec* methodSpecs, - size_t methodCount, - Prefable<JSPropertySpec>* attributes, - jsid* attributeIds, - JSPropertySpec* attributeSpecs, - size_t attributeCount, - Prefable<ConstantSpec>* constants, - jsid* constantIds, - ConstantSpec* constantSpecs, - size_t constantCount) -{ - for (size_t prefIdx = 0; prefIdx < methodCount; ++prefIdx) { - MOZ_ASSERT(methods[prefIdx].specs); - if (methods[prefIdx].enabled) { - // Set i to be the index into our full list of ids/specs that we're - // looking at now. - size_t i = methods[prefIdx].specs - methodSpecs; - for ( ; methodIds[i] != JSID_VOID; ++i) { - if (id == methodIds[i]) { - JSFunction *fun = JS_NewFunctionById(cx, methodSpecs[i].call.op, - methodSpecs[i].nargs, 0, - wrapper, id); - if (!fun) { - return false; - } - SET_JITINFO(fun, methodSpecs[i].call.info); - JSObject *funobj = JS_GetFunctionObject(fun); - desc->value.setObject(*funobj); - desc->attrs = methodSpecs[i].flags; - desc->obj = wrapper; - desc->setter = nullptr; - desc->getter = nullptr; - return true; - } - } - } - } - - for (size_t prefIdx = 0; prefIdx < attributeCount; ++prefIdx) { - MOZ_ASSERT(attributes[prefIdx].specs); - if (attributes[prefIdx].enabled) { - // Set i to be the index into our full list of ids/specs that we're - // looking at now. - size_t i = attributes[prefIdx].specs - attributeSpecs; - for ( ; attributeIds[i] != JSID_VOID; ++i) { - if (id == attributeIds[i]) { - // Because of centralization, we need to make sure we fault in the - // JitInfos as well. At present, until the JSAPI changes, the easiest - // way to do this is wrap them up as functions ourselves. - desc->attrs = attributeSpecs[i].flags & ~JSPROP_NATIVE_ACCESSORS; - // They all have getters, so we can just make it. - JSObject *global = JS_GetGlobalForObject(cx, wrapper); - JSFunction *fun = JS_NewFunction(cx, (JSNative)attributeSpecs[i].getter.op, - 0, 0, global, NULL); - if (!fun) - return false; - SET_JITINFO(fun, attributeSpecs[i].getter.info); - JSObject *funobj = JS_GetFunctionObject(fun); - desc->getter = js::CastAsJSPropertyOp(funobj); - desc->attrs |= JSPROP_GETTER; - if (attributeSpecs[i].setter.op) { - // We have a setter! Make it. - fun = JS_NewFunction(cx, (JSNative)attributeSpecs[i].setter.op, - 1, 0, global, NULL); - if (!fun) - return false; - SET_JITINFO(fun, attributeSpecs[i].setter.info); - funobj = JS_GetFunctionObject(fun); - desc->setter = js::CastAsJSStrictPropertyOp(funobj); - desc->attrs |= JSPROP_SETTER; - } else { - desc->setter = NULL; - } - desc->obj = wrapper; - return true; - } - } - } - } - - for (size_t prefIdx = 0; prefIdx < constantCount; ++prefIdx) { - MOZ_ASSERT(constants[prefIdx].specs); - if (constants[prefIdx].enabled) { - // Set i to be the index into our full list of ids/specs that we're - // looking at now. - size_t i = constants[prefIdx].specs - constantSpecs; - for ( ; constantIds[i] != JSID_VOID; ++i) { - if (id == constantIds[i]) { - desc->attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT; - desc->obj = wrapper; - desc->value = constantSpecs[i].value; - return true; - } - } - } - } - - return true; -} - -bool -XrayEnumerateProperties(JS::AutoIdVector& props, - Prefable<JSFunctionSpec>* methods, - jsid* methodIds, - JSFunctionSpec* methodSpecs, - size_t methodCount, - Prefable<JSPropertySpec>* attributes, - jsid* attributeIds, - JSPropertySpec* attributeSpecs, - size_t attributeCount, - Prefable<ConstantSpec>* constants, - jsid* constantIds, - ConstantSpec* constantSpecs, - size_t constantCount) -{ - for (size_t prefIdx = 0; prefIdx < methodCount; ++prefIdx) { - MOZ_ASSERT(methods[prefIdx].specs); - if (methods[prefIdx].enabled) { - // Set i to be the index into our full list of ids/specs that we're - // looking at now. - size_t i = methods[prefIdx].specs - methodSpecs; - for ( ; methodIds[i] != JSID_VOID; ++i) { - if ((methodSpecs[i].flags & JSPROP_ENUMERATE) && - !props.append(methodIds[i])) { - return false; - } - } - } - } - - for (size_t prefIdx = 0; prefIdx < attributeCount; ++prefIdx) { - MOZ_ASSERT(attributes[prefIdx].specs); - if (attributes[prefIdx].enabled) { - // Set i to be the index into our full list of ids/specs that we're - // looking at now. - size_t i = attributes[prefIdx].specs - attributeSpecs; - for ( ; attributeIds[i] != JSID_VOID; ++i) { - if ((attributeSpecs[i].flags & JSPROP_ENUMERATE) && - !props.append(attributeIds[i])) { - return false; - } - } - } - } - - for (size_t prefIdx = 0; prefIdx < constantCount; ++prefIdx) { - MOZ_ASSERT(constants[prefIdx].specs); - if (constants[prefIdx].enabled) { - // Set i to be the index into our full list of ids/specs that we're - // looking at now. - size_t i = constants[prefIdx].specs - constantSpecs; - for ( ; constantIds[i] != JSID_VOID; ++i) { - if (!props.append(constantIds[i])) { - return false; - } - } - } - } - - return true; -} - -bool -GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found, - JS::Value* vp) -{ - JSObject* proto; - if (!js::GetObjectProto(cx, proxy, &proto)) { - return false; - } - if (!proto) { - *found = false; - return true; - } - - JSBool hasProp; - if (!JS_HasPropertyById(cx, proto, id, &hasProp)) { - return false; - } - - *found = hasProp; - if (!hasProp || !vp) { - return true; - } - - return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp); -} - -bool -HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler, - jsid id) -{ - Maybe<JSAutoCompartment> ac; - if (xpc::WrapperFactory::IsXrayWrapper(proxy)) { - proxy = js::UnwrapObject(proxy); - ac.construct(cx, proxy); - } - MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler); - - bool found; - // We ignore an error from GetPropertyOnPrototype. - return !GetPropertyOnPrototype(cx, proxy, id, &found, NULL) || found; -} - -} // namespace dom -} // namespace mozilla diff --git a/components/script/dom/bindings/codegen/BindingUtils.h b/components/script/dom/bindings/codegen/BindingUtils.h deleted file mode 100644 index ee9d6c3691c..00000000000 --- a/components/script/dom/bindings/codegen/BindingUtils.h +++ /dev/null @@ -1,1151 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* vim: set ts=2 sw=2 et tw=79: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_BindingUtils_h__ -#define mozilla_dom_BindingUtils_h__ - -#include "mozilla/dom/DOMJSClass.h" -#include "mozilla/dom/DOMJSProxyHandler.h" -#include "mozilla/dom/workers/Workers.h" -#include "mozilla/ErrorResult.h" - -#include "jsapi.h" -#include "jsfriendapi.h" -#include "jswrapper.h" - -#include "nsIXPConnect.h" -#include "qsObjectHelper.h" -#include "xpcpublic.h" -#include "nsTraceRefcnt.h" -#include "nsWrapperCacheInlines.h" -#include "mozilla/Likely.h" - -// nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't -// try to use it without fixing that first. -class nsGlobalWindow; - -namespace mozilla { -namespace dom { - -enum ErrNum { -#define MSG_DEF(_name, _argc, _str) \ - _name, -#include "mozilla/dom/Errors.msg" -#undef MSG_DEF - Err_Limit -}; - -bool -ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...); - -template<bool mainThread> -inline bool -Throw(JSContext* cx, nsresult rv) -{ - using mozilla::dom::workers::exceptions::ThrowDOMExceptionForNSResult; - - // XXX Introduce exception machinery. - if (mainThread) { - xpc::Throw(cx, rv); - } else { - if (!JS_IsExceptionPending(cx)) { - ThrowDOMExceptionForNSResult(cx, rv); - } - } - return false; -} - -template<bool mainThread> -inline bool -ThrowMethodFailedWithDetails(JSContext* cx, const ErrorResult& rv, - const char* /* ifaceName */, - const char* /* memberName */) -{ - return Throw<mainThread>(cx, rv.ErrorCode()); -} - -inline bool -IsDOMClass(const JSClass* clasp) -{ - return clasp->flags & JSCLASS_IS_DOMJSCLASS; -} - -inline bool -IsDOMClass(const js::Class* clasp) -{ - return IsDOMClass(Jsvalify(clasp)); -} - -// It's ok for eRegularDOMObject and eProxyDOMObject to be the same, but -// eNonDOMObject should always be different from the other two. This enum -// shouldn't be used to differentiate between non-proxy and proxy bindings. -enum DOMObjectSlot { - eNonDOMObject = -1, - eRegularDOMObject = DOM_OBJECT_SLOT, - eProxyDOMObject = DOM_PROXY_OBJECT_SLOT -}; - -template <class T> -inline T* -UnwrapDOMObject(JSObject* obj, DOMObjectSlot slot) -{ - MOZ_ASSERT(slot != eNonDOMObject, - "Don't pass non-DOM objects to this function"); - -#ifdef DEBUG - if (IsDOMClass(js::GetObjectClass(obj))) { - MOZ_ASSERT(slot == eRegularDOMObject); - } else { - MOZ_ASSERT(js::IsObjectProxyClass(js::GetObjectClass(obj)) || - js::IsFunctionProxyClass(js::GetObjectClass(obj))); - MOZ_ASSERT(js::GetProxyHandler(obj)->family() == ProxyFamily()); - MOZ_ASSERT(IsNewProxyBinding(js::GetProxyHandler(obj))); - MOZ_ASSERT(slot == eProxyDOMObject); - } -#endif - - JS::Value val = js::GetReservedSlot(obj, slot); - // XXXbz/khuey worker code tries to unwrap interface objects (which have - // nothing here). That needs to stop. - // XXX We don't null-check UnwrapObject's result; aren't we going to crash - // anyway? - if (val.isUndefined()) { - return NULL; - } - - return static_cast<T*>(val.toPrivate()); -} - -// Only use this with a new DOM binding object (either proxy or regular). -inline const DOMClass* -GetDOMClass(JSObject* obj) -{ - js::Class* clasp = js::GetObjectClass(obj); - if (IsDOMClass(clasp)) { - return &DOMJSClass::FromJSClass(clasp)->mClass; - } - - js::BaseProxyHandler* handler = js::GetProxyHandler(obj); - MOZ_ASSERT(handler->family() == ProxyFamily()); - MOZ_ASSERT(IsNewProxyBinding(handler)); - return &static_cast<DOMProxyHandler*>(handler)->mClass; -} - -inline DOMObjectSlot -GetDOMClass(JSObject* obj, const DOMClass*& result) -{ - js::Class* clasp = js::GetObjectClass(obj); - if (IsDOMClass(clasp)) { - result = &DOMJSClass::FromJSClass(clasp)->mClass; - return eRegularDOMObject; - } - - if (js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) { - js::BaseProxyHandler* handler = js::GetProxyHandler(obj); - if (handler->family() == ProxyFamily() && IsNewProxyBinding(handler)) { - result = &static_cast<DOMProxyHandler*>(handler)->mClass; - return eProxyDOMObject; - } - } - - return eNonDOMObject; -} - -inline bool -UnwrapDOMObjectToISupports(JSObject* obj, nsISupports*& result) -{ - const DOMClass* clasp; - DOMObjectSlot slot = GetDOMClass(obj, clasp); - if (slot == eNonDOMObject || !clasp->mDOMObjectIsISupports) { - return false; - } - - result = UnwrapDOMObject<nsISupports>(obj, slot); - return true; -} - -inline bool -IsDOMObject(JSObject* obj) -{ - js::Class* clasp = js::GetObjectClass(obj); - return IsDOMClass(clasp) || - ((js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) && - (js::GetProxyHandler(obj)->family() == ProxyFamily() && - IsNewProxyBinding(js::GetProxyHandler(obj)))); -} - -// Some callers don't want to set an exception when unwrapping fails -// (for example, overload resolution uses unwrapping to tell what sort -// of thing it's looking at). -// U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>). -template <prototypes::ID PrototypeID, class T, typename U> -inline nsresult -UnwrapObject(JSContext* cx, JSObject* obj, U& value) -{ - /* First check to see whether we have a DOM object */ - const DOMClass* domClass; - DOMObjectSlot slot = GetDOMClass(obj, domClass); - if (slot == eNonDOMObject) { - /* Maybe we have a security wrapper or outer window? */ - if (!js::IsWrapper(obj)) { - /* Not a DOM object, not a wrapper, just bail */ - return NS_ERROR_XPC_BAD_CONVERT_JS; - } - - obj = xpc::Unwrap(cx, obj, false); - if (!obj) { - return NS_ERROR_XPC_SECURITY_MANAGER_VETO; - } - MOZ_ASSERT(!js::IsWrapper(obj)); - slot = GetDOMClass(obj, domClass); - if (slot == eNonDOMObject) { - /* We don't have a DOM object */ - return NS_ERROR_XPC_BAD_CONVERT_JS; - } - } - - /* This object is a DOM object. Double-check that it is safely - castable to T by checking whether it claims to inherit from the - class identified by protoID. */ - if (domClass->mInterfaceChain[PrototypeTraits<PrototypeID>::Depth] == - PrototypeID) { - value = UnwrapDOMObject<T>(obj, slot); - return NS_OK; - } - - /* It's the wrong sort of DOM object */ - return NS_ERROR_XPC_BAD_CONVERT_JS; -} - -inline bool -IsArrayLike(JSContext* cx, JSObject* obj) -{ - MOZ_ASSERT(obj); - // For simplicity, check for security wrappers up front. In case we - // have a security wrapper, don't forget to enter the compartment of - // the underlying object after unwrapping. - Maybe<JSAutoCompartment> ac; - if (js::IsWrapper(obj)) { - obj = xpc::Unwrap(cx, obj, false); - if (!obj) { - // Let's say it's not - return false; - } - - ac.construct(cx, obj); - } - - // XXXbz need to detect platform objects (including listbinding - // ones) with indexGetters here! - return JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj, cx); -} - -inline bool -IsPlatformObject(JSContext* cx, JSObject* obj) -{ - // XXXbz Should be treating list-binding objects as platform objects - // too? The one consumer so far wants non-array-like platform - // objects, so listbindings that have an indexGetter should test - // false from here. Maybe this function should have a different - // name? - MOZ_ASSERT(obj); - // Fast-path the common case - JSClass* clasp = js::GetObjectJSClass(obj); - if (IsDOMClass(clasp)) { - return true; - } - // Now for simplicity check for security wrappers before anything else - if (js::IsWrapper(obj)) { - obj = xpc::Unwrap(cx, obj, false); - if (!obj) { - // Let's say it's not - return false; - } - clasp = js::GetObjectJSClass(obj); - } - return IS_WRAPPER_CLASS(js::Valueify(clasp)) || IsDOMClass(clasp) || - JS_IsArrayBufferObject(obj, cx); -} - -// U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>). -template <class T, typename U> -inline nsresult -UnwrapObject(JSContext* cx, JSObject* obj, U& value) -{ - return UnwrapObject<static_cast<prototypes::ID>( - PrototypeIDMap<T>::PrototypeID), T>(cx, obj, value); -} - -const size_t kProtoOrIfaceCacheCount = - prototypes::id::_ID_Count + constructors::id::_ID_Count; - -inline void -AllocateProtoOrIfaceCache(JSObject* obj) -{ - MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL); - MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined()); - - // Important: The () at the end ensure zero-initialization - JSObject** protoOrIfaceArray = new JSObject*[kProtoOrIfaceCacheCount](); - - js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT, - JS::PrivateValue(protoOrIfaceArray)); -} - -inline void -TraceProtoOrIfaceCache(JSTracer* trc, JSObject* obj) -{ - MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL); - - if (!HasProtoOrIfaceArray(obj)) - return; - JSObject** protoOrIfaceArray = GetProtoOrIfaceArray(obj); - for (size_t i = 0; i < kProtoOrIfaceCacheCount; ++i) { - JSObject* proto = protoOrIfaceArray[i]; - if (proto) { - JS_CALL_OBJECT_TRACER(trc, proto, "protoOrIfaceArray[i]"); - } - } -} - -inline void -DestroyProtoOrIfaceCache(JSObject* obj) -{ - MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL); - - JSObject** protoOrIfaceArray = GetProtoOrIfaceArray(obj); - - delete [] protoOrIfaceArray; -} - -struct ConstantSpec -{ - const char* name; - JS::Value value; -}; - -/** - * Add constants to an object. - */ -bool -DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs); - -template<typename T> -struct Prefable { - // A boolean indicating whether this set of specs is enabled - bool enabled; - // Array of specs, terminated in whatever way is customary for T. - // Null to indicate a end-of-array for Prefable, when such an - // indicator is needed. - T* specs; -}; - -/* - * Create a DOM interface object (if constructorClass is non-null) and/or a - * DOM interface prototype object (if protoClass is non-null). - * - * global is used as the parent of the interface object and the interface - * prototype object - * receiver is the object on which we need to define the interface object as a - * property - * protoProto is the prototype to use for the interface prototype object. - * protoClass is the JSClass to use for the interface prototype object. - * This is null if we should not create an interface prototype - * object. - * constructorClass is the JSClass to use for the interface object. - * This is null if we should not create an interface object or - * if it should be a function object. - * constructor is the JSNative to use as a constructor. If this is non-null, it - * should be used as a JSNative to back the interface object, which - * should be a Function. If this is null, then we should create an - * object of constructorClass, unless that's also null, in which - * case we should not create an interface object at all. - * ctorNargs is the length of the constructor function; 0 if no constructor - * instanceClass is the JSClass of instance objects for this class. This can - * be null if this is not a concrete proto. - * methods and properties are to be defined on the interface prototype object; - * these arguments are allowed to be null if there are no - * methods or properties respectively. - * constants are to be defined on the interface object and on the interface - * prototype object; allowed to be null if there are no constants. - * staticMethods are to be defined on the interface object; allowed to be null - * if there are no static methods. - * - * At least one of protoClass and constructorClass should be non-null. - * If constructorClass is non-null, the resulting interface object will be - * defined on the given global with property name |name|, which must also be - * non-null. - * - * returns the interface prototype object if protoClass is non-null, else it - * returns the interface object. - */ -JSObject* -CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver, - JSObject* protoProto, JSClass* protoClass, - JSClass* constructorClass, JSNative constructor, - unsigned ctorNargs, const DOMClass* domClass, - Prefable<JSFunctionSpec>* methods, - Prefable<JSPropertySpec>* properties, - Prefable<ConstantSpec>* constants, - Prefable<JSFunctionSpec>* staticMethods, const char* name); - -template <class T> -inline bool -WrapNewBindingObject(JSContext* cx, JSObject* scope, T* value, JS::Value* vp) -{ - JSObject* obj = value->GetWrapper(); - if (obj && js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)) { - *vp = JS::ObjectValue(*obj); - return true; - } - - if (!obj) { - bool triedToWrap; - obj = value->WrapObject(cx, scope, &triedToWrap); - if (!obj) { - // At this point, obj is null, so just return false. We could - // try to communicate triedToWrap to the caller, but in practice - // callers seem to be testing JS_IsExceptionPending(cx) to - // figure out whether WrapObject() threw instead. - return false; - } - } - - // When called via XrayWrapper, we end up here while running in the - // chrome compartment. But the obj we have would be created in - // whatever the content compartment is. So at this point we need to - // make sure it's correctly wrapped for the compartment of |scope|. - // cx should already be in the compartment of |scope| here. - MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx)); - *vp = JS::ObjectValue(*obj); - return JS_WrapValue(cx, vp); -} - -// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr). -template <template <typename> class SmartPtr, class T> -inline bool -WrapNewBindingObject(JSContext* cx, JSObject* scope, const SmartPtr<T>& value, - JS::Value* vp) -{ - return WrapNewBindingObject(cx, scope, value.get(), vp); -} - -template <class T> -inline bool -WrapNewBindingNonWrapperCachedObject(JSContext* cx, JSObject* scope, T* value, - JS::Value* vp) -{ - // We try to wrap in the compartment of the underlying object of "scope" - JSObject* obj; - { - // scope for the JSAutoCompartment so that we restore the compartment - // before we call JS_WrapValue. - Maybe<JSAutoCompartment> ac; - if (js::IsWrapper(scope)) { - scope = xpc::Unwrap(cx, scope, false); - if (!scope) - return false; - ac.construct(cx, scope); - } - - obj = value->WrapObject(cx, scope); - } - - // We can end up here in all sorts of compartments, per above. Make - // sure to JS_WrapValue! - *vp = JS::ObjectValue(*obj); - return JS_WrapValue(cx, vp); -} - -// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr). -template <template <typename> class SmartPtr, typename T> -inline bool -WrapNewBindingNonWrapperCachedObject(JSContext* cx, JSObject* scope, - const SmartPtr<T>& value, JS::Value* vp) -{ - return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), vp); -} - -/** - * A method to handle new-binding wrap failure, by possibly falling back to - * wrapping as a non-new-binding object. - */ -bool -DoHandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope, - nsISupports* value, JS::Value* vp); - -/** - * An easy way to call the above when you have a value which - * multiply-inherits from nsISupports. - */ -template <class T> -bool -HandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope, T* value, - JS::Value* vp) -{ - nsCOMPtr<nsISupports> val; - CallQueryInterface(value, getter_AddRefs(val)); - return DoHandleNewBindingWrappingFailure(cx, scope, val, vp); -} - -// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr). -template <template <typename> class SmartPtr, class T> -MOZ_ALWAYS_INLINE bool -HandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope, - const SmartPtr<T>& value, JS::Value* vp) -{ - return HandleNewBindingWrappingFailure(cx, scope, value.get(), vp); -} - -struct EnumEntry { - const char* value; - size_t length; -}; - -template<bool Fatal> -inline bool -EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length, - const char* type) -{ - return false; -} - -template<> -inline bool -EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length, - const char* type) -{ - // TODO: Log a warning to the console. - return true; -} - -template<> -inline bool -EnumValueNotFound<true>(JSContext* cx, const jschar* chars, size_t length, - const char* type) -{ - NS_LossyConvertUTF16toASCII deflated(static_cast<const PRUnichar*>(chars), - length); - return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, deflated.get(), type); -} - - -template<bool InvalidValueFatal> -inline int -FindEnumStringIndex(JSContext* cx, JS::Value v, const EnumEntry* values, - const char* type, bool* ok) -{ - // JS_StringEqualsAscii is slow as molasses, so don't use it here. - JSString* str = JS_ValueToString(cx, v); - if (!str) { - *ok = false; - return 0; - } - JS::Anchor<JSString*> anchor(str); - size_t length; - const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length); - if (!chars) { - *ok = false; - return 0; - } - int i = 0; - for (const EnumEntry* value = values; value->value; ++value, ++i) { - if (length != value->length) { - continue; - } - - bool equal = true; - const char* val = value->value; - for (size_t j = 0; j != length; ++j) { - if (unsigned(val[j]) != unsigned(chars[j])) { - equal = false; - break; - } - } - - if (equal) { - *ok = true; - return i; - } - } - - *ok = EnumValueNotFound<InvalidValueFatal>(cx, chars, length, type); - return -1; -} - -inline nsWrapperCache* -GetWrapperCache(nsWrapperCache* cache) -{ - return cache; -} - -inline nsWrapperCache* -GetWrapperCache(nsGlobalWindow* not_allowed); - -inline nsWrapperCache* -GetWrapperCache(void* p) -{ - return NULL; -} - -struct ParentObject { - template<class T> - ParentObject(T* aObject) : - mObject(aObject), - mWrapperCache(GetWrapperCache(aObject)) - {} - - template<class T, template<typename> class SmartPtr> - ParentObject(const SmartPtr<T>& aObject) : - mObject(aObject.get()), - mWrapperCache(GetWrapperCache(aObject.get())) - {} - - ParentObject(nsISupports* aObject, nsWrapperCache* aCache) : - mObject(aObject), - mWrapperCache(aCache) - {} - - nsISupports* const mObject; - nsWrapperCache* const mWrapperCache; -}; - -inline nsWrapperCache* -GetWrapperCache(const ParentObject& aParentObject) -{ - return aParentObject.mWrapperCache; -} - -template<class T> -inline nsISupports* -GetParentPointer(T* aObject) -{ - return ToSupports(aObject); -} - -inline nsISupports* -GetParentPointer(const ParentObject& aObject) -{ - return ToSupports(aObject.mObject); -} - -template<class T> -inline void -ClearWrapper(T* p, nsWrapperCache* cache) -{ - cache->ClearWrapper(); -} - -template<class T> -inline void -ClearWrapper(T* p, void*) -{ - nsWrapperCache* cache; - CallQueryInterface(p, &cache); - ClearWrapper(p, cache); -} - -// Can only be called with the immediate prototype of the instance object. Can -// only be called on the prototype of an object known to be a DOM instance. -JSBool -InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID, - uint32_t depth); - -// Only set allowNativeWrapper to false if you really know you need it, if in -// doubt use true. Setting it to false disables security wrappers. -bool -XPCOMObjectToJsval(JSContext* cx, JSObject* scope, xpcObjectHelper &helper, - const nsIID* iid, bool allowNativeWrapper, JS::Value* rval); - -template<class T> -inline bool -WrapObject(JSContext* cx, JSObject* scope, T* p, nsWrapperCache* cache, - const nsIID* iid, JS::Value* vp) -{ - if (xpc_FastGetCachedWrapper(cache, scope, vp)) - return true; - qsObjectHelper helper(p, cache); - return XPCOMObjectToJsval(cx, scope, helper, iid, true, vp); -} - -template<class T> -inline bool -WrapObject(JSContext* cx, JSObject* scope, T* p, const nsIID* iid, - JS::Value* vp) -{ - return WrapObject(cx, scope, p, GetWrapperCache(p), iid, vp); -} - -template<class T> -inline bool -WrapObject(JSContext* cx, JSObject* scope, T* p, JS::Value* vp) -{ - return WrapObject(cx, scope, p, NULL, vp); -} - -template<class T> -inline bool -WrapObject(JSContext* cx, JSObject* scope, nsCOMPtr<T> &p, const nsIID* iid, - JS::Value* vp) -{ - return WrapObject(cx, scope, p.get(), iid, vp); -} - -template<class T> -inline bool -WrapObject(JSContext* cx, JSObject* scope, nsCOMPtr<T> &p, JS::Value* vp) -{ - return WrapObject(cx, scope, p, NULL, vp); -} - -template<class T> -inline bool -WrapObject(JSContext* cx, JSObject* scope, nsRefPtr<T> &p, const nsIID* iid, - JS::Value* vp) -{ - return WrapObject(cx, scope, p.get(), iid, vp); -} - -template<class T> -inline bool -WrapObject(JSContext* cx, JSObject* scope, nsRefPtr<T> &p, JS::Value* vp) -{ - return WrapObject(cx, scope, p, NULL, vp); -} - -template<> -inline bool -WrapObject<JSObject>(JSContext* cx, JSObject* scope, JSObject* p, JS::Value* vp) -{ - vp->setObjectOrNull(p); - return true; -} - -template<typename T> -static inline JSObject* -WrapNativeParent(JSContext* cx, JSObject* scope, const T& p) -{ - if (!GetParentPointer(p)) - return scope; - - nsWrapperCache* cache = GetWrapperCache(p); - JSObject* obj; - if (cache && (obj = cache->GetWrapper())) { -#ifdef DEBUG - qsObjectHelper helper(GetParentPointer(p), cache); - JS::Value debugVal; - - bool ok = XPCOMObjectToJsval(cx, scope, helper, NULL, false, &debugVal); - NS_ASSERTION(ok && JSVAL_TO_OBJECT(debugVal) == obj, - "Unexpected object in nsWrapperCache"); -#endif - return obj; - } - - qsObjectHelper helper(GetParentPointer(p), cache); - JS::Value v; - return XPCOMObjectToJsval(cx, scope, helper, NULL, false, &v) ? - JSVAL_TO_OBJECT(v) : - NULL; -} - -static inline bool -InternJSString(JSContext* cx, jsid& id, const char* chars) -{ - if (JSString *str = ::JS_InternString(cx, chars)) { - id = INTERNED_STRING_TO_JSID(cx, str); - return true; - } - return false; -} - -// Spec needs a name property -template <typename Spec> -static bool -InitIds(JSContext* cx, Prefable<Spec>* prefableSpecs, jsid* ids) -{ - MOZ_ASSERT(prefableSpecs); - MOZ_ASSERT(prefableSpecs->specs); - do { - // We ignore whether the set of ids is enabled and just intern all the IDs, - // because this is only done once per application runtime. - Spec* spec = prefableSpecs->specs; - do { - if (!InternJSString(cx, *ids, spec->name)) { - return false; - } - } while (++ids, (++spec)->name); - - // We ran out of ids for that pref. Put a JSID_VOID in on the id - // corresponding to the list terminator for the pref. - *ids = JSID_VOID; - ++ids; - } while ((++prefableSpecs)->specs); - - return true; -} - -JSBool -QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp); -JSBool -ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp); - -bool -GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found, - JS::Value* vp); - -bool -HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler, - jsid id); - -template<class T> -class NonNull -{ -public: - NonNull() -#ifdef DEBUG - : inited(false) -#endif - {} - - operator T&() { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "NonNull<T> was set to null"); - return *ptr; - } - - operator const T&() const { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "NonNull<T> was set to null"); - return *ptr; - } - - void operator=(T* t) { - ptr = t; - MOZ_ASSERT(ptr); -#ifdef DEBUG - inited = true; -#endif - } - - template<typename U> - void operator=(U* t) { - ptr = t->ToAStringPtr(); - MOZ_ASSERT(ptr); -#ifdef DEBUG - inited = true; -#endif - } - - T** Slot() { -#ifdef DEBUG - inited = true; -#endif - return &ptr; - } - -protected: - T* ptr; -#ifdef DEBUG - bool inited; -#endif -}; - -template<class T> -class OwningNonNull -{ -public: - OwningNonNull() -#ifdef DEBUG - : inited(false) -#endif - {} - - operator T&() { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "OwningNonNull<T> was set to null"); - return *ptr; - } - - void operator=(T* t) { - init(t); - } - - void operator=(const already_AddRefed<T>& t) { - init(t); - } - -protected: - template<typename U> - void init(U t) { - ptr = t; - MOZ_ASSERT(ptr); -#ifdef DEBUG - inited = true; -#endif - } - - nsRefPtr<T> ptr; -#ifdef DEBUG - bool inited; -#endif -}; - -// A struct that has the same layout as an nsDependentString but much -// faster constructor and destructor behavior -struct FakeDependentString { - FakeDependentString() : - mFlags(nsDependentString::F_TERMINATED) - { - } - - void SetData(const nsDependentString::char_type* aData, - nsDependentString::size_type aLength) { - MOZ_ASSERT(mFlags == nsDependentString::F_TERMINATED); - mData = aData; - mLength = aLength; - } - - void Truncate() { - mData = nsDependentString::char_traits::sEmptyBuffer; - mLength = 0; - } - - void SetNull() { - Truncate(); - mFlags |= nsDependentString::F_VOIDED; - } - - const nsAString* ToAStringPtr() const { - return reinterpret_cast<const nsDependentString*>(this); - } - - nsAString* ToAStringPtr() { - return reinterpret_cast<nsDependentString*>(this); - } - - operator const nsAString& () const { - return *reinterpret_cast<const nsDependentString*>(this); - } - -private: - const nsDependentString::char_type* mData; - nsDependentString::size_type mLength; - uint32_t mFlags; - - // A class to use for our static asserts to ensure our object layout - // matches that of nsDependentString. - class DependentStringAsserter; - friend class DependentStringAsserter; - - class DepedentStringAsserter : public nsDependentString { - public: - static void StaticAsserts() { - MOZ_STATIC_ASSERT(sizeof(FakeDependentString) == sizeof(nsDependentString), - "Must have right object size"); - MOZ_STATIC_ASSERT(offsetof(FakeDependentString, mData) == - offsetof(DepedentStringAsserter, mData), - "Offset of mData should match"); - MOZ_STATIC_ASSERT(offsetof(FakeDependentString, mLength) == - offsetof(DepedentStringAsserter, mLength), - "Offset of mLength should match"); - MOZ_STATIC_ASSERT(offsetof(FakeDependentString, mFlags) == - offsetof(DepedentStringAsserter, mFlags), - "Offset of mFlags should match"); - } - }; -}; - -enum StringificationBehavior { - eStringify, - eEmpty, - eNull -}; - -// pval must not be null and must point to a rooted JS::Value -static inline bool -ConvertJSValueToString(JSContext* cx, const JS::Value& v, JS::Value* pval, - StringificationBehavior nullBehavior, - StringificationBehavior undefinedBehavior, - FakeDependentString& result) -{ - JSString *s; - if (v.isString()) { - s = v.toString(); - } else { - StringificationBehavior behavior; - if (v.isNull()) { - behavior = nullBehavior; - } else if (v.isUndefined()) { - behavior = undefinedBehavior; - } else { - behavior = eStringify; - } - - if (behavior != eStringify) { - if (behavior == eEmpty) { - result.Truncate(); - } else { - result.SetNull(); - } - return true; - } - - s = JS_ValueToString(cx, v); - if (!s) { - return false; - } - pval->setString(s); // Root the new string. - } - - size_t len; - const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len); - if (!chars) { - return false; - } - - result.SetData(chars, len); - return true; -} - -// Class for representing optional arguments. -template<typename T> -class Optional { -public: - Optional() {} - - bool WasPassed() const { - return !mImpl.empty(); - } - - void Construct() { - mImpl.construct(); - } - - template <class T1, class T2> - void Construct(const T1 &t1, const T2 &t2) { - mImpl.construct(t1, t2); - } - - const T& Value() const { - return mImpl.ref(); - } - - T& Value() { - return mImpl.ref(); - } - -private: - // Forbid copy-construction and assignment - Optional(const Optional& other) MOZ_DELETE; - const Optional &operator=(const Optional &other) MOZ_DELETE; - - Maybe<T> mImpl; -}; - -// Specialization for strings. -template<> -class Optional<nsAString> { -public: - Optional() : mPassed(false) {} - - bool WasPassed() const { - return mPassed; - } - - void operator=(const nsAString* str) { - MOZ_ASSERT(str); - mStr = str; - mPassed = true; - } - - void operator=(const FakeDependentString* str) { - MOZ_ASSERT(str); - mStr = str->ToAStringPtr(); - mPassed = true; - } - - const nsAString& Value() const { - MOZ_ASSERT(WasPassed()); - return *mStr; - } - -private: - // Forbid copy-construction and assignment - Optional(const Optional& other) MOZ_DELETE; - const Optional &operator=(const Optional &other) MOZ_DELETE; - - bool mPassed; - const nsAString* mStr; -}; - -// Class for representing sequences in arguments. We use an auto array that can -// hold 16 elements, to avoid having to allocate in common cases. This needs to -// be fallible because web content controls the length of the array, and can -// easily try to create very large lengths. -template<typename T> -class Sequence : public AutoFallibleTArray<T, 16> -{ -public: - Sequence() : AutoFallibleTArray<T, 16>() {} -}; - -// Class for holding the type of members of a union. The union type has an enum -// to keep track of which of its UnionMembers has been constructed. -template<class T> -class UnionMember { - AlignedStorage2<T> storage; - -public: - T& SetValue() { - new (storage.addr()) T(); - return *storage.addr(); - } - const T& Value() const { - return *storage.addr(); - } - void Destroy() { - storage.addr()->~T(); - } -}; - -// Implementation of the bits that XrayWrapper needs -bool -XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id, - JSPropertyDescriptor* desc, - // And the things we need to determine the descriptor - Prefable<JSFunctionSpec>* methods, - jsid* methodIds, - JSFunctionSpec* methodSpecs, - size_t methodCount, - Prefable<JSPropertySpec>* attributes, - jsid* attributeIds, - JSPropertySpec* attributeSpecs, - size_t attributeCount, - Prefable<ConstantSpec>* constants, - jsid* constantIds, - ConstantSpec* constantSpecs, - size_t constantCount); - -bool -XrayEnumerateProperties(JS::AutoIdVector& props, - Prefable<JSFunctionSpec>* methods, - jsid* methodIds, - JSFunctionSpec* methodSpecs, - size_t methodCount, - Prefable<JSPropertySpec>* attributes, - jsid* attributeIds, - JSPropertySpec* attributeSpecs, - size_t attributeCount, - Prefable<ConstantSpec>* constants, - jsid* constantIds, - ConstantSpec* constantSpecs, - size_t constantCount); - -} // namespace dom -} // namespace mozilla - -#endif /* mozilla_dom_BindingUtils_h__ */ diff --git a/components/script/dom/bindings/codegen/Codegen.py b/components/script/dom/bindings/codegen/Codegen.py deleted file mode 100644 index 6d2cc0bde36..00000000000 --- a/components/script/dom/bindings/codegen/Codegen.py +++ /dev/null @@ -1,5788 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/. - -# Common codegen classes. - -import os -import string -import operator - -from WebIDL import * -from Configuration import NoSuchDescriptorError - -AUTOGENERATED_WARNING_COMMENT = \ - "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n" -ADDPROPERTY_HOOK_NAME = '_addProperty' -FINALIZE_HOOK_NAME = '_finalize' -TRACE_HOOK_NAME = '_trace' -CONSTRUCT_HOOK_NAME = '_constructor' -HASINSTANCE_HOOK_NAME = '_hasInstance' - -def replaceFileIfChanged(filename, newContents): - """ - Read a copy of the old file, so that we don't touch it if it hasn't changed. - Returns True if the file was updated, false otherwise. - """ - oldFileContents = "" - try: - oldFile = open(filename, 'rb') - oldFileContents = ''.join(oldFile.readlines()) - oldFile.close() - except: - pass - - if newContents == oldFileContents: - return False - - f = open(filename, 'wb') - f.write(newContents) - f.close() - -def toStringBool(arg): - return str(not not arg).lower() - -def toBindingNamespace(arg): - return re.sub("((_workers)?$)", "Binding\\1", arg); - -class CGThing(): - """ - Abstract base class for things that spit out code. - """ - def __init__(self): - pass # Nothing for now - def declare(self): - """Produce code for a header file.""" - assert(False) # Override me! - def define(self): - """Produce code for a cpp file.""" - assert(False) # Override me! - -class CGNativePropertyHooks(CGThing): - """ - Generate a NativePropertyHooks for a given descriptor - """ - def __init__(self, descriptor): - CGThing.__init__(self) - self.descriptor = descriptor - def declare(self): - if self.descriptor.workers: - return "" - return "extern const NativePropertyHooks NativeHooks;\n" - def define(self): - if self.descriptor.workers: - return "" - if self.descriptor.concrete and self.descriptor.proxy: - resolveOwnProperty = "ResolveOwnProperty" - enumerateOwnProperties = "EnumerateOwnProperties" - else: - enumerateOwnProperties = resolveOwnProperty = "NULL" - parent = self.descriptor.interface.parent - parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks" - if parent else 'NULL') - return """ -const NativePropertyHooks NativeHooks = { %s, ResolveProperty, %s, EnumerateProperties, %s }; -""" % (resolveOwnProperty, enumerateOwnProperties, parentHooks) - -def DOMClass(descriptor): - protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain] - # Pad out the list to the right length with _ID_Count so we - # guarantee that all the lists are the same length. _ID_Count - # is never the ID of any prototype, so it's safe to use as - # padding. - protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList))) - prototypeChainString = ', '.join(protoList) - nativeHooks = "NULL" if descriptor.workers else "&NativeHooks" - return """{ - { %s }, - %s, %s -}""" % (prototypeChainString, toStringBool(descriptor.nativeIsISupports), - nativeHooks) - -class CGDOMJSClass(CGThing): - """ - Generate a DOMJSClass for a given descriptor - """ - def __init__(self, descriptor): - CGThing.__init__(self) - self.descriptor = descriptor - def declare(self): - return "extern DOMJSClass Class;\n" - def define(self): - traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'NULL' - return """ -DOMJSClass Class = { - { "%s", - JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1), - %s, /* addProperty */ - JS_PropertyStub, /* delProperty */ - JS_PropertyStub, /* getProperty */ - JS_StrictPropertyStub, /* setProperty */ - JS_EnumerateStub, - JS_ResolveStub, - JS_ConvertStub, - %s, /* finalize */ - NULL, /* checkAccess */ - NULL, /* call */ - NULL, /* hasInstance */ - NULL, /* construct */ - %s, /* trace */ - JSCLASS_NO_INTERNAL_MEMBERS - }, - %s -}; -""" % (self.descriptor.interface.identifier.name, - ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub', - FINALIZE_HOOK_NAME, traceHook, - CGIndenter(CGGeneric(DOMClass(self.descriptor))).define()) - -class CGPrototypeJSClass(CGThing): - def __init__(self, descriptor): - CGThing.__init__(self) - self.descriptor = descriptor - def declare(self): - # We're purely for internal consumption - return "" - def define(self): - return """static JSClass PrototypeClass = { - "%sPrototype", - JSCLASS_HAS_RESERVED_SLOTS(1), - JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ - JS_PropertyStub, /* getProperty */ - JS_StrictPropertyStub, /* setProperty */ - JS_EnumerateStub, - JS_ResolveStub, - JS_ConvertStub, - NULL, /* finalize */ - NULL, /* checkAccess */ - NULL, /* call */ - NULL, /* hasInstance */ - NULL, /* construct */ - NULL, /* trace */ - JSCLASS_NO_INTERNAL_MEMBERS -}; -""" % (self.descriptor.interface.identifier.name) - -class CGInterfaceObjectJSClass(CGThing): - def __init__(self, descriptor): - CGThing.__init__(self) - self.descriptor = descriptor - def declare(self): - # We're purely for internal consumption - return "" - def define(self): - if not self.descriptor.hasInstanceInterface: - return "" - ctorname = "NULL" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME - hasinstance = HASINSTANCE_HOOK_NAME - return """ -static JSClass InterfaceObjectClass = { - "Function", 0, - JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ - JS_PropertyStub, /* getProperty */ - JS_StrictPropertyStub, /* setProperty */ - JS_EnumerateStub, - JS_ResolveStub, - JS_ConvertStub, - NULL, /* finalize */ - NULL, /* checkAccess */ - %s, /* call */ - %s, /* hasInstance */ - %s, /* construct */ - NULL, /* trace */ - JSCLASS_NO_INTERNAL_MEMBERS -}; -""" % (ctorname, hasinstance, ctorname) - -class CGList(CGThing): - """ - Generate code for a list of GCThings. Just concatenates them together, with - an optional joiner string. "\n" is a common joiner. - """ - def __init__(self, children, joiner=""): - CGThing.__init__(self) - self.children = children - self.joiner = joiner - def append(self, child): - self.children.append(child) - def prepend(self, child): - self.children.insert(0, child) - def join(self, generator): - return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator))) - def declare(self): - return self.join(child.declare() for child in self.children if child is not None) - def define(self): - return self.join(child.define() for child in self.children if child is not None) - -class CGGeneric(CGThing): - """ - A class that spits out a fixed string into the codegen. Can spit out a - separate string for the declaration too. - """ - def __init__(self, define="", declare=""): - self.declareText = declare - self.defineText = define - def declare(self): - return self.declareText - def define(self): - return self.defineText - -# We'll want to insert the indent at the beginnings of lines, but we -# don't want to indent empty lines. So only indent lines that have a -# non-newline character on them. -lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE) -class CGIndenter(CGThing): - """ - A class that takes another CGThing and generates code that indents that - CGThing by some number of spaces. The default indent is two spaces. - """ - def __init__(self, child, indentLevel=2, declareOnly=False): - CGThing.__init__(self) - self.child = child - self.indent = " " * indentLevel - self.declareOnly = declareOnly - def declare(self): - decl = self.child.declare() - if decl is not "": - return re.sub(lineStartDetector, self.indent, decl) - else: - return "" - def define(self): - defn = self.child.define() - if defn is not "" and not self.declareOnly: - return re.sub(lineStartDetector, self.indent, defn) - else: - return defn - -class CGWrapper(CGThing): - """ - Generic CGThing that wraps other CGThings with pre and post text. - """ - def __init__(self, child, pre="", post="", declarePre=None, - declarePost=None, definePre=None, definePost=None, - declareOnly=False, defineOnly=False, reindent=False): - CGThing.__init__(self) - self.child = child - self.declarePre = declarePre or pre - self.declarePost = declarePost or post - self.definePre = definePre or pre - self.definePost = definePost or post - self.declareOnly = declareOnly - self.defineOnly = defineOnly - self.reindent = reindent - def declare(self): - if self.defineOnly: - return '' - decl = self.child.declare() - if self.reindent: - # We don't use lineStartDetector because we don't want to - # insert whitespace at the beginning of our _first_ line. - decl = stripTrailingWhitespace( - decl.replace("\n", "\n" + (" " * len(self.declarePre)))) - return self.declarePre + decl + self.declarePost - def define(self): - if self.declareOnly: - return '' - defn = self.child.define() - if self.reindent: - # We don't use lineStartDetector because we don't want to - # insert whitespace at the beginning of our _first_ line. - defn = stripTrailingWhitespace( - defn.replace("\n", "\n" + (" " * len(self.definePre)))) - return self.definePre + defn + self.definePost - -class CGIfWrapper(CGWrapper): - def __init__(self, child, condition): - pre = CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", - reindent=True) - CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(), - post="\n}") - -class CGNamespace(CGWrapper): - def __init__(self, namespace, child, declareOnly=False): - pre = "namespace %s {\n" % namespace - post = "} // namespace %s\n" % namespace - CGWrapper.__init__(self, child, pre=pre, post=post, - declareOnly=declareOnly) - @staticmethod - def build(namespaces, child, declareOnly=False): - """ - Static helper method to build multiple wrapped namespaces. - """ - if not namespaces: - return CGWrapper(child, declareOnly=declareOnly) - inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly) - return CGNamespace(namespaces[0], inner, declareOnly=declareOnly) - -class CGIncludeGuard(CGWrapper): - """ - Generates include guards for a header. - """ - def __init__(self, prefix, child): - """|prefix| is the filename without the extension.""" - define = 'mozilla_dom_%s_h__' % prefix - CGWrapper.__init__(self, child, - declarePre='#ifndef %s\n#define %s\n\n' % (define, define), - declarePost='\n#endif // %s\n' % define) - -def getTypes(descriptor): - """ - Get all argument and return types for all members of the descriptor - """ - members = [m for m in descriptor.interface.members] - if descriptor.interface.ctor(): - members.append(descriptor.interface.ctor()) - signatures = [s for m in members if m.isMethod() for s in m.signatures()] - types = [] - for s in signatures: - assert len(s) == 2 - (returnType, arguments) = s - types.append(returnType) - types.extend([a.type for a in arguments]) - - types.extend(a.type for a in members if a.isAttr()) - return types - -class CGHeaders(CGWrapper): - """ - Generates the appropriate include statements. - """ - def __init__(self, descriptors, dictionaries, declareIncludes, - defineIncludes, child): - """ - Builds a set of includes to cover |descriptors|. - - Also includes the files in |declareIncludes| in the header - file and the files in |defineIncludes| in the .cpp. - """ - - # Determine the filenames for which we need headers. - interfaceDeps = [d.interface for d in descriptors] - ancestors = [] - for iface in interfaceDeps: - while iface.parent: - ancestors.append(iface.parent) - iface = iface.parent - interfaceDeps.extend(ancestors) - bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps) - - # Grab all the implementation declaration files we need. - implementationIncludes = set(d.headerFile for d in descriptors) - - # Now find all the things we'll need as arguments because we - # need to wrap or unwrap them. - bindingHeaders = set() - for d in descriptors: - types = getTypes(d) - for dictionary in dictionaries: - curDict = dictionary - while curDict: - types.extend([m.type for m in curDict.members]) - curDict = curDict.parent - - for t in types: - if t.unroll().isUnion(): - # UnionConversions.h includes UnionTypes.h - bindingHeaders.add("mozilla/dom/UnionConversions.h") - elif t.unroll().isInterface(): - if t.unroll().isSpiderMonkeyInterface(): - bindingHeaders.add("jsfriendapi.h") - bindingHeaders.add("mozilla/dom/TypedArray.h") - else: - typeDesc = d.getDescriptor(t.unroll().inner.identifier.name) - if typeDesc is not None: - implementationIncludes.add(typeDesc.headerFile) - bindingHeaders.add(self.getDeclarationFilename(typeDesc.interface)) - elif t.unroll().isDictionary(): - bindingHeaders.add(self.getDeclarationFilename(t.unroll().inner)) - - declareIncludes = set(declareIncludes) - for d in dictionaries: - if d.parent: - declareIncludes.add(self.getDeclarationFilename(d.parent)) - bindingHeaders.add(self.getDeclarationFilename(d)) - - # Let the machinery do its thing. - def _includeString(includes): - return ''.join(['#include "%s"\n' % i for i in includes]) + '\n' - CGWrapper.__init__(self, child, - declarePre=_includeString(sorted(declareIncludes)), - definePre=_includeString(sorted(set(defineIncludes) | - bindingIncludes | - bindingHeaders | - implementationIncludes))) - @staticmethod - def getDeclarationFilename(decl): - # Use our local version of the header, not the exported one, so that - # test bindings, which don't export, will work correctly. - basename = os.path.basename(decl.filename()) - return basename.replace('.webidl', 'Binding.h') - -def SortedTuples(l): - """ - Sort a list of tuples based on the first item in the tuple - """ - return sorted(l, key=operator.itemgetter(0)) - -def SortedDictValues(d): - """ - Returns a list of values from the dict sorted by key. - """ - # Create a list of tuples containing key and value, sorted on key. - d = SortedTuples(d.items()) - # We're only interested in the values. - return (i[1] for i in d) - -def UnionTypes(descriptors): - """ - Returns a tuple containing a set of header filenames to include, a set of - tuples containing a type declaration and a boolean if the type is a struct - for member types of the unions and a CGList containing CGUnionStructs for - every union. - """ - - # Now find all the things we'll need as arguments and return values because - # we need to wrap or unwrap them. - headers = set() - declarations = set() - unionStructs = dict() - for d in descriptors: - if d.interface.isExternal(): - continue - - for t in getTypes(d): - t = t.unroll() - if t.isUnion(): - name = str(t) - if not name in unionStructs: - unionStructs[name] = CGUnionStruct(t, d) - for f in t.flatMemberTypes: - f = f.unroll() - if f.isInterface(): - if f.isSpiderMonkeyInterface(): - headers.add("jsfriendapi.h") - headers.add("mozilla/dom/TypedArray.h") - else: - typeDesc = d.getDescriptor(f.inner.identifier.name) - if typeDesc is not None: - declarations.add((typeDesc.nativeType, False)) - elif f.isDictionary(): - declarations.add((f.inner.identifier.name, True)) - - return (headers, declarations, CGList(SortedDictValues(unionStructs), "\n")) - -def UnionConversions(descriptors): - """ - Returns a CGThing to declare all union argument conversion helper structs. - """ - # Now find all the things we'll need as arguments because we - # need to unwrap them. - unionConversions = dict() - for d in descriptors: - if d.interface.isExternal(): - continue - - def addUnionTypes(type): - if type.isUnion(): - type = type.unroll() - name = str(type) - if not name in unionConversions: - unionConversions[name] = CGUnionConversionStruct(type, d) - - members = [m for m in d.interface.members] - if d.interface.ctor(): - members.append(d.interface.ctor()) - signatures = [s for m in members if m.isMethod() for s in m.signatures()] - for s in signatures: - assert len(s) == 2 - (_, arguments) = s - for a in arguments: - addUnionTypes(a.type) - - for m in members: - if m.isAttr() and not m.readonly: - addUnionTypes(m.type) - - return CGWrapper(CGList(SortedDictValues(unionConversions), "\n"), - post="\n\n") - -class Argument(): - """ - A class for outputting the type and name of an argument - """ - def __init__(self, argType, name): - self.argType = argType - self.name = name - def __str__(self): - return self.argType + ' ' + self.name - -class CGAbstractMethod(CGThing): - """ - An abstract class for generating code for a method. Subclasses - should override definition_body to create the actual code. - - descriptor is the descriptor for the interface the method is associated with - - name is the name of the method as a string - - returnType is the IDLType of the return value - - args is a list of Argument objects - - inline should be True to generate an inline method, whose body is - part of the declaration. - - alwaysInline should be True to generate an inline method annotated with - MOZ_ALWAYS_INLINE. - - static should be True to generate a static method, which only has - a definition. - - If templateArgs is not None it should be a list of strings containing - template arguments, and the function will be templatized using those - arguments. - """ - def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None): - CGThing.__init__(self) - self.descriptor = descriptor - self.name = name - self.returnType = returnType - self.args = args - self.inline = inline - self.alwaysInline = alwaysInline - self.static = static - self.templateArgs = templateArgs - def _argstring(self): - return ', '.join([str(a) for a in self.args]) - def _template(self): - if self.templateArgs is None: - return '' - return 'template <%s>\n' % ', '.join(self.templateArgs) - def _decorators(self): - decorators = [] - if self.alwaysInline: - decorators.append('MOZ_ALWAYS_INLINE') - elif self.inline: - decorators.append('inline') - if self.static: - decorators.append('static') - decorators.append(self.returnType) - maybeNewline = " " if self.inline else "\n" - return ' '.join(decorators) + maybeNewline - def declare(self): - if self.inline: - return self._define() - return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring()) - def _define(self): - return self.definition_prologue() + "\n" + self.definition_body() + self.definition_epilogue() - def define(self): - return "" if self.inline else self._define() - def definition_prologue(self): - return "%s%s%s(%s)\n{" % (self._template(), self._decorators(), - self.name, self._argstring()) - def definition_epilogue(self): - return "\n}\n" - def definition_body(self): - assert(False) # Override me! - -class CGAbstractStaticMethod(CGAbstractMethod): - """ - Abstract base class for codegen of implementation-only (no - declaration) static methods. - """ - def __init__(self, descriptor, name, returnType, args): - CGAbstractMethod.__init__(self, descriptor, name, returnType, args, - inline=False, static=True) - def declare(self): - # We only have implementation - return "" - -class CGAbstractClassHook(CGAbstractStaticMethod): - """ - Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw - 'this' unwrapping as it assumes that the unwrapped type is always known. - """ - def __init__(self, descriptor, name, returnType, args): - CGAbstractStaticMethod.__init__(self, descriptor, name, returnType, - args) - - def definition_body_prologue(self): - return """ - %s* self = UnwrapDOMObject<%s>(obj, eRegularDOMObject); -""" % (self.descriptor.nativeType, self.descriptor.nativeType) - - def definition_body(self): - return self.definition_body_prologue() + self.generate_code() - - def generate_code(self): - # Override me - assert(False) - -class CGAddPropertyHook(CGAbstractClassHook): - """ - A hook for addProperty, used to preserve our wrapper from GC. - """ - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'), - Argument('JSHandleId', 'id'), Argument('JSMutableHandleValue', 'vp')] - CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME, - 'JSBool', args) - - def generate_code(self): - # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=774279 - # Using a real trace hook might enable us to deal with non-nsISupports - # wrappercached things here. - assert self.descriptor.nativeIsISupports - return """ nsContentUtils::PreserveWrapper(reinterpret_cast<nsISupports*>(self), self); - return true;""" - -def finalizeHook(descriptor, hookName, context): - if descriptor.customFinalize: - return """if (self) { - self->%s(%s); -}""" % (hookName, context) - clearWrapper = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else "" - if descriptor.workers: - release = "self->Release();" - else: - assert descriptor.nativeIsISupports - release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance(); -if (rt) { - rt->DeferredRelease(reinterpret_cast<nsISupports*>(self)); -} else { - NS_RELEASE(self); -}""" - return clearWrapper + release - -class CGClassFinalizeHook(CGAbstractClassHook): - """ - A hook for finalize, used to release our native object. - """ - def __init__(self, descriptor): - args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'obj')] - CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME, - 'void', args) - - def generate_code(self): - return CGIndenter(CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))).define() - -class CGClassTraceHook(CGAbstractClassHook): - """ - A hook to trace through our native object; used for GC and CC - """ - def __init__(self, descriptor): - args = [Argument('JSTracer*', 'trc'), Argument('JSObject*', 'obj')] - CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void', - args) - - def generate_code(self): - return """ if (self) { - self->%s(%s); - }""" % (self.name, self.args[0].name) - -class CGClassConstructHook(CGAbstractStaticMethod): - """ - JS-visible constructor for our objects - """ - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'), Argument('JS::Value*', 'vp')] - CGAbstractStaticMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME, - 'JSBool', args) - self._ctor = self.descriptor.interface.ctor() - - def define(self): - if not self._ctor: - return "" - return CGAbstractStaticMethod.define(self) - - def definition_body(self): - return self.generate_code() - - def generate_code(self): - preamble = """ - JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp))); -""" - if self.descriptor.workers: - preArgs = ["cx", "obj"] - else: - preamble += """ - nsISupports* global; - xpc_qsSelfRef globalRef; - { - nsresult rv; - JS::Value val = OBJECT_TO_JSVAL(obj); - rv = xpc_qsUnwrapArg<nsISupports>(cx, val, &global, &globalRef.ptr, &val); - if (NS_FAILED(rv)) { - return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS); - } - } -""" - preArgs = ["global"] - - name = self._ctor.identifier.name - nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name)) - callGenerator = CGMethodCall(preArgs, nativeName, True, - self.descriptor, self._ctor) - return preamble + callGenerator.define(); - -class CGClassHasInstanceHook(CGAbstractStaticMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'), - Argument('JSMutableHandleValue', 'vp'), Argument('JSBool*', 'bp')] - CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME, - 'JSBool', args) - - def define(self): - if not self.descriptor.hasInstanceInterface: - return "" - return CGAbstractStaticMethod.define(self) - - def definition_body(self): - return self.generate_code() - - def generate_code(self): - return """ if (!vp.isObject()) { - *bp = false; - return true; - } - - jsval protov; - if (!JS_GetProperty(cx, obj, "prototype", &protov)) - return false; - if (!protov.isObject()) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, - "%s"); - return false; - } - JSObject *objProto = &protov.toObject(); - - JSObject* instance = &vp.toObject(); - JSObject* proto; - if (!JS_GetPrototype(cx, instance, &proto)) - return false; - while (proto) { - if (proto == objProto) { - *bp = true; - return true; - } - if (!JS_GetPrototype(cx, proto, &proto)) - return false; - } - - nsISupports* native = - nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, instance); - nsCOMPtr<%s> qiResult = do_QueryInterface(native); - *bp = !!qiResult; - return true; -""" % (self.descriptor.name, self.descriptor.hasInstanceInterface) - -def isChromeOnly(m): - return m.getExtendedAttribute("ChromeOnly") - -class PropertyDefiner: - """ - A common superclass for defining things on prototype objects. - - Subclasses should implement generateArray to generate the actual arrays of - things we're defining. They should also set self.chrome to the list of - things exposed to chrome and self.regular to the list of things exposed to - web pages. self.chrome must be a superset of self.regular but also include - all the ChromeOnly stuff. - """ - def __init__(self, descriptor, name): - self.descriptor = descriptor - self.name = name - # self.prefCacheData will store an array of (prefname, bool*) - # pairs for our bool var caches. generateArray will fill it - # in as needed. - self.prefCacheData = [] - def hasChromeOnly(self): - return len(self.chrome) > len(self.regular) - def hasNonChromeOnly(self): - return len(self.regular) > 0 - def variableName(self, chrome): - if chrome and self.hasChromeOnly(): - return "sChrome" + self.name - if self.hasNonChromeOnly(): - return "s" + self.name - return "NULL" - def usedForXrays(self, chrome): - # We only need Xrays for methods, attributes and constants. And we only - # need them for the non-chrome ones if we have no chromeonly things. - # Otherwise (we have chromeonly attributes) we need Xrays for the chrome - # methods/attributes/constants. Finally, in workers there are no Xrays. - return ((self.name is "Methods" or self.name is "Attributes" or - self.name is "Constants") and - chrome == self.hasChromeOnly() and - not self.descriptor.workers) - - def __str__(self): - # We only need to generate id arrays for things that will end - # up used via ResolveProperty or EnumerateProperties. - str = self.generateArray(self.regular, self.variableName(False), - self.usedForXrays(False)) - if self.hasChromeOnly(): - str += self.generateArray(self.chrome, self.variableName(True), - self.usedForXrays(True)) - return str - - @staticmethod - def getControllingPref(interfaceMember): - prefName = interfaceMember.getExtendedAttribute("Pref") - if prefName is None: - return None - # It's a list of strings - assert(len(prefName) is 1) - assert(prefName[0] is not None) - return prefName[0] - - def generatePrefableArray(self, array, name, specTemplate, specTerminator, - specType, getPref, getDataTuple, doIdArrays): - """ - This method generates our various arrays. - - array is an array of interface members as passed to generateArray - - name is the name as passed to generateArray - - specTemplate is a template for each entry of the spec array - - specTerminator is a terminator for the spec array (inserted every time - our controlling pref changes and at the end of the array) - - specType is the actual typename of our spec - - getPref is a callback function that takes an array entry and returns - the corresponding pref value. - - getDataTuple is a callback function that takes an array entry and - returns a tuple suitable for substitution into specTemplate. - """ - - # We want to generate a single list of specs, but with specTerminator - # inserted at every point where the pref name controlling the member - # changes. That will make sure the order of the properties as exposed - # on the interface and interface prototype objects does not change when - # pref control is added to members while still allowing us to define all - # the members in the smallest number of JSAPI calls. - assert(len(array) is not 0) - lastPref = getPref(array[0]) # So we won't put a specTerminator - # at the very front of the list. - specs = [] - prefableSpecs = [] - if doIdArrays: - prefableIds = [] - - prefableTemplate = ' { true, &%s[%d] }' - prefCacheTemplate = '&%s[%d].enabled' - def switchToPref(props, pref): - # Remember the info about where our pref-controlled - # booleans live. - if pref is not None: - props.prefCacheData.append( - (pref, prefCacheTemplate % (name, len(prefableSpecs))) - ) - # Set up pointers to the new sets of specs and ids - # inside prefableSpecs and prefableIds - prefableSpecs.append(prefableTemplate % - (name + "_specs", len(specs))) - - switchToPref(self, lastPref) - - for member in array: - curPref = getPref(member) - if lastPref != curPref: - # Terminate previous list - specs.append(specTerminator) - # And switch to our new pref - switchToPref(self, curPref) - lastPref = curPref - # And the actual spec - specs.append(specTemplate % getDataTuple(member)) - specs.append(specTerminator) - prefableSpecs.append(" { false, NULL }"); - - arrays = (("static %s %s_specs[] = {\n" + - ',\n'.join(specs) + "\n" + - "};\n\n" + - "static Prefable<%s> %s[] = {\n" + - ',\n'.join(prefableSpecs) + "\n" + - "};\n\n") % (specType, name, specType, name)) - if doIdArrays: - arrays += ("static jsid %s_ids[%i] = { JSID_VOID };\n\n" % - (name, len(specs))) - return arrays - - -# The length of a method is the maximum of the lengths of the -# argument lists of all its overloads. -def methodLength(method): - signatures = method.signatures() - return max([len(arguments) for (retType, arguments) in signatures]) - -class MethodDefiner(PropertyDefiner): - """ - A class for defining methods on a prototype object. - """ - def __init__(self, descriptor, name, static): - PropertyDefiner.__init__(self, descriptor, name) - - # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822 - # We should be able to check for special operations without an - # identifier. For now we check if the name starts with __ - methods = [m for m in descriptor.interface.members if - m.isMethod() and m.isStatic() == static and - not m.isIdentifierLess()] - self.chrome = [{"name": m.identifier.name, - "length": methodLength(m), - "flags": "JSPROP_ENUMERATE", - "pref": PropertyDefiner.getControllingPref(m) } - for m in methods] - self.regular = [{"name": m.identifier.name, - "length": methodLength(m), - "flags": "JSPROP_ENUMERATE", - "pref": PropertyDefiner.getControllingPref(m) } - for m in methods if not isChromeOnly(m)] - - # FIXME Check for an existing iterator on the interface first. - if any(m.isGetter() and m.isIndexed() for m in methods): - self.chrome.append({"name": 'iterator', - "methodInfo": False, - "nativeName": "JS_ArrayIterator", - "length": 0, - "flags": "JSPROP_ENUMERATE", - "pref": None }) - self.regular.append({"name": 'iterator', - "methodInfo": False, - "nativeName": "JS_ArrayIterator", - "length": 0, - "flags": "JSPROP_ENUMERATE", - "pref": None }) - - if not descriptor.interface.parent and not static and not descriptor.workers: - self.chrome.append({"name": 'QueryInterface', - "methodInfo": False, - "length": 1, - "flags": "0", - "pref": None }) - - if static: - if not descriptor.interface.hasInterfaceObject(): - # static methods go on the interface object - assert not self.hasChromeOnly() and not self.hasNonChromeOnly() - else: - if not descriptor.interface.hasInterfacePrototypeObject(): - # non-static methods go on the interface prototype object - assert not self.hasChromeOnly() and not self.hasNonChromeOnly() - - def generateArray(self, array, name, doIdArrays): - if len(array) == 0: - return "" - - def pref(m): - return m["pref"] - - def specData(m): - if m.get("methodInfo", True): - jitinfo = ("&%s_methodinfo" % m["name"]) - accessor = "genericMethod" - else: - jitinfo = "nullptr" - accessor = m.get("nativeName", m["name"]) - return (m["name"], accessor, jitinfo, m["length"], m["flags"]) - - return self.generatePrefableArray( - array, name, - ' JS_FNINFO("%s", %s, %s, %s, %s)', - ' JS_FS_END', - 'JSFunctionSpec', - pref, specData, doIdArrays) - -class AttrDefiner(PropertyDefiner): - def __init__(self, descriptor, name): - PropertyDefiner.__init__(self, descriptor, name) - self.name = name - self.chrome = [m for m in descriptor.interface.members if m.isAttr()] - self.regular = [m for m in self.chrome if not isChromeOnly(m)] - - def generateArray(self, array, name, doIdArrays): - if len(array) == 0: - return "" - - def flags(attr): - return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS" - - def getter(attr): - native = ("genericLenientGetter" if attr.hasLenientThis() - else "genericGetter") - return ("{(JSPropertyOp)%(native)s, &%(name)s_getterinfo}" - % {"name" : attr.identifier.name, - "native" : native}) - - def setter(attr): - if attr.readonly: - return "JSOP_NULLWRAPPER" - native = ("genericLenientSetter" if attr.hasLenientThis() - else "genericSetter") - return ("{(JSStrictPropertyOp)%(native)s, &%(name)s_setterinfo}" - % {"name" : attr.identifier.name, - "native" : native}) - - def specData(attr): - return (attr.identifier.name, flags(attr), getter(attr), - setter(attr)) - - return self.generatePrefableArray( - array, name, - ' { "%s", 0, %s, %s, %s}', - ' { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }', - 'JSPropertySpec', - PropertyDefiner.getControllingPref, specData, doIdArrays) - -class ConstDefiner(PropertyDefiner): - """ - A class for definining constants on the interface object - """ - def __init__(self, descriptor, name): - PropertyDefiner.__init__(self, descriptor, name) - self.name = name - self.chrome = [m for m in descriptor.interface.members if m.isConst()] - self.regular = [m for m in self.chrome if not isChromeOnly(m)] - - def generateArray(self, array, name, doIdArrays): - if len(array) == 0: - return "" - - def specData(const): - return (const.identifier.name, - convertConstIDLValueToJSVal(const.value)) - - return self.generatePrefableArray( - array, name, - ' { "%s", %s }', - ' { 0, JSVAL_VOID }', - 'ConstantSpec', - PropertyDefiner.getControllingPref, specData, doIdArrays) - -class PropertyArrays(): - def __init__(self, descriptor): - self.staticMethods = MethodDefiner(descriptor, "StaticMethods", True) - self.methods = MethodDefiner(descriptor, "Methods", False) - self.attrs = AttrDefiner(descriptor, "Attributes") - self.consts = ConstDefiner(descriptor, "Constants") - - @staticmethod - def arrayNames(): - return [ "staticMethods", "methods", "attrs", "consts" ] - - @staticmethod - def xrayRelevantArrayNames(): - return [ "methods", "attrs", "consts" ] - - def hasChromeOnly(self): - return reduce(lambda b, a: b or getattr(self, a).hasChromeOnly(), - self.arrayNames(), False) - def variableNames(self, chrome): - names = {} - for array in self.arrayNames(): - names[array] = getattr(self, array).variableName(chrome) - return names - def __str__(self): - define = "" - for array in self.arrayNames(): - define += str(getattr(self, array)) - return define - -class CGCreateInterfaceObjectsMethod(CGAbstractMethod): - """ - Generate the CreateInterfaceObjects method for an interface descriptor. - - properties should be a PropertyArrays instance. - """ - def __init__(self, descriptor, properties): - args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'), - Argument('JSObject*', 'aReceiver')] - CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'JSObject*', args) - self.properties = properties - def definition_body(self): - protoChain = self.descriptor.prototypeChain - if len(protoChain) == 1: - getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)" - else: - parentProtoName = self.descriptor.prototypeChain[-2] - getParentProto = ("%s::GetProtoObject(aCx, aGlobal, aReceiver)" % - toBindingNamespace(parentProtoName)) - - needInterfaceObject = self.descriptor.interface.hasInterfaceObject() - needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject() - - # if we don't need to create anything, why are we generating this? - assert needInterfaceObject or needInterfacePrototypeObject - - idsToInit = [] - # There is no need to init any IDs in workers, because worker bindings - # don't have Xrays. - if not self.descriptor.workers: - for var in self.properties.xrayRelevantArrayNames(): - props = getattr(self.properties, var) - # We only have non-chrome ids to init if we have no chrome ids. - if props.hasChromeOnly(): - idsToInit.append(props.variableName(True)) - elif props.hasNonChromeOnly(): - idsToInit.append(props.variableName(False)) - if len(idsToInit) > 0: - initIds = CGList( - [CGGeneric("!InitIds(aCx, %s, %s_ids)" % (varname, varname)) for - varname in idsToInit], ' ||\n') - if len(idsToInit) > 1: - initIds = CGWrapper(initIds, pre="(", post=")", reindent=True) - initIds = CGList( - [CGGeneric("%s_ids[0] == JSID_VOID &&" % idsToInit[0]), initIds], - "\n") - initIds = CGWrapper(initIds, pre="if (", post=") {", reindent=True) - initIds = CGList( - [initIds, - CGGeneric((" %s_ids[0] = JSID_VOID;\n" - " return NULL;") % idsToInit[0]), - CGGeneric("}")], - "\n") - else: - initIds = None - - prefCacheData = [] - for var in self.properties.arrayNames(): - props = getattr(self.properties, var) - prefCacheData.extend(props.prefCacheData) - if len(prefCacheData) is not 0: - prefCacheData = [ - CGGeneric('Preferences::AddBoolVarCache(%s, "%s");' % (ptr, pref)) for - (pref, ptr) in prefCacheData] - prefCache = CGWrapper(CGIndenter(CGList(prefCacheData, "\n")), - pre=("static bool sPrefCachesInited = false;\n" - "if (!sPrefCachesInited) {\n" - " sPrefCachesInited = true;\n"), - post="\n}") - else: - prefCache = None - - getParentProto = ("JSObject* parentProto = %s;\n" + - "if (!parentProto) {\n" + - " return NULL;\n" + - "}\n") % getParentProto - - needInterfaceObjectClass = (needInterfaceObject and - self.descriptor.hasInstanceInterface) - needConstructor = (needInterfaceObject and - not self.descriptor.hasInstanceInterface) - if self.descriptor.interface.ctor(): - constructHook = CONSTRUCT_HOOK_NAME - constructArgs = methodLength(self.descriptor.interface.ctor()) - else: - constructHook = "ThrowingConstructor" - constructArgs = 0 - - if self.descriptor.concrete: - if self.descriptor.proxy: - domClass = "&Class" - else: - domClass = "&Class.mClass" - else: - domClass = "nullptr" - - call = """return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto, - %s, %s, %s, %d, - %s, - %%(methods)s, %%(attrs)s, - %%(consts)s, %%(staticMethods)s, - %s);""" % ( - "&PrototypeClass" if needInterfacePrototypeObject else "NULL", - "&InterfaceObjectClass" if needInterfaceObjectClass else "NULL", - constructHook if needConstructor else "NULL", - constructArgs, - domClass, - '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL") - if self.properties.hasChromeOnly(): - if self.descriptor.workers: - accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()" - else: - accessCheck = "xpc::AccessCheck::isChrome(js::GetObjectCompartment(aGlobal))" - chrome = CGIfWrapper(CGGeneric(call % self.properties.variableNames(True)), - accessCheck) - chrome = CGWrapper(chrome, pre="\n\n") - else: - chrome = None - - functionBody = CGList( - [CGGeneric(getParentProto), initIds, prefCache, chrome, - CGGeneric(call % self.properties.variableNames(False))], - "\n\n") - return CGIndenter(functionBody).define() - -class CGGetPerInterfaceObject(CGAbstractMethod): - """ - A method for getting a per-interface object (a prototype object or interface - constructor object). - """ - def __init__(self, descriptor, name, idPrefix=""): - args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'), - Argument('JSObject*', 'aReceiver')] - CGAbstractMethod.__init__(self, descriptor, name, - 'JSObject*', args, inline=True) - self.id = idPrefix + "id::" + self.descriptor.name - def definition_body(self): - return """ - - /* aGlobal and aReceiver are usually the same, but they can be different - too. For example a sandbox often has an xray wrapper for a window as the - prototype of the sandbox's global. In that case aReceiver is the xray - wrapper and aGlobal is the sandbox's global. - */ - - /* Make sure our global is sane. Hopefully we can remove this sometime */ - if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) { - return NULL; - } - /* Check to see whether the interface objects are already installed */ - JSObject** protoOrIfaceArray = GetProtoOrIfaceArray(aGlobal); - JSObject* cachedObject = protoOrIfaceArray[%s]; - if (!cachedObject) { - protoOrIfaceArray[%s] = cachedObject = CreateInterfaceObjects(aCx, aGlobal, aReceiver); - } - - /* cachedObject might _still_ be null, but that's OK */ - return cachedObject;""" % (self.id, self.id) - -class CGGetProtoObjectMethod(CGGetPerInterfaceObject): - """ - A method for getting the interface prototype object. - """ - def __init__(self, descriptor): - CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject", - "prototypes::") - def definition_body(self): - return """ - /* Get the interface prototype object for this class. This will create the - object as needed. */""" + CGGetPerInterfaceObject.definition_body(self) - -class CGGetConstructorObjectMethod(CGGetPerInterfaceObject): - """ - A method for getting the interface constructor object. - """ - def __init__(self, descriptor): - CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject", - "constructors::") - def definition_body(self): - return """ - /* Get the interface object for this class. This will create the object as - needed. */""" + CGGetPerInterfaceObject.definition_body(self) - -def CheckPref(descriptor, globalName, varName, retval, wrapperCache = None): - """ - Check whether bindings should be enabled for this descriptor. If not, set - varName to false and return retval. - """ - if not descriptor.prefable: - return "" - - if wrapperCache: - wrapperCache = " %s->ClearIsDOMBinding();\n" % (wrapperCache) - else: - wrapperCache = "" - - failureCode = (" %s = false;\n" + - " return %s;") % (varName, retval) - return """ - { - XPCWrappedNativeScope* scope = - XPCWrappedNativeScope::FindInJSObjectScope(aCx, %s); - if (!scope) { -%s - } - - if (!scope->ExperimentalBindingsEnabled()) { -%s%s - } - } -""" % (globalName, failureCode, wrapperCache, failureCode) - -class CGDefineDOMInterfaceMethod(CGAbstractMethod): - """ - A method for resolve hooks to try to lazily define the interface object for - a given interface. - """ - def __init__(self, descriptor): - args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aReceiver'), - Argument('bool*', 'aEnabled')] - CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args) - - def declare(self): - if self.descriptor.workers: - return '' - return CGAbstractMethod.declare(self) - - def define(self): - if self.descriptor.workers: - return '' - return CGAbstractMethod.define(self) - - def definition_body(self): - if self.descriptor.interface.hasInterfacePrototypeObject(): - # We depend on GetProtoObject defining an interface constructor - # object as needed. - getter = "GetProtoObject" - else: - getter = "GetConstructorObject" - - return (" JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" + - CheckPref(self.descriptor, "global", "*aEnabled", "false") + - """ - *aEnabled = true; - return !!%s(aCx, global, aReceiver);""" % (getter)) - -class CGPrefEnabled(CGAbstractMethod): - """ - A method for testing whether the preference controlling this - interface is enabled. When it's not, the interface should not be - visible on the global. - """ - def __init__(self, descriptor): - CGAbstractMethod.__init__(self, descriptor, 'PrefEnabled', 'bool', []) - - def declare(self): - return CGAbstractMethod.declare(self) - - def define(self): - return CGAbstractMethod.define(self) - - def definition_body(self): - return " return %s::PrefEnabled();" % self.descriptor.nativeType - -class CGIsMethod(CGAbstractMethod): - def __init__(self, descriptor): - args = [Argument('JSObject*', 'obj')] - CGAbstractMethod.__init__(self, descriptor, 'Is', 'bool', args) - - def definition_body(self): - # Non-proxy implementation would check - # js::GetObjectJSClass(obj) == &Class.mBase - return """ return IsProxy(obj);""" - -def CreateBindingJSObject(descriptor, parent): - if descriptor.proxy: - create = """ JSObject *obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(), - JS::PrivateValue(aObject), proto, %s); - if (!obj) { - return NULL; - } - -""" - else: - create = """ JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, %s); - if (!obj) { - return NULL; - } - - js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject)); -""" - return create % parent - -class CGWrapWithCacheMethod(CGAbstractMethod): - def __init__(self, descriptor): - assert descriptor.interface.hasInterfacePrototypeObject() - args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'), - Argument(descriptor.nativeType + '*', 'aObject'), - Argument('nsWrapperCache*', 'aCache'), - Argument('bool*', 'aTriedToWrap')] - CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args) - - def definition_body(self): - if self.descriptor.workers: - return """ *aTriedToWrap = true; - return aObject->GetJSObject();""" - - return """ *aTriedToWrap = true; - - JSObject* parent = WrapNativeParent(aCx, aScope, aObject->GetParentObject()); - if (!parent) { - return NULL; - } - - JSAutoCompartment ac(aCx, parent); - JSObject* global = JS_GetGlobalForObject(aCx, parent); -%s - JSObject* proto = GetProtoObject(aCx, global, global); - if (!proto) { - return NULL; - } - -%s - NS_ADDREF(aObject); - - aCache->SetWrapper(obj); - - return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"), - CreateBindingJSObject(self.descriptor, "parent")) - -class CGWrapMethod(CGAbstractMethod): - def __init__(self, descriptor): - # XXX can we wrap if we don't have an interface prototype object? - assert descriptor.interface.hasInterfacePrototypeObject() - args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'), - Argument('T*', 'aObject'), Argument('bool*', 'aTriedToWrap')] - CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args, inline=True, templateArgs=["class T"]) - - def definition_body(self): - return " return Wrap(aCx, aScope, aObject, aObject, aTriedToWrap);" - -class CGWrapNonWrapperCacheMethod(CGAbstractMethod): - def __init__(self, descriptor): - # XXX can we wrap if we don't have an interface prototype object? - assert descriptor.interface.hasInterfacePrototypeObject() - args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'), - Argument(descriptor.nativeType + '*', 'aObject')] - CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args) - - def definition_body(self): - return """ - JSObject* global = JS_GetGlobalForObject(aCx, aScope); - JSObject* proto = GetProtoObject(aCx, global, global); - if (!proto) { - return NULL; - } - -%s - NS_ADDREF(aObject); - - return obj;""" % CreateBindingJSObject(self.descriptor, "global") - -builtinNames = { - IDLType.Tags.bool: 'bool', - IDLType.Tags.int8: 'int8_t', - IDLType.Tags.int16: 'int16_t', - IDLType.Tags.int32: 'int32_t', - IDLType.Tags.int64: 'int64_t', - IDLType.Tags.uint8: 'uint8_t', - IDLType.Tags.uint16: 'uint16_t', - IDLType.Tags.uint32: 'uint32_t', - IDLType.Tags.uint64: 'uint64_t', - IDLType.Tags.float: 'float', - IDLType.Tags.double: 'double' -} - -numericTags = [ - IDLType.Tags.int8, IDLType.Tags.uint8, - IDLType.Tags.int16, IDLType.Tags.uint16, - IDLType.Tags.int32, IDLType.Tags.uint32, - IDLType.Tags.int64, IDLType.Tags.uint64, - IDLType.Tags.float, IDLType.Tags.double - ] - -class CastableObjectUnwrapper(): - """ - A class for unwrapping an object named by the "source" argument - based on the passed-in descriptor and storing it in a variable - called by the name in the "target" argument. - - codeOnFailure is the code to run if unwrapping fails. - """ - def __init__(self, descriptor, source, target, codeOnFailure): - assert descriptor.castable - - self.substitution = { "type" : descriptor.nativeType, - "protoID" : "prototypes::id::" + descriptor.name, - "source" : source, - "target" : target, - "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define() } - if descriptor.hasXPConnectImpls: - # We don't use xpc_qsUnwrapThis because it will always throw on - # unwrap failure, whereas we want to control whether we throw or - # not. - self.substitution["codeOnFailure"] = CGIndenter(CGGeneric(string.Template( - "${type} *objPtr;\n" - "xpc_qsSelfRef objRef;\n" - "JS::Value val = JS::ObjectValue(*${source});\n" - "nsresult rv = xpc_qsUnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n" - "if (NS_FAILED(rv)) {\n" - "${codeOnFailure}\n" - "}\n" - "// We should be castable!\n" - "MOZ_ASSERT(!objRef.ptr);\n" - "// We should have an object, too!\n" - "MOZ_ASSERT(objPtr);\n" - "${target} = objPtr;").substitute(self.substitution)), 4).define() - - def __str__(self): - return string.Template( -"""{ - nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target}); - if (NS_FAILED(rv)) { -${codeOnFailure} - } -}""").substitute(self.substitution) - -class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper): - """ - As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails - """ - def __init__(self, descriptor, source, target): - CastableObjectUnwrapper.__init__(self, descriptor, source, target, - "return Throw<%s>(cx, rv);" % - toStringBool(not descriptor.workers)) - -class CallbackObjectUnwrapper: - """ - A class for unwrapping objects implemented in JS. - - |source| is the JSObject we want to use in native code. - |target| is an nsCOMPtr of the appropriate type in which we store the result. - """ - def __init__(self, descriptor, source, target, codeOnFailure=None): - if codeOnFailure is None: - codeOnFailure = ("return Throw<%s>(cx, rv);" % - toStringBool(not descriptor.workers)) - self.descriptor = descriptor - self.substitution = { "nativeType" : descriptor.nativeType, - "source" : source, - "target" : target, - "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure)).define() } - - def __str__(self): - if self.descriptor.workers: - return string.Template( - "${target} = ${source};" - ).substitute(self.substitution) - - return string.Template( - """nsresult rv; -XPCCallContext ccx(JS_CALLER, cx); -if (!ccx.IsValid()) { - rv = NS_ERROR_XPC_BAD_CONVERT_JS; -${codeOnFailure} -} - -const nsIID& iid = NS_GET_IID(${nativeType}); -nsRefPtr<nsXPCWrappedJS> wrappedJS; -rv = nsXPCWrappedJS::GetNewOrUsed(ccx, ${source}, iid, - NULL, getter_AddRefs(wrappedJS)); -if (NS_FAILED(rv) || !wrappedJS) { -${codeOnFailure} -} - -// Use a temp nsCOMPtr for the null-check, because ${target} might be -// OwningNonNull, not an nsCOMPtr. -nsCOMPtr<${nativeType}> tmp = do_QueryObject(wrappedJS.get()); -if (!tmp) { -${codeOnFailure} -} -${target} = tmp.forget();""").substitute(self.substitution) - -def dictionaryHasSequenceMember(dictionary): - return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in - dictionary.members) or - (dictionary.parent and - dictionaryHasSequenceMember(dictionary.parent))) - -def typeIsSequenceOrHasSequenceMember(type): - if type.nullable(): - type = type.inner - if type.isSequence(): - return True - if type.isArray(): - elementType = type.inner - return typeIsSequenceOrHasSequenceMember(elementType) - if type.isDictionary(): - return dictionaryHasSequenceMember(type.inner) - if type.isUnion(): - return any(typeIsSequenceOrHasSequenceMember(m.type) for m in - type.flatMemberTypes) - return False - -def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, - isDefinitelyObject=False, - isMember=False, - isOptional=False, - invalidEnumValueFatal=True, - defaultValue=None, - treatNullAs="Default", - treatUndefinedAs="Default", - isEnforceRange=False, - isClamp=False): - """ - Get a template for converting a JS value to a native object based on the - given type and descriptor. If failureCode is given, then we're actually - testing whether we can convert the argument to the desired type. That - means that failures to convert due to the JS value being the wrong type of - value need to use failureCode instead of throwing exceptions. Failures to - convert that are due to JS exceptions (from toString or valueOf methods) or - out of memory conditions need to throw exceptions no matter what - failureCode is. - - If isDefinitelyObject is True, that means we know the value - isObject() and we have no need to recheck that. - - if isMember is True, we're being converted from a property of some - JS object, not from an actual method argument, so we can't rely on - our jsval being rooted or outliving us in any way. Any caller - passing true needs to ensure that it is handled correctly in - typeIsSequenceOrHasSequenceMember. - - If isOptional is true, then we are doing conversion of an optional - argument with no default value. - - invalidEnumValueFatal controls whether an invalid enum value conversion - attempt will throw (if true) or simply return without doing anything (if - false). - - If defaultValue is not None, it's the IDL default value for this conversion - - If isEnforceRange is true, we're converting an integer and throwing if the - value is out of range. - - If isClamp is true, we're converting an integer and clamping if the - value is out of range. - - The return value from this function is a tuple consisting of four things: - - 1) A string representing the conversion code. This will have template - substitution performed on it as follows: - - ${val} replaced by an expression for the JS::Value in question - ${valPtr} is a pointer to the JS::Value in question - ${holderName} replaced by the holder's name, if any - ${declName} replaced by the declaration's name - ${haveValue} replaced by an expression that evaluates to a boolean - for whether we have a JS::Value. Only used when - defaultValue is not None. - - 2) A CGThing representing the native C++ type we're converting to - (declType). This is allowed to be None if the conversion code is - supposed to be used as-is. - 3) A CGThing representing the type of a "holder" (holderType) which will - hold a possible reference to the C++ thing whose type we returned in #1, - or None if no such holder is needed. - 4) A boolean indicating whether the caller has to do optional-argument handling. - This will only be true if isOptional is true and if the returned template - expects both declType and holderType to be wrapped in Optional<>, with - ${declName} and ${holderName} adjusted to point to the Value() of the - Optional, and Construct() calls to be made on the Optional<>s as needed. - - ${declName} must be in scope before the generated code is entered. - - If holderType is not None then ${holderName} must be in scope - before the generated code is entered. - """ - # If we have a defaultValue then we're not actually optional for - # purposes of what we need to be declared as. - assert(defaultValue is None or not isOptional) - - # Also, we should not have a defaultValue if we know we're an object - assert(not isDefinitelyObject or defaultValue is None) - - # Helper functions for dealing with failures due to the JS value being the - # wrong type of value - def onFailureNotAnObject(failureCode): - return CGWrapper(CGGeneric( - failureCode or - 'return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n") - def onFailureBadType(failureCode, typeName): - return CGWrapper(CGGeneric( - failureCode or - 'return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n") - - # A helper function for handling default values. Takes a template - # body and the C++ code to set the default value and wraps the - # given template body in handling for the default value. - def handleDefault(template, setDefault): - if defaultValue is None: - return template - return CGWrapper( - CGIndenter(CGGeneric(template)), - pre="if (${haveValue}) {\n", - post=("\n" - "} else {\n" - "%s;\n" - "}" % - CGIndenter(CGGeneric(setDefault)).define())).define() - - # A helper function for handling null default values. Much like - # handleDefault, but checks that the default value, if it exists, is null. - def handleDefaultNull(template, codeToSetNull): - if (defaultValue is not None and - not isinstance(defaultValue, IDLNullValue)): - raise TypeError("Can't handle non-null default value here") - return handleDefault(template, codeToSetNull) - - # A helper function for wrapping up the template body for - # possibly-nullable objecty stuff - def wrapObjectTemplate(templateBody, isDefinitelyObject, type, - codeToSetNull, failureCode=None): - if not isDefinitelyObject: - # Handle the non-object cases by wrapping up the whole - # thing in an if cascade. - templateBody = ( - "if (${val}.isObject()) {\n" + - CGIndenter(CGGeneric(templateBody)).define() + "\n") - if type.nullable(): - templateBody += ( - "} else if (${val}.isNullOrUndefined()) {\n" - " %s;\n" % codeToSetNull) - templateBody += ( - "} else {\n" + - CGIndenter(onFailureNotAnObject(failureCode)).define() + - "}") - if type.nullable(): - templateBody = handleDefaultNull(templateBody, codeToSetNull) - else: - assert(defaultValue is None) - - return templateBody - - assert not (isEnforceRange and isClamp) # These are mutually exclusive - - if type.isArray(): - raise TypeError("Can't handle array arguments yet") - - if type.isSequence(): - assert not isEnforceRange and not isClamp - - if failureCode is not None: - raise TypeError("Can't handle sequences when failureCode is not None") - nullable = type.nullable(); - # Be very careful not to change "type": we need it later - if nullable: - elementType = type.inner.inner - else: - elementType = type.inner - - # We have to be careful with reallocation behavior for arrays. In - # particular, if we have a sequence of elements which are themselves - # sequences (so nsAutoTArrays) or have sequences as members, we have a - # problem. In that case, resizing the outermost nsAutoTarray to the - # right size will memmove its elements, but nsAutoTArrays are not - # memmovable and hence will end up with pointers to bogus memory, which - # is bad. To deal with this, we disallow sequences, arrays, - # dictionaries, and unions which contain sequences as sequence item - # types. If WebIDL ever adds another container type, we'd have to - # disallow it as well. - if typeIsSequenceOrHasSequenceMember(elementType): - raise TypeError("Can't handle a sequence containing another " - "sequence as an element or member of an element. " - "See the big comment explaining why.\n%s" % - str(type.location)) - - (elementTemplate, elementDeclType, - elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate( - elementType, descriptorProvider, isMember=True) - if dealWithOptional: - raise TypeError("Shouldn't have optional things in sequences") - if elementHolderType is not None: - raise TypeError("Shouldn't need holders for sequences") - - typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >") - if nullable: - typeName = CGWrapper(typeName, pre="Nullable< ", post=" >") - arrayRef = "${declName}.Value()" - else: - arrayRef = "${declName}" - # If we're optional, the const will come from the Optional - mutableTypeName = typeName - if not isOptional: - typeName = CGWrapper(typeName, pre="const ") - - templateBody = ("""JSObject* seq = &${val}.toObject();\n -if (!IsArrayLike(cx, seq)) { - return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS); -} -uint32_t length; -// JS_GetArrayLength actually works on all objects -if (!JS_GetArrayLength(cx, seq, &length)) { - return false; -} -Sequence< %s > &arr = const_cast< Sequence< %s >& >(%s); -if (!arr.SetCapacity(length)) { - return Throw<%s>(cx, NS_ERROR_OUT_OF_MEMORY); -} -for (uint32_t i = 0; i < length; ++i) { - jsval temp; - if (!JS_GetElement(cx, seq, i, &temp)) { - return false; - } -""" % (toStringBool(descriptorProvider.workers), - elementDeclType.define(), - elementDeclType.define(), - arrayRef, - toStringBool(descriptorProvider.workers))) - - templateBody += CGIndenter(CGGeneric( - string.Template(elementTemplate).substitute( - { - "val" : "temp", - "valPtr": "&temp", - "declName" : "(*arr.AppendElement())" - } - ))).define() - - templateBody += "\n}" - templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject, - type, - "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define()) - return (templateBody, typeName, None, isOptional) - - if type.isUnion(): - if isMember: - raise TypeError("Can't handle unions as members, we have a " - "holderType") - nullable = type.nullable(); - if nullable: - type = type.inner - - assert(defaultValue is None or - (isinstance(defaultValue, IDLNullValue) and nullable)) - - unionArgumentObj = "${holderName}" - if isOptional or nullable: - unionArgumentObj += ".ref()" - - memberTypes = type.flatMemberTypes - names = [] - - interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes) - if len(interfaceMemberTypes) > 0: - interfaceObject = [] - for memberType in interfaceMemberTypes: - if type.isGeckoInterface(): - name = memberType.inner.identifier.name - else: - name = memberType.name - interfaceObject.append(CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext" % (unionArgumentObj, name))) - names.append(name) - interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True) - else: - interfaceObject = None - - arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes) - if len(arrayObjectMemberTypes) > 0: - assert len(arrayObjectMemberTypes) == 1 - memberType = arrayObjectMemberTypes[0] - name = memberType.name - arrayObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name)) - # XXX Now we're supposed to check for an array or a platform object - # that supports indexed properties... skip that last for now. It's a - # bit of a pain. - arrayObject = CGWrapper(CGIndenter(arrayObject), - pre="if (IsArrayLike(cx, &argObj)) {\n", - post="}") - names.append(name) - else: - arrayObject = None - - dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes) - if len(dateObjectMemberTypes) > 0: - assert len(dateObjectMemberTypes) == 1 - memberType = dateObjectMemberTypes[0] - name = memberType.name - dateObject = CGGeneric("%s.SetTo%s(cx, ${val}, ${valPtr});\n" - "done = true;" % (unionArgumentObj, name)) - dateObject = CGWrapper(CGIndenter(dateObject), - pre="if (JS_ObjectIsDate(cx, &argObj)) {\n", - post="\n}") - names.append(name) - else: - dateObject = None - - callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes) - if len(callbackMemberTypes) > 0: - assert len(callbackMemberTypes) == 1 - memberType = callbackMemberTypes[0] - name = memberType.name - callbackObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name)) - names.append(name) - else: - callbackObject = None - - dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes) - if len(dictionaryMemberTypes) > 0: - raise TypeError("No support for unwrapping dictionaries as member " - "of a union") - else: - dictionaryObject = None - - if callbackObject or dictionaryObject: - nonPlatformObject = CGList([callbackObject, dictionaryObject], "\n") - nonPlatformObject = CGWrapper(CGIndenter(nonPlatformObject), - pre="if (!IsPlatformObject(cx, &argObj)) {\n", - post="\n}") - else: - nonPlatformObject = None - - objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) - if len(objectMemberTypes) > 0: - object = CGGeneric("%s.SetToObject(&argObj);\n" - "done = true;" % unionArgumentObj) - else: - object = None - - hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object - if hasObjectTypes: - # If we try more specific object types first then we need to check - # whether that succeeded before converting to object. - if object and (interfaceObject or arrayObject or dateObject or nonPlatformObject): - object = CGWrapper(CGIndenter(object), pre="if (!done) {\n", - post=("\n}")) - - if arrayObject or dateObject or nonPlatformObject: - # An object can be both an array object and not a platform - # object, but we shouldn't have both in the union's members - # because they are not distinguishable. - assert not (arrayObject and nonPlatformObject) - templateBody = CGList([arrayObject, dateObject, nonPlatformObject], " else ") - else: - templateBody = None - if interfaceObject: - if templateBody: - templateBody = CGList([templateBody, object], "\n") - templateBody = CGWrapper(CGIndenter(templateBody), - pre="if (!done) {\n", post=("\n}")) - templateBody = CGList([interfaceObject, templateBody], "\n") - else: - templateBody = CGList([templateBody, object], "\n") - - if any([arrayObject, dateObject, nonPlatformObject, object]): - templateBody.prepend(CGGeneric("JSObject& argObj = ${val}.toObject();")) - templateBody = CGWrapper(CGIndenter(templateBody), - pre="if (${val}.isObject()) {\n", - post="\n}") - else: - templateBody = CGGeneric() - - otherMemberTypes = filter(lambda t: t.isString() or t.isEnum(), - memberTypes) - otherMemberTypes.extend(t for t in memberTypes if t.isPrimitive()) - if len(otherMemberTypes) > 0: - assert len(otherMemberTypes) == 1 - memberType = otherMemberTypes[0] - if memberType.isEnum(): - name = memberType.inner.identifier.name - else: - name = memberType.name - other = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name)) - names.append(name) - if hasObjectTypes: - other = CGWrapper(CGIndenter(other), "{\n", post="\n}") - if object: - join = " else " - else: - other = CGWrapper(other, pre="if (!done) ") - join = "\n" - templateBody = CGList([templateBody, other], join) - else: - other = None - - templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n") - throw = CGGeneric("if (failed) {\n" - " return false;\n" - "}\n" - "if (!done) {\n" - " return ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n" - "}" % ", ".join(names)) - templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}") - - typeName = type.name - argumentTypeName = typeName + "Argument" - if nullable: - typeName = "Nullable<" + typeName + " >" - if isOptional: - nonConstDecl = "const_cast<Optional<" + typeName + " >& >(${declName})" - else: - nonConstDecl = "const_cast<" + typeName + "& >(${declName})" - typeName = "const " + typeName - - def handleNull(templateBody, setToNullVar, extraConditionForNull=""): - null = CGGeneric("if (%s${val}.isNullOrUndefined()) {\n" - " %s.SetNull();\n" - "}" % (extraConditionForNull, setToNullVar)) - templateBody = CGWrapper(CGIndenter(templateBody), pre="{\n", post="\n}") - return CGList([null, templateBody], " else ") - - if type.hasNullableType: - templateBody = handleNull(templateBody, unionArgumentObj) - - declType = CGGeneric(typeName) - holderType = CGGeneric(argumentTypeName) - if isOptional: - mutableDecl = nonConstDecl + ".Value()" - declType = CGWrapper(declType, pre="const Optional<", post=" >") - holderType = CGWrapper(holderType, pre="Maybe<", post=" >") - constructDecl = CGGeneric(nonConstDecl + ".Construct();") - if nullable: - constructHolder = CGGeneric("${holderName}.construct(%s.SetValue());" % mutableDecl) - else: - constructHolder = CGGeneric("${holderName}.construct(${declName}.Value());") - else: - mutableDecl = nonConstDecl - constructDecl = None - if nullable: - holderType = CGWrapper(holderType, pre="Maybe<", post=" >") - constructHolder = CGGeneric("${holderName}.construct(%s.SetValue());" % mutableDecl) - else: - constructHolder = CGWrapper(holderType, post=" ${holderName}(${declName});") - holderType = None - - templateBody = CGList([constructHolder, templateBody], "\n") - if nullable: - if defaultValue: - assert(isinstance(defaultValue, IDLNullValue)) - valueMissing = "!(${haveValue}) || " - else: - valueMissing = "" - templateBody = handleNull(templateBody, mutableDecl, - extraConditionForNull=valueMissing) - templateBody = CGList([constructDecl, templateBody], "\n") - - return templateBody.define(), declType, holderType, False - - if type.isGeckoInterface(): - assert not isEnforceRange and not isClamp - - descriptor = descriptorProvider.getDescriptor( - type.unroll().inner.identifier.name) - # This is an interface that we implement as a concrete class - # or an XPCOM interface. - - # Allow null pointers for nullable types and old-binding classes - argIsPointer = type.nullable() or type.unroll().inner.isExternal() - - # Sequences and non-worker callbacks have to hold a strong ref to the - # thing being passed down. - forceOwningType = (descriptor.interface.isCallback() and - not descriptor.workers) or isMember - - typeName = descriptor.nativeType - typePtr = typeName + "*" - - # Compute a few things: - # - declType is the type we want to return as the first element of our - # tuple. - # - holderType is the type we want to return as the third element - # of our tuple. - - # Set up some sensible defaults for these things insofar as we can. - holderType = None - if argIsPointer: - if forceOwningType: - declType = "nsRefPtr<" + typeName + ">" - else: - declType = typePtr - else: - if forceOwningType: - declType = "OwningNonNull<" + typeName + ">" - else: - declType = "NonNull<" + typeName + ">" - - templateBody = "" - if descriptor.castable: - if descriptor.prefable: - raise TypeError("We don't support prefable castable object " - "arguments (like %s), because we don't know " - "how to handle them being preffed off" % - descriptor.interface.identifier.name) - if descriptor.interface.isConsequential(): - raise TypeError("Consequential interface %s being used as an " - "argument but flagged as castable" % - descriptor.interface.identifier.name) - if failureCode is not None: - templateBody += str(CastableObjectUnwrapper( - descriptor, - "&${val}.toObject()", - "${declName}", - failureCode)) - else: - templateBody += str(FailureFatalCastableObjectUnwrapper( - descriptor, - "&${val}.toObject()", - "${declName}")) - elif descriptor.interface.isCallback(): - templateBody += str(CallbackObjectUnwrapper( - descriptor, - "&${val}.toObject()", - "${declName}", - codeOnFailure=failureCode)) - elif descriptor.workers: - templateBody += "${declName} = &${val}.toObject();" - else: - # Either external, or new-binding non-castable. We always have a - # holder for these, because we don't actually know whether we have - # to addref when unwrapping or not. So we just pass an - # getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release - # it'll put a non-null pointer in there. - if forceOwningType: - # Don't return a holderType in this case; our declName - # will just own stuff. - templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n" - else: - holderType = "nsRefPtr<" + typeName + ">" - templateBody += ( - "jsval tmpVal = ${val};\n" + - typePtr + " tmp;\n" - "if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n") - templateBody += CGIndenter(onFailureBadType(failureCode, - descriptor.interface.identifier.name)).define() - templateBody += ("}\n" - "MOZ_ASSERT(tmp);\n") - - if not isDefinitelyObject: - # Our tmpVal will go out of scope, so we can't rely on it - # for rooting - templateBody += ( - "if (tmpVal != ${val} && !${holderName}) {\n" - " // We have to have a strong ref, because we got this off\n" - " // some random object that might get GCed\n" - " ${holderName} = tmp;\n" - "}\n") - - # And store our tmp, before it goes out of scope. - templateBody += "${declName} = tmp;" - - templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject, - type, "${declName} = NULL", - failureCode) - - declType = CGGeneric(declType) - if holderType is not None: - holderType = CGGeneric(holderType) - return (templateBody, declType, holderType, isOptional) - - if type.isSpiderMonkeyInterface(): - assert not isEnforceRange and not isClamp - if isMember: - raise TypeError("Can't handle member arraybuffers or " - "arraybuffer views because making sure all the " - "objects are properly rooted is hard") - name = type.name - # By default, we use a Maybe<> to hold our typed array. And in the optional - # non-nullable case we want to pass Optional<TypedArray> to consumers, not - # Optional<NonNull<TypedArray> >, so jump though some hoops to do that. - holderType = "Maybe<%s>" % name - constructLoc = "${holderName}" - constructMethod = "construct" - constructInternal = "ref" - if type.nullable(): - if isOptional: - declType = "const Optional<" + name + "*>" - else: - declType = name + "*" - else: - if isOptional: - declType = "const Optional<" + name + ">" - # We don't need a holder in this case - holderType = None - constructLoc = "(const_cast<Optional<" + name + ">& >(${declName}))" - constructMethod = "Construct" - constructInternal = "Value" - else: - declType = "NonNull<" + name + ">" - template = ( - "%s.%s(cx, &${val}.toObject());\n" - "if (!%s.%s().inited()) {\n" - "%s" # No newline here because onFailureBadType() handles that - "}\n" % - (constructLoc, constructMethod, constructLoc, constructInternal, - CGIndenter(onFailureBadType(failureCode, type.name)).define())) - nullableTarget = "" - if type.nullable(): - if isOptional: - mutableDecl = "(const_cast<Optional<" + name + "*>& >(${declName}))" - template += "%s.Construct();\n" % mutableDecl - nullableTarget = "%s.Value()" % mutableDecl - else: - nullableTarget = "${declName}" - template += "%s = ${holderName}.addr();" % nullableTarget - elif not isOptional: - template += "${declName} = ${holderName}.addr();" - template = wrapObjectTemplate(template, isDefinitelyObject, type, - "%s = NULL" % nullableTarget, - failureCode) - - if holderType is not None: - holderType = CGGeneric(holderType) - # We handle all the optional stuff ourselves; no need for caller to do it. - return (template, CGGeneric(declType), holderType, False) - - if type.isString(): - assert not isEnforceRange and not isClamp - - treatAs = { - "Default": "eStringify", - "EmptyString": "eEmpty", - "Null": "eNull" - } - if type.nullable(): - # For nullable strings null becomes a null string. - treatNullAs = "Null" - # For nullable strings undefined becomes a null string unless - # specified otherwise. - if treatUndefinedAs == "Default": - treatUndefinedAs = "Null" - nullBehavior = treatAs[treatNullAs] - if treatUndefinedAs == "Missing": - raise TypeError("We don't support [TreatUndefinedAs=Missing]") - undefinedBehavior = treatAs[treatUndefinedAs] - - def getConversionCode(varName): - conversionCode = ( - "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n" - " return false;\n" - "}" % (nullBehavior, undefinedBehavior, varName)) - if defaultValue is None: - return conversionCode - - if isinstance(defaultValue, IDLNullValue): - assert(type.nullable()) - return handleDefault(conversionCode, - "%s.SetNull()" % varName) - return handleDefault( - conversionCode, - ("static const PRUnichar data[] = { %s };\n" - "%s.SetData(data, ArrayLength(data) - 1)" % - (", ".join(["'" + char + "'" for char in defaultValue.value] + ["0"]), - varName))) - - if isMember: - # We have to make a copy, because our jsval may well not - # live as long as our string needs to. - declType = CGGeneric("nsString") - return ( - "{\n" - " FakeDependentString str;\n" - "%s\n" - " ${declName} = str;\n" - "}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(), - declType, None, isOptional) - - if isOptional: - declType = "Optional<nsAString>" - else: - declType = "NonNull<nsAString>" - - return ( - "%s\n" - "const_cast<%s&>(${declName}) = &${holderName};" % - (getConversionCode("${holderName}"), declType), - CGGeneric("const " + declType), CGGeneric("FakeDependentString"), - # No need to deal with Optional here; we have handled it already - False) - - if type.isEnum(): - assert not isEnforceRange and not isClamp - - if type.nullable(): - raise TypeError("We don't support nullable enumerated arguments " - "yet") - enum = type.inner.identifier.name - if invalidEnumValueFatal: - handleInvalidEnumValueCode = " MOZ_ASSERT(index >= 0);\n" - else: - handleInvalidEnumValueCode = ( - " if (index < 0) {\n" - " return true;\n" - " }\n") - - template = ( - "{\n" - " bool ok;\n" - " int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n" - " if (!ok) {\n" - " return false;\n" - " }\n" - "%(handleInvalidEnumValueCode)s" - " ${declName} = static_cast<%(enumtype)s>(index);\n" - "}" % { "enumtype" : enum, - "values" : enum + "Values::strings", - "invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal), - "handleInvalidEnumValueCode" : handleInvalidEnumValueCode }) - - if defaultValue is not None: - assert(defaultValue.type.tag() == IDLType.Tags.domstring) - template = handleDefault(template, - ("${declName} = %sValues::%s" % - (enum, - getEnumValueName(defaultValue.value)))) - return (template, CGGeneric(enum), None, isOptional) - - if type.isCallback(): - assert not isEnforceRange and not isClamp - - if isMember: - raise TypeError("Can't handle member callbacks; need to sort out " - "rooting issues") - # XXXbz we're going to assume that callback types are always - # nullable and always have [TreatNonCallableAsNull] for now. - haveCallable = "${val}.isObject() && JS_ObjectIsCallable(cx, &${val}.toObject())" - if defaultValue is not None: - assert(isinstance(defaultValue, IDLNullValue)) - haveCallable = "${haveValue} && " + haveCallable - return ( - "if (%s) {\n" - " ${declName} = &${val}.toObject();\n" - "} else {\n" - " ${declName} = NULL;\n" - "}" % haveCallable, - CGGeneric("JSObject*"), None, isOptional) - - if type.isAny(): - assert not isEnforceRange and not isClamp - - if isMember: - raise TypeError("Can't handle member 'any'; need to sort out " - "rooting issues") - templateBody = "${declName} = ${val};" - templateBody = handleDefaultNull(templateBody, - "${declName} = JS::NullValue()") - return (templateBody, CGGeneric("JS::Value"), None, isOptional) - - if type.isObject(): - assert not isEnforceRange and not isClamp - - if isMember: - raise TypeError("Can't handle member 'object'; need to sort out " - "rooting issues") - template = wrapObjectTemplate("${declName} = &${val}.toObject();", - isDefinitelyObject, type, - "${declName} = NULL", - failureCode) - if type.nullable(): - declType = CGGeneric("JSObject*") - else: - declType = CGGeneric("NonNull<JSObject>") - return (template, declType, None, isOptional) - - if type.isDictionary(): - if failureCode is not None: - raise TypeError("Can't handle dictionaries when failureCode is not None") - # There are no nullable dictionaries - assert not type.nullable() - # All optional dictionaries always have default values, so we - # should be able to assume not isOptional here. - assert not isOptional - - typeName = CGDictionary.makeDictionaryName(type.inner, - descriptorProvider.workers) - actualTypeName = typeName - selfRef = "${declName}" - - declType = CGGeneric(actualTypeName) - - # If we're a member of something else, the const - # will come from the Optional or our container. - if not isMember: - declType = CGWrapper(declType, pre="const ") - selfRef = "const_cast<%s&>(%s)" % (typeName, selfRef) - - # We do manual default value handling here, because we - # actually do want a jsval, and we only handle null anyway - if defaultValue is not None: - assert(isinstance(defaultValue, IDLNullValue)) - val = "(${haveValue}) ? ${val} : JSVAL_NULL" - else: - val = "${val}" - - template = ("if (!%s.Init(cx, %s)) {\n" - " return false;\n" - "}" % (selfRef, val)) - - return (template, declType, None, False) - - if not type.isPrimitive(): - raise TypeError("Need conversion for argument type '%s'" % str(type)) - - typeName = builtinNames[type.tag()] - - conversionBehavior = "eDefault" - if isEnforceRange: - conversionBehavior = "eEnforceRange" - elif isClamp: - conversionBehavior = "eClamp" - - if type.nullable(): - dataLoc = "${declName}.SetValue()" - nullCondition = "${val}.isNullOrUndefined()" - if defaultValue is not None and isinstance(defaultValue, IDLNullValue): - nullCondition = "!(${haveValue}) || " + nullCondition - template = ( - "if (%s) {\n" - " ${declName}.SetNull();\n" - "} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n" - " return false;\n" - "}" % (nullCondition, typeName, conversionBehavior, dataLoc)) - declType = CGGeneric("Nullable<" + typeName + ">") - else: - assert(defaultValue is None or - not isinstance(defaultValue, IDLNullValue)) - dataLoc = "${declName}" - template = ( - "if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n" - " return false;\n" - "}" % (typeName, conversionBehavior, dataLoc)) - declType = CGGeneric(typeName) - if (defaultValue is not None and - # We already handled IDLNullValue, so just deal with the other ones - not isinstance(defaultValue, IDLNullValue)): - tag = defaultValue.type.tag() - if tag in numericTags: - defaultStr = defaultValue.value - else: - assert(tag == IDLType.Tags.bool) - defaultStr = toStringBool(defaultValue.value) - template = CGWrapper(CGIndenter(CGGeneric(template)), - pre="if (${haveValue}) {\n", - post=("\n" - "} else {\n" - " %s = %s;\n" - "}" % (dataLoc, defaultStr))).define() - - return (template, declType, None, isOptional) - -def instantiateJSToNativeConversionTemplate(templateTuple, replacements, - argcAndIndex=None): - """ - Take a tuple as returned by getJSToNativeConversionTemplate and a set of - replacements as required by the strings in such a tuple, and generate code - to convert into stack C++ types. - - If argcAndIndex is not None it must be a dict that can be used to - replace ${argc} and ${index}, where ${index} is the index of this - argument (0-based) and ${argc} is the total number of arguments. - """ - (templateBody, declType, holderType, dealWithOptional) = templateTuple - - if dealWithOptional and argcAndIndex is None: - raise TypeError("Have to deal with optional things, but don't know how") - if argcAndIndex is not None and declType is None: - raise TypeError("Need to predeclare optional things, so they will be " - "outside the check for big enough arg count!"); - - result = CGList([], "\n") - # Make a copy of "replacements" since we may be about to start modifying it - replacements = dict(replacements) - originalHolderName = replacements["holderName"] - if holderType is not None: - if dealWithOptional: - replacements["holderName"] = ( - "const_cast< %s & >(%s.Value())" % - (holderType.define(), originalHolderName)) - mutableHolderType = CGWrapper(holderType, pre="Optional< ", post=" >") - holderType = CGWrapper(mutableHolderType, pre="const ") - result.append( - CGList([holderType, CGGeneric(" "), - CGGeneric(originalHolderName), - CGGeneric(";")])) - - originalDeclName = replacements["declName"] - if declType is not None: - if dealWithOptional: - replacements["declName"] = ( - "const_cast< %s & >(%s.Value())" % - (declType.define(), originalDeclName)) - mutableDeclType = CGWrapper(declType, pre="Optional< ", post=" >") - declType = CGWrapper(mutableDeclType, pre="const ") - result.append( - CGList([declType, CGGeneric(" "), - CGGeneric(originalDeclName), - CGGeneric(";")])) - - conversion = CGGeneric( - string.Template(templateBody).substitute(replacements) - ) - - if argcAndIndex is not None: - if dealWithOptional: - declConstruct = CGIndenter( - CGGeneric("const_cast< %s &>(%s).Construct();" % - (mutableDeclType.define(), originalDeclName))) - if holderType is not None: - holderConstruct = CGIndenter( - CGGeneric("const_cast< %s &>(%s).Construct();" % - (mutableHolderType.define(), originalHolderName))) - else: - holderConstruct = None - else: - declConstruct = None - holderConstruct = None - - conversion = CGList( - [CGGeneric( - string.Template("if (${index} < ${argc}) {").substitute( - argcAndIndex - )), - declConstruct, - holderConstruct, - CGIndenter(conversion), - CGGeneric("}")], - "\n") - - result.append(conversion) - # Add an empty CGGeneric to get an extra newline after the argument - # conversion. - result.append(CGGeneric("")) - return result; - -def convertConstIDLValueToJSVal(value): - if isinstance(value, IDLNullValue): - return "JSVAL_NULL" - tag = value.type.tag() - if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16, - IDLType.Tags.uint16, IDLType.Tags.int32]: - return "INT_TO_JSVAL(%s)" % (value.value) - if tag == IDLType.Tags.uint32: - return "UINT_TO_JSVAL(%s)" % (value.value) - if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]: - return "DOUBLE_TO_JSVAL(%s)" % (value.value) - if tag == IDLType.Tags.bool: - return "JSVAL_TRUE" if value.value else "JSVAL_FALSE" - if tag in [IDLType.Tags.float, IDLType.Tags.double]: - return "DOUBLE_TO_JSVAL(%s)" % (value.value) - raise TypeError("Const value of unhandled type: " + value.type) - -class CGArgumentConverter(CGThing): - """ - A class that takes an IDL argument object, its index in the - argument list, and the argv and argc strings and generates code to - unwrap the argument to the right native type. - """ - def __init__(self, argument, index, argv, argc, descriptorProvider, - invalidEnumValueFatal=True): - CGThing.__init__(self) - self.argument = argument - if argument.variadic: - raise TypeError("We don't support variadic arguments yet " + - str(argument.location)) - assert(not argument.defaultValue or argument.optional) - - replacer = { - "index" : index, - "argc" : argc, - "argv" : argv - } - self.replacementVariables = { - "declName" : "arg%d" % index, - "holderName" : ("arg%d" % index) + "_holder" - } - self.replacementVariables["val"] = string.Template( - "${argv}[${index}]" - ).substitute(replacer) - self.replacementVariables["valPtr"] = ( - "&" + self.replacementVariables["val"]) - if argument.defaultValue: - self.replacementVariables["haveValue"] = string.Template( - "${index} < ${argc}").substitute(replacer) - self.descriptorProvider = descriptorProvider - if self.argument.optional and not self.argument.defaultValue: - self.argcAndIndex = replacer - else: - self.argcAndIndex = None - self.invalidEnumValueFatal = invalidEnumValueFatal - - def define(self): - return instantiateJSToNativeConversionTemplate( - getJSToNativeConversionTemplate(self.argument.type, - self.descriptorProvider, - isOptional=(self.argcAndIndex is not None), - invalidEnumValueFatal=self.invalidEnumValueFatal, - defaultValue=self.argument.defaultValue, - treatNullAs=self.argument.treatNullAs, - treatUndefinedAs=self.argument.treatUndefinedAs, - isEnforceRange=self.argument.enforceRange, - isClamp=self.argument.clamp), - self.replacementVariables, - self.argcAndIndex).define() - -def getWrapTemplateForType(type, descriptorProvider, result, successCode, - isCreator): - """ - Reflect a C++ value stored in "result", of IDL type "type" into JS. The - "successCode" is the code to run once we have successfully done the - conversion. The resulting string should be used with string.Template, it - needs the following keys when substituting: jsvalPtr/jsvalRef/obj. - - Returns (templateString, infallibility of conversion template) - """ - haveSuccessCode = successCode is not None - if not haveSuccessCode: - successCode = "return true;" - - def setValue(value, callWrapValue=False): - """ - Returns the code to set the jsval to value. If "callWrapValue" is true - JS_WrapValue will be called on the jsval. - """ - if not callWrapValue: - tail = successCode - elif haveSuccessCode: - tail = ("if (!JS_WrapValue(cx, ${jsvalPtr})) {\n" + - " return false;\n" + - "}\n" + - successCode) - else: - tail = "return JS_WrapValue(cx, ${jsvalPtr});" - return ("${jsvalRef} = %s;\n" + - tail) % (value) - - def wrapAndSetPtr(wrapCall, failureCode=None): - """ - Returns the code to set the jsval by calling "wrapCall". "failureCode" - is the code to run if calling "wrapCall" fails - """ - if failureCode is None: - if not haveSuccessCode: - return "return " + wrapCall + ";" - failureCode = "return false;" - str = ("if (!%s) {\n" + - CGIndenter(CGGeneric(failureCode)).define() + "\n" + - "}\n" + - successCode) % (wrapCall) - return str - - if type is None or type.isVoid(): - return (setValue("JSVAL_VOID"), True) - - if type.isArray(): - raise TypeError("Can't handle array return values yet") - - if type.isSequence(): - if type.nullable(): - # Nullable sequences are Nullable< nsTArray<T> > - (recTemplate, recInfall) = getWrapTemplateForType(type.inner, descriptorProvider, - "%s.Value()" % result, successCode, - isCreator) - return (""" -if (%s.IsNull()) { -%s -} -%s""" % (result, CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define(), recTemplate), recInfall) - - # Now do non-nullable sequences. We use setting the element - # in the array as our succcess code because when we succeed in - # wrapping that's what we should do. - innerTemplate = wrapForType( - type.inner, descriptorProvider, - { - 'result' : "%s[i]" % result, - 'successCode': ("if (!JS_DefineElement(cx, returnArray, i, tmp,\n" - " NULL, NULL, JSPROP_ENUMERATE)) {\n" - " return false;\n" - "}"), - 'jsvalRef': "tmp", - 'jsvalPtr': "&tmp", - 'isCreator': isCreator - } - ) - innerTemplate = CGIndenter(CGGeneric(innerTemplate)).define() - return ((""" -uint32_t length = %s.Length(); -JSObject *returnArray = JS_NewArrayObject(cx, length, NULL); -if (!returnArray) { - return false; -} -jsval tmp; -for (uint32_t i = 0; i < length; ++i) { -%s -}\n""" % (result, innerTemplate)) + setValue("JS::ObjectValue(*returnArray)"), False) - - if type.isGeckoInterface(): - descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name) - if type.nullable(): - wrappingCode = ("if (!%s) {\n" % (result) + - CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" + - "}\n") - else: - wrappingCode = "" - if (not descriptor.interface.isExternal() and - not descriptor.interface.isCallback()): - if descriptor.wrapperCache: - wrapMethod = "WrapNewBindingObject" - else: - if not isCreator: - raise MethodNotCreatorError(descriptor.interface.identifier.name) - wrapMethod = "WrapNewBindingNonWrapperCachedObject" - wrap = "%s(cx, ${obj}, %s, ${jsvalPtr})" % (wrapMethod, result) - # We don't support prefable stuff in workers. - assert(not descriptor.prefable or not descriptor.workers) - if not descriptor.prefable: - # Non-prefable bindings can only fail to wrap as a new-binding object - # if they already threw an exception. Same thing for - # non-prefable bindings. - failed = ("MOZ_ASSERT(JS_IsExceptionPending(cx));\n" + - "return false;") - else: - if descriptor.notflattened: - raise TypeError("%s is prefable but not flattened; " - "fallback won't work correctly" % - descriptor.interface.identifier.name) - # Try old-style wrapping for bindings which might be preffed off. - failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalPtr})" % result) - wrappingCode += wrapAndSetPtr(wrap, failed) - else: - if descriptor.notflattened: - getIID = "&NS_GET_IID(%s), " % descriptor.nativeType - else: - getIID = "" - wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID) - wrappingCode += wrapAndSetPtr(wrap) - return (wrappingCode, False) - - if type.isString(): - if type.nullable(): - return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalPtr})" % result), False) - else: - return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalPtr})" % result), False) - - if type.isEnum(): - if type.nullable(): - raise TypeError("We don't support nullable enumerated return types " - "yet") - return ("""MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s)); -JSString* %(resultStr)s = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length); -if (!%(resultStr)s) { - return false; -} -""" % { "result" : result, - "resultStr" : result + "_str", - "strings" : type.inner.identifier.name + "Values::strings" } + - setValue("JS::StringValue(%s_str)" % result), False) - - if type.isCallback(): - assert not type.isInterface() - # XXXbz we're going to assume that callback types are always - # nullable and always have [TreatNonCallableAsNull] for now. - # See comments in WrapNewBindingObject explaining why we need - # to wrap here. - # NB: setValue(..., True) calls JS_WrapValue(), so is fallible - return (setValue("JS::ObjectOrNullValue(%s)" % result, True), False) - - if type.tag() == IDLType.Tags.any: - # See comments in WrapNewBindingObject explaining why we need - # to wrap here. - # NB: setValue(..., True) calls JS_WrapValue(), so is fallible - return (setValue(result, True), False) - - if type.isObject() or type.isSpiderMonkeyInterface(): - # See comments in WrapNewBindingObject explaining why we need - # to wrap here. - if type.nullable(): - toValue = "JS::ObjectOrNullValue(%s)" - else: - toValue = "JS::ObjectValue(*%s)" - # NB: setValue(..., True) calls JS_WrapValue(), so is fallible - return (setValue(toValue % result, True), False) - - if not type.isPrimitive(): - raise TypeError("Need to learn to wrap %s" % type) - - if type.nullable(): - (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider, - "%s.Value()" % result, successCode, - isCreator) - return ("if (%s.IsNull()) {\n" % result + - CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" + - "}\n" + recTemplate, recInfal) - - tag = type.tag() - - if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16, - IDLType.Tags.uint16, IDLType.Tags.int32]: - return (setValue("INT_TO_JSVAL(int32_t(%s))" % result), True) - - elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float, - IDLType.Tags.double]: - # XXXbz will cast to double do the "even significand" thing that webidl - # calls for for 64-bit ints? Do we care? - return (setValue("JS_NumberValue(double(%s))" % result), True) - - elif tag == IDLType.Tags.uint32: - return (setValue("UINT_TO_JSVAL(%s)" % result), True) - - elif tag == IDLType.Tags.bool: - return (setValue("BOOLEAN_TO_JSVAL(%s)" % result), True) - - else: - raise TypeError("Need to learn to wrap primitive: %s" % type) - -def wrapForType(type, descriptorProvider, templateValues): - """ - Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict - that should contain: - - * 'jsvalRef': a C++ reference to the jsval in which to store the result of - the conversion - * 'jsvalPtr': a C++ pointer to the jsval in which to store the result of - the conversion - * 'obj' (optional): the name of the variable that contains the JSObject to - use as a scope when wrapping, if not supplied 'obj' - will be used as the name - * 'result' (optional): the name of the variable in which the C++ value is - stored, if not supplied 'result' will be used as - the name - * 'successCode' (optional): the code to run once we have successfully done - the conversion, if not supplied 'return true;' - will be used as the code - * 'isCreator' (optional): If true, we're wrapping for the return value of - a [Creator] method. Assumed false if not set. - """ - wrap = getWrapTemplateForType(type, descriptorProvider, - templateValues.get('result', 'result'), - templateValues.get('successCode', None), - templateValues.get('isCreator', False))[0] - - defaultValues = {'obj': 'obj'} - return string.Template(wrap).substitute(defaultValues, **templateValues) - -def infallibleForMember(member, type, descriptorProvider): - """ - Determine the fallibility of changing a C++ value of IDL type "type" into - JS for the given attribute. Apart from isCreator, all the defaults are used, - since the fallbility does not change based on the boolean values, - and the template will be discarded. - - CURRENT ASSUMPTIONS: - We assume that successCode for wrapping up return values cannot contain - failure conditions. - """ - return getWrapTemplateForType(type, descriptorProvider, 'result', None,\ - memberIsCreator(member))[1] - -def typeNeedsCx(type, retVal=False): - if type is None: - return False - if type.nullable(): - type = type.inner - if type.isSequence() or type.isArray(): - type = type.inner - if type.isUnion(): - return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes) - if retVal and type.isSpiderMonkeyInterface(): - return True - return type.isCallback() or type.isAny() or type.isObject() - -# Returns a tuple consisting of a CGThing containing the type of the return -# value, or None if there is no need for a return value, and a boolean signaling -# whether the return value is passed in an out parameter. -def getRetvalDeclarationForType(returnType, descriptorProvider, - resultAlreadyAddRefed): - if returnType is None or returnType.isVoid(): - # Nothing to declare - return None, False - if returnType.isPrimitive() and returnType.tag() in builtinNames: - result = CGGeneric(builtinNames[returnType.tag()]) - if returnType.nullable(): - result = CGWrapper(result, pre="Nullable<", post=">") - return result, False - if returnType.isString(): - return CGGeneric("nsString"), True - if returnType.isEnum(): - if returnType.nullable(): - raise TypeError("We don't support nullable enum return values") - return CGGeneric(returnType.inner.identifier.name), False - if returnType.isGeckoInterface(): - result = CGGeneric(descriptorProvider.getDescriptor( - returnType.unroll().inner.identifier.name).nativeType) - if resultAlreadyAddRefed: - result = CGWrapper(result, pre="nsRefPtr<", post=">") - else: - result = CGWrapper(result, post="*") - return result, False - if returnType.isCallback(): - # XXXbz we're going to assume that callback types are always - # nullable for now. - return CGGeneric("JSObject*"), False - if returnType.isAny(): - return CGGeneric("JS::Value"), False - if returnType.isObject() or returnType.isSpiderMonkeyInterface(): - return CGGeneric("JSObject*"), False - if returnType.isSequence(): - nullable = returnType.nullable() - if nullable: - returnType = returnType.inner - # If our result is already addrefed, use the right type in the - # sequence argument here. - (result, _) = getRetvalDeclarationForType(returnType.inner, - descriptorProvider, - resultAlreadyAddRefed) - result = CGWrapper(result, pre="nsTArray< ", post=" >") - if nullable: - result = CGWrapper(result, pre="Nullable< ", post=" >") - return result, True - raise TypeError("Don't know how to declare return value for %s" % - returnType) - -def isResultAlreadyAddRefed(descriptor, extendedAttributes): - # Default to already_AddRefed on the main thread, raw pointer in workers - return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes - -class CGCallGenerator(CGThing): - """ - A class to generate an actual call to a C++ object. Assumes that the C++ - object is stored in a variable whose name is given by the |object| argument. - - errorReport should be a CGThing for an error report or None if no - error reporting is needed. - """ - def __init__(self, errorReport, arguments, argsPre, returnType, - extendedAttributes, descriptorProvider, nativeMethodName, - static, object="self", declareResult=True): - CGThing.__init__(self) - - assert errorReport is None or isinstance(errorReport, CGThing) - - isFallible = errorReport is not None - - resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider, - extendedAttributes) - (result, resultOutParam) = getRetvalDeclarationForType(returnType, - descriptorProvider, - resultAlreadyAddRefed) - - args = CGList([CGGeneric(arg) for arg in argsPre], ", ") - for (a, name) in arguments: - # This is a workaround for a bug in Apple's clang. - if a.type.isObject() and not a.type.nullable() and not a.optional: - name = "(JSObject&)" + name - args.append(CGGeneric(name)) - - # Return values that go in outparams go here - if resultOutParam: - args.append(CGGeneric("result")) - if isFallible: - args.append(CGGeneric("rv")) - - needsCx = (typeNeedsCx(returnType, True) or - any(typeNeedsCx(a.type) for (a, _) in arguments) or - 'implicitJSContext' in extendedAttributes) - - if not "cx" in argsPre and needsCx: - args.prepend(CGGeneric("cx")) - - # Build up our actual call - self.cgRoot = CGList([], "\n") - - call = CGGeneric(nativeMethodName) - if static: - call = CGWrapper(call, pre="%s::" % descriptorProvider.nativeType) - else: - call = CGWrapper(call, pre="%s->" % object) - call = CGList([call, CGWrapper(args, pre="(", post=");")]) - if result is not None: - if declareResult: - result = CGWrapper(result, post=" result;") - self.cgRoot.prepend(result) - if not resultOutParam: - call = CGWrapper(call, pre="result = ") - - call = CGWrapper(call) - self.cgRoot.append(call) - - if isFallible: - self.cgRoot.prepend(CGGeneric("ErrorResult rv;")) - self.cgRoot.append(CGGeneric("if (rv.Failed()) {")) - self.cgRoot.append(CGIndenter(errorReport)) - self.cgRoot.append(CGGeneric("}")) - - def define(self): - return self.cgRoot.define() - -class MethodNotCreatorError(Exception): - def __init__(self, typename): - self.typename = typename - -class CGPerSignatureCall(CGThing): - """ - This class handles the guts of generating code for a particular - call signature. A call signature consists of four things: - - 1) A return type, which can be None to indicate that there is no - actual return value (e.g. this is an attribute setter) or an - IDLType if there's an IDL type involved (including |void|). - 2) An argument list, which is allowed to be empty. - 3) A name of a native method to call. - 4) Whether or not this method is static. - - We also need to know whether this is a method or a getter/setter - to do error reporting correctly. - - The idlNode parameter can be either a method or an attr. We can query - |idlNode.identifier| in both cases, so we can be agnostic between the two. - """ - # XXXbz For now each entry in the argument list is either an - # IDLArgument or a FakeArgument, but longer-term we may want to - # have ways of flagging things like JSContext* or optional_argc in - # there. - - def __init__(self, returnType, argsPre, arguments, nativeMethodName, static, - descriptor, idlNode, argConversionStartsAt=0, - getter=False, setter=False): - CGThing.__init__(self) - self.returnType = returnType - self.descriptor = descriptor - self.idlNode = idlNode - self.extendedAttributes = descriptor.getExtendedAttributes(idlNode, - getter=getter, - setter=setter) - self.argsPre = argsPre - self.arguments = arguments - self.argCount = len(arguments) - if self.argCount > argConversionStartsAt: - # Insert our argv in there - cgThings = [CGGeneric(self.getArgvDecl())] - else: - cgThings = [] - cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(), - self.getArgc(), self.descriptor, - invalidEnumValueFatal=not setter) for - i in range(argConversionStartsAt, self.argCount)]) - - cgThings.append(CGCallGenerator( - self.getErrorReport() if self.isFallible() else None, - self.getArguments(), self.argsPre, returnType, - self.extendedAttributes, descriptor, nativeMethodName, - static)) - self.cgRoot = CGList(cgThings, "\n") - - def getArgv(self): - return "argv" if self.argCount > 0 else "" - def getArgvDecl(self): - return "\nJS::Value* argv = JS_ARGV(cx, vp);\n" - def getArgc(self): - return "argc" - def getArguments(self): - return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)] - - def isFallible(self): - return not 'infallible' in self.extendedAttributes - - def wrap_return_value(self): - isCreator = memberIsCreator(self.idlNode) - if isCreator: - # We better be returning addrefed things! - assert(isResultAlreadyAddRefed(self.descriptor, - self.extendedAttributes) or - # Workers use raw pointers for new-object return - # values or something - self.descriptor.workers) - - resultTemplateValues = { 'jsvalRef': '*vp', 'jsvalPtr': 'vp', - 'isCreator': isCreator} - try: - return wrapForType(self.returnType, self.descriptor, - resultTemplateValues) - except MethodNotCreatorError, err: - assert not isCreator - raise TypeError("%s being returned from non-creator method or property %s.%s" % - (err.typename, - self.descriptor.interface.identifier.name, - self.idlNode.identifier.name)) - - def getErrorReport(self): - return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");' - % (toStringBool(not self.descriptor.workers), - self.descriptor.interface.identifier.name, - self.idlNode.identifier.name)) - - def define(self): - return (self.cgRoot.define() + "\n" + self.wrap_return_value()) - -class CGSwitch(CGList): - """ - A class to generate code for a switch statement. - - Takes three constructor arguments: an expression, a list of cases, - and an optional default. - - Each case is a CGCase. The default is a CGThing for the body of - the default case, if any. - """ - def __init__(self, expression, cases, default=None): - CGList.__init__(self, [CGIndenter(c) for c in cases], "\n") - self.prepend(CGWrapper(CGGeneric(expression), - pre="switch (", post=") {")); - if default is not None: - self.append( - CGIndenter( - CGWrapper( - CGIndenter(default), - pre="default: {\n", - post="\n break;\n}" - ) - ) - ) - - self.append(CGGeneric("}")) - -class CGCase(CGList): - """ - A class to generate code for a case statement. - - Takes three constructor arguments: an expression, a CGThing for - the body (allowed to be None if there is no body), and an optional - argument (defaulting to False) for whether to fall through. - """ - def __init__(self, expression, body, fallThrough=False): - CGList.__init__(self, [], "\n") - self.append(CGWrapper(CGGeneric(expression), pre="case ", post=": {")) - bodyList = CGList([body], "\n") - if fallThrough: - bodyList.append(CGGeneric("/* Fall through */")) - else: - bodyList.append(CGGeneric("break;")) - self.append(CGIndenter(bodyList)); - self.append(CGGeneric("}")) - -class CGMethodCall(CGThing): - """ - A class to generate selection of a method signature from a set of - signatures and generation of a call to that signature. - """ - def __init__(self, argsPre, nativeMethodName, static, descriptor, method): - CGThing.__init__(self) - - methodName = '"%s.%s"' % (descriptor.interface.identifier.name, method.identifier.name) - - def requiredArgCount(signature): - arguments = signature[1] - if len(arguments) == 0: - return 0 - requiredArgs = len(arguments) - while requiredArgs and arguments[requiredArgs-1].optional: - requiredArgs -= 1 - return requiredArgs - - def getPerSignatureCall(signature, argConversionStartsAt=0): - return CGPerSignatureCall(signature[0], argsPre, signature[1], - nativeMethodName, static, descriptor, - method, argConversionStartsAt) - - - signatures = method.signatures() - if len(signatures) == 1: - # Special case: we can just do a per-signature method call - # here for our one signature and not worry about switching - # on anything. - signature = signatures[0] - self.cgRoot = CGList([ CGIndenter(getPerSignatureCall(signature)) ]) - requiredArgs = requiredArgCount(signature) - - - if requiredArgs > 0: - code = ( - "if (argc < %d) {\n" - " return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n" - "}" % (requiredArgs, methodName)) - self.cgRoot.prepend( - CGWrapper(CGIndenter(CGGeneric(code)), pre="\n", post="\n")) - return - - # Need to find the right overload - maxArgCount = method.maxArgCount - allowedArgCounts = method.allowedArgCounts - - argCountCases = [] - for argCount in allowedArgCounts: - possibleSignatures = method.signaturesForArgCount(argCount) - if len(possibleSignatures) == 1: - # easy case! - signature = possibleSignatures[0] - - # (possibly) important optimization: if signature[1] has > - # argCount arguments and signature[1][argCount] is optional and - # there is only one signature for argCount+1, then the - # signature for argCount+1 is just ourselves and we can fall - # through. - if (len(signature[1]) > argCount and - signature[1][argCount].optional and - (argCount+1) in allowedArgCounts and - len(method.signaturesForArgCount(argCount+1)) == 1): - argCountCases.append( - CGCase(str(argCount), None, True)) - else: - argCountCases.append( - CGCase(str(argCount), getPerSignatureCall(signature))) - continue - - distinguishingIndex = method.distinguishingIndexForArgCount(argCount) - - # We can't handle unions at the distinguishing index. - for (returnType, args) in possibleSignatures: - if args[distinguishingIndex].type.isUnion(): - raise TypeError("No support for unions as distinguishing " - "arguments yet: %s", - args[distinguishingIndex].location) - - # Convert all our arguments up to the distinguishing index. - # Doesn't matter which of the possible signatures we use, since - # they all have the same types up to that point; just use - # possibleSignatures[0] - caseBody = [CGGeneric("JS::Value* argv_start = JS_ARGV(cx, vp);")] - caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i], - i, "argv_start", "argc", - descriptor) for i in - range(0, distinguishingIndex) ]) - - # Select the right overload from our set. - distinguishingArg = "argv_start[%d]" % distinguishingIndex - - def pickFirstSignature(condition, filterLambda): - sigs = filter(filterLambda, possibleSignatures) - assert len(sigs) < 2 - if len(sigs) > 0: - if condition is None: - caseBody.append( - getPerSignatureCall(sigs[0], distinguishingIndex)) - else: - caseBody.append(CGGeneric("if (" + condition + ") {")) - caseBody.append(CGIndenter( - getPerSignatureCall(sigs[0], distinguishingIndex))) - caseBody.append(CGGeneric("}")) - return True - return False - - # First check for null or undefined - pickFirstSignature("%s.isNullOrUndefined()" % distinguishingArg, - lambda s: (s[1][distinguishingIndex].type.nullable() or - s[1][distinguishingIndex].type.isDictionary())) - - # Now check for distinguishingArg being an object that implements a - # non-callback interface. That includes typed arrays and - # arraybuffers. - interfacesSigs = [ - s for s in possibleSignatures - if (s[1][distinguishingIndex].type.isObject() or - s[1][distinguishingIndex].type.isNonCallbackInterface()) ] - # There might be more than one of these; we need to check - # which ones we unwrap to. - - if len(interfacesSigs) > 0: - # The spec says that we should check for "platform objects - # implementing an interface", but it's enough to guard on these - # being an object. The code for unwrapping non-callback - # interfaces and typed arrays will just bail out and move on to - # the next overload if the object fails to unwrap correctly. We - # could even not do the isObject() check up front here, but in - # cases where we have multiple object overloads it makes sense - # to do it only once instead of for each overload. That will - # also allow the unwrapping test to skip having to do codegen - # for the null-or-undefined case, which we already handled - # above. - caseBody.append(CGGeneric("if (%s.isObject()) {" % - (distinguishingArg))) - for sig in interfacesSigs: - caseBody.append(CGIndenter(CGGeneric("do {"))); - type = sig[1][distinguishingIndex].type - - # The argument at index distinguishingIndex can't possibly - # be unset here, because we've already checked that argc is - # large enough that we can examine this argument. - testCode = instantiateJSToNativeConversionTemplate( - getJSToNativeConversionTemplate(type, descriptor, - failureCode="break;", - isDefinitelyObject=True), - { - "declName" : "arg%d" % distinguishingIndex, - "holderName" : ("arg%d" % distinguishingIndex) + "_holder", - "val" : distinguishingArg - }) - - # Indent by 4, since we need to indent further than our "do" statement - caseBody.append(CGIndenter(testCode, 4)); - # If we got this far, we know we unwrapped to the right - # interface, so just do the call. Start conversion with - # distinguishingIndex + 1, since we already converted - # distinguishingIndex. - caseBody.append(CGIndenter( - getPerSignatureCall(sig, distinguishingIndex + 1), 4)) - caseBody.append(CGIndenter(CGGeneric("} while (0);"))) - - caseBody.append(CGGeneric("}")) - - # XXXbz Now we're supposed to check for distinguishingArg being - # an array or a platform object that supports indexed - # properties... skip that last for now. It's a bit of a pain. - pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject())" % - (distinguishingArg, distinguishingArg), - lambda s: - (s[1][distinguishingIndex].type.isArray() or - s[1][distinguishingIndex].type.isSequence() or - s[1][distinguishingIndex].type.isObject())) - - # Check for Date objects - # XXXbz Do we need to worry about security wrappers around the Date? - pickFirstSignature("%s.isObject() && JS_ObjectIsDate(cx, &%s.toObject())" % - (distinguishingArg, distinguishingArg), - lambda s: (s[1][distinguishingIndex].type.isDate() or - s[1][distinguishingIndex].type.isObject())) - - # Check for vanilla JS objects - # XXXbz Do we need to worry about security wrappers? - pickFirstSignature("%s.isObject() && !IsPlatformObject(cx, &%s.toObject())" % - (distinguishingArg, distinguishingArg), - lambda s: (s[1][distinguishingIndex].type.isCallback() or - s[1][distinguishingIndex].type.isCallbackInterface() or - s[1][distinguishingIndex].type.isDictionary() or - s[1][distinguishingIndex].type.isObject())) - - # The remaining cases are mutually exclusive. The - # pickFirstSignature calls are what change caseBody - # Check for strings or enums - if pickFirstSignature(None, - lambda s: (s[1][distinguishingIndex].type.isString() or - s[1][distinguishingIndex].type.isEnum())): - pass - # Check for primitives - elif pickFirstSignature(None, - lambda s: s[1][distinguishingIndex].type.isPrimitive()): - pass - # Check for "any" - elif pickFirstSignature(None, - lambda s: s[1][distinguishingIndex].type.isAny()): - pass - else: - # Just throw; we have no idea what we're supposed to - # do with this. - caseBody.append(CGGeneric("return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);" % - toStringBool(not descriptor.workers))) - - argCountCases.append(CGCase(str(argCount), - CGList(caseBody, "\n"))) - - overloadCGThings = [] - overloadCGThings.append( - CGGeneric("unsigned argcount = NS_MIN(argc, %du);" % - maxArgCount)) - overloadCGThings.append( - CGSwitch("argcount", - argCountCases, - CGGeneric("return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n" % methodName))) - overloadCGThings.append( - CGGeneric('MOZ_NOT_REACHED("We have an always-returning default case");\n' - 'return false;')) - self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings, "\n")), - pre="\n") - - def define(self): - return self.cgRoot.define() - -class CGGetterCall(CGPerSignatureCall): - """ - A class to generate a native object getter call for a particular IDL - getter. - """ - def __init__(self, returnType, nativeMethodName, descriptor, attr): - CGPerSignatureCall.__init__(self, returnType, [], [], - nativeMethodName, False, descriptor, - attr, getter=True) - -class FakeArgument(): - """ - A class that quacks like an IDLArgument. This is used to make - setters look like method calls or for special operations. - """ - def __init__(self, type, interfaceMember): - self.type = type - self.optional = False - self.variadic = False - self.defaultValue = None - self.treatNullAs = interfaceMember.treatNullAs - self.treatUndefinedAs = interfaceMember.treatUndefinedAs - self.enforceRange = False - self.clamp = False - -class CGSetterCall(CGPerSignatureCall): - """ - A class to generate a native object setter call for a particular IDL - setter. - """ - def __init__(self, argType, nativeMethodName, descriptor, attr): - CGPerSignatureCall.__init__(self, None, [], - [FakeArgument(argType, attr)], - nativeMethodName, False, descriptor, attr, - setter=True) - def wrap_return_value(self): - # We have no return value - return "\nreturn true;" - def getArgc(self): - return "1" - def getArgvDecl(self): - # We just get our stuff from our last arg no matter what - return "" - -class FakeCastableDescriptor(): - def __init__(self, descriptor): - self.castable = True - self.workers = descriptor.workers - self.nativeType = descriptor.nativeType - self.name = descriptor.name - self.hasXPConnectImpls = descriptor.hasXPConnectImpls - -class CGAbstractBindingMethod(CGAbstractStaticMethod): - """ - Common class to generate the JSNatives for all our methods, getters, and - setters. This will generate the function declaration and unwrap the - |this| object. Subclasses are expected to override the generate_code - function to do the rest of the work. This function should return a - CGThing which is already properly indented. - """ - def __init__(self, descriptor, name, args, unwrapFailureCode=None): - CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args) - - if unwrapFailureCode is None: - self.unwrapFailureCode = ("return Throw<%s>(cx, rv);" % - toStringBool(not descriptor.workers)) - else: - self.unwrapFailureCode = unwrapFailureCode - - def definition_body(self): - # Our descriptor might claim that we're not castable, simply because - # we're someone's consequential interface. But for this-unwrapping, we - # know that we're the real deal. So fake a descriptor here for - # consumption by FailureFatalCastableObjectUnwrapper. - unwrapThis = CGIndenter(CGGeneric( - str(CastableObjectUnwrapper( - FakeCastableDescriptor(self.descriptor), - "obj", "self", self.unwrapFailureCode)))) - return CGList([ self.getThis(), unwrapThis, - self.generate_code() ], "\n").define() - - def getThis(self): - return CGIndenter( - CGGeneric("js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));\n" - "if (!obj) {\n" - " return false;\n" - "}\n" - "\n" - "%s* self;" % self.descriptor.nativeType)) - - def generate_code(self): - assert(False) # Override me - -def MakeNativeName(name): - return name[0].upper() + name[1:] - -class CGGenericMethod(CGAbstractBindingMethod): - """ - A class for generating the C++ code for an IDL method.. - """ - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'), - Argument('JS::Value*', 'vp')] - CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod', args) - - def generate_code(self): - return CGIndenter(CGGeneric( - "const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "JSJitMethodOp method = (JSJitMethodOp)info->op;\n" - "return method(cx, obj, self, argc, vp);")) - -class CGSpecializedMethod(CGAbstractStaticMethod): - """ - A class for generating the C++ code for a specialized method that the JIT - can call with lower overhead. - """ - def __init__(self, descriptor, method): - self.method = method - name = method.identifier.name - args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'), - Argument('%s*' % descriptor.nativeType, 'self'), - Argument('unsigned', 'argc'), Argument('JS::Value*', 'vp')] - CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args) - - def definition_body(self): - name = self.method.identifier.name - nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name)) - return CGMethodCall([], nativeName, self.method.isStatic(), - self.descriptor, self.method).define() - -class CGGenericGetter(CGAbstractBindingMethod): - """ - A class for generating the C++ code for an IDL attribute getter. - """ - def __init__(self, descriptor, lenientThis=False): - args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'), - Argument('JS::Value*', 'vp')] - if lenientThis: - name = "genericLenientGetter" - unwrapFailureCode = ( - "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n" - "JS_SET_RVAL(cx, vp, JS::UndefinedValue());\n" - "return true;") - else: - name = "genericGetter" - unwrapFailureCode = None - CGAbstractBindingMethod.__init__(self, descriptor, name, args, - unwrapFailureCode) - - def generate_code(self): - return CGIndenter(CGGeneric( - "const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "JSJitPropertyOp getter = info->op;\n" - "return getter(cx, obj, self, vp);")) - -class CGSpecializedGetter(CGAbstractStaticMethod): - """ - A class for generating the code for a specialized attribute getter - that the JIT can call with lower overhead. - """ - def __init__(self, descriptor, attr): - self.attr = attr - name = 'get_' + attr.identifier.name - args = [ Argument('JSContext*', 'cx'), - Argument('JSHandleObject', 'obj'), - Argument('%s*' % descriptor.nativeType, 'self'), - Argument('JS::Value*', 'vp') ] - CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args) - - def definition_body(self): - name = self.attr.identifier.name - nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name)) - # resultOutParam does not depend on whether resultAlreadyAddRefed is set - (_, resultOutParam) = getRetvalDeclarationForType(self.attr.type, - self.descriptor, - False) - infallible = ('infallible' in - self.descriptor.getExtendedAttributes(self.attr, - getter=True)) - if resultOutParam or self.attr.type.nullable() or not infallible: - nativeName = "Get" + nativeName - return CGIndenter(CGGetterCall(self.attr.type, nativeName, - self.descriptor, self.attr)).define() - -class CGGenericSetter(CGAbstractBindingMethod): - """ - A class for generating the C++ code for an IDL attribute setter. - """ - def __init__(self, descriptor, lenientThis=False): - args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'), - Argument('JS::Value*', 'vp')] - if lenientThis: - name = "genericLenientSetter" - unwrapFailureCode = ( - "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n" - "return true;") - else: - name = "genericSetter" - unwrapFailureCode = None - CGAbstractBindingMethod.__init__(self, descriptor, name, args, - unwrapFailureCode) - - def generate_code(self): - return CGIndenter(CGGeneric( - "JS::Value* argv = JS_ARGV(cx, vp);\n" - "JS::Value undef = JS::UndefinedValue();\n" - "if (argc == 0) {\n" - " argv = &undef;\n" - "}\n" - "const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "JSJitPropertyOp setter = info->op;\n" - "if (!setter(cx, obj, self, argv)) {\n" - " return false;\n" - "}\n" - "*vp = JSVAL_VOID;\n" - "return true;")) - -class CGSpecializedSetter(CGAbstractStaticMethod): - """ - A class for generating the code for a specialized attribute setter - that the JIT can call with lower overhead. - """ - def __init__(self, descriptor, attr): - self.attr = attr - name = 'set_' + attr.identifier.name - args = [ Argument('JSContext*', 'cx'), - Argument('JSHandleObject', 'obj'), - Argument('%s*' % descriptor.nativeType, 'self'), - Argument('JS::Value*', 'argv')] - CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args) - - def definition_body(self): - name = self.attr.identifier.name - nativeName = "Set" + MakeNativeName(self.descriptor.binaryNames.get(name, name)) - return CGIndenter(CGSetterCall(self.attr.type, nativeName, - self.descriptor, self.attr)).define() - -def memberIsCreator(member): - return member.getExtendedAttribute("Creator") is not None - -class CGMemberJITInfo(CGThing): - """ - A class for generating the JITInfo for a property that points to - our specialized getter and setter. - """ - def __init__(self, descriptor, member): - self.member = member - self.descriptor = descriptor - - def declare(self): - return "" - - def defineJitInfo(self, infoName, opName, infallible): - protoID = "prototypes::id::%s" % self.descriptor.name - depth = "PrototypeTraits<%s>::Depth" % protoID - failstr = "true" if infallible else "false" - return ("\n" - "const JSJitInfo %s = {\n" - " %s,\n" - " %s,\n" - " %s,\n" - " %s, /* isInfallible. False in setters. */\n" - " false /* isConstant. Only relevant for getters. */\n" - "};\n" % (infoName, opName, protoID, depth, failstr)) - - def define(self): - if self.member.isAttr(): - getterinfo = ("%s_getterinfo" % self.member.identifier.name) - getter = ("(JSJitPropertyOp)get_%s" % self.member.identifier.name) - getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True) - getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor) - result = self.defineJitInfo(getterinfo, getter, getterinfal) - if not self.member.readonly: - setterinfo = ("%s_setterinfo" % self.member.identifier.name) - setter = ("(JSJitPropertyOp)set_%s" % self.member.identifier.name) - # Setters are always fallible, since they have to do a typed unwrap. - result += self.defineJitInfo(setterinfo, setter, False) - return result - if self.member.isMethod(): - methodinfo = ("%s_methodinfo" % self.member.identifier.name) - # Actually a JSJitMethodOp, but JSJitPropertyOp by struct definition. - method = ("(JSJitPropertyOp)%s" % self.member.identifier.name) - - # Methods are infallible if they are infallible, have no arguments - # to unwrap, and have a return type that's infallible to wrap up for - # return. - methodInfal = False - sigs = self.member.signatures() - if len(sigs) == 1: - # Don't handle overloading. If there's more than one signature, - # one of them must take arguments. - sig = sigs[0] - if len(sig[1]) == 0 and infallibleForMember(self.member, sig[0], self.descriptor): - # No arguments and infallible return boxing - methodInfal = True - - result = self.defineJitInfo(methodinfo, method, methodInfal) - return result - raise TypeError("Illegal member type to CGPropertyJITInfo") - -def getEnumValueName(value): - # Some enum values can be empty strings. Others might have weird - # characters in them. Deal with the former by returning "_empty", - # deal with possible name collisions from that by throwing if the - # enum value is actually "_empty", and throw on any value - # containing chars other than [a-z] or '-' for now. Replace '-' with '_'. - value = value.replace('-', '_') - if value == "_empty": - raise SyntaxError('"_empty" is not an IDL enum value we support yet') - if value == "": - return "_empty" - if not re.match("^[a-z_]+$", value): - raise SyntaxError('Enum value "' + value + '" contains characters ' - 'outside [a-z_]') - return MakeNativeName(value) - -class CGEnum(CGThing): - def __init__(self, enum): - CGThing.__init__(self) - self.enum = enum - - def declare(self): - return """ - enum valuelist { - %s - }; - - extern const EnumEntry strings[%d]; -""" % (",\n ".join(map(getEnumValueName, self.enum.values())), - len(self.enum.values()) + 1) - - def define(self): - return """ - const EnumEntry strings[%d] = { - %s, - { NULL, 0 } - }; -""" % (len(self.enum.values()) + 1, - ",\n ".join(['{"' + val + '", ' + str(len(val)) + '}' for val in self.enum.values()])) - -def getUnionAccessorSignatureType(type, descriptorProvider): - """ - Returns the types that are used in the getter and setter signatures for - union types - """ - if type.isArray(): - raise TypeError("Can't handle array arguments yet") - - if type.isSequence(): - nullable = type.nullable(); - if nullable: - type = type.inner.inner - else: - type = type.inner - (elementTemplate, elementDeclType, - elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate( - type, descriptorProvider, isSequenceMember=True) - typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >&") - if nullable: - typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&") - - return typeName - - if type.isUnion(): - typeName = CGGeneric(type.name) - if type.nullable(): - typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&") - - return typeName - - if type.isGeckoInterface(): - descriptor = descriptorProvider.getDescriptor( - type.unroll().inner.identifier.name) - typeName = CGGeneric(descriptor.nativeType) - # Allow null pointers for nullable types and old-binding classes - if type.nullable() or type.unroll().inner.isExternal(): - typeName = CGWrapper(typeName, post="*") - else: - typeName = CGWrapper(typeName, post="&") - return typeName - - if type.isSpiderMonkeyInterface(): - typeName = CGGeneric(type.name) - if type.nullable(): - typeName = CGWrapper(typeName, post="*") - else: - typeName = CGWrapper(typeName, post="&") - return typeName - - if type.isString(): - return CGGeneric("const nsAString&") - - if type.isEnum(): - if type.nullable(): - raise TypeError("We don't support nullable enumerated arguments or " - "union members yet") - return CGGeneric(type.inner.identifier.name) - - if type.isCallback(): - return CGGeneric("JSObject*") - - if type.isAny(): - return CGGeneric("JS::Value") - - if type.isObject(): - typeName = CGGeneric("JSObject") - if type.nullable(): - typeName = CGWrapper(typeName, post="*") - else: - typeName = CGWrapper(typeName, post="&") - return typeName - - if not type.isPrimitive(): - raise TypeError("Need native type for argument type '%s'" % str(type)) - - typeName = CGGeneric(builtinNames[type.tag()]) - if type.nullable(): - typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&") - return typeName - -def getUnionTypeTemplateVars(type, descriptorProvider): - # For dictionaries and sequences we need to pass None as the failureCode - # for getJSToNativeConversionTemplate. - # Also, for dictionaries we would need to handle conversion of - # null/undefined to the dictionary correctly. - if type.isDictionary() or type.isSequence(): - raise TypeError("Can't handle dictionaries or sequences in unions") - - if type.isGeckoInterface(): - name = type.inner.identifier.name - elif type.isEnum(): - name = type.inner.identifier.name - elif type.isArray() or type.isSequence(): - name = str(type) - else: - name = type.name - - tryNextCode = """tryNext = true; -return true;""" - if type.isGeckoInterface(): - tryNextCode = ("""if (mUnion.mType != mUnion.eUninitialized) { - mUnion.Destroy%s(); -}""" % name) + tryNextCode - (template, declType, holderType, - dealWithOptional) = getJSToNativeConversionTemplate( - type, descriptorProvider, failureCode=tryNextCode, - isDefinitelyObject=True) - - # This is ugly, but UnionMember needs to call a constructor with no - # arguments so the type can't be const. - structType = declType.define() - if structType.startswith("const "): - structType = structType[6:] - externalType = getUnionAccessorSignatureType(type, descriptorProvider).define() - - if type.isObject(): - setter = CGGeneric("void SetToObject(JSObject* obj)\n" - "{\n" - " mUnion.mValue.mObject.SetValue() = obj;\n" - " mUnion.mType = mUnion.eObject;\n" - "}") - else: - jsConversion = string.Template(template).substitute( - { - "val": "value", - "valPtr": "pvalue", - "declName": "SetAs" + name + "()", - "holderName": "m" + name + "Holder" - } - ) - jsConversion = CGWrapper(CGGeneric(jsConversion), - post="\n" - "return true;") - setter = CGWrapper(CGIndenter(jsConversion), - pre="bool TrySetTo" + name + "(JSContext* cx, const JS::Value& value, JS::Value* pvalue, bool& tryNext)\n" - "{\n" - " tryNext = false;\n", - post="\n" - "}") - - return { - "name": name, - "structType": structType, - "externalType": externalType, - "setter": CGIndenter(setter).define(), - "holderType": holderType.define() if holderType else None - } - -def mapTemplate(template, templateVarArray): - return map(lambda v: string.Template(template).substitute(v), - templateVarArray) - -class CGUnionStruct(CGThing): - def __init__(self, type, descriptorProvider): - CGThing.__init__(self) - self.type = type.unroll() - self.descriptorProvider = descriptorProvider - - def declare(self): - templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider), - self.type.flatMemberTypes) - - callDestructors = [] - enumValues = [] - methods = [] - if self.type.hasNullableType: - callDestructors.append(" case eNull:\n" - " break;") - enumValues.append("eNull") - methods.append(""" bool IsNull() const - { - return mType == eNull; - }""") - - destructorTemplate = """ void Destroy${name}() - { - MOZ_ASSERT(Is${name}(), "Wrong type!"); - mValue.m${name}.Destroy(); - mType = eUninitialized; - }""" - destructors = mapTemplate(destructorTemplate, templateVars) - callDestructors.extend(mapTemplate(" case e${name}:\n" - " Destroy${name}();\n" - " break;", templateVars)) - enumValues.extend(mapTemplate("e${name}", templateVars)) - methodTemplate = """ bool Is${name}() const - { - return mType == e${name}; - } - ${externalType} GetAs${name}() const - { - MOZ_ASSERT(Is${name}(), "Wrong type!"); - // The cast to ${externalType} is needed to work around a bug in Apple's - // clang compiler, for some reason it doesn't call |S::operator T&| when - // casting S<T> to T& and T is forward declared. - return (${externalType})mValue.m${name}.Value(); - } - ${structType}& SetAs${name}() - { - mType = e${name}; - return mValue.m${name}.SetValue(); - }""" - methods.extend(mapTemplate(methodTemplate, templateVars)) - values = mapTemplate("UnionMember<${structType} > m${name};", templateVars) - return string.Template(""" -class ${structName} { -public: - ${structName}() : mType(eUninitialized) - { - } - ~${structName}() - { - switch (mType) { -${callDestructors} - case eUninitialized: - break; - } - } - -${methods} - -private: - friend class ${structName}Argument; - -${destructors} - - enum Type { - eUninitialized, - ${enumValues} - }; - union Value { - ${values} - }; - - Type mType; - Value mValue; -}; - -""").substitute( - { - "structName": self.type.__str__(), - "callDestructors": "\n".join(callDestructors), - "destructors": "\n".join(destructors), - "methods": "\n\n".join(methods), - "enumValues": ",\n ".join(enumValues), - "values": "\n ".join(values), - }) - - def define(self): - return """ -""" - -class CGUnionConversionStruct(CGThing): - def __init__(self, type, descriptorProvider): - CGThing.__init__(self) - self.type = type.unroll() - self.descriptorProvider = descriptorProvider - - def declare(self): - setters = [] - - if self.type.hasNullableType: - setters.append(""" bool SetNull() - { - mUnion.mType = mUnion.eNull; - return true; - }""") - - templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider), - self.type.flatMemberTypes) - structName = self.type.__str__() - - setters.extend(mapTemplate("${setter}", templateVars)) - private = "\n".join(mapTemplate(""" ${structType}& SetAs${name}() - { - mUnion.mType = mUnion.e${name}; - return mUnion.mValue.m${name}.SetValue(); - }""", templateVars)) - private += "\n\n" - holders = filter(lambda v: v["holderType"] is not None, templateVars) - if len(holders) > 0: - private += "\n".join(mapTemplate(" ${holderType} m${name}Holder;", holders)) - private += "\n\n" - private += " " + structName + "& mUnion;" - return string.Template(""" -class ${structName}Argument { -public: - ${structName}Argument(const ${structName}& aUnion) : mUnion(const_cast<${structName}&>(aUnion)) - { - } - -${setters} - -private: -${private} -}; -""").substitute({"structName": structName, - "setters": "\n\n".join(setters), - "private": private - }) - - def define(self): - return """ -""" - -class ClassItem: - """ Use with CGClass """ - def __init__(self, name, visibility): - self.name = name - self.visibility = visibility - def declare(self, cgClass): - assert False - def define(self, cgClass): - assert False - -class ClassBase(ClassItem): - def __init__(self, name, visibility='public'): - ClassItem.__init__(self, name, visibility) - def declare(self, cgClass): - return '%s %s' % (self.visibility, self.name) - def define(self, cgClass): - # Only in the header - return '' - -class ClassMethod(ClassItem): - def __init__(self, name, returnType, args, inline=False, static=False, - virtual=False, const=False, bodyInHeader=False, - templateArgs=None, visibility='public', body=None): - self.returnType = returnType - self.args = args - self.inline = inline or bodyInHeader - self.static = static - self.virtual = virtual - self.const = const - self.bodyInHeader = bodyInHeader - self.templateArgs = templateArgs - self.body = body - ClassItem.__init__(self, name, visibility) - - def getDecorators(self, declaring): - decorators = [] - if self.inline: - decorators.append('inline') - if declaring: - if self.static: - decorators.append('static') - if self.virtual: - decorators.append('virtual') - if decorators: - return ' '.join(decorators) + ' ' - return '' - - def getBody(self): - # Override me or pass a string to constructor - assert self.body is not None - return self.body - - def declare(self, cgClass): - templateClause = 'template <%s>\n' % ', '.join(self.templateArgs) \ - if self.bodyInHeader and self.templateArgs else '' - args = ', '.join([str(a) for a in self.args]) - if self.bodyInHeader: - body = CGIndenter(CGGeneric(self.getBody())).define() - body = '\n{\n' + body + '\n}' - else: - body = ';' - - return string.Template("""${templateClause}${decorators}${returnType} -${name}(${args})${const}${body} -""").substitute({ 'templateClause': templateClause, - 'decorators': self.getDecorators(True), - 'returnType': self.returnType, - 'name': self.name, - 'const': ' const' if self.const else '', - 'args': args, - 'body': body }) - - def define(self, cgClass): - if self.bodyInHeader: - return '' - - templateArgs = cgClass.templateArgs - if templateArgs: - if cgClass.templateSpecialization: - templateArgs = \ - templateArgs[len(cgClass.templateSpecialization):] - - if templateArgs: - templateClause = \ - 'template <%s>\n' % ', '.join([str(a) for a in templateArgs]) - else: - templateClause = '' - - args = ', '.join([str(a) for a in self.args]) - - body = CGIndenter(CGGeneric(self.getBody())).define() - - return string.Template("""${templateClause}${decorators}${returnType} -${className}::${name}(${args})${const} -{ -${body} -}\n -""").substitute({ 'templateClause': templateClause, - 'decorators': self.getDecorators(False), - 'returnType': self.returnType, - 'className': cgClass.getNameString(), - 'name': self.name, - 'args': args, - 'const': ' const' if self.const else '', - 'body': body }) - -class ClassConstructor(ClassItem): - """ - Used for adding a constructor to a CGClass. - - args is a list of Argument objects that are the arguments taken by the - constructor. - - inline should be True if the constructor should be marked inline. - - bodyInHeader should be True if the body should be placed in the class - declaration in the header. - - visibility determines the visibility of the constructor (public, - protected, private), defaults to private. - - baseConstructors is a list of strings containing calls to base constructors, - defaults to None. - - body contains a string with the code for the constructor, defaults to None. - """ - def __init__(self, args, inline=False, bodyInHeader=False, - visibility="private", baseConstructors=None, body=None): - self.args = args - self.inline = inline or bodyInHeader - self.bodyInHeader = bodyInHeader - self.baseConstructors = baseConstructors - self.body = body - ClassItem.__init__(self, None, visibility) - - def getDecorators(self, declaring): - decorators = [] - if self.inline and declaring: - decorators.append('inline') - if decorators: - return ' '.join(decorators) + ' ' - return '' - - def getInitializationList(self, cgClass): - items = [str(c) for c in self.baseConstructors] - for m in cgClass.members: - if not m.static: - initialize = m.getBody() - if initialize: - items.append(m.name + "(" + initialize + ")") - - if len(items) > 0: - return '\n : ' + ',\n '.join(items) - return '' - - def getBody(self): - assert self.body is not None - return self.body - - def declare(self, cgClass): - args = ', '.join([str(a) for a in self.args]) - if self.bodyInHeader: - body = ' ' + self.getBody(); - body = stripTrailingWhitespace(body.replace('\n', '\n ')) - if len(body) > 0: - body += '\n' - body = self.getInitializationList(cgClass) + '\n{\n' + body + '}' - else: - body = ';' - - return string.Template("""${decorators}${className}(${args})${body} -""").substitute({ 'decorators': self.getDecorators(True), - 'className': cgClass.getNameString(), - 'args': args, - 'body': body }) - - def define(self, cgClass): - if self.bodyInHeader: - return '' - - args = ', '.join([str(a) for a in self.args]) - - body = ' ' + self.getBody() - body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n ')) - if len(body) > 0: - body += '\n' - - return string.Template("""${decorators} -${className}::${className}(${args})${initializationList} -{${body}}\n -""").substitute({ 'decorators': self.getDecorators(False), - 'className': cgClass.getNameString(), - 'args': args, - 'initializationList': self.getInitializationList(cgClass), - 'body': body }) - -class ClassMember(ClassItem): - def __init__(self, name, type, visibility="private", static=False, - body=None): - self.type = type; - self.static = static - self.body = body - ClassItem.__init__(self, name, visibility) - - def declare(self, cgClass): - return '%s%s %s;\n' % ('static ' if self.static else '', self.type, - self.name) - - def define(self, cgClass): - if not self.static: - return '' - if self.body: - body = " = " + self.body - else: - body = "" - return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(), - self.name, body) - -class ClassTypedef(ClassItem): - def __init__(self, name, type, visibility="public"): - self.type = type - ClassItem.__init__(self, name, visibility) - - def declare(self, cgClass): - return 'typedef %s %s;\n' % (self.type, self.name) - - def define(self, cgClass): - # Only goes in the header - return '' - -class ClassEnum(ClassItem): - def __init__(self, name, entries, values=None, visibility="public"): - self.entries = entries - self.values = values - ClassItem.__init__(self, name, visibility) - - def declare(self, cgClass): - entries = [] - for i in range(0, len(self.entries)): - if i >= len(self.values): - entry = '%s' % self.entries[i] - else: - entry = '%s = %s' % (self.entries[i], self.values[i]) - entries.append(entry) - name = '' if not self.name else ' ' + self.name - return 'enum%s\n{\n %s\n};\n' % (name, ',\n '.join(entries)) - - def define(self, cgClass): - # Only goes in the header - return '' - -class CGClass(CGThing): - def __init__(self, name, bases=[], members=[], constructors=[], methods=[], - typedefs = [], enums=[], templateArgs=[], - templateSpecialization=[], isStruct=False, indent=''): - CGThing.__init__(self) - self.name = name - self.bases = bases - self.members = members - self.constructors = constructors - self.methods = methods - self.typedefs = typedefs - self.enums = enums - self.templateArgs = templateArgs - self.templateSpecialization = templateSpecialization - self.isStruct = isStruct - self.indent = indent - self.defaultVisibility ='public' if isStruct else 'private' - - def getNameString(self): - className = self.name - if self.templateSpecialization: - className = className + \ - '<%s>' % ', '.join([str(a) for a - in self.templateSpecialization]) - return className - - def declare(self): - result = '' - if self.templateArgs: - templateArgs = [str(a) for a in self.templateArgs] - templateArgs = templateArgs[len(self.templateSpecialization):] - result = result + self.indent + 'template <%s>\n' \ - % ','.join([str(a) for a in templateArgs]) - - type = 'struct' if self.isStruct else 'class' - - if self.templateSpecialization: - specialization = \ - '<%s>' % ', '.join([str(a) for a in self.templateSpecialization]) - else: - specialization = '' - - result = result + '%s%s %s%s' \ - % (self.indent, type, self.name, specialization) - - if self.bases: - result = result + ' : %s' % ', '.join([d.declare(self) for d in self.bases]) - - result = result + '\n%s{\n' % self.indent - - def declareMembers(cgClass, memberList, defaultVisibility, itemCount, - separator=''): - members = { 'private': [], 'protected': [], 'public': [] } - - for member in memberList: - members[member.visibility].append(member) - - - if defaultVisibility == 'public': - order = [ 'public', 'protected', 'private' ] - else: - order = [ 'private', 'protected', 'public' ] - - result = '' - - lastVisibility = defaultVisibility - for visibility in order: - list = members[visibility] - if list: - if visibility != lastVisibility: - if itemCount: - result = result + '\n' - result = result + visibility + ':\n' - itemCount = 0 - for member in list: - if itemCount != 0: - result = result + separator - declaration = member.declare(cgClass) - declaration = CGIndenter(CGGeneric(declaration)).define() - result = result + declaration - itemCount = itemCount + 1 - lastVisibility = visibility - return (result, lastVisibility, itemCount) - - order = [(self.enums, ''), (self.typedefs, ''), (self.members, ''), - (self.constructors, '\n'), (self.methods, '\n')] - - lastVisibility = self.defaultVisibility - itemCount = 0 - for (memberList, separator) in order: - (memberString, lastVisibility, itemCount) = \ - declareMembers(self, memberList, lastVisibility, itemCount, - separator) - if self.indent: - memberString = CGIndenter(CGGeneric(memberString), - len(self.indent)).define() - result = result + memberString - - result = result + self.indent + '};\n' - return result - - def define(self): - def defineMembers(cgClass, memberList, itemCount, separator=''): - result = '' - for member in memberList: - if itemCount != 0: - result = result + separator - result = result + member.define(cgClass) - itemCount = itemCount + 1 - return (result, itemCount) - - order = [(self.members, '\n'), (self.constructors, '\n'), - (self.methods, '\n')] - - result = '' - itemCount = 0 - for (memberList, separator) in order: - (memberString, itemCount) = defineMembers(self, memberList, - itemCount, separator) - result = result + memberString - return result - -class CGResolveOwnProperty(CGAbstractMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'), - Argument('jsid', 'id'), Argument('bool', 'set'), - Argument('JSPropertyDescriptor*', 'desc')] - CGAbstractMethod.__init__(self, descriptor, "ResolveOwnProperty", "bool", args) - def definition_body(self): - return """ JSObject* obj = wrapper; - if (xpc::WrapperFactory::IsXrayWrapper(obj)) { - obj = js::UnwrapObject(obj); - } - // We rely on getOwnPropertyDescriptor not shadowing prototype properties by named - // properties. If that changes we'll need to filter here. - return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, set, desc); -""" - -class CGEnumerateOwnProperties(CGAbstractMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'), - Argument('JS::AutoIdVector&', 'props')] - CGAbstractMethod.__init__(self, descriptor, "EnumerateOwnProperties", "bool", args) - def definition_body(self): - return """ JSObject* obj = wrapper; - if (xpc::WrapperFactory::IsXrayWrapper(obj)) { - obj = js::UnwrapObject(obj); - } - // We rely on getOwnPropertyNames not shadowing prototype properties by named - // properties. If that changes we'll need to filter here. - return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props); -""" - -class CGXrayHelper(CGAbstractMethod): - def __init__(self, descriptor, name, args, properties): - CGAbstractMethod.__init__(self, descriptor, name, "bool", args) - self.properties = properties - - def definition_body(self): - varNames = self.properties.variableNames(True) - - methods = self.properties.methods - if methods.hasNonChromeOnly() or methods.hasChromeOnly(): - methodArgs = """// %(methods)s has an end-of-list marker at the end that we ignore -%(methods)s, %(methods)s_ids, %(methods)s_specs, ArrayLength(%(methods)s) - 1""" % varNames - else: - methodArgs = "NULL, NULL, NULL, 0" - methodArgs = CGGeneric(methodArgs) - - attrs = self.properties.attrs - if attrs.hasNonChromeOnly() or attrs.hasChromeOnly(): - attrArgs = """// %(attrs)s has an end-of-list marker at the end that we ignore -%(attrs)s, %(attrs)s_ids, %(attrs)s_specs, ArrayLength(%(attrs)s) - 1""" % varNames - else: - attrArgs = "NULL, NULL, NULL, 0" - attrArgs = CGGeneric(attrArgs) - - consts = self.properties.consts - if consts.hasNonChromeOnly() or consts.hasChromeOnly(): - constArgs = """// %(consts)s has an end-of-list marker at the end that we ignore -%(consts)s, %(consts)s_ids, %(consts)s_specs, ArrayLength(%(consts)s) - 1""" % varNames - else: - constArgs = "NULL, NULL, NULL, 0" - constArgs = CGGeneric(constArgs) - - prefixArgs = CGGeneric(self.getPrefixArgs()) - - return CGIndenter( - CGWrapper(CGList([prefixArgs, methodArgs, attrArgs, constArgs], ",\n"), - pre=("return Xray%s(" % self.name), - post=");", - reindent=True)).define() - -class CGResolveProperty(CGXrayHelper): - def __init__(self, descriptor, properties): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'), - Argument('jsid', 'id'), Argument('bool', 'set'), - Argument('JSPropertyDescriptor*', 'desc')] - CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args, - properties) - - def getPrefixArgs(self): - return "cx, wrapper, id, desc" - - -class CGEnumerateProperties(CGXrayHelper): - def __init__(self, descriptor, properties): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'), - Argument('JS::AutoIdVector&', 'props')] - CGXrayHelper.__init__(self, descriptor, "EnumerateProperties", args, - properties) - - def getPrefixArgs(self): - return "props" - -class CGPrototypeTraitsClass(CGClass): - def __init__(self, descriptor, indent=''): - templateArgs = [Argument('prototypes::ID', 'PrototypeID')] - templateSpecialization = ['prototypes::id::' + descriptor.name] - enums = [ClassEnum('', ['Depth'], - [descriptor.interface.inheritanceDepth()])] - typedefs = [ClassTypedef('NativeType', descriptor.nativeType)] - CGClass.__init__(self, 'PrototypeTraits', indent=indent, - templateArgs=templateArgs, - templateSpecialization=templateSpecialization, - enums=enums, typedefs=typedefs, isStruct=True) - -class CGPrototypeIDMapClass(CGClass): - def __init__(self, descriptor, indent=''): - templateArgs = [Argument('class', 'ConcreteClass')] - templateSpecialization = [descriptor.nativeType] - enums = [ClassEnum('', ['PrototypeID'], - ['prototypes::id::' + descriptor.name])] - CGClass.__init__(self, 'PrototypeIDMap', indent=indent, - templateArgs=templateArgs, - templateSpecialization=templateSpecialization, - enums=enums, isStruct=True) - -class CGClassForwardDeclare(CGThing): - def __init__(self, name, isStruct=False): - CGThing.__init__(self) - self.name = name - self.isStruct = isStruct - def declare(self): - type = 'struct' if self.isStruct else 'class' - return '%s %s;\n' % (type, self.name) - def define(self): - # Header only - return '' - -class CGProxySpecialOperation(CGPerSignatureCall): - """ - Base class for classes for calling an indexed or named special operation - (don't use this directly, use the derived classes below). - """ - def __init__(self, descriptor, operation): - nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation)) - operation = descriptor.operations[operation] - assert len(operation.signatures()) == 1 - signature = operation.signatures()[0] - extendedAttributes = descriptor.getExtendedAttributes(operation) - - (returnType, arguments) = signature - - # We pass len(arguments) as the final argument so that the - # CGPerSignatureCall won't do any argument conversion of its own. - CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName, - False, descriptor, operation, - len(arguments)) - - if operation.isSetter() or operation.isCreator(): - # arguments[0] is the index or name of the item that we're setting. - argument = arguments[1] - template = getJSToNativeConversionTemplate(argument.type, descriptor, - treatNullAs=argument.treatNullAs, - treatUndefinedAs=argument.treatUndefinedAs) - templateValues = { - "declName": argument.identifier.name, - "holderName": argument.identifier.name + "_holder", - "val": "desc->value", - "valPtr": "&desc->value" - } - self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(template, templateValues)) - elif operation.isGetter(): - self.cgRoot.prepend(CGGeneric("bool found;")) - - def getArguments(self): - args = [(a, a.identifier.name) for a in self.arguments] - if self.idlNode.isGetter(): - args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean], - self.idlNode), - "found")) - return args - - def wrap_return_value(self): - if not self.idlNode.isGetter() or self.templateValues is None: - return "" - - wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues)) - wrap = CGIfWrapper(wrap, "found") - return "\n" + wrap.define() - -class CGProxyIndexedGetter(CGProxySpecialOperation): - """ - Class to generate a call to an indexed getter. If templateValues is not None - the returned value will be wrapped with wrapForType using templateValues. - """ - def __init__(self, descriptor, templateValues=None): - self.templateValues = templateValues - CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter') - -class CGProxyIndexedSetter(CGProxySpecialOperation): - """ - Class to generate a call to an indexed setter. - """ - def __init__(self, descriptor): - CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter') - -class CGProxyNamedGetter(CGProxySpecialOperation): - """ - Class to generate a call to an named getter. If templateValues is not None - the returned value will be wrapped with wrapForType using templateValues. - """ - def __init__(self, descriptor, templateValues=None): - self.templateValues = templateValues - CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter') - -class CGProxyNamedSetter(CGProxySpecialOperation): - """ - Class to generate a call to a named setter. - """ - def __init__(self, descriptor): - CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter') - -class CGProxyIsProxy(CGAbstractMethod): - def __init__(self, descriptor): - args = [Argument('JSObject*', 'obj')] - CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True) - def declare(self): - return "" - def definition_body(self): - return " return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();" - -class CGProxyUnwrap(CGAbstractMethod): - def __init__(self, descriptor): - args = [Argument('JSObject*', 'obj')] - CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True) - def declare(self): - return "" - def definition_body(self): - return """ if (xpc::WrapperFactory::IsXrayWrapper(obj)) { - obj = js::UnwrapObject(obj); - } - MOZ_ASSERT(IsProxy(obj)); - return static_cast<%s*>(js::GetProxyPrivate(obj).toPrivate());""" % (self.descriptor.nativeType) - -class CGDOMJSProxyHandlerDOMClass(CGThing): - def __init__(self, descriptor): - CGThing.__init__(self) - self.descriptor = descriptor - def declare(self): - return "extern const DOMClass Class;\n" - def define(self): - return """ -const DOMClass Class = """ + DOMClass(self.descriptor) + """; - -""" - -class CGDOMJSProxyHandler_CGDOMJSProxyHandler(ClassConstructor): - def __init__(self): - ClassConstructor.__init__(self, [], inline=True, visibility="private", - baseConstructors=["mozilla::dom::DOMProxyHandler(Class)"], - body="") - -class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'), - Argument('jsid', 'id'), Argument('bool', 'set'), - Argument('JSPropertyDescriptor*', 'desc')] - ClassMethod.__init__(self, "getOwnPropertyDescriptor", "bool", args) - self.descriptor = descriptor - def getBody(self): - indexedGetter = self.descriptor.operations['IndexedGetter'] - indexedSetter = self.descriptor.operations['IndexedSetter'] - - setOrIndexedGet = "" - if indexedGetter or indexedSetter: - setOrIndexedGet += "int32_t index = GetArrayIndexFromId(cx, id);\n" - - if indexedGetter: - readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None) - fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly - templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value', - 'obj': 'proxy', 'successCode': fillDescriptor} - get = ("if (index >= 0) {\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" + - "}\n") % (self.descriptor.nativeType) - - if indexedSetter or self.descriptor.operations['NamedSetter']: - setOrIndexedGet += "if (set) {\n" - if indexedSetter: - setOrIndexedGet += (" if (index >= 0) {\n") - if not 'IndexedCreator' in self.descriptor.operations: - # FIXME need to check that this is a 'supported property index' - assert False - setOrIndexedGet += (" FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" + - " return true;\n" + - " }\n") - if self.descriptor.operations['NamedSetter']: - setOrIndexedGet += " if (JSID_IS_STRING(id)) {\n" - if not 'NamedCreator' in self.descriptor.operations: - # FIXME need to check that this is a 'supported property name' - assert False - setOrIndexedGet += (" FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" + - " return true;\n" + - " }\n") - setOrIndexedGet += "}" - if indexedGetter: - setOrIndexedGet += (" else {\n" + - CGIndenter(CGGeneric(get)).define() + - "}") - setOrIndexedGet += "\n\n" - elif indexedGetter: - setOrIndexedGet += ("if (!set) {\n" + - CGIndenter(CGGeneric(get)).define() + - "}\n\n") - - namedGetter = self.descriptor.operations['NamedGetter'] - if namedGetter: - readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None) - fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly - templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value', - 'obj': 'proxy', 'successCode': fillDescriptor} - # Once we start supporting OverrideBuiltins we need to make - # ResolveOwnProperty or EnumerateOwnProperties filter out named - # properties that shadow prototype properties. - namedGet = ("\n" + - "if (!set && JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" + - " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" + - " FakeDependentString name;\n" - " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + - " eStringify, eStringify, name)) {\n" + - " return false;\n" + - " }\n" + - "\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" + - "}\n") % (self.descriptor.nativeType) - else: - namedGet = "" - - return setOrIndexedGet + """JSObject* expando; -if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { - unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED; - if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) { - return false; - } - if (desc->obj) { - // Pretend the property lives on the wrapper. - desc->obj = proxy; - return true; - } -} -""" + namedGet + """ -desc->obj = NULL; -return true;""" - -class CGDOMJSProxyHandler_defineProperty(ClassMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'), - Argument('jsid', 'id'), - Argument('JSPropertyDescriptor*', 'desc')] - ClassMethod.__init__(self, "defineProperty", "bool", args) - self.descriptor = descriptor - def getBody(self): - set = "" - - indexedSetter = self.descriptor.operations['IndexedSetter'] - if indexedSetter: - if not (self.descriptor.operations['IndexedCreator'] is indexedSetter): - raise TypeError("Can't handle creator that's different from the setter") - set += ("int32_t index = GetArrayIndexFromId(cx, id);\n" + - "if (index >= 0) {\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() + - " return true;\n" + - "}\n") % (self.descriptor.nativeType) - elif self.descriptor.operations['IndexedGetter']: - set += ("if (GetArrayIndexFromId(cx, id) >= 0) {\n" + - " return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" + - "}\n") % self.descriptor.name - - namedSetter = self.descriptor.operations['NamedSetter'] - if namedSetter: - if not self.descriptor.operations['NamedCreator'] is namedSetter: - raise TypeError("Can't handle creator that's different from the setter") - set += ("if (JSID_IS_STRING(id)) {\n" + - " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" + - " FakeDependentString name;\n" - " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + - " eStringify, eStringify, name)) {\n" + - " return false;\n" + - " }\n" + - "\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" + - "}\n") % (self.descriptor.nativeType) - elif self.descriptor.operations['NamedGetter']: - set += ("if (JSID_IS_STRING(id)) {\n" + - " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" + - " FakeDependentString name;\n" - " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + - " eStringify, eStringify, name)) {\n" + - " return false;\n" + - " }\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + - " if (found) {\n" - " return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" + - " }\n" + - " return true;\n" - "}\n") % (self.descriptor.nativeType, self.descriptor.name) - return set + """return mozilla::dom::DOMProxyHandler::defineProperty(%s);""" % ", ".join(a.name for a in self.args) - -class CGDOMJSProxyHandler_getOwnPropertyNames(ClassMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'), - Argument('JS::AutoIdVector&', 'props')] - ClassMethod.__init__(self, "getOwnPropertyNames", "bool", args) - self.descriptor = descriptor - def getBody(self): - indexedGetter = self.descriptor.operations['IndexedGetter'] - if indexedGetter: - addIndices = """uint32_t length = UnwrapProxy(proxy)->Length(); -MOZ_ASSERT(int32_t(length) >= 0); -for (int32_t i = 0; i < int32_t(length); ++i) { - if (!props.append(INT_TO_JSID(i))) { - return false; - } -} - -""" - else: - addIndices = "" - - return addIndices + """JSObject* expando; -if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = DOMProxyHandler::GetExpandoObject(proxy)) && - !js::GetPropertyNames(cx, expando, JSITER_OWNONLY | JSITER_HIDDEN, &props)) { - return false; -} - -// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=772869 Add named items -return true;""" - -class CGDOMJSProxyHandler_hasOwn(ClassMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'), - Argument('jsid', 'id'), Argument('bool*', 'bp')] - ClassMethod.__init__(self, "hasOwn", "bool", args) - self.descriptor = descriptor - def getBody(self): - indexedGetter = self.descriptor.operations['IndexedGetter'] - if indexedGetter: - indexed = ("int32_t index = GetArrayIndexFromId(cx, id);\n" + - "if (index >= 0) {\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" + - " *bp = found;\n" + - " return true;\n" + - "}\n\n") % (self.descriptor.nativeType) - else: - indexed = "" - - namedGetter = self.descriptor.operations['NamedGetter'] - if namedGetter: - named = ("if (JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" + - " jsval nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" + - " FakeDependentString name;\n" - " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + - " eStringify, eStringify, name)) {\n" + - " return false;\n" + - " }\n" + - "\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" + - " *bp = found;\n" - " return true;\n" - "}\n" + - "\n") % (self.descriptor.nativeType) - else: - named = "" - - return indexed + """JSObject* expando = GetExpandoObject(proxy); -if (expando) { - JSBool b = true; - JSBool ok = JS_HasPropertyById(cx, expando, id, &b); - *bp = !!b; - if (!ok || *bp) { - return ok; - } -} - -""" + named + """*bp = false; -return true;""" - -class CGDOMJSProxyHandler_get(ClassMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'), - Argument('JSObject*', 'receiver'), Argument('jsid', 'id'), - Argument('JS::Value*', 'vp')] - ClassMethod.__init__(self, "get", "bool", args) - self.descriptor = descriptor - def getBody(self): - getFromExpando = """JSObject* expando = DOMProxyHandler::GetExpandoObject(proxy); -if (expando) { - JSBool hasProp; - if (!JS_HasPropertyById(cx, expando, id, &hasProp)) { - return false; - } - - if (hasProp) { - return JS_GetPropertyById(cx, expando, id, vp); - } -}""" - - templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'} - - indexedGetter = self.descriptor.operations['IndexedGetter'] - if indexedGetter: - getIndexedOrExpando = ("int32_t index = GetArrayIndexFromId(cx, id);\n" + - "if (index >= 0) {\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) % (self.descriptor.nativeType) - getIndexedOrExpando += """ - // Even if we don't have this index, we don't forward the - // get on to our expando object. -} else { - %s -} -""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n '))) - else: - getIndexedOrExpando = getFromExpando + "\n" - - namedGetter = self.descriptor.operations['NamedGetter'] - if namedGetter: - getNamed = ("if (JSID_IS_STRING(id)) {\n" + - " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" + - " FakeDependentString name;\n" - " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + - " eStringify, eStringify, name)) {\n" + - " return false;\n" + - " }\n" + - "\n" + - " %s* self = UnwrapProxy(proxy);\n" + - CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + - "}\n") % (self.descriptor.nativeType) - else: - getNamed = "" - - return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), - "Should not have a XrayWrapper here"); - -%s -bool found; -if (!GetPropertyOnPrototype(cx, proxy, id, &found, vp)) { - return false; -} - -if (found) { - return true; -} -%s -vp->setUndefined(); -return true;""" % (getIndexedOrExpando, getNamed) - -class CGDOMJSProxyHandler_obj_toString(ClassMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy')] - ClassMethod.__init__(self, "obj_toString", "JSString*", args) - self.descriptor = descriptor - def getBody(self): - stringifier = self.descriptor.operations['Stringifier'] - if stringifier: - name = stringifier.identifier.name - nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name)) - signature = stringifier.signatures()[0] - returnType = signature[0] - extendedAttributes = self.descriptor.getExtendedAttributes(stringifier) - infallible = 'infallible' in extendedAttributes - if not infallible: - error = CGGeneric( - ('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString");\n' + - "return NULL;") % self.descriptor.interface.identifier.name) - else: - error = None - call = CGCallGenerator(error, [], "", returnType, extendedAttributes, self.descriptor, nativeName, False, object="UnwrapProxy(proxy)") - return call.define() + """ - -JSString* jsresult; -return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;""" - - return "return mozilla::dom::DOMProxyHandler::obj_toString(cx, \"%s\");" % self.descriptor.name - -class CGDOMJSProxyHandler_finalize(ClassMethod): - def __init__(self, descriptor): - args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')] - ClassMethod.__init__(self, "finalize", "void", args) - self.descriptor = descriptor - def getBody(self): - return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") + - finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name)) - -class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod): - def __init__(self, descriptor): - args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'), - Argument('JSObject*', 'receiver'), - Argument('uint32_t', 'index'), - Argument('JS::Value*', 'vp'), Argument('bool*', 'present')] - ClassMethod.__init__(self, "getElementIfPresent", "bool", args) - self.descriptor = descriptor - def getBody(self): - indexedGetter = self.descriptor.operations['IndexedGetter'] - if indexedGetter: - successCode = """*present = found; -return true;""" - templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', - 'obj': 'proxy', 'successCode': successCode} - get = ("%s* self = UnwrapProxy(proxy);\n" + - CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n" - "// We skip the expando object if there is an indexed getter.\n" + - "\n") % (self.descriptor.nativeType) - else: - get = """ - -JSObject* expando = GetExpandoObject(proxy); -if (expando) { - JSBool isPresent; - if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) { - return false; - } - if (isPresent) { - *present = true; - return true; - } -} -""" - - return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), - "Should not have a XrayWrapper here"); - -""" + get + """ -// No need to worry about name getters here, so just check the proto. - -JSObject *proto; -if (!js::GetObjectProto(cx, proxy, &proto)) { - return false; -} -if (proto) { - JSBool isPresent; - if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) { - return false; - } - *present = isPresent; - return true; -} - -*present = false; -// Can't Debug_SetValueRangeToCrashOnTouch because it's not public -return true;""" - -class CGDOMJSProxyHandler_getInstance(ClassMethod): - def __init__(self): - ClassMethod.__init__(self, "getInstance", "DOMProxyHandler*", [], static=True) - def getBody(self): - return """static DOMProxyHandler instance; -return &instance;""" - -class CGDOMJSProxyHandler(CGClass): - def __init__(self, descriptor): - constructors = [CGDOMJSProxyHandler_CGDOMJSProxyHandler()] - methods = [CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)] - if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']: - methods.append(CGDOMJSProxyHandler_defineProperty(descriptor)) - methods.extend([CGDOMJSProxyHandler_getOwnPropertyNames(descriptor), - CGDOMJSProxyHandler_hasOwn(descriptor), - CGDOMJSProxyHandler_get(descriptor), - CGDOMJSProxyHandler_obj_toString(descriptor), - CGDOMJSProxyHandler_finalize(descriptor), - CGDOMJSProxyHandler_getElementIfPresent(descriptor), - CGDOMJSProxyHandler_getInstance()]) - CGClass.__init__(self, 'DOMProxyHandler', - bases=[ClassBase('mozilla::dom::DOMProxyHandler')], - constructors=constructors, - methods=methods) - -def stripTrailingWhitespace(text): - tail = '\n' if text.endswith('\n') else '' - lines = text.splitlines() - for i in range(len(lines)): - lines[i] = lines[i].rstrip() - return '\n'.join(lines) + tail - -class CGDescriptor(CGThing): - def __init__(self, descriptor): - CGThing.__init__(self) - - assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject() - - cgThings = [] - if descriptor.interface.hasInterfacePrototypeObject(): - (hasMethod, hasGetter, hasLenientGetter, - hasSetter, hasLenientSetter) = False, False, False, False, False - for m in descriptor.interface.members: - if m.isMethod() and not m.isStatic() and not m.isIdentifierLess(): - cgThings.append(CGSpecializedMethod(descriptor, m)) - cgThings.append(CGMemberJITInfo(descriptor, m)) - hasMethod = True - elif m.isAttr(): - cgThings.append(CGSpecializedGetter(descriptor, m)) - if m.hasLenientThis(): - hasLenientGetter = True - else: - hasGetter = True - if not m.readonly: - cgThings.append(CGSpecializedSetter(descriptor, m)) - if m.hasLenientThis(): - hasLenientSetter = True - else: - hasSetter = True - cgThings.append(CGMemberJITInfo(descriptor, m)) - if hasMethod: cgThings.append(CGGenericMethod(descriptor)) - if hasGetter: cgThings.append(CGGenericGetter(descriptor)) - if hasLenientGetter: cgThings.append(CGGenericGetter(descriptor, - lenientThis=True)) - if hasSetter: cgThings.append(CGGenericSetter(descriptor)) - if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor, - lenientThis=True)) - - if descriptor.concrete and not descriptor.proxy: - if not descriptor.workers and descriptor.wrapperCache: - cgThings.append(CGAddPropertyHook(descriptor)) - - # Always have a finalize hook, regardless of whether the class wants a - # custom hook. - cgThings.append(CGClassFinalizeHook(descriptor)) - - # Only generate a trace hook if the class wants a custom hook. - if (descriptor.customTrace): - cgThings.append(CGClassTraceHook(descriptor)) - - if descriptor.interface.hasInterfaceObject(): - cgThings.append(CGClassConstructHook(descriptor)) - cgThings.append(CGClassHasInstanceHook(descriptor)) - cgThings.append(CGInterfaceObjectJSClass(descriptor)) - - if descriptor.interface.hasInterfacePrototypeObject(): - cgThings.append(CGPrototypeJSClass(descriptor)) - - properties = PropertyArrays(descriptor) - cgThings.append(CGGeneric(define=str(properties))) - cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties)) - if descriptor.interface.hasInterfacePrototypeObject(): - cgThings.append(CGGetProtoObjectMethod(descriptor)) - else: - cgThings.append(CGGetConstructorObjectMethod(descriptor)) - - # Set up our Xray callbacks as needed. Note that we don't need to do - # it in workers. - if (descriptor.interface.hasInterfacePrototypeObject() and - not descriptor.workers): - if descriptor.concrete and descriptor.proxy: - cgThings.append(CGResolveOwnProperty(descriptor)) - cgThings.append(CGEnumerateOwnProperties(descriptor)) - cgThings.append(CGResolveProperty(descriptor, properties)) - cgThings.append(CGEnumerateProperties(descriptor, properties)) - - if descriptor.interface.hasInterfaceObject(): - cgThings.append(CGDefineDOMInterfaceMethod(descriptor)) - if (not descriptor.interface.isExternal() and - # Workers stuff is never pref-controlled - not descriptor.workers and - descriptor.interface.getExtendedAttribute("PrefControlled") is not None): - cgThings.append(CGPrefEnabled(descriptor)) - - if descriptor.interface.hasInterfacePrototypeObject(): - cgThings.append(CGNativePropertyHooks(descriptor)) - - if descriptor.concrete: - if descriptor.proxy: - cgThings.append(CGProxyIsProxy(descriptor)) - cgThings.append(CGProxyUnwrap(descriptor)) - cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor)) - cgThings.append(CGDOMJSProxyHandler(descriptor)) - cgThings.append(CGIsMethod(descriptor)) - else: - cgThings.append(CGDOMJSClass(descriptor)) - - if descriptor.wrapperCache: - cgThings.append(CGWrapWithCacheMethod(descriptor)) - cgThings.append(CGWrapMethod(descriptor)) - else: - cgThings.append(CGWrapNonWrapperCacheMethod(descriptor)) - - cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n") - cgThings = CGWrapper(cgThings, pre='\n', post='\n') - self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name), - cgThings), - post='\n') - - def declare(self): - return self.cgRoot.declare() - def define(self): - return self.cgRoot.define() - -class CGNamespacedEnum(CGThing): - def __init__(self, namespace, enumName, names, values, comment=""): - - if not values: - values = [] - - # Account for explicit enum values. - entries = [] - for i in range(0, len(names)): - if len(values) > i and values[i] is not None: - entry = "%s = %s" % (names[i], values[i]) - else: - entry = names[i] - entries.append(entry) - - # Append a Count. - entries.append('_' + enumName + '_Count') - - # Indent. - entries = [' ' + e for e in entries] - - # Build the enum body. - enumstr = comment + 'enum %s\n{\n%s\n};\n' % (enumName, ',\n'.join(entries)) - curr = CGGeneric(declare=enumstr) - - # Add some whitespace padding. - curr = CGWrapper(curr, pre='\n',post='\n') - - # Add the namespace. - curr = CGNamespace(namespace, curr) - - # Add the typedef - typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName) - curr = CGList([curr, CGGeneric(declare=typedef)]) - - # Save the result. - self.node = curr - - def declare(self): - return self.node.declare() - def define(self): - assert False # Only for headers. - -class CGDictionary(CGThing): - def __init__(self, dictionary, descriptorProvider): - self.dictionary = dictionary; - self.workers = descriptorProvider.workers - if all(CGDictionary(d, descriptorProvider).generatable for - d in CGDictionary.getDictionaryDependencies(dictionary)): - self.generatable = True - else: - self.generatable = False - # Nothing else to do here - return - # Getting a conversion template for interface types can fail - # if we don't have a relevant descriptor when self.workers is True. - # If that happens, just mark ourselves as not being - # generatable and move on. - try: - self.memberInfo = [ - (member, - getJSToNativeConversionTemplate(member.type, - descriptorProvider, - isMember=True, - isOptional=(not member.defaultValue), - defaultValue=member.defaultValue)) - for member in dictionary.members ] - except NoSuchDescriptorError, err: - if not self.workers: - raise err - self.generatable = False - - def declare(self): - if not self.generatable: - return "" - d = self.dictionary - if d.parent: - inheritance = ": public %s " % self.makeClassName(d.parent) - else: - inheritance = "" - memberDecls = [" %s %s;" % - (self.getMemberType(m), m[0].identifier.name) - for m in self.memberInfo] - - return (string.Template( - "struct ${selfName} ${inheritance}{\n" - " ${selfName}() {}\n" - " bool Init(JSContext* cx, const JS::Value& val);\n" - "\n" + - "\n".join(memberDecls) + "\n" - "private:\n" - " // Disallow copy-construction\n" - " ${selfName}(const ${selfName}&) MOZ_DELETE;\n" + - # NOTE: jsids are per-runtime, so don't use them in workers - (" static bool InitIds(JSContext* cx);\n" - " static bool initedIds;\n" if not self.workers else "") + - "\n".join(" static jsid " + - self.makeIdName(m.identifier.name) + ";" for - m in d.members) + "\n" - "};").substitute( { "selfName": self.makeClassName(d), - "inheritance": inheritance })) - - def define(self): - if not self.generatable: - return "" - d = self.dictionary - if d.parent: - initParent = ("// Per spec, we init the parent's members first\n" - "if (!%s::Init(cx, val)) {\n" - " return false;\n" - "}\n" % self.makeClassName(d.parent)) - else: - initParent = "" - - memberInits = [CGIndenter(self.getMemberConversion(m)).define() - for m in self.memberInfo] - idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' % - (m.identifier.name + "_id", m.identifier.name)) - for m in d.members] - idinit = CGList(idinit, " ||\n") - idinit = CGWrapper(idinit, pre="if (", - post=(") {\n" - " return false;\n" - "}"), - reindent=True) - - return string.Template( - # NOTE: jsids are per-runtime, so don't use them in workers - ("bool ${selfName}::initedIds = false;\n" + - "\n".join("jsid ${selfName}::%s = JSID_VOID;" % - self.makeIdName(m.identifier.name) - for m in d.members) + "\n" - "\n" - "bool\n" - "${selfName}::InitIds(JSContext* cx)\n" - "{\n" - " MOZ_ASSERT(!initedIds);\n" - "${idInit}\n" - " initedIds = true;\n" - " return true;\n" - "}\n" - "\n" if not self.workers else "") + - "bool\n" - "${selfName}::Init(JSContext* cx, const JS::Value& val)\n" - "{\n" + - # NOTE: jsids are per-runtime, so don't use them in workers - (" if (!initedIds && !InitIds(cx)) {\n" - " return false;\n" - " }\n" if not self.workers else "") + - "${initParent}" - " JSBool found;\n" - " JS::Value temp;\n" - " bool isNull = val.isNullOrUndefined();\n" - " if (!isNull && !val.isObject()) {\n" - " return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n" - " }\n" - "\n" - "${initMembers}\n" - " return true;\n" - "}").substitute({ - "selfName": self.makeClassName(d), - "initParent": CGIndenter(CGGeneric(initParent)).define(), - "initMembers": "\n\n".join(memberInits), - "idInit": CGIndenter(idinit).define(), - "isMainThread": toStringBool(not self.workers) - }) - - @staticmethod - def makeDictionaryName(dictionary, workers): - suffix = "Workers" if workers else "" - return dictionary.identifier.name + suffix - - def makeClassName(self, dictionary): - return self.makeDictionaryName(dictionary, self.workers) - - def getMemberType(self, memberInfo): - (member, (templateBody, declType, - holderType, dealWithOptional)) = memberInfo - # We can't handle having a holderType here - assert holderType is None - if dealWithOptional: - declType = CGWrapper(declType, pre="Optional< ", post=" >") - return declType.define() - - def getMemberConversion(self, memberInfo): - (member, (templateBody, declType, - holderType, dealWithOptional)) = memberInfo - replacements = { "val": "temp", - "valPtr": "&temp", - # Use this->%s to refer to members, because we don't - # control the member names and want to make sure we're - # talking about the member, not some local that - # shadows the member. Another option would be to move - # the guts of init to a static method which is passed - # an explicit reference to our dictionary object, so - # we couldn't screw this up even if we wanted to.... - "declName": ("(this->%s)" % member.identifier.name), - # We need a holder name for external interfaces, but - # it's scoped down to the conversion so we can just use - # anything we want. - "holderName": "holder"} - # We can't handle having a holderType here - assert holderType is None - if dealWithOptional: - replacements["declName"] = "(" + replacements["declName"] + ".Value())" - if member.defaultValue: - replacements["haveValue"] = "found" - - # NOTE: jsids are per-runtime, so don't use them in workers - if self.workers: - propName = member.identifier.name - propCheck = ('JS_HasProperty(cx, &val.toObject(), "%s", &found)' % - propName) - propGet = ('JS_GetProperty(cx, &val.toObject(), "%s", &temp)' % - propName) - else: - propId = self.makeIdName(member.identifier.name); - propCheck = ("JS_HasPropertyById(cx, &val.toObject(), %s, &found)" % - propId) - propGet = ("JS_GetPropertyById(cx, &val.toObject(), %s, &temp)" % - propId) - - conversionReplacements = { - "prop": "(this->%s)" % member.identifier.name, - "convert": string.Template(templateBody).substitute(replacements), - "propCheck": propCheck, - "propGet": propGet - } - conversion = ("if (isNull) {\n" - " found = false;\n" - "} else if (!${propCheck}) {\n" - " return false;\n" - "}\n") - if member.defaultValue: - conversion += ( - "if (found) {\n" - " if (!${propGet}) {\n" - " return false;\n" - " }\n" - "}\n" - "${convert}") - else: - conversion += ( - "if (found) {\n" - " ${prop}.Construct();\n" - " if (!${propGet}) {\n" - " return false;\n" - " }\n" - "${convert}\n" - "}") - conversionReplacements["convert"] = CGIndenter( - CGGeneric(conversionReplacements["convert"])).define() - - return CGGeneric( - string.Template(conversion).substitute(conversionReplacements) - ) - - @staticmethod - def makeIdName(name): - return name + "_id" - - @staticmethod - def getDictionaryDependencies(dictionary): - deps = set(); - if dictionary.parent: - deps.add(dictionary.parent) - for member in dictionary.members: - if member.type.isDictionary(): - deps.add(member.type.unroll().inner) - return deps - - -class CGRegisterProtos(CGAbstractMethod): - def __init__(self, config): - CGAbstractMethod.__init__(self, None, 'Register', 'void', - [Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')]) - self.config = config - - def _defineMacro(self): - return """ -#define REGISTER_PROTO(_dom_class, _pref_check) \\ - aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), _dom_class##Binding::DefineDOMInterface, _pref_check);\n\n""" - def _undefineMacro(self): - return "\n#undef REGISTER_PROTO" - def _registerProtos(self): - def getPrefCheck(desc): - if desc.interface.getExtendedAttribute("PrefControlled") is None: - return "nullptr" - return "%sBinding::PrefEnabled" % desc.name - lines = ["REGISTER_PROTO(%s, %s);" % (desc.name, getPrefCheck(desc)) - for desc in self.config.getDescriptors(hasInterfaceObject=True, - isExternal=False, - workers=False, - register=True)] - return '\n'.join(lines) + '\n' - def definition_body(self): - return self._defineMacro() + self._registerProtos() + self._undefineMacro() - -class CGBindingRoot(CGThing): - """ - Root codegen class for binding generation. Instantiate the class, and call - declare or define to generate header or cpp code (respectively). - """ - def __init__(self, config, prefix, webIDLFile): - descriptors = config.getDescriptors(webIDLFile=webIDLFile, - hasInterfaceOrInterfacePrototypeObject=True) - dictionaries = config.getDictionaries(webIDLFile) - - forwardDeclares = [CGClassForwardDeclare('XPCWrappedNativeScope')] - - descriptorsForForwardDeclaration = list(descriptors) - for dictionary in dictionaries: - curDict = dictionary - ifacemembers = [] - while curDict: - ifacemembers.extend([m.type.unroll().inner for m - in curDict.members - if m.type.unroll().isInterface()]) - curDict = curDict.parent - # Put in all the non-worker descriptors - descriptorsForForwardDeclaration.extend( - [config.getDescriptor(iface.identifier.name, False) for - iface in ifacemembers]) - # And now the worker ones. But these may not exist, so we - # have to be more careful. - for iface in ifacemembers: - try: - descriptorsForForwardDeclaration.append( - config.getDescriptor(iface.identifier.name, True)) - except NoSuchDescriptorError: - # just move along - pass - - for x in descriptorsForForwardDeclaration: - nativeType = x.nativeType - components = x.nativeType.split('::') - className = components[-1] - # JSObject is a struct, not a class - declare = CGClassForwardDeclare(className, className is "JSObject") - if len(components) > 1: - declare = CGNamespace.build(components[:-1], - CGWrapper(declare, declarePre='\n', - declarePost='\n'), - declareOnly=True) - forwardDeclares.append(CGWrapper(declare, declarePost='\n')) - - forwardDeclares = CGList(forwardDeclares) - - descriptorsWithPrototype = filter(lambda d: d.interface.hasInterfacePrototypeObject(), - descriptors) - traitsClasses = [CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype] - - # We must have a 1:1 mapping here, skip for prototypes that have more - # than one concrete class implementation. - traitsClasses.extend([CGPrototypeIDMapClass(d) for d in descriptorsWithPrototype - if d.uniqueImplementation]) - - # Wrap all of that in our namespaces. - if len(traitsClasses) > 0: - traitsClasses = CGNamespace.build(['mozilla', 'dom'], - CGWrapper(CGList(traitsClasses), - declarePre='\n'), - declareOnly=True) - traitsClasses = CGWrapper(traitsClasses, declarePost='\n') - else: - traitsClasses = None - - # Do codegen for all the enums - def makeEnum(e): - return CGNamespace.build([e.identifier.name + "Values"], - CGEnum(e)) - def makeEnumTypedef(e): - return CGGeneric(declare=("typedef %sValues::valuelist %s;\n" % - (e.identifier.name, e.identifier.name))) - cgthings = [ fun(e) for e in config.getEnums(webIDLFile) - for fun in [makeEnum, makeEnumTypedef] ] - - # Do codegen for all the dictionaries. We have to be a bit careful - # here, because we have to generate these in order from least derived - # to most derived so that class inheritance works out. We also have to - # generate members before the dictionary that contains them. - # - # XXXbz this will fail if we have two webidl files A and B such that A - # declares a dictionary which inherits from a dictionary in B and B - # declares a dictionary (possibly a different one!) that inherits from a - # dictionary in A. The good news is that I expect this to never happen. - reSortedDictionaries = [] - dictionaries = set(dictionaries) - while len(dictionaries) != 0: - # Find the dictionaries that don't depend on anything else anymore - # and move them over. - toMove = [d for d in dictionaries if - len(CGDictionary.getDictionaryDependencies(d) & - dictionaries) == 0] - if len(toMove) == 0: - raise TypeError("Loop in dictionary dependency graph") - dictionaries = dictionaries - set(toMove) - reSortedDictionaries.extend(toMove) - - dictionaries = reSortedDictionaries - cgthings.extend([CGDictionary(d, config.getDescriptorProvider(True)) - for d in dictionaries]) - cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False)) - for d in dictionaries]) - - # Do codegen for all the descriptors - cgthings.extend([CGDescriptor(x) for x in descriptors]) - - # And make sure we have the right number of newlines at the end - curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n") - - # Wrap all of that in our namespaces. - curr = CGNamespace.build(['mozilla', 'dom'], - CGWrapper(curr, pre="\n")) - - curr = CGList([forwardDeclares, - CGWrapper(CGGeneric("using namespace mozilla::dom;"), - defineOnly=True), - traitsClasses, curr], - "\n") - - # Add header includes. - curr = CGHeaders(descriptors, - dictionaries, - ['mozilla/dom/BindingUtils.h', - 'mozilla/dom/DOMJSClass.h', - 'mozilla/dom/DOMJSProxyHandler.h'], - ['mozilla/dom/Nullable.h', - 'PrimitiveConversions.h', - 'XPCQuickStubs.h', - 'nsDOMQS.h', - 'AccessCheck.h', - 'WorkerPrivate.h', - 'nsContentUtils.h', - 'mozilla/Preferences.h', - # Have to include nsDOMQS.h to get fast arg unwrapping - # for old-binding things with castability. - 'nsDOMQS.h' - ], - curr) - - # Add include guards. - curr = CGIncludeGuard(prefix, curr) - - # Add the auto-generated comment. - curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) - - # Store the final result. - self.root = curr - - def declare(self): - return stripTrailingWhitespace(self.root.declare()) - def define(self): - return stripTrailingWhitespace(self.root.define()) - - -class GlobalGenRoots(): - """ - Roots for global codegen. - - To generate code, call the method associated with the target, and then - call the appropriate define/declare method. - """ - - @staticmethod - def PrototypeList(config): - - # Prototype ID enum. - protos = [d.name for d in config.getDescriptors(hasInterfacePrototypeObject=True)] - idEnum = CGNamespacedEnum('id', 'ID', protos, [0]) - idEnum = CGList([idEnum]) - idEnum.append(CGGeneric(declare="const unsigned MaxProtoChainLength = " + - str(config.maxProtoChainLength) + ";\n\n")) - - # Wrap all of that in our namespaces. - idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'], - CGWrapper(idEnum, pre='\n')) - idEnum = CGWrapper(idEnum, post='\n') - - curr = CGList([idEnum]) - - # Constructor ID enum. - constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True, - hasInterfacePrototypeObject=False)] - idEnum = CGNamespacedEnum('id', 'ID', constructors, [0]) - - # Wrap all of that in our namespaces. - idEnum = CGNamespace.build(['mozilla', 'dom', 'constructors'], - CGWrapper(idEnum, pre='\n')) - idEnum = CGWrapper(idEnum, post='\n') - - curr.append(idEnum) - - traitsDecl = CGGeneric(declare=""" -template <prototypes::ID PrototypeID> -struct PrototypeTraits; - -template <class ConcreteClass> -struct PrototypeIDMap; -""") - - traitsDecl = CGNamespace.build(['mozilla', 'dom'], - CGWrapper(traitsDecl, post='\n')) - - curr.append(traitsDecl) - - # Add include guards. - curr = CGIncludeGuard('PrototypeList', curr) - - # Add the auto-generated comment. - curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) - - # Done. - return curr - - @staticmethod - def RegisterBindings(config): - - # TODO - Generate the methods we want - curr = CGRegisterProtos(config) - - # Wrap all of that in our namespaces. - curr = CGNamespace.build(['mozilla', 'dom'], - CGWrapper(curr, post='\n')) - curr = CGWrapper(curr, post='\n') - - # Add the includes - defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface) - for desc in config.getDescriptors(hasInterfaceObject=True, - workers=False, - register=True)] - defineIncludes.append('nsScriptNameSpaceManager.h') - curr = CGHeaders([], [], [], defineIncludes, curr) - - # Add include guards. - curr = CGIncludeGuard('RegisterBindings', curr) - - # Done. - return curr - - @staticmethod - def UnionTypes(config): - - (includes, declarations, unions) = UnionTypes(config.getDescriptors()) - includes.add("mozilla/dom/BindingUtils.h") - - # Wrap all of that in our namespaces. - curr = CGNamespace.build(['mozilla', 'dom'], unions) - - curr = CGWrapper(curr, post='\n') - - namespaces = [] - stack = [CGList([])] - for (clazz, isStruct) in SortedTuples(declarations): - elements = clazz.split("::") - clazz = CGClassForwardDeclare(elements.pop(), isStruct=isStruct) - i = 0 - if len(elements) > 0: - common = min(len(namespaces), len(elements)) - while i < common and namespaces[i] == elements[i]: - i += 1 - - # pop all the namespaces that should be closed - namespaces = namespaces[:i] - - # add all the namespaces that should be opened - for j, namespace in enumerate(elements[i:]): - namespaces.append(namespace) - # every CGNamespace that we add holds a CGList - list = CGList([]) - # add the new namespace to the list on top of the stack - stack[i + j].append(CGNamespace(namespace, list)) - # set the top of the namespace stack to the list of the new - # namespace - stack[i + j + 1:] = [list] - - stack[len(elements)].append(clazz) - - curr = CGList([stack[0], curr], "\n") - - curr = CGHeaders([], [], includes, [], curr) - - # Add include guards. - curr = CGIncludeGuard('UnionTypes', curr) - - # Done. - return curr - - @staticmethod - def UnionConversions(config): - - unions = UnionConversions(config.getDescriptors()) - - # Wrap all of that in our namespaces. - curr = CGNamespace.build(['mozilla', 'dom'], unions) - - curr = CGWrapper(curr, post='\n') - - curr = CGHeaders([], [], ["nsDebug.h", "mozilla/dom/UnionTypes.h", "nsDOMQS.h"], [], curr) - - # Add include guards. - curr = CGIncludeGuard('UnionConversions', curr) - - # Done. - return curr diff --git a/components/script/dom/bindings/codegen/DOMJSClass.h b/components/script/dom/bindings/codegen/DOMJSClass.h deleted file mode 100644 index 151960b5901..00000000000 --- a/components/script/dom/bindings/codegen/DOMJSClass.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_DOMJSClass_h -#define mozilla_dom_DOMJSClass_h - -#include "jsapi.h" -#include "jsfriendapi.h" - -#include "mozilla/dom/PrototypeList.h" // auto-generated - -// We use slot 0 for holding the raw object. This is safe for both -// globals and non-globals. -#define DOM_OBJECT_SLOT 0 - -// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. We have to -// start at 1 past JSCLASS_GLOBAL_SLOT_COUNT because XPConnect uses -// that one. -#define DOM_PROTOTYPE_SLOT (JSCLASS_GLOBAL_SLOT_COUNT + 1) - -// We use these flag bits for the new bindings. -#define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1 - -// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and -// LSetDOMProperty. Those constants need to be changed accordingly if this value -// changes. -#define DOM_PROTO_INSTANCE_CLASS_SLOT 0 - -namespace mozilla { -namespace dom { - -typedef bool -(* ResolveProperty)(JSContext* cx, JSObject* wrapper, jsid id, bool set, - JSPropertyDescriptor* desc); -typedef bool -(* EnumerateProperties)(JSContext* cx, JSObject* wrapper, - JS::AutoIdVector& props); - -struct NativePropertyHooks -{ - ResolveProperty mResolveOwnProperty; - ResolveProperty mResolveProperty; - EnumerateProperties mEnumerateOwnProperties; - EnumerateProperties mEnumerateProperties; - - const NativePropertyHooks *mProtoHooks; -}; - -struct DOMClass -{ - // A list of interfaces that this object implements, in order of decreasing - // derivedness. - const prototypes::ID mInterfaceChain[prototypes::id::_ID_Count]; - - // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in - // the proxy private if we use a proxy object. - // Sometimes it's an nsISupports and sometimes it's not; this class tells - // us which it is. - const bool mDOMObjectIsISupports; - - const NativePropertyHooks* mNativeHooks; -}; - -// Special JSClass for reflected DOM objects. -struct DOMJSClass -{ - // It would be nice to just inherit from JSClass, but that precludes pure - // compile-time initialization of the form |DOMJSClass = {...};|, since C++ - // only allows brace initialization for aggregate/POD types. - JSClass mBase; - - DOMClass mClass; - - static DOMJSClass* FromJSClass(JSClass* base) { - MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS); - return reinterpret_cast<DOMJSClass*>(base); - } - static const DOMJSClass* FromJSClass(const JSClass* base) { - MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS); - return reinterpret_cast<const DOMJSClass*>(base); - } - - static DOMJSClass* FromJSClass(js::Class* base) { - return FromJSClass(Jsvalify(base)); - } - static const DOMJSClass* FromJSClass(const js::Class* base) { - return FromJSClass(Jsvalify(base)); - } - - JSClass* ToJSClass() { return &mBase; } -}; - -inline bool -HasProtoOrIfaceArray(JSObject* global) -{ - MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); - // This can be undefined if we GC while creating the global - return !js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).isUndefined(); -} - -inline JSObject** -GetProtoOrIfaceArray(JSObject* global) -{ - MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); - return static_cast<JSObject**>( - js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate()); -} - -} // namespace dom -} // namespace mozilla - -#endif /* mozilla_dom_DOMJSClass_h */ diff --git a/components/script/dom/bindings/codegen/DOMJSProxyHandler.cpp b/components/script/dom/bindings/codegen/DOMJSProxyHandler.cpp deleted file mode 100644 index af45cc6ed1a..00000000000 --- a/components/script/dom/bindings/codegen/DOMJSProxyHandler.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=2 sw=2 et tw=99 ft=cpp: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/Util.h" - -#include "DOMJSProxyHandler.h" -#include "xpcpublic.h" -#include "xpcprivate.h" -#include "XPCQuickStubs.h" -#include "XPCWrapper.h" -#include "WrapperFactory.h" -#include "nsDOMClassInfo.h" -#include "nsGlobalWindow.h" -#include "nsWrapperCacheInlines.h" -#include "mozilla/dom/BindingUtils.h" - -#include "jsapi.h" - -using namespace JS; - -namespace mozilla { -namespace dom { - -jsid s_length_id = JSID_VOID; - -bool -DefineStaticJSVals(JSContext* cx) -{ - JSAutoRequest ar(cx); - - return InternJSString(cx, s_length_id, "length"); -} - - -int HandlerFamily; - -// Store the information for the specialized ICs. -struct SetListBaseInformation -{ - SetListBaseInformation() { - js::SetListBaseInformation((void*) &HandlerFamily, js::JSSLOT_PROXY_EXTRA + JSPROXYSLOT_EXPANDO); - } -}; - -SetListBaseInformation gSetListBaseInformation; - - -bool -DefineConstructor(JSContext* cx, JSObject* obj, DefineInterface aDefine, nsresult* aResult) -{ - bool enabled; - bool defined = aDefine(cx, obj, &enabled); - MOZ_ASSERT(!defined || enabled, - "We defined a constructor but the new bindings are disabled?"); - *aResult = defined ? NS_OK : NS_ERROR_FAILURE; - return enabled; -} - -// static -JSObject* -DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JSObject* obj) -{ - NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object"); - JSObject* expando = GetExpandoObject(obj); - if (!expando) { - expando = JS_NewObjectWithGivenProto(cx, nullptr, nullptr, - js::GetObjectParent(obj)); - if (!expando) { - return NULL; - } - - xpc::CompartmentPrivate* priv = xpc::GetCompartmentPrivate(obj); - if (!priv->RegisterDOMExpandoObject(obj)) { - return NULL; - } - - nsWrapperCache* cache; - CallQueryInterface(UnwrapDOMObject<nsISupports>(obj, eProxyDOMObject), &cache); - cache->SetPreservingWrapper(true); - - js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando)); - } - return expando; -} - -bool -DOMProxyHandler::getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, bool set, - JSPropertyDescriptor* desc) -{ - if (!getOwnPropertyDescriptor(cx, proxy, id, set, desc)) { - return false; - } - if (desc->obj) { - return true; - } - - JSObject* proto; - if (!js::GetObjectProto(cx, proxy, &proto)) { - return false; - } - if (!proto) { - desc->obj = NULL; - return true; - } - - return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc); -} - -bool -DOMProxyHandler::defineProperty(JSContext* cx, JSObject* proxy, jsid id, - JSPropertyDescriptor* desc) -{ - if ((desc->attrs & JSPROP_GETTER) && desc->setter == JS_StrictPropertyStub) { - return JS_ReportErrorFlagsAndNumber(cx, - JSREPORT_WARNING | JSREPORT_STRICT | - JSREPORT_STRICT_MODE_ERROR, - js_GetErrorMessage, NULL, - JSMSG_GETTER_ONLY); - } - - if (xpc::WrapperFactory::IsXrayWrapper(proxy)) { - return true; - } - - JSObject* expando = EnsureExpandoObject(cx, proxy); - if (!expando) { - return false; - } - - return JS_DefinePropertyById(cx, expando, id, desc->value, desc->getter, desc->setter, - desc->attrs); -} - -bool -DOMProxyHandler::delete_(JSContext* cx, JSObject* proxy, jsid id, bool* bp) -{ - JSBool b = true; - - JSObject* expando; - if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { - Value v; - if (!JS_DeletePropertyById2(cx, expando, id, &v) || !JS_ValueToBoolean(cx, v, &b)) { - return false; - } - } - - *bp = !!b; - return true; -} - -bool -DOMProxyHandler::enumerate(JSContext* cx, JSObject* proxy, AutoIdVector& props) -{ - JSObject* proto; - if (!JS_GetPrototype(cx, proxy, &proto)) { - return false; - } - return getOwnPropertyNames(cx, proxy, props) && - (!proto || js::GetPropertyNames(cx, proto, 0, &props)); -} - -bool -DOMProxyHandler::fix(JSContext* cx, JSObject* proxy, Value* vp) -{ - vp->setUndefined(); - return true; -} - -bool -DOMProxyHandler::has(JSContext* cx, JSObject* proxy, jsid id, bool* bp) -{ - if (!hasOwn(cx, proxy, id, bp)) { - return false; - } - - if (*bp) { - // We have the property ourselves; no need to worry about our prototype - // chain. - return true; - } - - // OK, now we have to look at the proto - JSObject *proto; - if (!js::GetObjectProto(cx, proxy, &proto)) { - return false; - } - if (!proto) { - return true; - } - JSBool protoHasProp; - bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp); - if (ok) { - *bp = protoHasProp; - } - return ok; -} - -// static -JSString* -DOMProxyHandler::obj_toString(JSContext* cx, const char* className) -{ - size_t nchars = sizeof("[object ]") - 1 + strlen(className); - jschar* chars = static_cast<jschar*>(JS_malloc(cx, (nchars + 1) * sizeof(jschar))); - if (!chars) { - return NULL; - } - - const char* prefix = "[object "; - nchars = 0; - while ((chars[nchars] = (jschar)*prefix) != 0) { - nchars++, prefix++; - } - while ((chars[nchars] = (jschar)*className) != 0) { - nchars++, className++; - } - chars[nchars++] = ']'; - chars[nchars] = 0; - - JSString* str = JS_NewUCString(cx, chars, nchars); - if (!str) { - JS_free(cx, chars); - } - return str; -} - -int32_t -IdToInt32(JSContext* cx, jsid id) -{ - JSAutoRequest ar(cx); - - jsval idval; - double array_index; - int32_t i; - if (!::JS_IdToValue(cx, id, &idval) || - !::JS_ValueToNumber(cx, idval, &array_index) || - !::JS_DoubleIsInt32(array_index, &i)) { - return -1; - } - - return i; -} - -} // namespace dom -} // namespace mozilla diff --git a/components/script/dom/bindings/codegen/DOMJSProxyHandler.h b/components/script/dom/bindings/codegen/DOMJSProxyHandler.h deleted file mode 100644 index 394e2dc4d2f..00000000000 --- a/components/script/dom/bindings/codegen/DOMJSProxyHandler.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_DOMJSProxyHandler_h -#define mozilla_dom_DOMJSProxyHandler_h - -#include "jsapi.h" -#include "jsfriendapi.h" -#include "jsproxy.h" -#include "xpcpublic.h" -#include "nsString.h" -#include "mozilla/Likely.h" - -#define DOM_PROXY_OBJECT_SLOT js::JSSLOT_PROXY_PRIVATE - -namespace mozilla { -namespace dom { - -enum { - JSPROXYSLOT_EXPANDO = 0 -}; - -template<typename T> struct Prefable; - -class DOMProxyHandler : public DOMBaseProxyHandler -{ -public: - DOMProxyHandler(const DOMClass& aClass) - : DOMBaseProxyHandler(true), - mClass(aClass) - { - } - - bool getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, bool set, - JSPropertyDescriptor* desc); - bool defineProperty(JSContext* cx, JSObject* proxy, jsid id, - JSPropertyDescriptor* desc); - bool delete_(JSContext* cx, JSObject* proxy, jsid id, bool* bp); - bool enumerate(JSContext* cx, JSObject* proxy, JS::AutoIdVector& props); - bool fix(JSContext* cx, JSObject* proxy, JS::Value* vp); - bool has(JSContext* cx, JSObject* proxy, jsid id, bool* bp); - using js::BaseProxyHandler::obj_toString; - - static JSObject* GetExpandoObject(JSObject* obj) - { - MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object"); - JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); - return v.isUndefined() ? NULL : v.toObjectOrNull(); - } - static JSObject* EnsureExpandoObject(JSContext* cx, JSObject* obj); - - const DOMClass& mClass; - -protected: - static JSString* obj_toString(JSContext* cx, const char* className); -}; - -extern jsid s_length_id; - -int32_t IdToInt32(JSContext* cx, jsid id); - -inline int32_t -GetArrayIndexFromId(JSContext* cx, jsid id) -{ - if (MOZ_LIKELY(JSID_IS_INT(id))) { - return JSID_TO_INT(id); - } - if (MOZ_LIKELY(id == s_length_id)) { - return -1; - } - if (MOZ_LIKELY(JSID_IS_ATOM(id))) { - JSAtom* atom = JSID_TO_ATOM(id); - jschar s = *js::GetAtomChars(atom); - if (MOZ_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z')) - return -1; - - uint32_t i; - JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id)); - return js::StringIsArrayIndex(str, &i) ? i : -1; - } - return IdToInt32(cx, id); -} - -inline void -FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, bool readonly) -{ - desc->obj = obj; - desc->attrs = (readonly ? JSPROP_READONLY : 0) | JSPROP_ENUMERATE; - desc->getter = NULL; - desc->setter = NULL; - desc->shortid = 0; -} - -inline void -FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, jsval v, bool readonly) -{ - desc->value = v; - FillPropertyDescriptor(desc, obj, readonly); -} - -JSObject* -EnsureExpandoObject(JSContext* cx, JSObject* obj); - -} // namespace dom -} // namespace mozilla - -#endif /* mozilla_dom_DOMProxyHandler_h */ diff --git a/components/script/dom/bindings/codegen/ErrorResult.h b/components/script/dom/bindings/codegen/ErrorResult.h deleted file mode 100644 index bbd9404a865..00000000000 --- a/components/script/dom/bindings/codegen/ErrorResult.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* vim: set ts=2 sw=2 et tw=79: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * A struct for tracking exceptions that need to be thrown to JS. - */ - -#ifndef mozilla_ErrorResult_h -#define mozilla_ErrorResult_h - -#include "nscore.h" -#include "mozilla/Assertions.h" - -namespace mozilla { - -class ErrorResult { -public: - ErrorResult() { - mResult = NS_OK; - } - - void Throw(nsresult rv) { - MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success"); - mResult = rv; - } - - // In the future, we can add overloads of Throw that take more - // interesting things, like strings or DOM exception types or - // something if desired. - - // Backwards-compat to make conversion simpler. We don't call - // Throw() here because people can easily pass success codes to - // this. - void operator=(nsresult rv) { - mResult = rv; - } - - bool Failed() const { - return NS_FAILED(mResult); - } - - nsresult ErrorCode() const { - return mResult; - } - -private: - nsresult mResult; - - // Not to be implemented, to make sure people always pass this by - // reference, not by value. - ErrorResult(const ErrorResult&) MOZ_DELETE; -}; - -} // namespace mozilla - -#endif /* mozilla_ErrorResult_h */ diff --git a/components/script/dom/bindings/codegen/GlobalGen.py b/components/script/dom/bindings/codegen/GlobalGen.py index cdca464e029..e596ea44f51 100644 --- a/components/script/dom/bindings/codegen/GlobalGen.py +++ b/components/script/dom/bindings/codegen/GlobalGen.py @@ -14,8 +14,6 @@ import WebIDL import cPickle from Configuration import * from CodegenRust import GlobalGenRoots, replaceFileIfChanged -# import Codegen in general, so we can set a variable on it -import Codegen def generate_file(config, name, filename): root = getattr(GlobalGenRoots, name)(config) diff --git a/components/script/dom/bindings/codegen/Nullable.h b/components/script/dom/bindings/codegen/Nullable.h deleted file mode 100644 index 8b2cc08642b..00000000000 --- a/components/script/dom/bindings/codegen/Nullable.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* vim: set ts=2 sw=2 et tw=79: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_Nullable_h -#define mozilla_dom_Nullable_h - -#include "mozilla/Assertions.h" - -namespace mozilla { -namespace dom { - -// Support for nullable types -template <typename T> -struct Nullable -{ -private: - T mValue; - bool mIsNull; - -public: - Nullable() - : mIsNull(true) - {} - - Nullable(T aValue) - : mValue(aValue) - , mIsNull(false) - {} - - void SetValue(T aValue) { - mValue = aValue; - mIsNull = false; - } - - // For cases when |T| is some type with nontrivial copy behavior, we may want - // to get a reference to our internal copy of T and work with it directly - // instead of relying on the copying version of SetValue(). - T& SetValue() { - mIsNull = false; - return mValue; - } - - void SetNull() { - mIsNull = true; - } - - const T& Value() const { - MOZ_ASSERT(!mIsNull); - return mValue; - } - - T& Value() { - MOZ_ASSERT(!mIsNull); - return mValue; - } - - bool IsNull() const { - return mIsNull; - } -}; - -} // namespace dom -} // namespace mozilla - -#endif /* mozilla_dom_Nullable_h */ diff --git a/components/script/dom/bindings/codegen/PrimitiveConversions.h b/components/script/dom/bindings/codegen/PrimitiveConversions.h deleted file mode 100644 index 40c27425772..00000000000 --- a/components/script/dom/bindings/codegen/PrimitiveConversions.h +++ /dev/null @@ -1,350 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* vim: set ts=2 sw=2 et tw=79: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Conversions from jsval to primitive values - */ - -#ifndef mozilla_dom_PrimitiveConversions_h -#define mozilla_dom_PrimitiveConversions_h - -#include <limits> -#include <math.h> -#include "mozilla/Assertions.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/FloatingPoint.h" -#include "xpcpublic.h" - -namespace mozilla { -namespace dom { - -template<typename T> -struct TypeName { -}; - -template<> -struct TypeName<int8_t> { - static const char* value() { - return "byte"; - } -}; -template<> -struct TypeName<uint8_t> { - static const char* value() { - return "octet"; - } -}; -template<> -struct TypeName<int16_t> { - static const char* value() { - return "short"; - } -}; -template<> -struct TypeName<uint16_t> { - static const char* value() { - return "unsigned short"; - } -}; -template<> -struct TypeName<int32_t> { - static const char* value() { - return "long"; - } -}; -template<> -struct TypeName<uint32_t> { - static const char* value() { - return "unsigned long"; - } -}; -template<> -struct TypeName<int64_t> { - static const char* value() { - return "long long"; - } -}; -template<> -struct TypeName<uint64_t> { - static const char* value() { - return "unsigned long long"; - } -}; - - -enum ConversionBehavior { - eDefault, - eEnforceRange, - eClamp -}; - -template<typename T, ConversionBehavior B> -struct PrimitiveConversionTraits { -}; - -template<typename T> -struct DisallowedConversion { - typedef int jstype; - typedef int intermediateType; - -private: - static inline bool converter(JSContext* cx, JS::Value v, jstype* retval) { - MOZ_NOT_REACHED("This should never be instantiated!"); - return false; - } -}; - -struct PrimitiveConversionTraits_smallInt { - // The output of JS::ToInt32 is determined as follows: - // 1) The value is converted to a double - // 2) Anything that's not a finite double returns 0 - // 3) The double is rounded towards zero to the nearest integer - // 4) The resulting integer is reduced mod 2^32. The output of this - // operation is an integer in the range [0, 2^32). - // 5) If the resulting number is >= 2^31, 2^32 is subtracted from it. - // - // The result of all this is a number in the range [-2^31, 2^31) - // - // WebIDL conversions for the 8-bit, 16-bit, and 32-bit integer types - // are defined in the same way, except that step 4 uses reduction mod - // 2^8 and 2^16 for the 8-bit and 16-bit types respectively, and step 5 - // is only done for the signed types. - // - // C/C++ define integer conversion semantics to unsigned types as taking - // your input integer mod (1 + largest value representable in the - // unsigned type). Since 2^32 is zero mod 2^8, 2^16, and 2^32, - // converting to the unsigned int of the relevant width will correctly - // perform step 4; in particular, the 2^32 possibly subtracted in step 5 - // will become 0. - // - // Once we have step 4 done, we're just going to assume 2s-complement - // representation and cast directly to the type we really want. - // - // So we can cast directly for all unsigned types and for int32_t; for - // the smaller-width signed types we need to cast through the - // corresponding unsigned type. - typedef int32_t jstype; - typedef int32_t intermediateType; - static inline bool converter(JSContext* cx, JS::Value v, jstype* retval) { - return JS::ToInt32(cx, v, retval); - } -}; -template<> -struct PrimitiveConversionTraits<int8_t, eDefault> : PrimitiveConversionTraits_smallInt { - typedef uint8_t intermediateType; -}; -template<> -struct PrimitiveConversionTraits<uint8_t, eDefault> : PrimitiveConversionTraits_smallInt { -}; -template<> -struct PrimitiveConversionTraits<int16_t, eDefault> : PrimitiveConversionTraits_smallInt { - typedef uint16_t intermediateType; -}; -template<> -struct PrimitiveConversionTraits<uint16_t, eDefault> : PrimitiveConversionTraits_smallInt { -}; -template<> -struct PrimitiveConversionTraits<int32_t, eDefault> : PrimitiveConversionTraits_smallInt { -}; -template<> -struct PrimitiveConversionTraits<uint32_t, eDefault> : PrimitiveConversionTraits_smallInt { -}; - -template<> -struct PrimitiveConversionTraits<int64_t, eDefault> { - typedef int64_t jstype; - typedef int64_t intermediateType; - static inline bool converter(JSContext* cx, JS::Value v, jstype* retval) { - return JS::ToInt64(cx, v, retval); - } -}; - -template<> -struct PrimitiveConversionTraits<uint64_t, eDefault> { - typedef uint64_t jstype; - typedef uint64_t intermediateType; - static inline bool converter(JSContext* cx, JS::Value v, jstype* retval) { - return JS::ToUint64(cx, v, retval); - } -}; - -template<typename T> -struct PrimitiveConversionTraits_Limits { - static inline T min() { - return std::numeric_limits<T>::min(); - } - static inline T max() { - return std::numeric_limits<T>::max(); - } -}; - -template<> -struct PrimitiveConversionTraits_Limits<int64_t> { - static inline int64_t min() { - return -(1LL << 53) + 1; - } - static inline int64_t max() { - return (1LL << 53) - 1; - } -}; - -template<> -struct PrimitiveConversionTraits_Limits<uint64_t> { - static inline uint64_t min() { - return 0; - } - static inline uint64_t max() { - return (1LL << 53) - 1; - } -}; - -template<typename T, bool (*Enforce)(JSContext* cx, const double& d, T* retval)> -struct PrimitiveConversionTraits_ToCheckedIntHelper { - typedef T jstype; - typedef T intermediateType; - - static inline bool converter(JSContext* cx, JS::Value v, jstype* retval) { - double intermediate; - if (!JS::ToNumber(cx, v, &intermediate)) { - return false; - } - - return Enforce(cx, intermediate, retval); - } -}; - -template<typename T> -inline bool -PrimitiveConversionTraits_EnforceRange(JSContext* cx, const double& d, T* retval) -{ - MOZ_STATIC_ASSERT(std::numeric_limits<T>::is_integer, - "This can only be applied to integers!"); - - if (!MOZ_DOUBLE_IS_FINITE(d)) { - return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_NON_FINITE, TypeName<T>::value()); - } - - bool neg = (d < 0); - double rounded = floor(neg ? -d : d); - rounded = neg ? -rounded : rounded; - if (rounded < PrimitiveConversionTraits_Limits<T>::min() || - rounded > PrimitiveConversionTraits_Limits<T>::max()) { - return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_OUT_OF_RANGE, TypeName<T>::value()); - } - - *retval = static_cast<T>(rounded); - return true; -} - -template<typename T> -struct PrimitiveConversionTraits<T, eEnforceRange> : - public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_EnforceRange<T> > { -}; - -template<typename T> -inline bool -PrimitiveConversionTraits_Clamp(JSContext* cx, const double& d, T* retval) -{ - MOZ_STATIC_ASSERT(std::numeric_limits<T>::is_integer, - "This can only be applied to integers!"); - - if (MOZ_DOUBLE_IS_NaN(d)) { - *retval = 0; - return true; - } - if (d >= PrimitiveConversionTraits_Limits<T>::max()) { - *retval = PrimitiveConversionTraits_Limits<T>::max(); - return true; - } - if (d <= PrimitiveConversionTraits_Limits<T>::min()) { - *retval = PrimitiveConversionTraits_Limits<T>::min(); - return true; - } - - MOZ_ASSERT(MOZ_DOUBLE_IS_FINITE(d)); - - // Banker's rounding (round ties towards even). - // We move away from 0 by 0.5f and then truncate. That gets us the right - // answer for any starting value except plus or minus N.5. With a starting - // value of that form, we now have plus or minus N+1. If N is odd, this is - // the correct result. If N is even, plus or minus N is the correct result. - double toTruncate = (d < 0) ? d - 0.5 : d + 0.5; - - T truncated(toTruncate); - - if (truncated == toTruncate) { - /* - * It was a tie (since moving away from 0 by 0.5 gave us the exact integer - * we want). Since we rounded away from 0, we either already have an even - * number or we have an odd number but the number we want is one closer to - * 0. So just unconditionally masking out the ones bit should do the trick - * to get us the value we want. - */ - truncated &= ~1; - } - - *retval = truncated; - return true; -} - -template<typename T> -struct PrimitiveConversionTraits<T, eClamp> : - public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_Clamp<T> > { -}; - - -template<ConversionBehavior B> -struct PrimitiveConversionTraits<bool, B> : public DisallowedConversion<bool> {}; - -template<> -struct PrimitiveConversionTraits<bool, eDefault> { - typedef JSBool jstype; - typedef bool intermediateType; - static inline bool converter(JSContext* /* unused */, JS::Value v, jstype* retval) { - *retval = JS::ToBoolean(v); - return true; - } -}; - - -template<ConversionBehavior B> -struct PrimitiveConversionTraits<float, B> : public DisallowedConversion<float> {}; - -template<ConversionBehavior B> -struct PrimitiveConversionTraits<double, B> : public DisallowedConversion<double> {}; - -struct PrimitiveConversionTraits_float { - typedef double jstype; - typedef double intermediateType; - static inline bool converter(JSContext* cx, JS::Value v, jstype* retval) { - return JS::ToNumber(cx, v, retval); - } -}; - -template<> -struct PrimitiveConversionTraits<float, eDefault> : PrimitiveConversionTraits_float { -}; -template<> -struct PrimitiveConversionTraits<double, eDefault> : PrimitiveConversionTraits_float { -}; - - -template<typename T, ConversionBehavior B> -bool ValueToPrimitive(JSContext* cx, JS::Value v, T* retval) -{ - typename PrimitiveConversionTraits<T, B>::jstype t; - if (!PrimitiveConversionTraits<T, B>::converter(cx, v, &t)) - return false; - - *retval = - static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t); - return true; -} - -} // namespace dom -} // namespace mozilla - -#endif /* mozilla_dom_PrimitiveConversions_h */ diff --git a/components/script/dom/bindings/codegen/RegisterBindings.h b/components/script/dom/bindings/codegen/RegisterBindings.h deleted file mode 100644 index 7d83a747cc3..00000000000 --- a/components/script/dom/bindings/codegen/RegisterBindings.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef mozilla_dom_RegisterBindings_h__ -#define mozilla_dom_RegisterBindings_h__ - - -namespace mozilla { -namespace dom { -void -Register(nsScriptNameSpaceManager* aNameSpaceManager); - -} // namespace dom -} // namespace mozilla - - -#endif // mozilla_dom_RegisterBindings_h__ diff --git a/components/script/dom/bindings/codegen/TypedArray.h b/components/script/dom/bindings/codegen/TypedArray.h deleted file mode 100644 index 2a6f17bcb96..00000000000 --- a/components/script/dom/bindings/codegen/TypedArray.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* vim: set ts=2 sw=2 et tw=79: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_TypedArray_h -#define mozilla_dom_TypedArray_h - -#include "jsfriendapi.h" - -namespace mozilla { -namespace dom { - -/* - * Various typed array classes for argument conversion. We have a base class - * that has a way of initializing a TypedArray from an existing typed array, and - * a subclass of the base class that supports creation of a relevant typed array - * or array buffer object. - */ -template<typename T, - JSObject* UnboxArray(JSContext*, JSObject*, uint32_t*, T**)> -struct TypedArray_base { - TypedArray_base(JSContext* cx, JSObject* obj) - { - mObj = UnboxArray(cx, obj, &mLength, &mData); - } - -private: - T* mData; - uint32_t mLength; - JSObject* mObj; - -public: - inline bool inited() const { - return !!mObj; - } - - inline T *Data() const { - MOZ_ASSERT(inited()); - return mData; - } - - inline uint32_t Length() const { - MOZ_ASSERT(inited()); - return mLength; - } - - inline JSObject *Obj() const { - MOZ_ASSERT(inited()); - return mObj; - } -}; - - -template<typename T, - T* GetData(JSObject*, JSContext*), - JSObject* UnboxArray(JSContext*, JSObject*, uint32_t*, T**), - JSObject* CreateNew(JSContext*, uint32_t)> -struct TypedArray : public TypedArray_base<T,UnboxArray> { - TypedArray(JSContext* cx, JSObject* obj) : - TypedArray_base<T,UnboxArray>(cx, obj) - {} - - static inline JSObject* - Create(JSContext* cx, nsWrapperCache* creator, uint32_t length, - const T* data = NULL) { - JSObject* creatorWrapper; - Maybe<JSAutoCompartment> ac; - if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) { - ac.construct(cx, creatorWrapper); - } - JSObject* obj = CreateNew(cx, length); - if (!obj) { - return NULL; - } - if (data) { - T* buf = static_cast<T*>(GetData(obj, cx)); - memcpy(buf, data, length*sizeof(T)); - } - return obj; - } -}; - -typedef TypedArray<int8_t, JS_GetInt8ArrayData, JS_GetObjectAsInt8Array, - JS_NewInt8Array> - Int8Array; -typedef TypedArray<uint8_t, JS_GetUint8ArrayData, - JS_GetObjectAsUint8Array, JS_NewUint8Array> - Uint8Array; -typedef TypedArray<uint8_t, JS_GetUint8ClampedArrayData, - JS_GetObjectAsUint8ClampedArray, JS_NewUint8ClampedArray> - Uint8ClampedArray; -typedef TypedArray<int16_t, JS_GetInt16ArrayData, - JS_GetObjectAsInt16Array, JS_NewInt16Array> - Int16Array; -typedef TypedArray<uint16_t, JS_GetUint16ArrayData, - JS_GetObjectAsUint16Array, JS_NewUint16Array> - Uint16Array; -typedef TypedArray<int32_t, JS_GetInt32ArrayData, - JS_GetObjectAsInt32Array, JS_NewInt32Array> - Int32Array; -typedef TypedArray<uint32_t, JS_GetUint32ArrayData, - JS_GetObjectAsUint32Array, JS_NewUint32Array> - Uint32Array; -typedef TypedArray<float, JS_GetFloat32ArrayData, - JS_GetObjectAsFloat32Array, JS_NewFloat32Array> - Float32Array; -typedef TypedArray<double, JS_GetFloat64ArrayData, - JS_GetObjectAsFloat64Array, JS_NewFloat64Array> - Float64Array; -typedef TypedArray_base<uint8_t, JS_GetObjectAsArrayBufferView> - ArrayBufferView; -typedef TypedArray<uint8_t, JS_GetArrayBufferData, - JS_GetObjectAsArrayBuffer, JS_NewArrayBuffer> - ArrayBuffer; - -} // namespace dom -} // namespace mozilla - -#endif /* mozilla_dom_TypedArray_h */ |