зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-i to m-c, a=merge
This commit is contained in:
Коммит
c5e1a2b4ca
|
@ -597,7 +597,8 @@ static void
|
|||
MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
|
||||
if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name))
|
||||
if (aAtkObj->name &&
|
||||
!strncmp(aAtkObj->name, newNameUTF8.get(), newNameUTF8.Length()))
|
||||
return;
|
||||
|
||||
// Below we duplicate the functionality of atk_object_set_name(),
|
||||
|
|
|
@ -91,8 +91,13 @@ void
|
|||
AccessibleWrap::Shutdown()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
if (mID != kNoID)
|
||||
static_cast<DocAccessibleWrap*>(mDoc)->RemoveID(mID);
|
||||
if (mID != kNoID) {
|
||||
auto doc = static_cast<DocAccessibleWrap*>(mDoc);
|
||||
MOZ_ASSERT(doc);
|
||||
if (doc) {
|
||||
doc->RemoveID(mID);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Accessible::Shutdown();
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
@RESPATH@/chrome/@AB_CD@.manifest
|
||||
@RESPATH@/@PREF_DIR@/b2g-l10n.js
|
||||
@RESPATH@/searchplugins/*
|
||||
@RESPATH@/defaults/profile/bookmarks.html
|
||||
@RESPATH@/defaults/profile/localstore.rdf
|
||||
@RESPATH@/defaults/profile/mimeTypes.rdf
|
||||
@RESPATH@/defaults/profile/chrome/*
|
||||
#ifdef MOZ_UPDATER
|
||||
@RESPATH@/update.locale
|
||||
@RESPATH@/updater.ini
|
||||
|
@ -768,7 +764,6 @@
|
|||
@RESPATH@/@PREF_DIR@/channel-prefs.js
|
||||
@RESPATH@/greprefs.js
|
||||
@RESPATH@/defaults/autoconfig/prefcalls.js
|
||||
@RESPATH@/defaults/profile/prefs.js
|
||||
|
||||
; Services (gre) prefs
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
|
|
|
@ -46,9 +46,6 @@
|
|||
@RESPATH@/browser/chrome/@AB_CD@.manifest
|
||||
@RESPATH@/chrome/@AB_CD@@JAREXT@
|
||||
@RESPATH@/chrome/@AB_CD@.manifest
|
||||
@RESPATH@/browser/defaults/profile/chrome/*
|
||||
@RESPATH@/browser/defaults/profile/localstore.rdf
|
||||
@RESPATH@/browser/defaults/profile/mimeTypes.rdf
|
||||
@RESPATH@/dictionaries/*
|
||||
@RESPATH@/hyphenation/*
|
||||
@RESPATH@/browser/@PREF_DIR@/firefox-l10n.js
|
||||
|
@ -704,7 +701,6 @@
|
|||
@RESPATH@/browser/@PREF_DIR@/firefox-branding.js
|
||||
@RESPATH@/greprefs.js
|
||||
@RESPATH@/defaults/autoconfig/prefcalls.js
|
||||
@RESPATH@/browser/defaults/profile/prefs.js
|
||||
@RESPATH@/browser/defaults/permissions
|
||||
|
||||
; Warning: changing the path to channel-prefs.js can cause bugs (Bug 756325)
|
||||
|
|
|
@ -94,21 +94,8 @@ $(STAGEDIST): $(DIST)/branding
|
|||
$(DIST)/branding:
|
||||
$(NSINSTALL) -D $@
|
||||
|
||||
PROFILE_FILES = \
|
||||
localstore.rdf \
|
||||
mimeTypes.rdf \
|
||||
$(NULL)
|
||||
|
||||
PROFILE_CHROME = userChrome-example.css userContent-example.css
|
||||
|
||||
DEFINES += -DBOOKMARKS_INCLUDE_DIR=$(dir $(call MERGE_FILE,profile/bookmarks.inc))
|
||||
|
||||
libs:: $(addprefix generic/profile/,$(PROFILE_FILES))
|
||||
$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/defaults/profile
|
||||
|
||||
libs:: $(call MERGE_FILES,$(addprefix profile/chrome/,$(PROFILE_CHROME)))
|
||||
$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/defaults/profile/chrome
|
||||
|
||||
libs-%:
|
||||
$(NSINSTALL) -D $(DIST)/install
|
||||
@$(MAKE) -C ../../toolkit/locales libs-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* Edit this file and copy it as userChrome.css into your
|
||||
* profile-directory/chrome/
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file can be used to customize the look of Mozilla's user interface
|
||||
* You should consider using !important on rules which you want to
|
||||
* override default settings.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Do not remove the @namespace line -- it's required for correct functioning
|
||||
*/
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
|
||||
|
||||
|
||||
/*
|
||||
* Some possible accessibility enhancements:
|
||||
*/
|
||||
/*
|
||||
* Make all the default font sizes 20 pt:
|
||||
*
|
||||
* * {
|
||||
* font-size: 20pt !important
|
||||
* }
|
||||
*/
|
||||
/*
|
||||
* Make menu items in particular 15 pt instead of the default size:
|
||||
*
|
||||
* menupopup > * {
|
||||
* font-size: 15pt !important
|
||||
* }
|
||||
*/
|
||||
/*
|
||||
* Give the Location (URL) Bar a fixed-width font
|
||||
*
|
||||
* #urlbar {
|
||||
* font-family: monospace !important;
|
||||
* }
|
||||
*/
|
||||
|
||||
/*
|
||||
* For more examples see http://www.mozilla.org/unix/customizing.html
|
||||
*/
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* Edit this file and copy it as userContent.css into your
|
||||
* profile-directory/chrome/
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file can be used to apply a style to all web pages you view
|
||||
* Rules without !important are overruled by author rules if the
|
||||
* author sets any. Rules with !important overrule author rules.
|
||||
*/
|
||||
|
||||
/*
|
||||
* example: give all tables a 2px border
|
||||
*
|
||||
* table { border: 2px solid; }
|
||||
*/
|
||||
|
||||
/*
|
||||
* example: turn off "marquee" element
|
||||
*
|
||||
* marquee { -moz-binding: none; }
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* For more examples see http://www.mozilla.org/unix/customizing.html
|
||||
*/
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<RDF:RDF
|
||||
xmlns:NC="http://home.netscape.com/NC-rdf#"
|
||||
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
</RDF:RDF>
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:NC="http://home.netscape.com/NC-rdf#"
|
||||
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
|
||||
<Description about="urn:mimetypes">
|
||||
<NC:MIME-types>
|
||||
<Seq about="urn:mimetypes:root">
|
||||
</Seq>
|
||||
</NC:MIME-types>
|
||||
</Description>
|
||||
</RDF>
|
|
@ -1200,7 +1200,11 @@ void DiagnosticsMatcher::TrivialCtorDtorChecker::run(
|
|||
"class %0 must have trivial constructors and destructors");
|
||||
const CXXRecordDecl *node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
|
||||
|
||||
bool badCtor = !node->hasTrivialDefaultConstructor();
|
||||
// We need to accept non-constexpr trivial constructors as well. This occurs
|
||||
// when a struct contains pod members, which will not be initialized. As
|
||||
// constexpr values are initialized, the constructor is non-constexpr.
|
||||
bool badCtor = !(node->hasConstexprDefaultConstructor() ||
|
||||
node->hasTrivialDefaultConstructor());
|
||||
bool badDtor = !node->hasTrivialDestructor();
|
||||
if (badCtor || badDtor)
|
||||
Diag.Report(node->getLocStart(), errorID) << node;
|
||||
|
|
|
@ -5,6 +5,15 @@ struct MOZ_TRIVIAL_CTOR_DTOR EmptyClass{};
|
|||
template <class T>
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR TemplateEmptyClass{};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR NonEmptyClass {
|
||||
void *m;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR TemplateNonEmptyClass {
|
||||
T* m;
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedCtor { // expected-error {{class 'BadUserDefinedCtor' must have trivial constructors and destructors}}
|
||||
BadUserDefinedCtor() {}
|
||||
};
|
||||
|
@ -17,7 +26,7 @@ struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualDtor { // expected-error {{class 'BadVirt
|
|||
virtual ~BadVirtualDtor() {}
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualMember { // expected-error {{class 'BadVirtualMember' must have trivial constructors and destructors}}
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR OkVirtualMember {
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
|
@ -53,6 +62,22 @@ struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInMember { // expected-error {{cla
|
|||
NonTrivialDtor m;
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualMemberInMember { // expected-error {{class 'BadVirtualMemberInMember' must have trivial constructors and destructors}}
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR OkVirtualMemberInMember {
|
||||
VirtualMember m;
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR OkConstExprConstructor {
|
||||
constexpr OkConstExprConstructor() {}
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR OkConstExprConstructorInMember {
|
||||
OkConstExprConstructor m;
|
||||
};
|
||||
|
||||
// XXX: This error is unfortunate, but is unlikely to come up in real code.
|
||||
// In this situation, it should be possible to define a constexpr constructor
|
||||
// which explicitly initializes the members.
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadUnfortunateError { // expected-error {{class 'BadUnfortunateError' must have trivial constructors and destructors}}
|
||||
OkConstExprConstructor m;
|
||||
void *n;
|
||||
};
|
||||
|
|
|
@ -126,6 +126,67 @@ function* spawnTest() {
|
|||
exec: {
|
||||
output: 'Test Plug-in 1.0.0.0 enabled.'
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'addon ctp Test_Plug-in_1.0.0.0',
|
||||
check: {
|
||||
input: 'addon ctp Test_Plug-in_1.0.0.0',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
command: { name: 'addon ctp' },
|
||||
addon: {
|
||||
value: function(addon) {
|
||||
is(addon.name, 'Test Plug-in', 'test plugin name');
|
||||
},
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: 'Test Plug-in 1.0.0.0 set to click-to-play.'
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'addon ctp OpenH264_Video_Codec_provided_by_Cisco_Systems,_Inc._null',
|
||||
check: {
|
||||
input: 'addon ctp OpenH264_Video_Codec_provided_by_Cisco_Systems,_Inc._null',
|
||||
hints: '',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
command: { name: 'addon ctp' },
|
||||
addon: {
|
||||
value: function(addon) {
|
||||
is(addon.name, 'OpenH264 Video Codec provided by Cisco Systems, Inc.', 'openh264');
|
||||
},
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: 'OpenH264 Video Codec provided by Cisco Systems, Inc. null cannot be set to click-to-play.'
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'addon ctp Mochitest_1.0',
|
||||
check: {
|
||||
input: 'addon ctp Mochitest_1.0',
|
||||
hints: '',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
command: { name: 'addon ctp' },
|
||||
addon: {
|
||||
value: function(addon) {
|
||||
is(addon.name, 'Mochitest', 'mochitest');
|
||||
},
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: 'Mochitest 1.0 cannot be set to click-to-play because it is not a plugin.'
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
|
|
|
@ -189,10 +189,17 @@ exports.executeSoon = function executeSoon(aFn) {
|
|||
if (isWorker) {
|
||||
setImmediate(aFn);
|
||||
} else {
|
||||
let stack = components.stack;
|
||||
let executor = () => {
|
||||
Cu.callFunctionWithAsyncStack(aFn, stack, "DevToolsUtils.executeSoon");
|
||||
};
|
||||
let executor;
|
||||
// Only enable async stack reporting when DEBUG_JS_MODULES is set
|
||||
// (customized local builds) to avoid a performance penalty.
|
||||
if (AppConstants.DEBUG_JS_MODULES || exports.testing) {
|
||||
let stack = components.stack;
|
||||
executor = () => {
|
||||
Cu.callFunctionWithAsyncStack(aFn, stack, "DevToolsUtils.executeSoon");
|
||||
};
|
||||
} else {
|
||||
executor = aFn;
|
||||
}
|
||||
Services.tm.mainThread.dispatch({
|
||||
run: exports.makeInfallible(executor)
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
|
|
|
@ -279,6 +279,41 @@ var items = [
|
|||
|
||||
return l10n.lookupFormat("addonAlreadyDisabled", [ name ]);
|
||||
}
|
||||
},
|
||||
{
|
||||
item: "command",
|
||||
runAt: "client",
|
||||
name: "addon ctp",
|
||||
description: l10n.lookup("addonCtpDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "addon",
|
||||
type: "addon",
|
||||
description: l10n.lookup("addonNameDesc")
|
||||
}
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let name = (args.addon.name + " " + args.addon.version).trim();
|
||||
if (args.addon.type !== "plugin") {
|
||||
return l10n.lookupFormat("addonCantCtp", [ name ]);
|
||||
}
|
||||
|
||||
if (!args.addon.userDisabled ||
|
||||
args.addon.userDisabled === true) {
|
||||
args.addon.userDisabled = AddonManager.STATE_ASK_TO_ACTIVATE;
|
||||
|
||||
if (args.addon.userDisabled !== AddonManager.STATE_ASK_TO_ACTIVATE) {
|
||||
// Some plugins (e.g. OpenH264 shipped with Firefox) cannot be set to
|
||||
// click-to-play. Handle this.
|
||||
|
||||
return l10n.lookupFormat("addonNoCtp", [ name ]);
|
||||
}
|
||||
|
||||
return l10n.lookupFormat("addonCtp", [ name ]);
|
||||
}
|
||||
|
||||
return l10n.lookupFormat("addonAlreadyCtp", [ name ]);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -836,6 +836,30 @@ addonAlreadyDisabled=%S is already disabled.
|
|||
# command when an add-on is disabled.
|
||||
addonDisabled=%S disabled.
|
||||
|
||||
# LOCALIZATION NOTE (addonCtpDesc) A very short description of the
|
||||
# 'addon ctp <type>' command. This string is designed to be shown in a menu
|
||||
# alongside the command name, which is why it should be as short as possible.
|
||||
addonCtpDesc=Set the specified plugin to click-to-play.
|
||||
|
||||
# LOCALIZATION NOTE (addonCtp) Used in the output of the 'addon ctp'
|
||||
# command when a plugin is set to click-to-play.
|
||||
addonCtp=%S set to click-to-play.
|
||||
|
||||
# LOCALIZATION NOTE (addonAlreadyCtp) Used in the output of the
|
||||
# 'addon ctp' command when an attempt is made to set a plugin to
|
||||
# click-to-play that is already set to click-to-play.
|
||||
addonAlreadyCtp=%S is already set to click-to-play.
|
||||
|
||||
# LOCALIZATION NOTE (addonCantCtp) Used in the output of the 'addon
|
||||
# ctp' command when an attempt is made to set an addon to click-to-play,
|
||||
# but the addon is not a plugin.
|
||||
addonCantCtp=%S cannot be set to click-to-play because it is not a plugin.
|
||||
|
||||
# LOCALIZATION NOTE (addonNoCtp) Used in the output of the 'addon
|
||||
# ctp' command when an attempt is made to set an addon to click-to-play,
|
||||
# but the plugin cannot be set to click-to-play for some reason.
|
||||
addonNoCtp=%S cannot be set to click-to-play.
|
||||
|
||||
# LOCALIZATION NOTE (exportDesc) A very short description of the 'export'
|
||||
# command. This string is designed to be shown in a menu alongside the command
|
||||
# name, which is why it should be as short as possible.
|
||||
|
|
|
@ -7,6 +7,11 @@ var Cr = Components.results;
|
|||
var {require} = Cu.import("resource://devtools/shared/Loader.jsm");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
|
||||
DevToolsUtils.testing = true;
|
||||
do_register_cleanup(() => {
|
||||
DevToolsUtils.testing = false;
|
||||
});
|
||||
|
||||
// Register a console listener, so console messages don't just disappear
|
||||
// into the ether.
|
||||
|
||||
|
|
|
@ -1271,6 +1271,13 @@ public:
|
|||
return JS::AsmJSCache_Success;
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NoteActorDestroyed();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
~ChildRunnable()
|
||||
{
|
||||
|
@ -1329,7 +1336,7 @@ private:
|
|||
ActorDestroy(ActorDestroyReason why) override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mActorDestroyed = true;
|
||||
NoteActorDestroyed();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1368,6 +1375,11 @@ private:
|
|||
mCondVar.Notify();
|
||||
}
|
||||
|
||||
void NoteActorDestroyed()
|
||||
{
|
||||
mActorDestroyed = true;
|
||||
}
|
||||
|
||||
nsIPrincipal* const mPrincipal;
|
||||
nsAutoPtr<PrincipalInfo> mPrincipalInfo;
|
||||
WriteParams mWriteParams;
|
||||
|
@ -1553,6 +1565,7 @@ OpenFile(nsIPrincipal* aPrincipal,
|
|||
JS::AsmJSCacheResult openResult =
|
||||
childRunnable->BlockUntilOpen(aChildRunnable);
|
||||
if (openResult != JS::AsmJSCache_Success) {
|
||||
childRunnable->Cleanup();
|
||||
return openResult;
|
||||
}
|
||||
|
||||
|
|
|
@ -957,6 +957,32 @@ BlobImplFile::LookupAndCacheIsDirectory()
|
|||
mDirState = isDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// BlobImplEmptyFile implementation
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(BlobImplEmptyFile, BlobImpl)
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
BlobImplEmptyFile::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!aStart && !aLength);
|
||||
RefPtr<BlobImpl> impl = new BlobImplEmptyFile(aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void
|
||||
BlobImplEmptyFile::GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsresult rv = NS_NewCStringInputStream(aStream, EmptyCString());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// BlobImplMemory implementation
|
||||
|
||||
|
|
|
@ -833,6 +833,31 @@ private:
|
|||
bool mIsTemporary;
|
||||
};
|
||||
|
||||
class BlobImplEmptyFile final : public BlobImplBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
explicit BlobImplEmptyFile(const nsAString& aContentType)
|
||||
: BlobImplBase(EmptyString(), aContentType, 0 /* aLength */)
|
||||
{}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
~BlobImplEmptyFile() {}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -179,6 +179,8 @@ FormData::Has(const nsAString& aName)
|
|||
nsresult
|
||||
FormData::AddNameFilePair(const nsAString& aName, File* aFile)
|
||||
{
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
FormDataTuple* data = mFormData.AppendElement();
|
||||
SetNameFilePair(data, aName, aFile);
|
||||
return NS_OK;
|
||||
|
@ -272,12 +274,10 @@ FormData::SetNameFilePair(FormDataTuple* aData,
|
|||
File* aFile)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
aData->name = aName;
|
||||
if (aFile) {
|
||||
aData->value.SetAsFile() = aFile;
|
||||
} else {
|
||||
aData->value.SetAsUSVString() = EmptyString();
|
||||
}
|
||||
aData->value.SetAsFile() = aFile;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -364,7 +364,7 @@ FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
|||
fs.AddNameValuePair(mFormData[i].name,
|
||||
mFormData[i].value.GetAsUSVString());
|
||||
} else {
|
||||
fs.AddNameFilePair(mFormData[i].name, nullptr);
|
||||
MOZ_CRASH("This should no be possible.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7659,7 +7659,7 @@ nsContentUtils::ToWidgetPoint(const CSSPoint& aPoint,
|
|||
{
|
||||
return LayoutDeviceIntPoint::FromAppUnitsRounded(
|
||||
(CSSPoint::ToAppUnits(aPoint) +
|
||||
aOffset).ApplyResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution()),
|
||||
aOffset).ApplyResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(aPresContext->PresShell())),
|
||||
aPresContext->AppUnitsPerDevPixel());
|
||||
}
|
||||
|
||||
|
|
|
@ -3755,8 +3755,8 @@ nsIDocument::ShouldThrottleFrameRequests()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!mIsShowing) {
|
||||
// We're not showing (probably in a background tab or the bf cache).
|
||||
if (Hidden()) {
|
||||
// We're not visible (probably in a background tab or the bf cache).
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ protected:
|
|||
void TraceWrapper(JSTracer* aTrc, const char* name)
|
||||
{
|
||||
if (mWrapper) {
|
||||
JS_CallUnbarrieredObjectTracer(aTrc, &mWrapper, name);
|
||||
js::UnsafeTraceManuallyBarrieredEdge(aTrc, &mWrapper, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=789315
|
|||
<form id="a"><input name="b" type="file"/></form>
|
||||
|
||||
<script type="text/javascript">
|
||||
is(new FormData(document.getElementById('a')).get('b'), "", "This should return an empty string.");
|
||||
var obj = new FormData(document.getElementById('a')).get('b');
|
||||
|
||||
ok(obj instanceof File, "This should return an empty File");
|
||||
is(obj.size, 0, "Size should be 0");
|
||||
is(obj.name, "", "Name should be an empty string");
|
||||
is(obj.type, "application/octet-stream", "Type should be application/octet-stream");
|
||||
|
||||
var o = obj.slice(10, 100, "foo/bar");
|
||||
is(o.size, 0, "The new blob has size 0");
|
||||
is(o.type, "foo/bar", "The new blob has type foo/bar");
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -2095,7 +2095,7 @@ class SequenceTracer<JSObject*, false, false, false>
|
|||
public:
|
||||
static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
|
||||
for (; objp != end; ++objp) {
|
||||
JS_CallUnbarrieredObjectTracer(trc, objp, "sequence<object>");
|
||||
JS::UnsafeTraceRoot(trc, objp, "sequence<object>");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -2109,7 +2109,7 @@ class SequenceTracer<JS::Value, false, false, false>
|
|||
public:
|
||||
static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
|
||||
for (; valp != end; ++valp) {
|
||||
JS_CallUnbarrieredValueTracer(trc, valp, "sequence<any>");
|
||||
JS::UnsafeTraceRoot(trc, valp, "sequence<any>");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9620,7 +9620,7 @@ class CGUnionStruct(CGThing):
|
|||
if t.isObject():
|
||||
traceCases.append(
|
||||
CGCase("e" + vars["name"],
|
||||
CGGeneric('JS_CallUnbarrieredObjectTracer(trc, %s, "%s");\n' %
|
||||
CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
|
||||
("&mValue.m" + vars["name"] + ".Value()",
|
||||
"mValue.m" + vars["name"]))))
|
||||
elif t.isDictionary():
|
||||
|
@ -12603,12 +12603,12 @@ class CGDictionary(CGThing):
|
|||
memberLoc)
|
||||
|
||||
if type.isObject():
|
||||
trace = CGGeneric('JS_CallUnbarrieredObjectTracer(trc, %s, "%s");\n' %
|
||||
trace = CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
|
||||
("&"+memberData, memberName))
|
||||
if type.nullable():
|
||||
trace = CGIfWrapper(trace, memberData)
|
||||
elif type.isAny():
|
||||
trace = CGGeneric('JS_CallUnbarrieredValueTracer(trc, %s, "%s");\n' %
|
||||
trace = CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
|
||||
("&"+memberData, memberName))
|
||||
elif (type.isSequence() or type.isDictionary() or
|
||||
type.isSpiderMonkeyInterface() or type.isUnion()):
|
||||
|
|
|
@ -45,10 +45,10 @@ public:
|
|||
inline void TraceSelf(JSTracer* trc)
|
||||
{
|
||||
if (mTypedObj) {
|
||||
JS_CallUnbarrieredObjectTracer(trc, &mTypedObj, "TypedArray.mTypedObj");
|
||||
JS::UnsafeTraceRoot(trc, &mTypedObj, "TypedArray.mTypedObj");
|
||||
}
|
||||
if (mWrappedObj) {
|
||||
JS_CallUnbarrieredObjectTracer(trc, &mTypedObj, "TypedArray.mWrappedObj");
|
||||
JS::UnsafeTraceRoot(trc, &mTypedObj, "TypedArray.mWrappedObj");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -287,6 +287,20 @@ WebGL2Context::GetQuery(GLenum target, GLenum pname)
|
|||
return tmp.forget();
|
||||
}
|
||||
|
||||
static bool
|
||||
ValidateQueryEnum(WebGLContext* webgl, GLenum pname, const char* info)
|
||||
{
|
||||
switch (pname) {
|
||||
case LOCAL_GL_QUERY_RESULT_AVAILABLE:
|
||||
case LOCAL_GL_QUERY_RESULT:
|
||||
return true;
|
||||
|
||||
default:
|
||||
webgl->ErrorInvalidEnum("%s: invalid pname: %s", info, webgl->EnumName(pname));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::GetQueryParameter(JSContext*, WebGLQuery* query, GLenum pname,
|
||||
JS::MutableHandleValue retval)
|
||||
|
@ -296,6 +310,9 @@ WebGL2Context::GetQueryParameter(JSContext*, WebGLQuery* query, GLenum pname,
|
|||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateQueryEnum(this, pname, "getQueryParameter"))
|
||||
return;
|
||||
|
||||
if (!query) {
|
||||
/* OpenGL ES 3.0 spec 6.1.7 (spec getQueryObject 1):
|
||||
* If id is not the name of a query object, or if the query object
|
||||
|
@ -330,6 +347,9 @@ WebGL2Context::GetQueryParameter(JSContext*, WebGLQuery* query, GLenum pname,
|
|||
|
||||
// We must wait for an event loop before the query can be available
|
||||
if (!query->mCanBeAvailable && !gfxPrefs::WebGLImmediateQueries()) {
|
||||
if (pname == LOCAL_GL_QUERY_RESULT_AVAILABLE) {
|
||||
retval.set(JS::BooleanValue(false));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ WebGL2Context::GetSyncParameter(JSContext*, WebGLSync* sync, GLenum pname, JS::M
|
|||
MakeContextCurrent();
|
||||
gl->fGetSynciv(sync->mGLName, pname, 1, nullptr, &result);
|
||||
retval.set(JS::Int32Value(result));
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorInvalidEnum("getSyncParameter: Invalid pname 0x%04x", pname);
|
||||
|
|
|
@ -933,7 +933,7 @@ Event::GetScreenCoords(nsPresContext* aPresContext,
|
|||
LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
|
||||
|
||||
if (aPresContext->PresShell()) {
|
||||
pt = pt.RemoveResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution());
|
||||
pt = pt.RemoveResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(aPresContext->PresShell()));
|
||||
}
|
||||
|
||||
pt += LayoutDevicePixel::ToAppUnits(guiEvent->widget->WidgetToScreenOffset(),
|
||||
|
|
|
@ -5593,9 +5593,10 @@ HTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
|
|||
}
|
||||
|
||||
if (files.IsEmpty()) {
|
||||
// If no file was selected, pretend we had an empty file with an
|
||||
// empty filename.
|
||||
aFormSubmission->AddNameFilePair(name, nullptr);
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
new BlobImplEmptyFile(NS_LITERAL_STRING("application/octet-stream"));
|
||||
RefPtr<File> file = File::Create(OwnerDoc()->GetInnerWindow(), blobImpl);
|
||||
aFormSubmission->AddNameFilePair(name, file);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -167,15 +167,15 @@ nsresult
|
|||
nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
|
||||
File* aFile)
|
||||
{
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
if (!mWarnedFileControl) {
|
||||
SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0);
|
||||
mWarnedFileControl = true;
|
||||
}
|
||||
|
||||
nsAutoString filename;
|
||||
if (aFile) {
|
||||
aFile->GetName(filename);
|
||||
}
|
||||
aFile->GetName(filename);
|
||||
|
||||
return AddNameValuePair(aName, filename);
|
||||
}
|
||||
|
@ -441,61 +441,60 @@ nsresult
|
|||
nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
File* aFile)
|
||||
{
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
// Encode the control name
|
||||
nsAutoCString nameStr;
|
||||
nsresult rv = EncodeVal(aName, nameStr, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString filename, contentType;
|
||||
nsAutoString filename16;
|
||||
aFile->GetName(filename16);
|
||||
|
||||
ErrorResult error;
|
||||
nsAutoString filepath16;
|
||||
aFile->GetPath(filepath16, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
if (!filepath16.IsEmpty()) {
|
||||
// File.path includes trailing "/"
|
||||
filename16 = filepath16 + filename16;
|
||||
}
|
||||
|
||||
nsAutoCString filename;
|
||||
rv = EncodeVal(filename16, filename, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get content type
|
||||
nsAutoString contentType16;
|
||||
aFile->GetType(contentType16);
|
||||
if (contentType16.IsEmpty()) {
|
||||
contentType16.AssignLiteral("application/octet-stream");
|
||||
}
|
||||
|
||||
nsAutoCString contentType;
|
||||
contentType.Adopt(nsLinebreakConverter::
|
||||
ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
|
||||
nsLinebreakConverter::eLinebreakAny,
|
||||
nsLinebreakConverter::eLinebreakSpace));
|
||||
|
||||
// Get input stream
|
||||
nsCOMPtr<nsIInputStream> fileStream;
|
||||
if (aFile) {
|
||||
nsAutoString filename16;
|
||||
aFile->GetName(filename16);
|
||||
aFile->GetInternalStream(getter_AddRefs(fileStream), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
nsAutoString filepath16;
|
||||
aFile->GetPath(filepath16, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
if (!filepath16.IsEmpty()) {
|
||||
// File.path includes trailing "/"
|
||||
filename16 = filepath16 + filename16;
|
||||
}
|
||||
|
||||
rv = EncodeVal(filename16, filename, true);
|
||||
if (fileStream) {
|
||||
// Create buffered stream (for efficiency)
|
||||
nsCOMPtr<nsIInputStream> bufferedStream;
|
||||
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
|
||||
fileStream, 8192);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get content type
|
||||
nsAutoString contentType16;
|
||||
aFile->GetType(contentType16);
|
||||
if (contentType16.IsEmpty()) {
|
||||
contentType16.AssignLiteral("application/octet-stream");
|
||||
}
|
||||
contentType.Adopt(nsLinebreakConverter::
|
||||
ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
|
||||
nsLinebreakConverter::eLinebreakAny,
|
||||
nsLinebreakConverter::eLinebreakSpace));
|
||||
|
||||
// Get input stream
|
||||
aFile->GetInternalStream(getter_AddRefs(fileStream), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
if (fileStream) {
|
||||
// Create buffered stream (for efficiency)
|
||||
nsCOMPtr<nsIInputStream> bufferedStream;
|
||||
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
|
||||
fileStream, 8192);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
fileStream = bufferedStream;
|
||||
}
|
||||
}
|
||||
else {
|
||||
contentType.AssignLiteral("application/octet-stream");
|
||||
fileStream = bufferedStream;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -619,9 +618,7 @@ nsFSTextPlain::AddNameFilePair(const nsAString& aName,
|
|||
File* aFile)
|
||||
{
|
||||
nsAutoString filename;
|
||||
if (aFile) {
|
||||
aFile->GetName(filename);
|
||||
}
|
||||
aFile->GetName(filename);
|
||||
|
||||
AddNameValuePair(aName, filename);
|
||||
return NS_OK;
|
||||
|
|
|
@ -258,7 +258,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=523771
|
|||
<p>
|
||||
File input:
|
||||
<input type=file name="file_1" class="setfile">
|
||||
<input type=file name="file_2" class="setfile empty">
|
||||
<input type=file name="file_2">
|
||||
<input type=file name="" class="setfile">
|
||||
<input type=file name="">
|
||||
<input type=file class="setfile">
|
||||
|
@ -268,7 +268,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=523771
|
|||
Multifile input:
|
||||
<input multiple type=file name="file_3" class="setfile">
|
||||
<input multiple type=file name="file_4" class="setfile multi">
|
||||
<input multiple type=file name="file_5" class="setfile empty">
|
||||
<input multiple type=file name="file_5">
|
||||
<input multiple type=file name="" class="setfile">
|
||||
<input multiple type=file name="" class="setfile multi">
|
||||
<input multiple type=file name="">
|
||||
|
@ -426,7 +426,6 @@ function onFilesOpened(files) {
|
|||
|
||||
let singleFile = textFile;
|
||||
let multiFile = [textFile, imageFile];
|
||||
emptyFile = new File([], "", { type: "application/octet-stream" });
|
||||
|
||||
var addList = document.getElementsByClassName("setfile");
|
||||
let i = 0;
|
||||
|
@ -434,8 +433,6 @@ function onFilesOpened(files) {
|
|||
while (input = addList[i++]) {
|
||||
if (input.classList.contains("multi")) {
|
||||
SpecialPowers.wrap(input).mozSetFileArray(multiFile);
|
||||
} else if (input.classList.contains("empty")) {
|
||||
SpecialPowers.wrap(input).mozSetFileArray([emptyFile]);
|
||||
} else {
|
||||
SpecialPowers.wrap(input).mozSetFileArray([singleFile]);
|
||||
}
|
||||
|
@ -449,6 +446,7 @@ function onFilesOpened(files) {
|
|||
myFile2 = input.files[1];
|
||||
is(myFile1.size, 20, "File1 size");
|
||||
is(myFile2.size, 2711, "File2 size");
|
||||
emptyFile = { name: "", type: "application/octet-stream" };
|
||||
|
||||
// Now, actually run the tests; see below.
|
||||
onFilesSet();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
@ -618,7 +618,26 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
IPC::Channel* aChannel)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
gtk_init(nullptr, nullptr);
|
||||
// We need to pass a display down to gtk_init because it's not going to
|
||||
// use the one from the environment on its own when deciding which backend
|
||||
// to use, and when starting under XWayland, it may choose to start with
|
||||
// the wayland backend instead of the x11 backend.
|
||||
// The DISPLAY environment variable is normally set by the parent process.
|
||||
char* display_name = PR_GetEnv("DISPLAY");
|
||||
if (display_name) {
|
||||
int argc = 3;
|
||||
char option_name[] = "--display";
|
||||
char* argv[] = {
|
||||
nullptr,
|
||||
option_name,
|
||||
display_name,
|
||||
nullptr
|
||||
};
|
||||
char** argvp = argv;
|
||||
gtk_init(&argc, &argvp);
|
||||
} else {
|
||||
gtk_init(nullptr, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
|
@ -1572,7 +1591,7 @@ ContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
|
|||
mozilla::PRemoteSpellcheckEngineChild *
|
||||
ContentChild::AllocPRemoteSpellcheckEngineChild()
|
||||
{
|
||||
NS_NOTREACHED("Default Constructor for PRemoteSpellcheckEngineChild should never be called");
|
||||
MOZ_CRASH("Default Constructor for PRemoteSpellcheckEngineChild should never be called");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1599,7 +1618,7 @@ ContentChild::SendPBlobConstructor(PBlobChild* aActor,
|
|||
PPresentationChild*
|
||||
ContentChild::AllocPPresentationChild()
|
||||
{
|
||||
NS_NOTREACHED("We should never be manually allocating PPresentationChild actors");
|
||||
MOZ_CRASH("We should never be manually allocating PPresentationChild actors");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1704,7 +1723,7 @@ ContentChild::SendPIccConstructor(PIccChild* aActor,
|
|||
PIccChild*
|
||||
ContentChild::AllocPIccChild(const uint32_t& aServiceId)
|
||||
{
|
||||
NS_NOTREACHED("No one should be allocating PIccChild actors");
|
||||
MOZ_CRASH("No one should be allocating PIccChild actors");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1760,7 +1779,7 @@ ContentChild::DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild* aDev
|
|||
PFileSystemRequestChild*
|
||||
ContentChild::AllocPFileSystemRequestChild(const FileSystemParams& aParams)
|
||||
{
|
||||
NS_NOTREACHED("Should never get here!");
|
||||
MOZ_CRASH("Should never get here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1793,7 +1812,7 @@ PMobileConnectionChild*
|
|||
ContentChild::AllocPMobileConnectionChild(const uint32_t& aClientId)
|
||||
{
|
||||
#ifdef MOZ_B2G_RIL
|
||||
NS_NOTREACHED("No one should be allocating PMobileConnectionChild actors");
|
||||
MOZ_CRASH("No one should be allocating PMobileConnectionChild actors");
|
||||
return nullptr;
|
||||
#else
|
||||
MOZ_CRASH("No support for mobileconnection on this platform!");;
|
||||
|
@ -1832,7 +1851,7 @@ ContentChild::AllocPPrintingChild()
|
|||
// which implements PPrintingChild. Instead, the nsPrintingProxy service is
|
||||
// requested and instantiated via XPCOM, and the constructor of
|
||||
// nsPrintingProxy sets up the IPC connection.
|
||||
NS_NOTREACHED("Should never get here!");
|
||||
MOZ_CRASH("Should never get here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1851,7 +1870,7 @@ ContentChild::AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
|
|||
// nsScreenManagerProxy. Instead, the nsScreenManagerProxy
|
||||
// service is requested and instantiated via XPCOM, and the
|
||||
// constructor of nsScreenManagerProxy sets up the IPC connection.
|
||||
NS_NOTREACHED("Should never get here!");
|
||||
MOZ_CRASH("Should never get here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2007,7 +2026,7 @@ ContentChild::DeallocPMediaChild(media::PMediaChild *aActor)
|
|||
PStorageChild*
|
||||
ContentChild::AllocPStorageChild()
|
||||
{
|
||||
NS_NOTREACHED("We should never be manually allocating PStorageChild actors");
|
||||
MOZ_CRASH("We should never be manually allocating PStorageChild actors");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -3023,7 +3042,7 @@ ContentChild::RecvUpdateWindow(const uintptr_t& aChildId)
|
|||
}
|
||||
return true;
|
||||
#else
|
||||
NS_NOTREACHED("ContentChild::RecvUpdateWindow calls unexpected on this platform.");
|
||||
MOZ_ASSERT(false, "ContentChild::RecvUpdateWindow calls unexpected on this platform.");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
@ -5433,10 +5433,14 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
|||
|
||||
// The content process should never be in charge of computing whether or
|
||||
// not a window should be private or remote - the parent will do that.
|
||||
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW));
|
||||
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW));
|
||||
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME));
|
||||
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW));
|
||||
const uint32_t badFlags =
|
||||
nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
|
||||
| nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW
|
||||
| nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME
|
||||
| nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
|
||||
if (!!(aChromeFlags & badFlags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TabParent* thisTabParent = nullptr;
|
||||
if (aThisTab) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set sw=4 ts=8 et tw=80 :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "CrashReporterParent.h"
|
||||
|
|
|
@ -867,7 +867,7 @@ TabChild::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
|
|||
NS_IMETHODIMP
|
||||
TabChild::GetWebBrowser(nsIWebBrowser** aWebBrowser)
|
||||
{
|
||||
NS_NOTREACHED("TabChild::GetWebBrowser not supported in TabChild");
|
||||
NS_WARNING("TabChild::GetWebBrowser not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -875,7 +875,7 @@ TabChild::GetWebBrowser(nsIWebBrowser** aWebBrowser)
|
|||
NS_IMETHODIMP
|
||||
TabChild::SetWebBrowser(nsIWebBrowser* aWebBrowser)
|
||||
{
|
||||
NS_NOTREACHED("TabChild::SetWebBrowser not supported in TabChild");
|
||||
NS_WARNING("TabChild::SetWebBrowser not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -890,7 +890,7 @@ TabChild::GetChromeFlags(uint32_t* aChromeFlags)
|
|||
NS_IMETHODIMP
|
||||
TabChild::SetChromeFlags(uint32_t aChromeFlags)
|
||||
{
|
||||
NS_NOTREACHED("trying to SetChromeFlags from content process?");
|
||||
NS_WARNING("trying to SetChromeFlags from content process?");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -898,7 +898,7 @@ TabChild::SetChromeFlags(uint32_t aChromeFlags)
|
|||
NS_IMETHODIMP
|
||||
TabChild::DestroyBrowserWindow()
|
||||
{
|
||||
NS_NOTREACHED("TabChild::DestroyBrowserWindow not supported in TabChild");
|
||||
NS_WARNING("TabChild::DestroyBrowserWindow not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -906,7 +906,7 @@ TabChild::DestroyBrowserWindow()
|
|||
NS_IMETHODIMP
|
||||
TabChild::SizeBrowserTo(int32_t aCX, int32_t aCY)
|
||||
{
|
||||
NS_NOTREACHED("TabChild::SizeBrowserTo not supported in TabChild");
|
||||
NS_WARNING("TabChild::SizeBrowserTo not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -914,7 +914,7 @@ TabChild::SizeBrowserTo(int32_t aCX, int32_t aCY)
|
|||
NS_IMETHODIMP
|
||||
TabChild::ShowAsModal()
|
||||
{
|
||||
NS_NOTREACHED("TabChild::ShowAsModal not supported in TabChild");
|
||||
NS_WARNING("TabChild::ShowAsModal not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -929,7 +929,7 @@ TabChild::IsWindowModal(bool* aRetVal)
|
|||
NS_IMETHODIMP
|
||||
TabChild::ExitModalEventLoop(nsresult aStatus)
|
||||
{
|
||||
NS_NOTREACHED("TabChild::ExitModalEventLoop not supported in TabChild");
|
||||
NS_WARNING("TabChild::ExitModalEventLoop not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -1001,7 +1001,7 @@ TabChild::SetVisibility(bool aVisibility)
|
|||
NS_IMETHODIMP
|
||||
TabChild::GetTitle(char16_t** aTitle)
|
||||
{
|
||||
NS_NOTREACHED("TabChild::GetTitle not supported in TabChild");
|
||||
NS_WARNING("TabChild::GetTitle not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -1017,7 +1017,7 @@ TabChild::SetTitle(const char16_t* aTitle)
|
|||
NS_IMETHODIMP
|
||||
TabChild::GetSiteWindow(void** aSiteWindow)
|
||||
{
|
||||
NS_NOTREACHED("TabChild::GetSiteWindow not supported in TabChild");
|
||||
NS_WARNING("TabChild::GetSiteWindow not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
|
|
@ -205,7 +205,7 @@ MP3TrackDemuxer::FastSeek(const TimeUnit& aTime) {
|
|||
if (!aTime.ToMicroseconds()) {
|
||||
// Quick seek to the beginning of the stream.
|
||||
mFrameIndex = 0;
|
||||
} else if (vbr.IsTOCPresent()) {
|
||||
} else if (vbr.IsTOCPresent() && Duration().ToMicroseconds() > 0) {
|
||||
// Use TOC for more precise seeking.
|
||||
const float durationFrac = static_cast<float>(aTime.ToMicroseconds()) /
|
||||
Duration().ToMicroseconds();
|
||||
|
@ -358,7 +358,9 @@ MP3TrackDemuxer::Duration() const {
|
|||
// Unknown length, we can't estimate duration.
|
||||
return TimeUnit::FromMicroseconds(-1);
|
||||
}
|
||||
numFrames = (streamLen - mFirstFrameOffset) / AverageFrameLength();
|
||||
if (AverageFrameLength() > 0) {
|
||||
numFrames = (streamLen - mFirstFrameOffset) / AverageFrameLength();
|
||||
}
|
||||
}
|
||||
return Duration(numFrames);
|
||||
}
|
||||
|
@ -534,7 +536,7 @@ MP3TrackDemuxer::OffsetFromFrameIndex(int64_t aFrameIndex) const {
|
|||
int64_t offset = 0;
|
||||
const auto& vbr = mParser.VBRInfo();
|
||||
|
||||
if (vbr.NumBytes() && vbr.NumAudioFrames()) {
|
||||
if (vbr.IsValid()) {
|
||||
offset = mFirstFrameOffset + aFrameIndex * vbr.NumBytes().value() /
|
||||
vbr.NumAudioFrames().value();
|
||||
} else if (AverageFrameLength() > 0) {
|
||||
|
@ -550,7 +552,7 @@ MP3TrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const {
|
|||
int64_t frameIndex = 0;
|
||||
const auto& vbr = mParser.VBRInfo();
|
||||
|
||||
if (vbr.NumBytes() && vbr.NumAudioFrames()) {
|
||||
if (vbr.IsValid()) {
|
||||
frameIndex = static_cast<float>(aOffset - mFirstFrameOffset) /
|
||||
vbr.NumBytes().value() * vbr.NumAudioFrames().value();
|
||||
frameIndex = std::min<int64_t>(vbr.NumAudioFrames().value(), frameIndex);
|
||||
|
@ -626,7 +628,7 @@ MP3TrackDemuxer::AverageFrameLength() const {
|
|||
return static_cast<double>(mTotalFrameLen) / mNumParsedFrames;
|
||||
}
|
||||
const auto& vbr = mParser.VBRInfo();
|
||||
if (vbr.NumBytes() && vbr.NumAudioFrames()) {
|
||||
if (vbr.IsValid() && vbr.NumAudioFrames().value() + 1) {
|
||||
return static_cast<double>(vbr.NumBytes().value()) /
|
||||
(vbr.NumAudioFrames().value() + 1);
|
||||
}
|
||||
|
@ -962,6 +964,16 @@ FrameParser::VBRHeader::IsTOCPresent() const {
|
|||
return mTOC.size() == vbr_header::TOC_SIZE;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::VBRHeader::IsValid() const {
|
||||
return mType != NONE &&
|
||||
mNumAudioFrames.valueOr(0) > 0 &&
|
||||
mNumBytes.valueOr(0) > 0 &&
|
||||
// We don't care about the scale for any computations here.
|
||||
// mScale < 101 &&
|
||||
true;
|
||||
}
|
||||
|
||||
int64_t
|
||||
FrameParser::VBRHeader::Offset(float aDurationFac) const {
|
||||
if (!IsTOCPresent()) {
|
||||
|
|
|
@ -232,6 +232,9 @@ public:
|
|||
// Returns true iff Xing/Info TOC (table of contents) is present.
|
||||
bool IsTOCPresent() const;
|
||||
|
||||
// Returns whether the header is valid (containing reasonable field values).
|
||||
bool IsValid() const;
|
||||
|
||||
// Returns the byte offset for the given duration percentage as a factor
|
||||
// (0: begin, 1.0: end).
|
||||
int64_t Offset(float aDurationFac) const;
|
||||
|
|
|
@ -48,13 +48,12 @@ function ontimeupdate(e) {
|
|||
delta_wallclock = (t.timestamp - t.startTimestamp - t.bufferingTime) / 1000;
|
||||
|
||||
t.mozPreservesPitch = false;
|
||||
is(t.mozPreservesPitch, false, "If we disable the pitch preservation, it should appear as such.");
|
||||
is(t.mozPreservesPitch, false, t.name + ": If we disable the pitch preservation, it should appear as such.");
|
||||
|
||||
t.bufferingTime = 0;
|
||||
|
||||
is(t.playbackRate, SLOW_RATE,
|
||||
"The playback rate shoud be "+SLOW_RATE+"." + t.token);
|
||||
ok(checkPlaybackRate(delta_wallclock, delta, SLOW_RATE, 0.25), "We are effectively slowing down playback. (" + delta_wallclock + ", " + delta + ") for " + t.token);
|
||||
is(t.playbackRate, SLOW_RATE, t.name + ": The playback rate shoud be "+SLOW_RATE+".");
|
||||
ok(checkPlaybackRate(delta_wallclock, delta, SLOW_RATE, 0.25), t.name + ": We are effectively slowing down playback. (" + delta_wallclock + ", " + delta + ")");
|
||||
t.removeEventListener("timeupdate", ontimeupdate);
|
||||
t.addEventListener("pause", onpaused);
|
||||
t.playbackRate = NULL_RATE;
|
||||
|
@ -80,14 +79,14 @@ function afterNullPlaybackRate(e) {
|
|||
|
||||
t.testedForNull = true;
|
||||
|
||||
ok(t.currentTime == t.oldCurrentTime, "Current time should not change when playbackRate is null (" + t.currentTime + " " + t.oldCurrentTime + ").");
|
||||
ok(!t.paused, "The element should not be in paused state.");
|
||||
ok(t.currentTime == t.oldCurrentTime, t.name + ": Current time should not change when playbackRate is null (" + t.currentTime + " " + t.oldCurrentTime + ").");
|
||||
ok(!t.paused, t.name + ": The element should not be in paused state.");
|
||||
t.removeEventListener("paused", onpaused);
|
||||
is(t.pausedReceived, undefined, "Paused event should not have been received.");
|
||||
is(t.pausedReceived, undefined, t.name + ": Paused event should not have been received.");
|
||||
t.timestamp = Date.now();
|
||||
t.oldCurrentTime = t.currentTime;
|
||||
t.playbackRate = VERY_FAST_RATE;
|
||||
is(t.playbackRate, FAST_RATE, "Playback rate should be clamped to " + FAST_RATE + ".");
|
||||
is(t.playbackRate, FAST_RATE, t.name + ": Playback rate should be clamped to " + FAST_RATE + ".");
|
||||
}
|
||||
|
||||
function onended(e) {
|
||||
|
@ -97,9 +96,9 @@ function onended(e) {
|
|||
t.bufferingTime = 0;
|
||||
// If we got "ended" too early, skip these tests.
|
||||
if (t.testedForSlowdown && t.testedForNull) {
|
||||
is(t.playbackRate, FAST_RATE, "The playback rate should still be "+FAST_RATE+".");
|
||||
ok(!t.muted, "The audio should be muted when playing at high speed, but should not appear as such.");
|
||||
is(t.currentTime, t.duration, "Current time should be equal to the duration (not change by playback rate).");
|
||||
is(t.playbackRate, FAST_RATE, t.name + ": The playback rate should still be "+FAST_RATE+".");
|
||||
ok(!t.muted, t.name + ": The audio should be muted when playing at high speed, but should not appear as such.");
|
||||
is(t.currentTime, t.duration, t.name + ": Current time should be equal to the duration (not change by playback rate).");
|
||||
}
|
||||
finish_test(t);
|
||||
}
|
||||
|
@ -134,13 +133,14 @@ function onwaiting(e) {
|
|||
}
|
||||
|
||||
function onvolumechange(e) {
|
||||
ok(false, "We should not receive a volumechange event when changing the playback rate.");
|
||||
ok(false, e.target.name + ": We should not receive a volumechange event when changing the playback rate.");
|
||||
}
|
||||
|
||||
function startTest(test, token) {
|
||||
let elemType = /^audio/.test(test.type) ? "audio" : "video";
|
||||
let element = document.createElement(elemType);
|
||||
element.src = test.name;
|
||||
element.name = test.name;
|
||||
element.preload = "metadata";
|
||||
element.token = token;
|
||||
element.controls = true;
|
||||
|
@ -154,12 +154,12 @@ function startTest(test, token) {
|
|||
element.addEventListener("volumechange", onvolumechange);
|
||||
manager.started(token);
|
||||
element.startTimestamp = Date.now();
|
||||
is(element.mozPreservesPitch, true, "Pitch preservation should be enabled by default.");
|
||||
is(element.mozPreservesPitch, true, test.name + ": Pitch preservation should be enabled by default.");
|
||||
element.addEventListener("loadedmetadata", function() {
|
||||
is(element.playbackRate, 1.0, "playbackRate should be initially 1.0");
|
||||
is(element.defaultPlaybackRate, 1.0, "defaultPlaybackRate should be initially 1.0");
|
||||
is(element.playbackRate, 1.0, test.name + ": playbackRate should be initially 1.0");
|
||||
is(element.defaultPlaybackRate, 1.0, test.name + ": defaultPlaybackRate should be initially 1.0");
|
||||
element.playbackRate = VERY_SLOW_RATE;
|
||||
is(element.playbackRate, SLOW_RATE, "PlaybackRate should be clamped to " + SLOW_RATE + ".");
|
||||
is(element.playbackRate, SLOW_RATE, test.name + ": PlaybackRate should be clamped to " + SLOW_RATE + ".");
|
||||
element.play();
|
||||
element.playbackRate = SLOW_RATE;
|
||||
});
|
||||
|
|
|
@ -286,7 +286,7 @@ TraceJSObjWrappers(JSTracer *trc, void *data)
|
|||
// any of them moved.
|
||||
for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) {
|
||||
nsJSObjWrapperKey key = e.front().key();
|
||||
JS_CallUnbarrieredObjectTracer(trc, &key.mJSObj, "sJSObjWrappers key object");
|
||||
JS::UnsafeTraceRoot(trc, &key.mJSObj, "sJSObjWrappers key object");
|
||||
nsJSObjWrapper *wrapper = e.front().value();
|
||||
JS::TraceNullableEdge(trc, &wrapper->mJSObj, "sJSObjWrappers wrapper object");
|
||||
if (key != e.front().key()) {
|
||||
|
@ -1101,7 +1101,7 @@ JSObjWrapperKeyMarkCallback(JSTracer *trc, JSObject *obj, void *data) {
|
|||
if (!p)
|
||||
return;
|
||||
|
||||
JS_CallUnbarrieredObjectTracer(trc, &obj, "sJSObjWrappers key object");
|
||||
js::UnsafeTraceManuallyBarrieredEdge(trc, &obj, "sJSObjWrappers key object");
|
||||
nsJSObjWrapperKey newKey(obj, npp);
|
||||
sJSObjWrappers.rekeyIfMoved(oldKey, newKey);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ support-files =
|
|||
[test_MessageEvent.html]
|
||||
[test_postMessage_basehref.html]
|
||||
[test_postMessage_closed.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 894914 - wrong data - got FAIL, expected message # b2g(bug 894914 - wrong data - got FAIL, expected message) b2g-debug(bug 894914 - wrong data - got FAIL, expected message) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 894914 - wrong data - got FAIL, expected message # b2g(bug 894914 - wrong data - got FAIL, expected message) b2g-debug(bug 894914 - wrong data - got FAIL, expected message) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
|
||||
[test_postMessage_hash.html]
|
||||
[test_postMessage.html]
|
||||
[test_postMessage_idn.xhtml]
|
||||
|
|
|
@ -46,7 +46,12 @@ ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc)
|
|||
mWindowId = innerWindow->WindowID();
|
||||
}
|
||||
|
||||
aDoc->GetURL(mUrl);
|
||||
nsCOMPtr<nsIURI> originalURI = aDoc->GetOriginalURI();
|
||||
if (originalURI) {
|
||||
nsAutoCString spec;
|
||||
originalURI->GetSpec(spec);
|
||||
CopyUTF8toUTF16(spec, mUrl);
|
||||
}
|
||||
mVisibilityState = aDoc->VisibilityState();
|
||||
|
||||
ErrorResult result;
|
||||
|
|
|
@ -2920,8 +2920,10 @@ ServiceWorkerManager::LoadRegistration(
|
|||
registration = CreateNewRegistration(aRegistration.scope(), principal);
|
||||
} else {
|
||||
RefPtr<ServiceWorkerInfo> newest = registration->Newest();
|
||||
// If the script spec matches and our active worker state matches our
|
||||
// expectations for a "current worker", then we are done.
|
||||
if (newest && newest->ScriptSpec() == aRegistration.scriptSpec() &&
|
||||
!!registration->mActiveWorker == aRegistration.currentWorkerURL().IsEmpty()) {
|
||||
!registration->mActiveWorker == aRegistration.currentWorkerURL().IsEmpty()) {
|
||||
// No needs for updates.
|
||||
return;
|
||||
}
|
||||
|
@ -3599,7 +3601,8 @@ ServiceWorkerManager::DispatchFetchEvent(const PrincipalOriginAttributes& aOrigi
|
|||
|
||||
internalChannel->GetLoadGroup(getter_AddRefs(loadGroup));
|
||||
|
||||
documentId = aDocumentIdForTopLevelNavigation;
|
||||
// TODO: Use aDocumentIdForTopLevelNavigation for potentialClientId, pending
|
||||
// the spec change.
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aRv = aChannel->GetSecureUpgradedChannelURI(getter_AddRefs(uri));
|
||||
|
|
|
@ -1243,7 +1243,9 @@ private:
|
|||
init.mRequest.Value() = request;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = true;
|
||||
init.mClientId = mClientId;
|
||||
if (!mClientId.IsEmpty()) {
|
||||
init.mClientId = mClientId;
|
||||
}
|
||||
init.mIsReload = mIsReload;
|
||||
RefPtr<FetchEvent> event =
|
||||
FetchEvent::Constructor(globalObj, NS_LITERAL_STRING("fetch"), init, result);
|
||||
|
|
|
@ -1139,8 +1139,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode* aNode, char16_t** aText,
|
|||
nsCOMPtr<nsIURI> uri(linkContent->GetURIExternal());
|
||||
if (uri) {
|
||||
currElement->GetAttributeNS(
|
||||
NS_LITERAL_STRING("http://www.w3.org/1999/xlink"),
|
||||
NS_LITERAL_STRING("title"), outText);
|
||||
xlinkNS, NS_LITERAL_STRING("title"), outText);
|
||||
if (outText.Length()) {
|
||||
found = true;
|
||||
}
|
||||
|
@ -1150,7 +1149,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode* aNode, char16_t** aText,
|
|||
lookingForSVGTitle = UseSVGTitle(currElement);
|
||||
}
|
||||
if (lookingForSVGTitle) {
|
||||
nsINodeList* childNodes = node->ChildNodes();
|
||||
nsINodeList* childNodes = content->ChildNodes();
|
||||
uint32_t childNodeCount = childNodes->Length();
|
||||
for (uint32_t i = 0; i < childNodeCount; i++) {
|
||||
nsIContent* child = childNodes->Item(i);
|
||||
|
|
|
@ -145,4 +145,3 @@ interface nsIWebBrowserChrome : nsISupports
|
|||
*/
|
||||
void exitModalEventLoop(in nsresult aStatus);
|
||||
};
|
||||
|
||||
|
|
|
@ -808,7 +808,7 @@ CreateCGPattern(const Pattern &aPattern, CGAffineTransform aUserSpace)
|
|||
yStep = static_cast<CGFloat>(1 << 22);
|
||||
break;
|
||||
case ExtendMode::REFLECT:
|
||||
assert(0);
|
||||
MOZ_FALLTHROUGH_ASSERT("ExtendMode::REFLECT");
|
||||
case ExtendMode::REPEAT:
|
||||
xStep = static_cast<CGFloat>(CGImageGetWidth(image));
|
||||
yStep = static_cast<CGFloat>(CGImageGetHeight(image));
|
||||
|
|
|
@ -644,8 +644,7 @@ DrawTargetCairo::GetType() const
|
|||
|
||||
case CAIRO_SURFACE_TYPE_SKIA:
|
||||
case CAIRO_SURFACE_TYPE_QT:
|
||||
MOZ_ASSERT(false, "Can't determine actual DrawTargetType for DrawTargetCairo - assuming SOFTWARE_RASTER");
|
||||
// fallthrough
|
||||
MOZ_FALLTHROUGH_ASSERT("Can't determine actual DrawTargetType for DrawTargetCairo - assuming SOFTWARE_RASTER");
|
||||
case CAIRO_SURFACE_TYPE_IMAGE:
|
||||
case CAIRO_SURFACE_TYPE_XLIB:
|
||||
case CAIRO_SURFACE_TYPE_XCB:
|
||||
|
|
|
@ -91,6 +91,7 @@ bool
|
|||
GLBlitHelper::InitTexQuadProgram(BlitType target)
|
||||
{
|
||||
const char kTexBlit_VertShaderSource[] = "\
|
||||
#version 100 \n\
|
||||
#ifdef GL_ES \n\
|
||||
precision mediump float; \n\
|
||||
#endif \n\
|
||||
|
@ -109,6 +110,7 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
|||
";
|
||||
|
||||
const char kTex2DBlit_FragShaderSource[] = "\
|
||||
#version 100 \n\
|
||||
#ifdef GL_ES \n\
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH \n\
|
||||
precision highp float; \n\
|
||||
|
@ -127,6 +129,7 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
|||
";
|
||||
|
||||
const char kTex2DRectBlit_FragShaderSource[] = "\
|
||||
#version 100 \n\
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH \n\
|
||||
precision highp float; \n\
|
||||
#else \n\
|
||||
|
@ -146,6 +149,7 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
|||
";
|
||||
#ifdef ANDROID /* MOZ_WIDGET_ANDROID || MOZ_WIDGET_GONK */
|
||||
const char kTexExternalBlit_FragShaderSource[] = "\
|
||||
#version 100 \n\
|
||||
#extension GL_OES_EGL_image_external : require \n\
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH \n\
|
||||
precision highp float; \n\
|
||||
|
@ -174,6 +178,7 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
|||
[B] [1.16438, 2.01723, 0.00000] [Cr - 0.50196]
|
||||
*/
|
||||
const char kTexYUVPlanarBlit_FragShaderSource[] = "\
|
||||
#version 100 \n\
|
||||
#ifdef GL_ES \n\
|
||||
precision mediump float; \n\
|
||||
#endif \n\
|
||||
|
@ -200,6 +205,7 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
|||
|
||||
#ifdef XP_MACOSX
|
||||
const char kTexNV12PlanarBlit_FragShaderSource[] = "\
|
||||
#version 100 \n\
|
||||
#extension GL_ARB_texture_rectangle : require \n\
|
||||
#ifdef GL_ES \n\
|
||||
precision mediump float \n\
|
||||
|
@ -383,18 +389,16 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
|||
// Cache and set attribute and uniform
|
||||
mGL->fUseProgram(program);
|
||||
switch (target) {
|
||||
#ifdef ANDROID
|
||||
case ConvertSurfaceTexture:
|
||||
case ConvertGralloc:
|
||||
#endif
|
||||
case BlitTex2D:
|
||||
case BlitTexRect:
|
||||
case ConvertEGLImage:
|
||||
case ConvertSurfaceTexture:
|
||||
case ConvertGralloc: {
|
||||
#ifdef ANDROID
|
||||
case ConvertEGLImage: {
|
||||
GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
|
||||
MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
|
||||
mGL->fUniform1i(texUnitLoc, 0);
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE("gralloc not support on non-android");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ConvertPlanarYCbCr: {
|
||||
|
@ -434,6 +438,8 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0);
|
||||
mYFlipLoc = mGL->fGetUniformLocation(program, "uYflip");
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define GFX_LAYERMETRICSWRAPPER_H
|
||||
|
||||
#include "Layers.h"
|
||||
#include "UnitTransforms.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
@ -299,6 +300,11 @@ public:
|
|||
return gfx::Matrix4x4();
|
||||
}
|
||||
|
||||
CSSTransformMatrix GetTransformTyped() const
|
||||
{
|
||||
return ViewAs<CSSTransformMatrix>(GetTransform());
|
||||
}
|
||||
|
||||
bool TransformIsPerspective() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
|
|
@ -895,6 +895,12 @@ Layer::GetTransform() const
|
|||
return transform;
|
||||
}
|
||||
|
||||
const CSSTransformMatrix
|
||||
Layer::GetTransformTyped() const
|
||||
{
|
||||
return ViewAs<CSSTransformMatrix>(GetTransform());
|
||||
}
|
||||
|
||||
const Matrix4x4
|
||||
Layer::GetLocalTransform()
|
||||
{
|
||||
|
@ -912,6 +918,12 @@ Layer::GetLocalTransform()
|
|||
return transform;
|
||||
}
|
||||
|
||||
const LayerToParentLayerMatrix4x4
|
||||
Layer::GetLocalTransformTyped()
|
||||
{
|
||||
return ViewAs<LayerToParentLayerMatrix4x4>(GetLocalTransform());
|
||||
}
|
||||
|
||||
bool
|
||||
Layer::HasTransformAnimation() const
|
||||
{
|
||||
|
|
|
@ -1276,6 +1276,9 @@ public:
|
|||
virtual Layer* GetFirstChild() const { return nullptr; }
|
||||
virtual Layer* GetLastChild() const { return nullptr; }
|
||||
const gfx::Matrix4x4 GetTransform() const;
|
||||
// Same as GetTransform(), but returns the transform as a strongly-typed
|
||||
// matrix. Eventually this will replace GetTransform().
|
||||
const CSSTransformMatrix GetTransformTyped() const;
|
||||
const gfx::Matrix4x4& GetBaseTransform() const { return mTransform; }
|
||||
// Note: these are virtual because ContainerLayerComposite overrides them.
|
||||
virtual float GetPostXScale() const { return mPostXScale; }
|
||||
|
@ -1346,10 +1349,17 @@ public:
|
|||
|
||||
/**
|
||||
* Returns the local transform for this layer: either mTransform or,
|
||||
* for shadow layers, GetShadowTransform()
|
||||
* for shadow layers, GetShadowTransform(), in either case with the
|
||||
* pre- and post-scales applied.
|
||||
*/
|
||||
const gfx::Matrix4x4 GetLocalTransform();
|
||||
|
||||
/**
|
||||
* Same as GetLocalTransform(), but returns a strongly-typed matrix.
|
||||
* Eventually, this will replace GetLocalTransform().
|
||||
*/
|
||||
const LayerToParentLayerMatrix4x4 GetLocalTransformTyped();
|
||||
|
||||
/**
|
||||
* Returns the local opacity for this layer: either mOpacity or,
|
||||
* for shadow layers, GetShadowOpacity()
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/layers/GonkNativeHandle.h"
|
||||
#endif
|
||||
|
||||
#include "Units.h"
|
||||
#include "mozilla/gfx/Point.h" // for IntPoint
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
#include "nsRegion.h"
|
||||
|
@ -284,6 +285,22 @@ enum TextureDumpMode {
|
|||
DoNotCompress // dump texture uncompressed
|
||||
};
|
||||
|
||||
// Some specialized typedefs of Matrix4x4Typed.
|
||||
typedef gfx::Matrix4x4Typed<LayerPixel, CSSTransformedLayerPixel> CSSTransformMatrix;
|
||||
// Several different async transforms can contribute to a layer's transform
|
||||
// (specifically, an async animation can contribute a transform, and each APZC
|
||||
// that scrolls a layer can contribute async scroll/zoom and overscroll
|
||||
// transforms).
|
||||
// To try to model this with typed units, we represent individual async
|
||||
// transforms as ParentLayer -> ParentLayer transforms (aliased as
|
||||
// AsyncTransformComponentMatrix), and we represent the product of all of them
|
||||
// as a CSSTransformLayer -> ParentLayer transform (aliased as
|
||||
// AsyncTransformMatrix). To create an AsyncTransformMatrix from component
|
||||
// matrices, a ViewAs operation is needed. A MultipleAsyncTransforms
|
||||
// PixelCastJustification is provided for this purpose.
|
||||
typedef gfx::Matrix4x4Typed<ParentLayerPixel, ParentLayerPixel> AsyncTransformComponentMatrix;
|
||||
typedef gfx::Matrix4x4Typed<CSSTransformedLayerPixel, ParentLayerPixel> AsyncTransformMatrix;
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -358,7 +358,9 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
|||
if (!needsApzc) {
|
||||
node = RecycleOrCreateNode(aState, nullptr, aLayersId);
|
||||
AttachNodeToTree(node, aParent, aNextSibling);
|
||||
node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(),
|
||||
node->SetHitTestData(
|
||||
GetEventRegions(aLayer),
|
||||
aLayer.GetTransformTyped(),
|
||||
aLayer.GetClipRect() ? Some(ParentLayerIntRegion(*aLayer.GetClipRect())) : Nothing(),
|
||||
GetEventRegionsOverride(aParent, aLayer));
|
||||
node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
|
||||
|
@ -462,7 +464,10 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
|||
MOZ_ASSERT(node->IsPrimaryHolder() && node->GetApzc() && node->GetApzc()->Matches(guid));
|
||||
|
||||
ParentLayerIntRegion clipRegion = ComputeClipRegion(state->mController, aLayer);
|
||||
node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(), Some(clipRegion),
|
||||
node->SetHitTestData(
|
||||
GetEventRegions(aLayer),
|
||||
aLayer.GetTransformTyped(),
|
||||
Some(clipRegion),
|
||||
GetEventRegionsOverride(aParent, aLayer));
|
||||
apzc->SetAncestorTransform(aAncestorTransform);
|
||||
|
||||
|
@ -526,7 +531,10 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
|||
MOZ_ASSERT(aAncestorTransform.FuzzyEqualsMultiplicative(apzc->GetAncestorTransform()));
|
||||
|
||||
ParentLayerIntRegion clipRegion = ComputeClipRegion(state->mController, aLayer);
|
||||
node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(), Some(clipRegion),
|
||||
node->SetHitTestData(
|
||||
GetEventRegions(aLayer),
|
||||
aLayer.GetTransformTyped(),
|
||||
Some(clipRegion),
|
||||
GetEventRegionsOverride(aParent, aLayer));
|
||||
}
|
||||
|
||||
|
@ -1848,7 +1856,7 @@ APZCTreeManager::GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) c
|
|||
// ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P
|
||||
ancestorUntransform = parent->GetAncestorTransform().Inverse();
|
||||
// asyncUntransform is updated to PA.Inverse() when parent == P
|
||||
Matrix4x4 asyncUntransform = parent->GetCurrentAsyncTransformWithOverscroll().Inverse();
|
||||
Matrix4x4 asyncUntransform = parent->GetCurrentAsyncTransformWithOverscroll().Inverse().ToUnknownMatrix();
|
||||
// untransformSinceLastApzc is RC.Inverse() * QC.Inverse() * PA.Inverse()
|
||||
Matrix4x4 untransformSinceLastApzc = ancestorUntransform * asyncUntransform;
|
||||
|
||||
|
@ -1880,7 +1888,7 @@ APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) co
|
|||
// leftmost matrix in a multiplication is applied first.
|
||||
|
||||
// asyncUntransform is LA.Inverse()
|
||||
Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransformWithOverscroll().Inverse();
|
||||
Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransformWithOverscroll().Inverse().ToUnknownMatrix();
|
||||
|
||||
// aTransformToGeckoOut is initialized to LA.Inverse() * LD * MC * NC * OC * PC
|
||||
result = asyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetAncestorTransform();
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#define mozilla_layers_APZUtils_h
|
||||
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include "LayersTypes.h"
|
||||
#include "UnitTransforms.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
|
@ -61,6 +63,16 @@ static bool IsZero(const gfx::PointTyped<Units>& aPoint)
|
|||
&& FuzzyEqualsAdditive(aPoint.y, 0.0f, COORDINATE_EPSILON);
|
||||
}
|
||||
|
||||
// Deem an AsyncTransformComponentMatrix (obtained by multiplying together
|
||||
// one or more AsyncTransformComponentMatrix objects) as constituting a
|
||||
// complete async transform.
|
||||
inline AsyncTransformMatrix
|
||||
CompleteAsyncTransform(const AsyncTransformComponentMatrix& aMatrix)
|
||||
{
|
||||
return ViewAs<AsyncTransformMatrix>(aMatrix,
|
||||
PixelCastJustification::MultipleAsyncTransforms);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -2899,10 +2899,10 @@ bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
|
|||
return false;
|
||||
}
|
||||
|
||||
Matrix4x4 AsyncPanZoomController::GetOverscrollTransform() const {
|
||||
AsyncTransformComponentMatrix AsyncPanZoomController::GetOverscrollTransform() const {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
if (!IsOverscrolled()) {
|
||||
return Matrix4x4();
|
||||
return AsyncTransformComponentMatrix();
|
||||
}
|
||||
|
||||
// The overscroll effect is a uniform stretch along the overscrolled axis,
|
||||
|
@ -2939,7 +2939,7 @@ Matrix4x4 AsyncPanZoomController::GetOverscrollTransform() const {
|
|||
}
|
||||
|
||||
// Combine the transformations into a matrix.
|
||||
return Matrix4x4::Scaling(scaleX, scaleY, 1)
|
||||
return AsyncTransformComponentMatrix::Scaling(scaleX, scaleY, 1)
|
||||
.PostTranslate(translation.x, translation.y, 0);
|
||||
}
|
||||
|
||||
|
@ -2987,7 +2987,7 @@ bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
|
|||
return requestAnimationFrame;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SampleContentTransformForFrame(ViewTransform* aOutTransform,
|
||||
void AsyncPanZoomController::SampleContentTransformForFrame(AsyncTransform* aOutTransform,
|
||||
ParentLayerPoint& aScrollOffset)
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
@ -2996,7 +2996,7 @@ void AsyncPanZoomController::SampleContentTransformForFrame(ViewTransform* aOutT
|
|||
*aOutTransform = GetCurrentAsyncTransform();
|
||||
}
|
||||
|
||||
ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() const {
|
||||
AsyncTransform AsyncPanZoomController::GetCurrentAsyncTransform() const {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
CSSPoint lastPaintScrollOffset;
|
||||
|
@ -3028,13 +3028,14 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() const {
|
|||
ParentLayerPoint translation = (currentScrollOffset - lastPaintScrollOffset)
|
||||
* mFrameMetrics.GetZoom() * mTestAsyncZoom.scale;
|
||||
|
||||
return ViewTransform(
|
||||
return AsyncTransform(
|
||||
LayerToParentLayerScale(mFrameMetrics.GetAsyncZoom().scale * mTestAsyncZoom.scale),
|
||||
-translation);
|
||||
}
|
||||
|
||||
Matrix4x4 AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll() const {
|
||||
return Matrix4x4(GetCurrentAsyncTransform()) * GetOverscrollTransform();
|
||||
AsyncTransformComponentMatrix AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll() const {
|
||||
return AsyncTransformComponentMatrix(GetCurrentAsyncTransform())
|
||||
* GetOverscrollTransform();
|
||||
}
|
||||
|
||||
Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
|
||||
|
|
|
@ -44,7 +44,7 @@ struct ScrollableLayerGuid;
|
|||
class CompositorParent;
|
||||
class GestureEventListener;
|
||||
class PCompositorParent;
|
||||
struct ViewTransform;
|
||||
struct AsyncTransform;
|
||||
class AsyncPanZoomAnimation;
|
||||
class FlingAnimation;
|
||||
class InputBlockState;
|
||||
|
@ -166,14 +166,14 @@ public:
|
|||
* This function returns the async transform via the |aOutTransform|
|
||||
* out parameter.
|
||||
*/
|
||||
void SampleContentTransformForFrame(ViewTransform* aOutTransform,
|
||||
void SampleContentTransformForFrame(AsyncTransform* aOutTransform,
|
||||
ParentLayerPoint& aScrollOffset);
|
||||
|
||||
/**
|
||||
* Return a visual effect that reflects this apzc's
|
||||
* overscrolled state, if any.
|
||||
*/
|
||||
Matrix4x4 GetOverscrollTransform() const;
|
||||
AsyncTransformComponentMatrix GetOverscrollTransform() const;
|
||||
|
||||
/**
|
||||
* A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics
|
||||
|
@ -218,13 +218,13 @@ public:
|
|||
* existing transform, it will make the layer appear with the desired pan/zoom
|
||||
* amount.
|
||||
*/
|
||||
ViewTransform GetCurrentAsyncTransform() const;
|
||||
AsyncTransform GetCurrentAsyncTransform() const;
|
||||
|
||||
/**
|
||||
* Returns the same transform as GetCurrentAsyncTransform(), but includes
|
||||
* any transform due to axis over-scroll.
|
||||
*/
|
||||
Matrix4x4 GetCurrentAsyncTransformWithOverscroll() const;
|
||||
AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll() const;
|
||||
|
||||
/**
|
||||
* Returns the transform to take something from the coordinate space of the
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "LayersLogging.h" // for Stringify
|
||||
#include "mozilla/gfx/Point.h" // for Point4D
|
||||
#include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread
|
||||
#include "mozilla/layers/APZUtils.h" // for CompleteAsyncTransform
|
||||
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform::operator Matrix4x4()
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
#include "UnitTransforms.h" // for ViewAs
|
||||
|
@ -206,7 +207,7 @@ HitTestingTreeNode::GetLayersId() const
|
|||
|
||||
void
|
||||
HitTestingTreeNode::SetHitTestData(const EventRegions& aRegions,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const CSSTransformMatrix& aTransform,
|
||||
const Maybe<ParentLayerIntRegion>& aClipRegion,
|
||||
const EventRegionsOverride& aOverride)
|
||||
{
|
||||
|
@ -227,12 +228,12 @@ Maybe<LayerPoint>
|
|||
HitTestingTreeNode::Untransform(const ParentLayerPoint& aPoint) const
|
||||
{
|
||||
// convert into Layer coordinate space
|
||||
gfx::Matrix4x4 localTransform = mTransform;
|
||||
if (mApzc) {
|
||||
localTransform = localTransform * mApzc->GetCurrentAsyncTransformWithOverscroll();
|
||||
}
|
||||
return UntransformBy(
|
||||
ViewAs<LayerToParentLayerMatrix4x4>(localTransform).Inverse(), aPoint);
|
||||
LayerToParentLayerMatrix4x4 transform = mTransform *
|
||||
CompleteAsyncTransform(
|
||||
mApzc
|
||||
? mApzc->GetCurrentAsyncTransformWithOverscroll()
|
||||
: AsyncTransformComponentMatrix());
|
||||
return UntransformBy(transform.Inverse(), aPoint);
|
||||
}
|
||||
|
||||
HitTestResult
|
||||
|
|
|
@ -85,7 +85,7 @@ public:
|
|||
/* Hit test related methods */
|
||||
|
||||
void SetHitTestData(const EventRegions& aRegions,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const CSSTransformMatrix& aTransform,
|
||||
const Maybe<ParentLayerIntRegion>& aClipRegion,
|
||||
const EventRegionsOverride& aOverride);
|
||||
bool IsOutsideClip(const ParentLayerPoint& aPoint) const;
|
||||
|
@ -135,7 +135,7 @@ private:
|
|||
|
||||
/* This is the transform from layer L. This does NOT include any async
|
||||
* transforms. */
|
||||
gfx::Matrix4x4 mTransform;
|
||||
CSSTransformMatrix mTransform;
|
||||
|
||||
/* This is clip rect for L that we wish to use for hit-testing purposes. Note
|
||||
* that this may not be exactly the same as the clip rect on layer L because
|
||||
|
|
|
@ -233,7 +233,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool SampleContentTransformForFrame(ViewTransform* aOutTransform,
|
||||
bool SampleContentTransformForFrame(AsyncTransform* aOutTransform,
|
||||
ParentLayerPoint& aScrollOffset,
|
||||
const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(0)) {
|
||||
mcc->AdvanceBy(aIncrement);
|
||||
|
@ -340,7 +340,7 @@ protected:
|
|||
{
|
||||
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
mcc->AdvanceBy(increment);
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ protected:
|
|||
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
||||
bool recoveredFromOverscroll = false;
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
while (apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut)) {
|
||||
// The reported scroll offset should be the same throughout.
|
||||
EXPECT_EQ(aExpectedScrollOffset, pointOut);
|
||||
|
@ -1112,11 +1112,11 @@ TEST_F(APZCBasicTester, Overzoom) {
|
|||
|
||||
TEST_F(APZCBasicTester, SimpleTransform) {
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
|
||||
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
||||
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(), viewTransformOut);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1174,7 +1174,7 @@ TEST_F(APZCBasicTester, ComplexTransform) {
|
|||
layers[1]->SetFrameMetrics(childMetrics);
|
||||
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
|
||||
// Both the parent and child layer should behave exactly the same here, because
|
||||
// the CSS transform on the child layer does not affect the SampleContentTransformForFrame code
|
||||
|
@ -1183,39 +1183,39 @@ TEST_F(APZCBasicTester, ComplexTransform) {
|
|||
apzc->SetFrameMetrics(metrics);
|
||||
apzc->NotifyLayersUpdated(metrics, true);
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut);
|
||||
EXPECT_EQ(ParentLayerPoint(60, 60), pointOut);
|
||||
|
||||
childApzc->SetFrameMetrics(childMetrics);
|
||||
childApzc->NotifyLayersUpdated(childMetrics, true);
|
||||
childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut);
|
||||
EXPECT_EQ(ParentLayerPoint(60, 60), pointOut);
|
||||
|
||||
// do an async scroll by 5 pixels and check the transform
|
||||
metrics.ScrollBy(CSSPoint(5, 0));
|
||||
apzc->SetFrameMetrics(metrics);
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut);
|
||||
EXPECT_EQ(ParentLayerPoint(90, 60), pointOut);
|
||||
|
||||
childMetrics.ScrollBy(CSSPoint(5, 0));
|
||||
childApzc->SetFrameMetrics(childMetrics);
|
||||
childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut);
|
||||
EXPECT_EQ(ParentLayerPoint(90, 60), pointOut);
|
||||
|
||||
// do an async zoom of 1.5x and check the transform
|
||||
metrics.ZoomBy(1.5f);
|
||||
apzc->SetFrameMetrics(metrics);
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut);
|
||||
EXPECT_EQ(ParentLayerPoint(135, 90), pointOut);
|
||||
|
||||
childMetrics.ZoomBy(1.5f);
|
||||
childApzc->SetFrameMetrics(childMetrics);
|
||||
childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut);
|
||||
EXPECT_EQ(ParentLayerPoint(135, 90), pointOut);
|
||||
|
||||
childApzc->Destroy();
|
||||
|
@ -1253,7 +1253,7 @@ protected:
|
|||
int touchStart = 50;
|
||||
int touchEnd = 10;
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
|
||||
nsTArray<uint32_t> allowedTouchBehaviors;
|
||||
allowedTouchBehaviors.AppendElement(aBehavior);
|
||||
|
@ -1264,10 +1264,10 @@ protected:
|
|||
|
||||
if (aShouldTriggerScroll) {
|
||||
EXPECT_EQ(ParentLayerPoint(0, -(touchEnd-touchStart)), pointOut);
|
||||
EXPECT_NE(ViewTransform(), viewTransformOut);
|
||||
EXPECT_NE(AsyncTransform(), viewTransformOut);
|
||||
} else {
|
||||
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
||||
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(), viewTransformOut);
|
||||
}
|
||||
|
||||
// Clear the fling from the previous pan, or stopping it will
|
||||
|
@ -1279,7 +1279,7 @@ protected:
|
|||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
|
||||
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
||||
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(), viewTransformOut);
|
||||
}
|
||||
|
||||
void DoPanWithPreventDefaultTest()
|
||||
|
@ -1289,7 +1289,7 @@ protected:
|
|||
int touchStart = 50;
|
||||
int touchEnd = 10;
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
uint64_t blockId = 0;
|
||||
|
||||
// Pan down
|
||||
|
@ -1303,7 +1303,7 @@ protected:
|
|||
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
||||
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(), viewTransformOut);
|
||||
|
||||
apzc->AssertStateIsReset();
|
||||
}
|
||||
|
@ -1357,7 +1357,7 @@ TEST_F(APZCBasicTester, Fling) {
|
|||
int touchStart = 50;
|
||||
int touchEnd = 10;
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
|
||||
// Fling down. Each step scroll further down
|
||||
Pan(apzc, mcc, touchStart, touchEnd);
|
||||
|
@ -1525,7 +1525,7 @@ TEST_F(APZCBasicTester, OverScrollAbort) {
|
|||
EXPECT_TRUE(apzc->IsOverscrolled());
|
||||
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
|
||||
// This sample call will run to the end of the fling animation
|
||||
// and will schedule the overscroll animation.
|
||||
|
@ -1582,7 +1582,7 @@ protected:
|
|||
|
||||
// Advance the fling animation by timeDelta milliseconds.
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut, TimeDuration::FromMilliseconds(timeDelta));
|
||||
|
||||
// Deliver a tap to abort the fling. Ensure that we get a HandleSingleTap
|
||||
|
@ -1619,7 +1619,7 @@ protected:
|
|||
|
||||
// Sample the fling a couple of times to ensure it's going.
|
||||
ParentLayerPoint point, finalPoint;
|
||||
ViewTransform viewTransform;
|
||||
AsyncTransform viewTransform;
|
||||
apzc->SampleContentTransformForFrame(&viewTransform, point, TimeDuration::FromMilliseconds(10));
|
||||
apzc->SampleContentTransformForFrame(&viewTransform, finalPoint, TimeDuration::FromMilliseconds(10));
|
||||
EXPECT_GT(finalPoint.y, point.y);
|
||||
|
@ -1818,11 +1818,11 @@ protected:
|
|||
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
|
||||
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
|
||||
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
||||
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
||||
EXPECT_EQ(AsyncTransform(), viewTransformOut);
|
||||
|
||||
apzc->AssertStateIsReset();
|
||||
}
|
||||
|
@ -2049,7 +2049,7 @@ protected:
|
|||
void SampleAnimationsOnce() {
|
||||
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
||||
ParentLayerPoint pointOut;
|
||||
ViewTransform viewTransformOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
mcc->AdvanceBy(increment);
|
||||
|
||||
for (const RefPtr<Layer>& layer : layers) {
|
||||
|
@ -2710,7 +2710,7 @@ TEST_F(APZHitTestingTester, TestRepaintFlushOnWheelEvents) {
|
|||
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(swi, nullptr, nullptr));
|
||||
EXPECT_EQ(origin, swi.mOrigin);
|
||||
|
||||
ViewTransform viewTransform;
|
||||
AsyncTransform viewTransform;
|
||||
ParentLayerPoint point;
|
||||
apzcroot->SampleContentTransformForFrame(&viewTransform, point);
|
||||
EXPECT_EQ(0, point.x);
|
||||
|
|
|
@ -146,7 +146,7 @@ FuzzyEquals(float a, float b) {
|
|||
return (fabsf(a - b) < 1e-6);
|
||||
}
|
||||
|
||||
static ViewTransform
|
||||
static AsyncTransform
|
||||
ComputeViewTransform(const FrameMetrics& aContentMetrics, const FrameMetrics& aCompositorMetrics)
|
||||
{
|
||||
// This is basically the same code as AsyncPanZoomController::GetCurrentAsyncTransform
|
||||
|
@ -155,7 +155,7 @@ ComputeViewTransform(const FrameMetrics& aContentMetrics, const FrameMetrics& aC
|
|||
|
||||
ParentLayerPoint translation = (aCompositorMetrics.GetScrollOffset() - aContentMetrics.GetScrollOffset())
|
||||
* aCompositorMetrics.GetZoom();
|
||||
return ViewTransform(aCompositorMetrics.GetAsyncZoom(), -translation);
|
||||
return AsyncTransform(aCompositorMetrics.GetAsyncZoom(), -translation);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -163,7 +163,7 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
|||
const LayerMetricsWrapper& aLayer,
|
||||
bool aHasPendingNewThebesContent,
|
||||
bool aLowPrecision,
|
||||
ViewTransform& aViewTransform)
|
||||
AsyncTransform& aViewTransform)
|
||||
{
|
||||
MOZ_ASSERT(aLayer);
|
||||
|
||||
|
@ -1399,11 +1399,11 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
|||
static Maybe<LayerRect>
|
||||
GetCompositorSideCompositionBounds(const LayerMetricsWrapper& aScrollAncestor,
|
||||
const LayerToParentLayerMatrix4x4& aTransformToCompBounds,
|
||||
const ViewTransform& aAPZTransform,
|
||||
const AsyncTransform& aAPZTransform,
|
||||
const LayerRect& aClip)
|
||||
{
|
||||
LayerToParentLayerMatrix4x4 transform = aTransformToCompBounds *
|
||||
ViewAs<ParentLayerToParentLayerMatrix4x4>(aAPZTransform);
|
||||
AsyncTransformComponentMatrix(aAPZTransform);
|
||||
|
||||
return UntransformBy(transform.Inverse(),
|
||||
aScrollAncestor.Metrics().GetCompositionBounds(), aClip);
|
||||
|
@ -1443,7 +1443,7 @@ ClientMultiTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& a
|
|||
// Find out the current view transform to determine which tiles to draw
|
||||
// first, and see if we should just abort this paint. Aborting is usually
|
||||
// caused by there being an incoming, more relevant paint.
|
||||
ViewTransform viewTransform;
|
||||
AsyncTransform viewTransform;
|
||||
#if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_ANDROID_APZ)
|
||||
FrameMetrics contentMetrics = scrollAncestor.Metrics();
|
||||
bool abortPaint = false;
|
||||
|
|
|
@ -376,7 +376,7 @@ public:
|
|||
bool UpdateFromCompositorFrameMetrics(const LayerMetricsWrapper& aLayer,
|
||||
bool aHasPendingNewThebesContent,
|
||||
bool aLowPrecision,
|
||||
ViewTransform& aViewTransform);
|
||||
AsyncTransform& aViewTransform);
|
||||
|
||||
/**
|
||||
* Determines if the compositor's upcoming composition bounds has fallen
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/gfx/Point.h" // for RoundedToInt, PointTyped
|
||||
#include "mozilla/gfx/Rect.h" // for RoundedToInt, RectTyped
|
||||
#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
|
||||
#include "mozilla/layers/APZUtils.h" // for CompleteAsyncTransform
|
||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||
#include "mozilla/layers/CompositorParent.h" // for CompositorParent, etc
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
|
@ -222,7 +223,7 @@ TransformClipRect(Layer* aLayer,
|
|||
* only be applied once.
|
||||
*/
|
||||
static void
|
||||
SetShadowTransform(Layer* aLayer, Matrix4x4 aTransform)
|
||||
SetShadowTransform(Layer* aLayer, LayerToParentLayerMatrix4x4 aTransform)
|
||||
{
|
||||
if (ContainerLayer* c = aLayer->AsContainerLayer()) {
|
||||
aTransform.PreScale(1.0f / c->GetPreXScale(),
|
||||
|
@ -232,7 +233,7 @@ SetShadowTransform(Layer* aLayer, Matrix4x4 aTransform)
|
|||
aTransform.PostScale(1.0f / aLayer->GetPostXScale(),
|
||||
1.0f / aLayer->GetPostYScale(),
|
||||
1);
|
||||
aLayer->AsLayerComposite()->SetShadowTransform(aTransform);
|
||||
aLayer->AsLayerComposite()->SetShadowTransform(aTransform.ToUnknownMatrix());
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -246,7 +247,7 @@ TranslateShadowLayer(Layer* aLayer,
|
|||
// Note that the shadow transform is reset on every frame of composition so
|
||||
// we don't have to worry about the adjustments compounding over successive
|
||||
// frames.
|
||||
Matrix4x4 layerTransform = aLayer->GetLocalTransform();
|
||||
LayerToParentLayerMatrix4x4 layerTransform = aLayer->GetLocalTransformTyped();
|
||||
|
||||
// Apply the translation to the layer transform.
|
||||
layerTransform.PostTranslate(aTranslation.x, aTranslation.y, 0);
|
||||
|
@ -384,8 +385,8 @@ void
|
|||
AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
||||
Layer* aTransformedSubtreeRoot,
|
||||
FrameMetrics::ViewID aTransformScrollId,
|
||||
const Matrix4x4& aPreviousTransformForRoot,
|
||||
const Matrix4x4& aCurrentTransformForRoot,
|
||||
const LayerToParentLayerMatrix4x4& aPreviousTransformForRoot,
|
||||
const LayerToParentLayerMatrix4x4& aCurrentTransformForRoot,
|
||||
const ScreenMargin& aFixedLayerMargins,
|
||||
bool aTransformAffectsLayerClip)
|
||||
{
|
||||
|
@ -429,8 +430,8 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
|||
|
||||
// Calculate the cumulative transforms between the subtree root with the
|
||||
// old transform and the current transform.
|
||||
Matrix4x4 oldCumulativeTransform = ancestorTransform * aPreviousTransformForRoot;
|
||||
Matrix4x4 newCumulativeTransform = ancestorTransform * aCurrentTransformForRoot;
|
||||
Matrix4x4 oldCumulativeTransform = ancestorTransform * aPreviousTransformForRoot.ToUnknownMatrix();
|
||||
Matrix4x4 newCumulativeTransform = ancestorTransform * aCurrentTransformForRoot.ToUnknownMatrix();
|
||||
if (newCumulativeTransform.IsSingular()) {
|
||||
return;
|
||||
}
|
||||
|
@ -697,10 +698,10 @@ AsyncCompositionManager::RecordShadowTransforms(Layer* aLayer)
|
|||
}
|
||||
}
|
||||
|
||||
Matrix4x4
|
||||
AdjustForClip(const Matrix4x4& asyncTransform, Layer* aLayer)
|
||||
static AsyncTransformComponentMatrix
|
||||
AdjustForClip(const AsyncTransformComponentMatrix& asyncTransform, Layer* aLayer)
|
||||
{
|
||||
Matrix4x4 result = asyncTransform;
|
||||
AsyncTransformComponentMatrix result = asyncTransform;
|
||||
|
||||
// Container layers start at the origin, but they are clipped to where they
|
||||
// actually have content on the screen. The tree transform is meant to apply
|
||||
|
@ -801,9 +802,10 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
clipDeferredFromChildren);
|
||||
}
|
||||
|
||||
Matrix4x4 oldTransform = aLayer->GetTransform();
|
||||
LayerToParentLayerMatrix4x4 oldTransform = aLayer->GetTransformTyped() *
|
||||
AsyncTransformMatrix();
|
||||
|
||||
Matrix4x4 combinedAsyncTransform;
|
||||
AsyncTransformComponentMatrix combinedAsyncTransform;
|
||||
bool hasAsyncTransform = false;
|
||||
ScreenMargin fixedLayerMargins;
|
||||
|
||||
|
@ -835,13 +837,14 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
|
||||
hasAsyncTransform = true;
|
||||
|
||||
ViewTransform asyncTransformWithoutOverscroll;
|
||||
AsyncTransform asyncTransformWithoutOverscroll;
|
||||
ParentLayerPoint scrollOffset;
|
||||
controller->SampleContentTransformForFrame(&asyncTransformWithoutOverscroll,
|
||||
scrollOffset);
|
||||
Matrix4x4 overscrollTransform = controller->GetOverscrollTransform();
|
||||
Matrix4x4 asyncTransform =
|
||||
Matrix4x4(asyncTransformWithoutOverscroll) * overscrollTransform;
|
||||
AsyncTransformComponentMatrix overscrollTransform = controller->GetOverscrollTransform();
|
||||
AsyncTransformComponentMatrix asyncTransform =
|
||||
AsyncTransformComponentMatrix(asyncTransformWithoutOverscroll)
|
||||
* overscrollTransform;
|
||||
|
||||
if (!aLayer->IsScrollInfoLayer()) {
|
||||
controller->MarkAsyncTransformAppliedToContent();
|
||||
|
@ -897,8 +900,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
// frame and should not be transformed.
|
||||
if (asyncClip && !metrics.UsesContainerScrolling()) {
|
||||
MOZ_ASSERT(asyncTransform.Is2D());
|
||||
asyncClip = Some(TransformBy(
|
||||
ViewAs<ParentLayerToParentLayerMatrix4x4>(asyncTransform), *asyncClip));
|
||||
asyncClip = Some(TransformBy(asyncTransform, *asyncClip));
|
||||
}
|
||||
aLayer->AsLayerComposite()->SetShadowClipRect(asyncClip);
|
||||
|
||||
|
@ -911,8 +913,10 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
// effects apply to fixed and sticky layers. We do this by using
|
||||
// GetTransform() as the base transform rather than GetLocalTransform(),
|
||||
// which would include those factors.
|
||||
Matrix4x4 transformWithoutOverscrollOrOmta = aLayer->GetTransform() *
|
||||
AdjustForClip(asyncTransformWithoutOverscroll, aLayer);
|
||||
LayerToParentLayerMatrix4x4 transformWithoutOverscrollOrOmta =
|
||||
aLayer->GetTransformTyped()
|
||||
* CompleteAsyncTransform(
|
||||
AdjustForClip(asyncTransformWithoutOverscroll, aLayer));
|
||||
|
||||
// Since fixed/sticky layers are relative to their nearest scrolling ancestor,
|
||||
// we use the ViewID from the bottommost scrollable metrics here.
|
||||
|
@ -946,7 +950,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
// frame, so these are the ones we need to shift by our async transform.
|
||||
for (Layer* ancestorMaskLayer : ancestorMaskLayers) {
|
||||
SetShadowTransform(ancestorMaskLayer,
|
||||
ancestorMaskLayer->GetLocalTransform() * asyncTransform);
|
||||
ancestorMaskLayer->GetLocalTransformTyped() * asyncTransform);
|
||||
}
|
||||
|
||||
// Append the ancestor mask layer for this scroll frame to ancestorMaskLayers.
|
||||
|
@ -968,12 +972,13 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
// shadow transform; in that case we want to apply ours on top of that one
|
||||
// rather than clobber it.
|
||||
SetShadowTransform(aLayer,
|
||||
aLayer->GetLocalTransform() * AdjustForClip(combinedAsyncTransform, aLayer));
|
||||
aLayer->GetLocalTransformTyped()
|
||||
* AdjustForClip(combinedAsyncTransform, aLayer));
|
||||
|
||||
// Do the same for the layer's own mask layer, if it has one.
|
||||
if (Layer* maskLayer = aLayer->GetMaskLayer()) {
|
||||
SetShadowTransform(maskLayer,
|
||||
maskLayer->GetLocalTransform() * combinedAsyncTransform);
|
||||
maskLayer->GetLocalTransformTyped() * combinedAsyncTransform);
|
||||
}
|
||||
|
||||
appliedTransform = true;
|
||||
|
@ -1018,13 +1023,13 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
|
|||
const FrameMetrics& metrics = aContent.Metrics();
|
||||
AsyncPanZoomController* apzc = aContent.GetApzc();
|
||||
|
||||
Matrix4x4 asyncTransform = apzc->GetCurrentAsyncTransform();
|
||||
AsyncTransformComponentMatrix asyncTransform = apzc->GetCurrentAsyncTransform();
|
||||
|
||||
// |asyncTransform| represents the amount by which we have scrolled and
|
||||
// zoomed since the last paint. Because the scrollbar was sized and positioned based
|
||||
// on the painted content, we need to adjust it based on asyncTransform so that
|
||||
// it reflects what the user is actually seeing now.
|
||||
Matrix4x4 scrollbarTransform;
|
||||
AsyncTransformComponentMatrix scrollbarTransform;
|
||||
if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
|
||||
const ParentLayerCoord asyncScrollY = asyncTransform._42;
|
||||
const float asyncZoomY = asyncTransform._22;
|
||||
|
@ -1105,9 +1110,10 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
|
|||
scrollbarTransform.PostTranslate(xTranslation, 0, 0);
|
||||
}
|
||||
|
||||
Matrix4x4 transform = aScrollbar->GetLocalTransform() * scrollbarTransform;
|
||||
LayerToParentLayerMatrix4x4 transform =
|
||||
aScrollbar->GetLocalTransformTyped() * scrollbarTransform;
|
||||
|
||||
Matrix4x4 compensation;
|
||||
AsyncTransformComponentMatrix compensation;
|
||||
// If the scrollbar layer is for the root then the content's resolution
|
||||
// applies to the scrollbar as well. Since we don't actually want the scroll
|
||||
// thumb's size to vary with the zoom (other than its length reflecting the
|
||||
|
@ -1115,9 +1121,10 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
|
|||
// above), we apply a transform to cancel out this resolution.
|
||||
if (metrics.IsRootContent()) {
|
||||
compensation =
|
||||
Matrix4x4::Scaling(metrics.GetPresShellResolution(),
|
||||
metrics.GetPresShellResolution(),
|
||||
1.0f).Inverse();
|
||||
AsyncTransformComponentMatrix::Scaling(
|
||||
metrics.GetPresShellResolution(),
|
||||
metrics.GetPresShellResolution(),
|
||||
1.0f).Inverse();
|
||||
}
|
||||
// If the scrollbar layer is a child of the content it is a scrollbar for,
|
||||
// then we need to adjust for any async transform (including an overscroll
|
||||
|
@ -1131,13 +1138,15 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
|
|||
// the same coordinate space. This requires applying the content transform
|
||||
// and then unapplying it after unapplying the async transform.
|
||||
if (aScrollbarIsDescendant) {
|
||||
Matrix4x4 asyncUntransform = (asyncTransform * apzc->GetOverscrollTransform()).Inverse();
|
||||
Matrix4x4 asyncUntransform = (asyncTransform * apzc->GetOverscrollTransform()).Inverse().ToUnknownMatrix();
|
||||
Matrix4x4 contentTransform = aContent.GetTransform();
|
||||
Matrix4x4 contentUntransform = contentTransform.Inverse();
|
||||
|
||||
Matrix4x4 asyncCompensation = contentTransform
|
||||
* asyncUntransform
|
||||
* contentUntransform;
|
||||
AsyncTransformComponentMatrix asyncCompensation =
|
||||
ViewAs<AsyncTransformComponentMatrix>(
|
||||
contentTransform
|
||||
* asyncUntransform
|
||||
* contentUntransform);
|
||||
|
||||
compensation = compensation * asyncCompensation;
|
||||
|
||||
|
@ -1146,7 +1155,7 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
|
|||
// including the layer with the async transform. Otherwise the scrollbar
|
||||
// shifts but gets clipped and so appears to flicker.
|
||||
for (Layer* ancestor = aScrollbar; ancestor != aContent.GetLayer(); ancestor = ancestor->GetParent()) {
|
||||
TransformClipRect(ancestor, ViewAs<ParentLayerToParentLayerMatrix4x4>(asyncCompensation));
|
||||
TransformClipRect(ancestor, asyncCompensation);
|
||||
}
|
||||
}
|
||||
transform = transform * compensation;
|
||||
|
@ -1235,7 +1244,8 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
|
|||
|
||||
// We must apply the resolution scale before a pan/zoom transform, so we call
|
||||
// GetTransform here.
|
||||
Matrix4x4 oldTransform = aLayer->GetTransform();
|
||||
LayerToParentLayerMatrix4x4 oldTransform = aLayer->GetTransformTyped() *
|
||||
AsyncTransformMatrix();
|
||||
|
||||
CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor();
|
||||
|
||||
|
@ -1294,13 +1304,13 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
|
|||
|
||||
LayerToParentLayerScale asyncZoom = userZoom / metrics.LayersPixelsPerCSSPixel().ToScaleFactor();
|
||||
ParentLayerPoint translation = userRect.TopLeft() - geckoScroll;
|
||||
Matrix4x4 treeTransform = ViewTransform(asyncZoom, -translation);
|
||||
AsyncTransformComponentMatrix treeTransform = AsyncTransform(asyncZoom, -translation);
|
||||
|
||||
// Apply the tree transform on top of GetLocalTransform() here (rather than
|
||||
// GetTransform()) in case the OMTA code in SampleAnimations already set a
|
||||
// shadow transform; in that case we want to apply ours on top of that one
|
||||
// rather than clobber it.
|
||||
SetShadowTransform(aLayer, aLayer->GetLocalTransform() * treeTransform);
|
||||
SetShadowTransform(aLayer, aLayer->GetLocalTransformTyped() * treeTransform);
|
||||
|
||||
// Make sure that overscroll and under-zoom are represented in the old
|
||||
// transform so that fixed position content moves and scales accordingly.
|
||||
|
@ -1337,8 +1347,8 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
|
|||
// Make sure fixed position layers don't move away from their anchor points
|
||||
// when we're asynchronously panning or zooming
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform,
|
||||
aLayer->GetLocalTransform(), fixedLayerMargins,
|
||||
false);
|
||||
aLayer->GetLocalTransformTyped(),
|
||||
fixedLayerMargins, false);
|
||||
|
||||
ExpandRootClipRect(aLayer, fixedLayerMargins);
|
||||
}
|
||||
|
|
|
@ -28,32 +28,25 @@ class LayerManagerComposite;
|
|||
class AutoResolveRefLayers;
|
||||
class CompositorParent;
|
||||
|
||||
// Represents (affine) transforms that are calculated from a content view.
|
||||
struct ViewTransform {
|
||||
explicit ViewTransform(LayerToParentLayerScale aScale = LayerToParentLayerScale(),
|
||||
ParentLayerPoint aTranslation = ParentLayerPoint())
|
||||
// Represents async transforms consisting of a scale and a translation.
|
||||
struct AsyncTransform {
|
||||
explicit AsyncTransform(LayerToParentLayerScale aScale = LayerToParentLayerScale(),
|
||||
ParentLayerPoint aTranslation = ParentLayerPoint())
|
||||
: mScale(aScale)
|
||||
, mTranslation(aTranslation)
|
||||
{}
|
||||
|
||||
operator gfx::Matrix4x4() const
|
||||
operator AsyncTransformComponentMatrix() const
|
||||
{
|
||||
return
|
||||
gfx::Matrix4x4::Scaling(mScale.scale, mScale.scale, 1)
|
||||
.PostTranslate(mTranslation.x, mTranslation.y, 0);
|
||||
return AsyncTransformComponentMatrix::Scaling(mScale.scale, mScale.scale, 1)
|
||||
.PostTranslate(mTranslation.x, mTranslation.y, 0);
|
||||
}
|
||||
|
||||
// For convenience, to avoid writing the cumbersome
|
||||
// "gfx::Matrix4x4(a) * gfx::Matrix4x4(b)".
|
||||
friend gfx::Matrix4x4 operator*(const ViewTransform& a, const ViewTransform& b) {
|
||||
return gfx::Matrix4x4(a) * gfx::Matrix4x4(b);
|
||||
}
|
||||
|
||||
bool operator==(const ViewTransform& rhs) const {
|
||||
bool operator==(const AsyncTransform& rhs) const {
|
||||
return mTranslation == rhs.mTranslation && mScale == rhs.mScale;
|
||||
}
|
||||
|
||||
bool operator!=(const ViewTransform& rhs) const {
|
||||
bool operator!=(const AsyncTransform& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
|
@ -184,8 +177,8 @@ private:
|
|||
*/
|
||||
void AlignFixedAndStickyLayers(Layer* aLayer, Layer* aTransformedSubtreeRoot,
|
||||
FrameMetrics::ViewID aTransformScrollId,
|
||||
const gfx::Matrix4x4& aPreviousTransformForRoot,
|
||||
const gfx::Matrix4x4& aCurrentTransformForRoot,
|
||||
const LayerToParentLayerMatrix4x4& aPreviousTransformForRoot,
|
||||
const LayerToParentLayerMatrix4x4& aCurrentTransformForRoot,
|
||||
const ScreenMargin& aFixedLayerMargins,
|
||||
bool aTransformAffectsLayerClip);
|
||||
|
||||
|
|
|
@ -454,7 +454,7 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager,
|
|||
return;
|
||||
}
|
||||
|
||||
ViewTransform asyncTransformWithoutOverscroll;
|
||||
AsyncTransform asyncTransformWithoutOverscroll;
|
||||
ParentLayerPoint scrollOffset;
|
||||
controller->SampleContentTransformForFrame(&asyncTransformWithoutOverscroll,
|
||||
scrollOffset);
|
||||
|
@ -603,7 +603,7 @@ RenderLayers(ContainerT* aContainer,
|
|||
gfx::Rect(aClipRect.ToUnknownRect()),
|
||||
asyncTransform * aContainer->GetEffectiveTransform());
|
||||
if (AsyncPanZoomController* apzc = layer->GetAsyncPanZoomController(i - 1)) {
|
||||
asyncTransform = apzc->GetCurrentAsyncTransformWithOverscroll()
|
||||
asyncTransform = apzc->GetCurrentAsyncTransformWithOverscroll().ToUnknownMatrix()
|
||||
* asyncTransform;
|
||||
}
|
||||
}
|
||||
|
@ -753,7 +753,7 @@ ContainerRender(ContainerT* aContainer,
|
|||
for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
|
||||
if (AsyncPanZoomController* apzc = i.GetApzc()) {
|
||||
if (!apzc->GetAsyncTransformAppliedToContent()
|
||||
&& !Matrix4x4(apzc->GetCurrentAsyncTransform()).IsIdentity()) {
|
||||
&& !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform()).IsIdentity()) {
|
||||
aManager->UnusedApzTransformWarning();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -703,6 +703,7 @@ PrepareFontOptions(FcPattern* aPattern,
|
|||
// subpixel_order won't be used by the font as we won't use
|
||||
// CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
|
||||
// caching reasons described above. Fall through:
|
||||
MOZ_FALLTHROUGH;
|
||||
case FC_RGBA_RGB:
|
||||
subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
|
||||
break;
|
||||
|
|
|
@ -2180,6 +2180,7 @@ CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace)
|
|||
// subpixel_order won't be used by the font as we won't use
|
||||
// CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
|
||||
// caching reasons described above. Fall through:
|
||||
MOZ_FALLTHROUGH;
|
||||
case FC_RGBA_RGB:
|
||||
subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
|
||||
break;
|
||||
|
|
|
@ -710,6 +710,18 @@ nsBMPDecoder::ReadColorTable(const char* aData, size_t aLength)
|
|||
LexerTransition<nsBMPDecoder::State>
|
||||
nsBMPDecoder::SkipGap()
|
||||
{
|
||||
// If there are no pixels we can stop.
|
||||
//
|
||||
// XXX: normally, if there are no pixels we will have stopped decoding before
|
||||
// now, outside of this decoder. However, if the BMP is within an ICO file,
|
||||
// it's possible that the ICO claimed the image had a non-zero size while the
|
||||
// BMP claims otherwise. This test is to catch that awkward case. If we ever
|
||||
// come up with a more general solution to this ICO-and-BMP-disagree-on-size
|
||||
// problem, this test can be removed.
|
||||
if (mH.mWidth == 0 || mH.mHeight == 0) {
|
||||
return Transition::TerminateSuccess();
|
||||
}
|
||||
|
||||
bool hasRLE = mH.mCompression == Compression::RLE8 ||
|
||||
mH.mCompression == Compression::RLE4;
|
||||
return hasRLE
|
||||
|
@ -720,6 +732,7 @@ nsBMPDecoder::SkipGap()
|
|||
LexerTransition<nsBMPDecoder::State>
|
||||
nsBMPDecoder::ReadPixelRow(const char* aData)
|
||||
{
|
||||
MOZ_ASSERT(mCurrentRow > 0);
|
||||
MOZ_ASSERT(mCurrentPos == 0);
|
||||
|
||||
const uint8_t* src = reinterpret_cast<const uint8_t*>(aData);
|
||||
|
|
|
@ -304,33 +304,18 @@ template <typename T>
|
|||
extern JS_PUBLIC_API(void)
|
||||
TraceNullableEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
TraceNullableEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* edgep, const char* name);
|
||||
|
||||
// Edges that are always traced as part of root marking do not require
|
||||
// incremental barriers. This function allows for marking non-barriered
|
||||
// pointers, but asserts that this happens during root marking.
|
||||
template <typename T>
|
||||
extern JS_PUBLIC_API(void)
|
||||
UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
// The following JS_CallUnbarriered*Tracer functions should only be called where
|
||||
// you know for sure that a heap post barrier is not required. Use with extreme
|
||||
// caution!
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredValueTracer(JSTracer* trc, JS::Value* valuep, const char* name);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredIdTracer(JSTracer* trc, jsid* idp, const char* name);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, const char* name);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredStringTracer(JSTracer* trc, JSString** strp, const char* name);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredScriptTracer(JSTracer* trc, JSScript** scriptp, const char* name);
|
||||
|
||||
/**
|
||||
* Trace an object that is known to always be tenured. No post barriers are
|
||||
* required in this case.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, const char* name);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_TraceRuntime(JSTracer* trc);
|
||||
|
||||
|
@ -353,6 +338,10 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
|
|||
void* thing, JS::TraceKind kind, bool includeDetails);
|
||||
|
||||
namespace js {
|
||||
template <typename T>
|
||||
extern JS_PUBLIC_API(void)
|
||||
UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name);
|
||||
|
||||
namespace gc {
|
||||
template <typename T>
|
||||
extern JS_PUBLIC_API(bool)
|
||||
|
@ -396,8 +385,8 @@ struct DefaultGCPolicy : public StructGCPolicy<T> {};
|
|||
template <>
|
||||
struct DefaultGCPolicy<jsid>
|
||||
{
|
||||
static void trace(JSTracer* trc, jsid* id, const char* name) {
|
||||
JS_CallUnbarrieredIdTracer(trc, id, name);
|
||||
static void trace(JSTracer* trc, jsid* idp, const char* name) {
|
||||
js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -460,6 +460,14 @@ namespace JS {
|
|||
template<typename T>
|
||||
struct DeletePolicy
|
||||
{
|
||||
MOZ_CONSTEXPR DeletePolicy() {}
|
||||
|
||||
template<typename U>
|
||||
MOZ_IMPLICIT DeletePolicy(DeletePolicy<U> other,
|
||||
typename mozilla::EnableIf<mozilla::IsConvertible<U*, T*>::value,
|
||||
int>::Type dummy = 0)
|
||||
{}
|
||||
|
||||
void operator()(const T* ptr) {
|
||||
js_delete(const_cast<T*>(ptr));
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -19,11 +19,10 @@
|
|||
#ifndef asmjs_asmjs_h
|
||||
#define asmjs_asmjs_h
|
||||
|
||||
#include "vm/NativeObject.h"
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class AsmJSModule;
|
||||
class ExclusiveContext;
|
||||
namespace frontend {
|
||||
template <typename ParseHandler> class Parser;
|
||||
|
@ -34,29 +33,6 @@ namespace frontend {
|
|||
typedef frontend::Parser<frontend::FullParseHandler> AsmJSParser;
|
||||
typedef frontend::ParseContext<frontend::FullParseHandler> AsmJSParseContext;
|
||||
|
||||
// An AsmJSModuleObject is an internal implementation object (i.e., not exposed
|
||||
// directly to user script) which traces and owns an AsmJSModule. The
|
||||
// AsmJSModuleObject is referenced by the extended slots of the content-visible
|
||||
// module and export JSFunctions.
|
||||
|
||||
class AsmJSModuleObject : public NativeObject
|
||||
{
|
||||
static const unsigned MODULE_SLOT = 0;
|
||||
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 1;
|
||||
|
||||
bool hasModule() const;
|
||||
void setModule(AsmJSModule* module);
|
||||
AsmJSModule& module() const;
|
||||
|
||||
void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
|
||||
|
||||
static const Class class_;
|
||||
};
|
||||
|
||||
typedef Handle<AsmJSModuleObject*> HandleAsmJSModule;
|
||||
|
||||
// This function takes over parsing of a function starting with "use asm". The
|
||||
// return value indicates whether an error was reported which the caller should
|
||||
// propagate. If no error was reported, the function may still fail to validate
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef wasm_ir_h
|
||||
#define wasm_ir_h
|
||||
#ifndef wasm_binary_h
|
||||
#define wasm_binary_h
|
||||
|
||||
#include "asmjs/WasmTypes.h"
|
||||
|
||||
|
@ -422,102 +422,49 @@ enum NeedsBoundsCheck : uint8_t
|
|||
NEEDS_BOUNDS_CHECK
|
||||
};
|
||||
|
||||
// The FuncIR class contains the intermediate representation of a parsed/decoded
|
||||
// and validated asm.js/WebAssembly function. The FuncIR lives only until it
|
||||
// is fully compiled. Its contents are assumed to be well-formed; all validation
|
||||
// of untrusted content must happen before FuncIR generation. A FuncIR object is
|
||||
// associated with a LifoAlloc allocation which contains all the memory
|
||||
// referenced by the FuncIR.
|
||||
class FuncIR
|
||||
typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytecode;
|
||||
typedef UniquePtr<Bytecode, JS::DeletePolicy<Bytecode>> UniqueBytecode;
|
||||
|
||||
// The Encoder class recycles (through its constructor) or creates a new Bytecode (through its
|
||||
// init() method). Its Bytecode is released when it's done building the wasm IR in finish().
|
||||
class Encoder
|
||||
{
|
||||
typedef Vector<ValType, 4, LifoAllocPolicy<Fallible>> ValTypeVector;
|
||||
UniqueBytecode bytecode_;
|
||||
mozilla::DebugOnly<bool> done_;
|
||||
|
||||
public:
|
||||
// Source coordinates for a call site. As they're read sequentially, we
|
||||
// don't need to store the call's bytecode offset, unless we want to
|
||||
// check its consistency in debug mode.
|
||||
struct SourceCoords {
|
||||
DebugOnly<uint32_t> offset; // after call opcode
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
};
|
||||
|
||||
private:
|
||||
typedef Vector<uint8_t, 4096, LifoAllocPolicy<Fallible>> Bytecode;
|
||||
typedef Vector<SourceCoords, 4, LifoAllocPolicy<Fallible>> SourceCoordsVector;
|
||||
|
||||
// Note: this unrooted field assumes AutoKeepAtoms via TokenStream via
|
||||
// asm.js compilation.
|
||||
PropertyName* name_;
|
||||
unsigned line_;
|
||||
unsigned column_;
|
||||
SourceCoordsVector callSourceCoords_;
|
||||
|
||||
uint32_t index_;
|
||||
const LifoSig* sig_;
|
||||
ValTypeVector localVars_;
|
||||
Bytecode bytecode_;
|
||||
unsigned generateTime_;
|
||||
|
||||
public:
|
||||
FuncIR(LifoAlloc& alloc, PropertyName* name, unsigned line, unsigned column)
|
||||
: name_(name),
|
||||
line_(line),
|
||||
column_(column),
|
||||
callSourceCoords_(alloc),
|
||||
index_(UINT_MAX),
|
||||
sig_(nullptr),
|
||||
localVars_(alloc),
|
||||
bytecode_(alloc),
|
||||
generateTime_(UINT_MAX)
|
||||
{}
|
||||
|
||||
bool addVariable(ValType v) {
|
||||
return localVars_.append(v);
|
||||
}
|
||||
bool addSourceCoords(uint32_t line, uint32_t column) {
|
||||
SourceCoords sc = { bytecode_.length(), line, column };
|
||||
return callSourceCoords_.append(sc);
|
||||
}
|
||||
void finish(uint32_t funcIndex, const LifoSig& sig, unsigned generateTime) {
|
||||
MOZ_ASSERT(index_ == UINT_MAX);
|
||||
MOZ_ASSERT(!sig_);
|
||||
MOZ_ASSERT(generateTime_ == UINT_MAX);
|
||||
index_ = funcIndex;
|
||||
sig_ = &sig;
|
||||
generateTime_ = generateTime;
|
||||
}
|
||||
|
||||
private:
|
||||
template<class T>
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool write(T v, size_t* offset) {
|
||||
if (offset)
|
||||
*offset = bytecode_.length();
|
||||
return bytecode_.append(reinterpret_cast<uint8_t*>(&v), sizeof(T));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool read(size_t* pc, T* out) const {
|
||||
if (size_t(bytecode_.length() - *pc) >= sizeof(T))
|
||||
return false;
|
||||
memcpy((void*)out, &bytecode_[*pc], sizeof(T));
|
||||
*pc += sizeof(T);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T uncheckedRead(size_t* pc) const {
|
||||
MOZ_ASSERT(size_t(bytecode_.length() - *pc) >= sizeof(T));
|
||||
T ret;
|
||||
memcpy(&ret, &bytecode_[*pc], sizeof(T));
|
||||
*pc += sizeof(T);
|
||||
return ret;
|
||||
*offset = bytecode_->length();
|
||||
return bytecode_->append(reinterpret_cast<uint8_t*>(&v), sizeof(T));
|
||||
}
|
||||
|
||||
public:
|
||||
// Packing interface
|
||||
Encoder()
|
||||
: bytecode_(nullptr),
|
||||
done_(false)
|
||||
{}
|
||||
|
||||
bool init(UniqueBytecode bytecode) {
|
||||
if (bytecode) {
|
||||
bytecode_ = mozilla::Move(bytecode);
|
||||
bytecode_->clear();
|
||||
return true;
|
||||
}
|
||||
bytecode_.reset(js_new<Bytecode>());
|
||||
return !!bytecode_;
|
||||
}
|
||||
|
||||
size_t bytecodeOffset() const { return bytecode_->length(); }
|
||||
bool empty() const { return bytecodeOffset() == 0; }
|
||||
|
||||
UniqueBytecode finish() {
|
||||
MOZ_ASSERT(!done_);
|
||||
done_ = true;
|
||||
return mozilla::Move(bytecode_);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
writeU8(uint8_t i, size_t* offset = nullptr) { return write<uint8_t>(i, offset); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
|
@ -554,14 +501,14 @@ class FuncIR
|
|||
bool pcIsPatchable(size_t pc, unsigned size) const {
|
||||
bool patchable = true;
|
||||
for (unsigned i = 0; patchable && i < size; i++)
|
||||
patchable &= Stmt(bytecode_[pc]) == Stmt::Bad;
|
||||
patchable &= Stmt((*bytecode_)[pc]) == Stmt::Bad;
|
||||
return patchable;
|
||||
}
|
||||
#endif
|
||||
|
||||
void patchU8(size_t pc, uint8_t i) {
|
||||
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint8_t)));
|
||||
bytecode_[pc] = i;
|
||||
(*bytecode_)[pc] = i;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
@ -569,44 +516,72 @@ class FuncIR
|
|||
static_assert(sizeof(T) == sizeof(uint32_t),
|
||||
"patch32 must be used with 32-bits wide types");
|
||||
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint32_t)));
|
||||
memcpy(&bytecode_[pc], &i, sizeof(uint32_t));
|
||||
memcpy(&(*bytecode_)[pc], &i, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void patchSig(size_t pc, const LifoSig* ptr) {
|
||||
MOZ_ASSERT(pcIsPatchable(pc, sizeof(LifoSig*)));
|
||||
memcpy(&bytecode_[pc], &ptr, sizeof(LifoSig*));
|
||||
memcpy(&(*bytecode_)[pc], &ptr, sizeof(LifoSig*));
|
||||
}
|
||||
};
|
||||
|
||||
class Decoder
|
||||
{
|
||||
const Bytecode& bytecode_;
|
||||
size_t cur_;
|
||||
|
||||
template<class T>
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool read(T* out) {
|
||||
if (uintptr_t(bytecode_.length() - cur_) < sizeof(T))
|
||||
return false;
|
||||
memcpy((void*)out, &bytecode_[cur_], sizeof(T));
|
||||
cur_ += sizeof(T);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T uncheckedRead() {
|
||||
MOZ_ASSERT(uintptr_t(bytecode_.length() - cur_) >= sizeof(T));
|
||||
T ret;
|
||||
memcpy(&ret, &bytecode_[cur_], sizeof(T));
|
||||
cur_ += sizeof(T);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Decoder(const Bytecode& bytecode)
|
||||
: bytecode_(bytecode),
|
||||
cur_(0)
|
||||
{}
|
||||
|
||||
bool done() const { return cur_ == bytecode_.length(); }
|
||||
void assertCurrentIs(const DebugOnly<size_t> offset) const {
|
||||
MOZ_ASSERT(offset == cur_);
|
||||
}
|
||||
|
||||
// The fallible unpacking API should be used when we're not assuming
|
||||
// anything about the bytecode, in particular if it is well-formed.
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readU8 (size_t* pc, uint8_t* i) const { return read(pc, i); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readI32(size_t* pc, int32_t* i) const { return read(pc, i); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readF32(size_t* pc, float* f) const { return read(pc, f); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readU32(size_t* pc, uint32_t* u) const { return read(pc, u); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readF64(size_t* pc, double* d) const { return read(pc, d); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readSig(size_t* pc, const LifoSig* sig) const { return read(pc, sig); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readU8 (uint8_t* i) { return read(i); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readI32(int32_t* i) { return read(i); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readF32(float* f) { return read(f); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readU32(uint32_t* u) { return read(u); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readF64(double* d) { return read(d); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readSig(const LifoSig* sig) { return read(sig); }
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readI32X4(size_t* pc, jit::SimdConstant* c) const {
|
||||
MOZ_WARN_UNUSED_RESULT bool readI32X4(jit::SimdConstant* c) {
|
||||
int32_t v[4] = { 0, 0, 0, 0 };
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
if (!readI32(pc, &v[i]))
|
||||
if (!readI32(&v[i]))
|
||||
return false;
|
||||
}
|
||||
*c = jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
|
||||
return true;
|
||||
}
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readF32X4(size_t* pc, jit::SimdConstant* c) const {
|
||||
MOZ_WARN_UNUSED_RESULT bool readF32X4(jit::SimdConstant* c) {
|
||||
float v[4] = { 0., 0., 0., 0. };
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
if (!readF32(pc, &v[i]))
|
||||
if (!readF32(&v[i]))
|
||||
return false;
|
||||
}
|
||||
*c = jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
|
||||
|
@ -615,45 +590,100 @@ class FuncIR
|
|||
|
||||
// The unfallible unpacking API should be used when we are sure that the
|
||||
// bytecode is well-formed.
|
||||
uint8_t uncheckedReadU8 (size_t* pc) const { return uncheckedRead<uint8_t>(pc); }
|
||||
int32_t uncheckedReadI32(size_t* pc) const { return uncheckedRead<int32_t>(pc); }
|
||||
float uncheckedReadF32(size_t* pc) const { return uncheckedRead<float>(pc); }
|
||||
uint32_t uncheckedReadU32(size_t* pc) const { return uncheckedRead<uint32_t>(pc); }
|
||||
double uncheckedReadF64(size_t* pc) const { return uncheckedRead<double>(pc); }
|
||||
const LifoSig* uncheckedReadSig(size_t* pc) const { return uncheckedRead<const LifoSig*>(pc); }
|
||||
uint8_t uncheckedReadU8 () { return uncheckedRead<uint8_t>(); }
|
||||
int32_t uncheckedReadI32() { return uncheckedRead<int32_t>(); }
|
||||
float uncheckedReadF32() { return uncheckedRead<float>(); }
|
||||
uint32_t uncheckedReadU32() { return uncheckedRead<uint32_t>(); }
|
||||
double uncheckedReadF64() { return uncheckedRead<double>(); }
|
||||
const LifoSig* uncheckedReadSig() { return uncheckedRead<const LifoSig*>(); }
|
||||
|
||||
jit::SimdConstant uncheckedReadI32X4(size_t* pc) const {
|
||||
jit::SimdConstant uncheckedReadI32X4() {
|
||||
int32_t v[4] = { 0, 0, 0, 0 };
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
v[i] = uncheckedReadI32(pc);
|
||||
v[i] = uncheckedReadI32();
|
||||
return jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
jit::SimdConstant uncheckedReadF32X4(size_t* pc) const {
|
||||
jit::SimdConstant uncheckedReadF32X4() {
|
||||
float v[4] = { 0., 0., 0., 0. };
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
v[i] = uncheckedReadF32(pc);
|
||||
v[i] = uncheckedReadF32();
|
||||
return jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
};
|
||||
|
||||
// Source coordinates for a call site. As they're read sequentially, we
|
||||
// don't need to store the call's bytecode offset, unless we want to
|
||||
// check its correctness in debug mode.
|
||||
struct SourceCoords {
|
||||
DebugOnly<size_t> offset; // after call opcode
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
};
|
||||
|
||||
typedef Vector<SourceCoords, 0, SystemAllocPolicy> SourceCoordsVector;
|
||||
typedef Vector<ValType, 0, SystemAllocPolicy> ValTypeVector;
|
||||
|
||||
// The FuncBytecode class contains the intermediate representation of a
|
||||
// parsed/decoded and validated asm.js/WebAssembly function. The FuncBytecode
|
||||
// lives only until it is fully compiled.
|
||||
class FuncBytecode
|
||||
{
|
||||
// Note: this unrooted field assumes AutoKeepAtoms via TokenStream via
|
||||
// asm.js compilation.
|
||||
PropertyName* name_;
|
||||
unsigned line_;
|
||||
unsigned column_;
|
||||
|
||||
SourceCoordsVector callSourceCoords_;
|
||||
|
||||
uint32_t index_;
|
||||
const LifoSig& sig_;
|
||||
UniqueBytecode bytecode_;
|
||||
ValTypeVector localVars_;
|
||||
unsigned generateTime_;
|
||||
|
||||
public:
|
||||
FuncBytecode(PropertyName* name,
|
||||
unsigned line,
|
||||
unsigned column,
|
||||
SourceCoordsVector&& sourceCoords,
|
||||
uint32_t index,
|
||||
const LifoSig& sig,
|
||||
UniqueBytecode bytecode,
|
||||
ValTypeVector&& localVars,
|
||||
unsigned generateTime)
|
||||
: name_(name),
|
||||
line_(line),
|
||||
column_(column),
|
||||
callSourceCoords_(mozilla::Move(sourceCoords)),
|
||||
index_(index),
|
||||
sig_(sig),
|
||||
bytecode_(mozilla::Move(bytecode)),
|
||||
localVars_(mozilla::Move(localVars)),
|
||||
generateTime_(generateTime)
|
||||
{}
|
||||
|
||||
UniqueBytecode recycleBytecode() { return mozilla::Move(bytecode_); }
|
||||
|
||||
// Read-only interface
|
||||
PropertyName* name() const { return name_; }
|
||||
unsigned line() const { return line_; }
|
||||
unsigned column() const { return column_; }
|
||||
const SourceCoords& sourceCoords(size_t i) const { return callSourceCoords_[i]; }
|
||||
|
||||
uint32_t index() const { MOZ_ASSERT(index_ != UINT32_MAX); return index_; }
|
||||
const LifoSig& sig() const { MOZ_ASSERT(sig_); return *sig_; }
|
||||
uint32_t index() const { return index_; }
|
||||
const LifoSig& sig() const { return sig_; }
|
||||
const Bytecode& bytecode() const { return *bytecode_; }
|
||||
|
||||
size_t numLocalVars() const { return localVars_.length(); }
|
||||
ValType localVarType(size_t i) const { return localVars_[i]; }
|
||||
size_t numLocals() const { return sig_->args().length() + numLocalVars(); }
|
||||
size_t numLocals() const { return sig_.args().length() + numLocalVars(); }
|
||||
|
||||
unsigned generateTime() const { MOZ_ASSERT(generateTime_ != UINT_MAX); return generateTime_; }
|
||||
|
||||
size_t size() const { return bytecode_.length(); }
|
||||
unsigned generateTime() const { return generateTime_; }
|
||||
};
|
||||
|
||||
typedef mozilla::UniquePtr<FuncBytecode, JS::DeletePolicy<FuncBytecode>> UniqueFuncBytecode;
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
||||
#endif // wasm_ir_h
|
||||
#endif // wasm_binary_h
|
|
@ -35,20 +35,18 @@ static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|||
|
||||
ModuleGenerator::ModuleGenerator(ExclusiveContext* cx)
|
||||
: cx_(cx),
|
||||
args_(cx),
|
||||
globalBytes_(InitialGlobalDataBytes),
|
||||
slowFuncs_(cx),
|
||||
lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
|
||||
jcx_(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread())),
|
||||
alloc_(&lifo_),
|
||||
masm_(MacroAssembler::AsmJSToken(), alloc_),
|
||||
sigs_(cx),
|
||||
funcEntryOffsets_(cx),
|
||||
exportFuncIndices_(cx),
|
||||
parallel_(false),
|
||||
outstanding_(0),
|
||||
tasks_(cx),
|
||||
freeTasks_(cx),
|
||||
funcBytes_(0),
|
||||
funcEntryOffsets_(cx),
|
||||
activeFunc_(nullptr),
|
||||
finishedFuncs_(false)
|
||||
{
|
||||
|
@ -108,8 +106,15 @@ ParallelCompilationEnabled(ExclusiveContext* cx)
|
|||
bool
|
||||
ModuleGenerator::init()
|
||||
{
|
||||
staticLinkData_ = cx_->make_unique<StaticLinkData>();
|
||||
if (!staticLinkData_)
|
||||
module_ = cx_->make_unique<ModuleData>();
|
||||
if (!module_)
|
||||
return false;
|
||||
|
||||
module_->globalBytes = InitialGlobalDataBytes;
|
||||
module_->compileArgs = CompileArgs(cx_);
|
||||
|
||||
link_ = cx_->make_unique<StaticLinkData>();
|
||||
if (!link_)
|
||||
return false;
|
||||
|
||||
if (!sigs_.init())
|
||||
|
@ -138,7 +143,7 @@ ModuleGenerator::init()
|
|||
return false;
|
||||
JSRuntime* runtime = cx_->compartment()->runtimeFromAnyThread();
|
||||
for (size_t i = 0; i < numTasks; i++)
|
||||
tasks_.infallibleEmplaceBack(runtime, args_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
|
||||
tasks_.infallibleEmplaceBack(runtime, args(), COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
|
||||
|
||||
if (!freeTasks_.reserve(numTasks))
|
||||
return false;
|
||||
|
@ -151,13 +156,17 @@ ModuleGenerator::init()
|
|||
bool
|
||||
ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset)
|
||||
{
|
||||
uint32_t pad = ComputeByteAlignment(globalBytes_, align);
|
||||
if (UINT32_MAX - globalBytes_ < pad + bytes)
|
||||
uint32_t globalBytes = module_->globalBytes;
|
||||
|
||||
uint32_t pad = ComputeByteAlignment(globalBytes, align);
|
||||
if (UINT32_MAX - globalBytes < pad + bytes)
|
||||
return false;
|
||||
|
||||
globalBytes_ += pad;
|
||||
*globalDataOffset = globalBytes_;
|
||||
globalBytes_ += bytes;
|
||||
globalBytes += pad;
|
||||
*globalDataOffset = globalBytes;
|
||||
globalBytes += bytes;
|
||||
|
||||
module_->globalBytes = globalBytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -191,7 +200,7 @@ ModuleGenerator::finishOutstandingTask()
|
|||
bool
|
||||
ModuleGenerator::finishTask(IonCompileTask* task)
|
||||
{
|
||||
const FuncIR& func = task->func();
|
||||
const FuncBytecode& func = task->func();
|
||||
FuncCompileResults& results = task->results();
|
||||
|
||||
// Offset the recorded FuncOffsets by the offset of the function in the
|
||||
|
@ -216,10 +225,10 @@ ModuleGenerator::finishTask(IonCompileTask* task)
|
|||
CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func.name());
|
||||
if (!funcName)
|
||||
return false;
|
||||
uint32_t nameIndex = funcNames_.length();
|
||||
if (!funcNames_.emplaceBack(Move(funcName)))
|
||||
uint32_t nameIndex = module_->funcNames.length();
|
||||
if (!module_->funcNames.emplaceBack(Move(funcName)))
|
||||
return false;
|
||||
if (!codeRanges_.emplaceBack(nameIndex, func.line(), results.offsets()))
|
||||
if (!module_->codeRanges.emplaceBack(nameIndex, func.line(), results.offsets()))
|
||||
return false;
|
||||
|
||||
// Keep a record of slow functions for printing in the final console message.
|
||||
|
@ -229,7 +238,6 @@ ModuleGenerator::finishTask(IonCompileTask* task)
|
|||
return false;
|
||||
}
|
||||
|
||||
task->reset();
|
||||
freeTasks_.infallibleAppend(task);
|
||||
return true;
|
||||
}
|
||||
|
@ -279,72 +287,73 @@ ModuleGenerator::declareImport(MallocSig&& sig, unsigned* index)
|
|||
if (!allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
|
||||
return false;
|
||||
|
||||
*index = unsigned(imports_.length());
|
||||
return imports_.emplaceBack(Move(sig), globalDataOffset);
|
||||
*index = unsigned(module_->imports.length());
|
||||
return module_->imports.emplaceBack(Move(sig), globalDataOffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ModuleGenerator::numDeclaredImports() const
|
||||
{
|
||||
return imports_.length();
|
||||
return module_->imports.length();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ModuleGenerator::importExitGlobalDataOffset(uint32_t index) const
|
||||
{
|
||||
return imports_[index].exitGlobalDataOffset();
|
||||
return module_->imports[index].exitGlobalDataOffset();
|
||||
}
|
||||
|
||||
const MallocSig&
|
||||
ModuleGenerator::importSig(uint32_t index) const
|
||||
{
|
||||
return imports_[index].sig();
|
||||
return module_->imports[index].sig();
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit)
|
||||
{
|
||||
Import& import = imports_[index];
|
||||
Import& import = module_->imports[index];
|
||||
import.initInterpExitOffset(interpExit.begin);
|
||||
import.initJitExitOffset(jitExit.begin);
|
||||
return codeRanges_.emplaceBack(CodeRange::ImportInterpExit, interpExit) &&
|
||||
codeRanges_.emplaceBack(CodeRange::ImportJitExit, jitExit);
|
||||
return module_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExit) &&
|
||||
module_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExit);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::declareExport(MallocSig&& sig, uint32_t funcIndex)
|
||||
{
|
||||
return exports_.emplaceBack(Move(sig), funcIndex);
|
||||
return module_->exports.emplaceBack(Move(sig)) &&
|
||||
exportFuncIndices_.append(funcIndex);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ModuleGenerator::exportFuncIndex(uint32_t index) const
|
||||
{
|
||||
return exports_[index].funcIndex();
|
||||
return exportFuncIndices_[index];
|
||||
}
|
||||
|
||||
const MallocSig&
|
||||
ModuleGenerator::exportSig(uint32_t index) const
|
||||
{
|
||||
return exports_[index].sig();
|
||||
return module_->exports[index].sig();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ModuleGenerator::numDeclaredExports() const
|
||||
{
|
||||
return exports_.length();
|
||||
return module_->exports.length();
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::defineExport(uint32_t index, Offsets offsets)
|
||||
{
|
||||
exports_[index].initStubOffset(offsets.begin);
|
||||
return codeRanges_.emplaceBack(CodeRange::Entry, offsets);
|
||||
module_->exports[index].initStubOffset(offsets.begin);
|
||||
return module_->codeRanges.emplaceBack(CodeRange::Entry, offsets);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::startFunc(PropertyName* name, unsigned line, unsigned column,
|
||||
FunctionGenerator* fg)
|
||||
UniqueBytecode* recycled, FunctionGenerator* fg)
|
||||
{
|
||||
MOZ_ASSERT(!activeFunc_);
|
||||
MOZ_ASSERT(!finishedFuncs_);
|
||||
|
@ -353,25 +362,38 @@ ModuleGenerator::startFunc(PropertyName* name, unsigned line, unsigned column,
|
|||
return false;
|
||||
|
||||
IonCompileTask* task = freeTasks_.popCopy();
|
||||
FuncIR* func = task->lifo().new_<FuncIR>(task->lifo(), name, line, column);
|
||||
if (!func)
|
||||
return false;
|
||||
|
||||
task->init(*func);
|
||||
task->reset(recycled);
|
||||
|
||||
fg->name_= name;
|
||||
fg->line_ = line;
|
||||
fg->column_ = column;
|
||||
fg->m_ = this;
|
||||
fg->task_ = task;
|
||||
fg->func_ = func;
|
||||
activeFunc_ = fg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishFunc(uint32_t funcIndex, const LifoSig& sig, unsigned generateTime,
|
||||
FunctionGenerator* fg)
|
||||
ModuleGenerator::finishFunc(uint32_t funcIndex, const LifoSig& sig, UniqueBytecode bytecode,
|
||||
unsigned generateTime, FunctionGenerator* fg)
|
||||
{
|
||||
MOZ_ASSERT(activeFunc_ == fg);
|
||||
|
||||
fg->func_->finish(funcIndex, sig, generateTime);
|
||||
UniqueFuncBytecode func = cx_->make_unique<FuncBytecode>(fg->name_,
|
||||
fg->line_,
|
||||
fg->column_,
|
||||
Move(fg->callSourceCoords_),
|
||||
funcIndex,
|
||||
sig,
|
||||
Move(bytecode),
|
||||
Move(fg->localVars_),
|
||||
generateTime
|
||||
);
|
||||
if (!func)
|
||||
return false;
|
||||
|
||||
fg->task_->init(Move(func));
|
||||
|
||||
if (parallel_) {
|
||||
if (!StartOffThreadWasmCompile(cx_, fg->task_))
|
||||
|
@ -386,7 +408,6 @@ ModuleGenerator::finishFunc(uint32_t funcIndex, const LifoSig& sig, unsigned gen
|
|||
|
||||
fg->m_ = nullptr;
|
||||
fg->task_ = nullptr;
|
||||
fg->func_ = nullptr;
|
||||
activeFunc_ = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
@ -417,7 +438,7 @@ ModuleGenerator::finishFuncs()
|
|||
masm_.patchCall(callerOffset, calleeOffset);
|
||||
}
|
||||
|
||||
funcBytes_ = masm_.size();
|
||||
module_->functionBytes = masm_.size();
|
||||
finishedFuncs_ = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -437,7 +458,7 @@ ModuleGenerator::declareFuncPtrTable(uint32_t numElems, uint32_t* index)
|
|||
if (!allocateGlobalBytes(numElems * sizeof(void*), sizeof(void*), &globalDataOffset))
|
||||
return false;
|
||||
|
||||
StaticLinkData::FuncPtrTableVector& tables = staticLinkData_->funcPtrTables;
|
||||
StaticLinkData::FuncPtrTableVector& tables = link_->funcPtrTables;
|
||||
|
||||
*index = tables.length();
|
||||
if (!tables.emplaceBack(globalDataOffset))
|
||||
|
@ -452,7 +473,7 @@ ModuleGenerator::declareFuncPtrTable(uint32_t numElems, uint32_t* index)
|
|||
uint32_t
|
||||
ModuleGenerator::funcPtrTableGlobalDataOffset(uint32_t index) const
|
||||
{
|
||||
return staticLinkData_->funcPtrTables[index].globalDataOffset;
|
||||
return link_->funcPtrTables[index].globalDataOffset;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -460,7 +481,7 @@ ModuleGenerator::defineFuncPtrTable(uint32_t index, const Vector<uint32_t>& elem
|
|||
{
|
||||
MOZ_ASSERT(finishedFuncs_);
|
||||
|
||||
StaticLinkData::FuncPtrTable& table = staticLinkData_->funcPtrTables[index];
|
||||
StaticLinkData::FuncPtrTable& table = link_->funcPtrTables[index];
|
||||
MOZ_ASSERT(table.elemOffsets.length() == elemFuncIndices.length());
|
||||
|
||||
for (size_t i = 0; i < elemFuncIndices.length(); i++)
|
||||
|
@ -471,69 +492,74 @@ bool
|
|||
ModuleGenerator::defineInlineStub(Offsets offsets)
|
||||
{
|
||||
MOZ_ASSERT(finishedFuncs_);
|
||||
return codeRanges_.emplaceBack(CodeRange::Inline, offsets);
|
||||
return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::defineSyncInterruptStub(ProfilingOffsets offsets)
|
||||
{
|
||||
MOZ_ASSERT(finishedFuncs_);
|
||||
return codeRanges_.emplaceBack(CodeRange::Interrupt, offsets);
|
||||
return module_->codeRanges.emplaceBack(CodeRange::Interrupt, offsets);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::defineAsyncInterruptStub(Offsets offsets)
|
||||
{
|
||||
MOZ_ASSERT(finishedFuncs_);
|
||||
staticLinkData_->pod.interruptOffset = offsets.begin;
|
||||
return codeRanges_.emplaceBack(CodeRange::Inline, offsets);
|
||||
link_->pod.interruptOffset = offsets.begin;
|
||||
return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::defineOutOfBoundsStub(Offsets offsets)
|
||||
{
|
||||
MOZ_ASSERT(finishedFuncs_);
|
||||
staticLinkData_->pod.outOfBoundsOffset = offsets.begin;
|
||||
return codeRanges_.emplaceBack(CodeRange::Inline, offsets);
|
||||
link_->pod.outOfBoundsOffset = offsets.begin;
|
||||
return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
|
||||
}
|
||||
|
||||
Module*
|
||||
bool
|
||||
ModuleGenerator::finish(HeapUsage heapUsage,
|
||||
Module::MutedBool mutedErrors,
|
||||
MutedErrorsBool mutedErrors,
|
||||
CacheableChars filename,
|
||||
CacheableTwoByteChars displayURL,
|
||||
UniqueStaticLinkData* staticLinkData,
|
||||
UniqueModuleData* module,
|
||||
UniqueStaticLinkData* linkData,
|
||||
SlowFunctionVector* slowFuncs)
|
||||
{
|
||||
MOZ_ASSERT(!activeFunc_);
|
||||
MOZ_ASSERT(finishedFuncs_);
|
||||
|
||||
module_->heapUsage = heapUsage;
|
||||
module_->mutedErrors = mutedErrors;
|
||||
module_->filename = Move(filename);
|
||||
|
||||
if (!GenerateStubs(*this, UsesHeap(heapUsage)))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
masm_.finish();
|
||||
if (masm_.oom())
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
// Start global data on a new page so JIT code may be given independent
|
||||
// protection flags. Note assumption that global data starts right after
|
||||
// code below.
|
||||
uint32_t codeBytes = AlignBytes(masm_.bytesNeeded(), AsmJSPageSize);
|
||||
module_->codeBytes = AlignBytes(masm_.bytesNeeded(), AsmJSPageSize);
|
||||
|
||||
// Inflate the global bytes up to page size so that the total bytes are a
|
||||
// page size (as required by the allocator functions).
|
||||
globalBytes_ = AlignBytes(globalBytes_, AsmJSPageSize);
|
||||
uint32_t totalBytes = codeBytes + globalBytes_;
|
||||
module_->globalBytes = AlignBytes(module_->globalBytes, AsmJSPageSize);
|
||||
|
||||
// Allocate the code (guarded by a UniquePtr until it is given to the Module).
|
||||
UniqueCodePtr code = AllocateCode(cx_, totalBytes);
|
||||
if (!code)
|
||||
return nullptr;
|
||||
module_->code = AllocateCode(cx_, module_->totalBytes());
|
||||
if (!module_->code)
|
||||
return false;
|
||||
|
||||
// Delay flushing until Module::dynamicallyLink. The flush-inhibited range
|
||||
// is set by executableCopy.
|
||||
AutoFlushICache afc("ModuleGenerator::finish", /* inhibit = */ true);
|
||||
masm_.executableCopy(code.get());
|
||||
uint8_t* code = module_->code.get();
|
||||
masm_.executableCopy(code);
|
||||
|
||||
// c.f. JitCode::copyFrom
|
||||
MOZ_ASSERT(masm_.jumpRelocationTableBytes() == 0);
|
||||
|
@ -543,16 +569,18 @@ ModuleGenerator::finish(HeapUsage heapUsage,
|
|||
|
||||
// Convert the CallSiteAndTargetVector (needed during generation) to a
|
||||
// CallSiteVector (what is stored in the Module).
|
||||
CallSiteVector callSites;
|
||||
if (!callSites.appendAll(masm_.callSites()))
|
||||
return nullptr;
|
||||
if (!module_->callSites.appendAll(masm_.callSites()))
|
||||
return false;
|
||||
|
||||
// The MacroAssembler has accumulated all the heap accesses during codegen.
|
||||
module_->heapAccesses = masm_.extractHeapAccesses();
|
||||
|
||||
// Add links to absolute addresses identified symbolically.
|
||||
StaticLinkData::SymbolicLinkArray& symbolicLinks = staticLinkData_->symbolicLinks;
|
||||
StaticLinkData::SymbolicLinkArray& symbolicLinks = link_->symbolicLinks;
|
||||
for (size_t i = 0; i < masm_.numAsmJSAbsoluteAddresses(); i++) {
|
||||
AsmJSAbsoluteAddress src = masm_.asmJSAbsoluteAddress(i);
|
||||
if (!symbolicLinks[src.target].append(src.patchAt.offset()))
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Relative link metadata: absolute addresses that refer to another point within
|
||||
|
@ -565,8 +593,8 @@ ModuleGenerator::finish(HeapUsage heapUsage,
|
|||
StaticLinkData::InternalLink link(StaticLinkData::InternalLink::CodeLabel);
|
||||
link.patchAtOffset = masm_.labelToPatchOffset(*cl.patchAt());
|
||||
link.targetOffset = cl.target()->offset();
|
||||
if (!staticLinkData_->internalLinks.append(link))
|
||||
return nullptr;
|
||||
if (!link_->internalLinks.append(link))
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(JS_CODEGEN_X86)
|
||||
|
@ -577,9 +605,9 @@ ModuleGenerator::finish(HeapUsage heapUsage,
|
|||
AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
|
||||
StaticLinkData::InternalLink link(StaticLinkData::InternalLink::RawPointer);
|
||||
link.patchAtOffset = masm_.labelToPatchOffset(a.patchAt);
|
||||
link.targetOffset = codeBytes + a.globalDataOffset;
|
||||
if (!staticLinkData_->internalLinks.append(link))
|
||||
return nullptr;
|
||||
link.targetOffset = module_->codeBytes + a.globalDataOffset;
|
||||
if (!link_->internalLinks.append(link))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -591,38 +619,24 @@ ModuleGenerator::finish(HeapUsage heapUsage,
|
|||
size_t off = masm_.longJump(i);
|
||||
StaticLinkData::InternalLink link(StaticLinkData::InternalLink::InstructionImmediate);
|
||||
link.patchAtOffset = off;
|
||||
link.targetOffset = Assembler::ExtractInstructionImmediate(code.get() + off) -
|
||||
uintptr_t(code.get());
|
||||
if (!staticLinkData_->internalLinks.append(link))
|
||||
return nullptr;
|
||||
link.targetOffset = Assembler::ExtractInstructionImmediate(code + off) - uintptr_t(code);
|
||||
if (!link_->internalLinks.append(link))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
// Global data accesses on x64 use rip-relative addressing and thus do
|
||||
// not need patching after deserialization.
|
||||
uint8_t* globalData = code.get() + codeBytes;
|
||||
uint8_t* globalData = code + module_->codeBytes;
|
||||
for (size_t i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
|
||||
AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
|
||||
masm_.patchAsmJSGlobalAccess(a.patchAt, code.get(), globalData, a.globalDataOffset);
|
||||
masm_.patchAsmJSGlobalAccess(a.patchAt, code, globalData, a.globalDataOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
*staticLinkData = Move(staticLinkData_);
|
||||
*module = Move(module_);
|
||||
*linkData = Move(link_);
|
||||
*slowFuncs = Move(slowFuncs_);
|
||||
return cx_->new_<Module>(args_,
|
||||
funcBytes_,
|
||||
codeBytes,
|
||||
globalBytes_,
|
||||
heapUsage,
|
||||
mutedErrors,
|
||||
Move(code),
|
||||
Move(imports_),
|
||||
Move(exports_),
|
||||
masm_.extractHeapAccesses(),
|
||||
Move(codeRanges_),
|
||||
Move(callSites),
|
||||
Move(funcNames_),
|
||||
Move(filename),
|
||||
Move(displayURL));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#ifndef wasm_generator_h
|
||||
#define wasm_generator_h
|
||||
|
||||
#include "asmjs/WasmBinary.h"
|
||||
#include "asmjs/WasmIonCompile.h"
|
||||
#include "asmjs/WasmIR.h"
|
||||
#include "asmjs/WasmModule.h"
|
||||
#include "jit/MacroAssembler.h"
|
||||
|
||||
|
@ -54,6 +54,7 @@ typedef Vector<SlowFunction> SlowFunctionVector;
|
|||
class MOZ_STACK_CLASS ModuleGenerator
|
||||
{
|
||||
typedef Vector<uint32_t> FuncOffsetVector;
|
||||
typedef Vector<uint32_t> FuncIndexVector;
|
||||
|
||||
struct SigHashPolicy
|
||||
{
|
||||
|
@ -64,17 +65,10 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
typedef HashSet<const LifoSig*, SigHashPolicy> SigSet;
|
||||
|
||||
ExclusiveContext* cx_;
|
||||
CompileArgs args_;
|
||||
|
||||
// Data handed over to the Module in finish()
|
||||
uint32_t globalBytes_;
|
||||
ImportVector imports_;
|
||||
ExportVector exports_;
|
||||
CodeRangeVector codeRanges_;
|
||||
CacheableCharsVector funcNames_;
|
||||
|
||||
// Data handed back to the caller in finish()
|
||||
UniqueStaticLinkData staticLinkData_;
|
||||
UniqueModuleData module_;
|
||||
UniqueStaticLinkData link_;
|
||||
SlowFunctionVector slowFuncs_;
|
||||
|
||||
// Data scoped to the ModuleGenerator's lifetime
|
||||
|
@ -83,6 +77,8 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
jit::TempAllocator alloc_;
|
||||
jit::MacroAssembler masm_;
|
||||
SigSet sigs_;
|
||||
FuncOffsetVector funcEntryOffsets_;
|
||||
FuncIndexVector exportFuncIndices_;
|
||||
|
||||
// Parallel compilation
|
||||
bool parallel_;
|
||||
|
@ -90,9 +86,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
Vector<IonCompileTask> tasks_;
|
||||
Vector<IonCompileTask*> freeTasks_;
|
||||
|
||||
// Function compilation
|
||||
uint32_t funcBytes_;
|
||||
FuncOffsetVector funcEntryOffsets_;
|
||||
// Assertions
|
||||
DebugOnly<FunctionGenerator*> activeFunc_;
|
||||
DebugOnly<bool> finishedFuncs_;
|
||||
|
||||
|
@ -106,7 +100,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
|
||||
bool init();
|
||||
|
||||
CompileArgs args() const { return args_; }
|
||||
CompileArgs args() const { return module_->compileArgs; }
|
||||
jit::MacroAssembler& masm() { return masm_; }
|
||||
const FuncOffsetVector& funcEntryOffsets() const { return funcEntryOffsets_; }
|
||||
|
||||
|
@ -130,8 +124,10 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
bool defineExport(uint32_t index, Offsets offsets);
|
||||
|
||||
// Functions:
|
||||
bool startFunc(PropertyName* name, unsigned line, unsigned column, FunctionGenerator* fg);
|
||||
bool finishFunc(uint32_t funcIndex, const LifoSig& sig, unsigned generateTime, FunctionGenerator* fg);
|
||||
bool startFunc(PropertyName* name, unsigned line, unsigned column, UniqueBytecode* recycled,
|
||||
FunctionGenerator* fg);
|
||||
bool finishFunc(uint32_t funcIndex, const LifoSig& sig, UniqueBytecode bytecode,
|
||||
unsigned generateTime, FunctionGenerator* fg);
|
||||
bool finishFuncs();
|
||||
|
||||
// Function-pointer tables:
|
||||
|
@ -145,14 +141,16 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
bool defineAsyncInterruptStub(Offsets offsets);
|
||||
bool defineOutOfBoundsStub(Offsets offsets);
|
||||
|
||||
// Null return indicates failure. The caller must immediately root a
|
||||
// non-null return value.
|
||||
Module* finish(HeapUsage heapUsage,
|
||||
Module::MutedBool mutedErrors,
|
||||
CacheableChars filename,
|
||||
CacheableTwoByteChars displayURL,
|
||||
UniqueStaticLinkData* staticLinkData,
|
||||
SlowFunctionVector* slowFuncs);
|
||||
// Return a ModuleData object which may be used to construct a Module, the
|
||||
// StaticLinkData required to call Module::staticallyLink, and the list of
|
||||
// functions that took a long time to compile.
|
||||
bool finish(HeapUsage heapUsage,
|
||||
MutedErrorsBool mutedErrors,
|
||||
CacheableChars filename,
|
||||
CacheableTwoByteChars displayURL,
|
||||
UniqueModuleData* module,
|
||||
UniqueStaticLinkData* staticLinkData,
|
||||
SlowFunctionVector* slowFuncs);
|
||||
};
|
||||
|
||||
// A FunctionGenerator encapsulates the generation of a single function body.
|
||||
|
@ -164,13 +162,36 @@ class MOZ_STACK_CLASS FunctionGenerator
|
|||
{
|
||||
friend class ModuleGenerator;
|
||||
|
||||
ModuleGenerator* m_;
|
||||
IonCompileTask* task_;
|
||||
FuncIR* func_;
|
||||
ModuleGenerator* m_;
|
||||
IonCompileTask* task_;
|
||||
|
||||
// Function metadata created during function generation, then handed over
|
||||
// to the FuncBytecode in ModuleGenerator::finishFunc().
|
||||
SourceCoordsVector callSourceCoords_;
|
||||
ValTypeVector localVars_;
|
||||
|
||||
// Note: this unrooted field assumes AutoKeepAtoms via TokenStream via
|
||||
// asm.js compilation.
|
||||
PropertyName* name_;
|
||||
unsigned line_;
|
||||
unsigned column_;
|
||||
|
||||
public:
|
||||
FunctionGenerator() : m_(nullptr), task_(nullptr), func_(nullptr) {}
|
||||
FuncIR& func() const { MOZ_ASSERT(func_); return *func_; }
|
||||
FunctionGenerator()
|
||||
: m_(nullptr),
|
||||
task_(nullptr),
|
||||
name_(nullptr),
|
||||
line_(0),
|
||||
column_(0)
|
||||
{}
|
||||
|
||||
bool addSourceCoords(size_t byteOffset, uint32_t line, uint32_t column) {
|
||||
SourceCoords sc = { byteOffset, line, column };
|
||||
return callSourceCoords_.append(sc);
|
||||
}
|
||||
bool addVariable(ValType v) {
|
||||
return localVars_.append(v);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
|
|
|
@ -39,8 +39,9 @@ class FunctionCompiler
|
|||
typedef HashMap<size_t, BlockVector, DefaultHasher<uint32_t>, SystemAllocPolicy> UnlabeledBlockMap;
|
||||
typedef Vector<size_t, 4, SystemAllocPolicy> PositionStack;
|
||||
|
||||
const FuncIR& func_;
|
||||
size_t pc_;
|
||||
const FuncBytecode& func_;
|
||||
Decoder decoder_;
|
||||
size_t nextId_;
|
||||
size_t lastReadCallSite_;
|
||||
|
||||
TempAllocator& alloc_;
|
||||
|
@ -60,9 +61,10 @@ class FunctionCompiler
|
|||
FuncCompileResults& compileResults_;
|
||||
|
||||
public:
|
||||
FunctionCompiler(const FuncIR& func, MIRGenerator& mirGen, FuncCompileResults& compileResults)
|
||||
FunctionCompiler(const FuncBytecode& func, MIRGenerator& mirGen, FuncCompileResults& compileResults)
|
||||
: func_(func),
|
||||
pc_(0),
|
||||
decoder_(func.bytecode()),
|
||||
nextId_(0),
|
||||
lastReadCallSite_(0),
|
||||
alloc_(mirGen.alloc()),
|
||||
graph_(mirGen.graph()),
|
||||
|
@ -91,6 +93,8 @@ class FunctionCompiler
|
|||
const LifoSig::ArgVector& args = func_.sig().args();
|
||||
unsigned firstVarSlot = args.length();
|
||||
|
||||
if (!mirGen_.ensureBallast())
|
||||
return false;
|
||||
if (!newBlock(/* pred = */ nullptr, &curBlock_))
|
||||
return false;
|
||||
|
||||
|
@ -145,7 +149,7 @@ class FunctionCompiler
|
|||
MOZ_ASSERT(labeledBreaks_.empty());
|
||||
MOZ_ASSERT(labeledContinues_.empty());
|
||||
MOZ_ASSERT(inDeadCode());
|
||||
MOZ_ASSERT(pc_ == func_.size(), "all bytecode must be consumed");
|
||||
MOZ_ASSERT(decoder_.done(), "all bytecode must be consumed");
|
||||
}
|
||||
|
||||
/************************* Read-only interface (after local scope setup) */
|
||||
|
@ -889,9 +893,9 @@ class FunctionCompiler
|
|||
return curBlock_->pop();
|
||||
}
|
||||
|
||||
bool startPendingLoop(size_t pos, MBasicBlock** loopEntry)
|
||||
bool startPendingLoop(size_t id, MBasicBlock** loopEntry)
|
||||
{
|
||||
if (!loopStack_.append(pos) || !breakableStack_.append(pos))
|
||||
if (!loopStack_.append(id) || !breakableStack_.append(id))
|
||||
return false;
|
||||
if (inDeadCode()) {
|
||||
*loopEntry = nullptr;
|
||||
|
@ -934,10 +938,10 @@ class FunctionCompiler
|
|||
private:
|
||||
size_t popLoop()
|
||||
{
|
||||
size_t pos = loopStack_.popCopy();
|
||||
MOZ_ASSERT(!unlabeledContinues_.has(pos));
|
||||
size_t id = loopStack_.popCopy();
|
||||
MOZ_ASSERT(!unlabeledContinues_.has(id));
|
||||
breakableStack_.popBack();
|
||||
return pos;
|
||||
return id;
|
||||
}
|
||||
|
||||
void fixupRedundantPhis(MBasicBlock* b)
|
||||
|
@ -998,11 +1002,11 @@ class FunctionCompiler
|
|||
public:
|
||||
bool closeLoop(MBasicBlock* loopEntry, MBasicBlock* afterLoop)
|
||||
{
|
||||
size_t pos = popLoop();
|
||||
size_t id = popLoop();
|
||||
if (!loopEntry) {
|
||||
MOZ_ASSERT(!afterLoop);
|
||||
MOZ_ASSERT(inDeadCode());
|
||||
MOZ_ASSERT(!unlabeledBreaks_.has(pos));
|
||||
MOZ_ASSERT(!unlabeledBreaks_.has(id));
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(loopEntry->loopDepth() == loopStack_.length() + 1);
|
||||
|
@ -1016,15 +1020,15 @@ class FunctionCompiler
|
|||
curBlock_ = afterLoop;
|
||||
if (curBlock_)
|
||||
mirGraph().moveBlockToEnd(curBlock_);
|
||||
return bindUnlabeledBreaks(pos);
|
||||
return bindUnlabeledBreaks(id);
|
||||
}
|
||||
|
||||
bool branchAndCloseDoWhileLoop(MDefinition* cond, MBasicBlock* loopEntry)
|
||||
{
|
||||
size_t pos = popLoop();
|
||||
size_t id = popLoop();
|
||||
if (!loopEntry) {
|
||||
MOZ_ASSERT(inDeadCode());
|
||||
MOZ_ASSERT(!unlabeledBreaks_.has(pos));
|
||||
MOZ_ASSERT(!unlabeledBreaks_.has(id));
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(loopEntry->loopDepth() == loopStack_.length() + 1);
|
||||
|
@ -1053,13 +1057,13 @@ class FunctionCompiler
|
|||
curBlock_ = afterLoop;
|
||||
}
|
||||
}
|
||||
return bindUnlabeledBreaks(pos);
|
||||
return bindUnlabeledBreaks(id);
|
||||
}
|
||||
|
||||
bool bindContinues(size_t pos, const LabelVector* maybeLabels)
|
||||
bool bindContinues(size_t id, const LabelVector* maybeLabels)
|
||||
{
|
||||
bool createdJoinBlock = false;
|
||||
if (UnlabeledBlockMap::Ptr p = unlabeledContinues_.lookup(pos)) {
|
||||
if (UnlabeledBlockMap::Ptr p = unlabeledContinues_.lookup(id)) {
|
||||
if (!bindBreaksOrContinues(&p->value(), &createdJoinBlock))
|
||||
return false;
|
||||
unlabeledContinues_.remove(p);
|
||||
|
@ -1085,10 +1089,10 @@ class FunctionCompiler
|
|||
return addBreakOrContinue(loopStack_.back(), &unlabeledContinues_);
|
||||
}
|
||||
|
||||
bool startSwitch(size_t pos, MDefinition* expr, int32_t low, int32_t high,
|
||||
bool startSwitch(size_t id, MDefinition* expr, int32_t low, int32_t high,
|
||||
MBasicBlock** switchBlock)
|
||||
{
|
||||
if (!breakableStack_.append(pos))
|
||||
if (!breakableStack_.append(id))
|
||||
return false;
|
||||
if (inDeadCode()) {
|
||||
*switchBlock = nullptr;
|
||||
|
@ -1129,7 +1133,7 @@ class FunctionCompiler
|
|||
|
||||
bool joinSwitch(MBasicBlock* switchBlock, const BlockVector& cases, MBasicBlock* defaultBlock)
|
||||
{
|
||||
size_t pos = breakableStack_.popCopy();
|
||||
size_t id = breakableStack_.popCopy();
|
||||
if (!switchBlock)
|
||||
return true;
|
||||
MTableSwitch* mir = switchBlock->lastIns()->toTableSwitch();
|
||||
|
@ -1155,25 +1159,29 @@ class FunctionCompiler
|
|||
curBlock_->end(MGoto::New(alloc(), next));
|
||||
curBlock_ = next;
|
||||
}
|
||||
return bindUnlabeledBreaks(pos);
|
||||
return bindUnlabeledBreaks(id);
|
||||
}
|
||||
|
||||
// Provides unique identifiers for internal uses in the control flow stacks;
|
||||
// these ids have to grow monotonically.
|
||||
unsigned nextId() { return nextId_++; }
|
||||
|
||||
/************************************************************ DECODING ***/
|
||||
|
||||
uint8_t readU8() { return func_.uncheckedReadU8(&pc_); }
|
||||
uint32_t readU32() { return func_.uncheckedReadU32(&pc_); }
|
||||
int32_t readI32() { return func_.uncheckedReadI32(&pc_); }
|
||||
float readF32() { return func_.uncheckedReadF32(&pc_); }
|
||||
double readF64() { return func_.uncheckedReadF64(&pc_); }
|
||||
const LifoSig* readSig() { return func_.uncheckedReadSig(&pc_); }
|
||||
SimdConstant readI32X4() { return func_.uncheckedReadI32X4(&pc_); }
|
||||
SimdConstant readF32X4() { return func_.uncheckedReadF32X4(&pc_); }
|
||||
uint8_t readU8() { return decoder_.uncheckedReadU8(); }
|
||||
uint32_t readU32() { return decoder_.uncheckedReadU32(); }
|
||||
int32_t readI32() { return decoder_.uncheckedReadI32(); }
|
||||
float readF32() { return decoder_.uncheckedReadF32(); }
|
||||
double readF64() { return decoder_.uncheckedReadF64(); }
|
||||
const LifoSig* readSig() { return decoder_.uncheckedReadSig(); }
|
||||
SimdConstant readI32X4() { return decoder_.uncheckedReadI32X4(); }
|
||||
SimdConstant readF32X4() { return decoder_.uncheckedReadF32X4(); }
|
||||
|
||||
Stmt readStmtOp() { return Stmt(readU8()); }
|
||||
|
||||
void readCallLineCol(uint32_t* line, uint32_t* column) {
|
||||
const FuncIR::SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++);
|
||||
MOZ_ASSERT(pc_ == sc.offset);
|
||||
const SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++);
|
||||
decoder_.assertCurrentIs(sc.offset);
|
||||
*line = sc.line;
|
||||
*column = sc.column;
|
||||
}
|
||||
|
@ -1182,8 +1190,7 @@ class FunctionCompiler
|
|||
MOZ_ASSERT(Stmt(readU8()) == Stmt::DebugCheckPoint);
|
||||
}
|
||||
|
||||
bool done() const { return pc_ == func_.size(); }
|
||||
size_t pc() const { return pc_; }
|
||||
bool done() const { return decoder_.done(); }
|
||||
|
||||
/*************************************************************************/
|
||||
private:
|
||||
|
@ -1266,10 +1273,10 @@ class FunctionCompiler
|
|||
return true;
|
||||
}
|
||||
|
||||
bool bindUnlabeledBreaks(size_t pos)
|
||||
bool bindUnlabeledBreaks(size_t id)
|
||||
{
|
||||
bool createdJoinBlock = false;
|
||||
if (UnlabeledBlockMap::Ptr p = unlabeledBreaks_.lookup(pos)) {
|
||||
if (UnlabeledBlockMap::Ptr p = unlabeledBreaks_.lookup(id)) {
|
||||
if (!bindBreaksOrContinues(&p->value(), &createdJoinBlock))
|
||||
return false;
|
||||
unlabeledBreaks_.remove(p);
|
||||
|
@ -2287,10 +2294,10 @@ EmitInterruptCheckLoop(FunctionCompiler& f)
|
|||
static bool
|
||||
EmitWhile(FunctionCompiler& f, const LabelVector* maybeLabels)
|
||||
{
|
||||
size_t headPc = f.pc();
|
||||
size_t headId = f.nextId();
|
||||
|
||||
MBasicBlock* loopEntry;
|
||||
if (!f.startPendingLoop(headPc, &loopEntry))
|
||||
if (!f.startPendingLoop(headId, &loopEntry))
|
||||
return false;
|
||||
|
||||
MDefinition* condDef;
|
||||
|
@ -2304,7 +2311,7 @@ EmitWhile(FunctionCompiler& f, const LabelVector* maybeLabels)
|
|||
if (!EmitStatement(f))
|
||||
return false;
|
||||
|
||||
if (!f.bindContinues(headPc, maybeLabels))
|
||||
if (!f.bindContinues(headId, maybeLabels))
|
||||
return false;
|
||||
|
||||
return f.closeLoop(loopEntry, afterLoop);
|
||||
|
@ -2315,7 +2322,7 @@ EmitFor(FunctionCompiler& f, Stmt stmt, const LabelVector* maybeLabels)
|
|||
{
|
||||
MOZ_ASSERT(stmt == Stmt::ForInitInc || stmt == Stmt::ForInitNoInc ||
|
||||
stmt == Stmt::ForNoInitInc || stmt == Stmt::ForNoInitNoInc);
|
||||
size_t headPc = f.pc();
|
||||
size_t headId = f.nextId();
|
||||
|
||||
if (stmt == Stmt::ForInitInc || stmt == Stmt::ForInitNoInc) {
|
||||
if (!EmitStatement(f))
|
||||
|
@ -2323,7 +2330,7 @@ EmitFor(FunctionCompiler& f, Stmt stmt, const LabelVector* maybeLabels)
|
|||
}
|
||||
|
||||
MBasicBlock* loopEntry;
|
||||
if (!f.startPendingLoop(headPc, &loopEntry))
|
||||
if (!f.startPendingLoop(headId, &loopEntry))
|
||||
return false;
|
||||
|
||||
MDefinition* condDef;
|
||||
|
@ -2337,7 +2344,7 @@ EmitFor(FunctionCompiler& f, Stmt stmt, const LabelVector* maybeLabels)
|
|||
if (!EmitStatement(f))
|
||||
return false;
|
||||
|
||||
if (!f.bindContinues(headPc, maybeLabels))
|
||||
if (!f.bindContinues(headId, maybeLabels))
|
||||
return false;
|
||||
|
||||
if (stmt == Stmt::ForInitInc || stmt == Stmt::ForNoInitInc) {
|
||||
|
@ -2353,16 +2360,16 @@ EmitFor(FunctionCompiler& f, Stmt stmt, const LabelVector* maybeLabels)
|
|||
static bool
|
||||
EmitDoWhile(FunctionCompiler& f, const LabelVector* maybeLabels)
|
||||
{
|
||||
size_t headPc = f.pc();
|
||||
size_t headId = f.nextId();
|
||||
|
||||
MBasicBlock* loopEntry;
|
||||
if (!f.startPendingLoop(headPc, &loopEntry))
|
||||
if (!f.startPendingLoop(headId, &loopEntry))
|
||||
return false;
|
||||
|
||||
if (!EmitStatement(f))
|
||||
return false;
|
||||
|
||||
if (!f.bindContinues(headPc, maybeLabels))
|
||||
if (!f.bindContinues(headId, maybeLabels))
|
||||
return false;
|
||||
|
||||
MDefinition* condDef;
|
||||
|
@ -2465,7 +2472,7 @@ EmitSwitch(FunctionCompiler& f)
|
|||
return false;
|
||||
|
||||
MBasicBlock* switchBlock;
|
||||
if (!f.startSwitch(f.pc(), exprDef, low, high, &switchBlock))
|
||||
if (!f.startSwitch(f.nextId(), exprDef, low, high, &switchBlock))
|
||||
return false;
|
||||
|
||||
while (numCases--) {
|
||||
|
@ -3040,7 +3047,7 @@ wasm::IonCompileFunction(IonCompileTask* task)
|
|||
{
|
||||
int64_t before = PRMJ_Now();
|
||||
|
||||
const FuncIR& func = task->func();
|
||||
const FuncBytecode& func = task->func();
|
||||
FuncCompileResults& results = task->results();
|
||||
|
||||
JitContext jitContext(CompileRuntime::get(task->runtime()), &results.alloc());
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#ifndef wasm_ion_compile_h
|
||||
#define wasm_ion_compile_h
|
||||
|
||||
#include "asmjs/WasmIR.h"
|
||||
#include "asmjs/WasmBinary.h"
|
||||
#include "jit/MacroAssembler.h"
|
||||
|
||||
namespace js {
|
||||
|
@ -63,7 +63,7 @@ class IonCompileTask
|
|||
JSRuntime* const runtime_;
|
||||
const CompileArgs args_;
|
||||
LifoAlloc lifo_;
|
||||
const FuncIR* func_;
|
||||
UniqueFuncBytecode func_;
|
||||
mozilla::Maybe<FuncCompileResults> results_;
|
||||
|
||||
IonCompileTask(const IonCompileTask&) = delete;
|
||||
|
@ -85,19 +85,22 @@ class IonCompileTask
|
|||
CompileArgs args() const {
|
||||
return args_;
|
||||
}
|
||||
void init(const FuncIR& func) {
|
||||
func_ = &func;
|
||||
void init(UniqueFuncBytecode func) {
|
||||
MOZ_ASSERT(!func_);
|
||||
func_ = mozilla::Move(func);
|
||||
results_.emplace(lifo_);
|
||||
}
|
||||
const FuncIR& func() const {
|
||||
const FuncBytecode& func() const {
|
||||
MOZ_ASSERT(func_);
|
||||
return *func_;
|
||||
}
|
||||
FuncCompileResults& results() {
|
||||
return *results_;
|
||||
}
|
||||
void reset() {
|
||||
func_ = nullptr;
|
||||
void reset(UniqueBytecode* recycled) {
|
||||
if (func_)
|
||||
*recycled = func_->recycleBytecode();
|
||||
func_.reset(nullptr);
|
||||
results_.reset();
|
||||
lifo_.releaseAll();
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ wasm::AllocateCode(ExclusiveContext* cx, size_t bytes)
|
|||
void
|
||||
CodeDeleter::operator()(uint8_t* p)
|
||||
{
|
||||
MOZ_ASSERT(bytes_ != 0);
|
||||
DeallocateExecutableMemory(p, bytes_, AsmJSPageSize);
|
||||
}
|
||||
|
||||
|
@ -462,6 +463,13 @@ CacheableUniquePtr<CharT>::clone(JSContext* cx, CacheableUniquePtr* out) const
|
|||
return true;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
size_t
|
||||
CacheableUniquePtr<CharT>::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
return mallocSizeOf(this->get());
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
template struct CacheableUniquePtr<char>;
|
||||
|
@ -469,24 +477,90 @@ template struct CacheableUniquePtr<char16_t>;
|
|||
}
|
||||
}
|
||||
|
||||
class Module::AutoMutateCode
|
||||
size_t
|
||||
ModuleData::serializedSize() const
|
||||
{
|
||||
AutoWritableJitCode awjc_;
|
||||
AutoFlushICache afc_;
|
||||
return sizeof(pod()) +
|
||||
codeBytes +
|
||||
SerializedVectorSize(imports) +
|
||||
SerializedVectorSize(exports) +
|
||||
SerializedPodVectorSize(heapAccesses) +
|
||||
SerializedPodVectorSize(codeRanges) +
|
||||
SerializedPodVectorSize(callSites) +
|
||||
SerializedVectorSize(funcNames) +
|
||||
filename.serializedSize() +
|
||||
displayURL.serializedSize();
|
||||
}
|
||||
|
||||
public:
|
||||
AutoMutateCode(JSContext* cx, Module& module, const char* name)
|
||||
: awjc_(cx->runtime(), module.code(), module.pod.codeBytes_),
|
||||
afc_(name)
|
||||
{
|
||||
AutoFlushICache::setRange(uintptr_t(module.code()), module.pod.codeBytes_);
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t
|
||||
Module::totalBytes() const
|
||||
uint8_t*
|
||||
ModuleData::serialize(uint8_t* cursor) const
|
||||
{
|
||||
return pod.codeBytes_ + pod.globalBytes_;
|
||||
cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
|
||||
cursor = WriteBytes(cursor, code.get(), codeBytes);
|
||||
cursor = SerializeVector(cursor, imports);
|
||||
cursor = SerializeVector(cursor, exports);
|
||||
cursor = SerializePodVector(cursor, heapAccesses);
|
||||
cursor = SerializePodVector(cursor, codeRanges);
|
||||
cursor = SerializePodVector(cursor, callSites);
|
||||
cursor = SerializeVector(cursor, funcNames);
|
||||
cursor = filename.serialize(cursor);
|
||||
cursor = displayURL.serialize(cursor);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/* static */ const uint8_t*
|
||||
ModuleData::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
|
||||
{
|
||||
cursor = ReadBytes(cursor, &pod(), sizeof(pod()));
|
||||
|
||||
code = AllocateCode(cx, totalBytes());
|
||||
if (!code)
|
||||
return nullptr;
|
||||
cursor = ReadBytes(cursor, code.get(), codeBytes);
|
||||
|
||||
(cursor = DeserializeVector(cx, cursor, &imports)) &&
|
||||
(cursor = DeserializeVector(cx, cursor, &exports)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &heapAccesses)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &codeRanges)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &callSites)) &&
|
||||
(cursor = DeserializeVector(cx, cursor, &funcNames)) &&
|
||||
(cursor = filename.deserialize(cx, cursor)) &&
|
||||
(cursor = displayURL.deserialize(cx, cursor));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleData::clone(JSContext* cx, ModuleData* out) const
|
||||
{
|
||||
out->pod() = pod();
|
||||
|
||||
out->code = AllocateCode(cx, totalBytes());
|
||||
if (!out->code)
|
||||
return false;
|
||||
memcpy(out->code.get(), code.get(), codeBytes);
|
||||
|
||||
return CloneVector(cx, imports, &out->imports) &&
|
||||
CloneVector(cx, exports, &out->exports) &&
|
||||
ClonePodVector(cx, heapAccesses, &out->heapAccesses) &&
|
||||
ClonePodVector(cx, codeRanges, &out->codeRanges) &&
|
||||
ClonePodVector(cx, callSites, &out->callSites) &&
|
||||
CloneVector(cx, funcNames, &out->funcNames) &&
|
||||
filename.clone(cx, &out->filename) &&
|
||||
displayURL.clone(cx, &out->displayURL);
|
||||
}
|
||||
|
||||
size_t
|
||||
ModuleData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
// Module::addSizeOfMisc takes care of code and global memory.
|
||||
return SizeOfVectorExcludingThis(imports, mallocSizeOf) +
|
||||
SizeOfVectorExcludingThis(exports, mallocSizeOf) +
|
||||
heapAccesses.sizeOfExcludingThis(mallocSizeOf) +
|
||||
codeRanges.sizeOfExcludingThis(mallocSizeOf) +
|
||||
callSites.sizeOfExcludingThis(mallocSizeOf) +
|
||||
funcNames.sizeOfExcludingThis(mallocSizeOf) +
|
||||
filename.sizeOfExcludingThis(mallocSizeOf) +
|
||||
displayURL.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
|
@ -524,7 +598,7 @@ Module::specializeToHeap(ArrayBufferObjectMaybeShared* heap)
|
|||
// i.e. ptr > heapLength - data-type-byte-size - offset. data-type-byte-size
|
||||
// and offset are already included in the addend so we
|
||||
// just have to add the heap length here.
|
||||
for (const HeapAccess& access : heapAccesses_) {
|
||||
for (const HeapAccess& access : module_->heapAccesses) {
|
||||
if (access.hasLengthCheck())
|
||||
X86Encoding::AddInt32(access.patchLengthAt(code()), heapLength);
|
||||
void* addr = access.patchHeapPtrImmAt(code());
|
||||
|
@ -540,14 +614,14 @@ Module::specializeToHeap(ArrayBufferObjectMaybeShared* heap)
|
|||
// checks at the right places. All accesses that have been recorded are the
|
||||
// only ones that need bound checks (see also
|
||||
// CodeGeneratorX64::visitAsmJS{Load,Store,CompareExchange,Exchange,AtomicBinop}Heap)
|
||||
for (const HeapAccess& access : heapAccesses_) {
|
||||
for (const HeapAccess& access : module_->heapAccesses) {
|
||||
// See comment above for x86 codegen.
|
||||
if (access.hasLengthCheck())
|
||||
X86Encoding::AddInt32(access.patchLengthAt(code()), heapLength);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
|
||||
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
for (const HeapAccess& access : heapAccesses_)
|
||||
for (const HeapAccess& access : module_->heapAccesses)
|
||||
Assembler::UpdateBoundsCheck(heapLength, (Instruction*)(access.insnOffset() + code()));
|
||||
#endif
|
||||
|
||||
|
@ -567,8 +641,8 @@ Module::despecializeFromHeap(ArrayBufferObjectMaybeShared* heap)
|
|||
#if defined(JS_CODEGEN_X86)
|
||||
uint32_t heapLength = heap->byteLength();
|
||||
uint8_t* ptrBase = heap->dataPointerEither().unwrap(/*safe - used for value*/);
|
||||
for (unsigned i = 0; i < heapAccesses_.length(); i++) {
|
||||
const HeapAccess& access = heapAccesses_[i];
|
||||
for (unsigned i = 0; i < module_->heapAccesses.length(); i++) {
|
||||
const HeapAccess& access = module_->heapAccesses[i];
|
||||
if (access.hasLengthCheck())
|
||||
X86Encoding::AddInt32(access.patchLengthAt(code()), -heapLength);
|
||||
void* addr = access.patchHeapPtrImmAt(code());
|
||||
|
@ -578,8 +652,8 @@ Module::despecializeFromHeap(ArrayBufferObjectMaybeShared* heap)
|
|||
}
|
||||
#elif defined(JS_CODEGEN_X64)
|
||||
uint32_t heapLength = heap->byteLength();
|
||||
for (unsigned i = 0; i < heapAccesses_.length(); i++) {
|
||||
const HeapAccess& access = heapAccesses_[i];
|
||||
for (unsigned i = 0; i < module_->heapAccesses.length(); i++) {
|
||||
const HeapAccess& access = module_->heapAccesses[i];
|
||||
if (access.hasLengthCheck())
|
||||
X86Encoding::AddInt32(access.patchLengthAt(code()), -heapLength);
|
||||
}
|
||||
|
@ -594,17 +668,17 @@ Module::sendCodeRangesToProfiler(JSContext* cx)
|
|||
{
|
||||
#ifdef JS_ION_PERF
|
||||
if (PerfFuncEnabled()) {
|
||||
for (const CodeRange& codeRange : codeRanges_) {
|
||||
for (const CodeRange& codeRange : module_->codeRanges) {
|
||||
if (!codeRange.isFunction())
|
||||
continue;
|
||||
|
||||
uintptr_t start = uintptr_t(code() + codeRange.begin());
|
||||
uintptr_t end = uintptr_t(code() + codeRange.end());
|
||||
uintptr_t size = end - start;
|
||||
const char* file = filename_.get();
|
||||
const char* file = module_->filename.get();
|
||||
unsigned line = codeRange.funcLineNumber();
|
||||
unsigned column = 0;
|
||||
const char* name = funcNames_[codeRange.funcNameIndex()].get();
|
||||
const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
|
||||
|
||||
writePerfSpewerAsmJSFunctionMap(start, size, file, line, column, name);
|
||||
}
|
||||
|
@ -612,14 +686,14 @@ Module::sendCodeRangesToProfiler(JSContext* cx)
|
|||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
if (IsVTuneProfilingActive()) {
|
||||
for (const CodeRange& codeRange : codeRanges_) {
|
||||
for (const CodeRange& codeRange : module_->codeRanges) {
|
||||
if (!codeRange.isFunction())
|
||||
continue;
|
||||
|
||||
uintptr_t start = uintptr_t(code() + codeRange.begin());
|
||||
uintptr_t end = uintptr_t(code() + codeRange.end());
|
||||
uintptr_t size = end - start;
|
||||
const char* name = funcNames_[codeRange.funcNameIndex()].get();
|
||||
const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
|
||||
|
||||
unsigned method_id = iJIT_GetNewMethodID();
|
||||
if (method_id == 0)
|
||||
|
@ -654,16 +728,16 @@ Module::setProfilingEnabled(JSContext* cx, bool enabled)
|
|||
// do it now since, once we start sampling, we'll be in a signal-handing
|
||||
// context where we cannot malloc.
|
||||
if (enabled) {
|
||||
if (!funcLabels_.resize(funcNames_.length())) {
|
||||
if (!funcLabels_.resize(module_->funcNames.length())) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
for (const CodeRange& codeRange : codeRanges_) {
|
||||
for (const CodeRange& codeRange : module_->codeRanges) {
|
||||
if (!codeRange.isFunction())
|
||||
continue;
|
||||
unsigned lineno = codeRange.funcLineNumber();
|
||||
const char* name = funcNames_[codeRange.funcNameIndex()].get();
|
||||
UniqueChars label(JS_smprintf("%s (%s:%u)", name, filename_.get(), lineno));
|
||||
const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
|
||||
UniqueChars label(JS_smprintf("%s (%s:%u)", name, module_->filename.get(), lineno));
|
||||
if (!label) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
|
@ -674,14 +748,16 @@ Module::setProfilingEnabled(JSContext* cx, bool enabled)
|
|||
funcLabels_.clear();
|
||||
}
|
||||
|
||||
// Patch callsites and returns to execute profiling prologues/epililogues.
|
||||
// Patch callsites and returns to execute profiling prologues/epilogues.
|
||||
{
|
||||
AutoMutateCode amc(cx, *this, "Module::setProfilingEnabled");
|
||||
AutoWritableJitCode awjc(cx->runtime(), code(), codeBytes());
|
||||
AutoFlushICache afc("Module::setProfilingEnabled");
|
||||
AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
|
||||
|
||||
for (const CallSite& callSite : callSites_)
|
||||
for (const CallSite& callSite : module_->callSites)
|
||||
EnableProfilingPrologue(*this, callSite, enabled);
|
||||
|
||||
for (const CodeRange& codeRange : codeRanges_)
|
||||
for (const CodeRange& codeRange : module_->codeRanges)
|
||||
EnableProfilingEpilogue(*this, codeRange, enabled);
|
||||
}
|
||||
|
||||
|
@ -709,114 +785,70 @@ Module::importToExit(const Import& import)
|
|||
return *reinterpret_cast<ImportExit*>(globalData() + import.exitGlobalDataOffset());
|
||||
}
|
||||
|
||||
/* static */ Module::CacheablePod
|
||||
Module::zeroPod()
|
||||
bool
|
||||
Module::clone(JSContext* cx, const StaticLinkData& link, Module* out) const
|
||||
{
|
||||
CacheablePod pod = {0, 0, 0, HeapUsage::None, false, false, false};
|
||||
return pod;
|
||||
MOZ_ASSERT(dynamicallyLinked_);
|
||||
|
||||
// The out->module_ field was already cloned and initialized when 'out' was
|
||||
// constructed. This function should clone the rest.
|
||||
MOZ_ASSERT(out->module_);
|
||||
|
||||
out->isAsmJS_ = isAsmJS_;
|
||||
out->profilingEnabled_ = profilingEnabled_;
|
||||
|
||||
if (!CloneVector(cx, funcLabels_, &out->funcLabels_))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Put the symbolic links back to -1 so PatchDataWithValueCheck assertions
|
||||
// in Module::staticallyLink are valid.
|
||||
for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
|
||||
void* callee = AddressOf(imm, cx);
|
||||
const StaticLinkData::OffsetVector& offsets = link.symbolicLinks[imm];
|
||||
for (uint32_t offset : offsets) {
|
||||
jit::Assembler::PatchDataWithValueCheck(jit::CodeLocationLabel(out->code() + offset),
|
||||
jit::PatchedImmPtr((void*)-1),
|
||||
jit::PatchedImmPtr(callee));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// If the copied machine code has been specialized to the heap, it must be
|
||||
// unspecialized in the copy.
|
||||
if (usesHeap())
|
||||
out->despecializeFromHeap(heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Module::init()
|
||||
{
|
||||
staticallyLinked_ = false;
|
||||
interrupt_ = nullptr;
|
||||
outOfBounds_ = nullptr;
|
||||
dynamicallyLinked_ = false;
|
||||
|
||||
Module::Module(UniqueModuleData module, AsmJSBool isAsmJS)
|
||||
: module_(Move(module)),
|
||||
isAsmJS_(bool(isAsmJS)),
|
||||
staticallyLinked_(false),
|
||||
interrupt_(nullptr),
|
||||
outOfBounds_(nullptr),
|
||||
dynamicallyLinked_(false),
|
||||
profilingEnabled_(false)
|
||||
{
|
||||
*(double*)(globalData() + NaN64GlobalDataOffset) = GenericNaN();
|
||||
*(float*)(globalData() + NaN32GlobalDataOffset) = GenericNaN();
|
||||
}
|
||||
|
||||
// Private constructor used for deserialization and cloning.
|
||||
Module::Module(const CacheablePod& pod,
|
||||
UniqueCodePtr code,
|
||||
ImportVector&& imports,
|
||||
ExportVector&& exports,
|
||||
HeapAccessVector&& heapAccesses,
|
||||
CodeRangeVector&& codeRanges,
|
||||
CallSiteVector&& callSites,
|
||||
CacheableCharsVector&& funcNames,
|
||||
CacheableChars filename,
|
||||
CacheableTwoByteChars displayURL,
|
||||
CacheBool loadedFromCache,
|
||||
ProfilingBool profilingEnabled,
|
||||
FuncLabelVector&& funcLabels)
|
||||
: pod(pod),
|
||||
code_(Move(code)),
|
||||
imports_(Move(imports)),
|
||||
exports_(Move(exports)),
|
||||
heapAccesses_(Move(heapAccesses)),
|
||||
codeRanges_(Move(codeRanges)),
|
||||
callSites_(Move(callSites)),
|
||||
funcNames_(Move(funcNames)),
|
||||
filename_(Move(filename)),
|
||||
displayURL_(Move(displayURL)),
|
||||
loadedFromCache_(loadedFromCache),
|
||||
profilingEnabled_(profilingEnabled),
|
||||
funcLabels_(Move(funcLabels))
|
||||
{
|
||||
MOZ_ASSERT_IF(!profilingEnabled, funcLabels_.empty());
|
||||
MOZ_ASSERT_IF(profilingEnabled, funcNames_.length() == funcLabels_.length());
|
||||
init();
|
||||
}
|
||||
|
||||
// Public constructor for compilation.
|
||||
Module::Module(CompileArgs args,
|
||||
uint32_t functionBytes,
|
||||
uint32_t codeBytes,
|
||||
uint32_t globalBytes,
|
||||
HeapUsage heapUsage,
|
||||
MutedBool mutedErrors,
|
||||
UniqueCodePtr code,
|
||||
ImportVector&& imports,
|
||||
ExportVector&& exports,
|
||||
HeapAccessVector&& heapAccesses,
|
||||
CodeRangeVector&& codeRanges,
|
||||
CallSiteVector&& callSites,
|
||||
CacheableCharsVector&& funcNames,
|
||||
CacheableChars filename,
|
||||
CacheableTwoByteChars displayURL)
|
||||
: pod(zeroPod()),
|
||||
code_(Move(code)),
|
||||
imports_(Move(imports)),
|
||||
exports_(Move(exports)),
|
||||
heapAccesses_(Move(heapAccesses)),
|
||||
codeRanges_(Move(codeRanges)),
|
||||
callSites_(Move(callSites)),
|
||||
funcNames_(Move(funcNames)),
|
||||
filename_(Move(filename)),
|
||||
displayURL_(Move(displayURL)),
|
||||
loadedFromCache_(false),
|
||||
profilingEnabled_(false)
|
||||
{
|
||||
// Work around MSVC 2013 bug around {} member initialization.
|
||||
const_cast<uint32_t&>(pod.functionBytes_) = functionBytes;
|
||||
const_cast<uint32_t&>(pod.codeBytes_) = codeBytes;
|
||||
const_cast<uint32_t&>(pod.globalBytes_) = globalBytes;
|
||||
const_cast<HeapUsage&>(pod.heapUsage_) = heapUsage;
|
||||
const_cast<bool&>(pod.mutedErrors_) = bool(mutedErrors);
|
||||
const_cast<bool&>(pod.usesSignalHandlersForOOB_) = args.useSignalHandlersForOOB;
|
||||
const_cast<bool&>(pod.usesSignalHandlersForInterrupt_) = args.useSignalHandlersForInterrupt;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
Module::~Module()
|
||||
{
|
||||
if (code_) {
|
||||
for (unsigned i = 0; i < imports_.length(); i++) {
|
||||
ImportExit& exit = importToExit(imports_[i]);
|
||||
if (exit.baselineScript)
|
||||
exit.baselineScript->removeDependentWasmModule(*this, i);
|
||||
}
|
||||
for (unsigned i = 0; i < imports().length(); i++) {
|
||||
ImportExit& exit = importToExit(imports()[i]);
|
||||
if (exit.baselineScript)
|
||||
exit.baselineScript->removeDependentWasmModule(*this, i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Module::trace(JSTracer* trc)
|
||||
{
|
||||
for (const Import& import : imports_) {
|
||||
for (const Import& import : imports()) {
|
||||
if (importToExit(import).fun)
|
||||
TraceEdge(trc, &importToExit(import).fun, "wasm function import");
|
||||
}
|
||||
|
@ -825,25 +857,16 @@ Module::trace(JSTracer* trc)
|
|||
TraceEdge(trc, &heap_, "wasm buffer");
|
||||
}
|
||||
|
||||
CompileArgs
|
||||
Module::compileArgs() const
|
||||
{
|
||||
CompileArgs args;
|
||||
args.useSignalHandlersForOOB = pod.usesSignalHandlersForOOB_;
|
||||
args.useSignalHandlersForInterrupt = pod.usesSignalHandlersForInterrupt_;
|
||||
return args;
|
||||
}
|
||||
|
||||
bool
|
||||
Module::containsFunctionPC(void* pc) const
|
||||
{
|
||||
return pc >= code() && pc < (code() + pod.functionBytes_);
|
||||
return pc >= code() && pc < (code() + module_->functionBytes);
|
||||
}
|
||||
|
||||
bool
|
||||
Module::containsCodePC(void* pc) const
|
||||
{
|
||||
return pc >= code() && pc < (code() + pod.codeBytes_);
|
||||
return pc >= code() && pc < (code() + codeBytes());
|
||||
}
|
||||
|
||||
struct CallSiteRetAddrOffset
|
||||
|
@ -860,13 +883,13 @@ Module::lookupCallSite(void* returnAddress) const
|
|||
{
|
||||
uint32_t target = ((uint8_t*)returnAddress) - code();
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = callSites_.length();
|
||||
size_t upperBound = module_->callSites.length();
|
||||
|
||||
size_t match;
|
||||
if (!BinarySearch(CallSiteRetAddrOffset(callSites_), lowerBound, upperBound, target, &match))
|
||||
if (!BinarySearch(CallSiteRetAddrOffset(module_->callSites), lowerBound, upperBound, target, &match))
|
||||
return nullptr;
|
||||
|
||||
return &callSites_[match];
|
||||
return &module_->callSites[match];
|
||||
}
|
||||
|
||||
const CodeRange*
|
||||
|
@ -874,13 +897,13 @@ Module::lookupCodeRange(void* pc) const
|
|||
{
|
||||
CodeRange::PC target((uint8_t*)pc - code());
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = codeRanges_.length();
|
||||
size_t upperBound = module_->codeRanges.length();
|
||||
|
||||
size_t match;
|
||||
if (!BinarySearch(codeRanges_, lowerBound, upperBound, target, &match))
|
||||
if (!BinarySearch(module_->codeRanges, lowerBound, upperBound, target, &match))
|
||||
return nullptr;
|
||||
|
||||
return &codeRanges_[match];
|
||||
return &module_->codeRanges[match];
|
||||
}
|
||||
|
||||
struct HeapAccessOffset
|
||||
|
@ -899,13 +922,13 @@ Module::lookupHeapAccess(void* pc) const
|
|||
|
||||
uint32_t target = ((uint8_t*)pc) - code();
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = heapAccesses_.length();
|
||||
size_t upperBound = module_->heapAccesses.length();
|
||||
|
||||
size_t match;
|
||||
if (!BinarySearch(HeapAccessOffset(heapAccesses_), lowerBound, upperBound, target, &match))
|
||||
if (!BinarySearch(HeapAccessOffset(module_->heapAccesses), lowerBound, upperBound, target, &match))
|
||||
return nullptr;
|
||||
|
||||
return &heapAccesses_[match];
|
||||
return &module_->heapAccesses[match];
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -920,7 +943,7 @@ Module::staticallyLink(ExclusiveContext* cx, const StaticLinkData& linkData)
|
|||
JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
|
||||
MOZ_ASSERT(IsCompilingAsmJS());
|
||||
AutoFlushICache afc("Module::staticallyLink", /* inhibit = */ true);
|
||||
AutoFlushICache::setRange(uintptr_t(code()), pod.codeBytes_);
|
||||
AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
|
||||
|
||||
interrupt_ = code() + linkData.pod.interruptOffset;
|
||||
outOfBounds_ = code() + linkData.pod.outOfBoundsOffset;
|
||||
|
@ -983,7 +1006,7 @@ Module::staticallyLink(ExclusiveContext* cx, const StaticLinkData& linkData)
|
|||
|
||||
bool
|
||||
Module::dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> heap,
|
||||
const AutoVectorRooter<JSFunction*>& imports)
|
||||
const AutoVectorRooter<JSFunction*>& importArgs)
|
||||
{
|
||||
MOZ_ASSERT(staticallyLinked_);
|
||||
MOZ_ASSERT(!dynamicallyLinked_);
|
||||
|
@ -994,15 +1017,15 @@ Module::dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> hea
|
|||
JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
|
||||
MOZ_ASSERT(IsCompilingAsmJS());
|
||||
AutoFlushICache afc("Module::dynamicallyLink");
|
||||
AutoFlushICache::setRange(uintptr_t(code()), pod.codeBytes_);
|
||||
AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
|
||||
|
||||
// Initialize imports with actual imported values.
|
||||
MOZ_ASSERT(imports.length() == imports_.length());
|
||||
for (size_t i = 0; i < imports_.length(); i++) {
|
||||
const Import& import = imports_[i];
|
||||
MOZ_ASSERT(importArgs.length() == imports().length());
|
||||
for (size_t i = 0; i < imports().length(); i++) {
|
||||
const Import& import = imports()[i];
|
||||
ImportExit& exit = importToExit(import);
|
||||
exit.code = code() + import.interpExitCodeOffset();
|
||||
exit.fun = imports[i];
|
||||
exit.fun = importArgs[i];
|
||||
exit.baselineScript = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1011,7 +1034,7 @@ Module::dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> hea
|
|||
specializeToHeap(heap);
|
||||
|
||||
// See AllocateCode comment above.
|
||||
if (!ExecutableAllocator::makeExecutable(code(), pod.codeBytes_)) {
|
||||
if (!ExecutableAllocator::makeExecutable(code(), codeBytes())) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
@ -1043,7 +1066,7 @@ void
|
|||
Module::deoptimizeImportExit(uint32_t importIndex)
|
||||
{
|
||||
MOZ_ASSERT(dynamicallyLinked_);
|
||||
const Import& import = imports_[importIndex];
|
||||
const Import& import = imports()[importIndex];
|
||||
ImportExit& exit = importToExit(import);
|
||||
exit.code = code() + import.interpExitCodeOffset();
|
||||
exit.baselineScript = nullptr;
|
||||
|
@ -1054,7 +1077,7 @@ Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
|
|||
{
|
||||
MOZ_ASSERT(dynamicallyLinked_);
|
||||
|
||||
const Export& exp = exports_[exportIndex];
|
||||
const Export& exp = exports()[exportIndex];
|
||||
|
||||
// Enable/disable profiling in the Module to match the current global
|
||||
// profiling state. Don't do this if the Module is already active on the
|
||||
|
@ -1190,7 +1213,7 @@ Module::callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const Val
|
|||
{
|
||||
MOZ_ASSERT(dynamicallyLinked_);
|
||||
|
||||
const Import& import = imports_[importIndex];
|
||||
const Import& import = imports()[importIndex];
|
||||
|
||||
RootedValue fval(cx, ObjectValue(*importToExit(import).fun));
|
||||
if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval))
|
||||
|
@ -1264,211 +1287,93 @@ Module::profilingLabel(uint32_t funcIndex) const
|
|||
return funcLabels_[funcIndex].get();
|
||||
}
|
||||
|
||||
size_t
|
||||
Module::serializedSize() const
|
||||
void
|
||||
Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
|
||||
{
|
||||
return sizeof(pod) +
|
||||
pod.codeBytes_ +
|
||||
SerializedVectorSize(imports_) +
|
||||
SerializedVectorSize(exports_) +
|
||||
SerializedPodVectorSize(heapAccesses_) +
|
||||
SerializedPodVectorSize(codeRanges_) +
|
||||
SerializedPodVectorSize(callSites_) +
|
||||
SerializedVectorSize(funcNames_) +
|
||||
filename_.serializedSize() +
|
||||
displayURL_.serializedSize();
|
||||
*code += codeBytes();
|
||||
*data += mallocSizeOf(this) +
|
||||
globalBytes() +
|
||||
mallocSizeOf(module_.get()) +
|
||||
module_->sizeOfExcludingThis(mallocSizeOf) +
|
||||
funcPtrTables_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
SizeOfVectorExcludingThis(funcLabels_, mallocSizeOf);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
Module::serialize(uint8_t* cursor) const
|
||||
{
|
||||
MOZ_ASSERT(!profilingEnabled_, "assumed by Module::deserialize");
|
||||
const Class WasmModuleObject::class_ = {
|
||||
"WasmModuleObject",
|
||||
JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_CALLBACK |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS),
|
||||
nullptr, /* addProperty */
|
||||
nullptr, /* delProperty */
|
||||
nullptr, /* getProperty */
|
||||
nullptr, /* setProperty */
|
||||
nullptr, /* enumerate */
|
||||
nullptr, /* resolve */
|
||||
nullptr, /* mayResolve */
|
||||
WasmModuleObject::finalize,
|
||||
nullptr, /* call */
|
||||
nullptr, /* hasInstance */
|
||||
nullptr, /* construct */
|
||||
WasmModuleObject::trace
|
||||
};
|
||||
|
||||
cursor = WriteBytes(cursor, &pod, sizeof(pod));
|
||||
cursor = WriteBytes(cursor, code(), pod.codeBytes_);
|
||||
cursor = SerializeVector(cursor, imports_);
|
||||
cursor = SerializeVector(cursor, exports_);
|
||||
cursor = SerializePodVector(cursor, heapAccesses_);
|
||||
cursor = SerializePodVector(cursor, codeRanges_);
|
||||
cursor = SerializePodVector(cursor, callSites_);
|
||||
cursor = SerializeVector(cursor, funcNames_);
|
||||
cursor = filename_.serialize(cursor);
|
||||
cursor = displayURL_.serialize(cursor);
|
||||
return cursor;
|
||||
bool
|
||||
WasmModuleObject::hasModule() const
|
||||
{
|
||||
MOZ_ASSERT(is<WasmModuleObject>());
|
||||
return !getReservedSlot(MODULE_SLOT).isUndefined();
|
||||
}
|
||||
|
||||
/* static */ const uint8_t*
|
||||
Module::deserialize(ExclusiveContext* cx, const uint8_t* cursor, UniqueModule* out)
|
||||
/* static */ void
|
||||
WasmModuleObject::finalize(FreeOp* fop, JSObject* obj)
|
||||
{
|
||||
CacheablePod pod = zeroPod();
|
||||
cursor = ReadBytes(cursor, &pod, sizeof(pod));
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
UniqueCodePtr code = AllocateCode(cx, pod.codeBytes_ + pod.globalBytes_);
|
||||
if (!code)
|
||||
return nullptr;
|
||||
|
||||
cursor = ReadBytes(cursor, code.get(), pod.codeBytes_);
|
||||
|
||||
ImportVector imports;
|
||||
cursor = DeserializeVector(cx, cursor, &imports);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
ExportVector exports;
|
||||
cursor = DeserializeVector(cx, cursor, &exports);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
HeapAccessVector heapAccesses;
|
||||
cursor = DeserializePodVector(cx, cursor, &heapAccesses);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
CodeRangeVector codeRanges;
|
||||
cursor = DeserializePodVector(cx, cursor, &codeRanges);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
CallSiteVector callSites;
|
||||
cursor = DeserializePodVector(cx, cursor, &callSites);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
CacheableCharsVector funcNames;
|
||||
cursor = DeserializeVector(cx, cursor, &funcNames);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
CacheableChars filename;
|
||||
cursor = filename.deserialize(cx, cursor);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
CacheableTwoByteChars displayURL;
|
||||
cursor = displayURL.deserialize(cx, cursor);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
*out = cx->make_unique<Module>(pod,
|
||||
Move(code),
|
||||
Move(imports),
|
||||
Move(exports),
|
||||
Move(heapAccesses),
|
||||
Move(codeRanges),
|
||||
Move(callSites),
|
||||
Move(funcNames),
|
||||
Move(filename),
|
||||
Move(displayURL),
|
||||
Module::LoadedFromCache,
|
||||
Module::ProfilingDisabled,
|
||||
FuncLabelVector());
|
||||
|
||||
return cursor;
|
||||
WasmModuleObject& moduleObj = obj->as<WasmModuleObject>();
|
||||
if (moduleObj.hasModule())
|
||||
fop->delete_(&moduleObj.module());
|
||||
}
|
||||
|
||||
Module::UniqueModule
|
||||
Module::clone(JSContext* cx, const StaticLinkData& linkData) const
|
||||
/* static */ void
|
||||
WasmModuleObject::trace(JSTracer* trc, JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(dynamicallyLinked_);
|
||||
WasmModuleObject& moduleObj = obj->as<WasmModuleObject>();
|
||||
if (moduleObj.hasModule())
|
||||
moduleObj.module().trace(trc);
|
||||
}
|
||||
|
||||
UniqueCodePtr code = AllocateCode(cx, totalBytes());
|
||||
if (!code)
|
||||
/* static */ WasmModuleObject*
|
||||
WasmModuleObject::create(ExclusiveContext* cx)
|
||||
{
|
||||
AutoSetNewObjectMetadata metadata(cx);
|
||||
JSObject* obj = NewObjectWithGivenProto(cx, &WasmModuleObject::class_, nullptr);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
memcpy(code.get(), this->code(), pod.codeBytes_);
|
||||
return &obj->as<WasmModuleObject>();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Put the symbolic links back to -1 so PatchDataWithValueCheck assertions
|
||||
// in Module::staticallyLink are valid.
|
||||
for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
|
||||
void* callee = AddressOf(imm, cx);
|
||||
const StaticLinkData::OffsetVector& offsets = linkData.symbolicLinks[imm];
|
||||
for (uint32_t offset : offsets) {
|
||||
jit::Assembler::PatchDataWithValueCheck(jit::CodeLocationLabel(code.get() + offset),
|
||||
jit::PatchedImmPtr((void*)-1),
|
||||
jit::PatchedImmPtr(callee));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
bool
|
||||
WasmModuleObject::init(Module* module)
|
||||
{
|
||||
MOZ_ASSERT(is<WasmModuleObject>());
|
||||
MOZ_ASSERT(!hasModule());
|
||||
if (!module)
|
||||
return false;
|
||||
setReservedSlot(MODULE_SLOT, PrivateValue(module));
|
||||
return true;
|
||||
}
|
||||
|
||||
ImportVector imports;
|
||||
if (!CloneVector(cx, imports_, &imports))
|
||||
return nullptr;
|
||||
|
||||
ExportVector exports;
|
||||
if (!CloneVector(cx, exports_, &exports))
|
||||
return nullptr;
|
||||
|
||||
HeapAccessVector heapAccesses;
|
||||
if (!ClonePodVector(cx, heapAccesses_, &heapAccesses))
|
||||
return nullptr;
|
||||
|
||||
CodeRangeVector codeRanges;
|
||||
if (!ClonePodVector(cx, codeRanges_, &codeRanges))
|
||||
return nullptr;
|
||||
|
||||
CallSiteVector callSites;
|
||||
if (!ClonePodVector(cx, callSites_, &callSites))
|
||||
return nullptr;
|
||||
|
||||
CacheableCharsVector funcNames;
|
||||
if (!CloneVector(cx, funcNames_, &funcNames))
|
||||
return nullptr;
|
||||
|
||||
CacheableChars filename;
|
||||
if (!filename_.clone(cx, &filename))
|
||||
return nullptr;
|
||||
|
||||
CacheableTwoByteChars displayURL;
|
||||
if (!displayURL_.clone(cx, &displayURL))
|
||||
return nullptr;
|
||||
|
||||
FuncLabelVector funcLabels;
|
||||
if (!CloneVector(cx, funcLabels_, &funcLabels))
|
||||
return nullptr;
|
||||
|
||||
// Must not GC between Module allocation and (successful) return.
|
||||
auto out = cx->make_unique<Module>(pod,
|
||||
Move(code),
|
||||
Move(imports),
|
||||
Move(exports),
|
||||
Move(heapAccesses),
|
||||
Move(codeRanges),
|
||||
Move(callSites),
|
||||
Move(funcNames),
|
||||
Move(filename),
|
||||
Move(displayURL),
|
||||
CacheBool::NotLoadedFromCache,
|
||||
ProfilingBool(profilingEnabled_),
|
||||
Move(funcLabels));
|
||||
if (!out)
|
||||
return nullptr;
|
||||
|
||||
// If the copied machine code has been specialized to the heap, it must be
|
||||
// unspecialized in the copy.
|
||||
if (usesHeap())
|
||||
out->despecializeFromHeap(heap_);
|
||||
|
||||
if (!out->staticallyLink(cx, linkData))
|
||||
return nullptr;
|
||||
|
||||
return Move(out);
|
||||
Module&
|
||||
WasmModuleObject::module() const
|
||||
{
|
||||
MOZ_ASSERT(is<WasmModuleObject>());
|
||||
MOZ_ASSERT(hasModule());
|
||||
return *(Module*)getReservedSlot(MODULE_SLOT).toPrivate();
|
||||
}
|
||||
|
||||
void
|
||||
Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* asmJSModuleCode, size_t* asmJSModuleData)
|
||||
WasmModuleObject::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
|
||||
{
|
||||
*asmJSModuleCode += pod.codeBytes_;
|
||||
*asmJSModuleData += mallocSizeOf(this) +
|
||||
pod.globalBytes_ +
|
||||
SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
|
||||
SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
|
||||
heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
codeRanges_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
callSites_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
funcNames_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
funcPtrTables_.sizeOfExcludingThis(mallocSizeOf);
|
||||
if (hasModule())
|
||||
module().addSizeOfMisc(mallocSizeOf, code, data);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
class AsmJSModule;
|
||||
class WasmActivation;
|
||||
namespace jit { struct BaselineScript; }
|
||||
|
||||
|
@ -34,8 +35,7 @@ namespace wasm {
|
|||
// deserialization and cloning. Some data can be simply copied as raw bytes and,
|
||||
// as a convention, is stored in an inline CacheablePod struct. Everything else
|
||||
// should implement the below methods which are called recusively by the
|
||||
// containing Module. The implementation of all these methods are grouped
|
||||
// together in WasmSerialize.cpp.
|
||||
// containing Module. See comments for these methods in wasm::Module.
|
||||
|
||||
#define WASM_DECLARE_SERIALIZABLE(Type) \
|
||||
size_t serializedSize() const; \
|
||||
|
@ -103,16 +103,14 @@ class Export
|
|||
{
|
||||
MallocSig sig_;
|
||||
struct CacheablePod {
|
||||
uint32_t funcIndex_;
|
||||
uint32_t stubOffset_;
|
||||
} pod;
|
||||
|
||||
public:
|
||||
Export() = default;
|
||||
Export(MallocSig&& sig, uint32_t funcIndex)
|
||||
explicit Export(MallocSig&& sig)
|
||||
: sig_(Move(sig))
|
||||
{
|
||||
pod.funcIndex_ = funcIndex;
|
||||
pod.stubOffset_ = UINT32_MAX;
|
||||
}
|
||||
Export(Export&& rhs)
|
||||
|
@ -125,9 +123,6 @@ class Export
|
|||
pod.stubOffset_ = stubOffset;
|
||||
}
|
||||
|
||||
uint32_t funcIndex() const {
|
||||
return pod.funcIndex_;
|
||||
}
|
||||
uint32_t stubOffset() const {
|
||||
return pod.stubOffset_;
|
||||
}
|
||||
|
@ -317,6 +312,7 @@ class CodeDeleter
|
|||
{
|
||||
uint32_t bytes_;
|
||||
public:
|
||||
CodeDeleter() : bytes_(0) {}
|
||||
explicit CodeDeleter(uint32_t bytes) : bytes_(bytes) {}
|
||||
void operator()(uint8_t* p);
|
||||
};
|
||||
|
@ -341,6 +337,55 @@ UsesHeap(HeapUsage heapUsage)
|
|||
return bool(heapUsage);
|
||||
}
|
||||
|
||||
// See mutedErrors comment in jsapi.h.
|
||||
|
||||
enum class MutedErrorsBool
|
||||
{
|
||||
DontMuteErrors = false,
|
||||
MuteErrors = true
|
||||
};
|
||||
|
||||
// ModuleCacheablePod holds the trivially-memcpy()able serializable portion of
|
||||
// ModuleData.
|
||||
|
||||
struct ModuleCacheablePod
|
||||
{
|
||||
uint32_t functionBytes;
|
||||
uint32_t codeBytes;
|
||||
uint32_t globalBytes;
|
||||
HeapUsage heapUsage;
|
||||
MutedErrorsBool mutedErrors;
|
||||
CompileArgs compileArgs;
|
||||
|
||||
uint32_t totalBytes() const { return codeBytes + globalBytes; }
|
||||
};
|
||||
|
||||
// ModuleData holds the guts of a Module. ModuleData is mutably built up by
|
||||
// ModuleGenerator and then handed over to the Module constructor in finish(),
|
||||
// where it is stored immutably.
|
||||
|
||||
struct ModuleData : ModuleCacheablePod
|
||||
{
|
||||
ModuleData() : loadedFromCache(false) { mozilla::PodZero(&pod()); }
|
||||
ModuleCacheablePod& pod() { return *this; }
|
||||
const ModuleCacheablePod& pod() const { return *this; }
|
||||
|
||||
UniqueCodePtr code;
|
||||
ImportVector imports;
|
||||
ExportVector exports;
|
||||
HeapAccessVector heapAccesses;
|
||||
CodeRangeVector codeRanges;
|
||||
CallSiteVector callSites;
|
||||
CacheableCharsVector funcNames;
|
||||
CacheableChars filename;
|
||||
CacheableTwoByteChars displayURL;
|
||||
bool loadedFromCache;
|
||||
|
||||
WASM_DECLARE_SERIALIZABLE(ModuleData);
|
||||
};
|
||||
|
||||
typedef UniquePtr<ModuleData, JS::DeletePolicy<ModuleData>> UniqueModuleData;
|
||||
|
||||
// Module represents a compiled WebAssembly module which lives until the last
|
||||
// reference to any exported functions is dropped. Modules must be wrapped by a
|
||||
// rooted JSObject immediately after creation so that Module::trace() is called
|
||||
|
@ -363,6 +408,7 @@ UsesHeap(HeapUsage heapUsage)
|
|||
|
||||
class Module
|
||||
{
|
||||
typedef UniquePtr<const ModuleData, JS::DeletePolicy<const ModuleData>> UniqueConstModuleData;
|
||||
struct ImportExit {
|
||||
void* code;
|
||||
jit::BaselineScript* baselineScript;
|
||||
|
@ -387,25 +433,8 @@ class Module
|
|||
typedef RelocatablePtrArrayBufferObjectMaybeShared BufferPtr;
|
||||
|
||||
// Initialized when constructed:
|
||||
struct CacheablePod {
|
||||
const uint32_t functionBytes_;
|
||||
const uint32_t codeBytes_;
|
||||
const uint32_t globalBytes_;
|
||||
const HeapUsage heapUsage_;
|
||||
const bool mutedErrors_;
|
||||
const bool usesSignalHandlersForOOB_;
|
||||
const bool usesSignalHandlersForInterrupt_;
|
||||
} pod;
|
||||
const UniqueCodePtr code_;
|
||||
const ImportVector imports_;
|
||||
const ExportVector exports_;
|
||||
const HeapAccessVector heapAccesses_;
|
||||
const CodeRangeVector codeRanges_;
|
||||
const CallSiteVector callSites_;
|
||||
const CacheableCharsVector funcNames_;
|
||||
const CacheableChars filename_;
|
||||
const CacheableTwoByteChars displayURL_;
|
||||
const bool loadedFromCache_;
|
||||
const UniqueConstModuleData module_;
|
||||
bool isAsmJS_;
|
||||
|
||||
// Initialized during staticallyLink:
|
||||
bool staticallyLinked_;
|
||||
|
@ -421,9 +450,6 @@ class Module
|
|||
bool profilingEnabled_;
|
||||
FuncLabelVector funcLabels_;
|
||||
|
||||
class AutoMutateCode;
|
||||
|
||||
uint32_t totalBytes() const;
|
||||
uint8_t* rawHeapPtr() const;
|
||||
uint8_t*& rawHeapPtr();
|
||||
WasmActivation*& activation();
|
||||
|
@ -433,70 +459,50 @@ class Module
|
|||
MOZ_WARN_UNUSED_RESULT bool setProfilingEnabled(JSContext* cx, bool enabled);
|
||||
ImportExit& importToExit(const Import& import);
|
||||
|
||||
enum CacheBool { NotLoadedFromCache = false, LoadedFromCache = true };
|
||||
enum ProfilingBool { ProfilingDisabled = false, ProfilingEnabled = true };
|
||||
|
||||
static CacheablePod zeroPod();
|
||||
void init();
|
||||
Module(const CacheablePod& pod,
|
||||
UniqueCodePtr code,
|
||||
ImportVector&& imports,
|
||||
ExportVector&& exports,
|
||||
HeapAccessVector&& heapAccesses,
|
||||
CodeRangeVector&& codeRanges,
|
||||
CallSiteVector&& callSites,
|
||||
CacheableCharsVector&& funcNames,
|
||||
CacheableChars filename,
|
||||
CacheableTwoByteChars displayURL,
|
||||
CacheBool loadedFromCache,
|
||||
ProfilingBool profilingEnabled,
|
||||
FuncLabelVector&& funcLabels);
|
||||
|
||||
template <class> friend struct js::MallocProvider;
|
||||
friend class js::WasmActivation;
|
||||
|
||||
protected:
|
||||
enum AsmJSBool { NotAsmJS = false, IsAsmJS = true };
|
||||
const ModuleData& base() const { return *module_; }
|
||||
bool clone(JSContext* cx, const StaticLinkData& link, Module* clone) const;
|
||||
|
||||
public:
|
||||
static const unsigned SizeOfImportExit = sizeof(ImportExit);
|
||||
static const unsigned OffsetOfImportExitFun = offsetof(ImportExit, fun);
|
||||
static const unsigned SizeOfEntryArg = sizeof(EntryArg);
|
||||
|
||||
enum MutedBool { DontMuteErrors = false, MuteErrors = true };
|
||||
explicit Module(UniqueModuleData module, AsmJSBool = NotAsmJS);
|
||||
virtual ~Module();
|
||||
virtual void trace(JSTracer* trc);
|
||||
virtual void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
|
||||
|
||||
Module(CompileArgs args,
|
||||
uint32_t functionBytes,
|
||||
uint32_t codeBytes,
|
||||
uint32_t globalBytes,
|
||||
HeapUsage heapUsage,
|
||||
MutedBool mutedErrors,
|
||||
UniqueCodePtr code,
|
||||
ImportVector&& imports,
|
||||
ExportVector&& exports,
|
||||
HeapAccessVector&& heapAccesses,
|
||||
CodeRangeVector&& codeRanges,
|
||||
CallSiteVector&& callSites,
|
||||
CacheableCharsVector&& funcNames,
|
||||
CacheableChars filename,
|
||||
CacheableTwoByteChars displayURL);
|
||||
~Module();
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
uint8_t* code() const { return code_.get(); }
|
||||
uint8_t* globalData() const { return code() + pod.codeBytes_; }
|
||||
uint32_t globalBytes() const { return pod.globalBytes_; }
|
||||
HeapUsage heapUsage() const { return pod.heapUsage_; }
|
||||
bool usesHeap() const { return UsesHeap(pod.heapUsage_); }
|
||||
bool hasSharedHeap() const { return pod.heapUsage_ == HeapUsage::Shared; }
|
||||
bool mutedErrors() const { return pod.mutedErrors_; }
|
||||
CompileArgs compileArgs() const;
|
||||
const ImportVector& imports() const { return imports_; }
|
||||
const ExportVector& exports() const { return exports_; }
|
||||
const char* functionName(uint32_t i) const { return funcNames_[i].get(); }
|
||||
const char* filename() const { return filename_.get(); }
|
||||
const char16_t* displayURL() const { return displayURL_.get(); }
|
||||
bool loadedFromCache() const { return loadedFromCache_; }
|
||||
uint8_t* code() const { return module_->code.get(); }
|
||||
uint32_t codeBytes() const { return module_->codeBytes; }
|
||||
uint8_t* globalData() const { return code() + module_->codeBytes; }
|
||||
uint32_t globalBytes() const { return module_->globalBytes; }
|
||||
HeapUsage heapUsage() const { return module_->heapUsage; }
|
||||
bool usesHeap() const { return UsesHeap(module_->heapUsage); }
|
||||
bool hasSharedHeap() const { return module_->heapUsage == HeapUsage::Shared; }
|
||||
bool mutedErrors() const { return bool(module_->mutedErrors); }
|
||||
CompileArgs compileArgs() const { return module_->compileArgs; }
|
||||
const ImportVector& imports() const { return module_->imports; }
|
||||
const ExportVector& exports() const { return module_->exports; }
|
||||
const char* functionName(uint32_t i) const { return module_->funcNames[i].get(); }
|
||||
const char* filename() const { return module_->filename.get(); }
|
||||
const char16_t* displayURL() const { return module_->displayURL.get(); }
|
||||
bool loadedFromCache() const { return module_->loadedFromCache; }
|
||||
bool staticallyLinked() const { return staticallyLinked_; }
|
||||
bool dynamicallyLinked() const { return dynamicallyLinked_; }
|
||||
|
||||
// Some wasm::Module's have the most-derived type AsmJSModule. The
|
||||
// AsmJSModule stores the extra metadata necessary to implement asm.js (JS)
|
||||
// semantics. The asAsmJS() member may be used as a checked downcast when
|
||||
// isAsmJS() is true.
|
||||
|
||||
bool isAsmJS() const { return isAsmJS_; }
|
||||
AsmJSModule& asAsmJS() { MOZ_ASSERT(isAsmJS_); return *(AsmJSModule*)this; }
|
||||
const AsmJSModule& asAsmJS() const { MOZ_ASSERT(isAsmJS_); return *(const AsmJSModule*)this; }
|
||||
|
||||
// The range [0, functionBytes) is a subrange of [0, codeBytes) that
|
||||
// contains only function body code, not the stub code. This distinction is
|
||||
// used by the async interrupt handler to only interrupt when the pc is in
|
||||
|
@ -513,7 +519,7 @@ class Module
|
|||
// statically-linked state. The given StaticLinkData must have come from the
|
||||
// compilation of this module.
|
||||
|
||||
bool staticallyLink(ExclusiveContext* cx, const StaticLinkData& linkData);
|
||||
bool staticallyLink(ExclusiveContext* cx, const StaticLinkData& link);
|
||||
|
||||
// This function transitions the module from a statically-linked state to a
|
||||
// dynamically-linked state. If this module usesHeap(), a non-null heap
|
||||
|
@ -558,19 +564,32 @@ class Module
|
|||
|
||||
bool profilingEnabled() const { return profilingEnabled_; }
|
||||
const char* profilingLabel(uint32_t funcIndex) const;
|
||||
};
|
||||
|
||||
// See WASM_DECLARE_SERIALIZABLE.
|
||||
size_t serializedSize() const;
|
||||
uint8_t* serialize(uint8_t* cursor) const;
|
||||
typedef UniquePtr<Module, JS::DeletePolicy<Module>> UniqueModule;
|
||||
static const uint8_t* deserialize(ExclusiveContext* cx, const uint8_t* cursor,
|
||||
UniqueModule* out);
|
||||
UniqueModule clone(JSContext* cx, const StaticLinkData& linkData) const;
|
||||
void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* asmJSModuleCode,
|
||||
size_t* asmJSModuleData);
|
||||
typedef UniquePtr<Module, JS::DeletePolicy<Module>> UniqueModule;
|
||||
|
||||
} // namespace wasm
|
||||
|
||||
// An WasmModuleObject is an internal object (i.e., not exposed directly to user
|
||||
// code) which traces and owns a wasm::Module. The WasmModuleObject is
|
||||
// referenced by the extended slots of exported JSFunctions and serves to keep
|
||||
// the wasm::Module alive until its last GC reference is dead.
|
||||
|
||||
class WasmModuleObject : public NativeObject
|
||||
{
|
||||
static const unsigned MODULE_SLOT = 0;
|
||||
bool hasModule() const;
|
||||
static void finalize(FreeOp* fop, JSObject* obj);
|
||||
static void trace(JSTracer* trc, JSObject* obj);
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 1;
|
||||
static WasmModuleObject* create(ExclusiveContext* cx);
|
||||
bool init(wasm::Module* module);
|
||||
wasm::Module& module() const;
|
||||
void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
|
||||
static const Class class_;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
} // namespace wasm
|
||||
|
||||
#endif // wasm_module_h
|
||||
|
|
|
@ -262,7 +262,7 @@ GenerateEntry(ModuleGenerator& mg, unsigned exportIndex, bool usesHeap)
|
|||
MOZ_CRASH("no int64 in asm.js");
|
||||
case ExprType::F32:
|
||||
masm.convertFloat32ToDouble(ReturnFloat32Reg, ReturnDoubleReg);
|
||||
// Fall through as ReturnDoubleReg now contains a Double
|
||||
MOZ_FALLTHROUGH; // as ReturnDoubleReg now contains a Double
|
||||
case ExprType::F64:
|
||||
masm.canonicalizeDouble(ReturnDoubleReg);
|
||||
masm.storeDouble(ReturnDoubleReg, Address(argv, 0));
|
||||
|
|
|
@ -2448,7 +2448,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
|
|||
pn = pn->pn_expr;
|
||||
if (!pn->isKind(PNK_STATEMENTLIST))
|
||||
return statement(pn, dst);
|
||||
/* FALL THROUGH */
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case PNK_STATEMENTLIST:
|
||||
return blockStatement(pn, dst);
|
||||
|
|
|
@ -4059,7 +4059,8 @@ CType::Finalize(JSFreeOp* fop, JSObject* obj)
|
|||
}
|
||||
}
|
||||
|
||||
// Fall through.
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case TYPE_array: {
|
||||
// Free the ffi_type info.
|
||||
slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
|
||||
|
@ -5508,7 +5509,7 @@ PostBarrierCallback(JSTracer* trc, JSString* key, void* data)
|
|||
|
||||
UnbarrieredFieldInfoHash* table = reinterpret_cast<UnbarrieredFieldInfoHash*>(data);
|
||||
JSString* prior = key;
|
||||
JS_CallUnbarrieredStringTracer(trc, &key, "CType fieldName");
|
||||
js::UnsafeTraceManuallyBarrieredEdge(trc, &key, "CType fieldName");
|
||||
table->rekeyIfMoved(JS_ASSERT_STRING_IS_FLAT(prior), JS_ASSERT_STRING_IS_FLAT(key));
|
||||
}
|
||||
|
||||
|
|
|
@ -2108,6 +2108,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
|||
// Any subexpression of a comma expression could be effectful.
|
||||
case PNK_COMMA:
|
||||
MOZ_ASSERT(pn->pn_count > 0);
|
||||
MOZ_FALLTHROUGH;
|
||||
// Subcomponents of a literal may be effectful.
|
||||
case PNK_ARRAY:
|
||||
case PNK_OBJECT:
|
||||
|
@ -8802,7 +8803,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
|
|||
break;
|
||||
|
||||
case PNK_POSHOLDER:
|
||||
MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER");
|
||||
MOZ_FALLTHROUGH_ASSERT("Should never try to emit PNK_POSHOLDER");
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(0);
|
||||
|
|
|
@ -156,7 +156,7 @@ class NameResolver
|
|||
* flagged as a contributor.
|
||||
*/
|
||||
pos--;
|
||||
/* fallthrough */
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
default:
|
||||
/* Save any other nodes we encounter on the way up. */
|
||||
|
@ -727,8 +727,8 @@ class NameResolver
|
|||
// Import/export spec lists contain import/export specs containing
|
||||
// only pairs of names. Alternatively, an export spec lists may
|
||||
// contain a single export batch specifier.
|
||||
case PNK_IMPORT_SPEC_LIST: {
|
||||
case PNK_EXPORT_SPEC_LIST:
|
||||
case PNK_IMPORT_SPEC_LIST: {
|
||||
MOZ_ASSERT(cur->isArity(PN_LIST));
|
||||
#ifdef DEBUG
|
||||
bool isImport = cur->isKind(PNK_IMPORT_SPEC_LIST);
|
||||
|
|
|
@ -6356,7 +6356,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
|
|||
case TOK_MUL:
|
||||
kind = PNK_YIELD_STAR;
|
||||
tokenStream.consumeKnownToken(TOK_MUL, TokenStream::Operand);
|
||||
// Fall through.
|
||||
MOZ_FALLTHROUGH;
|
||||
default:
|
||||
exprNode = assignExpr(inHandling, YieldIsKeyword, TripledotProhibited);
|
||||
if (!exprNode)
|
||||
|
@ -6388,7 +6388,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
|
|||
JSMSG_BAD_ANON_GENERATOR_RETURN);
|
||||
return null();
|
||||
}
|
||||
// Fall through.
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case LegacyGenerator:
|
||||
{
|
||||
|
@ -6659,7 +6659,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
|
|||
// check its validity for legacy generators.
|
||||
if (!checkYieldNameValidity())
|
||||
return null();
|
||||
// Fall through.
|
||||
MOZ_FALLTHROUGH;
|
||||
case TOK_NAME:
|
||||
{
|
||||
RootedPropertyName label(context, tokenStream.currentName());
|
||||
|
@ -9121,7 +9121,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
|
|||
case TOK_YIELD:
|
||||
if (!checkYieldNameValidity())
|
||||
return null();
|
||||
// Fall through.
|
||||
MOZ_FALLTHROUGH;
|
||||
case TOK_NAME:
|
||||
return identifierName(yieldHandling);
|
||||
|
||||
|
|
|
@ -414,6 +414,16 @@ JS::TraceNullableEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name)
|
|||
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::TraceNullableEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* thingp, const char* name)
|
||||
{
|
||||
MOZ_ASSERT(thingp);
|
||||
if (JSObject* ptr = thingp->getPtr()) {
|
||||
DispatchToTracer(trc, &ptr, name);
|
||||
thingp->setPtr(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
|
||||
|
@ -421,6 +431,13 @@ js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
|
|||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JS_PUBLIC_API(void)
|
||||
js::UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceWeakEdge(JSTracer* trc, WeakRef<T>* thingp, const char* name)
|
||||
|
@ -441,6 +458,13 @@ js::TraceRoot(JSTracer* trc, T* thingp, const char* name)
|
|||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JS_PUBLIC_API(void)
|
||||
JS::UnsafeTraceRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
js::TraceRoot(trc, thingp, name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
|
@ -506,7 +530,10 @@ FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
|
|||
#define INSTANTIATE_PUBLIC_TRACE_FUNCTIONS(type) \
|
||||
template JS_PUBLIC_API(void) JS::TraceEdge<type>(JSTracer*, JS::Heap<type>*, const char*); \
|
||||
template JS_PUBLIC_API(void) JS::TraceNullableEdge<type>(JSTracer*, JS::Heap<type>*, \
|
||||
const char*);
|
||||
const char*); \
|
||||
template JS_PUBLIC_API(void) JS::UnsafeTraceRoot<type>(JSTracer*, type*, const char*); \
|
||||
template JS_PUBLIC_API(void) js::UnsafeTraceManuallyBarrieredEdge<type>(JSTracer*, type*, \
|
||||
const char*);
|
||||
FOR_EACH_PUBLIC_GC_POINTER_TYPE(INSTANTIATE_PUBLIC_TRACE_FUNCTIONS)
|
||||
#undef INSTANTIATE_PUBLIC_TRACE_FUNCTIONS
|
||||
|
||||
|
|
|
@ -105,48 +105,6 @@ JS::CallbackTracer::getTracingEdgeName(char* buffer, size_t bufferSize)
|
|||
|
||||
/*** Public Tracing API **************************************************************************/
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredValueTracer(JSTracer* trc, Value* valuep, const char* name)
|
||||
{
|
||||
TraceManuallyBarrieredEdge(trc, valuep, name);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredIdTracer(JSTracer* trc, jsid* idp, const char* name)
|
||||
{
|
||||
TraceManuallyBarrieredEdge(trc, idp, name);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, const char* name)
|
||||
{
|
||||
TraceManuallyBarrieredEdge(trc, objp, name);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredStringTracer(JSTracer* trc, JSString** strp, const char* name)
|
||||
{
|
||||
TraceManuallyBarrieredEdge(trc, strp, name);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredScriptTracer(JSTracer* trc, JSScript** scriptp, const char* name)
|
||||
{
|
||||
TraceManuallyBarrieredEdge(trc, scriptp, name);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, const char* name)
|
||||
{
|
||||
JSObject* obj = objp->getPtr();
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
TraceManuallyBarrieredEdge(trc, &obj, name);
|
||||
|
||||
objp->setPtr(obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::TraceChildren(JSTracer* trc, GCCellPtr thing)
|
||||
{
|
||||
|
|
|
@ -3815,7 +3815,7 @@ EmitAtomLetter(RegExpCompiler* compiler,
|
|||
}
|
||||
case 4:
|
||||
macro_assembler->CheckCharacter(chars[3], &ok);
|
||||
// Fall through!
|
||||
MOZ_FALLTHROUGH;
|
||||
case 3:
|
||||
macro_assembler->CheckCharacter(chars[0], &ok);
|
||||
macro_assembler->CheckCharacter(chars[1], &ok);
|
||||
|
|
|
@ -1563,7 +1563,7 @@ RegExpParser<CharT>::ParseDisjunction()
|
|||
Advance();
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
MOZ_FALLTHROUGH;
|
||||
case 'd': case 's': case 'w': {
|
||||
widechar c = Next();
|
||||
Advance(2);
|
||||
|
@ -1605,8 +1605,8 @@ RegExpParser<CharT>::ParseDisjunction()
|
|||
Advance(2);
|
||||
break;
|
||||
}
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
// FALLTHROUGH
|
||||
case '0': {
|
||||
if (unicode_) {
|
||||
Advance(2);
|
||||
|
@ -1735,7 +1735,7 @@ RegExpParser<CharT>::ParseDisjunction()
|
|||
int dummy;
|
||||
if (ParseIntervalQuantifier(&dummy, &dummy))
|
||||
return ReportError(JSMSG_NOTHING_TO_REPEAT);
|
||||
// fallthrough
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
default:
|
||||
if (unicode_) {
|
||||
|
|
|
@ -2481,6 +2481,7 @@ BacktrackingAllocator::computeSpillWeight(LiveBundle* bundle)
|
|||
|
||||
case LUse::FIXED:
|
||||
fixed = true;
|
||||
MOZ_FALLTHROUGH;
|
||||
case LUse::REGISTER:
|
||||
usesTotal += 2000;
|
||||
break;
|
||||
|
|
|
@ -1913,7 +1913,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
|
|||
// Invalid assumption based on baseline code.
|
||||
case Bailout_OverflowInvalidate:
|
||||
outerScript->setHadOverflowBailout();
|
||||
// FALL THROUGH
|
||||
MOZ_FALLTHROUGH;
|
||||
case Bailout_NonStringInputInvalidate:
|
||||
case Bailout_DoubleOutput:
|
||||
case Bailout_ObjectIdentityOrTypeGuard:
|
||||
|
|
|
@ -1173,6 +1173,7 @@ RemoveExistingGetElemNativeStubs(JSContext* cx, ICGetElem_Fallback* stub, Handle
|
|||
case ICStub::GetElem_NativeSlotSymbol:
|
||||
if (indirect)
|
||||
continue;
|
||||
MOZ_FALLTHROUGH;
|
||||
case ICStub::GetElem_NativePrototypeSlotName:
|
||||
case ICStub::GetElem_NativePrototypeSlotSymbol:
|
||||
case ICStub::GetElem_NativePrototypeCallNativeName:
|
||||
|
|
|
@ -721,6 +721,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
|
|||
case JSOP_MOD:
|
||||
case JSOP_NEG:
|
||||
type = inspector->expectedResultType(last);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1549,7 +1550,7 @@ IonBuilder::traverseBytecode()
|
|||
MOZ_ASSERT(i == 0);
|
||||
if (current->peek(-1) == popped[0])
|
||||
break;
|
||||
// FALL THROUGH
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(popped[i]->isImplicitlyUsed() ||
|
||||
|
@ -1940,6 +1941,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
|||
return pushConstant(ObjectValue(*scope));
|
||||
}
|
||||
// Fall through to JSOP_BINDNAME
|
||||
MOZ_FALLTHROUGH;
|
||||
case JSOP_BINDNAME:
|
||||
return jsop_bindname(info().getName(pc));
|
||||
|
||||
|
|
|
@ -923,6 +923,7 @@ class JitcodeGlobalEntry
|
|||
break;
|
||||
case IonCache:
|
||||
markedAny |= ionCacheEntry().mark<ShouldMarkProvider>(trc);
|
||||
break;
|
||||
case Dummy:
|
||||
break;
|
||||
default:
|
||||
|
@ -941,6 +942,7 @@ class JitcodeGlobalEntry
|
|||
break;
|
||||
case IonCache:
|
||||
ionCacheEntry().sweepChildren(rt);
|
||||
break;
|
||||
case Dummy:
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1815,7 +1815,7 @@ LIRGenerator::visitToDouble(MToDouble* convert)
|
|||
|
||||
case MIRType_Boolean:
|
||||
MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
|
||||
/* FALLTHROUGH */
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case MIRType_Int32:
|
||||
{
|
||||
|
@ -1871,7 +1871,7 @@ LIRGenerator::visitToFloat32(MToFloat32* convert)
|
|||
|
||||
case MIRType_Boolean:
|
||||
MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
|
||||
/* FALLTHROUGH */
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case MIRType_Int32:
|
||||
{
|
||||
|
|
|
@ -2236,6 +2236,7 @@ CanProduceNegativeZero(MDefinition* def) {
|
|||
case MDefinition::Op_Constant:
|
||||
if (def->type() == MIRType_Double && def->constantValue().toDouble() == -0.0)
|
||||
return true;
|
||||
MOZ_FALLTHROUGH;
|
||||
case MDefinition::Op_BitAnd:
|
||||
case MDefinition::Op_BitOr:
|
||||
case MDefinition::Op_BitXor:
|
||||
|
@ -2314,7 +2315,7 @@ NeedNegativeZeroCheck(MDefinition* def)
|
|||
if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs))
|
||||
return true;
|
||||
|
||||
/* Fall through... */
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
case MDefinition::Op_StoreElement:
|
||||
case MDefinition::Op_StoreElementHole:
|
||||
|
@ -3093,7 +3094,7 @@ MTypeOf::foldsTo(TempAllocator& alloc)
|
|||
type = JSTYPE_OBJECT;
|
||||
break;
|
||||
}
|
||||
// FALL THROUGH
|
||||
MOZ_FALLTHROUGH;
|
||||
default:
|
||||
return this;
|
||||
}
|
||||
|
@ -3378,9 +3379,10 @@ MToInt32::foldsTo(TempAllocator& alloc)
|
|||
case MIRType_Float32:
|
||||
case MIRType_Double:
|
||||
int32_t ival;
|
||||
// Only the value within the range of Int32 can be substitued as constant.
|
||||
// Only the value within the range of Int32 can be substituted as constant.
|
||||
if (mozilla::NumberEqualsInt32(val.toNumber(), &ival))
|
||||
return MConstant::New(alloc, Int32Value(ival));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче