Esempio n. 1
0
// static
XPCNativeInterface*
XPCNativeInterface::NewInstance(XPCCallContext& ccx,
                                nsIInterfaceInfo* aInfo)
{
    static const PRUint16 MAX_LOCAL_MEMBER_COUNT = 16;
    XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT];
    XPCNativeInterface* obj = nsnull;
    XPCNativeMember* members = nsnull;

    int i;
    JSBool failed = false;
    PRUint16 constCount;
    PRUint16 methodCount;
    PRUint16 totalCount;
    PRUint16 realTotalCount = 0;
    XPCNativeMember* cur;
    JSString* str = NULL;
    jsid name;
    jsid interfaceName;

    // XXX Investigate lazy init? This is a problem given the
    // 'placement new' scheme - we need to at least know how big to make
    // the object. We might do a scan of methods to determine needed size,
    // then make our object, but avoid init'ing *any* members until asked?
    // Find out how often we create these objects w/o really looking at
    // (or using) the members.

    bool canScript;
    if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
        return nsnull;

    if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
        NS_FAILED(aInfo->GetConstantCount(&constCount)))
        return nsnull;

    // If the interface does not have nsISupports in its inheritance chain
    // then we know we can't reflect its methods. However, some interfaces that
    // are used just to reflect constants are declared this way. We need to
    // go ahead and build the thing. But, we'll ignore whatever methods it may
    // have.
    if (!nsXPConnect::IsISupportsDescendant(aInfo))
        methodCount = 0;

    totalCount = methodCount + constCount;

    if (totalCount > MAX_LOCAL_MEMBER_COUNT) {
        members = new XPCNativeMember[totalCount];
        if (!members)
            return nsnull;
    } else {
        members = local_members;
    }

    // NOTE: since getters and setters share a member, we might not use all
    // of the member objects.

    for (i = 0; i < methodCount; i++) {
        const nsXPTMethodInfo* info;
        if (NS_FAILED(aInfo->GetMethodInfo(i, &info))) {
            failed = true;
            break;
        }

        // don't reflect Addref or Release
        if (i == 1 || i == 2)
            continue;

        if (!XPCConvert::IsMethodReflectable(*info))
            continue;

        str = JS_InternString(ccx, info->GetName());
        if (!str) {
            NS_ERROR("bad method name");
            failed = true;
            break;
        }
        name = INTERNED_STRING_TO_JSID(ccx, str);

        if (info->IsSetter()) {
            NS_ASSERTION(realTotalCount,"bad setter");
            // Note: ASSUMES Getter/Setter pairs are next to each other
            // This is a rule of the typelib spec.
            cur = &members[realTotalCount-1];
            NS_ASSERTION(cur->GetName() == name,"bad setter");
            NS_ASSERTION(cur->IsReadOnlyAttribute(),"bad setter");
            NS_ASSERTION(cur->GetIndex() == i-1,"bad setter");
            cur->SetWritableAttribute();
        } else {
            // XXX need better way to find dups
            // NS_ASSERTION(!LookupMemberByID(name),"duplicate method name");
            cur = &members[realTotalCount++];
            cur->SetName(name);
            if (info->IsGetter())
                cur->SetReadOnlyAttribute(i);
            else
                cur->SetMethod(i);
        }
    }

    if (!failed) {
        for (i = 0; i < constCount; i++) {
            const nsXPTConstant* constant;
            if (NS_FAILED(aInfo->GetConstant(i, &constant))) {
                failed = true;
                break;
            }

            str = JS_InternString(ccx, constant->GetName());
            if (!str) {
                NS_ERROR("bad constant name");
                failed = true;
                break;
            }
            name = INTERNED_STRING_TO_JSID(ccx, str);

            // XXX need better way to find dups
            //NS_ASSERTION(!LookupMemberByID(name),"duplicate method/constant name");

            cur = &members[realTotalCount++];
            cur->SetName(name);
            cur->SetConstant(i);
        }
    }

    if (!failed) {
        const char* bytes;
        if (NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
            nsnull == (str = JS_InternString(ccx, bytes))) {
            failed = true;
        }
        interfaceName = INTERNED_STRING_TO_JSID(ccx, str);
    }

    if (!failed) {
        // Use placement new to create an object with the right amount of space
        // to hold the members array
        int size = sizeof(XPCNativeInterface);
        if (realTotalCount > 1)
            size += (realTotalCount - 1) * sizeof(XPCNativeMember);
        void* place = new char[size];
        if (place)
            obj = new(place) XPCNativeInterface(aInfo, interfaceName);

        if (obj) {
            obj->mMemberCount = realTotalCount;
            // copy valid members
            if (realTotalCount)
                memcpy(obj->mMembers, members,
                       realTotalCount * sizeof(XPCNativeMember));
        }
    }

    if (members && members != local_members)
        delete [] members;

    return obj;
}
// static
XPCNativeInterface*
XPCNativeInterface::NewInstance(nsIInterfaceInfo* aInfo)
{
    AutoJSContext cx;
    static const uint16_t MAX_LOCAL_MEMBER_COUNT = 16;
    XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT];
    XPCNativeInterface* obj = nullptr;
    XPCNativeMember* members = nullptr;

    int i;
    bool failed = false;
    uint16_t constCount;
    uint16_t methodCount;
    uint16_t totalCount;
    uint16_t realTotalCount = 0;
    XPCNativeMember* cur;
    RootedString str(cx);
    RootedId interfaceName(cx);

    // XXX Investigate lazy init? This is a problem given the
    // 'placement new' scheme - we need to at least know how big to make
    // the object. We might do a scan of methods to determine needed size,
    // then make our object, but avoid init'ing *any* members until asked?
    // Find out how often we create these objects w/o really looking at
    // (or using) the members.

    bool canScript;
    if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
        return nullptr;

    bool mainProcessScriptableOnly;
    if (NS_FAILED(aInfo->IsMainProcessScriptableOnly(&mainProcessScriptableOnly)))
        return nullptr;
    if (mainProcessScriptableOnly && !XRE_IsParentProcess()) {
        nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
        if (console) {
            const char* intfNameChars;
            aInfo->GetNameShared(&intfNameChars);
            nsPrintfCString errorMsg("Use of %s in content process is deprecated.", intfNameChars);

            nsAutoString filename;
            uint32_t lineno = 0, column = 0;
            nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column);
            nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
            error->Init(NS_ConvertUTF8toUTF16(errorMsg),
                        filename, EmptyString(),
                        lineno, column, nsIScriptError::warningFlag, "chrome javascript");
            console->LogMessage(error);
        }
    }

    if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
            NS_FAILED(aInfo->GetConstantCount(&constCount)))
        return nullptr;

    // If the interface does not have nsISupports in its inheritance chain
    // then we know we can't reflect its methods. However, some interfaces that
    // are used just to reflect constants are declared this way. We need to
    // go ahead and build the thing. But, we'll ignore whatever methods it may
    // have.
    if (!nsXPConnect::IsISupportsDescendant(aInfo))
        methodCount = 0;

    totalCount = methodCount + constCount;

    if (totalCount > MAX_LOCAL_MEMBER_COUNT) {
        members = new XPCNativeMember[totalCount];
        if (!members)
            return nullptr;
    } else {
        members = local_members;
    }

    // NOTE: since getters and setters share a member, we might not use all
    // of the member objects.

    for (i = 0; i < methodCount; i++) {
        const nsXPTMethodInfo* info;
        if (NS_FAILED(aInfo->GetMethodInfo(i, &info))) {
            failed = true;
            break;
        }

        // don't reflect Addref or Release
        if (i == 1 || i == 2)
            continue;

        if (!XPCConvert::IsMethodReflectable(*info))
            continue;

        str = JS_AtomizeAndPinString(cx, info->GetName());
        if (!str) {
            NS_ERROR("bad method name");
            failed = true;
            break;
        }
        jsid name = INTERNED_STRING_TO_JSID(cx, str);

        if (info->IsSetter()) {
            MOZ_ASSERT(realTotalCount,"bad setter");
            // Note: ASSUMES Getter/Setter pairs are next to each other
            // This is a rule of the typelib spec.
            cur = &members[realTotalCount-1];
            MOZ_ASSERT(cur->GetName() == name,"bad setter");
            MOZ_ASSERT(cur->IsReadOnlyAttribute(),"bad setter");
            MOZ_ASSERT(cur->GetIndex() == i-1,"bad setter");
            cur->SetWritableAttribute();
        } else {
            // XXX need better way to find dups
            // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method name");
            if (realTotalCount == XPCNativeMember::GetMaxIndexInInterface()) {
                NS_WARNING("Too many members in interface");
                failed = true;
                break;
            }
            cur = &members[realTotalCount];
            cur->SetName(name);
            if (info->IsGetter())
                cur->SetReadOnlyAttribute(i);
            else
                cur->SetMethod(i);
            cur->SetIndexInInterface(realTotalCount);
            ++realTotalCount;
        }
    }

    if (!failed) {
        for (i = 0; i < constCount; i++) {
            RootedValue constant(cx);
            nsXPIDLCString namestr;
            if (NS_FAILED(aInfo->GetConstant(i, &constant, getter_Copies(namestr)))) {
                failed = true;
                break;
            }

            str = JS_AtomizeAndPinString(cx, namestr);
            if (!str) {
                NS_ERROR("bad constant name");
                failed = true;
                break;
            }
            jsid name = INTERNED_STRING_TO_JSID(cx, str);

            // XXX need better way to find dups
            //MOZ_ASSERT(!LookupMemberByID(name),"duplicate method/constant name");
            if (realTotalCount == XPCNativeMember::GetMaxIndexInInterface()) {
                NS_WARNING("Too many members in interface");
                failed = true;
                break;
            }
            cur = &members[realTotalCount];
            cur->SetName(name);
            cur->SetConstant(i);
            cur->SetIndexInInterface(realTotalCount);
            ++realTotalCount;
        }
    }

    if (!failed) {
        const char* bytes;
        if (NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
                nullptr == (str = JS_AtomizeAndPinString(cx, bytes))) {
            failed = true;
        }
        interfaceName = INTERNED_STRING_TO_JSID(cx, str);
    }

    if (!failed) {
        // Use placement new to create an object with the right amount of space
        // to hold the members array
        int size = sizeof(XPCNativeInterface);
        if (realTotalCount > 1)
            size += (realTotalCount - 1) * sizeof(XPCNativeMember);
        void* place = new char[size];
        if (place)
            obj = new(place) XPCNativeInterface(aInfo, interfaceName);

        if (obj) {
            obj->mMemberCount = realTotalCount;
            // copy valid members
            if (realTotalCount)
                memcpy(obj->mMembers, members,
                       realTotalCount * sizeof(XPCNativeMember));
        }
    }

    if (members && members != local_members)
        delete [] members;

    return obj;
}