Merge inbound to mozilla-central. a=merge

This commit is contained in:
Csoregi Natalia 2018-05-15 12:53:24 +03:00
commit 00dd116638
82 changed files with 1573 additions and 1609 deletions

View File

@ -80,7 +80,31 @@ ShowError(DWORD aError = ::GetLastError())
::LocalFree(rawMsgBuf);
}
static wchar_t gAbsPath[MAX_PATH];
static bool
SetArgv0ToFullBinaryPath(wchar_t* aArgv[])
{
DWORD bufLen = MAX_PATH;
mozilla::UniquePtr<wchar_t[]> buf;
while (true) {
buf = mozilla::MakeUnique<wchar_t[]>(bufLen);
DWORD retLen = ::GetModuleFileNameW(nullptr, buf.get(), bufLen);
if (!retLen) {
return false;
}
if (retLen == bufLen && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
bufLen *= 2;
continue;
}
break;
}
// We intentionally leak buf into argv[0]
aArgv[0] = buf.release();
return true;
}
namespace mozilla {
@ -112,18 +136,11 @@ LauncherMain(int argc, wchar_t* argv[])
}
}
// Convert argv[0] to an absolute path if necessary
DWORD absPathLen = ::SearchPathW(nullptr, argv[0], L".exe",
ArrayLength(gAbsPath), gAbsPath, nullptr);
if (!absPathLen) {
if (!SetArgv0ToFullBinaryPath(argv)) {
ShowError();
return 1;
}
if (absPathLen < ArrayLength(gAbsPath)) {
argv[0] = gAbsPath;
}
// If we're elevated, we should relaunch ourselves as a normal user
Maybe<bool> isElevated = IsElevated();
if (!isElevated) {

View File

@ -25,6 +25,7 @@ skip-if = !e10s # Pref and test only relevant for e10s.
[browser_newwindow_tabstrip_overflow.js]
[browser_opened_file_tab_navigated_to_web.js]
[browser_new_tab_insert_position.js]
skip-if = (debug && os == 'linux' && bits == 32) #Bug 1455882, disabled on Linux32 for almost permafailing
support-files = file_new_tab_page.html
[browser_overflowScroll.js]
[browser_pinnedTabs.js]

View File

@ -283,5 +283,48 @@ DocumentOrShadowRoot::ElementsFromPointHelper(float aX, float aY,
}
}
Element*
DocumentOrShadowRoot::AddIDTargetObserver(nsAtom* aID,
IDTargetObserver aObserver,
void* aData, bool aForImage)
{
nsDependentAtomString id(aID);
if (!CheckGetElementByIdArg(id)) {
return nullptr;
}
nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aID);
NS_ENSURE_TRUE(entry, nullptr);
entry->AddContentChangeCallback(aObserver, aData, aForImage);
return aForImage ? entry->GetImageIdElement() : entry->GetIdElement();
}
void
DocumentOrShadowRoot::RemoveIDTargetObserver(nsAtom* aID,
IDTargetObserver aObserver,
void* aData, bool aForImage)
{
nsDependentAtomString id(aID);
if (!CheckGetElementByIdArg(id)) {
return;
}
nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aID);
if (!entry) {
return;
}
entry->RemoveContentChangeCallback(aObserver, aData, aForImage);
}
void
DocumentOrShadowRoot::ReportEmptyGetElementByIdArg()
{
nsContentUtils::ReportEmptyGetElementByIdArg(AsNode().OwnerDoc());
}
}
}

View File

@ -139,6 +139,54 @@ public:
void ElementsFromPointHelper(float aX, float aY, uint32_t aFlags,
nsTArray<RefPtr<mozilla::dom::Element>>& aElements);
/**
* This gets fired when the element that an id refers to changes.
* This fires at difficult times. It is generally not safe to do anything
* which could modify the DOM in any way. Use
* nsContentUtils::AddScriptRunner.
* @return true to keep the callback in the callback set, false
* to remove it.
*/
typedef bool (* IDTargetObserver)(Element* aOldElement,
Element* aNewelement, void* aData);
/**
* Add an IDTargetObserver for a specific ID. The IDTargetObserver
* will be fired whenever the content associated with the ID changes
* in the future. If aForImage is true, mozSetImageElement can override
* what content is associated with the ID. In that case the IDTargetObserver
* will be notified at those times when the result of LookupImageElement
* changes.
* At most one (aObserver, aData, aForImage) triple can be
* registered for each ID.
* @return the content currently associated with the ID.
*/
Element* AddIDTargetObserver(nsAtom* aID, IDTargetObserver aObserver,
void* aData, bool aForImage);
/**
* Remove the (aObserver, aData, aForImage) triple for a specific ID, if
* registered.
*/
void RemoveIDTargetObserver(nsAtom* aID, IDTargetObserver aObserver,
void* aData, bool aForImage);
/**
* Check that aId is not empty and log a message to the console
* service if it is.
* @returns true if aId looks correct, false otherwise.
*/
inline bool CheckGetElementByIdArg(const nsAString& aId)
{
if (aId.IsEmpty()) {
ReportEmptyGetElementByIdArg();
return false;
}
return true;
}
void ReportEmptyGetElementByIdArg();
protected:
nsIContent* Retarget(nsIContent* aContent) const;

View File

@ -14,6 +14,7 @@
#include "AnimationCommon.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Attr.h"
#include "mozilla/dom/Flex.h"
@ -1247,6 +1248,10 @@ Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError)
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
if (StaticPrefs::dom_webcomponents_shadowdom_report_usage()) {
OwnerDoc()->ReportShadowDOMUsage();
}
/**
* 5. Set context objects shadow root to shadow.
*/

View File

@ -1456,6 +1456,7 @@ nsIDocument::nsIDocument()
mWidthStrEmpty(false),
mParserAborted(false),
mReportedUseCounters(false),
mHasReportedShadowDOMUsage(false),
#ifdef DEBUG
mWillReparent(false),
#endif
@ -5091,45 +5092,6 @@ nsDocument::BeginLoad()
NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
}
void
nsIDocument::ReportEmptyGetElementByIdArg()
{
nsContentUtils::ReportEmptyGetElementByIdArg(this);
}
Element*
nsIDocument::AddIDTargetObserver(nsAtom* aID, IDTargetObserver aObserver,
void* aData, bool aForImage)
{
nsDependentAtomString id(aID);
if (!CheckGetElementByIdArg(id))
return nullptr;
nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aID);
NS_ENSURE_TRUE(entry, nullptr);
entry->AddContentChangeCallback(aObserver, aData, aForImage);
return aForImage ? entry->GetImageIdElement() : entry->GetIdElement();
}
void
nsIDocument::RemoveIDTargetObserver(nsAtom* aID, IDTargetObserver aObserver,
void* aData, bool aForImage)
{
nsDependentAtomString id(aID);
if (!CheckGetElementByIdArg(id))
return;
nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aID);
if (!entry) {
return;
}
entry->RemoveContentChangeCallback(aObserver, aData, aForImage);
}
void
nsIDocument::MozSetImageElement(const nsAString& aImageElementId,
Element* aElement)
@ -13259,3 +13221,27 @@ nsIDocument::ModuleScriptsEnabled()
return nsContentUtils::IsChromeDoc(this) || sEnabledForContent;
}
void
nsIDocument::ReportShadowDOMUsage()
{
if (mHasReportedShadowDOMUsage) {
return;
}
nsIDocument* topLevel = GetTopLevelContentDocument();
if (topLevel && !topLevel->mHasReportedShadowDOMUsage) {
topLevel->mHasReportedShadowDOMUsage = true;
nsString uri;
Unused << topLevel->GetDocumentURI(uri);
if (!uri.IsEmpty()) {
nsAutoString msg = NS_LITERAL_STRING("Shadow DOM used in [") + uri +
NS_LITERAL_STRING("] or in some of its subdocuments.");
nsContentUtils::ReportToConsoleNonLocalized(msg, nsIScriptError::infoFlag,
NS_LITERAL_CSTRING("DOM"),
topLevel);
}
}
mHasReportedShadowDOMUsage = true;
}

View File

@ -799,53 +799,6 @@ public:
mCharacterSetSource = aCharsetSource;
}
/**
* This gets fired when the element that an id refers to changes.
* This fires at difficult times. It is generally not safe to do anything
* which could modify the DOM in any way. Use
* nsContentUtils::AddScriptRunner.
* @return true to keep the callback in the callback set, false
* to remove it.
*/
typedef bool (* IDTargetObserver)(Element* aOldElement,
Element* aNewelement, void* aData);
/**
* Add an IDTargetObserver for a specific ID. The IDTargetObserver
* will be fired whenever the content associated with the ID changes
* in the future. If aForImage is true, mozSetImageElement can override
* what content is associated with the ID. In that case the IDTargetObserver
* will be notified at those times when the result of LookupImageElement
* changes.
* At most one (aObserver, aData, aForImage) triple can be
* registered for each ID.
* @return the content currently associated with the ID.
*/
Element* AddIDTargetObserver(nsAtom* aID, IDTargetObserver aObserver,
void* aData, bool aForImage);
/**
* Remove the (aObserver, aData, aForImage) triple for a specific ID, if
* registered.
*/
void RemoveIDTargetObserver(nsAtom* aID, IDTargetObserver aObserver,
void* aData, bool aForImage);
/**
* Check that aId is not empty and log a message to the console
* service if it is.
* @returns true if aId looks correct, false otherwise.
*/
inline bool CheckGetElementByIdArg(const nsAString& aId)
{
if (aId.IsEmpty()) {
ReportEmptyGetElementByIdArg();
return false;
}
return true;
}
void ReportEmptyGetElementByIdArg();
/**
* Get the Content-Type of this document.
*/
@ -3583,6 +3536,8 @@ public:
*/
nsIContent* GetContentInThisDocument(nsIFrame* aFrame) const;
void ReportShadowDOMUsage();
protected:
already_AddRefed<nsIPrincipal> MaybeDowngradePrincipal(nsIPrincipal* aPrincipal);
@ -4099,6 +4054,8 @@ protected:
// that we only report them once for the document.
bool mReportedUseCounters: 1;
bool mHasReportedShadowDOMUsage: 1;
#ifdef DEBUG
public:
bool mWillReparent: 1;

View File

@ -2268,10 +2268,9 @@ nsPluginHost::UpdatePluginBlocklistState(nsPluginTag* aPluginTag, bool aShouldSo
return;
}
// Asynchronously get the blocklist state.
nsCOMPtr<nsISupports> result;
RefPtr<Promise> promise;
blocklist->GetPluginBlocklistState(aPluginTag, EmptyString(),
EmptyString(), getter_AddRefs(result));
RefPtr<Promise> promise = do_QueryObject(result);
EmptyString(), getter_AddRefs(promise));
MOZ_ASSERT(promise, "Should always get a promise for plugin blocklist state.");
if (promise) {
promise->AppendNativeHandler(new mozilla::plugins::BlocklistPromiseHandler(aPluginTag, aShouldSoftblock));

View File

@ -541,14 +541,13 @@ PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aReques
ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
}
nsCOMPtr<nsISupports> promise;
RefPtr<Promise> promise;
rv = glue->SendRequest(url, sessionId, device, getter_AddRefs(promise));
if (NS_WARN_IF(NS_FAILED(rv))) {
ctrlChannel->Disconnect(rv);
return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
}
nsCOMPtr<Promise> realPromise = do_QueryInterface(promise);
static_cast<PresentationPresentingInfo*>(info.get())->SetPromise(realPromise);
static_cast<PresentationPresentingInfo*>(info.get())->SetPromise(promise);
return NS_OK;
}

View File

@ -23,7 +23,7 @@ interface nsIPresentationRequestUIGlue : nsISupports
*
* @return A promise that resolves to the opening frame.
*/
nsISupports sendRequest(in DOMString url,
in DOMString sessionId,
in nsIPresentationDevice device);
Promise sendRequest(in DOMString url,
in DOMString sessionId,
in nsIPresentationDevice device);
};

View File

@ -63,13 +63,8 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Promise)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPromiseObj);
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(Promise)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Promise)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Promise)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(Promise)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Promise, AddRef);
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Promise, Release);
Promise::Promise(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal)

View File

@ -32,21 +32,15 @@ class PromiseInit;
class PromiseNativeHandler;
class PromiseDebugging;
#define NS_PROMISE_IID \
{ 0x1b8d6215, 0x3e67, 0x43ba, \
{ 0x8a, 0xf9, 0x31, 0x5e, 0x8f, 0xce, 0x75, 0x65 } }
class Promise : public nsISupports,
public SupportsWeakPtr<Promise>
class Promise : public SupportsWeakPtr<Promise>
{
friend class PromiseTask;
friend class PromiseWorkerProxy;
friend class PromiseWorkerProxyRunnable;
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROMISE_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Promise)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Promise)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Promise)
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Promise)
// Promise creation tries to create a JS reflector for the Promise, so is
@ -204,8 +198,6 @@ private:
JS::Heap<JSObject*> mPromiseObj;
};
NS_DEFINE_STATIC_IID_ACCESSOR(Promise, NS_PROMISE_IID)
} // namespace dom
} // namespace mozilla

View File

@ -1244,8 +1244,6 @@ var interfaceNamesInGlobalScope =
{name: "XMLHttpRequestUpload", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XMLSerializer", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XMLStylesheetProcessingInstruction", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XPathEvaluator", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -4,12 +4,17 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://www.w3.org/TR/2012/WD-dom-20120105/
* https://dom.spec.whatwg.org/#interface-processinginstruction
* https://drafts.csswg.org/cssom/#requirements-on-user-agents-implementing-the-xml-stylesheet-processing-instruction
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
// https://dom.spec.whatwg.org/#interface-processinginstruction
interface ProcessingInstruction : CharacterData {
readonly attribute DOMString target;
};
// https://drafts.csswg.org/cssom/#requirements-on-user-agents-implementing-the-xml-stylesheet-processing-instruction
ProcessingInstruction implements LinkStyle;

View File

@ -1,9 +0,0 @@
/* -*- Mode: IDL; 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/.
*/
interface XMLStylesheetProcessingInstruction : ProcessingInstruction {
readonly attribute StyleSheet? sheet;
};

View File

@ -941,7 +941,6 @@ WEBIDL_FILES = [
'XMLHttpRequestEventTarget.webidl',
'XMLHttpRequestUpload.webidl',
'XMLSerializer.webidl',
'XMLStylesheetProcessingInstruction.webidl',
'XPathEvaluator.webidl',
'XPathExpression.webidl',
'XPathNSResolver.webidl',

View File

@ -62,6 +62,8 @@ ProcessingInstruction::~ProcessingInstruction()
{
}
// If you add nsIStyleSheetLinkingElement here, make sure we actually
// implement the nsStyleLinkElement methods.
NS_IMPL_ISUPPORTS_INHERITED(ProcessingInstruction, CharacterData, nsIDOMNode)
JSObject*
@ -89,6 +91,16 @@ ProcessingInstruction::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
return do_AddRef(new ProcessingInstruction(ni.forget(), data));
}
Maybe<nsStyleLinkElement::SheetInfo>
ProcessingInstruction::GetStyleSheetInfo()
{
MOZ_ASSERT_UNREACHABLE("XMLStylesheetProcessingInstruction should override "
"this and we don't try to do stylesheet stuff. In "
"particular, we do not implement "
"nsIStyleSheetLinkingElement");
return Nothing();
}
#ifdef DEBUG
void
ProcessingInstruction::List(FILE* out, int32_t aIndent) const

View File

@ -11,12 +11,17 @@
#include "mozilla/dom/CharacterData.h"
#include "nsIDOMNode.h"
#include "nsAString.h"
#include "nsStyleLinkElement.h"
class nsIPrincipal;
class nsIURI;
namespace mozilla {
namespace dom {
class ProcessingInstruction : public CharacterData,
public nsIDOMNode
class ProcessingInstruction : public CharacterData
, public nsStyleLinkElement
, public nsIDOMNode
{
public:
ProcessingInstruction(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
@ -60,6 +65,9 @@ protected:
bool GetAttrValue(nsAtom *aName, nsAString& aValue);
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
// nsStyleLinkElement overrides, because we can't leave them pure virtual.
Maybe<SheetInfo> GetStyleSheetInfo() override;
};
} // namespace dom

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "XMLStylesheetProcessingInstruction.h"
#include "mozilla/dom/XMLStylesheetProcessingInstructionBinding.h"
#include "nsContentUtils.h"
#include "nsNetUtil.h"
@ -36,12 +35,6 @@ XMLStylesheetProcessingInstruction::~XMLStylesheetProcessingInstruction()
{
}
JSObject*
XMLStylesheetProcessingInstruction::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
return XMLStylesheetProcessingInstructionBinding::Wrap(aCx, this, aGivenProto);
}
// nsIContent
nsresult

View File

@ -17,8 +17,7 @@ namespace mozilla {
namespace dom {
class XMLStylesheetProcessingInstruction final
: public ProcessingInstruction
, public nsStyleLinkElement
: public ProcessingInstruction
{
public:
XMLStylesheetProcessingInstruction(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
@ -37,8 +36,6 @@ public:
{
}
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
// nsISupports
NS_DECL_ISUPPORTS_INHERITED

View File

@ -6,6 +6,7 @@
#include "CrashReporterHost.h"
#include "CrashReporterMetadataShmem.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/Sprintf.h"
#include "mozilla/SyncRunnable.h"
@ -275,7 +276,7 @@ CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType,
return;
}
nsCOMPtr<nsISupports> promise;
RefPtr<Promise> promise;
crashService->AddCrash(processType, crashType, aChildDumpID, getter_AddRefs(promise));
Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, telemetryKey, 1);
}

View File

@ -14,6 +14,8 @@
#include "js/TraceKind.h"
#include "js/Utility.h"
struct JSStringFinalizer;
/* These values are private to the JS engine. */
namespace js {
@ -201,6 +203,47 @@ struct Zone
}
};
struct String
{
static const uint32_t NON_ATOM_BIT = JS_BIT(0);
static const uint32_t LINEAR_BIT = JS_BIT(1);
static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
static const uint32_t PERMANENT_ATOM_MASK = NON_ATOM_BIT | JS_BIT(5);
static const uint32_t PERMANENT_ATOM_FLAGS = JS_BIT(5);
uint32_t flags;
uint32_t length;
union {
const JS::Latin1Char* nonInlineCharsLatin1;
const char16_t* nonInlineCharsTwoByte;
JS::Latin1Char inlineStorageLatin1[1];
char16_t inlineStorageTwoByte[1];
};
const JSStringFinalizer* externalFinalizer;
static bool nurseryCellIsString(const js::gc::Cell* cell) {
MOZ_ASSERT(IsInsideNursery(cell));
return reinterpret_cast<const String*>(cell)->flags & NON_ATOM_BIT;
}
static bool isPermanentAtom(const js::gc::Cell* cell) {
uint32_t flags = reinterpret_cast<const String*>(cell)->flags;
return (flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
}
};
struct Symbol {
uint32_t code_;
static const uint32_t WellKnownAPILimit = 0x80000000;
static bool isWellKnownSymbol(const js::gc::Cell* cell) {
return reinterpret_cast<const Symbol*>(cell)->code_ < WellKnownAPILimit;
}
};
} /* namespace shadow */
/**
@ -272,9 +315,12 @@ class JS_FRIEND_API(GCCellPtr)
}
MOZ_ALWAYS_INLINE bool mayBeOwnedByOtherRuntime() const {
if (is<JSString>() || is<JS::Symbol>())
return mayBeOwnedByOtherRuntimeSlow();
return false;
if (!is<JSString>() && !is<JS::Symbol>())
return false;
if (is<JSString>())
return JS::shadow::String::isPermanentAtom(asCell());
MOZ_ASSERT(is<JS::Symbol>());
return JS::shadow::Symbol::isWellKnownSymbol(asCell());
}
private:

View File

@ -42,7 +42,7 @@ install:: $(LIBRARY_NAME).pc
$(SYSINSTALL) $(JS_LIBRARY_NAME).pc $(DESTDIR)$(libdir)/pkgconfig
install:: ../js-config.h
$(SYSINSTALL) $^ $(DESTDIR)$(includedir)
$(SYSINSTALL) $^ $(DESTDIR)$(includedir)/$(JS_LIBRARY_NAME)
######################################################
# BEGIN SpiderMonkey header installation
@ -56,7 +56,7 @@ install:: ../js-config.h
# The overall directory structure of the installed headers looks like so:
#
# $(includedir)/
# $(LIBRARY_NAME)/
# $(JS_LIBRARY_NAME)/
# jsapi.h, jspubtd.h, etc. (all of EXPORTS)
# js/
# js/public/* headers (all are public)
@ -69,7 +69,7 @@ install:: ../js-config.h
#
install::
$(call py_action,process_install_manifest,--track install_dist_include.track --no-symlinks $(DESTDIR)$(includedir) $(DEPTH)/_build_manifests/install/dist_include)
$(call py_action,process_install_manifest,--track install_dist_include.track --no-symlinks $(DESTDIR)$(includedir)/$(JS_LIBRARY_NAME) $(DEPTH)/_build_manifests/install/dist_include)
#
# END SpiderMonkey header installation

View File

@ -255,7 +255,7 @@ Cell::getTraceKind() const
{
if (isTenured())
return asTenured().getTraceKind();
if (js::shadow::String::nurseryCellIsString(this))
if (JS::shadow::String::nurseryCellIsString(this))
return JS::TraceKind::String;
return JS::TraceKind::Object;
}

View File

@ -8448,14 +8448,6 @@ JS::GCCellPtr::outOfLineKind() const
return MapAllocToTraceKind(asCell()->asTenured().getAllocKind());
}
bool
JS::GCCellPtr::mayBeOwnedByOtherRuntimeSlow() const
{
if (is<JSString>())
return as<JSString>().isPermanentAtom();
return as<Symbol>().isWellKnownSymbol();
}
#ifdef JSGC_HASH_TABLE_CHECKS
void
js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt)

View File

@ -111,7 +111,8 @@ IterateHeapUnbarrieredForZone(JSContext* cx, JS::Zone* zone, void* data,
extern void
IterateChunks(JSContext* cx, void* data, IterateChunkCallback chunkCallback);
typedef void (*IterateScriptCallback)(JSRuntime* rt, void* data, JSScript* script);
typedef void (*IterateScriptCallback)(JSRuntime* rt, void* data, JSScript* script,
const JS::AutoRequireNoGC& nogc);
/*
* Invoke scriptCallback on every in-use script for

View File

@ -86,17 +86,18 @@ js::IterateScripts(JSContext* cx, JSCompartment* compartment,
MOZ_ASSERT(!cx->suppressGC);
AutoEmptyNursery empty(cx);
AutoPrepareForTracing prep(cx);
JS::AutoSuppressGCAnalysis nogc;
if (compartment) {
Zone* zone = compartment->zone();
for (auto script = zone->cellIter<JSScript>(empty); !script.done(); script.next()) {
if (script->compartment() == compartment)
scriptCallback(cx->runtime(), data, script);
scriptCallback(cx->runtime(), data, script, nogc);
}
} else {
for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) {
for (auto script = zone->cellIter<JSScript>(empty); !script.done(); script.next())
scriptCallback(cx->runtime(), data, script);
scriptCallback(cx->runtime(), data, script, nogc);
}
}
}

View File

@ -2,6 +2,121 @@
if (!wasmBulkMemSupported())
quit(0);
//---------------------------------------------------------------------//
//---------------------------------------------------------------------//
// Validation tests
//-----------------------------------------------------------
// Test helpers. Copied and simplified from binary.js.
load(libdir + "wasm-binary.js");
function toU8(array) {
for (let b of array)
assertEq(b < 256, true);
return Uint8Array.from(array);
}
function varU32(u32) {
assertEq(u32 >= 0, true);
assertEq(u32 < Math.pow(2,32), true);
var bytes = [];
do {
var byte = u32 & 0x7f;
u32 >>>= 7;
if (u32 != 0)
byte |= 0x80;
bytes.push(byte);
} while (u32 != 0);
return bytes;
}
function moduleHeaderThen(...rest) {
return [magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, ...rest];
}
function moduleWithSections(sectionArray) {
var bytes = moduleHeaderThen();
for (let section of sectionArray) {
bytes.push(section.name);
bytes.push(...varU32(section.body.length));
bytes.push(...section.body);
}
return toU8(bytes);
}
function sigSection(sigs) {
var body = [];
body.push(...varU32(sigs.length));
for (let sig of sigs) {
body.push(...varU32(FuncCode));
body.push(...varU32(sig.args.length));
for (let arg of sig.args)
body.push(...varU32(arg));
body.push(...varU32(sig.ret == VoidCode ? 0 : 1));
if (sig.ret != VoidCode)
body.push(...varU32(sig.ret));
}
return { name: typeId, body };
}
function declSection(decls) {
var body = [];
body.push(...varU32(decls.length));
for (let decl of decls)
body.push(...varU32(decl));
return { name: functionId, body };
}
function funcBody(func) {
var body = varU32(func.locals.length);
for (let local of func.locals)
body.push(...varU32(local));
body = body.concat(...func.body);
body.push(EndCode);
body.splice(0, 0, ...varU32(body.length));
return body;
}
function bodySection(bodies) {
var body = varU32(bodies.length).concat(...bodies);
return { name: codeId, body };
}
const v2vSig = {args:[], ret:VoidCode};
const v2vSigSection = sigSection([v2vSig]);
// Prefixed opcodes
function checkMiscPrefixed(opcode, expect_failure) {
let binary = moduleWithSections(
[v2vSigSection, declSection([0]),
bodySection(
[funcBody(
{locals:[],
body:[0x41, 0x0, 0x41, 0x0, 0x41, 0x0, // 3 x const.i32 0
MiscPrefix, opcode]})])]);
if (expect_failure) {
assertErrorMessage(() => new WebAssembly.Module(binary),
WebAssembly.CompileError, /unrecognized opcode/);
} else {
assertEq(true, WebAssembly.validate(binary));
}
}
//-----------------------------------------------------------
// Verification cases for memory.copy/fill
checkMiscPrefixed(0x3f, true); // unassigned
checkMiscPrefixed(0x40, false); // memory.copy
checkMiscPrefixed(0x41, false); // memory.fill
checkMiscPrefixed(0x42, true); // unassigned
//---------------------------------------------------------------------//
//---------------------------------------------------------------------//
// Run tests
//-----------------------------------------------------------
// Test helpers
function checkRange(arr, minIx, maxIxPlusOne, expectedValue)

View File

@ -10,7 +10,7 @@
using namespace JS;
static void
ScriptCallback(JSRuntime* rt, void* data, JSScript* script)
ScriptCallback(JSRuntime* rt, void* data, JSScript* script, const JS::AutoRequireNoGC& nogc)
{
unsigned& count = *static_cast<unsigned*>(data);
if (script->hasIonScript())

View File

@ -5043,6 +5043,7 @@ enum class SymbolCode : uint32_t {
JS_FOR_EACH_WELL_KNOWN_SYMBOL(JS_DEFINE_SYMBOL_ENUM) // SymbolCode::iterator, etc.
#undef JS_DEFINE_SYMBOL_ENUM
Limit,
WellKnownAPILimit = 0x80000000, // matches JS::shadow::Symbol::WellKnownAPILimit for inline use
InSymbolRegistry = 0xfffffffe, // created by Symbol.for() or JS::GetSymbolFor()
UniqueSymbol = 0xffffffff // created by Symbol() or JS::NewSymbol()
};

View File

@ -624,30 +624,6 @@ struct Function {
void* _1;
};
struct String
{
static const uint32_t NON_ATOM_BIT = JS_BIT(0);
static const uint32_t LINEAR_BIT = JS_BIT(1);
static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
uint32_t flags;
uint32_t length;
union {
const JS::Latin1Char* nonInlineCharsLatin1;
const char16_t* nonInlineCharsTwoByte;
JS::Latin1Char inlineStorageLatin1[1];
char16_t inlineStorageTwoByte[1];
};
const JSStringFinalizer* externalFinalizer;
static bool nurseryCellIsString(const js::gc::Cell* cell) {
MOZ_ASSERT(IsInsideNursery(cell));
return reinterpret_cast<const String*>(cell)->flags & NON_ATOM_BIT;
}
};
} /* namespace shadow */
// This is equal to |&JSObject::class_|. Use it in places where you don't want
@ -806,7 +782,7 @@ GetObjectSlot(JSObject* obj, size_t slot)
MOZ_ALWAYS_INLINE size_t
GetAtomLength(JSAtom* atom)
{
return reinterpret_cast<shadow::String*>(atom)->length;
return reinterpret_cast<JS::shadow::String*>(atom)->length;
}
static const uint32_t MaxStringLength = (1 << 28) - 1;
@ -814,37 +790,37 @@ static const uint32_t MaxStringLength = (1 << 28) - 1;
MOZ_ALWAYS_INLINE size_t
GetStringLength(JSString* s)
{
return reinterpret_cast<shadow::String*>(s)->length;
return reinterpret_cast<JS::shadow::String*>(s)->length;
}
MOZ_ALWAYS_INLINE size_t
GetFlatStringLength(JSFlatString* s)
{
return reinterpret_cast<shadow::String*>(s)->length;
return reinterpret_cast<JS::shadow::String*>(s)->length;
}
MOZ_ALWAYS_INLINE size_t
GetLinearStringLength(JSLinearString* s)
{
return reinterpret_cast<shadow::String*>(s)->length;
return reinterpret_cast<JS::shadow::String*>(s)->length;
}
MOZ_ALWAYS_INLINE bool
LinearStringHasLatin1Chars(JSLinearString* s)
{
return reinterpret_cast<shadow::String*>(s)->flags & shadow::String::LATIN1_CHARS_BIT;
return reinterpret_cast<JS::shadow::String*>(s)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
}
MOZ_ALWAYS_INLINE bool
AtomHasLatin1Chars(JSAtom* atom)
{
return reinterpret_cast<shadow::String*>(atom)->flags & shadow::String::LATIN1_CHARS_BIT;
return reinterpret_cast<JS::shadow::String*>(atom)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
}
MOZ_ALWAYS_INLINE bool
StringHasLatin1Chars(JSString* s)
{
return reinterpret_cast<shadow::String*>(s)->flags & shadow::String::LATIN1_CHARS_BIT;
return reinterpret_cast<JS::shadow::String*>(s)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
}
MOZ_ALWAYS_INLINE const JS::Latin1Char*
@ -852,7 +828,7 @@ GetLatin1LinearStringChars(const JS::AutoRequireNoGC& nogc, JSLinearString* line
{
MOZ_ASSERT(LinearStringHasLatin1Chars(linear));
using shadow::String;
using JS::shadow::String;
String* s = reinterpret_cast<String*>(linear);
if (s->flags & String::INLINE_CHARS_BIT)
return s->inlineStorageLatin1;
@ -864,7 +840,7 @@ GetTwoByteLinearStringChars(const JS::AutoRequireNoGC& nogc, JSLinearString* lin
{
MOZ_ASSERT(!LinearStringHasLatin1Chars(linear));
using shadow::String;
using JS::shadow::String;
String* s = reinterpret_cast<String*>(linear);
if (s->flags & String::INLINE_CHARS_BIT)
return s->inlineStorageTwoByte;
@ -904,7 +880,7 @@ GetTwoByteAtomChars(const JS::AutoRequireNoGC& nogc, JSAtom* atom)
MOZ_ALWAYS_INLINE bool
IsExternalString(JSString* str, const JSStringFinalizer** fin, const char16_t** chars)
{
using shadow::String;
using JS::shadow::String;
String* s = reinterpret_cast<String*>(str);
if ((s->flags & String::TYPE_FLAGS_MASK) != String::EXTERNAL_FLAGS)
@ -922,7 +898,7 @@ StringToLinearStringSlow(JSContext* cx, JSString* str);
MOZ_ALWAYS_INLINE JSLinearString*
StringToLinearString(JSContext* cx, JSString* str)
{
using shadow::String;
using JS::shadow::String;
String* s = reinterpret_cast<String*>(str);
if (MOZ_UNLIKELY(!(s->flags & String::LINEAR_BIT)))
return StringToLinearStringSlow(cx, str);

View File

@ -4589,9 +4589,10 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery
return true;
}
static void considerScript(JSRuntime* rt, void* data, JSScript* script) {
static void considerScript(JSRuntime* rt, void* data, JSScript* script,
const JS::AutoRequireNoGC& nogc) {
ScriptQuery* self = static_cast<ScriptQuery*>(data);
self->consider(script);
self->consider(script, nogc);
}
/*
@ -4599,7 +4600,7 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery
* |innermostForCompartment|, as appropriate. Set |oom| if an out of memory
* condition occurred.
*/
void consider(JSScript* script) {
void consider(JSScript* script, const JS::AutoRequireNoGC& nogc) {
// We check for presence of script->code() because it is possible that
// the script was created and thus exposed to GC, but *not* fully
// initialized from fullyInit{FromEmitter,Trivial} due to errors.

View File

@ -316,7 +316,7 @@ class JSString : public js::gc::Cell
"Inline char16_t chars must fit in a JSString");
/* Ensure js::shadow::String has the same layout. */
using js::shadow::String;
using JS::shadow::String;
static_assert(offsetof(JSString, d.u1.length) == offsetof(String, length),
"shadow::String length offset must match JSString");
static_assert(offsetof(JSString, d.u1.flags) == offsetof(String, flags),

View File

@ -17,6 +17,7 @@
#include "gc/Tracer.h"
#include "js/AllocPolicy.h"
#include "js/GCHashTable.h"
#include "js/HeapAPI.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
@ -50,6 +51,8 @@ class Symbol : public js::gc::TenuredCell
{
// Silence warnings about unused_ being... unused.
(void)unused_;
static_assert(uint32_t(SymbolCode::WellKnownAPILimit) == JS::shadow::Symbol::WellKnownAPILimit,
"JS::shadow::Symbol::WellKnownAPILimit must match SymbolCode::WellKnownAPILimit");
}
Symbol(const Symbol&) = delete;

View File

@ -9200,7 +9200,7 @@ BaseCompiler::emitMemCopy()
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
Nothing nothing;
if (!iter_.readMemCopy(ValType::I32, &nothing, &nothing, &nothing))
if (!iter_.readMemCopy(&nothing, &nothing, &nothing))
return false;
if (deadCode_)
@ -9222,7 +9222,7 @@ BaseCompiler::emitMemFill()
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
Nothing nothing;
if (!iter_.readMemFill(ValType::I32, &nothing, &nothing, &nothing))
if (!iter_.readMemFill(&nothing, &nothing, &nothing))
return false;
if (deadCode_)

View File

@ -1253,7 +1253,7 @@ AstDecodeWake(AstDecodeContext& c)
static bool
AstDecodeMemCopy(AstDecodeContext& c)
{
if (!c.iter().readMemCopy(ValType::I32, nullptr, nullptr, nullptr))
if (!c.iter().readMemCopy(nullptr, nullptr, nullptr))
return false;
AstDecodeStackItem dest = c.popCopy();
@ -1274,7 +1274,7 @@ AstDecodeMemCopy(AstDecodeContext& c)
static bool
AstDecodeMemFill(AstDecodeContext& c)
{
if (!c.iter().readMemFill(ValType::I32, nullptr, nullptr, nullptr))
if (!c.iter().readMemFill(nullptr, nullptr, nullptr))
return false;
AstDecodeStackItem len = c.popCopy();

View File

@ -3603,7 +3603,7 @@ static bool
EmitMemCopy(FunctionCompiler& f)
{
MDefinition *dest, *src, *len;
if (!f.iter().readMemCopy(ValType::I32, &dest, &src, &len))
if (!f.iter().readMemCopy(&dest, &src, &len))
return false;
if (f.inDeadCode())
@ -3642,7 +3642,7 @@ static bool
EmitMemFill(FunctionCompiler& f)
{
MDefinition *start, *val, *len;
if (!f.iter().readMemFill(ValType::I32, &start, &val, &len))
if (!f.iter().readMemFill(&start, &val, &len))
return false;
if (f.inDeadCode())

View File

@ -658,8 +658,8 @@ class MOZ_STACK_CLASS OpIter : private Policy
Value* condition);
MOZ_MUST_USE bool readSimdCtor(ValType elementType, uint32_t numElements, ValType simdType,
ValueVector* argValues);
MOZ_MUST_USE bool readMemCopy(ValType argType, Value* dest, Value* src, Value* len);
MOZ_MUST_USE bool readMemFill(ValType argType, Value* start, Value* val, Value* len);
MOZ_MUST_USE bool readMemCopy(Value* dest, Value* src, Value* len);
MOZ_MUST_USE bool readMemFill(Value* start, Value* val, Value* len);
// At a location where readOp is allowed, peek at the next opcode
// without consuming it or updating any internal state.
@ -2239,18 +2239,17 @@ OpIter<Policy>::readSimdCtor(ValType elementType, uint32_t numElements, ValType
template <typename Policy>
inline bool
OpIter<Policy>::readMemCopy(ValType argType,
Value* dest, Value* src, Value* len)
OpIter<Policy>::readMemCopy(Value* dest, Value* src, Value* len)
{
MOZ_ASSERT(Classify(op_) == OpKind::MemCopy);
if (!popWithType(argType, len))
if (!popWithType(ValType::I32, len))
return false;
if (!popWithType(argType, src))
if (!popWithType(ValType::I32, src))
return false;
if (!popWithType(argType, dest))
if (!popWithType(ValType::I32, dest))
return false;
return true;
@ -2258,18 +2257,17 @@ OpIter<Policy>::readMemCopy(ValType argType,
template <typename Policy>
inline bool
OpIter<Policy>::readMemFill(ValType argType,
Value* start, Value* val, Value* len)
OpIter<Policy>::readMemFill(Value* start, Value* val, Value* len)
{
MOZ_ASSERT(Classify(op_) == OpKind::MemFill);
if (!popWithType(argType, len))
if (!popWithType(ValType::I32, len))
return false;
if (!popWithType(argType, val))
if (!popWithType(ValType::I32, val))
return false;
if (!popWithType(argType, start))
if (!popWithType(ValType::I32, start))
return false;
return true;

View File

@ -816,6 +816,12 @@ DecodeFunctionBodyExprs(const ModuleEnvironment& env, const Sig& sig, const ValT
case uint16_t(MiscOp::I64TruncSSatF64):
case uint16_t(MiscOp::I64TruncUSatF64):
CHECK(iter.readConversion(ValType::F64, ValType::I64, &nothing));
#endif
#ifdef ENABLE_WASM_BULKMEM_OPS
case uint16_t(MiscOp::MemCopy):
CHECK(iter.readMemCopy(&nothing, &nothing, &nothing));
case uint16_t(MiscOp::MemFill):
CHECK(iter.readMemFill(&nothing, &nothing, &nothing));
#endif
default:
return iter.unrecognizedOpcode(&op);

File diff suppressed because it is too large Load Diff

View File

@ -522,4 +522,20 @@ void ThrowBadResult(nsresult result, XPCCallContext& ccx)
/***************************************************************************/
inline void
xpc::CleanupValue(const nsXPTType& aType,
void* aValue,
uint32_t aArrayLen)
{
// Check if we can do a cheap early return, and only perform the inner call
// if we can't. We never have to clean up null pointer types or arithmetic
// types.
if (aType.IsArithmetic() || (aType.HasPointerRepr() && !*(void**)aValue)) {
return;
}
xpc::InnerCleanupValue(aType, aValue, aArrayLen);
}
/***************************************************************************/
#endif /* xpcinlines_h___ */

View File

@ -218,28 +218,28 @@ XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array,
switch (state) {
case tInt :
*resultType = TD_INT32;
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INT32);
break;
case tDbl :
*resultType = TD_DOUBLE;
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::DOUBLE);
break;
case tBool:
*resultType = TD_BOOL;
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::BOOL);
break;
case tStr :
*resultType = TD_PWSTRING;
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::PWSTRING);
break;
case tID :
*resultType = TD_PNSIID;
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::PNSIID);
break;
case tISup:
*resultType = TD_INTERFACE_IS_TYPE;
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INTERFACE_IS_TYPE);
*resultID = NS_GET_IID(nsISupports);
break;
case tNull:
// FALL THROUGH
case tVar :
*resultType = TD_INTERFACE_IS_TYPE;
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INTERFACE_IS_TYPE);
*resultID = NS_GET_IID(nsIVariant);
break;
case tArr :
@ -339,15 +339,16 @@ bool XPCVariant::InitializeData(JSContext* cx)
if (!XPCArrayHomogenizer::GetTypeForArray(cx, jsobj, len, &type, &id))
return false;
if (!XPCConvert::JSArray2Native(&mData.u.array.mArrayValue,
val, len, type, &id, nullptr))
if (!XPCConvert::JSData2Native(&mData.u.array.mArrayValue,
val, type, &id, len, nullptr))
return false;
const nsXPTType& elty = type.ArrayElementType();
mData.mType = nsIDataType::VTYPE_ARRAY;
if (type.IsInterfacePointer())
if (elty.IsInterfacePointer())
mData.u.array.mArrayInterfaceID = id;
mData.u.array.mArrayCount = len;
mData.u.array.mArrayType = type.TagPart();
mData.u.array.mArrayType = elty.Tag();
return true;
}
@ -453,56 +454,49 @@ XPCVariant::VariantDataToJS(nsIVariant* variant,
char c;
if (NS_FAILED(variant->GetAsChar(&c)))
return false;
return XPCConvert::NativeData2JS(pJSVal, (const void*)&c, { TD_CHAR }, &iid, pErr);
return XPCConvert::NativeData2JS(pJSVal, (const void*)&c, { TD_CHAR }, &iid, 0, pErr);
}
case nsIDataType::VTYPE_WCHAR:
{
char16_t wc;
if (NS_FAILED(variant->GetAsWChar(&wc)))
return false;
return XPCConvert::NativeData2JS(pJSVal, (const void*)&wc, { TD_WCHAR }, &iid, pErr);
return XPCConvert::NativeData2JS(pJSVal, (const void*)&wc, { TD_WCHAR }, &iid, 0, pErr);
}
case nsIDataType::VTYPE_ID:
{
if (NS_FAILED(variant->GetAsID(&iid)))
return false;
nsID* v = &iid;
return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, { TD_PNSIID }, &iid, pErr);
return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, { TD_PNSIID }, &iid, 0, pErr);
}
case nsIDataType::VTYPE_ASTRING:
{
nsAutoString astring;
if (NS_FAILED(variant->GetAsAString(astring)))
return false;
nsAutoString* v = &astring;
return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, { TD_ASTRING }, &iid, pErr);
return XPCConvert::NativeData2JS(pJSVal, &astring, { TD_ASTRING }, &iid, 0, pErr);
}
case nsIDataType::VTYPE_DOMSTRING:
{
nsAutoString astring;
if (NS_FAILED(variant->GetAsAString(astring)))
return false;
nsAutoString* v = &astring;
return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
{ TD_DOMSTRING }, &iid, pErr);
return XPCConvert::NativeData2JS(pJSVal, &astring, { TD_DOMSTRING }, &iid, 0, pErr);
}
case nsIDataType::VTYPE_CSTRING:
{
nsAutoCString cString;
if (NS_FAILED(variant->GetAsACString(cString)))
return false;
nsAutoCString* v = &cString;
return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
{ TD_CSTRING }, &iid, pErr);
return XPCConvert::NativeData2JS(pJSVal, &cString, { TD_CSTRING }, &iid, 0, pErr);
}
case nsIDataType::VTYPE_UTF8STRING:
{
nsUTF8String utf8String;
if (NS_FAILED(variant->GetAsAUTF8String(utf8String)))
return false;
nsUTF8String* v = &utf8String;
return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
{ TD_UTF8STRING }, &iid, pErr);
return XPCConvert::NativeData2JS(pJSVal, &utf8String, { TD_UTF8STRING }, &iid, 0, pErr);
}
case nsIDataType::VTYPE_CHAR_STR:
{
@ -510,7 +504,7 @@ XPCVariant::VariantDataToJS(nsIVariant* variant,
if (NS_FAILED(variant->GetAsString(&pc)))
return false;
bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pc,
{ TD_PSTRING }, &iid, pErr);
{ TD_PSTRING }, &iid, 0, pErr);
free(pc);
return success;
}
@ -520,8 +514,9 @@ XPCVariant::VariantDataToJS(nsIVariant* variant,
uint32_t size;
if (NS_FAILED(variant->GetAsStringWithSize(&size, &pc)))
return false;
bool success = XPCConvert::NativeStringWithSize2JS(pJSVal, (const void*)&pc,
{ TD_PSTRING_SIZE_IS }, size, pErr);
bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pc,
{ TD_PSTRING_SIZE_IS },
&iid, size, pErr);
free(pc);
return success;
}
@ -531,7 +526,7 @@ XPCVariant::VariantDataToJS(nsIVariant* variant,
if (NS_FAILED(variant->GetAsWString(&pwc)))
return false;
bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pwc,
{ TD_PSTRING }, &iid, pErr);
{ TD_PSTRING }, &iid, 0, pErr);
free(pwc);
return success;
}
@ -541,8 +536,9 @@ XPCVariant::VariantDataToJS(nsIVariant* variant,
uint32_t size;
if (NS_FAILED(variant->GetAsWStringWithSize(&size, &pwc)))
return false;
bool success = XPCConvert::NativeStringWithSize2JS(pJSVal, (const void*)&pwc,
{ TD_PWSTRING_SIZE_IS }, size, pErr);
bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pwc,
{ TD_PWSTRING_SIZE_IS },
&iid, size, pErr);
free(pwc);
return success;
}
@ -558,7 +554,8 @@ XPCVariant::VariantDataToJS(nsIVariant* variant,
free((char*)piid);
bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pi,
{ TD_INTERFACE_IS_TYPE }, &iid, pErr);
{ TD_INTERFACE_IS_TYPE },
&iid, 0, pErr);
if (pi)
pi->Release();
return success;
@ -578,41 +575,66 @@ XPCVariant::VariantDataToJS(nsIVariant* variant,
// must exit via VARIANT_DONE from here on...
du.mType = nsIDataType::VTYPE_ARRAY;
nsXPTType conversionType;
uint16_t elementType = du.u.array.mArrayType;
const nsID* pid = nullptr;
nsXPTType::Idx xptIndex;
switch (elementType) {
case nsIDataType::VTYPE_INT8:
xptIndex = nsXPTType::Idx::INT8;
break;
case nsIDataType::VTYPE_INT16:
xptIndex = nsXPTType::Idx::INT16;
break;
case nsIDataType::VTYPE_INT32:
xptIndex = nsXPTType::Idx::INT32;
break;
case nsIDataType::VTYPE_INT64:
xptIndex = nsXPTType::Idx::INT64;
break;
case nsIDataType::VTYPE_UINT8:
xptIndex = nsXPTType::Idx::UINT8;
break;
case nsIDataType::VTYPE_UINT16:
xptIndex = nsXPTType::Idx::UINT16;
break;
case nsIDataType::VTYPE_UINT32:
xptIndex = nsXPTType::Idx::UINT32;
break;
case nsIDataType::VTYPE_UINT64:
xptIndex = nsXPTType::Idx::UINT64;
break;
case nsIDataType::VTYPE_FLOAT:
xptIndex = nsXPTType::Idx::FLOAT;
break;
case nsIDataType::VTYPE_DOUBLE:
xptIndex = nsXPTType::Idx::DOUBLE;
break;
case nsIDataType::VTYPE_BOOL:
xptIndex = nsXPTType::Idx::BOOL;
break;
case nsIDataType::VTYPE_CHAR:
xptIndex = nsXPTType::Idx::CHAR;
break;
case nsIDataType::VTYPE_WCHAR:
conversionType = (uint8_t)elementType;
xptIndex = nsXPTType::Idx::WCHAR;
break;
case nsIDataType::VTYPE_ID:
case nsIDataType::VTYPE_CHAR_STR:
case nsIDataType::VTYPE_WCHAR_STR:
conversionType = (uint8_t)elementType;
xptIndex = nsXPTType::Idx::PNSIID;
break;
case nsIDataType::VTYPE_CHAR_STR:
xptIndex = nsXPTType::Idx::PSTRING;
break;
case nsIDataType::VTYPE_WCHAR_STR:
xptIndex = nsXPTType::Idx::PWSTRING;
break;
case nsIDataType::VTYPE_INTERFACE:
pid = &NS_GET_IID(nsISupports);
conversionType = (uint8_t)elementType;
xptIndex = nsXPTType::Idx::INTERFACE_IS_TYPE;
break;
case nsIDataType::VTYPE_INTERFACE_IS:
pid = &du.u.array.mArrayInterfaceID;
conversionType = (uint8_t)elementType;
xptIndex = nsXPTType::Idx::INTERFACE_IS_TYPE;
break;
// The rest are illegal.
@ -632,10 +654,9 @@ XPCVariant::VariantDataToJS(nsIVariant* variant,
}
bool success =
XPCConvert::NativeArray2JS(pJSVal,
(const void**)&du.u.array.mArrayValue,
conversionType, pid,
du.u.array.mArrayCount, pErr);
XPCConvert::NativeData2JS(pJSVal, (const void*)&du.u.array.mArrayValue,
nsXPTType::MkArrayType(xptIndex), pid,
du.u.array.mArrayCount, pErr);
return success;
}

View File

@ -304,7 +304,7 @@ GetNamedPropertyAsVariantRaw(XPCCallContext& ccx,
return JS_GetPropertyById(ccx, aJSObj, aName, &val) &&
XPCConvert::JSData2Native(aResult, val, type,
&NS_GET_IID(nsIVariant), pErr);
&NS_GET_IID(nsIVariant), 0, pErr);
}
// static
@ -492,10 +492,10 @@ GetFunctionName(JSContext* cx, HandleObject obj)
nsCString displayName("anonymous");
if (funName) {
nsCString* displayNamePtr = &displayName;
RootedValue funNameVal(cx, StringValue(funName));
if (!XPCConvert::JSData2Native(&displayNamePtr, funNameVal, { nsXPTType::T_UTF8STRING },
nullptr, nullptr))
if (!XPCConvert::JSData2Native(&displayName, funNameVal,
{ nsXPTType::T_UTF8STRING },
nullptr, 0, nullptr))
{
JS_ClearPendingException(cx);
return nsCString("anonymous");
@ -663,162 +663,108 @@ nsXPCWrappedJSClass::GetRootJSObject(JSContext* cx, JSObject* aJSObjArg)
}
bool
nsXPCWrappedJSClass::GetArraySizeFromParam(JSContext* cx,
const nsXPTMethodInfo* method,
const nsXPTParamInfo& param,
uint16_t methodIndex,
uint8_t paramIndex,
nsXPCWrappedJSClass::GetArraySizeFromParam(const nsXPTMethodInfo* method,
const nsXPTType& type,
nsXPTCMiniVariant* nativeParams,
uint32_t* result) const
{
uint8_t argnum;
nsresult rv;
if (type.Tag() != nsXPTType::T_ARRAY &&
type.Tag() != nsXPTType::T_PSTRING_SIZE_IS &&
type.Tag() != nsXPTType::T_PWSTRING_SIZE_IS) {
*result = 0;
return true;
}
rv = mInfo->GetSizeIsArgNumberForParam(methodIndex, &param, 0, &argnum);
if (NS_FAILED(rv))
return false;
const nsXPTParamInfo& arg_param = method->GetParam(argnum);
uint8_t argnum = type.ArgNum();
const nsXPTParamInfo& param = method->Param(argnum);
// This should be enforced by the xpidl compiler, but it's not.
// See bug 695235.
MOZ_ASSERT(arg_param.GetType().TagPart() == nsXPTType::T_U32,
"size_is references parameter of invalid type.");
if (param.Type().Tag() != nsXPTType::T_U32) {
return false;
}
if (arg_param.IsIndirect())
// If the length is passed indirectly (as an outparam), dereference by an
// extra level.
if (param.IsIndirect()) {
*result = *(uint32_t*)nativeParams[argnum].val.p;
else
} else {
*result = nativeParams[argnum].val.u32;
}
return true;
}
bool
nsXPCWrappedJSClass::GetInterfaceTypeFromParam(JSContext* cx,
const nsXPTMethodInfo* method,
const nsXPTParamInfo& param,
uint16_t methodIndex,
nsXPCWrappedJSClass::GetInterfaceTypeFromParam(const nsXPTMethodInfo* method,
const nsXPTType& type,
nsXPTCMiniVariant* nativeParams,
nsID* result) const
{
uint8_t type_tag = type.TagPart();
result->Clear();
if (type_tag == nsXPTType::T_INTERFACE) {
if (NS_SUCCEEDED(GetInterfaceInfo()->
GetIIDForParamNoAlloc(methodIndex, &param, result))) {
return true;
}
} else if (type_tag == nsXPTType::T_INTERFACE_IS) {
uint8_t argnum;
nsresult rv;
rv = mInfo->GetInterfaceIsArgNumberForParam(methodIndex,
&param, &argnum);
if (NS_FAILED(rv))
const nsXPTType& inner = type.InnermostType();
if (inner.Tag() == nsXPTType::T_INTERFACE) {
// Directly get IID from nsXPTInterfaceInfo.
if (!inner.GetInterface()) {
return false;
const nsXPTParamInfo& arg_param = method->GetParam(argnum);
const nsXPTType& arg_type = arg_param.GetType();
if (arg_type.TagPart() == nsXPTType::T_IID) {
if (arg_param.IsIndirect()) {
nsID** p = (nsID**) nativeParams[argnum].val.p;
if (!p || !*p)
return false;
*result = **p;
} else {
nsID* p = (nsID*) nativeParams[argnum].val.p;
if (!p)
return false;
*result = *p;
}
return true;
}
}
return false;
}
/* static */ void
nsXPCWrappedJSClass::CleanupPointerArray(const nsXPTType& datum_type,
uint32_t array_count,
void** arrayp)
{
if (datum_type.IsInterfacePointer()) {
nsISupports** pp = (nsISupports**) arrayp;
for (uint32_t k = 0; k < array_count; k++) {
nsISupports* p = pp[k];
NS_IF_RELEASE(p);
*result = inner.GetInterface()->IID();
} else if (inner.Tag() == nsXPTType::T_INTERFACE_IS) {
// Get IID from a passed parameter.
const nsXPTParamInfo& param = method->Param(inner.ArgNum());
if (param.Type().Tag() != nsXPTType::T_IID) {
return false;
}
} else {
void** pp = (void**) arrayp;
for (uint32_t k = 0; k < array_count; k++) {
void* p = pp[k];
if (p) free(p);
}
}
}
/* static */ void
nsXPCWrappedJSClass::CleanupPointerTypeObject(const nsXPTType& type,
void** pp)
{
MOZ_ASSERT(pp,"null pointer");
if (type.IsInterfacePointer()) {
nsISupports* p = *((nsISupports**)pp);
if (p) p->Release();
} else {
void* p = *((void**)pp);
if (p) free(p);
void* ptr = nativeParams[inner.ArgNum()].val.p;
// If the IID is passed indirectly (as an outparam), dereference by an
// extra level.
if (ptr && param.IsIndirect()) {
ptr = *(nsID**) ptr;
}
if (!ptr) {
return false;
}
*result = *(nsID*) ptr;
}
return true;
}
void
nsXPCWrappedJSClass::CleanupOutparams(JSContext* cx, uint16_t methodIndex,
const nsXPTMethodInfo* info, nsXPTCMiniVariant* nativeParams,
bool inOutOnly, uint8_t n) const
nsXPCWrappedJSClass::CleanupOutparams(const nsXPTMethodInfo* info,
nsXPTCMiniVariant* nativeParams,
bool inOutOnly, uint8_t count) const
{
// clean up any 'out' params handed in
for (uint8_t i = 0; i < n; i++) {
for (uint8_t i = 0; i < count; i++) {
const nsXPTParamInfo& param = info->GetParam(i);
if (!param.IsOut())
continue;
const nsXPTType& type = param.GetType();
if (!type.deprecated_IsPointer())
continue;
void* p = nativeParams[i].val.p;
if (!p)
// Extract the array length so we can use it in CleanupValue.
uint32_t arrayLen = 0;
if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
continue;
// The inOutOnly flag was introduced when consolidating two very
// similar code paths in CallMethod in bug 1175513. I don't know
// if and why the difference is necessary.
MOZ_ASSERT(param.IsIndirect(), "Outparams are always indirect");
// The inOutOnly flag is necessary because full outparams may contain
// uninitialized junk before the call is made, and we don't want to try
// to clean up uninitialized junk.
if (!inOutOnly || param.IsIn()) {
if (type.IsArray()) {
void** pp = *static_cast<void***>(p);
if (pp) {
// we need to get the array length and iterate the items
uint32_t array_count;
nsXPTType datum_type;
if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, &param,
1, &datum_type)) &&
datum_type.deprecated_IsPointer() &&
GetArraySizeFromParam(cx, info, param, methodIndex,
i, nativeParams, &array_count) &&
array_count) {
CleanupPointerArray(datum_type, array_count, pp);
}
// always release the array if it is inout
free(pp);
}
} else {
CleanupPointerTypeObject(type, static_cast<void**>(p));
}
xpc::CleanupValue(param.Type(), nativeParams[i].val.p, arrayLen);
}
// Even if we didn't call CleanupValue, null out any pointers. This is
// just to protect C++ callers which may read garbage if they forget to
// check the error value.
if (param.Type().HasPointerRepr()) {
*(void**)nativeParams[i].val.p = nullptr;
}
*static_cast<void**>(p) = nullptr;
}
}
@ -1102,14 +1048,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
for (i = 0; i < argc; i++) {
const nsXPTParamInfo& param = info->GetParam(i);
const nsXPTType& type = param.GetType();
nsXPTType datum_type;
uint32_t array_count;
bool isArray = type.IsArray();
RootedValue val(cx, NullValue());
bool isSizedString = isArray ?
false :
type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
// verify that null was not passed for 'out' param
@ -1118,53 +1058,24 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
goto pre_call_clean_up;
}
if (isArray) {
if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
&datum_type)))
goto pre_call_clean_up;
} else
datum_type = type;
if (param.IsIn()) {
nsXPTCMiniVariant* pv;
const void* pv;
if (param.IsIndirect())
pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
pv = nativeParams[i].val.p;
else
pv = &nativeParams[i];
if (datum_type.IsInterfacePointer() &&
!GetInterfaceTypeFromParam(cx, info, param, methodIndex,
datum_type, nativeParams,
&param_iid))
if (!GetInterfaceTypeFromParam(info, type, nativeParams, &param_iid) ||
!GetArraySizeFromParam(info, type, nativeParams, &array_count))
goto pre_call_clean_up;
if (isArray || isSizedString) {
if (!GetArraySizeFromParam(cx, info, param, methodIndex,
i, nativeParams, &array_count))
goto pre_call_clean_up;
}
if (isArray) {
if (!XPCConvert::NativeArray2JS(&val,
(const void**)&pv->val,
datum_type, &param_iid,
array_count, nullptr))
goto pre_call_clean_up;
} else if (isSizedString) {
if (!XPCConvert::NativeStringWithSize2JS(&val,
(const void*)&pv->val,
datum_type,
array_count, nullptr))
goto pre_call_clean_up;
} else {
if (!XPCConvert::NativeData2JS(&val, &pv->val, type,
&param_iid, nullptr))
goto pre_call_clean_up;
}
if (!XPCConvert::NativeData2JS(&val, pv, type,
&param_iid, array_count,
nullptr))
goto pre_call_clean_up;
}
if (param.IsOut() || param.IsDipper()) {
if (param.IsOut()) {
// create an 'out' object
RootedObject out_obj(cx, NewOutObject(cx));
if (!out_obj) {
@ -1188,7 +1099,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
pre_call_clean_up:
// clean up any 'out' params handed in
CleanupOutparams(cx, methodIndex, info, nativeParams, /* inOutOnly = */ true, paramCount);
CleanupOutparams(info, nativeParams, /* inOutOnly = */ true, paramCount);
// Make sure "this" doesn't get deleted during this call.
nsCOMPtr<nsIXPCWrappedJSClass> kungFuDeathGrip(this);
@ -1247,7 +1158,7 @@ pre_call_clean_up:
for (i = 0; i < paramCount; i++) {
const nsXPTParamInfo& param = info->GetParam(i);
MOZ_ASSERT(!param.IsShared(), "[shared] implies [noscript]!");
if (!param.IsOut() && !param.IsDipper())
if (!param.IsOut())
continue;
const nsXPTType& type = param.GetType();
@ -1257,13 +1168,6 @@ pre_call_clean_up:
}
RootedValue val(cx);
uint8_t type_tag = type.TagPart();
nsXPTCMiniVariant* pv;
if (param.IsDipper())
pv = (nsXPTCMiniVariant*) &nativeParams[i].val.p;
else
pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
if (&param == info->GetRetval())
val = rval;
@ -1279,15 +1183,16 @@ pre_call_clean_up:
// setup allocator and/or iid
if (type_tag == nsXPTType::T_INTERFACE) {
if (NS_FAILED(GetInterfaceInfo()->
GetIIDForParamNoAlloc(methodIndex, &param,
&param_iid)))
const nsXPTType& inner = type.InnermostType();
if (inner.Tag() == nsXPTType::T_INTERFACE) {
if (!inner.GetInterface())
break;
param_iid = inner.GetInterface()->IID();
}
if (!XPCConvert::JSData2Native(&pv->val, val, type,
&param_iid, nullptr))
MOZ_ASSERT(param.IsIndirect(), "outparams are always indirect");
if (!XPCConvert::JSData2Native(nativeParams[i].val.p, val, type,
&param_iid, 0, nullptr))
break;
}
@ -1303,16 +1208,7 @@ pre_call_clean_up:
continue;
RootedValue val(cx);
nsXPTCMiniVariant* pv;
nsXPTType datum_type;
uint32_t array_count;
bool isArray = type.IsArray();
bool isSizedString = isArray ?
false :
type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
if (&param == info->GetRetval())
val = rval;
@ -1326,50 +1222,21 @@ pre_call_clean_up:
// setup allocator and/or iid
if (isArray) {
if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
&datum_type)))
break;
} else
datum_type = type;
if (!GetInterfaceTypeFromParam(info, type, nativeParams, &param_iid) ||
!GetArraySizeFromParam(info, type, nativeParams, &array_count))
break;
if (datum_type.IsInterfacePointer()) {
if (!GetInterfaceTypeFromParam(cx, info, param, methodIndex,
datum_type, nativeParams,
&param_iid))
break;
}
if (isArray || isSizedString) {
if (!GetArraySizeFromParam(cx, info, param, methodIndex,
i, nativeParams, &array_count))
break;
}
if (isArray) {
if (array_count &&
!XPCConvert::JSArray2Native((void**)&pv->val, val,
array_count, datum_type,
&param_iid, nullptr))
break;
} else if (isSizedString) {
if (!XPCConvert::JSStringWithSize2Native((void*)&pv->val, val,
array_count, datum_type,
nullptr))
break;
} else {
if (!XPCConvert::JSData2Native(&pv->val, val, type,
&param_iid,
nullptr))
break;
}
MOZ_ASSERT(param.IsIndirect(), "outparams are always indirect");
if (!XPCConvert::JSData2Native(nativeParams[i].val.p, val, type,
&param_iid, array_count, nullptr))
break;
}
}
if (i != paramCount) {
// We didn't manage all the result conversions!
// We have to cleanup any junk that *did* get converted.
CleanupOutparams(cx, methodIndex, info, nativeParams, /* inOutOnly = */ false, i);
CleanupOutparams(info, nativeParams, /* inOutOnly = */ false, i);
} else {
// set to whatever the JS code might have set as the result
retval = xpccx->GetPendingResult();

View File

@ -1133,7 +1133,7 @@ static bool Throw(nsresult errNum, XPCCallContext& ccx)
/***************************************************************************/
class MOZ_STACK_CLASS CallMethodHelper
class MOZ_STACK_CLASS CallMethodHelper final
{
XPCCallContext& mCallContext;
nsresult mInvokeResult;
@ -1151,12 +1151,10 @@ class MOZ_STACK_CLASS CallMethodHelper
const uint32_t mArgc;
MOZ_ALWAYS_INLINE bool
GetArraySizeFromParam(uint8_t paramIndex, HandleValue maybeArray, uint32_t* result);
GetArraySizeFromParam(const nsXPTType& type, HandleValue maybeArray, uint32_t* result);
MOZ_ALWAYS_INLINE bool
GetInterfaceTypeFromParam(uint8_t paramIndex,
const nsXPTType& datum_type,
nsID* result) const;
GetInterfaceTypeFromParam(const nsXPTType& type, nsID* result) const;
MOZ_ALWAYS_INLINE bool
GetOutParamSource(uint8_t paramIndex, MutableHandleValue srcp) const;
@ -1189,11 +1187,6 @@ class MOZ_STACK_CLASS CallMethodHelper
MOZ_ALWAYS_INLINE bool ConvertDependentParams();
MOZ_ALWAYS_INLINE bool ConvertDependentParam(uint8_t i);
MOZ_ALWAYS_INLINE void CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type);
MOZ_ALWAYS_INLINE bool AllocateStringClass(nsXPTCVariant* dp,
const nsXPTParamInfo& paramInfo);
MOZ_ALWAYS_INLINE nsresult Invoke();
public:
@ -1220,6 +1213,9 @@ public:
MOZ_ALWAYS_INLINE bool Call();
// Trace implementation so we can put our CallMethodHelper in a Rooted<T>.
void trace(JSTracer* aTrc);
};
// static
@ -1232,7 +1228,8 @@ XPCWrappedNative::CallMethod(XPCCallContext& ccx,
return Throw(rv, ccx);
}
return CallMethodHelper(ccx).Call();
JS::Rooted<CallMethodHelper> helper(ccx, /* init = */ ccx);
return helper.get().Call();
}
bool
@ -1281,82 +1278,51 @@ CallMethodHelper::Call()
CallMethodHelper::~CallMethodHelper()
{
uint8_t paramCount = mMethodInfo->GetParamCount();
if (mDispatchParams.Length()) {
for (uint8_t i = 0; i < paramCount; i++) {
nsXPTCVariant* dp = GetDispatchParam(i);
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
for (nsXPTCVariant& param : mDispatchParams) {
// Only clean up values which need cleanup.
if (!param.DoesValNeedCleanup())
continue;
if (paramInfo.GetType().IsArray()) {
void* p = dp->val.p;
if (!p)
continue;
uint32_t arraylen = 0;
if (!GetArraySizeFromParam(param.type, UndefinedHandleValue, &arraylen))
continue;
// Clean up the array contents if necessary.
if (dp->DoesValNeedCleanup()) {
// We need some basic information to properly destroy the array.
uint32_t array_count = 0;
nsXPTType datum_type;
if (!GetArraySizeFromParam(i, UndefinedHandleValue, &array_count) ||
!NS_SUCCEEDED(mIFaceInfo->GetTypeForParam(mVTableIndex,
&paramInfo,
1, &datum_type))) {
// XXXbholley - I'm not convinced that the above calls will
// ever fail.
NS_ERROR("failed to get array information, we'll leak here");
continue;
}
// Loop over the array contents. For each one, we create a
// dummy 'val' and pass it to the cleanup helper.
for (uint32_t k = 0; k < array_count; k++) {
nsXPTCMiniVariant v;
v.val.p = static_cast<void**>(p)[k];
CleanupParam(v, datum_type);
}
}
// always free the array itself
free(p);
} else {
// Clean up single parameters (if requested).
if (dp->DoesValNeedCleanup())
CleanupParam(*dp, dp->type);
}
}
xpc::CleanupValue(param.type, &param.val, arraylen);
}
}
bool
CallMethodHelper::GetArraySizeFromParam(uint8_t paramIndex,
CallMethodHelper::GetArraySizeFromParam(const nsXPTType& type,
HandleValue maybeArray,
uint32_t* result)
{
nsresult rv;
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
if (type.Tag() != nsXPTType::T_ARRAY &&
type.Tag() != nsXPTType::T_PSTRING_SIZE_IS &&
type.Tag() != nsXPTType::T_PWSTRING_SIZE_IS) {
*result = 0;
return true;
}
uint8_t argnum = type.ArgNum();
uint32_t* lengthp = &GetDispatchParam(argnum)->val.u32;
// TODO fixup the various exceptions that are thrown
rv = mIFaceInfo->GetSizeIsArgNumberForParam(mVTableIndex, &paramInfo, 0, &paramIndex);
if (NS_FAILED(rv))
return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
// If the array length wasn't passed, it might have been listed as optional.
// When converting arguments from JS to C++, we pass the array as |maybeArray|,
// and give ourselves the chance to infer the length. Once we have it, we stick
// it in the right slot so that we can find it again when cleaning up the params.
// from the array.
if (paramIndex >= mArgc && maybeArray.isObject()) {
MOZ_ASSERT(mMethodInfo->GetParam(paramIndex).IsOptional());
RootedObject arrayOrNull(mCallContext, maybeArray.isObject() ? &maybeArray.toObject()
: nullptr);
if (argnum >= mArgc && maybeArray.isObject()) {
MOZ_ASSERT(mMethodInfo->Param(argnum).IsOptional());
RootedObject arrayOrNull(mCallContext, &maybeArray.toObject());
bool isArray;
bool ok = false;
if (JS_IsArrayObject(mCallContext, maybeArray, &isArray) && isArray) {
ok = JS_GetArrayLength(mCallContext, arrayOrNull, &GetDispatchParam(paramIndex)->val.u32);
ok = JS_GetArrayLength(mCallContext, arrayOrNull, lengthp);
} else if (JS_IsTypedArrayObject(&maybeArray.toObject())) {
GetDispatchParam(paramIndex)->val.u32 = JS_GetTypedArrayLength(&maybeArray.toObject());
*lengthp = JS_GetTypedArrayLength(&maybeArray.toObject());
ok = true;
}
@ -1365,38 +1331,31 @@ CallMethodHelper::GetArraySizeFromParam(uint8_t paramIndex,
}
}
*result = GetDispatchParam(paramIndex)->val.u32;
*result = *lengthp;
return true;
}
bool
CallMethodHelper::GetInterfaceTypeFromParam(uint8_t paramIndex,
const nsXPTType& datum_type,
CallMethodHelper::GetInterfaceTypeFromParam(const nsXPTType& type,
nsID* result) const
{
nsresult rv;
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
uint8_t tag = datum_type.TagPart();
result->Clear();
// TODO fixup the various exceptions that are thrown
const nsXPTType& inner = type.InnermostType();
if (inner.Tag() == nsXPTType::T_INTERFACE) {
if (!inner.GetInterface()) {
return Throw(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO, mCallContext);
}
if (tag == nsXPTType::T_INTERFACE) {
rv = mIFaceInfo->GetIIDForParamNoAlloc(mVTableIndex, &paramInfo, result);
if (NS_FAILED(rv))
*result = inner.GetInterface()->IID();
} else if (inner.Tag() == nsXPTType::T_INTERFACE_IS) {
nsID* id = (nsID*) GetDispatchParam(inner.ArgNum())->val.p;
if (!id) {
return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO,
paramIndex, mCallContext);
} else if (tag == nsXPTType::T_INTERFACE_IS) {
rv = mIFaceInfo->GetInterfaceIsArgNumberForParam(mVTableIndex, &paramInfo,
&paramIndex);
if (NS_FAILED(rv))
return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
inner.ArgNum(), mCallContext);
}
nsID* p = (nsID*) GetDispatchParam(paramIndex)->val.p;
if (!p)
return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO,
paramIndex, mCallContext);
*result = *p;
*result = *id;
}
return true;
}
@ -1407,7 +1366,6 @@ CallMethodHelper::GetOutParamSource(uint8_t paramIndex, MutableHandleValue srcp)
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
bool isRetval = &paramInfo == mMethodInfo->GetRetval();
MOZ_ASSERT(!paramInfo.IsDipper(), "Dipper params are handled separately");
if (paramInfo.IsOut() && !isRetval) {
MOZ_ASSERT(paramIndex < mArgc || paramInfo.IsOptional(),
"Expected either enough arguments or an optional argument");
@ -1437,62 +1395,24 @@ CallMethodHelper::GatherAndConvertResults()
uint8_t paramCount = mMethodInfo->GetParamCount();
for (uint8_t i = 0; i < paramCount; i++) {
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
if (!paramInfo.IsOut() && !paramInfo.IsDipper())
if (!paramInfo.IsOut())
continue;
const nsXPTType& type = paramInfo.GetType();
nsXPTCVariant* dp = GetDispatchParam(i);
RootedValue v(mCallContext, NullValue());
uint32_t array_count = 0;
nsXPTType datum_type;
bool isArray = type.IsArray();
bool isSizedString = isArray ?
false :
type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
if (isArray) {
if (NS_FAILED(mIFaceInfo->GetTypeForParam(mVTableIndex, &paramInfo, 1,
&datum_type))) {
Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
return false;
}
} else
datum_type = type;
if (isArray || isSizedString) {
if (!GetArraySizeFromParam(i, UndefinedHandleValue, &array_count))
return false;
}
nsID param_iid;
if (datum_type.IsInterfacePointer() &&
!GetInterfaceTypeFromParam(i, datum_type, &param_iid))
if (!GetInterfaceTypeFromParam(type, &param_iid) ||
!GetArraySizeFromParam(type, UndefinedHandleValue, &array_count))
return false;
nsresult err;
if (isArray) {
if (!XPCConvert::NativeArray2JS(&v, (const void**)&dp->val,
datum_type, &param_iid,
array_count, &err)) {
// XXX need exception scheme for arrays to indicate bad element
ThrowBadParam(err, i, mCallContext);
return false;
}
} else if (isSizedString) {
if (!XPCConvert::NativeStringWithSize2JS(&v,
(const void*)&dp->val,
datum_type,
array_count, &err)) {
ThrowBadParam(err, i, mCallContext);
return false;
}
} else {
if (!XPCConvert::NativeData2JS(&v, &dp->val, datum_type,
&param_iid, &err)) {
ThrowBadParam(err, i, mCallContext);
return false;
}
if (!XPCConvert::NativeData2JS(&v, &dp->val, type,
&param_iid, array_count, &err)) {
ThrowBadParam(err, i, mCallContext);
return false;
}
if (&paramInfo == mMethodInfo->GetRetval()) {
@ -1549,7 +1469,7 @@ CallMethodHelper::QueryInterfaceFastPath()
bool success =
XPCConvert::NativeData2JS(&v, &qiresult,
{ nsXPTType::T_INTERFACE_IS },
iid, &err);
iid, 0, &err);
NS_IF_RELEASE(qiresult);
if (!success) {
@ -1647,48 +1567,34 @@ CallMethodHelper::ConvertIndependentParam(uint8_t i)
{
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
const nsXPTType& type = paramInfo.GetType();
uint8_t type_tag = type.TagPart();
nsXPTCVariant* dp = GetDispatchParam(i);
dp->type = type;
MOZ_ASSERT(!paramInfo.IsShared(), "[shared] implies [noscript]!");
// String classes are always "in" - those that are marked "out" are converted
// by the XPIDL compiler to "in+dipper". See the note above IsDipper() in
// xptinfo.h.
//
// Also note that the fact that we bail out early for dipper parameters means
// that "inout" dipper parameters don't work - see bug 687612.
if (paramInfo.IsStringClass()) {
if (!AllocateStringClass(dp, paramInfo))
return false;
if (paramInfo.IsDipper()) {
// We've allocated our string class explicitly, so we don't need
// to do any conversions on the incoming argument. However, we still
// need to verify that it's an object, so that we don't get surprised
// later on when trying to assign the result to .value.
if (i < mArgc && !mArgv[i].isObject()) {
ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, i, mCallContext);
return false;
}
return true;
}
}
// Specify the correct storage/calling semantics.
if (paramInfo.IsIndirect())
dp->SetIndirect();
// The JSVal proper is always stored within the 'val' union and passed
// indirectly, regardless of in/out-ness.
if (type_tag == nsXPTType::T_JSVAL) {
// Root the value.
new (&dp->val.j) JS::Value();
MOZ_ASSERT(dp->val.j.isUndefined());
if (!js::AddRawValueRoot(mCallContext, &dp->val.j,
"XPCWrappedNative::CallMethod param"))
{
return false;
}
// Some types are always stored within the nsXPTCVariant, and passed
// indirectly, regardless of in/out-ness. These types are stored in the
// nsXPTCVariant's extended value.
switch (type.Tag()) {
// Ensure that the jsval has a valid value.
case nsXPTType::T_JSVAL:
new (&dp->ext.jsval) JS::Value();
MOZ_ASSERT(dp->ext.jsval.isUndefined());
break;
// Initialize our temporary string class values so they can be assigned
// to by the XPCConvert logic.
case nsXPTType::T_ASTRING:
case nsXPTType::T_DOMSTRING:
new (&dp->ext.nsstr) nsString();
break;
case nsXPTType::T_CSTRING:
case nsXPTType::T_UTF8STRING:
new (&dp->ext.nscstr) nsCString();
break;
}
// Flag cleanup for anything that isn't self-contained.
@ -1719,25 +1625,27 @@ CallMethodHelper::ConvertIndependentParam(uint8_t i)
"Expected either enough arguments or an optional argument");
if (i < mArgc)
src = mArgv[i];
else if (type_tag == nsXPTType::T_JSVAL)
else if (type.Tag() == nsXPTType::T_JSVAL)
src.setUndefined();
else
src.setNull();
}
nsID param_iid;
if (type_tag == nsXPTType::T_INTERFACE &&
NS_FAILED(mIFaceInfo->GetIIDForParamNoAlloc(mVTableIndex, &paramInfo,
&param_iid))) {
ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO, i, mCallContext);
return false;
nsID param_iid = { 0 };
const nsXPTType& inner = type.InnermostType();
if (inner.Tag() == nsXPTType::T_INTERFACE) {
if (!inner.GetInterface()) {
return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO,
i, mCallContext);
}
param_iid = inner.GetInterface()->IID();
}
// Don't allow CPOWs to be passed to native code (in case they try to cast
// to a concrete type).
if (src.isObject() &&
jsipc::IsWrappedCPOW(&src.toObject()) &&
type_tag == nsXPTType::T_INTERFACE &&
type.Tag() == nsXPTType::T_INTERFACE &&
!param_iid.Equals(NS_GET_IID(nsISupports)))
{
// Allow passing CPOWs to XPCWrappedJS.
@ -1749,7 +1657,7 @@ CallMethodHelper::ConvertIndependentParam(uint8_t i)
}
nsresult err;
if (!XPCConvert::JSData2Native(&dp->val, src, type, &param_iid, &err)) {
if (!XPCConvert::JSData2Native(&dp->val, src, type, &param_iid, 0, &err)) {
ThrowBadParam(err, i, mCallContext);
return false;
}
@ -1778,41 +1686,17 @@ CallMethodHelper::ConvertDependentParam(uint8_t i)
{
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
const nsXPTType& type = paramInfo.GetType();
nsXPTType datum_type;
uint32_t array_count = 0;
bool isArray = type.IsArray();
bool isSizedString = isArray ?
false :
type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
nsXPTCVariant* dp = GetDispatchParam(i);
dp->type = type;
if (isArray) {
if (NS_FAILED(mIFaceInfo->GetTypeForParam(mVTableIndex, &paramInfo, 1,
&datum_type))) {
Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
return false;
}
MOZ_ASSERT(datum_type.TagPart() != nsXPTType::T_JSVAL,
"Arrays of JSVals not currently supported - see bug 693337.");
} else {
datum_type = type;
}
// Specify the correct storage/calling semantics.
if (paramInfo.IsIndirect())
dp->SetIndirect();
// We have 3 possible type of dependent parameters: Arrays, Sized Strings,
// and iid_is Interface pointers. The latter two always need cleanup, and
// arrays need cleanup for all non-arithmetic types. Since the latter two
// cases also happen to be non-arithmetic, we can just inspect datum_type
// here.
if (!datum_type.IsArithmetic())
dp->SetValNeedsCleanup();
// Make sure we clean up all of our dependent types. All of them require
// allocations of some kind.
dp->SetValNeedsCleanup();
// Even if there's nothing to convert, we still need to examine the
// JSObject container for out-params. If it's null or otherwise invalid,
@ -1840,116 +1724,19 @@ CallMethodHelper::ConvertDependentParam(uint8_t i)
}
nsID param_iid;
if (datum_type.IsInterfacePointer() &&
!GetInterfaceTypeFromParam(i, datum_type, &param_iid))
uint32_t array_count;
if (!GetInterfaceTypeFromParam(type, &param_iid) ||
!GetArraySizeFromParam(type, src, &array_count))
return false;
nsresult err;
if (isArray || isSizedString) {
if (!GetArraySizeFromParam(i, src, &array_count))
return false;
if (isArray) {
if (array_count &&
!XPCConvert::JSArray2Native((void**)&dp->val, src,
array_count, datum_type, &param_iid,
&err)) {
// XXX need exception scheme for arrays to indicate bad element
ThrowBadParam(err, i, mCallContext);
return false;
}
} else // if (isSizedString)
{
if (!XPCConvert::JSStringWithSize2Native((void*)&dp->val,
src, array_count,
datum_type, &err)) {
ThrowBadParam(err, i, mCallContext);
return false;
}
}
} else {
if (!XPCConvert::JSData2Native(&dp->val, src, type,
&param_iid, &err)) {
ThrowBadParam(err, i, mCallContext);
return false;
}
}
return true;
}
// Performs all necessary teardown on a parameter after method invocation.
//
// This method should only be called if the value in question was flagged
// for cleanup (ie, if dp->DoesValNeedCleanup()).
void
CallMethodHelper::CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type)
{
// We handle array elements, but not the arrays themselves.
MOZ_ASSERT(type.TagPart() != nsXPTType::T_ARRAY, "Can't handle arrays.");
// Pointers may sometimes be null even if cleanup was requested. Combine
// the null checking for all the different types into one check here.
if (type.TagPart() != nsXPTType::T_JSVAL && param.val.p == nullptr)
return;
switch (type.TagPart()) {
case nsXPTType::T_JSVAL:
js::RemoveRawValueRoot(mCallContext, &param.val.j);
break;
case nsXPTType::T_INTERFACE:
case nsXPTType::T_INTERFACE_IS:
((nsISupports*)param.val.p)->Release();
break;
case nsXPTType::T_DOMOBJECT:
type.GetDOMObjectInfo().Cleanup(param.val.p);
break;
case nsXPTType::T_ASTRING:
case nsXPTType::T_DOMSTRING:
mCallContext.GetContext()->mScratchStrings.Destroy((nsString*)param.val.p);
break;
case nsXPTType::T_UTF8STRING:
case nsXPTType::T_CSTRING:
mCallContext.GetContext()->mScratchCStrings.Destroy((nsCString*)param.val.p);
break;
default:
MOZ_ASSERT(!type.IsArithmetic(), "Cleanup requested on unexpected type.");
free(param.val.p);
break;
}
}
bool
CallMethodHelper::AllocateStringClass(nsXPTCVariant* dp,
const nsXPTParamInfo& paramInfo)
{
// Get something we can make comparisons with.
uint8_t type_tag = paramInfo.GetType().TagPart();
// There should be 4 cases, all strings. Verify that here.
MOZ_ASSERT(type_tag == nsXPTType::T_ASTRING ||
type_tag == nsXPTType::T_DOMSTRING ||
type_tag == nsXPTType::T_UTF8STRING ||
type_tag == nsXPTType::T_CSTRING,
"Unexpected string class type!");
// ASTRING and DOMSTRING are very similar, and both use nsString.
// UTF8_STRING and CSTRING are also quite similar, and both use nsCString.
if (type_tag == nsXPTType::T_ASTRING || type_tag == nsXPTType::T_DOMSTRING)
dp->val.p = mCallContext.GetContext()->mScratchStrings.Create();
else
dp->val.p = mCallContext.GetContext()->mScratchCStrings.Create();
// Check for OOM, in either case.
if (!dp->val.p) {
JS_ReportOutOfMemory(mCallContext);
if (!XPCConvert::JSData2Native(&dp->val, src, type,
&param_iid, array_count, &err)) {
ThrowBadParam(err, i, mCallContext);
return false;
}
// We allocated, so we need to deallocate after the method call completes.
dp->SetValNeedsCleanup();
return true;
}
@ -1962,6 +1749,44 @@ CallMethodHelper::Invoke()
return NS_InvokeByIndex(mCallee, mVTableIndex, argc, argv);
}
static void
TraceParam(JSTracer* aTrc, void* aVal, const nsXPTType& aType,
uint32_t aArrayLen = 0)
{
if (aType.Tag() == nsXPTType::T_JSVAL) {
JS::UnsafeTraceRoot(aTrc, (JS::Value*)aVal,
"XPCWrappedNative::CallMethod param");
} else if (aType.Tag() == nsXPTType::T_ARRAY && *(void**)aVal) {
const nsXPTType& elty = aType.ArrayElementType();
if (elty.Tag() != nsXPTType::T_JSVAL) {
return;
}
for (uint32_t i = 0; i < aArrayLen; ++i) {
TraceParam(aTrc, elty.ElementPtr(aVal, i), elty);
}
}
}
void
CallMethodHelper::trace(JSTracer* aTrc)
{
// We need to note each of our initialized parameters which contain jsvals.
for (nsXPTCVariant& param : mDispatchParams) {
if (!param.DoesValNeedCleanup()) {
MOZ_ASSERT(param.type.Tag() != nsXPTType::T_JSVAL,
"JSVals are marked as needing cleanup (even though they don't)");
continue;
}
uint32_t arrayLen = 0;
if (!GetArraySizeFromParam(param.type, UndefinedHandleValue, &arrayLen))
continue;
TraceParam(aTrc, &param.val, param.type, arrayLen);
}
}
/***************************************************************************/
// interface methods

View File

@ -332,52 +332,6 @@ MOZ_DEFINE_ENUM(WatchdogTimestampCategory, (
class AsyncFreeSnowWhite;
template <class StringType>
class ShortLivedStringBuffer
{
public:
StringType* Create()
{
for (uint32_t i = 0; i < ArrayLength(mStrings); ++i) {
if (!mStrings[i]) {
mStrings[i].emplace();
return mStrings[i].ptr();
}
}
// All our internal string wrappers are used, allocate a new string.
return new StringType();
}
void Destroy(StringType* string)
{
for (uint32_t i = 0; i < ArrayLength(mStrings); ++i) {
if (mStrings[i] && mStrings[i].ptr() == string) {
// One of our internal strings is no longer in use, mark
// it as such and free its data.
mStrings[i].reset();
return;
}
}
// We're done with a string that's not one of our internal
// strings, delete it.
delete string;
}
~ShortLivedStringBuffer()
{
#ifdef DEBUG
for (uint32_t i = 0; i < ArrayLength(mStrings); ++i) {
MOZ_ASSERT(!mStrings[i], "Short lived string still in use");
}
#endif
}
private:
mozilla::Maybe<StringType> mStrings[2];
};
class XPCJSContext final : public mozilla::CycleCollectedJSContext
, public mozilla::LinkedListElement<XPCJSContext>
{
@ -470,9 +424,6 @@ public:
inline JS::HandleId GetStringID(unsigned index) const;
inline const char* GetStringName(unsigned index) const;
ShortLivedStringBuffer<nsString> mScratchStrings;
ShortLivedStringBuffer<nsCString> mScratchCStrings;
private:
XPCJSContext();
@ -1799,31 +1750,19 @@ private:
{if (b) mDescriptors[i/32] |= (1 << (i%32));
else mDescriptors[i/32] &= ~(1 << (i%32));}
bool GetArraySizeFromParam(JSContext* cx,
const nsXPTMethodInfo* method,
const nsXPTParamInfo& param,
uint16_t methodIndex,
uint8_t paramIndex,
bool GetArraySizeFromParam(const nsXPTMethodInfo* method,
const nsXPTType& type,
nsXPTCMiniVariant* params,
uint32_t* result) const;
bool GetInterfaceTypeFromParam(JSContext* cx,
const nsXPTMethodInfo* method,
const nsXPTParamInfo& param,
uint16_t methodIndex,
bool GetInterfaceTypeFromParam(const nsXPTMethodInfo* method,
const nsXPTType& type,
nsXPTCMiniVariant* params,
nsID* result) const;
static void CleanupPointerArray(const nsXPTType& datum_type,
uint32_t array_count,
void** arrayp);
static void CleanupPointerTypeObject(const nsXPTType& type,
void** pp);
void CleanupOutparams(JSContext* cx, uint16_t methodIndex, const nsXPTMethodInfo* info,
nsXPTCMiniVariant* nativeParams, bool inOutOnly, uint8_t n) const;
void CleanupOutparams(const nsXPTMethodInfo* info,
nsXPTCMiniVariant* nativeParams,
bool inOutOnly, uint8_t n) const;
private:
XPCJSRuntime* mRuntime;
@ -1999,11 +1938,13 @@ public:
static bool NativeData2JS(JS::MutableHandleValue d,
const void* s, const nsXPTType& type,
const nsID* iid, nsresult* pErr);
const nsID* iid, uint32_t arrlen,
nsresult* pErr);
static bool JSData2Native(void* d, JS::HandleValue s,
const nsXPTType& type,
const nsID* iid,
uint32_t arrlen,
nsresult* pErr);
/**
@ -2049,7 +1990,7 @@ public:
* @param scope the default scope to put on the new JSObjects' parent chain
* @param pErr [out] relevant error code, if any.
*/
static bool NativeArray2JS(JS::MutableHandleValue d, const void** s,
static bool NativeArray2JS(JS::MutableHandleValue d, const void* const* s,
const nsXPTType& type, const nsID* iid,
uint32_t count, nsresult* pErr);
@ -2063,15 +2004,6 @@ public:
const nsXPTType& type,
nsresult* pErr);
static bool NativeStringWithSize2JS(JS::MutableHandleValue d, const void* s,
const nsXPTType& type,
uint32_t count,
nsresult* pErr);
static bool JSStringWithSize2Native(void* d, JS::HandleValue s,
uint32_t count, const nsXPTType& type,
nsresult* pErr);
static nsresult JSValToXPCException(JS::MutableHandleValue s,
const char* ifaceName,
const char* methodName,
@ -3109,6 +3041,39 @@ nsresult HasInstance(JSContext* cx, JS::HandleObject objArg, const nsID* iid, bo
nsIPrincipal* GetObjectPrincipal(JSObject* obj);
// Attempt to clean up the passed in value pointer. The pointer `value` must be
// a pointer to a value described by the type `nsXPTType`.
//
// This method expects a value of the following types:
// TD_PNSIID
// value : nsID* (free)
// TD_DOMSTRING, TD_ASTRING, TD_CSTRING, TD_UTF8STRING
// value : ns[C]String* (truncate)
// TD_PSTRING, TD_PWSTRING, TD_PSTRING_SIZE_IS, TD_PWSTRING_SIZE_IS
// value : char[16_t]** (free)
// TD_INTERFACE_TYPE, TD_INTERFACE_IS_TYPE
// value : nsISupports** (release)
// TD_ARRAY (NOTE: aArrayLen should be passed)
// value : void** (cleanup elements & free)
// TD_DOMOBJECT
// value : T** (cleanup)
// TD_PROMISE
// value : dom::Promise** (release)
//
// Other types are ignored.
//
// Custom behaviour may be desired in some situations:
// - This method Truncate()s nsStrings, it does not free them.
// - This method does not unroot JSValues.
inline void CleanupValue(const nsXPTType& aType,
void* aValue,
uint32_t aArrayLen = 0);
// Out-of-line internals for xpc::CleanupValue. Defined in XPCConvert.cpp.
void InnerCleanupValue(const nsXPTType& aType,
void* aValue,
uint32_t aArrayLen);
} // namespace xpc
namespace mozilla {

View File

@ -87,6 +87,16 @@ VARCACHE_PREF(
bool, false
)
//---------------------------------------------------------------------------
// DOM prefs
//---------------------------------------------------------------------------
VARCACHE_PREF(
"dom.webcomponents.shadowdom.report_usage",
dom_webcomponents_shadowdom_report_usage,
bool, false
)
//---------------------------------------------------------------------------
// Full-screen prefs
//---------------------------------------------------------------------------

View File

@ -145,7 +145,7 @@ NS_IMETHODIMP
SecretDecoderRing::AsyncEncryptStrings(uint32_t plaintextsCount,
const char16_t** plaintexts,
JSContext* aCx,
nsISupports** aPromise) {
Promise** aPromise) {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
NS_ENSURE_ARG(plaintextsCount);
NS_ENSURE_ARG_POINTER(plaintexts);

View File

@ -33,8 +33,8 @@ interface nsISecretDecoderRing: nsISupports {
* @return A promise for the list of encrypted strings, encoded as Base64.
*/
[implicit_jscontext, must_use]
nsISupports asyncEncryptStrings(in unsigned long plaintextsCount,
[array, size_is(plaintextsCount)] in wstring plaintexts);
Promise asyncEncryptStrings(in unsigned long plaintextsCount,
[array, size_is(plaintextsCount)] in wstring plaintexts);
/**
* Decrypt Base64 input.

View File

@ -1 +1 @@
NSS_3_37_RTM
6e4b0141df2f

View File

@ -1 +1 @@
NSS_3_36_BRANCH
NSS_3_37_BRANCH

View File

@ -1,4 +1,4 @@
FROM ubuntu:latest
FROM ubuntu:16.04
MAINTAINER Tim Taubert <ttaubert@mozilla.com>
RUN useradd -d /home/worker -s /bin/bash -m worker

View File

@ -10,3 +10,4 @@
*/
#error "Do not include this header file."

View File

@ -884,6 +884,45 @@ TEST_P(TlsConnectDatagram12Plus, MissAWindowAndOne) {
SendReceive();
}
// This filter replaces the first record it sees with junk application data.
class TlsReplaceFirstRecordWithJunk : public TlsRecordFilter {
public:
TlsReplaceFirstRecordWithJunk(const std::shared_ptr<TlsAgent>& a)
: TlsRecordFilter(a), replaced_(false) {}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& record, size_t* offset,
DataBuffer* output) override {
if (replaced_) {
return KEEP;
}
replaced_ = true;
TlsRecordHeader out_header(header.variant(), header.version(),
kTlsApplicationDataType,
header.sequence_number());
static const uint8_t junk[] = {1, 2, 3, 4};
*offset = out_header.Write(output, *offset, DataBuffer(junk, sizeof(junk)));
return CHANGE;
}
private:
bool replaced_;
};
// DTLS needs to discard application_data that it receives prior to handshake
// completion, not generate an error.
TEST_P(TlsConnectDatagram, ReplaceFirstServerRecordWithApplicationData) {
MakeTlsFilter<TlsReplaceFirstRecordWithJunk>(server_);
Connect();
}
TEST_P(TlsConnectDatagram, ReplaceFirstClientRecordWithApplicationData) {
MakeTlsFilter<TlsReplaceFirstRecordWithJunk>(client_);
Connect();
}
INSTANTIATE_TEST_CASE_P(Datagram12Plus, TlsConnectDatagram12Plus,
TlsConnectTestBase::kTlsV12Plus);
INSTANTIATE_TEST_CASE_P(DatagramPre13, TlsConnectDatagramPre13,

View File

@ -528,7 +528,9 @@ nssToken_ImportCertificate(
*/
NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
if (!rvObject->label && nickname) {
NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
}
NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
/* reset the mutable attributes on the token */
nssCKObject_SetAttributes(rvObject->handle,

View File

@ -180,7 +180,7 @@ blake2b_Begin(BLAKE2BContext* ctx, uint8_t outlen, const uint8_t* key,
return SECSuccess;
failure:
PORT_Memset(&ctx, 0, sizeof(ctx));
PORT_Memset(ctx, 0, sizeof(*ctx));
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}

View File

@ -22,12 +22,12 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define NSS_VERSION "3.37" _NSS_CUSTOMIZED
#define NSS_VERSION "3.38" _NSS_CUSTOMIZED " Beta"
#define NSS_VMAJOR 3
#define NSS_VMINOR 37
#define NSS_VMINOR 38
#define NSS_VPATCH 0
#define NSS_VBUILD 0
#define NSS_BETA PR_FALSE
#define NSS_BETA PR_TRUE
#ifndef RC_INVOKED

View File

@ -37,6 +37,10 @@
#elif defined(XP_UNIX)
#include <unistd.h>
#endif
#if defined(LINUX) && !defined(ANDROID)
#include <linux/magic.h>
#include <sys/vfs.h>
#endif
#include "utilpars.h"
#ifdef SQLITE_UNSAFE_THREADS
@ -1763,6 +1767,8 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
PRIntervalTime now = 0;
char *env;
PRBool enableCache = PR_FALSE;
PRBool checkFSType = PR_FALSE;
PRBool measureSpeed = PR_FALSE;
PRBool create;
int flags = inFlags & 0x7;
@ -1923,11 +1929,48 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
env = PR_GetEnvSecure("NSS_SDB_USE_CACHE");
if (!env || PORT_Strcasecmp(env, "no") == 0) {
enableCache = PR_FALSE;
/* Variables enableCache, checkFSType, measureSpeed are PR_FALSE by default,
* which is the expected behavior for NSS_SDB_USE_CACHE="no".
* We don't need to check for "no" here. */
if (!env) {
/* By default, with no variable set, we avoid expensive measuring for
* most FS types. We start with inexpensive FS type checking, and
* might perform measuring for some types. */
checkFSType = PR_TRUE;
} else if (PORT_Strcasecmp(env, "yes") == 0) {
enableCache = PR_TRUE;
} else {
} else if (PORT_Strcasecmp(env, "no") != 0) { /* not "no" => "auto" */
measureSpeed = PR_TRUE;
}
if (checkFSType) {
#if defined(LINUX) && !defined(ANDROID)
struct statfs statfs_s;
if (statfs(dbname, &statfs_s) == 0) {
switch (statfs_s.f_type) {
case SMB_SUPER_MAGIC:
case 0xff534d42: /* CIFS_MAGIC_NUMBER */
case NFS_SUPER_MAGIC:
/* We assume these are slow. */
enableCache = PR_TRUE;
break;
case CODA_SUPER_MAGIC:
case 0x65735546: /* FUSE_SUPER_MAGIC */
case NCP_SUPER_MAGIC:
/* It's uncertain if this FS is fast or slow.
* It seems reasonable to perform slow measuring for users
* with questionable FS speed. */
measureSpeed = PR_TRUE;
break;
case AFS_SUPER_MAGIC: /* Already implements caching. */
default:
break;
}
}
#endif
}
if (measureSpeed) {
char *tempDir = NULL;
PRUint32 tempOps = 0;
/*

View File

@ -17,11 +17,11 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define SOFTOKEN_VERSION "3.37" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VERSION "3.38" SOFTOKEN_ECC_STRING " Beta"
#define SOFTOKEN_VMAJOR 3
#define SOFTOKEN_VMINOR 37
#define SOFTOKEN_VMINOR 38
#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE
#define SOFTOKEN_BETA PR_TRUE
#endif /* _SOFTKVER_H_ */

View File

@ -12166,6 +12166,14 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
* processed twice. */
plaintext->len = 0;
/* We're waiting for another ClientHello, which will appear unencrypted.
* Use the content type to tell whether this should be discarded. */
if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr &&
cText->hdr[0] == content_application_data) {
PORT_Assert(ss->ssl3.hs.ws == wait_client_hello);
return SECSuccess;
}
ssl_GetSpecReadLock(ss); /******************************************/
spec = ssl3_GetCipherSpec(ss, cText);
if (!spec) {
@ -12196,18 +12204,6 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
return SECFailure;
}
/* We're waiting for another ClientHello, which will appear unencrypted.
* Use the content type to tell whether this is should be discarded.
*
* XXX If we decide to remove the content type from encrypted records, this
* will become much more difficult to manage. */
if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr &&
cText->hdr[0] == content_application_data) {
ssl_ReleaseSpecReadLock(ss); /*****************************/
PORT_Assert(ss->ssl3.hs.ws == wait_client_hello);
return SECSuccess;
}
if (plaintext->space < MAX_FRAGMENT_LENGTH) {
rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
if (rv != SECSuccess) {
@ -12220,23 +12216,33 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
}
}
#ifdef UNSAFE_FUZZER_MODE
/* Most record types aside from protected TLS 1.3 records carry the content
* type in the first octet. TLS 1.3 will override this value later. */
rType = cText->hdr[0];
rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len,
plaintext->space, cText->buf->buf, cText->buf->len);
#else
/* IMPORTANT: Unprotect functions MUST NOT send alerts
* because we still hold the spec read lock. Instead, if they
* return SECFailure, they set *alert to the alert to be sent. */
if (spec->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
spec->cipherDef->calg == ssl_calg_null) {
/* Unencrypted TLS 1.3 records use the pre-TLS 1.3 format. */
rType = cText->hdr[0];
rv = ssl3_UnprotectRecord(ss, spec, cText, plaintext, &alert);
/* Encrypted application data records could arrive before the handshake
* completes in DTLS 1.3. These can look like valid TLS 1.2 application_data
* records in epoch 0, which is never valid. Pretend they didn't decrypt. */
if (spec->epoch == 0 && rType == content_application_data) {
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
alert = unexpected_message;
rv = SECFailure;
} else {
rv = tls13_UnprotectRecord(ss, spec, cText, plaintext, &rType, &alert);
}
#ifdef UNSAFE_FUZZER_MODE
rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len,
plaintext->space, cText->buf->buf, cText->buf->len);
#else
/* IMPORTANT: Unprotect functions MUST NOT send alerts
* because we still hold the spec read lock. Instead, if they
* return SECFailure, they set *alert to the alert to be sent. */
if (spec->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
spec->epoch == 0) {
rv = ssl3_UnprotectRecord(ss, spec, cText, plaintext, &alert);
} else {
rv = tls13_UnprotectRecord(ss, spec, cText, plaintext, &rType,
&alert);
}
#endif
}
if (rv != SECSuccess) {
ssl_ReleaseSpecReadLock(ss); /***************************/
@ -12246,10 +12252,10 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
/* Ensure that we don't process this data again. */
plaintext->len = 0;
/* Ignore a CCS if the alternative handshake is negotiated. Note that
* this will fail if the server fails to negotiate the alternative
* handshake type in a 0-RTT session that is resumed from a session that
* did negotiate it. We don't care about that corner case right now. */
/* Ignore a CCS if compatibility mode is negotiated. Note that this
* will fail if the server fails to negotiate compatibility mode in a
* 0-RTT session that is resumed from a session that did negotiate it.
* We don't care about that corner case right now. */
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
cText->hdr[0] == content_change_cipher_spec &&
ss->ssl3.hs.ws != idle_handshake &&
@ -12258,19 +12264,20 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
/* Ignore the CCS. */
return SECSuccess;
}
if (IS_DTLS(ss) ||
(ss->sec.isServer &&
ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
/* Silently drop the packet */
return SECSuccess;
} else {
int errCode = PORT_GetError();
SSL3_SendAlert(ss, alert_fatal, alert);
/* Reset the error code in case SSL3_SendAlert called
* PORT_SetError(). */
PORT_SetError(errCode);
return SECFailure;
}
int errCode = PORT_GetError();
SSL3_SendAlert(ss, alert_fatal, alert);
/* Reset the error code in case SSL3_SendAlert called
* PORT_SetError(). */
PORT_SetError(errCode);
return SECFailure;
}
/* SECSuccess */

View File

@ -19,12 +19,12 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
#define NSSUTIL_VERSION "3.37"
#define NSSUTIL_VERSION "3.38 Beta"
#define NSSUTIL_VMAJOR 3
#define NSSUTIL_VMINOR 37
#define NSSUTIL_VMINOR 38
#define NSSUTIL_VPATCH 0
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_FALSE
#define NSSUTIL_BETA PR_TRUE
SEC_BEGIN_PROTOS

View File

@ -1060,6 +1060,25 @@ cert_extended_ssl()
# -d "${PROFILEDIR}" -i "${CLIENT_CADIR}/clientCA-ecmixed.ca.cert" \
# 2>&1
# Check that a repeated import with a different nickname doesn't change the
# nickname of the existing cert (bug 1458518).
# We want to search for the results using grep, to avoid subset matches,
# we'll use one of the longer nicknames for testing.
# (Because "grep -w hostname" matches "grep -w hostname-dsamixed")
MYDBPASS="-d ${PROFILEDIR} -f ${R_PWFILE}"
TESTNAME="Ensure there's exactly one match for ${CERTNAME}-dsamixed"
cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-dsamixed" 0 1 "${TESTNAME}"
CU_ACTION="Repeated import of $CERTNAME's mixed DSA Cert with different nickname"
certu -A -n "${CERTNAME}-repeated-dsamixed" -t "u,u,u" -d "${PROFILEDIR}" \
-f "${R_PWFILE}" -i "${CERTNAME}-dsamixed.cert" 2>&1
TESTNAME="Ensure there's still exactly one match for ${CERTNAME}-dsamixed"
cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-dsamixed" 0 1 "${TESTNAME}"
TESTNAME="Ensure there's zero matches for ${CERTNAME}-repeated-dsamixed"
cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-repeated-dsamixed" 0 0 "${TESTNAME}"
echo "Importing all the server's own CA chain into the servers DB"
for CA in `find ${SERVER_CADIR} -name "?*.ca.cert"` ;
do
@ -1532,6 +1551,37 @@ cert_make_with_param()
return 0
}
cert_check_nickname_exists()
{
MYDIRPASS="$1"
MYCERTNAME="$2"
EXPECT="$3"
EXPECTCOUNT="$4"
MYTESTNAME="$5"
echo certutil ${MYDIRPASS} -L
${BINDIR}/certutil ${MYDIRPASS} -L
RET=$?
if [ "${RET}" -ne "${EXPECT}" ]; then
CERTFAILED=1
html_failed "${MYTESTNAME} - list"
cert_log "ERROR: ${MYTESTNAME} - list"
return 1
fi
LISTCOUNT=`${BINDIR}/certutil ${MYDIRPASS} -L | grep -wc ${MYCERTNAME}`
if [ "${LISTCOUNT}" -ne "${EXPECTCOUNT}" ]; then
CERTFAILED=1
html_failed "${MYTESTNAME} - list and count"
cert_log "ERROR: ${MYTESTNAME} - list and count failed"
return 1
fi
html_passed "${MYTESTNAME}"
return 0
}
cert_list_and_count_dns()
{
DIRPASS="$1"

View File

@ -42,6 +42,7 @@ xpcshell:
linux32/debug: 12
linux64/debug: 10
android-4.2-x86/opt: 6
android-4.3-arm7-api-16/debug: 12
macosx.*: 1
windows.*: 1
windows10-64-ccov/debug: 8

View File

@ -1,4 +1,5 @@
[child-navigates-parent-blocked.html]
disabled: if not debug && (os == "linux") https://bugzilla.mozilla.org/show_bug.cgi?id=1450864
[Test that the child can't navigate the parent because the relevant policy belongs to the navigation initiator (in this case the child)]
expected: FAIL

View File

@ -5,9 +5,6 @@
[Stringification of document]
expected: FAIL
[ProcessingInstruction interface: attribute sheet]
expected: FAIL
[CSSRule interface: constant MARGIN_RULE on interface object]
expected: FAIL

View File

@ -17,9 +17,9 @@ interface nsICrashService : nsISupports
* @param id
* Crash ID. Likely a UUID.
*
* @return {Promise} A promise that resolves after the crash has been stored
* @return A promise that resolves after the crash has been stored
*/
nsISupports addCrash(in long processType, in long crashType, in AString id);
Promise addCrash(in long processType, in long crashType, in AString id);
const long PROCESS_TYPE_MAIN = 0;
const long PROCESS_TYPE_CONTENT = 1;

View File

@ -976,7 +976,7 @@ public:
#endif // MOZ_GECKO_PROFILER
NS_IMETHODIMP
TelemetryImpl::GetLoadedModules(JSContext *cx, nsISupports** aPromise)
TelemetryImpl::GetLoadedModules(JSContext *cx, Promise** aPromise)
{
#if defined(MOZ_GECKO_PROFILER)
nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));

View File

@ -198,7 +198,7 @@ interface nsITelemetry : nsISupports
* @throws NS_ERROR_NOT_IMPLEMENTED if the Gecko profiler is not enabled.
*/
[implicit_jscontext]
nsISupports getLoadedModules();
Promise getLoadedModules();
/*
* An object with two fields: memoryMap and stacks.

View File

@ -5,7 +5,7 @@
"use strict";
/* import-globals-from ../../../content/contentAreaUtils.js */
/* globals XMLStylesheetProcessingInstruction */
/* globals ProcessingInstruction */
/* exported UPDATES_RELEASENOTES_TRANSFORMFILE, XMLURI_PARSE_ERROR, loadView, gBrowser */
ChromeUtils.import("resource://gre/modules/DeferredTask.jsm");
@ -109,7 +109,7 @@ Object.defineProperty(this, "gIsInitializing", {
function initialize(event) {
// XXXbz this listener gets _all_ load events for all nodes in the
// document... but relies on not being called "too early".
if (event.target instanceof XMLStylesheetProcessingInstruction) {
if (event.target instanceof ProcessingInstruction) {
return;
}
document.removeEventListener("load", initialize, true);

View File

@ -56,17 +56,17 @@ interface nsIProfiler : nsISupports
jsval getProfileData([optional] in double aSinceTime);
[implicit_jscontext]
nsISupports getProfileDataAsync([optional] in double aSinceTime);
Promise getProfileDataAsync([optional] in double aSinceTime);
[implicit_jscontext]
nsISupports getProfileDataAsArrayBuffer([optional] in double aSinceTime);
Promise getProfileDataAsArrayBuffer([optional] in double aSinceTime);
/**
* Returns a promise that resolves once the file has been written.
*/
[implicit_jscontext]
nsISupports dumpProfileToFileAsync(in ACString aFilename,
[optional] in double aSinceTime);
Promise dumpProfileToFileAsync(in ACString aFilename,
[optional] in double aSinceTime);
boolean IsActive();

View File

@ -222,7 +222,7 @@ nsProfiler::GetProfileData(double aSinceTime, JSContext* aCx,
NS_IMETHODIMP
nsProfiler::GetProfileDataAsync(double aSinceTime, JSContext* aCx,
nsISupports** aPromise)
Promise** aPromise)
{
MOZ_ASSERT(NS_IsMainThread());
@ -290,7 +290,7 @@ nsProfiler::GetProfileDataAsync(double aSinceTime, JSContext* aCx,
NS_IMETHODIMP
nsProfiler::GetProfileDataAsArrayBuffer(double aSinceTime, JSContext* aCx,
nsISupports** aPromise)
Promise** aPromise)
{
MOZ_ASSERT(NS_IsMainThread());
@ -347,7 +347,7 @@ nsProfiler::GetProfileDataAsArrayBuffer(double aSinceTime, JSContext* aCx,
NS_IMETHODIMP
nsProfiler::DumpProfileToFileAsync(const nsACString& aFilename,
double aSinceTime, JSContext* aCx,
nsISupports** aPromise)
Promise** aPromise)
{
MOZ_ASSERT(NS_IsMainThread());

View File

@ -17,7 +17,16 @@ typedef int64_t PRTime;
*/
#include "nsStringFwd.h"
/*
/*
* Forward declaration of mozilla::dom::Promise
*/
namespace mozilla {
namespace dom {
class Promise;
} // namespace dom
} // namespace mozilla
/*
* Start commenting out the C++ versions of the below in the output header
*/
#if 0
@ -88,6 +97,8 @@ typedef unsigned long size_t;
[ref, jsval] native jsval(jsval);
native jsid(jsid);
[ptr, promise] native Promise(ignored);
%{C++
/*
* End commenting out the C++ versions of the above in the output header

View File

@ -53,8 +53,6 @@
#include "nsThreadManager.h"
#include "nsThreadPool.h"
#include "xptinfo.h"
#include "nsTimerImpl.h"
#include "TimerThread.h"

View File

@ -9,7 +9,6 @@
#include "nscore.h"
#include "nsXPCOM.h"
#include "xptcall.h"
/**
* During this shutdown notification all threads which run XPCOM code must

View File

@ -178,6 +178,7 @@ jsvalue_include = """
"""
infallible_includes = """
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"
"""
@ -306,7 +307,7 @@ iface_forward_safe = """
/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
#define NS_FORWARD_SAFE_%(macroname)s(_to) """
attr_infallible_tmpl = """\
attr_builtin_infallible_tmpl = """\
inline %(realtype)s%(nativename)s(%(args)s)
{
%(realtype)sresult;
@ -316,6 +317,19 @@ attr_infallible_tmpl = """\
}
"""
# NOTE: We don't use RefPtr::forget here because we don't want to need the
# definition of %(realtype)s in scope, which we would need for the
# AddRef/Release calls.
attr_refcnt_infallible_tmpl = """\
inline already_AddRefed<%(realtype)s>%(nativename)s(%(args)s)
{
%(realtype)s* result = nullptr;
mozilla::DebugOnly<nsresult> rv = %(nativename)s(%(argnames)s&result);
MOZ_ASSERT(NS_SUCCEEDED(rv));
return already_AddRefed<%(realtype)s>(result);
}
"""
def write_interface(iface, fd):
if iface.namemap is None:
@ -363,11 +377,18 @@ def write_interface(iface, fd):
fd.write(" %s = 0;\n" % attributeAsNative(a, True))
if a.infallible:
fd.write(attr_infallible_tmpl %
{'realtype': a.realtype.nativeType('in'),
'nativename': attributeNativeName(a, getter=True),
'args': '' if not a.implicit_jscontext else 'JSContext* cx',
'argnames': '' if not a.implicit_jscontext else 'cx, '})
realtype = a.realtype.nativeType('in')
tmpl = attr_builtin_infallible_tmpl
if a.realtype.kind != 'builtin':
assert realtype.endswith(' *'), "bad infallible type"
tmpl = attr_refcnt_infallible_tmpl
realtype = realtype[:-2] # strip trailing pointer
fd.write(tmpl % {'realtype': realtype,
'nativename': attributeNativeName(a, getter=True),
'args': '' if not a.implicit_jscontext else 'JSContext* cx',
'argnames': '' if not a.implicit_jscontext else 'cx, '})
if not a.readonly:
fd.write(" %s = 0;\n" % attributeAsNative(a, False))

View File

@ -45,6 +45,7 @@ TypeMap = {
'utf8string': 'TD_UTF8STRING',
'cstring': 'TD_CSTRING',
'jsval': 'TD_JSVAL',
'promise': 'TD_PROMISE',
}

View File

@ -245,7 +245,8 @@ def attrAsWrapper(iface, m, getter):
name = attributeParamName(m)
if getter and m.infallible:
if getter and m.infallible and m.realtype.kind == 'builtin':
# NOTE: We don't support non-builtin infallible getters in Rust code.
return infallible_impl_tmpl % {
'name': attributeNativeName(m, getter),
'realtype': m.realtype.rustType('in'),

View File

@ -455,8 +455,9 @@ class Native(object):
'utf8string': 'nsACString',
'cstring': 'nsACString',
'astring': 'nsAString',
'jsval': 'JS::Value'
}
'jsval': 'JS::Value',
'promise': '::mozilla::dom::Promise',
}
# Mappings from C++ native name types to rust native names. Types which
# aren't listed here are incompatible with rust code.
@ -505,6 +506,9 @@ class Native(object):
if self.specialtype is None:
return False
if self.specialtype == 'promise':
return self.modifier == 'ptr'
if self.specialtype == 'nsid':
return self.modifier is not None
@ -522,7 +526,7 @@ class Native(object):
raise IDLError("[shared] only applies to out parameters.")
const = True
if self.specialtype is not None and calltype == 'in':
if self.specialtype not in [None, 'promise'] and calltype == 'in':
const = True
if self.specialtype == 'jsval':
@ -936,8 +940,8 @@ class Attribute(object):
getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
raise IDLError("'Undefined' attribute can only be used on DOMString",
self.location)
if self.infallible and not self.realtype.kind == 'builtin':
raise IDLError('[infallible] only works on builtin types '
if self.infallible and not self.realtype.kind in ['builtin', 'interface', 'forward', 'webidl']:
raise IDLError('[infallible] only works on interfaces, domobjects, and builtin types '
'(numbers, booleans, and raw char types)',
self.location)
if self.infallible and not iface.attributes.builtinclass:

View File

@ -17,7 +17,9 @@
struct nsXPTCMiniVariant
{
union U
// No ctors or dtors so that we can use arrays of these on the stack
// with no penalty.
union Union
{
int8_t i8;
int16_t i16;
@ -33,26 +35,47 @@ struct nsXPTCMiniVariant
char c;
char16_t wc;
void* p;
};
// Types below here are unknown to the assembly implementations, and
// therefore _must_ be passed with indirect semantics. We put them in
// the union here for type safety, so that we can avoid void* tricks.
JS::Value j;
// |j| has a non-trivial constructor and therefore MUST be
// placement-new'd into existence.
MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
U() {}
MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
} val;
Union val;
};
struct nsXPTCVariant : public nsXPTCMiniVariant
{
// No ctors or dtors so that we can use arrays of these on the stack
// with no penalty.
static_assert(offsetof(nsXPTCMiniVariant, val) == 0,
"nsXPTCMiniVariant must be a thin wrapper");
struct nsXPTCVariant
{
// No ctors or dtors so that we can use arrays of these on the stack with no
// penalty.
union ExtendedVal
{
// ExtendedVal is an extension on nsXPTCMiniVariant. It contains types
// unknown to the assembly implementations which must be passed by indirect
// semantics.
//
// nsXPTCVariant contains enough space to store ExtendedVal inline, which
// can be used to store these types when IsIndirect() is true.
nsXPTCMiniVariant mini;
nsCString nscstr;
nsString nsstr;
JS::Value jsval;
// This type contains non-standard-layout types, so needs an explicit
// Ctor/Dtor - we'll just delete them.
ExtendedVal() = delete;
~ExtendedVal() = delete;
};
union
{
// The `val` field from nsXPTCMiniVariant.
nsXPTCMiniVariant::Union val;
// Storage for any extended variants.
ExtendedVal ext;
};
// inherits 'val' here
void* ptr;
nsXPTType type;
uint8_t flags;
@ -98,53 +121,23 @@ struct nsXPTCVariant : public nsXPTCMiniVariant
// Internal use only. Use IsIndirect() instead.
bool IsPtrData() const {return 0 != (flags & PTR_IS_DATA);}
void Init(const nsXPTCMiniVariant& mv, const nsXPTType& t, uint8_t f)
{
type = t;
flags = f;
if(f & PTR_IS_DATA)
{
ptr = mv.val.p;
val.p = nullptr;
}
else
{
ptr = nullptr;
val.p = nullptr; // make sure 'val.p' is always initialized
switch(t.TagPart()) {
case nsXPTType::T_I8: val.i8 = mv.val.i8; break;
case nsXPTType::T_I16: val.i16 = mv.val.i16; break;
case nsXPTType::T_I32: val.i32 = mv.val.i32; break;
case nsXPTType::T_I64: val.i64 = mv.val.i64; break;
case nsXPTType::T_U8: val.u8 = mv.val.u8; break;
case nsXPTType::T_U16: val.u16 = mv.val.u16; break;
case nsXPTType::T_U32: val.u32 = mv.val.u32; break;
case nsXPTType::T_U64: val.u64 = mv.val.u64; break;
case nsXPTType::T_FLOAT: val.f = mv.val.f; break;
case nsXPTType::T_DOUBLE: val.d = mv.val.d; break;
case nsXPTType::T_BOOL: val.b = mv.val.b; break;
case nsXPTType::T_CHAR: val.c = mv.val.c; break;
case nsXPTType::T_WCHAR: val.wc = mv.val.wc; break;
case nsXPTType::T_VOID: /* fall through */
case nsXPTType::T_IID: /* fall through */
case nsXPTType::T_DOMSTRING: /* fall through */
case nsXPTType::T_CHAR_STR: /* fall through */
case nsXPTType::T_WCHAR_STR: /* fall through */
case nsXPTType::T_INTERFACE: /* fall through */
case nsXPTType::T_INTERFACE_IS: /* fall through */
case nsXPTType::T_DOMOBJECT: /* fall through */
case nsXPTType::T_ARRAY: /* fall through */
case nsXPTType::T_PSTRING_SIZE_IS: /* fall through */
case nsXPTType::T_PWSTRING_SIZE_IS: /* fall through */
case nsXPTType::T_UTF8STRING: /* fall through */
case nsXPTType::T_CSTRING: /* fall through */
default: val.p = mv.val.p; break;
}
}
// Implicitly convert to nsXPTCMiniVariant.
operator nsXPTCMiniVariant&() {
return *(nsXPTCMiniVariant*) &val;
}
operator const nsXPTCMiniVariant&() const {
return *(const nsXPTCMiniVariant*) &val;
}
// As this type contains an anonymous union, we need to provide explicit
// constructors & destructors.
nsXPTCVariant() { }
~nsXPTCVariant() { }
};
static_assert(offsetof(nsXPTCVariant, val) == offsetof(nsXPTCVariant, ext),
"nsXPTCVariant::{ext,val} must have matching offsets");
class nsIXPTCProxy : public nsISupports
{
public:

View File

@ -150,6 +150,33 @@ def splitint(i):
return (i >> 8, i & 0xff)
# Occasionally in xpconnect, we need to fabricate types to pass into the
# conversion methods. In some cases, these types need to be arrays, which hold
# indicies into the extra types array.
#
# These are some types which should have known indexes into the extra types
# array.
utility_types = [
{ 'tag': 'TD_INT8' },
{ 'tag': 'TD_UINT8' },
{ 'tag': 'TD_INT16' },
{ 'tag': 'TD_UINT16' },
{ 'tag': 'TD_INT32' },
{ 'tag': 'TD_UINT32' },
{ 'tag': 'TD_INT64' },
{ 'tag': 'TD_UINT64' },
{ 'tag': 'TD_FLOAT' },
{ 'tag': 'TD_DOUBLE' },
{ 'tag': 'TD_BOOL' },
{ 'tag': 'TD_CHAR' },
{ 'tag': 'TD_WCHAR' },
{ 'tag': 'TD_PNSIID' },
{ 'tag': 'TD_PSTRING' },
{ 'tag': 'TD_PWSTRING' },
{ 'tag': 'TD_INTERFACE_IS_TYPE', 'iid_is': 0 },
]
# Core of the code generator. Takes a list of raw JSON XPT interfaces, and
# writes out a file containing the necessary static declarations into fd.
def link_to_cpp(interfaces, fd):
@ -220,6 +247,14 @@ def link_to_cpp(interfaces, fd):
strings[s] = 0
return strings[s]
def lower_extra_type(type):
key = describe_type(type)
idx = type_cache.get(key)
if idx is None:
idx = type_cache[key] = len(types)
types.append(lower_type(type))
return idx
def describe_type(type): # Create the type's documentation comment.
tag = type['tag'][3:].lower()
if tag == 'array':
@ -239,13 +274,7 @@ def link_to_cpp(interfaces, fd):
if tag == 'TD_ARRAY':
d1 = type['size_is']
# index of element in extra types list
key = describe_type(type['element'])
d2 = type_cache.get(key)
if d2 is None:
d2 = type_cache[key] = len(types)
types.append(lower_type(type['element']))
d2 = lower_extra_type(type['element'])
elif tag == 'TD_INTERFACE_TYPE':
d1, d2 = splitint(interface_idx(type['name']))
@ -411,6 +440,12 @@ def link_to_cpp(interfaces, fd):
for const in iface['consts']:
lower_const(const, iface['name'])
# Lower the types which have fixed indexes first, and check that the indexes
# seem correct.
for expected, ty in enumerate(utility_types):
got = lower_extra_type(ty)
assert got == expected, "Wrong index when lowering"
# Lower interfaces in the order of the IID phf's values lookup.
for iface in iid_phf.values:
lower_iface(iface)
@ -486,8 +521,14 @@ namespace detail {
phfarr("sPHF_Names", "uint32_t", name_phf.intermediate)
phfarr("sPHF_NamesIdxs", "uint16_t", name_phf.values)
# Generate some checks that the indexes for the utility types match the
# declared ones in xptinfo.h
for idx, ty in enumerate(utility_types):
fd.write("static_assert(%d == (uint8_t)nsXPTType::Idx::%s, \"Bad idx\");\n" %
(idx, ty['tag'][3:]))
# The footer contains some checks re: the size of the generated arrays.
fd.write("""\
fd.write("""
const uint16_t sInterfacesSize = mozilla::ArrayLength(sInterfaces);
static_assert(sInterfacesSize == mozilla::ArrayLength(sPHF_NamesIdxs),
"sPHF_NamesIdxs must have same size as sInterfaces");

View File

@ -261,70 +261,6 @@ nsXPTInterfaceInfo::GetConstant(uint16_t aIndex,
return *aName ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
nsXPTInterfaceInfo::GetTypeForParam(uint16_t /* UNUSED aMethodIndex */,
const nsXPTParamInfo* aParam,
uint16_t aDimension,
nsXPTType* aRetval) const
{
const nsXPTType* type = &aParam->Type();
for (uint16_t i = 0; i < aDimension; ++i) {
if (type->Tag() != TD_ARRAY) {
NS_ERROR("bad dimension");
return NS_ERROR_INVALID_ARG;
}
type = &type->ArrayElementType();
}
*aRetval = *type; // NOTE: This copies the type, which is fine I guess?
return NS_OK;
}
nsresult
nsXPTInterfaceInfo::GetSizeIsArgNumberForParam(uint16_t /* UNUSED aMethodIndex */,
const nsXPTParamInfo* aParam,
uint16_t aDimension,
uint8_t* aRetval) const
{
const nsXPTType* type = &aParam->Type();
for (uint16_t i = 0; i < aDimension; ++i) {
if (type->Tag() != TD_ARRAY) {
NS_ERROR("bad dimension");
return NS_ERROR_INVALID_ARG;
}
type = &type->ArrayElementType();
}
if (type->Tag() != TD_ARRAY &&
type->Tag() != TD_PSTRING_SIZE_IS &&
type->Tag() != TD_PWSTRING_SIZE_IS) {
NS_ERROR("not a size_is");
return NS_ERROR_INVALID_ARG;
}
*aRetval = type->ArgNum();
return NS_OK;
}
nsresult
nsXPTInterfaceInfo::GetInterfaceIsArgNumberForParam(uint16_t /* UNUSED aMethodIndex */,
const nsXPTParamInfo* aParam,
uint8_t* aRetval) const
{
const nsXPTType* type = &aParam->Type();
while (type->Tag() == TD_ARRAY) {
type = &type->ArrayElementType();
}
if (type->Tag() != TD_INTERFACE_IS_TYPE) {
NS_ERROR("not an iid_is");
return NS_ERROR_INVALID_ARG;
}
*aRetval = type->ArgNum();
return NS_OK;
}
nsresult
nsXPTInterfaceInfo::IsIID(const nsIID* aIID, bool* aIs) const
{
@ -360,26 +296,6 @@ nsXPTInterfaceInfo::HasAncestor(const nsIID* aIID, bool* aRetval) const
return NS_OK;
}
nsresult
nsXPTInterfaceInfo::GetIIDForParamNoAlloc(uint16_t aMethodIndex,
const nsXPTParamInfo* aParam,
nsIID* aIID) const
{
const nsXPTType* type = &aParam->Type();
while (type->Tag() == TD_ARRAY) {
type = &type->ArrayElementType();
}
if (type->Tag() == TD_INTERFACE_TYPE) {
const nsXPTInterfaceInfo* info = type->GetInterface();
if (info) {
*aIID = info->IID();
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
nsresult
nsXPTInterfaceInfo::IsMainProcessScriptableOnly(bool* aRetval) const
{

View File

@ -17,6 +17,7 @@
#include "nsID.h"
#include "mozilla/Assertions.h"
#include "js/Value.h"
#include "nsString.h"
// Forward Declarations
namespace mozilla {
@ -106,23 +107,11 @@ struct nsXPTInterfaceInfo
nsresult GetConstant(uint16_t aIndex,
JS::MutableHandleValue constant,
char** aName) const;
nsresult GetTypeForParam(uint16_t aMethodIndex, const nsXPTParamInfo* aParam,
uint16_t aDimension, nsXPTType* aRetval) const;
nsresult GetSizeIsArgNumberForParam(uint16_t aMethodIndex,
const nsXPTParamInfo* aParam,
uint16_t aDimension,
uint8_t* aRetval) const;
nsresult GetInterfaceIsArgNumberForParam(uint16_t aMethodIndex,
const nsXPTParamInfo* aParam,
uint8_t* aRetval) const;
nsresult IsIID(const nsIID* aIID, bool* aIs) const;
nsresult GetNameShared(const char** aName) const;
nsresult GetIIDShared(const nsIID** aIID) const;
nsresult IsFunction(bool* aRetval) const;
nsresult HasAncestor(const nsIID* aIID, bool* aRetval) const;
nsresult GetIIDForParamNoAlloc(uint16_t aMethodIndex,
const nsXPTParamInfo* aParam,
nsIID* aIID) const;
nsresult IsMainProcessScriptableOnly(bool* aRetval) const;
// XXX: We can probably get away with removing this method. A shim interface
@ -190,7 +179,8 @@ enum nsXPTTypeTag : uint8_t
TD_CSTRING = 24,
TD_ASTRING = 25,
TD_JSVAL = 26,
TD_DOMOBJECT = 27
TD_DOMOBJECT = 27,
TD_PROMISE = 28
};
@ -203,7 +193,9 @@ enum nsXPTTypeTag : uint8_t
*/
struct nsXPTType
{
nsXPTTypeTag Tag() const { return static_cast<nsXPTTypeTag>(mTag); }
// NOTE: This is uint8_t instead of nsXPTTypeTag so that it can be compared
// with the nsXPTType::* re-exports.
uint8_t Tag() const { return mTag; }
uint8_t ArgNum() const {
MOZ_ASSERT(Tag() == TD_INTERFACE_IS_TYPE ||
@ -244,15 +236,6 @@ public:
// place in xptcall. :-(
bool IsArithmetic() const { return Tag() <= TD_WCHAR; }
// We used to abuse 'pointer' flag bit in typelib format quite extensively.
// We've gotten rid of most of the cases, but there's still a fair amount
// of refactoring to be done in XPCWrappedJSClass before we can safely stop
// asking about this. In the mean time, we've got a temporary version of
// IsPointer() that should do the right thing.
bool deprecated_IsPointer() const {
return !IsArithmetic() && Tag() != TD_JSVAL;
}
bool IsInterfacePointer() const {
return Tag() == TD_INTERFACE_TYPE || Tag() == TD_INTERFACE_IS_TYPE;
}
@ -264,9 +247,53 @@ public:
Tag() == TD_PSTRING_SIZE_IS || Tag() == TD_PWSTRING_SIZE_IS;
}
bool IsStringClass() const {
return Tag() == TD_DOMSTRING || Tag() == TD_ASTRING ||
Tag() == TD_CSTRING || Tag() == TD_UTF8STRING;
// Unwrap a nested type to its innermost value (e.g. through arrays).
const nsXPTType& InnermostType() const {
if (Tag() == TD_ARRAY) {
return ArrayElementType().InnermostType();
}
return *this;
}
// Helper methods for working with the type's native representation.
inline size_t Stride() const;
inline bool HasPointerRepr() const;
// Offset the given base pointer to reference the element at the given index.
void* ElementPtr(const void* aBase, uint32_t aIndex) const {
return (char*)aBase + (aIndex * Stride());
}
// Indexes into the extra types array of a small set of known types.
enum class Idx : uint8_t
{
INT8 = 0,
UINT8,
INT16,
UINT16,
INT32,
UINT32,
INT64,
UINT64,
FLOAT,
DOUBLE,
BOOL,
CHAR,
WCHAR,
PNSIID,
PSTRING,
PWSTRING,
INTERFACE_IS_TYPE
};
// Helper methods for fabricating nsXPTType values used by xpconnect.
static nsXPTType MkArrayType(Idx aInner) {
MOZ_ASSERT(aInner <= Idx::INTERFACE_IS_TYPE);
return { TD_ARRAY, false, false, false, 0, (uint8_t)aInner };
}
static const nsXPTType& Get(Idx aInner) {
MOZ_ASSERT(aInner <= Idx::INTERFACE_IS_TYPE);
return xpt::detail::GetType((uint8_t)aInner);
}
///////////////////////////////////////
@ -306,7 +333,8 @@ public:
T_CSTRING = TD_CSTRING ,
T_ASTRING = TD_ASTRING ,
T_JSVAL = TD_JSVAL ,
T_DOMOBJECT = TD_DOMOBJECT
T_DOMOBJECT = TD_DOMOBJECT ,
T_PROMISE = TD_PROMISE
};
////////////////////////////////////////////////////////////////
@ -339,7 +367,7 @@ static_assert(sizeof(nsXPTType) == 3, "wrong size");
struct nsXPTParamInfo
{
bool IsIn() const { return mType.mInParam; }
bool IsOut() const { return mType.mOutParam && !IsDipper(); }
bool IsOut() const { return mType.mOutParam; }
bool IsOptional() const { return mType.mOptionalParam; }
bool IsShared() const { return false; } // XXX remove (backcompat)
@ -347,30 +375,17 @@ struct nsXPTParamInfo
const nsXPTType& Type() const { return mType; }
const nsXPTType& GetType() const { return Type(); } // XXX remove (backcompat)
// Dipper types are one of the more inscrutable aspects of xpidl. In a
// nutshell, dippers are empty container objects, created and passed by the
// caller, and filled by the callee. The callee receives a fully- formed
// object, and thus does not have to construct anything. But the object is
// functionally empty, and the callee is responsible for putting something
// useful inside of it.
//
// Dipper types are treated as `in` parameters when declared as an `out`
// parameter. For this reason, dipper types are sometimes referred to as 'out
// parameters masquerading as in'. The burden of maintaining this illusion
// falls mostly on XPConnect, which creates the empty containers, and harvest
// the results after the call.
//
// Currently, the only dipper types are the string classes.
//
// XXX: Dipper types may be able to go away? (bug 677784)
bool IsDipper() const { return mType.mOutParam && IsStringClass(); }
// Whether this parameter is passed indirectly on the stack. This mainly
// applies to out/inout params, but we use it unconditionally for certain
// types.
bool IsIndirect() const { return IsOut() || mType.Tag() == TD_JSVAL; }
bool IsStringClass() const { return mType.IsStringClass(); }
// Whether this parameter is passed indirectly on the stack. All out/inout
// params are passed indirectly, although some types are passed indirectly
// unconditionally.
bool IsIndirect() const {
return IsOut() ||
mType.Tag() == TD_JSVAL ||
mType.Tag() == TD_ASTRING ||
mType.Tag() == TD_DOMSTRING ||
mType.Tag() == TD_CSTRING ||
mType.Tag() == TD_UTF8STRING;
}
////////////////////////////////////////////////////////////////
// Ensure these fields are in the same order as xptcodegen.py //
@ -562,4 +577,71 @@ GetString(uint32_t aIndex)
} // namespace detail
} // namespace xpt
inline bool
nsXPTType::HasPointerRepr() const
{
// This method should return `true` if the given type would be represented as
// a pointer when not passed indirectly.
switch (Tag()) {
case TD_VOID:
case TD_PNSIID:
case TD_PSTRING:
case TD_PWSTRING:
case TD_INTERFACE_TYPE:
case TD_INTERFACE_IS_TYPE:
case TD_ARRAY:
case TD_PSTRING_SIZE_IS:
case TD_PWSTRING_SIZE_IS:
case TD_DOMOBJECT:
case TD_PROMISE:
return true;
default:
return false;
}
}
inline size_t
nsXPTType::Stride() const
{
// Compute the stride to use when walking an array of the given type.
//
// NOTE: We cast to nsXPTTypeTag here so we get a warning if a type is missed
// in this switch statement. It's important that this method returns a value
// for every possible type.
switch (static_cast<nsXPTTypeTag>(Tag())) {
case TD_INT8: return sizeof(int8_t);
case TD_INT16: return sizeof(int16_t);
case TD_INT32: return sizeof(int32_t);
case TD_INT64: return sizeof(int64_t);
case TD_UINT8: return sizeof(uint8_t);
case TD_UINT16: return sizeof(uint16_t);
case TD_UINT32: return sizeof(uint32_t);
case TD_UINT64: return sizeof(uint64_t);
case TD_FLOAT: return sizeof(float);
case TD_DOUBLE: return sizeof(double);
case TD_BOOL: return sizeof(bool);
case TD_CHAR: return sizeof(char);
case TD_WCHAR: return sizeof(char16_t);
case TD_VOID: return sizeof(void*);
case TD_PNSIID: return sizeof(nsIID*);
case TD_DOMSTRING: return sizeof(nsString);
case TD_PSTRING: return sizeof(char*);
case TD_PWSTRING: return sizeof(char16_t*);
case TD_INTERFACE_TYPE: return sizeof(nsISupports*);
case TD_INTERFACE_IS_TYPE: return sizeof(nsISupports*);
case TD_ARRAY: return sizeof(void*);
case TD_PSTRING_SIZE_IS: return sizeof(char*);
case TD_PWSTRING_SIZE_IS: return sizeof(char16_t*);
case TD_UTF8STRING: return sizeof(nsCString);
case TD_CSTRING: return sizeof(nsCString);
case TD_ASTRING: return sizeof(nsString);
case TD_JSVAL: return sizeof(JS::Value);
case TD_DOMOBJECT: return sizeof(void*);
case TD_PROMISE: return sizeof(void*);
}
MOZ_CRASH("Unknown type");
}
#endif /* xptinfo_h */

View File

@ -44,9 +44,9 @@ interface nsIBlocklistService : nsISupports
* is used.
* @returns Promise that resolves to the STATE constant.
*/
nsISupports getPluginBlocklistState(in nsIPluginTag plugin,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
Promise getPluginBlocklistState(in nsIPluginTag plugin,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
readonly attribute boolean isLoaded;
};