// 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; }