зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge on a CLOSED TREE
This commit is contained in:
Коммит
69ae5fe098
|
@ -121,4 +121,5 @@ jobs:
|
|||
by-project:
|
||||
# No default branch
|
||||
mozilla-central:
|
||||
- {hour: 10, minute: 0}
|
||||
- {weekday: 'Monday', hour: 10, minute: 0}
|
||||
- {weekday: 'Thursday', hour: 10, minute: 0}
|
||||
|
|
|
@ -592,7 +592,7 @@ TextAttrsMgr::FontStyleTextAttr::
|
|||
|
||||
TextAttrsMgr::FontWeightTextAttr::
|
||||
FontWeightTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
|
||||
TTextAttr<int32_t>(!aFrame)
|
||||
TTextAttr<FontWeight>(!aFrame)
|
||||
{
|
||||
mRootNativeValue = GetFontWeight(aRootFrame);
|
||||
mIsRootDefined = true;
|
||||
|
@ -605,7 +605,7 @@ TextAttrsMgr::FontWeightTextAttr::
|
|||
|
||||
bool
|
||||
TextAttrsMgr::FontWeightTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, int32_t* aValue)
|
||||
GetValueFor(Accessible* aAccessible, FontWeight* aValue)
|
||||
{
|
||||
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
if (elm) {
|
||||
|
@ -620,15 +620,16 @@ TextAttrsMgr::FontWeightTextAttr::
|
|||
|
||||
void
|
||||
TextAttrsMgr::FontWeightTextAttr::
|
||||
ExposeValue(nsIPersistentProperties* aAttributes, const int32_t& aValue)
|
||||
ExposeValue(nsIPersistentProperties* aAttributes,
|
||||
const FontWeight& aValue)
|
||||
{
|
||||
nsAutoString formattedValue;
|
||||
formattedValue.AppendInt(aValue);
|
||||
formattedValue.AppendFloat(aValue.ToFloat());
|
||||
|
||||
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::fontWeight, formattedValue);
|
||||
}
|
||||
|
||||
int32_t
|
||||
FontWeight
|
||||
TextAttrsMgr::FontWeightTextAttr::
|
||||
GetFontWeight(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -645,8 +646,9 @@ TextAttrsMgr::FontWeightTextAttr::
|
|||
// bold font, i.e. synthetic bolding is used. IsSyntheticBold method is only
|
||||
// needed on Mac, but it is "safe" to use on all platforms. (For non-Mac
|
||||
// platforms it always return false.)
|
||||
if (font->IsSyntheticBold())
|
||||
return 700;
|
||||
if (font->IsSyntheticBold()) {
|
||||
return FontWeight::Bold();
|
||||
}
|
||||
|
||||
// On Windows, font->GetStyle()->weight will give the same weight as
|
||||
// fontEntry->Weight(), the weight of the first font in the font group,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef nsTextAttrs_h_
|
||||
#define nsTextAttrs_h_
|
||||
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsString.h"
|
||||
|
@ -354,7 +355,7 @@ protected:
|
|||
/**
|
||||
* Class is used for the work with "font-weight" text attribute.
|
||||
*/
|
||||
class FontWeightTextAttr : public TTextAttr<int32_t>
|
||||
class FontWeightTextAttr : public TTextAttr<mozilla::FontWeight>
|
||||
{
|
||||
public:
|
||||
FontWeightTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
|
||||
|
@ -363,13 +364,14 @@ protected:
|
|||
protected:
|
||||
|
||||
// TTextAttr
|
||||
virtual bool GetValueFor(Accessible* aAccessible, int32_t* aValue)
|
||||
virtual bool GetValueFor(Accessible* aAccessible,
|
||||
mozilla::FontWeight* aValue)
|
||||
override;
|
||||
virtual void ExposeValue(nsIPersistentProperties* aAttributes,
|
||||
const int32_t& aValue) override;
|
||||
const mozilla::FontWeight& aValue) override;
|
||||
|
||||
private:
|
||||
int32_t GetFontWeight(nsIFrame* aFrame);
|
||||
mozilla::FontWeight GetFontWeight(nsIFrame* aFrame);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -144,6 +144,7 @@ support-files =
|
|||
[browser_dbg-async-stepping.js]
|
||||
[browser_dbg-babel-breakpoint-console.js]
|
||||
[browser_dbg-babel-scopes.js]
|
||||
skip-if = ccov # Bug 1441545
|
||||
[browser_dbg-babel-stepping.js]
|
||||
[browser_dbg-babel-preview.js]
|
||||
skip-if = (os == "win" && ccov) # Bug 1448523
|
||||
|
|
|
@ -82,6 +82,7 @@ skip-if = os == 'win' || debug # Bug 1282269, 1448084
|
|||
[browser_toolbox_keyboard_navigation.js]
|
||||
skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
|
||||
[browser_toolbox_options.js]
|
||||
[browser_toolbox_options_multiple_tabs.js]
|
||||
[browser_toolbox_options_disable_buttons.js]
|
||||
[browser_toolbox_options_disable_cache-01.js]
|
||||
[browser_toolbox_options_disable_cache-02.js]
|
||||
|
|
|
@ -332,11 +332,16 @@ async function testToggleWebExtensions() {
|
|||
"There should not be any checkbox for the unregistered WebExtensions");
|
||||
}
|
||||
|
||||
function getToolNode(id) {
|
||||
return panelWin.document.getElementById(id);
|
||||
}
|
||||
|
||||
async function testToggleTools() {
|
||||
let toolNodes = panelWin.document.querySelectorAll(
|
||||
"#default-tools-box input[type=checkbox]:not([data-unsupported])," +
|
||||
"#additional-tools-box input[type=checkbox]:not([data-unsupported])");
|
||||
let enabledTools = [...toolNodes].filter(node => node.checked);
|
||||
let toolNodeIds = [...toolNodes].map(node => node.id);
|
||||
let enabledToolIds = [...toolNodes].filter(node => node.checked).map(node => node.id);
|
||||
|
||||
let toggleableTools = gDevTools.getDefaultTools()
|
||||
.filter(tool => {
|
||||
|
@ -358,39 +363,43 @@ async function testToggleTools() {
|
|||
}
|
||||
|
||||
// Toggle each tool
|
||||
for (let node of toolNodes) {
|
||||
await toggleTool(node);
|
||||
for (let id of toolNodeIds) {
|
||||
await toggleTool(getToolNode(id));
|
||||
}
|
||||
|
||||
// Toggle again to reset tool enablement state
|
||||
for (let node of toolNodes) {
|
||||
await toggleTool(node);
|
||||
for (let id of toolNodeIds) {
|
||||
await toggleTool(getToolNode(id));
|
||||
}
|
||||
|
||||
// Test that a tool can still be added when no tabs are present:
|
||||
// Disable all tools
|
||||
for (let node of enabledTools) {
|
||||
await toggleTool(node);
|
||||
for (let id of enabledToolIds) {
|
||||
await toggleTool(getToolNode(id));
|
||||
}
|
||||
// Re-enable the tools which are enabled by default
|
||||
for (let node of enabledTools) {
|
||||
await toggleTool(node);
|
||||
for (let id of enabledToolIds) {
|
||||
await toggleTool(getToolNode(id));
|
||||
}
|
||||
|
||||
// Toggle first, middle, and last tools to ensure that toolbox tabs are
|
||||
// inserted in order
|
||||
let firstTool = toolNodes[0];
|
||||
let middleTool = toolNodes[(toolNodes.length / 2) | 0];
|
||||
let lastTool = toolNodes[toolNodes.length - 1];
|
||||
let firstToolId = toolNodeIds[0];
|
||||
let middleToolId = toolNodeIds[(toolNodeIds.length / 2) | 0];
|
||||
let lastToolId = toolNodeIds[toolNodeIds.length - 1];
|
||||
|
||||
await toggleTool(firstTool);
|
||||
await toggleTool(firstTool);
|
||||
await toggleTool(middleTool);
|
||||
await toggleTool(middleTool);
|
||||
await toggleTool(lastTool);
|
||||
await toggleTool(lastTool);
|
||||
await toggleTool(getToolNode(firstToolId));
|
||||
await toggleTool(getToolNode(firstToolId));
|
||||
await toggleTool(getToolNode(middleToolId));
|
||||
await toggleTool(getToolNode(middleToolId));
|
||||
await toggleTool(getToolNode(lastToolId));
|
||||
await toggleTool(getToolNode(lastToolId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle tool node checkbox. Note: because toggling the checkbox will result in
|
||||
* re-rendering of the tool list, we must re-query the checkboxes every time.
|
||||
*/
|
||||
async function toggleTool(node) {
|
||||
let deferred = defer();
|
||||
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const URL = "data:text/html;charset=utf8,test for dynamically registering " +
|
||||
"and unregistering tools across multiple tabs";
|
||||
|
||||
let tab1, tab2, modifiedPref;
|
||||
|
||||
add_task(async function() {
|
||||
tab1 = await openToolboxOptionsInNewTab();
|
||||
tab2 = await openToolboxOptionsInNewTab();
|
||||
|
||||
await testToggleTools();
|
||||
await cleanup();
|
||||
});
|
||||
|
||||
async function openToolboxOptionsInNewTab() {
|
||||
const tab = await addTab(URL);
|
||||
const target = TargetFactory.forTab(tab);
|
||||
const toolbox = await gDevTools.showToolbox(target);
|
||||
const doc = toolbox.doc;
|
||||
const panel = await toolbox.selectTool("options");
|
||||
const { id } = panel.panelDoc.querySelector(
|
||||
"#default-tools-box input[type=checkbox]:not([data-unsupported]):not([checked])");
|
||||
|
||||
return {
|
||||
tab,
|
||||
toolbox,
|
||||
doc,
|
||||
panelWin: panel.panelWin,
|
||||
// This is a getter becuse toolbox tools list gets re-setup every time there
|
||||
// is a tool-registered or tool-undregistered event.
|
||||
get checkbox() {
|
||||
return panel.panelDoc.getElementById(id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function testToggleTools() {
|
||||
is(tab1.checkbox.id, tab2.checkbox.id, "Default tool box should be in sync.");
|
||||
|
||||
const toolId = tab1.checkbox.id;
|
||||
const testTool = gDevTools.getDefaultTools().find(tool => tool.id === toolId);
|
||||
// Store modified pref names so that they can be cleared on error.
|
||||
modifiedPref = testTool.visibilityswitch;
|
||||
|
||||
info(`Registering tool ${toolId} in the first tab.`);
|
||||
await toggleTool(tab1, toolId);
|
||||
|
||||
info(`Unregistering tool ${toolId} in the first tab.`);
|
||||
await toggleTool(tab1, toolId);
|
||||
|
||||
info(`Registering tool ${toolId} in the second tab.`);
|
||||
await toggleTool(tab2, toolId);
|
||||
|
||||
info(`Unregistering tool ${toolId} in the second tab.`);
|
||||
await toggleTool(tab2, toolId);
|
||||
|
||||
info(`Registering tool ${toolId} in the first tab.`);
|
||||
await toggleTool(tab1, toolId);
|
||||
|
||||
info(`Unregistering tool ${toolId} in the second tab.`);
|
||||
await toggleTool(tab2, toolId);
|
||||
}
|
||||
|
||||
async function toggleTool({ doc, panelWin, checkbox, tab }, toolId) {
|
||||
const prevChecked = checkbox.checked;
|
||||
|
||||
(prevChecked ? checkRegistered : checkUnregistered)(toolId);
|
||||
|
||||
const onToggleTool = gDevTools.once(
|
||||
`tool-${prevChecked ? "unregistered" : "registered"}`);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, checkbox, panelWin);
|
||||
const id = await onToggleTool;
|
||||
|
||||
is(id, toolId, `Correct event for ${toolId} was fired`);
|
||||
// await new Promise(resolve => setTimeout(resolve, 60000));
|
||||
(prevChecked ? checkUnregistered : checkRegistered)(toolId);
|
||||
}
|
||||
|
||||
async function checkUnregistered(toolId) {
|
||||
ok(!tab1.doc.getElementById("toolbox-tab-" + toolId),
|
||||
`Tab for unregistered tool ${toolId} is not present in first toolbox`);
|
||||
ok(!tab1.checkbox.checked,
|
||||
`Checkbox for unregistered tool ${toolId} is not checked in first toolbox`);
|
||||
ok(!tab2.doc.getElementById("toolbox-tab-" + toolId),
|
||||
`Tab for unregistered tool ${toolId} is not present in second toolbox`);
|
||||
ok(!tab2.checkbox.checked,
|
||||
`Checkbox for unregistered tool ${toolId} is not checked in second toolbox`);
|
||||
}
|
||||
|
||||
function checkRegistered(toolId) {
|
||||
ok(tab1.doc.getElementById("toolbox-tab-" + toolId),
|
||||
`Tab for registered tool ${toolId} is present in first toolbox`);
|
||||
ok(tab1.checkbox.checked,
|
||||
`Checkbox for registered tool ${toolId} is checked in first toolbox`);
|
||||
ok(tab2.doc.getElementById("toolbox-tab-" + toolId),
|
||||
`Tab for registered tool ${toolId} is present in second toolbox`);
|
||||
ok(tab2.checkbox.checked,
|
||||
`Checkbox for registered tool ${toolId} is checked in second toolbox`);
|
||||
}
|
||||
|
||||
async function cleanup() {
|
||||
await tab1.toolbox.destroy();
|
||||
await tab2.toolbox.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
gBrowser.removeCurrentTab();
|
||||
Services.prefs.clearUserPref(modifiedPref);
|
||||
tab1 = tab2 = modifiedPref = null;
|
||||
}
|
|
@ -61,11 +61,10 @@ function OptionsPanel(iframeWindow, toolbox) {
|
|||
this.toolbox = toolbox;
|
||||
this.isReady = false;
|
||||
|
||||
this.setupToolsList = this.setupToolsList.bind(this);
|
||||
this._prefChanged = this._prefChanged.bind(this);
|
||||
this._themeRegistered = this._themeRegistered.bind(this);
|
||||
this._themeUnregistered = this._themeUnregistered.bind(this);
|
||||
this._webExtensionRegistered = this._webExtensionRegistered.bind(this);
|
||||
this._webExtensionUnregistered = this._webExtensionUnregistered.bind(this);
|
||||
this._disableJSClicked = this._disableJSClicked.bind(this);
|
||||
|
||||
this.disableJSNode = this.panelDoc.getElementById("devtools-disable-javascript");
|
||||
|
@ -106,8 +105,14 @@ OptionsPanel.prototype = {
|
|||
gDevTools.on("theme-registered", this._themeRegistered);
|
||||
gDevTools.on("theme-unregistered", this._themeUnregistered);
|
||||
|
||||
this.toolbox.on("webextension-registered", this._webExtensionRegistered);
|
||||
this.toolbox.on("webextension-unregistered", this._webExtensionUnregistered);
|
||||
// Refresh the tools list when a new tool or webextension has been
|
||||
// registered to the toolbox.
|
||||
this.toolbox.on("tool-registered", this.setupToolsList);
|
||||
this.toolbox.on("webextension-registered", this.setupToolsList);
|
||||
// Refresh the tools list when a new tool or webextension has been
|
||||
// unregistered from the toolbox.
|
||||
this.toolbox.on("tool-unregistered", this.setupToolsList);
|
||||
this.toolbox.on("webextension-unregistered", this.setupToolsList);
|
||||
},
|
||||
|
||||
_removeListeners: function() {
|
||||
|
@ -116,8 +121,10 @@ OptionsPanel.prototype = {
|
|||
Services.prefs.removeObserver("devtools.source-map.client-service.enabled",
|
||||
this._prefChanged);
|
||||
|
||||
this.toolbox.off("webextension-registered", this._webExtensionRegistered);
|
||||
this.toolbox.off("webextension-unregistered", this._webExtensionUnregistered);
|
||||
this.toolbox.off("tool-registered", this.setupToolsList);
|
||||
this.toolbox.off("tool-unregistered", this.setupToolsList);
|
||||
this.toolbox.off("webextension-registered", this.setupToolsList);
|
||||
this.toolbox.off("webextension-unregistered", this.setupToolsList);
|
||||
|
||||
gDevTools.off("theme-registered", this._themeRegistered);
|
||||
gDevTools.off("theme-unregistered", this._themeUnregistered);
|
||||
|
@ -148,18 +155,6 @@ OptionsPanel.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_webExtensionRegistered: function(extensionUUID) {
|
||||
// Refresh the tools list when a new webextension has been registered
|
||||
// to the toolbox.
|
||||
this.setupToolsList();
|
||||
},
|
||||
|
||||
_webExtensionUnregistered: function(extensionUUID) {
|
||||
// Refresh the tools list when a new webextension has been unregistered
|
||||
// from the toolbox.
|
||||
this.setupToolsList();
|
||||
},
|
||||
|
||||
async setupToolbarButtonsList() {
|
||||
// Ensure the toolbox is open, and the buttons are all set up.
|
||||
await this.toolbox.isOpen;
|
||||
|
|
|
@ -380,8 +380,20 @@ IPCBlobInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
|
|||
|
||||
// We have the remote inputStream, let's check if we can execute the callback.
|
||||
case eRunning: {
|
||||
MutexAutoLock lock(mMutex);
|
||||
return MaybeExecuteInputStreamCallback(aCallback, aEventTarget, lock);
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mInputStreamCallback = aCallback;
|
||||
mInputStreamCallbackEventTarget = aEventTarget;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureAsyncRemoteStream();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mAsyncRemoteStream);
|
||||
return mAsyncRemoteStream->AsyncWait(aCallback ? this : nullptr,
|
||||
0, 0, aEventTarget);
|
||||
}
|
||||
|
||||
// Stream is closed.
|
||||
|
@ -435,64 +447,28 @@ IPCBlobInputStream::StreamReady(already_AddRefed<nsIInputStream> aInputStream)
|
|||
this);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> inputStreamCallback = this;
|
||||
nsCOMPtr<nsIEventTarget> inputStreamCallbackEventTarget;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> inputStreamCallback;
|
||||
inputStreamCallback.swap(mInputStreamCallback);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> inputStreamCallbackEventTarget;
|
||||
inputStreamCallbackEventTarget.swap(mInputStreamCallbackEventTarget);
|
||||
|
||||
if (inputStreamCallback) {
|
||||
MaybeExecuteInputStreamCallback(inputStreamCallback,
|
||||
inputStreamCallbackEventTarget,
|
||||
lock);
|
||||
inputStreamCallbackEventTarget = mInputStreamCallbackEventTarget;
|
||||
if (!mInputStreamCallback) {
|
||||
inputStreamCallback = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
IPCBlobInputStream::MaybeExecuteInputStreamCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aCallbackEventTarget,
|
||||
const MutexAutoLock& aProofOfLock)
|
||||
{
|
||||
MOZ_ASSERT(mState == eRunning);
|
||||
MOZ_ASSERT(mRemoteStream || mAsyncRemoteStream);
|
||||
|
||||
// If the callback has been already set, we return an error.
|
||||
if (mInputStreamCallback && aCallback) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool hadCallback = !!mInputStreamCallback;
|
||||
|
||||
mInputStreamCallback = aCallback;
|
||||
mInputStreamCallbackEventTarget = aCallbackEventTarget;
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> callback = this;
|
||||
|
||||
if (!mInputStreamCallback) {
|
||||
if (!hadCallback) {
|
||||
// Nothing was pending.
|
||||
return NS_OK;
|
||||
if (inputStreamCallback) {
|
||||
nsresult rv = EnsureAsyncRemoteStream();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's set a null callback in order to abort the current operation.
|
||||
callback = nullptr;
|
||||
MOZ_ASSERT(mAsyncRemoteStream);
|
||||
|
||||
rv = mAsyncRemoteStream->AsyncWait(inputStreamCallback, 0, 0,
|
||||
inputStreamCallbackEventTarget);
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
// We don't need to be locked anymore.
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
nsresult rv = EnsureAsyncRemoteStream();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mAsyncRemoteStream);
|
||||
|
||||
return mAsyncRemoteStream->AsyncWait(callback, 0, 0, aCallbackEventTarget);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -44,11 +44,6 @@ public:
|
|||
private:
|
||||
~IPCBlobInputStream();
|
||||
|
||||
nsresult
|
||||
MaybeExecuteInputStreamCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget,
|
||||
const MutexAutoLock& aProofOfLock);
|
||||
|
||||
nsresult
|
||||
EnsureAsyncRemoteStream();
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ struct FontListEntry {
|
|||
nsString familyName;
|
||||
nsString faceName;
|
||||
nsCString filepath;
|
||||
uint16_t weight;
|
||||
float weight;
|
||||
int16_t stretch;
|
||||
uint8_t italic;
|
||||
uint8_t index;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "nsMathMLElement.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsITableCellLayout.h" // for MAX_COLSPAN / MAX_ROWSPAN
|
||||
#include "nsCRT.h"
|
||||
|
@ -726,10 +727,10 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
|
|||
str.CompressWhitespace();
|
||||
if (str.EqualsASCII("normal")) {
|
||||
aData->SetKeywordValue(eCSSProperty_font_weight,
|
||||
NS_FONT_WEIGHT_NORMAL);
|
||||
FontWeight::Normal().ToFloat());
|
||||
} else if (str.EqualsASCII("bold")) {
|
||||
aData->SetKeywordValue(eCSSProperty_font_weight,
|
||||
NS_FONT_WEIGHT_BOLD);
|
||||
FontWeight::Bold().ToFloat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -645,11 +645,11 @@ public:
|
|||
|
||||
// Set size of buffer, allocating memory as required.
|
||||
// If size is increased, new buffer area is filled with 0.
|
||||
bool SetSize(size_t aSize);
|
||||
MOZ_MUST_USE bool SetSize(size_t aSize);
|
||||
// Add aData at the beginning of buffer.
|
||||
bool Prepend(const uint8_t* aData, size_t aSize);
|
||||
MOZ_MUST_USE bool Prepend(const uint8_t* aData, size_t aSize);
|
||||
// Replace current content with aData.
|
||||
bool Replace(const uint8_t* aData, size_t aSize);
|
||||
MOZ_MUST_USE bool Replace(const uint8_t* aData, size_t aSize);
|
||||
// Clear the memory buffer. Will set target mData and mSize to 0.
|
||||
void Clear();
|
||||
// Remove aSize bytes from the front of the sample.
|
||||
|
@ -658,7 +658,7 @@ public:
|
|||
private:
|
||||
friend class MediaRawData;
|
||||
explicit MediaRawDataWriter(MediaRawData* aMediaRawData);
|
||||
bool EnsureSize(size_t aSize);
|
||||
MOZ_MUST_USE bool EnsureSize(size_t aSize);
|
||||
MediaRawData* mTarget;
|
||||
};
|
||||
|
||||
|
|
|
@ -3054,6 +3054,22 @@ ScriptLoader::NumberOfProcessors()
|
|||
return mNumberOfProcessors;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsInternalURIScheme(nsIURI* uri)
|
||||
{
|
||||
bool isWebExt;
|
||||
if (NS_SUCCEEDED(uri->SchemeIs("moz-extension", &isWebExt)) && isWebExt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isResource;
|
||||
if (NS_SUCCEEDED(uri->SchemeIs("resource", &isResource)) && isResource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
|
||||
nsIIncrementalStreamLoader* aLoader,
|
||||
|
@ -3142,10 +3158,9 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
|
|||
rv = channel->GetOriginalURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Fixup moz-extension URIs, because the channel URI points to file:,
|
||||
// which won't be allowed to load.
|
||||
bool isWebExt = false;
|
||||
if (uri && NS_SUCCEEDED(uri->SchemeIs("moz-extension", &isWebExt)) && isWebExt) {
|
||||
// Fixup moz-extension: and resource: URIs, because the channel URI will
|
||||
// point to file:, which won't be allowed to load.
|
||||
if (uri && IsInternalURIScheme(uri)) {
|
||||
request->mBaseURL = uri;
|
||||
} else {
|
||||
channel->GetURI(getter_AddRefs(request->mBaseURL));
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
// Custom *.sjs file specifically for the needs of Bug 1453814
|
||||
|
||||
// small red image
|
||||
const IMG_BYTES = atob(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
|
||||
"P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==");
|
||||
|
||||
const FRAME = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1453814 - Do not allow same-site cookies for cross origin redirect</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
let cookie = document.cookie;
|
||||
// now reset the cookie for the next test
|
||||
document.cookie = "myKey=;" + "expires=Thu, 01 Jan 1970 00:00:00 GMT";
|
||||
window.parent.postMessage({result: cookie}, 'http://mochi.test:8888');
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const SAME_ORIGIN = "http://mochi.test:8888/"
|
||||
const CROSS_ORIGIN = "http://example.com/";
|
||||
const PATH = "tests/dom/security/test/general/file_same_site_cookies_redirect.sjs";
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
if (request.queryString === "setSameSiteCookie") {
|
||||
response.setHeader("Set-Cookie", "myKey=strictSameSiteCookie; samesite=strict", true);
|
||||
response.setHeader("Content-Type", "image/png");
|
||||
response.write(IMG_BYTES);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.queryString === "sameToCrossRedirect") {
|
||||
let URL = CROSS_ORIGIN + PATH + "?loadFrame";
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", URL, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.queryString === "crossToSameRedirect") {
|
||||
let URL = SAME_ORIGIN + PATH + "?loadFrame";
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", URL, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.queryString === "loadFrame") {
|
||||
response.write(FRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
// we should never get here, but just in case return something unexpected
|
||||
response.write("D'oh");
|
||||
}
|
|
@ -12,6 +12,7 @@ support-files =
|
|||
file_same_site_cookies_toplevel_nav.sjs
|
||||
file_same_site_cookies_cross_origin_context.sjs
|
||||
file_same_site_cookies_from_script.sjs
|
||||
file_same_site_cookies_redirect.sjs
|
||||
|
||||
[test_contentpolicytype_targeted_link_iframe.html]
|
||||
[test_nosniff.html]
|
||||
|
@ -29,3 +30,4 @@ skip-if = toolkit == 'android'
|
|||
[test_same_site_cookies_toplevel_nav.html]
|
||||
[test_same_site_cookies_cross_origin_context.html]
|
||||
[test_same_site_cookies_from_script.html]
|
||||
[test_same_site_cookies_redirect.html]
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1453814 - Do not allow same-site cookies for cross origin redirect</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<img id="cookieImage">
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/*
|
||||
* Description of the test:
|
||||
* 1) We load an image from http://mochi.test which set a same site cookie
|
||||
* 2) We then load an iframe that redirects
|
||||
* (a) from same-origin to cross-origin
|
||||
* (b) from cross-origin to same-origin
|
||||
* 3) We observe that in both cases same-site cookies should not be send
|
||||
*/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const SAME_ORIGIN = "http://mochi.test:8888/"
|
||||
const CROSS_ORIGIN = "http://example.com/";
|
||||
const PATH = "tests/dom/security/test/general/file_same_site_cookies_redirect.sjs";
|
||||
|
||||
let curTest = 0;
|
||||
|
||||
var tests = [
|
||||
{
|
||||
description: "same-site cookie, redirect same-site to cross-site",
|
||||
imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
|
||||
frameSRC: SAME_ORIGIN + PATH + "?sameToCrossRedirect",
|
||||
result: "", // no cookie should be set
|
||||
},
|
||||
{
|
||||
description: "same-site cookie, redirect cross-site to same-site",
|
||||
imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
|
||||
frameSRC: CROSS_ORIGIN + PATH + "?crossToSameRedirect",
|
||||
result: "", // no cookie should be set
|
||||
},
|
||||
];
|
||||
|
||||
window.addEventListener("message", receiveMessage);
|
||||
function receiveMessage(event) {
|
||||
is(event.data.result, tests[curTest].result, tests[curTest].description);
|
||||
curTest += 1;
|
||||
|
||||
// // lets see if we ran all the tests
|
||||
if (curTest == tests.length) {
|
||||
window.removeEventListener("message", receiveMessage);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
// otherwise it's time to run the next test
|
||||
setCookieAndInitTest();
|
||||
}
|
||||
|
||||
function setupQueryResultAndRunTest() {
|
||||
let testframe = document.getElementById("testframe");
|
||||
testframe.src = tests[curTest].frameSRC;
|
||||
}
|
||||
|
||||
function setCookieAndInitTest() {
|
||||
var cookieImage = document.getElementById("cookieImage");
|
||||
cookieImage.onload = function() {
|
||||
ok(true, "trying to set cookie for test (" + tests[curTest].description + ")");
|
||||
setupQueryResultAndRunTest();
|
||||
}
|
||||
cookieImage.onerror = function() {
|
||||
ok(false, "could not load image for test (" + tests[curTest].description + ")");
|
||||
}
|
||||
cookieImage.src = tests[curTest].imgSRC;
|
||||
}
|
||||
|
||||
// fire up the test
|
||||
setCookieAndInitTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -294,6 +294,9 @@ LoadContextOptions(const char* aPrefName, void* /* aClosure */)
|
|||
.setWasm(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm")))
|
||||
.setWasmBaseline(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm_baselinejit")))
|
||||
.setWasmIon(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm_ionjit")))
|
||||
#ifdef ENABLE_WASM_GC
|
||||
.setWasmGc(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm_gc")))
|
||||
#endif
|
||||
.setThrowOnAsmJSValidationFailure(GetWorkerPref<bool>(
|
||||
NS_LITERAL_CSTRING("throw_on_asmjs_validation_failure")))
|
||||
.setBaseline(GetWorkerPref<bool>(NS_LITERAL_CSTRING("baselinejit")))
|
||||
|
|
|
@ -98,3 +98,6 @@ BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
|||
|
||||
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
|
||||
if CONFIG['NIGHTLY_BUILD']:
|
||||
DEFINES['ENABLE_WASM_GC'] = True
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "Logging.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
@ -84,6 +85,8 @@ private:
|
|||
class DWriteFontFileStream final : public IDWriteFontFileStream
|
||||
{
|
||||
public:
|
||||
explicit DWriteFontFileStream(uint64_t aFontFileKey);
|
||||
|
||||
/**
|
||||
* Used by the FontFileLoader to create a new font stream,
|
||||
* this font stream is created from data in memory. The memory
|
||||
|
@ -92,7 +95,7 @@ public:
|
|||
*
|
||||
* @param aData Font data
|
||||
*/
|
||||
DWriteFontFileStream(uint8_t *aData, uint32_t aSize, uint64_t aFontFileKey);
|
||||
bool Initialize(uint8_t *aData, uint32_t aSize);
|
||||
|
||||
// IUnknown interface
|
||||
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
|
||||
|
@ -135,7 +138,7 @@ public:
|
|||
virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> mData;
|
||||
nsTArray<uint8_t> mData;
|
||||
Atomic<uint32_t> mRefCnt;
|
||||
uint64_t mFontFileKey;
|
||||
|
||||
|
@ -166,13 +169,10 @@ DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
DWriteFontFileStream::DWriteFontFileStream(uint8_t *aData, uint32_t aSize,
|
||||
uint64_t aFontFileKey)
|
||||
DWriteFontFileStream::DWriteFontFileStream(uint64_t aFontFileKey)
|
||||
: mRefCnt(0)
|
||||
, mFontFileKey(aFontFileKey)
|
||||
{
|
||||
mData.resize(aSize);
|
||||
memcpy(&mData.front(), aData, aSize);
|
||||
}
|
||||
|
||||
DWriteFontFileStream::~DWriteFontFileStream()
|
||||
|
@ -181,10 +181,20 @@ DWriteFontFileStream::~DWriteFontFileStream()
|
|||
sFontFileStreams.erase(mFontFileKey);
|
||||
}
|
||||
|
||||
bool
|
||||
DWriteFontFileStream::Initialize(uint8_t *aData, uint32_t aSize)
|
||||
{
|
||||
if (!mData.SetLength(aSize, fallible)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(mData.Elements(), aData, aSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
DWriteFontFileStream::GetFileSize(UINT64 *fileSize)
|
||||
{
|
||||
*fileSize = mData.size();
|
||||
*fileSize = mData.Length();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -201,7 +211,7 @@ DWriteFontFileStream::ReadFileFragment(const void **fragmentStart,
|
|||
void **fragmentContext)
|
||||
{
|
||||
// We are required to do bounds checking.
|
||||
if (fileOffset + fragmentSize > mData.size()) {
|
||||
if (fileOffset + fragmentSize > mData.Length()) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
@ -232,8 +242,12 @@ NativeFontResourceDWrite::Create(uint8_t *aFontData, uint32_t aDataLength,
|
|||
|
||||
sFontFileStreamsMutex.Lock();
|
||||
uint64_t fontFileKey = sNextFontFileKey++;
|
||||
RefPtr<IDWriteFontFileStream> ffsRef =
|
||||
new DWriteFontFileStream(aFontData, aDataLength, fontFileKey);
|
||||
RefPtr<DWriteFontFileStream> ffsRef = new DWriteFontFileStream(fontFileKey);
|
||||
if (!ffsRef->Initialize(aFontData, aDataLength)) {
|
||||
sFontFileStreamsMutex.Unlock();
|
||||
gfxWarning() << "Failed to create DWriteFontFileStream.";
|
||||
return nullptr;
|
||||
}
|
||||
sFontFileStreams[fontFileKey] = ffsRef;
|
||||
sFontFileStreamsMutex.Unlock();
|
||||
|
||||
|
|
|
@ -32,7 +32,10 @@ NativeFontResourceFontconfig::Create(uint8_t *aFontData, uint32_t aDataLength, F
|
|||
if (!aFontData || !aDataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
UniquePtr<uint8_t[]> fontData(new uint8_t[aDataLength]);
|
||||
UniquePtr<uint8_t[]> fontData(new (fallible) uint8_t[aDataLength]);
|
||||
if (!fontData) {
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(fontData.get(), aFontData, aDataLength);
|
||||
|
||||
FT_Face face = Factory::NewFTFaceFromData(aFTLibrary, fontData.get(), aDataLength, 0);
|
||||
|
|
|
@ -137,7 +137,7 @@ ScaledFontDWrite::ScaledFontDWrite(IDWriteFontFace *aFontFace,
|
|||
, mContrast(aContrast)
|
||||
{
|
||||
if (aStyle) {
|
||||
mStyle = SkFontStyle(aStyle->weight,
|
||||
mStyle = SkFontStyle(aStyle->weight.ToIntRounded(),
|
||||
DWriteFontStretchFromStretch(aStyle->stretch),
|
||||
aStyle->style == NS_FONT_STYLE_NORMAL ?
|
||||
SkFontStyle::kUpright_Slant : SkFontStyle::kItalic_Slant);
|
||||
|
|
|
@ -82,17 +82,6 @@ public:
|
|||
void Unmap() override
|
||||
{ }
|
||||
|
||||
bool AddConsumer()
|
||||
{
|
||||
return ++mConsumers == 1;
|
||||
}
|
||||
|
||||
bool RemoveConsumer()
|
||||
{
|
||||
MOZ_ASSERT(mConsumers > 0);
|
||||
return --mConsumers == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t GetDataLength() const
|
||||
{
|
||||
|
@ -105,7 +94,6 @@ private:
|
|||
}
|
||||
|
||||
int32_t mStride;
|
||||
uint32_t mConsumers;
|
||||
IntSize mSize;
|
||||
RefPtr<SharedMemoryBasic> mBuf;
|
||||
SurfaceFormat mFormat;
|
||||
|
|
|
@ -54,44 +54,22 @@ SharedSurfacesParent::Get(const wr::ExternalImageId& aId)
|
|||
return surface.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<DataSourceSurface>
|
||||
SharedSurfacesParent::Acquire(const wr::ExternalImageId& aId)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
if (!sInstance) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurfaceSharedDataWrapper> surface;
|
||||
sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface));
|
||||
|
||||
if (surface) {
|
||||
DebugOnly<bool> rv = surface->AddConsumer();
|
||||
MOZ_ASSERT(!rv);
|
||||
}
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
SharedSurfacesParent::Release(const wr::ExternalImageId& aId)
|
||||
/* static */ void
|
||||
SharedSurfacesParent::Remove(const wr::ExternalImageId& aId)
|
||||
{
|
||||
//MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
if (!sInstance) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t id = wr::AsUint64(aId);
|
||||
RefPtr<SourceSurfaceSharedDataWrapper> surface;
|
||||
sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface));
|
||||
if (!surface) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface->RemoveConsumer()) {
|
||||
sInstance->mSurfaces.Remove(id);
|
||||
}
|
||||
|
||||
return true;
|
||||
sInstance->mSurfaces.Remove(id);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
@ -193,13 +171,5 @@ SharedSurfacesParent::Add(const wr::ExternalImageId& aId,
|
|||
sInstance->mSurfaces.Put(id, surface.forget());
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
SharedSurfacesParent::Remove(const wr::ExternalImageId& aId)
|
||||
{
|
||||
//MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
DebugOnly<bool> rv = Release(aId);
|
||||
MOZ_ASSERT(rv);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -35,16 +35,9 @@ public:
|
|||
static void Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
// Get without increasing the consumer count.
|
||||
static already_AddRefed<gfx::DataSourceSurface>
|
||||
Get(const wr::ExternalImageId& aId);
|
||||
|
||||
// Get but also increase the consumer count. Must call Release after finished.
|
||||
static already_AddRefed<gfx::DataSourceSurface>
|
||||
Acquire(const wr::ExternalImageId& aId);
|
||||
|
||||
static bool Release(const wr::ExternalImageId& aId);
|
||||
|
||||
static void Add(const wr::ExternalImageId& aId,
|
||||
const SurfaceDescriptorShared& aDesc,
|
||||
base::ProcessId aPid);
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
/* font specific types shared by both thebes and layout */
|
||||
|
||||
#ifndef GFX_FONT_PROPERTY_TYPES_H
|
||||
#define GFX_FONT_PROPERTY_TYPES_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/*
|
||||
* This file is separate from gfxFont.h so that layout can include it
|
||||
* without bringing in gfxFont.h and everything it includes.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* A type that will in future encode a value as fixed point.
|
||||
*/
|
||||
class FontFixedPointValue
|
||||
{
|
||||
public:
|
||||
// Ugh. We need a default constructor to allow this type to be used in the
|
||||
// union in nsCSSValue. Furthermore we need the default and copy
|
||||
// constructors to be "trivial" (i.e. the compiler implemented defaults that
|
||||
// do no initialization).
|
||||
// Annoyingly it seems we can't make the default implementations constexpr
|
||||
// (at least in clang). We'd like to do that to allow Thin() et. al. below
|
||||
// to also be constexpr. :/
|
||||
FontFixedPointValue() = default;
|
||||
FontFixedPointValue(const FontFixedPointValue& aOther) = default;
|
||||
|
||||
// Not currently encoded, but it will be in future
|
||||
explicit FontFixedPointValue(int16_t aValue)
|
||||
: mEncoded(aValue)
|
||||
{}
|
||||
|
||||
explicit FontFixedPointValue(int32_t aValue)
|
||||
: mEncoded(aValue)
|
||||
{}
|
||||
|
||||
explicit FontFixedPointValue(float aValue)
|
||||
: mEncoded(int16_t(aValue))
|
||||
{}
|
||||
|
||||
float ToFloat() const {
|
||||
return float(mEncoded);
|
||||
}
|
||||
|
||||
int16_t ToIntRounded() const {
|
||||
return mEncoded;
|
||||
}
|
||||
|
||||
bool operator==(const FontFixedPointValue& aOther) const {
|
||||
return mEncoded == aOther.mEncoded;
|
||||
}
|
||||
|
||||
bool operator!=(const FontFixedPointValue& aOther) const {
|
||||
return mEncoded != aOther.mEncoded;
|
||||
}
|
||||
|
||||
bool operator<(const FontFixedPointValue& aOther) const {
|
||||
return mEncoded < aOther.mEncoded;
|
||||
}
|
||||
|
||||
bool operator<=(const FontFixedPointValue& aOther) const {
|
||||
return mEncoded <= aOther.mEncoded;
|
||||
}
|
||||
|
||||
bool operator>=(const FontFixedPointValue& aOther) const {
|
||||
return mEncoded >= aOther.mEncoded;
|
||||
}
|
||||
|
||||
bool operator>(const FontFixedPointValue& aOther) const {
|
||||
return mEncoded > aOther.mEncoded;
|
||||
}
|
||||
|
||||
int16_t ForHash() const {
|
||||
return mEncoded;
|
||||
}
|
||||
|
||||
protected:
|
||||
int16_t mEncoded;
|
||||
};
|
||||
|
||||
class FontWeight : public FontFixedPointValue
|
||||
{
|
||||
public:
|
||||
// Ugh, to get union in nsCSSValue compiling
|
||||
FontWeight() = default;
|
||||
FontWeight(const FontWeight& aOther) = default;
|
||||
|
||||
// Not currently encoded, but it will be in future
|
||||
explicit FontWeight(int16_t aValue)
|
||||
: FontFixedPointValue(aValue)
|
||||
{}
|
||||
|
||||
explicit FontWeight(int32_t aValue)
|
||||
: FontFixedPointValue(aValue)
|
||||
{}
|
||||
|
||||
explicit FontWeight(float aValue)
|
||||
: FontFixedPointValue(int16_t(aValue))
|
||||
{}
|
||||
|
||||
bool operator==(const FontWeight& aOther) const
|
||||
{
|
||||
return mEncoded == aOther.mEncoded;
|
||||
}
|
||||
|
||||
/// The "distance" between two font weights
|
||||
float operator-(const FontWeight& aOther) const {
|
||||
return this->ToFloat() - aOther.ToFloat();
|
||||
}
|
||||
|
||||
static FontWeight Thin() {
|
||||
return FontWeight{100};
|
||||
}
|
||||
static FontWeight Normal() {
|
||||
return FontWeight{400};
|
||||
}
|
||||
static FontWeight Bold() {
|
||||
return FontWeight{700};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GFX_FONT_PROPERTY_TYPES_H
|
||||
|
|
@ -45,6 +45,7 @@ EXPORTS += [
|
|||
EXPORTS.mozilla += [
|
||||
'AppUnits.h',
|
||||
'ArrayView.h',
|
||||
'FontPropertyTypes.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.gfx += [
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "gfxFontConstants.h" // for NS_FONT_KERNING_AUTO, etc
|
||||
#include "gfxFontFeatures.h"
|
||||
#include "gfxFontVariations.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "nsColor.h" // for nsColor and NS_RGBA
|
||||
#include "nsCoord.h" // for nscoord
|
||||
|
@ -44,6 +45,7 @@ const uint8_t kGenericFont_fantasy = 0x20;
|
|||
|
||||
// Font structure.
|
||||
struct nsFont {
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
|
||||
// list of font families, either named or generic
|
||||
mozilla::FontFamilyList fontlist;
|
||||
|
@ -79,7 +81,7 @@ struct nsFont {
|
|||
nscolor fontSmoothingBackgroundColor = NS_RGBA(0,0,0,0);
|
||||
|
||||
// The weight of the font; see gfxFontConstants.h.
|
||||
uint16_t weight = NS_FONT_WEIGHT_NORMAL;
|
||||
FontWeight weight = FontWeight::Normal();
|
||||
|
||||
// The stretch of the font (the sum of various NS_FONT_STRETCH_*
|
||||
// constants; see gfxFontConstants.h).
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/intl/OSPreferences.h"
|
||||
|
||||
|
@ -219,12 +220,12 @@ gfxDWriteFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
|
|||
|
||||
if (LOG_FONTLIST_ENABLED()) {
|
||||
LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
|
||||
" with style: %s weight: %d stretch: %d psname: %s fullname: %s",
|
||||
" with style: %s weight: %g stretch: %d psname: %s fullname: %s",
|
||||
NS_ConvertUTF16toUTF8(fe->Name()).get(),
|
||||
NS_ConvertUTF16toUTF8(Name()).get(),
|
||||
(fe->IsItalic()) ?
|
||||
"italic" : (fe->IsOblique() ? "oblique" : "normal"),
|
||||
fe->Weight(), fe->Stretch(),
|
||||
fe->Weight().ToFloat(), fe->Stretch(),
|
||||
NS_ConvertUTF16toUTF8(psname).get(),
|
||||
NS_ConvertUTF16toUTF8(fullname).get()));
|
||||
}
|
||||
|
@ -956,7 +957,7 @@ gfxDWriteFontList::GetDefaultFontForPlatform(const gfxFontStyle *aStyle)
|
|||
|
||||
gfxFontEntry *
|
||||
gfxDWriteFontList::LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
{
|
||||
|
@ -980,7 +981,7 @@ gfxDWriteFontList::LookupLocalFont(const nsAString& aFontName,
|
|||
|
||||
gfxFontEntry *
|
||||
gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
@ -1151,12 +1152,12 @@ gfxDWriteFontList::InitFontListForPlatform()
|
|||
if (LOG_FONTLIST_ENABLED()) {
|
||||
gfxFontEntry *fe = faces[i];
|
||||
LOG_FONTLIST(("(fontlist) moved (%s) to family (%s)"
|
||||
" with style: %s weight: %d stretch: %d",
|
||||
" with style: %s weight: %g stretch: %d",
|
||||
NS_ConvertUTF16toUTF8(fe->Name()).get(),
|
||||
NS_ConvertUTF16toUTF8(gillSansMTFamily->Name()).get(),
|
||||
(fe->IsItalic()) ?
|
||||
"italic" : (fe->IsOblique() ? "oblique" : "normal"),
|
||||
fe->Weight(), fe->Stretch()));
|
||||
fe->Weight().ToFloat(), fe->Stretch()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef GFX_DWRITEFONTLIST_H
|
||||
#define GFX_DWRITEFONTLIST_H
|
||||
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "gfxDWriteCommon.h"
|
||||
#include "dwrite_3.h"
|
||||
|
@ -46,6 +47,8 @@ class gfxDWriteFontEntry;
|
|||
class gfxDWriteFontFamily : public gfxFontFamily
|
||||
{
|
||||
public:
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
|
||||
/**
|
||||
* Constructs a new DWriteFont Family.
|
||||
*
|
||||
|
@ -119,7 +122,7 @@ public:
|
|||
|
||||
weight = std::max<uint16_t>(100, weight);
|
||||
weight = std::min<uint16_t>(900, weight);
|
||||
mWeight = weight;
|
||||
mWeight = FontWeight(weight);
|
||||
|
||||
mIsCJK = UNINITIALIZED_VALUE;
|
||||
}
|
||||
|
@ -137,7 +140,7 @@ public:
|
|||
*/
|
||||
gfxDWriteFontEntry(const nsAString& aFaceName,
|
||||
IDWriteFont *aFont,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
: gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
|
||||
|
@ -164,7 +167,7 @@ public:
|
|||
gfxDWriteFontEntry(const nsAString& aFaceName,
|
||||
IDWriteFontFile *aFontFile,
|
||||
IDWriteFontFileStream *aFontFileStream,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
: gfxFontEntry(aFaceName), mFont(nullptr),
|
||||
|
@ -401,12 +404,12 @@ public:
|
|||
gfxFontFamily* CreateFontFamily(const nsAString& aName) const override;
|
||||
|
||||
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle);
|
||||
|
||||
virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "gfxTextRun.h"
|
||||
|
||||
#include "harfbuzz/hb.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
@ -135,7 +136,7 @@ bool
|
|||
gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics)
|
||||
{
|
||||
gfxFontStyle style(mStyle);
|
||||
style.weight = 700;
|
||||
style.weight = FontWeight(700);
|
||||
bool needsBold;
|
||||
|
||||
gfxFontEntry* fe =
|
||||
|
@ -156,7 +157,7 @@ void
|
|||
gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
|
||||
{
|
||||
DWRITE_FONT_METRICS fontMetrics;
|
||||
if (!(mFontEntry->Weight() == 900 &&
|
||||
if (!(mFontEntry->Weight() == FontWeight(900) &&
|
||||
!mFontEntry->IsUserFont() &&
|
||||
mFontEntry->Name().EqualsLiteral("Arial Black") &&
|
||||
GetFakeMetricsForArialBlack(&fontMetrics)))
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
@ -256,7 +257,7 @@ FT2FontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold
|
|||
/* static */
|
||||
FT2FontEntry*
|
||||
FT2FontEntry::CreateFontEntry(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
@ -327,7 +328,9 @@ FT2FontEntry::CreateFontEntry(const FontListEntry& aFLE)
|
|||
FT2FontEntry *fe = new FT2FontEntry(aFLE.faceName());
|
||||
fe->mFilename = aFLE.filepath();
|
||||
fe->mFTFontIndex = aFLE.index();
|
||||
fe->mWeight = aFLE.weight();
|
||||
// The weight transported across IPC is a float, so we need to explicitly
|
||||
// convert it back to a FontWeight.
|
||||
fe->mWeight = FontWeight(aFLE.weight());
|
||||
fe->mStretch = aFLE.stretch();
|
||||
fe->mStyle = (aFLE.italic() ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL);
|
||||
return fe;
|
||||
|
@ -340,7 +343,7 @@ FTFaceIsItalic(FT_Face aFace)
|
|||
return !!(aFace->style_flags & FT_STYLE_FLAG_ITALIC);
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
static FontWeight
|
||||
FTFaceGetWeight(FT_Face aFace)
|
||||
{
|
||||
TT_OS2 *os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(aFace, ft_sfnt_os2));
|
||||
|
@ -368,7 +371,7 @@ FTFaceGetWeight(FT_Face aFace)
|
|||
|
||||
NS_ASSERTION(result >= 100 && result <= 900, "Invalid weight in font!");
|
||||
|
||||
return result;
|
||||
return FontWeight(result);
|
||||
}
|
||||
|
||||
// Used to create the font entry for installed faces on the device,
|
||||
|
@ -661,9 +664,12 @@ FT2FontFamily::AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList)
|
|||
continue;
|
||||
}
|
||||
|
||||
// We convert the weight to a float purely for transport across IPC.
|
||||
// Ideally we'd avoid doing that.
|
||||
aFontList->AppendElement(FontListEntry(Name(), fe->Name(),
|
||||
fe->mFilename,
|
||||
fe->Weight(), fe->Stretch(),
|
||||
fe->Weight().ToFloat(),
|
||||
fe->Stretch(),
|
||||
fe->mStyle,
|
||||
fe->mFTFontIndex));
|
||||
}
|
||||
|
@ -985,7 +991,7 @@ AppendToFaceList(nsCString& aFaceList,
|
|||
aFaceList.Append(',');
|
||||
aFaceList.Append(aFontEntry->IsItalic() ? '1' : '0');
|
||||
aFaceList.Append(',');
|
||||
aFaceList.AppendInt(aFontEntry->Weight());
|
||||
aFaceList.AppendFloat(aFontEntry->Weight().ToFloat());
|
||||
aFaceList.Append(',');
|
||||
aFaceList.AppendInt(aFontEntry->Stretch());
|
||||
aFaceList.Append(',');
|
||||
|
@ -1144,11 +1150,11 @@ gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
|
|||
AppendToFaceList(aFaceList, name, fe);
|
||||
if (LOG_ENABLED()) {
|
||||
LOG(("(fontinit) added (%s) to family (%s)"
|
||||
" with style: %s weight: %d stretch: %d",
|
||||
" with style: %s weight: %g stretch: %d",
|
||||
NS_ConvertUTF16toUTF8(fe->Name()).get(),
|
||||
NS_ConvertUTF16toUTF8(family->Name()).get(),
|
||||
fe->IsItalic() ? "italic" : "normal",
|
||||
fe->Weight(), fe->Stretch()));
|
||||
fe->Weight().ToFloat(), fe->Stretch()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1458,7 +1464,7 @@ gfxFT2FontList::InitFontListForPlatform()
|
|||
|
||||
gfxFontEntry*
|
||||
gfxFT2FontList::LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
{
|
||||
|
@ -1540,7 +1546,7 @@ gfxFT2FontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
|
|||
|
||||
gfxFontEntry*
|
||||
gfxFT2FontList::MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
// create a font entry for a downloaded font
|
||||
static FT2FontEntry*
|
||||
CreateFontEntry(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
@ -122,12 +122,12 @@ public:
|
|||
virtual ~gfxFT2FontList();
|
||||
|
||||
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle) override;
|
||||
|
||||
virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -160,40 +160,40 @@ GetFaceNames(FcPattern* aFont, const nsAString& aFamilyName,
|
|||
}
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
static FontWeight
|
||||
MapFcWeight(int aFcWeight)
|
||||
{
|
||||
if (aFcWeight <= (FC_WEIGHT_THIN + FC_WEIGHT_EXTRALIGHT) / 2) {
|
||||
return 100;
|
||||
return FontWeight(100);
|
||||
}
|
||||
if (aFcWeight <= (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2) {
|
||||
return 200;
|
||||
return FontWeight(200);
|
||||
}
|
||||
if (aFcWeight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_BOOK) / 2) {
|
||||
return 300;
|
||||
return FontWeight(300);
|
||||
}
|
||||
if (aFcWeight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2) {
|
||||
// This includes FC_WEIGHT_BOOK
|
||||
return 400;
|
||||
return FontWeight(400);
|
||||
}
|
||||
if (aFcWeight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) {
|
||||
return 500;
|
||||
return FontWeight(500);
|
||||
}
|
||||
if (aFcWeight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) {
|
||||
return 600;
|
||||
return FontWeight(600);
|
||||
}
|
||||
if (aFcWeight <= (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2) {
|
||||
return 700;
|
||||
return FontWeight(700);
|
||||
}
|
||||
if (aFcWeight <= (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2) {
|
||||
return 800;
|
||||
return FontWeight(800);
|
||||
}
|
||||
if (aFcWeight <= FC_WEIGHT_BLACK) {
|
||||
return 900;
|
||||
return FontWeight(900);
|
||||
}
|
||||
|
||||
// including FC_WEIGHT_EXTRABLACK
|
||||
return 901;
|
||||
return FontWeight(901);
|
||||
}
|
||||
|
||||
static int16_t
|
||||
|
@ -311,7 +311,7 @@ CreateFaceForPattern(FcPattern* aPattern)
|
|||
}
|
||||
|
||||
gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t *aData,
|
||||
|
@ -334,7 +334,7 @@ gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
|
|||
|
||||
gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
|
||||
FcPattern* aFontPattern,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
: gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
|
||||
|
@ -1202,13 +1202,13 @@ gfxFontconfigFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
|
|||
|
||||
if (LOG_FONTLIST_ENABLED()) {
|
||||
LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
|
||||
" with style: %s weight: %d stretch: %d"
|
||||
" with style: %s weight: %g stretch: %d"
|
||||
" psname: %s fullname: %s",
|
||||
NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
|
||||
NS_ConvertUTF16toUTF8(Name()).get(),
|
||||
(fontEntry->IsItalic()) ?
|
||||
"italic" : (fontEntry->IsOblique() ? "oblique" : "normal"),
|
||||
fontEntry->Weight(), fontEntry->Stretch(),
|
||||
fontEntry->Weight().ToFloat(), fontEntry->Stretch(),
|
||||
NS_ConvertUTF16toUTF8(psname).get(),
|
||||
NS_ConvertUTF16toUTF8(fullname).get()));
|
||||
}
|
||||
|
@ -1857,7 +1857,7 @@ gfxFcPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
|
|||
|
||||
gfxFontEntry*
|
||||
gfxFcPlatformFontList::LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
{
|
||||
|
@ -1876,7 +1876,7 @@ gfxFcPlatformFontList::LookupLocalFont(const nsAString& aFontName,
|
|||
|
||||
gfxFontEntry*
|
||||
gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "gfxFontEntry.h"
|
||||
#include "gfxFT2FontBase.h"
|
||||
#include "gfxPlatformFontList.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
@ -93,7 +94,7 @@ public:
|
|||
// used for data fonts where the fontentry takes ownership
|
||||
// of the font data and the FT_Face
|
||||
explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t *aData,
|
||||
|
@ -103,7 +104,7 @@ public:
|
|||
// used for @font-face local system fonts with explicit patterns
|
||||
explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
|
||||
FcPattern* aFontPattern,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle);
|
||||
|
||||
|
@ -287,11 +288,13 @@ public:
|
|||
InfallibleTArray<mozilla::dom::SystemFontListEntry>* retValue);
|
||||
|
||||
gfxFontEntry*
|
||||
LookupLocalFont(const nsAString& aFontName, uint16_t aWeight,
|
||||
LookupLocalFont(const nsAString& aFontName,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch, uint8_t aStyle) override;
|
||||
|
||||
gfxFontEntry*
|
||||
MakePlatformFont(const nsAString& aFontName, uint16_t aWeight,
|
||||
MakePlatformFont(const nsAString& aFontName,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "mozilla/BinarySearch.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/SVGContextPaint.h"
|
||||
|
@ -3521,7 +3522,7 @@ gfxFont::GetSmallCapsFont()
|
|||
style.size *= SMALL_CAPS_SCALE_FACTOR;
|
||||
style.variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
|
||||
gfxFontEntry* fe = GetFontEntry();
|
||||
bool needsBold = style.weight >= 600 && !fe->IsBold();
|
||||
bool needsBold = style.weight >= FontWeight(600) && !fe->IsBold();
|
||||
return fe->FindOrMakeFont(&style, needsBold, mUnicodeRangeMap);
|
||||
}
|
||||
|
||||
|
@ -3531,7 +3532,7 @@ gfxFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel)
|
|||
gfxFontStyle style(*GetStyle());
|
||||
style.AdjustForSubSuperscript(aAppUnitsPerDevPixel);
|
||||
gfxFontEntry* fe = GetFontEntry();
|
||||
bool needsBold = style.weight >= 600 && !fe->IsBold();
|
||||
bool needsBold = style.weight >= FontWeight(600) && !fe->IsBold();
|
||||
return fe->FindOrMakeFont(&style, needsBold, mUnicodeRangeMap);
|
||||
}
|
||||
|
||||
|
@ -4110,7 +4111,8 @@ gfxFontStyle::gfxFontStyle() :
|
|||
size(DEFAULT_PIXEL_FONT_SIZE), sizeAdjust(-1.0f), baselineOffset(0.0f),
|
||||
languageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
fontSmoothingBackgroundColor(NS_RGBA(0, 0, 0, 0)),
|
||||
weight(NS_FONT_WEIGHT_NORMAL), stretch(NS_FONT_STRETCH_NORMAL),
|
||||
weight(FontWeight::Normal()),
|
||||
stretch(NS_FONT_STRETCH_NORMAL),
|
||||
style(NS_FONT_STYLE_NORMAL),
|
||||
variantCaps(NS_FONT_VARIANT_CAPS_NORMAL),
|
||||
variantSubSuper(NS_FONT_VARIANT_POSITION_NORMAL),
|
||||
|
@ -4121,7 +4123,9 @@ gfxFontStyle::gfxFontStyle() :
|
|||
{
|
||||
}
|
||||
|
||||
gfxFontStyle::gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
|
||||
gfxFontStyle::gfxFontStyle(uint8_t aStyle,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
gfxFloat aSize,
|
||||
nsAtom *aLanguage, bool aExplicitLanguage,
|
||||
float aSizeAdjust, bool aSystemFont,
|
||||
|
@ -4133,7 +4137,8 @@ gfxFontStyle::gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
|
|||
size(aSize), sizeAdjust(aSizeAdjust), baselineOffset(0.0f),
|
||||
languageOverride(aLanguageOverride),
|
||||
fontSmoothingBackgroundColor(NS_RGBA(0, 0, 0, 0)),
|
||||
weight(aWeight), stretch(aStretch),
|
||||
weight(aWeight),
|
||||
stretch(aStretch),
|
||||
style(aStyle),
|
||||
variantCaps(NS_FONT_VARIANT_CAPS_NORMAL),
|
||||
variantSubSuper(NS_FONT_VARIANT_POSITION_NORMAL),
|
||||
|
@ -4147,10 +4152,12 @@ gfxFontStyle::gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
|
|||
MOZ_ASSERT(!mozilla::IsNaN(size));
|
||||
MOZ_ASSERT(!mozilla::IsNaN(sizeAdjust));
|
||||
|
||||
if (weight > 900)
|
||||
weight = 900;
|
||||
if (weight < 100)
|
||||
weight = 100;
|
||||
if (weight > FontWeight(900)) {
|
||||
weight = FontWeight(900);
|
||||
}
|
||||
if (weight < FontWeight(100)) {
|
||||
weight = FontWeight(100);
|
||||
}
|
||||
|
||||
if (size >= FONT_MAX_SIZE) {
|
||||
size = FONT_MAX_SIZE;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "nsIObserver.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include <algorithm>
|
||||
|
@ -75,8 +76,10 @@ class SVGContextPaint;
|
|||
} // namespace mozilla
|
||||
|
||||
struct gfxFontStyle {
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
|
||||
gfxFontStyle();
|
||||
gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
|
||||
gfxFontStyle(uint8_t aStyle, FontWeight aWeight, int16_t aStretch,
|
||||
gfxFloat aSize, nsAtom *aLanguage, bool aExplicitLanguage,
|
||||
float aSizeAdjust, bool aSystemFont,
|
||||
bool aPrinterFont,
|
||||
|
@ -137,7 +140,7 @@ struct gfxFontStyle {
|
|||
nscolor fontSmoothingBackgroundColor;
|
||||
|
||||
// The weight of the font: 100, 200, ... 900.
|
||||
uint16_t weight;
|
||||
FontWeight weight;
|
||||
|
||||
// The stretch of the font (the sum of various NS_FONT_STRETCH_*
|
||||
// constants; see gfxFontConstants.h).
|
||||
|
@ -184,8 +187,8 @@ struct gfxFontStyle {
|
|||
}
|
||||
|
||||
PLDHashNumber Hash() const {
|
||||
return ((style + (systemFont << 7) +
|
||||
(weight << 8)) + uint32_t(size*1000) + int32_t(sizeAdjust*1000)) ^
|
||||
return (style + (systemFont << 7) + (weight.ForHash() << 8) +
|
||||
uint32_t(size*1000) + int32_t(sizeAdjust*1000)) ^
|
||||
nsRefPtrHashKey<nsAtom>::HashKey(language);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
* 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 "gfxFontEntry.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
#include "gfxFontEntry.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
@ -1234,24 +1236,25 @@ StretchDistance(int16_t aFontStretch, int16_t aTargetStretch)
|
|||
|
||||
// weight distance ==> [0,1598]
|
||||
static inline uint32_t
|
||||
WeightDistance(uint32_t aFontWeight, uint32_t aTargetWeight)
|
||||
WeightDistance(FontWeight aFontWeight, FontWeight aTargetWeight)
|
||||
{
|
||||
// Compute a measure of the "distance" between the requested
|
||||
// weight and the given fontEntry
|
||||
|
||||
int32_t distance = 0, addedDistance = 0;
|
||||
float distance = 0.0f, addedDistance = 0.0f;
|
||||
if (aTargetWeight != aFontWeight) {
|
||||
if (aTargetWeight > 500) {
|
||||
if (aTargetWeight > FontWeight(500)) {
|
||||
distance = aFontWeight - aTargetWeight;
|
||||
} else if (aTargetWeight < 400) {
|
||||
} else if (aTargetWeight < FontWeight(400)) {
|
||||
distance = aTargetWeight - aFontWeight;
|
||||
} else {
|
||||
// special case - target is between 400 and 500
|
||||
|
||||
// font weights between 400 and 500 are close
|
||||
if (aFontWeight >= 400 && aFontWeight <= 500) {
|
||||
if (aFontWeight >= FontWeight(400) &&
|
||||
aFontWeight <= FontWeight(500)) {
|
||||
if (aFontWeight < aTargetWeight) {
|
||||
distance = 500 - aFontWeight;
|
||||
distance = FontWeight(500) - aFontWeight;
|
||||
} else {
|
||||
distance = aFontWeight - aTargetWeight;
|
||||
}
|
||||
|
@ -1263,7 +1266,7 @@ WeightDistance(uint32_t aFontWeight, uint32_t aTargetWeight)
|
|||
addedDistance = 100;
|
||||
}
|
||||
}
|
||||
if (distance < 0) {
|
||||
if (distance < 0.0f) {
|
||||
distance = -distance + REVERSE_WEIGHT_DISTANCE;
|
||||
}
|
||||
distance += addedDistance;
|
||||
|
@ -1307,7 +1310,7 @@ gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
|
|||
|
||||
aNeedsSyntheticBold = false;
|
||||
|
||||
bool wantBold = aFontStyle.weight >= 600;
|
||||
bool wantBold = aFontStyle.weight >= FontWeight(600);
|
||||
gfxFontEntry *fe = nullptr;
|
||||
|
||||
// If the family has only one face, we simply return it; no further
|
||||
|
@ -1406,7 +1409,7 @@ gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
|
|||
|
||||
if (matched) {
|
||||
aFontEntryList.AppendElement(matched);
|
||||
if (!matched->IsBold() && aFontStyle.weight >= 600 &&
|
||||
if (!matched->IsBold() && aFontStyle.weight >= FontWeight(600) &&
|
||||
aFontStyle.allowSyntheticWeight) {
|
||||
aNeedsSyntheticBold = true;
|
||||
}
|
||||
|
@ -1442,7 +1445,7 @@ gfxFontFamily::CheckForSimpleFamily()
|
|||
return;
|
||||
}
|
||||
uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
|
||||
(fe->Weight() >= 600 ? kBoldMask : 0);
|
||||
(fe->Weight() >= FontWeight(600) ? kBoldMask : 0);
|
||||
if (faces[faceIndex]) {
|
||||
return; // two faces resolve to the same slot; family isn't "simple"
|
||||
}
|
||||
|
@ -1501,7 +1504,7 @@ CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
|
|||
}
|
||||
|
||||
// measure of closeness of weight to the desired value
|
||||
rank += 9 - Abs((aFontEntry->Weight() - aStyle->weight) / 100);
|
||||
rank += 9 - Abs((aFontEntry->Weight() - aStyle->weight) / 100.0f);
|
||||
} else {
|
||||
// if no font to match, prefer non-bold, non-italic fonts
|
||||
if (aFontEntry->IsUpright()) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsUnicodeScriptCodes.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
|
@ -109,6 +110,7 @@ struct gfxFontFeatureInfo {
|
|||
|
||||
class gfxFontEntry {
|
||||
public:
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
typedef mozilla::unicode::Script Script;
|
||||
|
||||
|
@ -139,7 +141,7 @@ public:
|
|||
// returns Name() if nothing better is available.
|
||||
virtual nsString RealFaceName();
|
||||
|
||||
uint16_t Weight() const { return mWeight; }
|
||||
FontWeight Weight() const { return mWeight; }
|
||||
int16_t Stretch() const { return mStretch; }
|
||||
|
||||
bool IsUserFont() const { return mIsDataUserFont || mIsLocalUserFont; }
|
||||
|
@ -148,7 +150,7 @@ public:
|
|||
bool IsItalic() const { return mStyle == NS_FONT_STYLE_ITALIC; }
|
||||
bool IsOblique() const { return mStyle == NS_FONT_STYLE_OBLIQUE; }
|
||||
bool IsUpright() const { return mStyle == NS_FONT_STYLE_NORMAL; }
|
||||
bool IsBold() const { return mWeight >= 600; } // bold == weights 600 and above
|
||||
bool IsBold() const { return mWeight >= FontWeight(600); } // bold == weights 600 and above
|
||||
bool IgnoreGDEF() const { return mIgnoreGDEF; }
|
||||
bool IgnoreGSUB() const { return mIgnoreGSUB; }
|
||||
|
||||
|
@ -161,7 +163,7 @@ public:
|
|||
bool IsNormalStyle() const
|
||||
{
|
||||
return IsUpright() &&
|
||||
Weight() == NS_FONT_WEIGHT_NORMAL &&
|
||||
Weight() == FontWeight::Normal() &&
|
||||
Stretch() == NS_FONT_STRETCH_NORMAL;
|
||||
}
|
||||
|
||||
|
@ -402,7 +404,7 @@ public:
|
|||
uint32_t mDefaultSubSpaceFeatures[(int(Script::NUM_SCRIPT_CODES) + 31) / 32];
|
||||
uint32_t mNonDefaultSubSpaceFeatures[(int(Script::NUM_SCRIPT_CODES) + 31) / 32];
|
||||
|
||||
uint16_t mWeight;
|
||||
FontWeight mWeight;
|
||||
int16_t mStretch;
|
||||
|
||||
RefPtr<gfxCharacterMap> mCharacterMap;
|
||||
|
|
|
@ -445,20 +445,20 @@ gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize)
|
|||
{
|
||||
GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
|
||||
|
||||
uint16_t weight;
|
||||
FontWeight weight;
|
||||
if (fe->IsUserFont()) {
|
||||
if (fe->IsLocalUserFont()) {
|
||||
// for local user fonts, don't change the original weight
|
||||
// in the entry's logfont, because that could alter the
|
||||
// choice of actual face used (bug 724231)
|
||||
weight = 0;
|
||||
weight = FontWeight(0);
|
||||
} else {
|
||||
// avoid GDI synthetic bold which occurs when weight
|
||||
// specified is >= font data weight + 200
|
||||
weight = mNeedsBold ? 700 : 200;
|
||||
weight = mNeedsBold ? FontWeight(700) : FontWeight(200);
|
||||
}
|
||||
} else {
|
||||
weight = mNeedsBold ? 700 : fe->Weight();
|
||||
weight = mNeedsBold ? FontWeight(700) : fe->Weight();
|
||||
}
|
||||
|
||||
fe->FillLogFont(&aLogFont, weight, aSize);
|
||||
|
|
|
@ -115,7 +115,8 @@ FontTypeToOutPrecision(uint8_t fontType)
|
|||
|
||||
GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
|
||||
gfxWindowsFontType aFontType,
|
||||
uint8_t aStyle, uint16_t aWeight,
|
||||
uint8_t aStyle,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
gfxUserFontData *aUserFontData)
|
||||
: gfxFontEntry(aFaceName),
|
||||
|
@ -255,7 +256,8 @@ GDIFontEntry::LookupUnscaledFont(HFONT aFont)
|
|||
|
||||
void
|
||||
GDIFontEntry::FillLogFont(LOGFONTW *aLogFont,
|
||||
uint16_t aWeight, gfxFloat aSize)
|
||||
FontWeight aWeight,
|
||||
gfxFloat aSize)
|
||||
{
|
||||
memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW));
|
||||
|
||||
|
@ -270,8 +272,8 @@ GDIFontEntry::FillLogFont(LOGFONTW *aLogFont,
|
|||
// for installed families with no bold face, and for downloaded fonts
|
||||
// (but NOT for local user fonts, because it could cause a different,
|
||||
// glyph-incompatible face to be used)
|
||||
if (aWeight) {
|
||||
aLogFont->lfWeight = aWeight;
|
||||
if (aWeight.ToFloat() != 0.0f) {
|
||||
aLogFont->lfWeight = LONG(aWeight.ToFloat());
|
||||
}
|
||||
|
||||
// for non-local() user fonts, we never want to apply italics here;
|
||||
|
@ -303,7 +305,7 @@ GDIFontEntry::TestCharacterMap(uint32_t aCh)
|
|||
if (!IsUpright()) {
|
||||
fakeStyle.style = NS_FONT_STYLE_ITALIC;
|
||||
}
|
||||
fakeStyle.weight = mWeight * 100;
|
||||
fakeStyle.weight = mWeight;
|
||||
|
||||
RefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, false);
|
||||
if (!tempFont || !tempFont->Valid())
|
||||
|
@ -382,7 +384,7 @@ GDIFontEntry::InitLogFont(const nsAString& aName,
|
|||
// it may give us a regular one based on weight. Windows should
|
||||
// do fake italic for us in that case.
|
||||
mLogFont.lfItalic = !IsUpright();
|
||||
mLogFont.lfWeight = mWeight;
|
||||
mLogFont.lfWeight = int(mWeight.ToFloat());
|
||||
|
||||
int len = std::min<int>(aName.Length(), LF_FACESIZE - 1);
|
||||
memcpy(&mLogFont.lfFaceName, aName.BeginReading(), len * sizeof(char16_t));
|
||||
|
@ -393,7 +395,8 @@ GDIFontEntry*
|
|||
GDIFontEntry::CreateFontEntry(const nsAString& aName,
|
||||
gfxWindowsFontType aFontType,
|
||||
uint8_t aStyle,
|
||||
uint16_t aWeight, int16_t aStretch,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
gfxUserFontData* aUserFontData)
|
||||
{
|
||||
// jtdfix - need to set charset, unicode ranges, pitch/family
|
||||
|
@ -464,7 +467,7 @@ GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
|
|||
for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) {
|
||||
fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
|
||||
// check if we already know about this face
|
||||
if (fe->mWeight == logFont.lfWeight &&
|
||||
if (fe->mWeight == FontWeight(int32_t(logFont.lfWeight)) &&
|
||||
fe->IsItalic() == (logFont.lfItalic == 0xFF)) {
|
||||
// update the charset bit here since this could be different
|
||||
// XXX Can we still do this now that we store mCharset
|
||||
|
@ -481,7 +484,7 @@ GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
|
|||
NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL);
|
||||
fe = GDIFontEntry::CreateFontEntry(nsDependentString(lpelfe->elfFullName),
|
||||
feType, italicStyle,
|
||||
(uint16_t) (logFont.lfWeight), 0,
|
||||
FontWeight(int32_t(logFont.lfWeight)), 0,
|
||||
nullptr);
|
||||
if (!fe)
|
||||
return 1;
|
||||
|
@ -707,7 +710,7 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
|
|||
|
||||
gfxFontEntry*
|
||||
gfxGDIFontList::LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
{
|
||||
|
@ -734,7 +737,7 @@ gfxGDIFontList::LookupLocalFont(const nsAString& aFontName,
|
|||
fe->mIsLocalUserFont = true;
|
||||
|
||||
// make the new font entry match the userfont entry style characteristics
|
||||
fe->mWeight = (aWeight == 0 ? 400 : aWeight);
|
||||
fe->mWeight = (aWeight == FontWeight(0) ? FontWeight(400) : aWeight);
|
||||
fe->mStyle = aStyle;
|
||||
|
||||
return fe;
|
||||
|
@ -799,7 +802,7 @@ FixupSymbolEncodedFont(uint8_t* aFontData, uint32_t aLength)
|
|||
|
||||
gfxFontEntry*
|
||||
gfxGDIFontList::MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
@ -864,7 +867,7 @@ gfxGDIFontList::MakePlatformFont(const nsAString& aFontName,
|
|||
|
||||
// make a new font entry using the unique name
|
||||
WinUserFontData *winUserFontData = new WinUserFontData(fontRef);
|
||||
uint16_t w = (aWeight == 0 ? 400 : aWeight);
|
||||
FontWeight w = (aWeight == FontWeight(0) ? FontWeight(400) : aWeight);
|
||||
|
||||
GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName,
|
||||
gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef GFX_GDIFONTLIST_H
|
||||
#define GFX_GDIFONTLIST_H
|
||||
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "gfxPlatformFontList.h"
|
||||
|
@ -107,11 +108,15 @@ enum gfxWindowsFontType {
|
|||
class GDIFontEntry : public gfxFontEntry
|
||||
{
|
||||
public:
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
|
||||
LPLOGFONTW GetLogFont() { return &mLogFont; }
|
||||
|
||||
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
|
||||
|
||||
void FillLogFont(LOGFONTW *aLogFont, uint16_t aWeight, gfxFloat aSize);
|
||||
void FillLogFont(LOGFONTW *aLogFont,
|
||||
FontWeight aWeight,
|
||||
gfxFloat aSize);
|
||||
|
||||
static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics,
|
||||
DWORD fontType)
|
||||
|
@ -164,12 +169,13 @@ public:
|
|||
static GDIFontEntry* CreateFontEntry(const nsAString& aName,
|
||||
gfxWindowsFontType aFontType,
|
||||
uint8_t aStyle,
|
||||
uint16_t aWeight, int16_t aStretch,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
gfxUserFontData* aUserFontData);
|
||||
|
||||
// create a font entry for a font referenced by its fullname
|
||||
static GDIFontEntry* LoadLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle);
|
||||
|
||||
|
@ -182,7 +188,7 @@ protected:
|
|||
friend class gfxGDIFont;
|
||||
|
||||
GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
|
||||
uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
|
||||
uint8_t aStyle, FontWeight aWeight, int16_t aStretch,
|
||||
gfxUserFontData *aUserFontData);
|
||||
|
||||
void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType);
|
||||
|
@ -314,6 +320,8 @@ private:
|
|||
|
||||
class gfxGDIFontList : public gfxPlatformFontList {
|
||||
public:
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
|
||||
static gfxGDIFontList* PlatformFontList() {
|
||||
return static_cast<gfxGDIFontList*>(sPlatformFontList);
|
||||
}
|
||||
|
@ -330,12 +338,12 @@ public:
|
|||
gfxFloat aDevToCssSize = 1.0) override;
|
||||
|
||||
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle);
|
||||
|
||||
virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
@ -30,13 +31,13 @@ class MacOSFontEntry : public gfxFontEntry
|
|||
public:
|
||||
friend class gfxMacPlatformFontList;
|
||||
|
||||
MacOSFontEntry(const nsAString& aPostscriptName, int32_t aWeight,
|
||||
MacOSFontEntry(const nsAString& aPostscriptName, FontWeight aWeight,
|
||||
bool aIsStandardFace = false,
|
||||
double aSizeHint = 0.0);
|
||||
|
||||
// for use with data fonts
|
||||
MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef,
|
||||
uint16_t aWeight, uint16_t aStretch, uint8_t aStyle,
|
||||
FontWeight aWeight, uint16_t aStretch, uint8_t aStyle,
|
||||
bool aIsDataUserFont, bool aIsLocal);
|
||||
|
||||
virtual ~MacOSFontEntry() {
|
||||
|
@ -130,12 +131,12 @@ public:
|
|||
bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override;
|
||||
|
||||
gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle) override;
|
||||
|
||||
gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
@ -363,7 +364,7 @@ MacOSFontEntry::IsCFF()
|
|||
}
|
||||
|
||||
MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
|
||||
int32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
bool aIsStandardFace,
|
||||
double aSizeHint)
|
||||
: gfxFontEntry(aPostscriptName, aIsStandardFace),
|
||||
|
@ -387,7 +388,8 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
|
|||
|
||||
MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
|
||||
CGFontRef aFontRef,
|
||||
uint16_t aWeight, uint16_t aStretch,
|
||||
FontWeight aWeight,
|
||||
uint16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
bool aIsDataUserFont,
|
||||
bool aIsLocalUserFont)
|
||||
|
@ -902,7 +904,8 @@ gfxMacFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
|
|||
|
||||
// create a font entry
|
||||
MacOSFontEntry *fontEntry =
|
||||
new MacOSFontEntry(postscriptFontName, cssWeight, isStandardFace, mSizeHint);
|
||||
new MacOSFontEntry(postscriptFontName, FontWeight(cssWeight),
|
||||
isStandardFace, mSizeHint);
|
||||
if (!fontEntry) {
|
||||
break;
|
||||
}
|
||||
|
@ -1530,7 +1533,7 @@ gfxMacPlatformFontList::AppleWeightToCSSWeight(int32_t aAppleWeight)
|
|||
|
||||
gfxFontEntry*
|
||||
gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
{
|
||||
|
@ -1545,8 +1548,8 @@ gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aWeight >= 100 && aWeight <= 900,
|
||||
"bogus font weight value!");
|
||||
MOZ_ASSERT(aWeight >= FontWeight(100) && aWeight <= FontWeight(900),
|
||||
"bogus font weight value!");
|
||||
|
||||
newFontEntry =
|
||||
new MacOSFontEntry(aFontName, fontRef, aWeight, aStretch, aStyle,
|
||||
|
@ -1563,7 +1566,7 @@ static void ReleaseData(void *info, const void *data, size_t size)
|
|||
|
||||
gfxFontEntry*
|
||||
gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
@ -1571,7 +1574,8 @@ gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName,
|
|||
{
|
||||
NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
|
||||
|
||||
NS_ASSERTION(aWeight >= 100 && aWeight <= 900, "bogus font weight value!");
|
||||
MOZ_ASSERT(aWeight >= FontWeight(100) && aWeight <= FontWeight(900),
|
||||
"bogus font weight value!");
|
||||
|
||||
// create the font entry
|
||||
nsAutoString uniqueName;
|
||||
|
@ -1701,7 +1705,7 @@ gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
|
|||
aFontStyle.style =
|
||||
(traits & NSFontItalicTrait) ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL;
|
||||
aFontStyle.weight =
|
||||
(traits & NSFontBoldTrait) ? NS_FONT_WEIGHT_BOLD : NS_FONT_WEIGHT_NORMAL;
|
||||
(traits & NSFontBoldTrait) ? FontWeight::Bold() : FontWeight::Normal();
|
||||
aFontStyle.stretch =
|
||||
(traits & NSFontExpandedTrait) ?
|
||||
NS_FONT_STRETCH_EXPANDED : (traits & NSFontCondensedTrait) ?
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/layers/CompositorManagerChild.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
|
@ -1757,7 +1758,7 @@ gfxPlatform::IsFontFormatSupported(uint32_t aFormatFlags)
|
|||
|
||||
gfxFontEntry*
|
||||
gfxPlatform::LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
{
|
||||
|
@ -1769,7 +1770,7 @@ gfxPlatform::LookupLocalFont(const nsAString& aFontName,
|
|||
|
||||
gfxFontEntry*
|
||||
gfxPlatform::MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef GFX_PLATFORM_H
|
||||
#define GFX_PLATFORM_H
|
||||
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "nsTArray.h"
|
||||
|
@ -158,6 +159,7 @@ class gfxPlatform {
|
|||
friend class SRGBOverrideObserver;
|
||||
|
||||
public:
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
typedef mozilla::gfx::Color Color;
|
||||
typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
|
@ -391,7 +393,7 @@ public:
|
|||
* who must either AddRef() or delete.
|
||||
*/
|
||||
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle);
|
||||
|
||||
|
@ -404,7 +406,7 @@ public:
|
|||
* who must either AddRef() or delete.
|
||||
*/
|
||||
virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/RangedArray.h"
|
||||
|
@ -97,6 +98,7 @@ class gfxPlatformFontList : public gfxFontInfoLoader
|
|||
friend class InitOtherFamilyNamesRunnable;
|
||||
|
||||
public:
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
typedef mozilla::unicode::Script Script;
|
||||
|
||||
static gfxPlatformFontList* PlatformFontList() {
|
||||
|
@ -186,14 +188,14 @@ public:
|
|||
|
||||
// look up a font by name on the host platform
|
||||
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle) = 0;
|
||||
|
||||
// create a new platform font from downloaded data (@font-face)
|
||||
// this method is responsible to ensure aFontData is free()'d
|
||||
virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "base/task.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
@ -274,7 +275,7 @@ gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList,
|
|||
|
||||
gfxFontEntry*
|
||||
gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle)
|
||||
{
|
||||
|
@ -285,7 +286,7 @@ gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName,
|
|||
|
||||
gfxFontEntry*
|
||||
gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
* support @font-face src local() )
|
||||
*/
|
||||
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle) override;
|
||||
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
*
|
||||
*/
|
||||
virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
|
|
|
@ -1768,9 +1768,9 @@ gfxTextRun::Dump(FILE* aOutput) {
|
|||
NS_ConvertUTF16toUTF8 fontName(font->GetName());
|
||||
nsAutoCString lang;
|
||||
style->language->ToUTF8String(lang);
|
||||
fprintf(aOutput, "%d: %s %f/%d/%d/%s", glyphRuns[i].mCharacterOffset,
|
||||
fprintf(aOutput, "%d: %s %f/%g/%d/%s", glyphRuns[i].mCharacterOffset,
|
||||
fontName.get(), style->size,
|
||||
style->weight, style->style, lang.get());
|
||||
style->weight.ToFloat(), style->style, lang.get());
|
||||
}
|
||||
fputc(']', aOutput);
|
||||
}
|
||||
|
@ -2416,7 +2416,7 @@ gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget,
|
|||
nsAutoCString str((const char*)aString, aLength);
|
||||
MOZ_LOG(log, LogLevel::Warning,\
|
||||
("(%s) fontgroup: [%s] default: %s lang: %s script: %d "
|
||||
"len %d weight: %d width: %d style: %s size: %6.2f %zu-byte "
|
||||
"len %d weight: %g width: %d style: %s size: %6.2f %zu-byte "
|
||||
"TEXTRUN [%s] ENDTEXTRUN\n",
|
||||
(mStyle.systemFont ? "textrunui" : "textrun"),
|
||||
NS_ConvertUTF16toUTF8(families).get(),
|
||||
|
@ -2425,7 +2425,7 @@ gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget,
|
|||
(mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
|
||||
"sans-serif" : "none")),
|
||||
lang.get(), static_cast<int>(Script::LATIN), aLength,
|
||||
uint32_t(mStyle.weight), uint32_t(mStyle.stretch),
|
||||
mStyle.weight.ToFloat(), uint32_t(mStyle.stretch),
|
||||
(mStyle.style & NS_FONT_STYLE_ITALIC ? "italic" :
|
||||
(mStyle.style & NS_FONT_STYLE_OBLIQUE ? "oblique" :
|
||||
"normal")),
|
||||
|
@ -2464,7 +2464,7 @@ gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget,
|
|||
uint32_t runLen = runLimit - runStart;
|
||||
MOZ_LOG(log, LogLevel::Warning,\
|
||||
("(%s) fontgroup: [%s] default: %s lang: %s script: %d "
|
||||
"len %d weight: %d width: %d style: %s size: %6.2f "
|
||||
"len %d weight: %g width: %d style: %s size: %6.2f "
|
||||
"%zu-byte TEXTRUN [%s] ENDTEXTRUN\n",
|
||||
(mStyle.systemFont ? "textrunui" : "textrun"),
|
||||
NS_ConvertUTF16toUTF8(families).get(),
|
||||
|
@ -2473,7 +2473,7 @@ gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget,
|
|||
(mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
|
||||
"sans-serif" : "none")),
|
||||
lang.get(), static_cast<int>(runScript), runLen,
|
||||
uint32_t(mStyle.weight), uint32_t(mStyle.stretch),
|
||||
mStyle.weight.ToFloat(), uint32_t(mStyle.stretch),
|
||||
(mStyle.style & NS_FONT_STYLE_ITALIC ? "italic" :
|
||||
(mStyle.style & NS_FONT_STYLE_OBLIQUE ? "oblique" :
|
||||
"normal")),
|
||||
|
@ -2818,7 +2818,7 @@ gfxFontGroup::FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool needsBold = mStyle.weight >= 600 && !fe->IsBold() &&
|
||||
bool needsBold = mStyle.weight >= FontWeight(600) && !fe->IsBold() &&
|
||||
mStyle.allowSyntheticWeight;
|
||||
return fe->FindOrMakeFont(&mStyle, needsBold);
|
||||
}
|
||||
|
@ -3444,7 +3444,7 @@ gfxFontGroup::WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
|
|||
gfxPlatformFontList::PlatformFontList()->
|
||||
SystemFindFontForChar(aCh, aNextCh, aRunScript, &mStyle);
|
||||
if (fe) {
|
||||
bool wantBold = mStyle.weight >= 600;
|
||||
bool wantBold = mStyle.weight >= FontWeight(600);
|
||||
return fe->FindOrMakeFont(&mStyle, wantBold && !fe->IsBold());
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "gfxPrefs.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
@ -104,7 +105,7 @@ private:
|
|||
|
||||
gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -120,8 +121,8 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
|
|||
mLoader(nullptr),
|
||||
mFontSet(aFontSet)
|
||||
{
|
||||
MOZ_ASSERT(aWeight != 0,
|
||||
"aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
|
||||
MOZ_ASSERT(aWeight != FontWeight(0),
|
||||
"aWeight must not be 0; use FontWeight::Normal() instead");
|
||||
mIsUserFontContainer = true;
|
||||
mSrcList = aFontFaceSrcList;
|
||||
mSrcIndex = 0;
|
||||
|
@ -144,7 +145,7 @@ gfxUserFontEntry::~gfxUserFontEntry()
|
|||
|
||||
bool
|
||||
gfxUserFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -935,7 +936,7 @@ already_AddRefed<gfxUserFontEntry>
|
|||
gfxUserFontSet::FindOrCreateUserFontEntry(
|
||||
const nsAString& aFamilyName,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -975,7 +976,7 @@ gfxUserFontSet::FindOrCreateUserFontEntry(
|
|||
already_AddRefed<gfxUserFontEntry>
|
||||
gfxUserFontSet::CreateUserFontEntry(
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -996,7 +997,7 @@ gfxUserFontEntry*
|
|||
gfxUserFontSet::FindExistingUserFontEntry(
|
||||
gfxUserFontFamily* aFamily,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -1005,8 +1006,8 @@ gfxUserFontSet::FindExistingUserFontEntry(
|
|||
gfxCharacterMap* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
{
|
||||
MOZ_ASSERT(aWeight != 0,
|
||||
"aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
|
||||
MOZ_ASSERT(aWeight != FontWeight(0),
|
||||
"aWeight must not be 0; use FontWeight::Normal() instead");
|
||||
|
||||
nsTArray<RefPtr<gfxFontEntry>>& fontList = aFamily->GetFontList();
|
||||
|
||||
|
@ -1039,12 +1040,12 @@ gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName,
|
|||
family->AddFontEntry(aUserFontEntry);
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %d "
|
||||
LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %g "
|
||||
"stretch: %d display: %d",
|
||||
this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry,
|
||||
(aUserFontEntry->IsItalic() ? "italic" :
|
||||
(aUserFontEntry->IsOblique() ? "oblique" : "normal")),
|
||||
aUserFontEntry->Weight(), aUserFontEntry->Stretch(),
|
||||
aUserFontEntry->Weight().ToFloat(), aUserFontEntry->Stretch(),
|
||||
aUserFontEntry->GetFontDisplay()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsURIHashKey.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "gfxFontConstants.h"
|
||||
|
||||
|
@ -184,6 +185,7 @@ class gfxUserFontSet {
|
|||
friend class gfxOTSContext;
|
||||
|
||||
public:
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxUserFontSet)
|
||||
|
||||
|
@ -229,7 +231,7 @@ public:
|
|||
// TODO: support for unicode ranges not yet implemented
|
||||
virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -243,7 +245,7 @@ public:
|
|||
already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntry(
|
||||
const nsAString& aFamilyName,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -404,8 +406,8 @@ public:
|
|||
HashFeatures(aKey->mFontEntry->mFeatureSettings),
|
||||
HashVariations(aKey->mFontEntry->mVariationSettings),
|
||||
mozilla::HashString(aKey->mFontEntry->mFamilyName),
|
||||
aKey->mFontEntry->mWeight.ForHash(),
|
||||
(aKey->mFontEntry->mStyle |
|
||||
(aKey->mFontEntry->mWeight << 2) |
|
||||
(aKey->mFontEntry->mStretch << 11) ) ^
|
||||
aKey->mFontEntry->mLanguageOverride);
|
||||
}
|
||||
|
@ -497,7 +499,7 @@ protected:
|
|||
gfxUserFontEntry* FindExistingUserFontEntry(
|
||||
gfxUserFontFamily* aFamily,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -537,6 +539,8 @@ class gfxUserFontEntry : public gfxFontEntry {
|
|||
friend class gfxOTSContext;
|
||||
|
||||
public:
|
||||
typedef mozilla::FontWeight FontWeight;
|
||||
|
||||
enum UserFontLoadState {
|
||||
STATUS_NOT_LOADED = 0,
|
||||
STATUS_LOAD_PENDING,
|
||||
|
@ -547,7 +551,7 @@ public:
|
|||
|
||||
gfxUserFontEntry(gfxUserFontSet* aFontSet,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
@ -560,7 +564,7 @@ public:
|
|||
|
||||
// Return whether the entry matches the given list of attributes
|
||||
bool Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
FontWeight aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
|
|
|
@ -100,6 +100,9 @@ RenderThread::ShutDownTask(layers::SynchronousTask* aTask)
|
|||
{
|
||||
layers::AutoCompleteTask complete(aTask);
|
||||
MOZ_ASSERT(IsInRenderThread());
|
||||
|
||||
MutexAutoLock lock(mRenderTextureMapLock);
|
||||
mRenderTextures.Clear();
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -456,10 +456,9 @@ fn get_proc_address(glcontext_ptr: *mut c_void,
|
|||
let symbol_name = CString::new(name).unwrap();
|
||||
let symbol = unsafe { get_proc_address_from_glcontext(glcontext_ptr, symbol_name.as_ptr()) };
|
||||
|
||||
// For now panic, not sure we should be though or if we can recover
|
||||
if symbol.is_null() {
|
||||
// XXX Bug 1322949 Make whitelist for extensions
|
||||
println!("Could not find symbol {:?} by glcontext", symbol_name);
|
||||
warn!("Could not find symbol {:?} by glcontext", symbol_name);
|
||||
}
|
||||
|
||||
symbol as *const _
|
||||
|
@ -564,7 +563,7 @@ pub extern "C" fn wr_renderer_render(renderer: &mut Renderer,
|
|||
Ok(_) => true,
|
||||
Err(errors) => {
|
||||
for e in errors {
|
||||
println!(" Failed to render: {:?}", e);
|
||||
warn!(" Failed to render: {:?}", e);
|
||||
let msg = CString::new(format!("wr_renderer_render: {:?}", e)).unwrap();
|
||||
unsafe {
|
||||
gfx_critical_note(msg.as_ptr());
|
||||
|
@ -836,7 +835,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
|
|||
|
||||
let version = gl.get_string(gl::VERSION);
|
||||
|
||||
println!("WebRender - OpenGL version new {}", version);
|
||||
info!("WebRender - OpenGL version new {}", version);
|
||||
|
||||
let workers = unsafe {
|
||||
Arc::clone(&(*thread_pool).0)
|
||||
|
@ -879,7 +878,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
|
|||
let (renderer, sender) = match Renderer::new(gl, notifier, opts) {
|
||||
Ok((renderer, sender)) => (renderer, sender),
|
||||
Err(e) => {
|
||||
println!(" Failed to create a Renderer: {:?}", e);
|
||||
warn!(" Failed to create a Renderer: {:?}", e);
|
||||
let msg = CString::new(format!("wr_window_new: {:?}", e)).unwrap();
|
||||
unsafe {
|
||||
gfx_critical_note(msg.as_ptr());
|
||||
|
@ -1323,7 +1322,7 @@ pub extern "C" fn wr_api_capture(
|
|||
file.write(revision).unwrap();
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Unable to create path '{:?}' for capture: {:?}", path, e);
|
||||
warn!("Unable to create path '{:?}' for capture: {:?}", path, e);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ extern crate app_units;
|
|||
extern crate gleam;
|
||||
extern crate rayon;
|
||||
extern crate thread_profiler;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
|
|
|
@ -17,6 +17,7 @@ AnimationFrameBuffer::AnimationFrameBuffer()
|
|||
, mInsertIndex(0)
|
||||
, mGetIndex(0)
|
||||
, mSizeKnown(false)
|
||||
, mRedecodeError(false)
|
||||
{ }
|
||||
|
||||
void
|
||||
|
@ -71,7 +72,16 @@ AnimationFrameBuffer::Insert(RawAccessFrameRef&& aFrame)
|
|||
// and we did not keep all of the frames. Replace whatever is there
|
||||
// (probably an empty frame) with the new frame.
|
||||
MOZ_ASSERT(MayDiscard());
|
||||
MOZ_ASSERT(mInsertIndex < mFrames.Length());
|
||||
|
||||
// The first decode produced fewer frames than the redecodes, presumably
|
||||
// because it hit an out-of-memory error which later attempts avoided. Just
|
||||
// stop the animation because we can't tell the image that we have more
|
||||
// frames now.
|
||||
if (mInsertIndex >= mFrames.Length()) {
|
||||
mRedecodeError = true;
|
||||
mPending = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mInsertIndex > 0) {
|
||||
MOZ_ASSERT(!mFrames[mInsertIndex]);
|
||||
|
@ -127,9 +137,23 @@ AnimationFrameBuffer::Insert(RawAccessFrameRef&& aFrame)
|
|||
bool
|
||||
AnimationFrameBuffer::MarkComplete()
|
||||
{
|
||||
// We may have stopped decoding at a different point in the animation than we
|
||||
// did previously. That means the decoder likely hit a new error, e.g. OOM.
|
||||
// This will prevent us from advancing as well, because we are missing the
|
||||
// required frames to blend.
|
||||
//
|
||||
// XXX(aosmond): In an ideal world, we would be generating full frames, and
|
||||
// the consumer of our data doesn't care about our internal state. It simply
|
||||
// knows about the first frame, the current frame, and how long to display the
|
||||
// current frame.
|
||||
if (NS_WARN_IF(mInsertIndex != mFrames.Length())) {
|
||||
MOZ_ASSERT(mSizeKnown);
|
||||
mRedecodeError = true;
|
||||
mPending = 0;
|
||||
}
|
||||
|
||||
// We reached the end of the animation, the next frame we get, if we get
|
||||
// another, will be the first frame again.
|
||||
MOZ_ASSERT(mInsertIndex == mFrames.Length());
|
||||
mInsertIndex = 0;
|
||||
|
||||
// Since we only request advancing when we want to resume at a certain point
|
||||
|
@ -231,7 +255,7 @@ AnimationFrameBuffer::AdvanceInternal()
|
|||
}
|
||||
}
|
||||
|
||||
if (!mSizeKnown || MayDiscard()) {
|
||||
if (!mRedecodeError && (!mSizeKnown || MayDiscard())) {
|
||||
// Calculate how many frames we have requested ahead of the current frame.
|
||||
size_t buffered = mPending;
|
||||
if (mGetIndex > mInsertIndex) {
|
||||
|
@ -276,13 +300,6 @@ AnimationFrameBuffer::Reset()
|
|||
return false;
|
||||
}
|
||||
|
||||
// If we are over the threshold, then we know we will have missing frames in
|
||||
// our buffer. The easiest thing to do is to drop everything but the first
|
||||
// frame and go back to the initial state.
|
||||
bool restartDecoder = mPending == 0;
|
||||
mInsertIndex = 0;
|
||||
mPending = 2 * mBatch;
|
||||
|
||||
// Discard all frames besides the first, because the decoder always expects
|
||||
// that when it re-inserts a frame, it is not present. (It doesn't re-insert
|
||||
// the first frame.)
|
||||
|
@ -290,6 +307,16 @@ AnimationFrameBuffer::Reset()
|
|||
RawAccessFrameRef discard = Move(mFrames[i]);
|
||||
}
|
||||
|
||||
mInsertIndex = 0;
|
||||
|
||||
// If we hit an error after redecoding, we never want to restart decoding.
|
||||
if (mRedecodeError) {
|
||||
MOZ_ASSERT(mPending == 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool restartDecoder = mPending == 0;
|
||||
mPending = 2 * mBatch;
|
||||
return restartDecoder;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,12 @@ public:
|
|||
*/
|
||||
bool SizeKnown() const { return mSizeKnown; }
|
||||
|
||||
/**
|
||||
* @returns True if encountered an error during redecode which should cause
|
||||
* the caller to stop inserting frames.
|
||||
*/
|
||||
bool HasRedecodeError() const { return mRedecodeError; }
|
||||
|
||||
/**
|
||||
* @returns The current frame index we have advanced to.
|
||||
*/
|
||||
|
@ -187,6 +193,9 @@ private:
|
|||
|
||||
// True if the total number of frames is known.
|
||||
bool mSizeKnown;
|
||||
|
||||
// True if we encountered an error while redecoding.
|
||||
bool mRedecodeError;
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
|
|
|
@ -224,13 +224,14 @@ AnimationSurfaceProvider::Run()
|
|||
FinishDecoding();
|
||||
|
||||
// Even if it is the last frame, we may not have enough frames buffered
|
||||
// ahead of the current.
|
||||
if (continueDecoding) {
|
||||
MOZ_ASSERT(mDecoder);
|
||||
continue;
|
||||
// ahead of the current. If we are shutting down, we want to ensure we
|
||||
// release the thread as soon as possible. The animation may advance even
|
||||
// during shutdown, which keeps us decoding, and thus blocking the decode
|
||||
// pool during teardown.
|
||||
if (!mDecoder || !continueDecoding ||
|
||||
DecodePool::Singleton()->IsShuttingDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify for the progress we've made so far.
|
||||
|
@ -245,9 +246,13 @@ AnimationSurfaceProvider::Run()
|
|||
}
|
||||
|
||||
// There's new output available - a new frame! Grab it. If we don't need any
|
||||
// more for the moment we can break out of the loop.
|
||||
// more for the moment we can break out of the loop. If we are shutting
|
||||
// down, we want to ensure we release the thread as soon as possible. The
|
||||
// animation may advance even during shutdown, which keeps us decoding, and
|
||||
// thus blocking the decode pool during teardown.
|
||||
MOZ_ASSERT(result == LexerResult(Yield::OUTPUT_AVAILABLE));
|
||||
if (!CheckForNewFrameAtYield()) {
|
||||
if (!CheckForNewFrameAtYield() ||
|
||||
DecodePool::Singleton()->IsShuttingDown()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -294,10 +299,7 @@ AnimationSurfaceProvider::CheckForNewFrameAtYield()
|
|||
AnnounceSurfaceAvailable();
|
||||
}
|
||||
|
||||
// If we are shutting down, we want to ensure we release the thread as soon
|
||||
// as possible. The animation may advance even during shutdown, which keeps
|
||||
// us decoding, and thus blocking the decode pool during teardown.
|
||||
return continueDecoding && !DecodePool::Singleton()->IsShuttingDown();
|
||||
return continueDecoding;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -347,10 +349,7 @@ AnimationSurfaceProvider::CheckForNewFrameAtTerminalState()
|
|||
AnnounceSurfaceAvailable();
|
||||
}
|
||||
|
||||
// If we are shutting down, we want to ensure we release the thread as soon
|
||||
// as possible. The animation may advance even during shutdown, which keeps
|
||||
// us decoding, and thus blocking the decode pool during teardown.
|
||||
return continueDecoding && !DecodePool::Singleton()->IsShuttingDown();
|
||||
return continueDecoding;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -378,15 +377,15 @@ AnimationSurfaceProvider::FinishDecoding()
|
|||
NotifyDecodeComplete(WrapNotNull(mImage), WrapNotNull(mDecoder));
|
||||
}
|
||||
|
||||
// Destroy our decoder; we don't need it anymore.
|
||||
bool mayDiscard;
|
||||
// Determine if we need to recreate the decoder, in case we are discarding
|
||||
// frames and need to loop back to the beginning.
|
||||
bool recreateDecoder;
|
||||
{
|
||||
MutexAutoLock lock(mFramesMutex);
|
||||
mayDiscard = mFrames.MayDiscard();
|
||||
recreateDecoder = !mFrames.HasRedecodeError() && mFrames.MayDiscard();
|
||||
}
|
||||
|
||||
if (mayDiscard) {
|
||||
// Recreate the decoder so we can regenerate the frames again.
|
||||
if (recreateDecoder) {
|
||||
mDecoder = DecoderFactory::CloneAnimationDecoder(mDecoder);
|
||||
MOZ_ASSERT(mDecoder);
|
||||
} else {
|
||||
|
|
|
@ -143,6 +143,7 @@ TEST_F(ImageAnimationFrameBuffer, FinishUnderBatchAndThreshold)
|
|||
EXPECT_FALSE(keepDecoding);
|
||||
EXPECT_TRUE(buffer.SizeKnown());
|
||||
EXPECT_EQ(size_t(0), buffer.PendingDecode());
|
||||
EXPECT_FALSE(buffer.HasRedecodeError());
|
||||
}
|
||||
|
||||
EXPECT_FALSE(buffer.MayDiscard());
|
||||
|
@ -220,6 +221,7 @@ TEST_F(ImageAnimationFrameBuffer, FinishMultipleBatchesUnderThreshold)
|
|||
EXPECT_TRUE(buffer.SizeKnown());
|
||||
EXPECT_EQ(size_t(0), buffer.PendingDecode());
|
||||
EXPECT_EQ(size_t(5), frames.Length());
|
||||
EXPECT_FALSE(buffer.HasRedecodeError());
|
||||
|
||||
// Finish progressing through the animation.
|
||||
for ( ; i < frames.Length(); ++i) {
|
||||
|
@ -330,6 +332,7 @@ TEST_F(ImageAnimationFrameBuffer, MayDiscard)
|
|||
EXPECT_TRUE(buffer.SizeKnown());
|
||||
EXPECT_EQ(size_t(2), buffer.PendingDecode());
|
||||
EXPECT_EQ(size_t(10), frames.Length());
|
||||
EXPECT_FALSE(buffer.HasRedecodeError());
|
||||
|
||||
// Use remaining pending room. It shouldn't add new frames, only replace.
|
||||
do {
|
||||
|
@ -513,3 +516,159 @@ TEST_F(ImageAnimationFrameBuffer, StartAfterBeginningAndReset)
|
|||
EXPECT_EQ(size_t(0), buffer.PendingAdvance());
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, RedecodeMoreFrames)
|
||||
{
|
||||
const size_t kThreshold = 5;
|
||||
const size_t kBatch = 2;
|
||||
AnimationFrameBuffer buffer;
|
||||
buffer.Initialize(kThreshold, kBatch, 0);
|
||||
const auto& frames = buffer.Frames();
|
||||
|
||||
// Add frames until we exceed the threshold.
|
||||
bool keepDecoding;
|
||||
bool restartDecoder;
|
||||
size_t i = 0;
|
||||
do {
|
||||
keepDecoding = buffer.Insert(CreateEmptyFrame());
|
||||
EXPECT_TRUE(keepDecoding);
|
||||
if (i > 0) {
|
||||
restartDecoder = buffer.AdvanceTo(i);
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
}
|
||||
++i;
|
||||
} while (!buffer.MayDiscard());
|
||||
|
||||
// Should have threshold + 1 frames, and still not complete.
|
||||
EXPECT_EQ(size_t(6), frames.Length());
|
||||
EXPECT_FALSE(buffer.SizeKnown());
|
||||
|
||||
// Now we lock in at 6 frames.
|
||||
keepDecoding = buffer.MarkComplete();
|
||||
EXPECT_TRUE(keepDecoding);
|
||||
EXPECT_TRUE(buffer.SizeKnown());
|
||||
EXPECT_FALSE(buffer.HasRedecodeError());
|
||||
|
||||
// Reinsert 6 frames first.
|
||||
i = 0;
|
||||
do {
|
||||
keepDecoding = buffer.Insert(CreateEmptyFrame());
|
||||
EXPECT_TRUE(keepDecoding);
|
||||
restartDecoder = buffer.AdvanceTo(i);
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
++i;
|
||||
} while (i < 6);
|
||||
|
||||
// We should now encounter an error and shutdown further decodes.
|
||||
keepDecoding = buffer.Insert(CreateEmptyFrame());
|
||||
EXPECT_FALSE(keepDecoding);
|
||||
EXPECT_EQ(size_t(0), buffer.PendingDecode());
|
||||
EXPECT_TRUE(buffer.HasRedecodeError());
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, RedecodeFewerFrames)
|
||||
{
|
||||
const size_t kThreshold = 5;
|
||||
const size_t kBatch = 2;
|
||||
AnimationFrameBuffer buffer;
|
||||
buffer.Initialize(kThreshold, kBatch, 0);
|
||||
const auto& frames = buffer.Frames();
|
||||
|
||||
// Add frames until we exceed the threshold.
|
||||
bool keepDecoding;
|
||||
bool restartDecoder;
|
||||
size_t i = 0;
|
||||
do {
|
||||
keepDecoding = buffer.Insert(CreateEmptyFrame());
|
||||
EXPECT_TRUE(keepDecoding);
|
||||
if (i > 0) {
|
||||
restartDecoder = buffer.AdvanceTo(i);
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
}
|
||||
++i;
|
||||
} while (!buffer.MayDiscard());
|
||||
|
||||
// Should have threshold + 1 frames, and still not complete.
|
||||
EXPECT_EQ(size_t(6), frames.Length());
|
||||
EXPECT_FALSE(buffer.SizeKnown());
|
||||
|
||||
// Now we lock in at 6 frames.
|
||||
keepDecoding = buffer.MarkComplete();
|
||||
EXPECT_TRUE(keepDecoding);
|
||||
EXPECT_TRUE(buffer.SizeKnown());
|
||||
EXPECT_FALSE(buffer.HasRedecodeError());
|
||||
|
||||
// Reinsert 5 frames before marking complete.
|
||||
i = 0;
|
||||
do {
|
||||
keepDecoding = buffer.Insert(CreateEmptyFrame());
|
||||
EXPECT_TRUE(keepDecoding);
|
||||
restartDecoder = buffer.AdvanceTo(i);
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
++i;
|
||||
} while (i < 5);
|
||||
|
||||
// We should now encounter an error and shutdown further decodes.
|
||||
keepDecoding = buffer.MarkComplete();
|
||||
EXPECT_FALSE(keepDecoding);
|
||||
EXPECT_EQ(size_t(0), buffer.PendingDecode());
|
||||
EXPECT_TRUE(buffer.HasRedecodeError());
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, RedecodeFewerFramesAndBehindAdvancing)
|
||||
{
|
||||
const size_t kThreshold = 5;
|
||||
const size_t kBatch = 2;
|
||||
AnimationFrameBuffer buffer;
|
||||
buffer.Initialize(kThreshold, kBatch, 0);
|
||||
const auto& frames = buffer.Frames();
|
||||
|
||||
// Add frames until we exceed the threshold.
|
||||
bool keepDecoding;
|
||||
bool restartDecoder;
|
||||
size_t i = 0;
|
||||
do {
|
||||
keepDecoding = buffer.Insert(CreateEmptyFrame());
|
||||
EXPECT_TRUE(keepDecoding);
|
||||
if (i > 0) {
|
||||
restartDecoder = buffer.AdvanceTo(i);
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
}
|
||||
++i;
|
||||
} while (!buffer.MayDiscard());
|
||||
|
||||
// Should have threshold + 1 frames, and still not complete.
|
||||
EXPECT_EQ(size_t(6), frames.Length());
|
||||
EXPECT_FALSE(buffer.SizeKnown());
|
||||
|
||||
// Now we lock in at 6 frames.
|
||||
keepDecoding = buffer.MarkComplete();
|
||||
EXPECT_TRUE(keepDecoding);
|
||||
EXPECT_TRUE(buffer.SizeKnown());
|
||||
EXPECT_FALSE(buffer.HasRedecodeError());
|
||||
|
||||
// Reinsert frames without advancing until we exhaust our pending space. This
|
||||
// should be less than the current buffer length by definition.
|
||||
i = 0;
|
||||
do {
|
||||
keepDecoding = buffer.Insert(CreateEmptyFrame());
|
||||
++i;
|
||||
} while (keepDecoding);
|
||||
|
||||
EXPECT_EQ(size_t(2), i);
|
||||
|
||||
// We should now encounter an error and shutdown further decodes.
|
||||
keepDecoding = buffer.MarkComplete();
|
||||
EXPECT_FALSE(keepDecoding);
|
||||
EXPECT_EQ(size_t(0), buffer.PendingDecode());
|
||||
EXPECT_TRUE(buffer.HasRedecodeError());
|
||||
|
||||
// We should however be able to continue advancing to the last decoded frame
|
||||
// without it requesting the decoder to restart.
|
||||
i = 0;
|
||||
do {
|
||||
restartDecoder = buffer.AdvanceTo(i);
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
++i;
|
||||
} while (i < 2);
|
||||
}
|
||||
|
||||
|
|
|
@ -587,6 +587,19 @@ WasmSaturatingTruncationSupported(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
WasmGcEnabled(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
#ifdef ENABLE_WASM_GC
|
||||
bool isSupported = cx->options().wasmBaseline() && cx->options().wasmGc();
|
||||
#else
|
||||
bool isSupported = false;
|
||||
#endif
|
||||
args.rval().setBoolean(isSupported);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
WasmCompileMode(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -5503,6 +5516,10 @@ gc::ZealModeHelpText),
|
|||
" Returns a boolean indicating whether a given module has finished compiled code for tier2. \n"
|
||||
"This will return true early if compilation isn't two-tiered. "),
|
||||
|
||||
JS_FN_HELP("wasmGcEnabled", WasmGcEnabled, 1, 0,
|
||||
"wasmGcEnabled(bool)",
|
||||
" Returns a boolean indicating whether the WebAssembly GC support is enabled."),
|
||||
|
||||
JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
|
||||
"isLazyFunction(fun)",
|
||||
" True if fun is a lazy JSFunction."),
|
||||
|
|
|
@ -0,0 +1,383 @@
|
|||
// Ensure that if gc types aren't enabled, test cases properly fail.
|
||||
|
||||
if (!wasmGcEnabled()) {
|
||||
quit(0);
|
||||
}
|
||||
|
||||
// Dummy constructor.
|
||||
function Baguette(calories) {
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
// Type checking.
|
||||
|
||||
const { validate, CompileError } = WebAssembly;
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module
|
||||
(func (result anyref)
|
||||
i32.const 42
|
||||
)
|
||||
)`), CompileError, mismatchError('i32', 'anyref'));
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module
|
||||
(func (result anyref)
|
||||
i32.const 0
|
||||
ref.null anyref
|
||||
i32.const 42
|
||||
select
|
||||
)
|
||||
)`), CompileError, /select operand types/);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module
|
||||
(func (result i32)
|
||||
ref.null anyref
|
||||
if
|
||||
i32.const 42
|
||||
end
|
||||
)
|
||||
)`), CompileError, mismatchError('anyref', 'i32'));
|
||||
|
||||
|
||||
// Basic compilation tests.
|
||||
|
||||
let simpleTests = [
|
||||
"(module (func (drop (ref.null anyref))))",
|
||||
"(module (func $test (local anyref)))",
|
||||
"(module (func $test (param anyref)))",
|
||||
"(module (func $test (result anyref) (ref.null anyref)))",
|
||||
"(module (func $test (block anyref (unreachable)) unreachable))",
|
||||
"(module (func $test (local anyref) (result i32) (ref.is_null (get_local 0))))",
|
||||
`(module (import "a" "b" (param anyref)))`,
|
||||
`(module (import "a" "b" (result anyref)))`,
|
||||
];
|
||||
|
||||
for (let src of simpleTests) {
|
||||
wasmEvalText(src, {a:{b(){}}});
|
||||
assertEq(validate(wasmTextToBinary(src)), true);
|
||||
}
|
||||
|
||||
// Basic behavioral tests.
|
||||
|
||||
let { exports } = wasmEvalText(`(module
|
||||
(func (export "is_null") (result i32)
|
||||
ref.null anyref
|
||||
ref.is_null
|
||||
)
|
||||
|
||||
(func $sum (result i32) (param i32)
|
||||
get_local 0
|
||||
i32.const 42
|
||||
i32.add
|
||||
)
|
||||
|
||||
(func (export "is_null_spill") (result i32)
|
||||
ref.null anyref
|
||||
i32.const 58
|
||||
call $sum
|
||||
drop
|
||||
ref.is_null
|
||||
)
|
||||
|
||||
(func (export "is_null_local") (result i32) (local anyref)
|
||||
ref.null anyref
|
||||
set_local 0
|
||||
i32.const 58
|
||||
call $sum
|
||||
drop
|
||||
get_local 0
|
||||
ref.is_null
|
||||
)
|
||||
)`);
|
||||
|
||||
assertEq(exports.is_null(), 1);
|
||||
assertEq(exports.is_null_spill(), 1);
|
||||
assertEq(exports.is_null_local(), 1);
|
||||
|
||||
// Anyref param and result in wasm functions.
|
||||
|
||||
exports = wasmEvalText(`(module
|
||||
(func (export "is_null") (result i32) (param $ref anyref)
|
||||
get_local $ref
|
||||
ref.is_null
|
||||
)
|
||||
|
||||
(func (export "ref_or_null") (result anyref) (param $ref anyref) (param $selector i32)
|
||||
get_local $ref
|
||||
ref.null anyref
|
||||
get_local $selector
|
||||
select
|
||||
)
|
||||
|
||||
(func $recursive (export "nested") (result anyref) (param $ref anyref) (param $i i32)
|
||||
;; i == 10 => ret $ref
|
||||
get_local $i
|
||||
i32.const 10
|
||||
i32.eq
|
||||
if
|
||||
get_local $ref
|
||||
return
|
||||
end
|
||||
|
||||
get_local $ref
|
||||
|
||||
get_local $i
|
||||
i32.const 1
|
||||
i32.add
|
||||
|
||||
call $recursive
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
assertErrorMessage(() => exports.is_null(undefined), TypeError, "can't convert undefined to object");
|
||||
assertEq(exports.is_null(null), 1);
|
||||
assertEq(exports.is_null({}), 0);
|
||||
assertEq(exports.is_null("hi"), 0);
|
||||
assertEq(exports.is_null(3), 0);
|
||||
assertEq(exports.is_null(3.5), 0);
|
||||
assertEq(exports.is_null(true), 0);
|
||||
assertEq(exports.is_null(Symbol("croissant")), 0);
|
||||
assertEq(exports.is_null(new Baguette(100)), 0);
|
||||
|
||||
let baguette = new Baguette(42);
|
||||
assertEq(exports.ref_or_null(null, 0), null);
|
||||
assertEq(exports.ref_or_null(baguette, 0), null);
|
||||
|
||||
let ref = exports.ref_or_null(baguette, 1);
|
||||
assertEq(ref, baguette);
|
||||
assertEq(ref.calories, baguette.calories);
|
||||
|
||||
ref = exports.nested(baguette, 0);
|
||||
assertEq(ref, baguette);
|
||||
assertEq(ref.calories, baguette.calories);
|
||||
|
||||
// More interesting use cases about control flow joins.
|
||||
|
||||
function assertJoin(body) {
|
||||
let val = { i: -1 };
|
||||
assertEq(wasmEvalText(`(module
|
||||
(func (export "test") (param $ref anyref) (param $i i32) (result anyref)
|
||||
${body}
|
||||
)
|
||||
)`).exports.test(val), val);
|
||||
assertEq(val.i, -1);
|
||||
}
|
||||
|
||||
assertJoin("(block anyref get_local $ref)");
|
||||
assertJoin("(block $out anyref get_local $ref br $out)");
|
||||
assertJoin("(loop anyref get_local $ref)");
|
||||
|
||||
assertJoin(`(block $out anyref (loop $top anyref
|
||||
get_local $i
|
||||
i32.const 1
|
||||
i32.add
|
||||
tee_local $i
|
||||
i32.const 10
|
||||
i32.eq
|
||||
if
|
||||
get_local $ref
|
||||
return
|
||||
end
|
||||
br $top))
|
||||
`);
|
||||
|
||||
assertJoin(`(block $out (loop $top
|
||||
get_local $i
|
||||
i32.const 1
|
||||
i32.add
|
||||
tee_local $i
|
||||
i32.const 10
|
||||
i32.le_s
|
||||
if
|
||||
br $top
|
||||
else
|
||||
get_local $ref
|
||||
return
|
||||
end
|
||||
)) unreachable
|
||||
`);
|
||||
|
||||
assertJoin(`(block $out anyref (loop $top
|
||||
get_local $ref
|
||||
get_local $i
|
||||
i32.const 1
|
||||
i32.add
|
||||
tee_local $i
|
||||
i32.const 10
|
||||
i32.eq
|
||||
br_if $out
|
||||
br $top
|
||||
) unreachable)
|
||||
`);
|
||||
|
||||
assertJoin(`(block $out anyref (block $unreachable anyref (loop $top
|
||||
get_local $ref
|
||||
get_local $i
|
||||
i32.const 1
|
||||
i32.add
|
||||
tee_local $i
|
||||
br_table $unreachable $out
|
||||
) unreachable))
|
||||
`);
|
||||
|
||||
let x = { i: 42 }, y = { f: 53 };
|
||||
exports = wasmEvalText(`(module
|
||||
(func (export "test") (param $lhs anyref) (param $rhs anyref) (param $i i32) (result anyref)
|
||||
get_local $lhs
|
||||
get_local $rhs
|
||||
get_local $i
|
||||
select
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
let result = exports.test(x, y, 0);
|
||||
assertEq(result, y);
|
||||
assertEq(result.i, undefined);
|
||||
assertEq(result.f, 53);
|
||||
assertEq(x.i, 42);
|
||||
|
||||
result = exports.test(x, y, 1);
|
||||
assertEq(result, x);
|
||||
assertEq(result.i, 42);
|
||||
assertEq(result.f, undefined);
|
||||
assertEq(y.f, 53);
|
||||
|
||||
// Anyref in params/result of imported functions.
|
||||
|
||||
let firstBaguette = new Baguette(13),
|
||||
secondBaguette = new Baguette(37);
|
||||
|
||||
let imports = {
|
||||
i: 0,
|
||||
myBaguette: null,
|
||||
funcs: {
|
||||
param(x) {
|
||||
if (this.i === 0) {
|
||||
assertEq(x, firstBaguette);
|
||||
assertEq(x.calories, 13);
|
||||
assertEq(secondBaguette !== null, true);
|
||||
} else if (this.i === 1 || this.i === 2) {
|
||||
assertEq(x, secondBaguette);
|
||||
assertEq(x.calories, 37);
|
||||
assertEq(firstBaguette !== null, true);
|
||||
} else if (this.i === 3) {
|
||||
assertEq(x, null);
|
||||
} else {
|
||||
firstBaguette = null;
|
||||
secondBaguette = null;
|
||||
gc(); // evil mode
|
||||
}
|
||||
this.i++;
|
||||
},
|
||||
ret() {
|
||||
return imports.myBaguette;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports = wasmEvalText(`(module
|
||||
(import $ret "funcs" "ret" (result anyref))
|
||||
(import $param "funcs" "param" (param anyref))
|
||||
|
||||
(func (export "param") (param $x anyref) (param $y anyref)
|
||||
get_local $y
|
||||
get_local $x
|
||||
call $param
|
||||
call $param
|
||||
)
|
||||
|
||||
(func (export "ret") (result anyref)
|
||||
call $ret
|
||||
)
|
||||
)`, imports).exports;
|
||||
|
||||
exports.param(firstBaguette, secondBaguette);
|
||||
exports.param(secondBaguette, null);
|
||||
exports.param(firstBaguette, secondBaguette);
|
||||
|
||||
imports.myBaguette = null;
|
||||
assertEq(exports.ret(), null);
|
||||
|
||||
imports.myBaguette = new Baguette(1337);
|
||||
assertEq(exports.ret(), imports.myBaguette);
|
||||
|
||||
// Check lazy stubs generation.
|
||||
|
||||
exports = wasmEvalText(`(module
|
||||
(import $mirror "funcs" "mirror" (param anyref) (result anyref))
|
||||
(import $augment "funcs" "augment" (param anyref) (result anyref))
|
||||
|
||||
(global $count_f (mut i32) (i32.const 0))
|
||||
(global $count_g (mut i32) (i32.const 0))
|
||||
|
||||
(func $f (param $param anyref) (result anyref)
|
||||
i32.const 1
|
||||
get_global $count_f
|
||||
i32.add
|
||||
set_global $count_f
|
||||
|
||||
get_local $param
|
||||
call $augment
|
||||
)
|
||||
|
||||
(func $g (param $param anyref) (result anyref)
|
||||
i32.const 1
|
||||
get_global $count_g
|
||||
i32.add
|
||||
set_global $count_g
|
||||
|
||||
get_local $param
|
||||
call $mirror
|
||||
)
|
||||
|
||||
(table (export "table") 10 anyfunc)
|
||||
(elem (i32.const 0) $f $g $mirror $augment)
|
||||
(type $table_type (func (param anyref) (result anyref)))
|
||||
|
||||
(func (export "call_indirect") (param $i i32) (param $ref anyref) (result anyref)
|
||||
get_local $ref
|
||||
get_local $i
|
||||
call_indirect $table_type
|
||||
)
|
||||
|
||||
(func (export "count_f") (result i32) get_global $count_f)
|
||||
(func (export "count_g") (result i32) get_global $count_g)
|
||||
)`, {
|
||||
funcs: {
|
||||
mirror(x) {
|
||||
return x;
|
||||
},
|
||||
augment(x) {
|
||||
x.i++;
|
||||
x.newProp = "hello";
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}).exports;
|
||||
|
||||
x = { i: 19 };
|
||||
assertEq(exports.table.get(0)(x), x);
|
||||
assertEq(x.i, 20);
|
||||
assertEq(x.newProp, "hello");
|
||||
assertEq(exports.count_f(), 1);
|
||||
assertEq(exports.count_g(), 0);
|
||||
|
||||
x = { i: 21 };
|
||||
assertEq(exports.table.get(1)(x), x);
|
||||
assertEq(x.i, 21);
|
||||
assertEq(typeof x.newProp, "undefined");
|
||||
assertEq(exports.count_f(), 1);
|
||||
assertEq(exports.count_g(), 1);
|
||||
|
||||
x = { i: 22 };
|
||||
assertEq(exports.table.get(2)(x), x);
|
||||
assertEq(x.i, 22);
|
||||
assertEq(typeof x.newProp, "undefined");
|
||||
assertEq(exports.count_f(), 1);
|
||||
assertEq(exports.count_g(), 1);
|
||||
|
||||
x = { i: 23 };
|
||||
assertEq(exports.table.get(3)(x), x);
|
||||
assertEq(x.i, 24);
|
||||
assertEq(x.newProp, "hello");
|
||||
assertEq(exports.count_f(), 1);
|
||||
assertEq(exports.count_g(), 1);
|
|
@ -0,0 +1 @@
|
|||
|jit-test| test-also=--wasm-gc; include:wasm.js
|
|
@ -0,0 +1,28 @@
|
|||
if (wasmGcEnabled()) {
|
||||
quit();
|
||||
}
|
||||
|
||||
const { CompileError, validate } = WebAssembly;
|
||||
|
||||
const UNRECOGNIZED_OPCODE_OR_BAD_TYPE = /(unrecognized opcode|bad type|invalid inline block type)/;
|
||||
|
||||
function assertValidateError(text) {
|
||||
assertEq(validate(wasmTextToBinary(text)), false);
|
||||
}
|
||||
|
||||
let simpleTests = [
|
||||
"(module (func (drop (ref.null anyref))))",
|
||||
"(module (func $test (local anyref)))",
|
||||
"(module (func $test (param anyref)))",
|
||||
"(module (func $test (result anyref) (ref.null anyref)))",
|
||||
"(module (func $test (block anyref (unreachable)) unreachable))",
|
||||
"(module (func $test (local anyref) (result i32) (ref.is_null (get_local 0))))",
|
||||
`(module (import "a" "b" (param anyref)))`,
|
||||
`(module (import "a" "b" (result anyref)))`,
|
||||
];
|
||||
|
||||
for (let src of simpleTests) {
|
||||
print(src)
|
||||
assertErrorMessage(() => wasmEvalText(src), CompileError, UNRECOGNIZED_OPCODE_OR_BAD_TYPE);
|
||||
assertValidateError(src);
|
||||
}
|
|
@ -568,6 +568,8 @@ MIRTypeToSize(MIRType type)
|
|||
return 4;
|
||||
case MIRType::Double:
|
||||
return 8;
|
||||
case MIRType::Pointer:
|
||||
return sizeof(uintptr_t);
|
||||
default:
|
||||
MOZ_CRASH("MIRTypeToSize - unhandled case");
|
||||
}
|
||||
|
|
|
@ -935,6 +935,9 @@ class JS_PUBLIC_API(ContextOptions) {
|
|||
wasm_(true),
|
||||
wasmBaseline_(true),
|
||||
wasmIon_(true),
|
||||
#ifdef ENABLE_WASM_GC
|
||||
wasmGc_(false),
|
||||
#endif
|
||||
testWasmAwaitTier2_(false),
|
||||
throwOnAsmJSValidationFailure_(false),
|
||||
nativeRegExp_(true),
|
||||
|
@ -1032,6 +1035,14 @@ class JS_PUBLIC_API(ContextOptions) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
bool wasmGc() const { return wasmGc_; }
|
||||
ContextOptions& setWasmGc(bool flag) {
|
||||
wasmGc_ = flag;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; }
|
||||
ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) {
|
||||
throwOnAsmJSValidationFailure_ = flag;
|
||||
|
@ -1117,6 +1128,9 @@ class JS_PUBLIC_API(ContextOptions) {
|
|||
setWasm(false);
|
||||
setWasmBaseline(false);
|
||||
setWasmIon(false);
|
||||
#ifdef ENABLE_WASM_GC
|
||||
setWasmGc(false);
|
||||
#endif
|
||||
setNativeRegExp(false);
|
||||
}
|
||||
|
||||
|
@ -1127,6 +1141,9 @@ class JS_PUBLIC_API(ContextOptions) {
|
|||
bool wasm_ : 1;
|
||||
bool wasmBaseline_ : 1;
|
||||
bool wasmIon_ : 1;
|
||||
#ifdef ENABLE_WASM_GC
|
||||
bool wasmGc_ : 1;
|
||||
#endif
|
||||
bool testWasmAwaitTier2_ : 1;
|
||||
bool throwOnAsmJSValidationFailure_ : 1;
|
||||
bool nativeRegExp_ : 1;
|
||||
|
|
|
@ -695,6 +695,7 @@ if CONFIG['NIGHTLY_BUILD']:
|
|||
DEFINES['ENABLE_WASM_SATURATING_TRUNC_OPS'] = True
|
||||
DEFINES['ENABLE_WASM_SIGNEXTEND_OPS'] = True
|
||||
DEFINES['ENABLE_WASM_THREAD_OPS'] = True
|
||||
DEFINES['ENABLE_WASM_GC'] = True
|
||||
|
||||
# An experiment we want to run on Nightly and early Beta: Can we change the JS
|
||||
# representation of an exported global from the global's value to an instance
|
||||
|
|
|
@ -482,6 +482,9 @@ static bool enableNativeRegExp = false;
|
|||
static bool enableSharedMemory = SHARED_MEMORY_DEFAULT;
|
||||
static bool enableWasmBaseline = false;
|
||||
static bool enableWasmIon = false;
|
||||
#ifdef ENABLE_WASM_GC
|
||||
static bool enableWasmGc = false;
|
||||
#endif
|
||||
static bool enableTestWasmAwaitTier2 = false;
|
||||
static bool enableAsyncStacks = false;
|
||||
static bool enableStreams = false;
|
||||
|
@ -8295,6 +8298,9 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
|
|||
enableNativeRegExp = !op.getBoolOption("no-native-regexp");
|
||||
enableWasmBaseline = !op.getBoolOption("no-wasm-baseline");
|
||||
enableWasmIon = !op.getBoolOption("no-wasm-ion");
|
||||
#ifdef ENABLE_WASM_GC
|
||||
enableWasmGc = op.getBoolOption("wasm-gc");
|
||||
#endif
|
||||
enableTestWasmAwaitTier2 = op.getBoolOption("test-wasm-await-tier2");
|
||||
enableAsyncStacks = !op.getBoolOption("no-async-stacks");
|
||||
enableStreams = op.getBoolOption("enable-streams");
|
||||
|
@ -8306,6 +8312,9 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
|
|||
.setWasm(enableWasm)
|
||||
.setWasmBaseline(enableWasmBaseline)
|
||||
.setWasmIon(enableWasmIon)
|
||||
#ifdef ENABLE_WASM_GC
|
||||
.setWasmGc(enableWasmGc)
|
||||
#endif
|
||||
.setTestWasmAwaitTier2(enableTestWasmAwaitTier2)
|
||||
.setNativeRegExp(enableNativeRegExp)
|
||||
.setAsyncStack(enableAsyncStacks)
|
||||
|
@ -8608,6 +8617,9 @@ SetWorkerContextOptions(JSContext* cx)
|
|||
.setWasm(enableWasm)
|
||||
.setWasmBaseline(enableWasmBaseline)
|
||||
.setWasmIon(enableWasmIon)
|
||||
#ifdef ENABLE_WASM_GC
|
||||
.setWasmGc(enableWasmGc)
|
||||
#endif
|
||||
.setTestWasmAwaitTier2(enableTestWasmAwaitTier2)
|
||||
.setNativeRegExp(enableNativeRegExp)
|
||||
.setStreams(enableStreams)
|
||||
|
@ -8851,6 +8863,9 @@ main(int argc, char** argv, char** envp)
|
|||
|| !op.addBoolOption('\0', "no-wasm-ion", "Disable wasm ion compiler")
|
||||
|| !op.addBoolOption('\0', "test-wasm-await-tier2", "Forcibly activate tiering and block "
|
||||
"instantiation on completion of tier2")
|
||||
#ifdef ENABLE_WASM_GC
|
||||
|| !op.addBoolOption('\0', "wasm-gc", "Enable wasm GC features")
|
||||
#endif
|
||||
|| !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
|
||||
|| !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects")
|
||||
|| !op.addBoolOption('\0', "enable-streams", "Enable WHATWG Streams")
|
||||
|
|
|
@ -20,6 +20,9 @@ UNIFIED_SOURCES += [
|
|||
DEFINES['EXPORT_JS_API'] = True
|
||||
DEFINES['ENABLE_WASM_GLOBAL'] = True
|
||||
|
||||
if CONFIG['NIGHTLY_BUILD']:
|
||||
DEFINES['ENABLE_WASM_GC'] = True
|
||||
|
||||
# Also set in ../moz.build
|
||||
DEFINES['ENABLE_SHARED_ARRAY_BUFFER'] = True
|
||||
|
||||
|
|
|
@ -116,6 +116,10 @@ class ProtectedData
|
|||
T& refNoCheck() { return value; }
|
||||
const T& refNoCheck() const { return value; }
|
||||
|
||||
static size_t offsetOfValue() {
|
||||
return offsetof(ThisType, value);
|
||||
}
|
||||
|
||||
private:
|
||||
T value;
|
||||
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
|
||||
|
|
|
@ -95,6 +95,7 @@ class JSFunction : public js::NativeObject
|
|||
NATIVE_CLASS_CTOR = NATIVE_FUN | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
|
||||
ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
|
||||
ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
|
||||
ASMJS_NATIVE = ASMJS_KIND | NATIVE_FUN,
|
||||
WASM_FUN = NATIVE_FUN | WASM_OPTIMIZED,
|
||||
INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
|
||||
INTERPRETED_METHOD_GENERATOR_OR_ASYNC = INTERPRETED | METHOD_KIND,
|
||||
|
|
|
@ -1759,7 +1759,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
arrayViews_(cx),
|
||||
atomicsPresent_(false),
|
||||
simdPresent_(false),
|
||||
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False,
|
||||
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, HasGcTypes::False,
|
||||
cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled()
|
||||
? Shareable::True
|
||||
: Shareable::False,
|
||||
|
@ -7724,6 +7724,9 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp
|
|||
*val = Val(simdConstant.asInt32x4());
|
||||
return true;
|
||||
}
|
||||
case ValType::AnyRef: {
|
||||
MOZ_CRASH("not available in asm.js");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -209,6 +209,7 @@ enum class AstExprKind
|
|||
Load,
|
||||
Nop,
|
||||
Pop,
|
||||
RefNull,
|
||||
Return,
|
||||
SetGlobal,
|
||||
SetLocal,
|
||||
|
@ -1163,6 +1164,19 @@ class AstExtraConversionOperator final : public AstExpr
|
|||
};
|
||||
#endif
|
||||
|
||||
class AstRefNull final : public AstExpr
|
||||
{
|
||||
ValType refType_;
|
||||
public:
|
||||
static const AstExprKind Kind = AstExprKind::RefNull;
|
||||
explicit AstRefNull(ValType refType)
|
||||
: AstExpr(Kind, ExprType::Limit), refType_(refType)
|
||||
{}
|
||||
ValType refType() const {
|
||||
return refType_;
|
||||
}
|
||||
};
|
||||
|
||||
// This is an artificial AST node which can fill operand slots in an AST
|
||||
// constructed from parsing or decoding stack-machine code that doesn't have
|
||||
// an inherent AST structure.
|
||||
|
|
|
@ -296,6 +296,15 @@ struct RegI64 : public Register64
|
|||
static RegI64 Invalid() { return RegI64(Register64::Invalid()); }
|
||||
};
|
||||
|
||||
struct RegPtr : public Register
|
||||
{
|
||||
RegPtr() : Register(Register::Invalid()) {}
|
||||
explicit RegPtr(Register reg) : Register(reg) {}
|
||||
bool isValid() const { return *this != Invalid(); }
|
||||
bool isInvalid() const { return !isValid(); }
|
||||
static RegPtr Invalid() { return RegPtr(Register::Invalid()); }
|
||||
};
|
||||
|
||||
struct RegF32 : public FloatRegister
|
||||
{
|
||||
RegF32() : FloatRegister() {}
|
||||
|
@ -316,10 +325,21 @@ struct RegF64 : public FloatRegister
|
|||
|
||||
struct AnyReg
|
||||
{
|
||||
union {
|
||||
RegI32 i32_;
|
||||
RegI64 i64_;
|
||||
RegPtr ref_;
|
||||
RegF32 f32_;
|
||||
RegF64 f64_;
|
||||
};
|
||||
|
||||
enum { I32, I64, REF, F32, F64 } tag;
|
||||
|
||||
explicit AnyReg(RegI32 r) { tag = I32; i32_ = r; }
|
||||
explicit AnyReg(RegI64 r) { tag = I64; i64_ = r; }
|
||||
explicit AnyReg(RegF32 r) { tag = F32; f32_ = r; }
|
||||
explicit AnyReg(RegF64 r) { tag = F64; f64_ = r; }
|
||||
explicit AnyReg(RegPtr r) { tag = REF; ref_ = r; }
|
||||
|
||||
RegI32 i32() const {
|
||||
MOZ_ASSERT(tag == I32);
|
||||
|
@ -337,6 +357,11 @@ struct AnyReg
|
|||
MOZ_ASSERT(tag == F64);
|
||||
return f64_;
|
||||
}
|
||||
RegPtr ref() const {
|
||||
MOZ_ASSERT(tag == REF);
|
||||
return ref_;
|
||||
}
|
||||
|
||||
AnyRegister any() const {
|
||||
switch (tag) {
|
||||
case F32: return AnyRegister(f32_);
|
||||
|
@ -352,20 +377,14 @@ struct AnyReg
|
|||
// only on 64-bit platforms.
|
||||
MOZ_CRASH("AnyReg::any() on 32-bit platform");
|
||||
#endif
|
||||
case REF:
|
||||
MOZ_CRASH("AnyReg::any() not implemented for ref types");
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
// Work around GCC 5 analysis/warning bug.
|
||||
MOZ_CRASH("AnyReg::any(): impossible case");
|
||||
}
|
||||
|
||||
union {
|
||||
RegI32 i32_;
|
||||
RegI64 i64_;
|
||||
RegF32 f32_;
|
||||
RegF64 f64_;
|
||||
};
|
||||
enum { I32, I64, F32, F64 } tag;
|
||||
};
|
||||
|
||||
// Platform-specific registers.
|
||||
|
@ -691,6 +710,10 @@ class BaseRegAlloc
|
|||
#endif
|
||||
}
|
||||
|
||||
bool isAvailablePtr(RegPtr r) {
|
||||
return isAvailableGPR(r);
|
||||
}
|
||||
|
||||
bool isAvailableF32(RegF32 r) {
|
||||
return isAvailableFPU(r);
|
||||
}
|
||||
|
@ -726,6 +749,18 @@ class BaseRegAlloc
|
|||
allocInt64(specific);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE RegPtr needPtr() {
|
||||
if (!hasGPR())
|
||||
bc.sync();
|
||||
return RegPtr(allocGPR());
|
||||
}
|
||||
|
||||
void needPtr(RegPtr specific) {
|
||||
if (!isAvailablePtr(specific))
|
||||
bc.sync();
|
||||
allocGPR(specific);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE RegF32 needF32() {
|
||||
if (!hasFPU<MIRType::Float32>())
|
||||
bc.sync();
|
||||
|
@ -758,6 +793,10 @@ class BaseRegAlloc
|
|||
freeInt64(r);
|
||||
}
|
||||
|
||||
void freePtr(RegPtr r) {
|
||||
freeGPR(r);
|
||||
}
|
||||
|
||||
void freeF64(RegF64 r) {
|
||||
freeFPU(r);
|
||||
}
|
||||
|
@ -817,6 +856,10 @@ class BaseRegAlloc
|
|||
void addKnownF64(RegF64 r) {
|
||||
knownFPU_.add(r);
|
||||
}
|
||||
|
||||
void addKnownRef(RegPtr r) {
|
||||
knownGPR_.add(r);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
@ -888,23 +931,28 @@ class ScratchF32 : public ScratchFloat32Scope
|
|||
#endif
|
||||
|
||||
#ifdef RABALDR_SCRATCH_I32
|
||||
class ScratchI32 : public BaseScratchRegister
|
||||
template<class RegType>
|
||||
class ScratchGPR : public BaseScratchRegister
|
||||
{
|
||||
public:
|
||||
explicit ScratchI32(BaseRegAlloc& ra)
|
||||
explicit ScratchGPR(BaseRegAlloc& ra)
|
||||
: BaseScratchRegister(ra, BaseRegAlloc::ScratchKind::I32)
|
||||
{}
|
||||
operator RegI32() const { return RegI32(RabaldrScratchI32); }
|
||||
operator RegType() const { return RegType(RabaldrScratchI32); }
|
||||
};
|
||||
#else
|
||||
class ScratchI32 : public ScratchRegisterScope
|
||||
template<class RegType>
|
||||
class ScratchGPR : public ScratchRegisterScope
|
||||
{
|
||||
public:
|
||||
explicit ScratchI32(MacroAssembler& m) : ScratchRegisterScope(m) {}
|
||||
operator RegI32() const { return RegI32(Register(*this)); }
|
||||
explicit ScratchGPR(MacroAssembler& m) : ScratchRegisterScope(m) {}
|
||||
operator RegType() const { return RegType(Register(*this)); }
|
||||
};
|
||||
#endif
|
||||
|
||||
using ScratchI32 = ScratchGPR<RegI32>;
|
||||
using ScratchPtr = ScratchGPR<RegPtr>;
|
||||
|
||||
#if defined(JS_CODEGEN_X86)
|
||||
// ScratchEBX is a mnemonic device: For some atomic ops we really need EBX,
|
||||
// no other register will do. And we would normally have to allocate that
|
||||
|
@ -985,6 +1033,7 @@ BaseLocalIter::settle()
|
|||
case MIRType::Int64:
|
||||
case MIRType::Double:
|
||||
case MIRType::Float32:
|
||||
case MIRType::Pointer:
|
||||
if (argsIter_->argInRegister())
|
||||
frameOffset_ = pushLocal(MIRTypeToSize(mirType_));
|
||||
else
|
||||
|
@ -1003,6 +1052,7 @@ BaseLocalIter::settle()
|
|||
case ValType::I64:
|
||||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
case ValType::AnyRef:
|
||||
mirType_ = ToMIRType(locals_[index_]);
|
||||
frameOffset_ = pushLocal(MIRTypeToSize(mirType_));
|
||||
break;
|
||||
|
@ -1242,7 +1292,7 @@ class BaseStackFrame
|
|||
masm.load64(Address(sp_, localOffset(src)), dest);
|
||||
}
|
||||
|
||||
void loadLocalPtr(const Local& src, Register dest) {
|
||||
void loadLocalPtr(const Local& src, RegPtr dest) {
|
||||
masm.loadPtr(Address(sp_, localOffset(src)), dest);
|
||||
}
|
||||
|
||||
|
@ -1551,7 +1601,7 @@ class BaseStackFrame
|
|||
// Disambiguation: this loads a "Ptr" value from the stack, it does not load
|
||||
// the "StackPtr".
|
||||
|
||||
void loadStackPtr(int32_t offset, Register dest) {
|
||||
void loadStackPtr(int32_t offset, RegPtr dest) {
|
||||
masm.loadPtr(Address(sp_, stackOffset(offset)), dest);
|
||||
}
|
||||
|
||||
|
@ -1862,6 +1912,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
|
||||
RegI32 joinRegI32_;
|
||||
RegI64 joinRegI64_;
|
||||
RegPtr joinRegPtr_;
|
||||
RegF32 joinRegF32_;
|
||||
RegF64 joinRegF64_;
|
||||
|
||||
|
@ -1924,16 +1975,19 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
|
||||
bool isAvailableI32(RegI32 r) { return ra.isAvailableI32(r); }
|
||||
bool isAvailableI64(RegI64 r) { return ra.isAvailableI64(r); }
|
||||
bool isAvailableRef(RegPtr r) { return ra.isAvailablePtr(r); }
|
||||
bool isAvailableF32(RegF32 r) { return ra.isAvailableF32(r); }
|
||||
bool isAvailableF64(RegF64 r) { return ra.isAvailableF64(r); }
|
||||
|
||||
MOZ_MUST_USE RegI32 needI32() { return ra.needI32(); }
|
||||
MOZ_MUST_USE RegI64 needI64() { return ra.needI64(); }
|
||||
MOZ_MUST_USE RegPtr needRef() { return ra.needPtr(); }
|
||||
MOZ_MUST_USE RegF32 needF32() { return ra.needF32(); }
|
||||
MOZ_MUST_USE RegF64 needF64() { return ra.needF64(); }
|
||||
|
||||
void needI32(RegI32 specific) { ra.needI32(specific); }
|
||||
void needI64(RegI64 specific) { ra.needI64(specific); }
|
||||
void needRef(RegPtr specific) { ra.needPtr(specific); }
|
||||
void needF32(RegF32 specific) { ra.needF32(specific); }
|
||||
void needF64(RegF64 specific) { ra.needF64(specific); }
|
||||
|
||||
|
@ -1943,6 +1997,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
|
||||
void freeI32(RegI32 r) { ra.freeI32(r); }
|
||||
void freeI64(RegI64 r) { ra.freeI64(r); }
|
||||
void freeRef(RegPtr r) { ra.freePtr(r); }
|
||||
void freeF32(RegF32 r) { ra.freeF32(r); }
|
||||
void freeF64(RegF64 r) { ra.freeF64(r); }
|
||||
|
||||
|
@ -2018,6 +2073,10 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
#endif
|
||||
}
|
||||
|
||||
RegI32 narrowPtr(RegPtr r) {
|
||||
return RegI32(r);
|
||||
}
|
||||
|
||||
RegI32 lowPart(RegI64 r) {
|
||||
#ifdef JS_PUNBOX64
|
||||
return RegI32(r.reg);
|
||||
|
@ -2050,6 +2109,11 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
masm.move64(src, dest);
|
||||
}
|
||||
|
||||
void moveRef(RegPtr src, RegPtr dest) {
|
||||
if (src != dest)
|
||||
masm.movePtr(src, dest);
|
||||
}
|
||||
|
||||
void moveF64(RegF64 src, RegF64 dest) {
|
||||
if (src != dest)
|
||||
masm.moveDouble(src, dest);
|
||||
|
@ -2065,6 +2129,8 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
needI32(joinRegI32_);
|
||||
else if (type == ExprType::I64)
|
||||
needI64(joinRegI64_);
|
||||
else if (type == ExprType::AnyRef)
|
||||
needRef(joinRegPtr_);
|
||||
}
|
||||
|
||||
void maybeUnreserveJoinRegI(ExprType type) {
|
||||
|
@ -2072,6 +2138,8 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
freeI32(joinRegI32_);
|
||||
else if (type == ExprType::I64)
|
||||
freeI64(joinRegI64_);
|
||||
else if (type == ExprType::AnyRef)
|
||||
freeRef(joinRegPtr_);
|
||||
}
|
||||
|
||||
void maybeReserveJoinReg(ExprType type) {
|
||||
|
@ -2088,6 +2156,9 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
case ExprType::F64:
|
||||
needF64(joinRegF64_);
|
||||
break;
|
||||
case ExprType::AnyRef:
|
||||
needRef(joinRegPtr_);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -2107,6 +2178,9 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
case ExprType::F64:
|
||||
freeF64(joinRegF64_);
|
||||
break;
|
||||
case ExprType::AnyRef:
|
||||
freeRef(joinRegPtr_);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -2127,6 +2201,10 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
|
||||
struct Stk
|
||||
{
|
||||
private:
|
||||
Stk() : kind_(Unknown), i64val_(0) {}
|
||||
|
||||
public:
|
||||
enum Kind
|
||||
{
|
||||
// The Mem opcodes are all clustered at the beginning to
|
||||
|
@ -2135,6 +2213,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
MemI64, // 64-bit integer stack value ("offs")
|
||||
MemF32, // 32-bit floating stack value ("offs")
|
||||
MemF64, // 64-bit floating stack value ("offs")
|
||||
MemRef, // reftype (pointer wide) stack value ("offs")
|
||||
|
||||
// The Local opcodes follow the Mem opcodes for a similar
|
||||
// quick test within hasLocal().
|
||||
|
@ -2142,47 +2221,61 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
LocalI64, // Local int64 var ("slot")
|
||||
LocalF32, // Local float32 var ("slot")
|
||||
LocalF64, // Local double var ("slot")
|
||||
LocalRef, // Local reftype (pointer wide) var ("slot")
|
||||
|
||||
RegisterI32, // 32-bit integer register ("i32reg")
|
||||
RegisterI64, // 64-bit integer register ("i64reg")
|
||||
RegisterF32, // 32-bit floating register ("f32reg")
|
||||
RegisterF64, // 64-bit floating register ("f64reg")
|
||||
RegisterRef, // reftype (pointer wide) register ("refReg")
|
||||
|
||||
ConstI32, // 32-bit integer constant ("i32val")
|
||||
ConstI64, // 64-bit integer constant ("i64val")
|
||||
ConstF32, // 32-bit floating constant ("f32val")
|
||||
ConstF64, // 64-bit floating constant ("f64val")
|
||||
ConstRef, // reftype (pointer wide) constant ("refval")
|
||||
|
||||
Unknown,
|
||||
};
|
||||
|
||||
Kind kind_;
|
||||
|
||||
static const Kind MemLast = MemF64;
|
||||
static const Kind LocalLast = LocalF64;
|
||||
static const Kind MemLast = MemRef;
|
||||
static const Kind LocalLast = LocalRef;
|
||||
|
||||
union {
|
||||
RegI32 i32reg_;
|
||||
RegI64 i64reg_;
|
||||
RegPtr refReg_;
|
||||
RegF32 f32reg_;
|
||||
RegF64 f64reg_;
|
||||
int32_t i32val_;
|
||||
int64_t i64val_;
|
||||
intptr_t refval_;
|
||||
float f32val_;
|
||||
double f64val_;
|
||||
uint32_t slot_;
|
||||
uint32_t offs_;
|
||||
};
|
||||
|
||||
explicit Stk(RegI32 r) : kind_(RegisterI32), i32reg_(r) {}
|
||||
explicit Stk(RegI64 r) : kind_(RegisterI64), i64reg_(r) {}
|
||||
explicit Stk(RegF32 r) : kind_(RegisterF32), f32reg_(r) {}
|
||||
explicit Stk(RegF64 r) : kind_(RegisterF64), f64reg_(r) {}
|
||||
explicit Stk(int32_t v) : kind_(ConstI32), i32val_(v) {}
|
||||
explicit Stk(int64_t v) : kind_(ConstI64), i64val_(v) {}
|
||||
explicit Stk(float v) : kind_(ConstF32), f32val_(v) {}
|
||||
explicit Stk(double v) : kind_(ConstF64), f64val_(v) {}
|
||||
explicit Stk(RegI32 r) : kind_(RegisterI32), i32reg_(r) {}
|
||||
explicit Stk(RegI64 r) : kind_(RegisterI64), i64reg_(r) {}
|
||||
explicit Stk(RegPtr r) : kind_(RegisterRef), refReg_(r) {}
|
||||
explicit Stk(RegF32 r) : kind_(RegisterF32), f32reg_(r) {}
|
||||
explicit Stk(RegF64 r) : kind_(RegisterF64), f64reg_(r) {}
|
||||
explicit Stk(int32_t v) : kind_(ConstI32), i32val_(v) {}
|
||||
explicit Stk(int64_t v) : kind_(ConstI64), i64val_(v) {}
|
||||
explicit Stk(float v) : kind_(ConstF32), f32val_(v) {}
|
||||
explicit Stk(double v) : kind_(ConstF64), f64val_(v) {}
|
||||
explicit Stk(Kind k, uint32_t v) : kind_(k), slot_(v) {
|
||||
MOZ_ASSERT(k > MemLast && k <= LocalLast);
|
||||
}
|
||||
static Stk StkRef(intptr_t v) {
|
||||
Stk s;
|
||||
s.kind_ = ConstRef;
|
||||
s.refval_ = v;
|
||||
return s;
|
||||
}
|
||||
|
||||
void setOffs(Kind k, uint32_t v) { MOZ_ASSERT(k <= MemLast); kind_ = k; offs_ = v; }
|
||||
|
||||
|
@ -2191,11 +2284,13 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
|
||||
RegI32 i32reg() const { MOZ_ASSERT(kind_ == RegisterI32); return i32reg_; }
|
||||
RegI64 i64reg() const { MOZ_ASSERT(kind_ == RegisterI64); return i64reg_; }
|
||||
RegPtr refReg() const { MOZ_ASSERT(kind_ == RegisterRef); return refReg_; }
|
||||
RegF32 f32reg() const { MOZ_ASSERT(kind_ == RegisterF32); return f32reg_; }
|
||||
RegF64 f64reg() const { MOZ_ASSERT(kind_ == RegisterF64); return f64reg_; }
|
||||
|
||||
int32_t i32val() const { MOZ_ASSERT(kind_ == ConstI32); return i32val_; }
|
||||
int64_t i64val() const { MOZ_ASSERT(kind_ == ConstI64); return i64val_; }
|
||||
intptr_t refval() const { MOZ_ASSERT(kind_ == ConstRef); return refval_; }
|
||||
|
||||
// For these two, use an out-param instead of simply returning, to
|
||||
// use the normal stack and not the x87 FP stack (which has effect on
|
||||
|
@ -2215,6 +2310,10 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
stk_.infallibleEmplaceBack(Stk(Forward<Args>(args)...));
|
||||
}
|
||||
|
||||
void pushConstRef(intptr_t v) {
|
||||
stk_.infallibleEmplaceBack(Stk::StkRef(v));
|
||||
}
|
||||
|
||||
void loadConstI32(const Stk& src, RegI32 dest) {
|
||||
moveImm32(src.i32val(), dest);
|
||||
}
|
||||
|
@ -2247,6 +2346,22 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
moveI64(src.i64reg(), dest);
|
||||
}
|
||||
|
||||
void loadConstRef(const Stk& src, RegPtr dest) {
|
||||
moveImmRef(src.refval(), dest);
|
||||
}
|
||||
|
||||
void loadMemRef(const Stk& src, RegPtr dest) {
|
||||
fr.loadStackPtr(src.offs(), dest);
|
||||
}
|
||||
|
||||
void loadLocalRef(const Stk& src, RegPtr dest) {
|
||||
fr.loadLocalPtr(localFromSlot(src.slot(), MIRType::Pointer), dest);
|
||||
}
|
||||
|
||||
void loadRegisterRef(const Stk& src, RegPtr dest) {
|
||||
moveRef(src.refReg(), dest);
|
||||
}
|
||||
|
||||
void loadConstF64(const Stk& src, RegF64 dest) {
|
||||
double d;
|
||||
src.f64val(&d);
|
||||
|
@ -2399,6 +2514,25 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
}
|
||||
}
|
||||
|
||||
void loadRef(const Stk& src, RegPtr dest) {
|
||||
switch (src.kind()) {
|
||||
case Stk::ConstRef:
|
||||
loadConstRef(src, dest);
|
||||
break;
|
||||
case Stk::MemRef:
|
||||
loadMemRef(src, dest);
|
||||
break;
|
||||
case Stk::LocalRef:
|
||||
loadLocalRef(src, dest);
|
||||
break;
|
||||
case Stk::RegisterRef:
|
||||
loadRegisterRef(src, dest);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Compiler bug: expected ref on stack");
|
||||
}
|
||||
}
|
||||
|
||||
// Flush all local and register value stack elements to memory.
|
||||
//
|
||||
// TODO / OPTIMIZE: As this is fairly expensive and causes worse
|
||||
|
@ -2501,6 +2635,19 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
v.setOffs(Stk::MemF32, offs);
|
||||
break;
|
||||
}
|
||||
case Stk::LocalRef: {
|
||||
ScratchPtr scratch(*this);
|
||||
loadLocalRef(v, scratch);
|
||||
uint32_t offs = fr.pushPtr(scratch);
|
||||
v.setOffs(Stk::MemRef, offs);
|
||||
break;
|
||||
}
|
||||
case Stk::RegisterRef: {
|
||||
uint32_t offs = fr.pushPtr(v.refReg());
|
||||
freeRef(v.refReg());
|
||||
v.setOffs(Stk::MemRef, offs);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
|
@ -2544,6 +2691,11 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
push(r);
|
||||
}
|
||||
|
||||
void pushRef(RegPtr r) {
|
||||
MOZ_ASSERT(!isAvailableRef(r));
|
||||
push(r);
|
||||
}
|
||||
|
||||
void pushF64(RegF64 r) {
|
||||
MOZ_ASSERT(!isAvailableF64(r));
|
||||
push(r);
|
||||
|
@ -2564,6 +2716,10 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
push(v);
|
||||
}
|
||||
|
||||
void pushRef(intptr_t v) {
|
||||
pushConstRef(v);
|
||||
}
|
||||
|
||||
void pushF64(double v) {
|
||||
push(v);
|
||||
}
|
||||
|
@ -2584,6 +2740,10 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
push(Stk::LocalI64, slot);
|
||||
}
|
||||
|
||||
void pushLocalRef(uint32_t slot) {
|
||||
push(Stk::LocalRef, slot);
|
||||
}
|
||||
|
||||
void pushLocalF64(uint32_t slot) {
|
||||
push(Stk::LocalF64, slot);
|
||||
}
|
||||
|
@ -2698,6 +2858,54 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
return specific;
|
||||
}
|
||||
|
||||
// Call only from other popRef() variants.
|
||||
// v must be the stack top. May pop the CPU stack.
|
||||
|
||||
void popRef(const Stk& v, RegPtr dest) {
|
||||
MOZ_ASSERT(&v == &stk_.back());
|
||||
switch (v.kind()) {
|
||||
case Stk::ConstRef:
|
||||
loadConstRef(v, dest);
|
||||
break;
|
||||
case Stk::LocalRef:
|
||||
loadLocalRef(v, dest);
|
||||
break;
|
||||
case Stk::MemRef:
|
||||
fr.popPtr(dest);
|
||||
break;
|
||||
case Stk::RegisterRef:
|
||||
loadRegisterRef(v, dest);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Compiler bug: expected ref on stack");
|
||||
}
|
||||
}
|
||||
|
||||
RegPtr popRef(RegPtr specific) {
|
||||
Stk& v = stk_.back();
|
||||
|
||||
if (!(v.kind() == Stk::RegisterRef && v.refReg() == specific)) {
|
||||
needRef(specific);
|
||||
popRef(v, specific);
|
||||
if (v.kind() == Stk::RegisterRef)
|
||||
freeRef(v.refReg());
|
||||
}
|
||||
|
||||
stk_.popBack();
|
||||
return specific;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE RegPtr popRef() {
|
||||
Stk& v = stk_.back();
|
||||
RegPtr r;
|
||||
if (v.kind() == Stk::RegisterRef)
|
||||
r = v.refReg();
|
||||
else
|
||||
popRef(v, (r = needRef()));
|
||||
stk_.popBack();
|
||||
return r;
|
||||
}
|
||||
|
||||
// Call only from other popF64() variants.
|
||||
// v must be the stack top. May pop the CPU stack.
|
||||
|
||||
|
@ -2914,6 +3122,12 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
k == Stk::LocalF32);
|
||||
return Some(AnyReg(popF32(joinRegF32_)));
|
||||
}
|
||||
case ExprType::AnyRef: {
|
||||
DebugOnly<Stk::Kind> k(stk_.back().kind());
|
||||
MOZ_ASSERT(k == Stk::RegisterRef || k == Stk::ConstRef || k == Stk::MemRef ||
|
||||
k == Stk::LocalRef);
|
||||
return Some(AnyReg(popRef(joinRegPtr_)));
|
||||
}
|
||||
default: {
|
||||
MOZ_CRASH("Compiler bug: unexpected expression type");
|
||||
}
|
||||
|
@ -2944,6 +3158,10 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
MOZ_ASSERT(isAvailableF64(joinRegF64_));
|
||||
needF64(joinRegF64_);
|
||||
return Some(AnyReg(joinRegF64_));
|
||||
case ExprType::AnyRef:
|
||||
MOZ_ASSERT(isAvailableRef(joinRegPtr_));
|
||||
needRef(joinRegPtr_);
|
||||
return Some(AnyReg(joinRegPtr_));
|
||||
case ExprType::Void:
|
||||
return Nothing();
|
||||
default:
|
||||
|
@ -2967,6 +3185,9 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
case AnyReg::F32:
|
||||
pushF32(r->f32());
|
||||
break;
|
||||
case AnyReg::REF:
|
||||
pushRef(r->ref());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2986,6 +3207,9 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
case AnyReg::F32:
|
||||
freeF32(r->f32());
|
||||
break;
|
||||
case AnyReg::REF:
|
||||
freeRef(r->ref());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2998,6 +3222,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
for (uint32_t i = stk_.length() - 1; numval > 0; numval--, i--) {
|
||||
Stk& v = stk_[i];
|
||||
switch (v.kind()) {
|
||||
case Stk::MemRef: size += BaseStackFrame::StackSizeOfPtr; break;
|
||||
case Stk::MemI32: size += BaseStackFrame::StackSizeOfPtr; break;
|
||||
case Stk::MemI64: size += BaseStackFrame::StackSizeOfInt64; break;
|
||||
case Stk::MemF64: size += BaseStackFrame::StackSizeOfDouble; break;
|
||||
|
@ -3024,6 +3249,9 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
case Stk::RegisterF32:
|
||||
freeF32(v.f32reg());
|
||||
break;
|
||||
case Stk::RegisterRef:
|
||||
freeRef(v.refReg());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3070,6 +3298,9 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
case Stk::RegisterF64:
|
||||
check.addKnownF64(item.f64reg());
|
||||
break;
|
||||
case Stk::RegisterRef:
|
||||
check.addKnownRef(item.refReg());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3159,6 +3390,9 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
case MIRType::Int64:
|
||||
fr.storeLocalI64(RegI64(i->gpr64()), l);
|
||||
break;
|
||||
case MIRType::Pointer:
|
||||
fr.storeLocalPtr(RegPtr(i->gpr()), l);
|
||||
break;
|
||||
case MIRType::Double:
|
||||
fr.storeLocalF64(RegF64(i->fpu()), l);
|
||||
break;
|
||||
|
@ -3488,6 +3722,17 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ValType::AnyRef: {
|
||||
ABIArg argLoc = call->abi.next(MIRType::Pointer);
|
||||
if (argLoc.kind() == ABIArg::Stack) {
|
||||
ScratchPtr scratch(*this);
|
||||
loadRef(arg, scratch);
|
||||
masm.storePtr(scratch, Address(masm.getStackPointer(), argLoc.offsetFromArgBase()));
|
||||
} else {
|
||||
loadRef(arg, RegPtr(argLoc.gpr()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Function argument type");
|
||||
}
|
||||
|
@ -3561,6 +3806,10 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
masm.move64(Imm64(v), dest);
|
||||
}
|
||||
|
||||
void moveImmRef(intptr_t v, RegPtr dest) {
|
||||
masm.movePtr(ImmWord(v), dest);
|
||||
}
|
||||
|
||||
void moveImmF32(float f, RegF32 dest) {
|
||||
masm.loadConstantFloat32(f, dest);
|
||||
}
|
||||
|
@ -3691,6 +3940,13 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
return r;
|
||||
}
|
||||
|
||||
RegPtr captureReturnedRef() {
|
||||
RegPtr r = RegPtr(ReturnReg);
|
||||
MOZ_ASSERT(isAvailableRef(r));
|
||||
needRef(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
void returnCleanup(bool popStack) {
|
||||
if (popStack)
|
||||
fr.popStackBeforeBranch(controlOutermost().stackHeight);
|
||||
|
@ -5275,6 +5531,11 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
*r0 = popF64();
|
||||
}
|
||||
|
||||
void pop2xRef(RegPtr* r0, RegPtr* r1) {
|
||||
*r1 = popRef();
|
||||
*r0 = popRef();
|
||||
}
|
||||
|
||||
RegI32 popI64ToI32() {
|
||||
RegI64 r = popI64();
|
||||
return narrowI64(r);
|
||||
|
@ -5614,6 +5875,9 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
MOZ_MUST_USE bool emitGrowMemory();
|
||||
MOZ_MUST_USE bool emitCurrentMemory();
|
||||
|
||||
MOZ_MUST_USE bool emitRefNull();
|
||||
void emitRefIsNull();
|
||||
|
||||
MOZ_MUST_USE bool emitAtomicCmpXchg(ValType type, Scalar::Type viewType);
|
||||
MOZ_MUST_USE bool emitAtomicLoad(ValType type, Scalar::Type viewType);
|
||||
MOZ_MUST_USE bool emitAtomicRMW(ValType type, Scalar::Type viewType, AtomicOp op);
|
||||
|
@ -6851,10 +7115,9 @@ BaseCompiler::sniffConditionalControlCmp(Cond compareOp, ValType operandType)
|
|||
OpBytes op;
|
||||
iter_.peekOp(&op);
|
||||
switch (op.b0) {
|
||||
case uint16_t(Op::Select):
|
||||
MOZ_FALLTHROUGH;
|
||||
case uint16_t(Op::BrIf):
|
||||
case uint16_t(Op::If):
|
||||
case uint16_t(Op::Select):
|
||||
setLatentCompare(compareOp, operandType);
|
||||
return true;
|
||||
default:
|
||||
|
@ -7436,6 +7699,12 @@ BaseCompiler::doReturn(ExprType type, bool popStack)
|
|||
freeF32(rv);
|
||||
break;
|
||||
}
|
||||
case ExprType::AnyRef: {
|
||||
RegPtr rv = popRef(RegPtr(ReturnReg));
|
||||
returnCleanup(popStack);
|
||||
freeRef(rv);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
MOZ_CRASH("Function return type");
|
||||
}
|
||||
|
@ -7500,6 +7769,11 @@ BaseCompiler::pushReturned(const FunctionCall& call, ExprType type)
|
|||
pushF64(rv);
|
||||
break;
|
||||
}
|
||||
case ExprType::AnyRef: {
|
||||
RegPtr rv = captureReturnedRef();
|
||||
pushRef(rv);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Function return type");
|
||||
}
|
||||
|
@ -7827,6 +8101,9 @@ BaseCompiler::emitGetLocal()
|
|||
case ValType::F32:
|
||||
pushLocalF32(slot);
|
||||
break;
|
||||
case ValType::AnyRef:
|
||||
pushLocalRef(slot);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Local variable type");
|
||||
}
|
||||
|
@ -7883,6 +8160,16 @@ BaseCompiler::emitSetOrTeeLocal(uint32_t slot)
|
|||
pushF32(rv);
|
||||
break;
|
||||
}
|
||||
case ValType::AnyRef: {
|
||||
RegPtr rv = popRef();
|
||||
syncLocal(slot);
|
||||
fr.storeLocalPtr(rv, localFromSlot(slot, MIRType::Pointer));
|
||||
if (isSetLocal)
|
||||
freeRef(rv);
|
||||
else
|
||||
pushRef(rv);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Local variable type");
|
||||
}
|
||||
|
@ -8403,6 +8690,16 @@ BaseCompiler::emitSelect()
|
|||
pushF64(r);
|
||||
break;
|
||||
}
|
||||
case ValType::AnyRef: {
|
||||
RegPtr r, rs;
|
||||
pop2xRef(&r, &rs);
|
||||
emitBranchPerform(&b);
|
||||
moveRef(rs, r);
|
||||
masm.bind(&done);
|
||||
freeRef(rs);
|
||||
pushRef(r);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
MOZ_CRASH("select type");
|
||||
}
|
||||
|
@ -8557,6 +8854,29 @@ BaseCompiler::emitCurrentMemory()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseCompiler::emitRefNull()
|
||||
{
|
||||
if (!iter_.readRefNull())
|
||||
return false;
|
||||
|
||||
if (deadCode_)
|
||||
return true;
|
||||
|
||||
pushRef(NULLREF_VALUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BaseCompiler::emitRefIsNull()
|
||||
{
|
||||
RegPtr r = popRef();
|
||||
RegI32 rd = narrowPtr(r);
|
||||
|
||||
masm.cmpPtrSet(Assembler::Equal, r, ImmWord(NULLREF_VALUE), rd);
|
||||
pushI32(rd);
|
||||
}
|
||||
|
||||
bool
|
||||
BaseCompiler::emitAtomicCmpXchg(ValType type, Scalar::Type viewType)
|
||||
{
|
||||
|
@ -9424,6 +9744,19 @@ BaseCompiler::emitBody()
|
|||
case uint16_t(Op::CurrentMemory):
|
||||
CHECK_NEXT(emitCurrentMemory());
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
case uint16_t(Op::RefNull):
|
||||
if (env_.gcTypesEnabled == HasGcTypes::False)
|
||||
return iter_.unrecognizedOpcode(&op);
|
||||
CHECK_NEXT(emitRefNull());
|
||||
break;
|
||||
case uint16_t(Op::RefIsNull):
|
||||
if (env_.gcTypesEnabled == HasGcTypes::False)
|
||||
return iter_.unrecognizedOpcode(&op);
|
||||
CHECK_NEXT(emitConversion(emitRefIsNull, ValType::AnyRef, ValType::I32));
|
||||
break;
|
||||
#endif
|
||||
|
||||
// Numeric operations
|
||||
case uint16_t(Op::NumericPrefix): {
|
||||
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
|
||||
|
@ -9702,6 +10035,7 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
|
|||
fr(*masm),
|
||||
joinRegI32_(RegI32(ReturnReg)),
|
||||
joinRegI64_(RegI64(ReturnReg64)),
|
||||
joinRegPtr_(RegPtr(ReturnReg)),
|
||||
joinRegF32_(RegF32(ReturnFloat32Reg)),
|
||||
joinRegF64_(RegF64(ReturnDoubleReg))
|
||||
{
|
||||
|
@ -9809,7 +10143,7 @@ js::wasm::BaselineCompileFunctions(const ModuleEnvironment& env, LifoAlloc& lifo
|
|||
ValTypeVector locals;
|
||||
if (!locals.appendAll(env.funcSigs[func.index]->args()))
|
||||
return false;
|
||||
if (!DecodeLocalEntries(d, env.kind, &locals))
|
||||
if (!DecodeLocalEntries(d, env.kind, env.gcTypesEnabled, &locals))
|
||||
return false;
|
||||
|
||||
// One-pass baseline compilation.
|
||||
|
|
|
@ -62,6 +62,9 @@ enum class TypeCode
|
|||
// A function pointer with any signature
|
||||
AnyFunc = 0x70, // SLEB128(-0x10)
|
||||
|
||||
// A reference to any type.
|
||||
AnyRef = 0x6f,
|
||||
|
||||
// Type constructor for function types
|
||||
Func = 0x60, // SLEB128(-0x20)
|
||||
|
||||
|
@ -78,6 +81,8 @@ enum class ValType
|
|||
F32 = uint8_t(TypeCode::F32),
|
||||
F64 = uint8_t(TypeCode::F64),
|
||||
|
||||
AnyRef = uint8_t(TypeCode::AnyRef),
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The rest of these types are currently only emitted internally when
|
||||
// compiling asm.js and are rejected by wasm validation.
|
||||
|
@ -93,6 +98,10 @@ enum class ValType
|
|||
|
||||
typedef Vector<ValType, 8, SystemAllocPolicy> ValTypeVector;
|
||||
|
||||
// The representation of a null reference value throughout the compiler.
|
||||
|
||||
static const intptr_t NULLREF_VALUE = intptr_t((void*)nullptr);
|
||||
|
||||
enum class DefinitionKind
|
||||
{
|
||||
Function = 0x00,
|
||||
|
@ -323,6 +332,10 @@ enum class Op
|
|||
I64Extend32S = 0xc4,
|
||||
#endif
|
||||
|
||||
// GC ops
|
||||
RefNull = 0xd0,
|
||||
RefIsNull = 0xd1,
|
||||
|
||||
FirstPrefix = 0xfc,
|
||||
NumericPrefix = 0xfc,
|
||||
ThreadPrefix = 0xfe,
|
||||
|
|
|
@ -177,6 +177,7 @@ wasm::Classify(OpBytes op)
|
|||
case Op::F64ConvertUI64:
|
||||
case Op::F64ReinterpretI64:
|
||||
case Op::F64PromoteF32:
|
||||
case Op::RefIsNull:
|
||||
#ifdef ENABLE_WASM_SIGNEXTEND_OPS
|
||||
case Op::I32Extend8S:
|
||||
case Op::I32Extend16S:
|
||||
|
@ -240,6 +241,8 @@ wasm::Classify(OpBytes op)
|
|||
return OpKind::CurrentMemory;
|
||||
case Op::GrowMemory:
|
||||
return OpKind::GrowMemory;
|
||||
case Op::RefNull:
|
||||
return OpKind::RefNull;
|
||||
case Op::NumericPrefix: {
|
||||
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
|
||||
switch (NumericOp(op.b1)) {
|
||||
|
|
|
@ -41,20 +41,22 @@ enum class LabelKind : uint8_t
|
|||
// represents the type of a value produced by an unconditional branch.
|
||||
enum class StackType
|
||||
{
|
||||
I32 = uint8_t(ValType::I32),
|
||||
I64 = uint8_t(ValType::I64),
|
||||
F32 = uint8_t(ValType::F32),
|
||||
F64 = uint8_t(ValType::F64),
|
||||
I32 = uint8_t(ValType::I32),
|
||||
I64 = uint8_t(ValType::I64),
|
||||
F32 = uint8_t(ValType::F32),
|
||||
F64 = uint8_t(ValType::F64),
|
||||
|
||||
I8x16 = uint8_t(ValType::I8x16),
|
||||
I16x8 = uint8_t(ValType::I16x8),
|
||||
I32x4 = uint8_t(ValType::I32x4),
|
||||
F32x4 = uint8_t(ValType::F32x4),
|
||||
B8x16 = uint8_t(ValType::B8x16),
|
||||
B16x8 = uint8_t(ValType::B16x8),
|
||||
B32x4 = uint8_t(ValType::B32x4),
|
||||
I8x16 = uint8_t(ValType::I8x16),
|
||||
I16x8 = uint8_t(ValType::I16x8),
|
||||
I32x4 = uint8_t(ValType::I32x4),
|
||||
F32x4 = uint8_t(ValType::F32x4),
|
||||
B8x16 = uint8_t(ValType::B8x16),
|
||||
B16x8 = uint8_t(ValType::B16x8),
|
||||
B32x4 = uint8_t(ValType::B32x4),
|
||||
|
||||
Any = uint8_t(TypeCode::Limit)
|
||||
AnyRef = uint8_t(ValType::AnyRef),
|
||||
|
||||
Any = uint8_t(TypeCode::Limit),
|
||||
};
|
||||
|
||||
static inline StackType
|
||||
|
@ -71,7 +73,49 @@ NonAnyToValType(StackType type)
|
|||
}
|
||||
|
||||
static inline bool
|
||||
Unify(StackType one, StackType two, StackType* result)
|
||||
IsRefType(StackType st)
|
||||
{
|
||||
return IsRefType(NonAnyToValType(st));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsSubtypeOf(StackType one, StackType two)
|
||||
{
|
||||
MOZ_ASSERT(IsRefType(one));
|
||||
MOZ_ASSERT(IsRefType(two));
|
||||
return one == two || two == StackType::AnyRef;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Unify(HasGcTypes gcTypesEnabled, StackType observed, StackType expected, StackType* result)
|
||||
{
|
||||
if (MOZ_LIKELY(observed == expected)) {
|
||||
*result = observed;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (observed == StackType::Any) {
|
||||
*result = expected;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expected == StackType::Any) {
|
||||
*result = observed;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gcTypesEnabled == HasGcTypes::True && IsRefType(observed) && IsRefType(expected) &&
|
||||
IsSubtypeOf(observed, expected))
|
||||
{
|
||||
*result = expected;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Join(HasGcTypes gcTypesEnabled, StackType one, StackType two, StackType* result)
|
||||
{
|
||||
if (MOZ_LIKELY(one == two)) {
|
||||
*result = one;
|
||||
|
@ -88,6 +132,22 @@ Unify(StackType one, StackType two, StackType* result)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (gcTypesEnabled == HasGcTypes::True && IsRefType(one) && IsRefType(two)) {
|
||||
if (IsSubtypeOf(two, one)) {
|
||||
*result = one;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsSubtypeOf(one, two)) {
|
||||
*result = two;
|
||||
return true;
|
||||
}
|
||||
|
||||
// No subtyping relations between the two types.
|
||||
*result = StackType::AnyRef;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -113,7 +173,6 @@ enum class OpKind {
|
|||
BrIf,
|
||||
BrTable,
|
||||
Nop,
|
||||
Nullary,
|
||||
Unary,
|
||||
Binary,
|
||||
Comparison,
|
||||
|
@ -159,6 +218,7 @@ enum class OpKind {
|
|||
SimdBooleanReduction,
|
||||
SimdShiftByScalar,
|
||||
SimdComparison,
|
||||
RefNull,
|
||||
};
|
||||
|
||||
// Return the OpKind for a given Op. This is used for sanity-checking that
|
||||
|
@ -534,6 +594,7 @@ class MOZ_STACK_CLASS OpIter : private Policy
|
|||
MOZ_MUST_USE bool readB8x16Const(I8x16* i8x16);
|
||||
MOZ_MUST_USE bool readB16x8Const(I16x8* i16x8);
|
||||
MOZ_MUST_USE bool readB32x4Const(I32x4* i32x4);
|
||||
MOZ_MUST_USE bool readRefNull();
|
||||
MOZ_MUST_USE bool readCall(uint32_t* calleeIndex, ValueVector* argValues);
|
||||
MOZ_MUST_USE bool readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector* argValues);
|
||||
MOZ_MUST_USE bool readOldCallDirect(uint32_t numFuncImports, uint32_t* funcIndex,
|
||||
|
@ -731,7 +792,7 @@ OpIter<Policy>::popWithType(StackType expectedType, Value* value)
|
|||
TypeAndValue<Value> tv = valueStack_.popCopy();
|
||||
|
||||
StackType _;
|
||||
if (MOZ_UNLIKELY(!Unify(tv.type(), expectedType, &_)))
|
||||
if (MOZ_UNLIKELY(!Unify(env_.gcTypesEnabled, tv.type(), expectedType, &_)))
|
||||
return typeMismatch(tv.type(), expectedType);
|
||||
|
||||
*value = tv.value();
|
||||
|
@ -783,8 +844,11 @@ OpIter<Policy>::topWithType(ValType expectedType, Value* value)
|
|||
|
||||
TypeAndValue<Value>& tv = valueStack_.back();
|
||||
|
||||
if (MOZ_UNLIKELY(!Unify(tv.type(), ToStackType(expectedType), &tv.typeRef())))
|
||||
if (MOZ_UNLIKELY(!Unify(env_.gcTypesEnabled, tv.type(), ToStackType(expectedType),
|
||||
&tv.typeRef())))
|
||||
{
|
||||
return typeMismatch(tv.type(), ToStackType(expectedType));
|
||||
}
|
||||
|
||||
*value = tv.value();
|
||||
return true;
|
||||
|
@ -846,6 +910,7 @@ OpIter<Policy>::readBlockType(ExprType* type)
|
|||
if (!d_.readBlockType(&unchecked))
|
||||
return fail("unable to read block signature");
|
||||
|
||||
bool known = false;
|
||||
switch (unchecked) {
|
||||
case uint8_t(ExprType::Void):
|
||||
case uint8_t(ExprType::I32):
|
||||
|
@ -859,11 +924,18 @@ OpIter<Policy>::readBlockType(ExprType* type)
|
|||
case uint8_t(ExprType::B8x16):
|
||||
case uint8_t(ExprType::B16x8):
|
||||
case uint8_t(ExprType::B32x4):
|
||||
known = true;
|
||||
break;
|
||||
case uint8_t(ExprType::AnyRef):
|
||||
known = env_.gcTypesEnabled == HasGcTypes::True;
|
||||
break;
|
||||
case uint8_t(ExprType::Limit):
|
||||
break;
|
||||
default:
|
||||
return fail("invalid inline block type");
|
||||
}
|
||||
|
||||
if (!known)
|
||||
return fail("invalid inline block type");
|
||||
|
||||
*type = ExprType(unchecked);
|
||||
return true;
|
||||
}
|
||||
|
@ -1382,7 +1454,7 @@ OpIter<Policy>::readSelect(StackType* type, Value* trueValue, Value* falseValue,
|
|||
if (!popAnyType(&trueType, trueValue))
|
||||
return false;
|
||||
|
||||
if (!Unify(falseType, trueType, type))
|
||||
if (!Join(env_.gcTypesEnabled, falseType, trueType, type))
|
||||
return fail("select operand types must match");
|
||||
|
||||
infalliblePush(*type);
|
||||
|
@ -1595,6 +1667,17 @@ OpIter<Policy>::readB32x4Const(I32x4* i32x4)
|
|||
push(ValType::B32x4);
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool
|
||||
OpIter<Policy>::readRefNull()
|
||||
{
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::RefNull);
|
||||
uint8_t valType;
|
||||
if (!d_.readValType(&valType) || ValType(valType) != ValType::AnyRef)
|
||||
return fail("unknown nullref type");
|
||||
return push(StackType::AnyRef);
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool
|
||||
OpIter<Policy>::popCallArgs(const ValTypeVector& expectedTypes, ValueVector* values)
|
||||
|
|
|
@ -102,7 +102,7 @@ class AstDecodeContext
|
|||
lifo(lifo),
|
||||
d(d),
|
||||
generateNames(generateNames),
|
||||
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False,
|
||||
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, HasGcTypes::False,
|
||||
cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled()
|
||||
? Shareable::True
|
||||
: Shareable::False),
|
||||
|
@ -1824,7 +1824,7 @@ AstDecodeFunctionBody(AstDecodeContext &c, uint32_t funcIndex, AstFunc** func)
|
|||
if (!locals.appendAll(sig->args()))
|
||||
return false;
|
||||
|
||||
if (!DecodeLocalEntries(c.d, ModuleKind::Wasm, &locals))
|
||||
if (!DecodeLocalEntries(c.d, ModuleKind::Wasm, c.env().gcTypesEnabled, &locals))
|
||||
return false;
|
||||
|
||||
AstDecodeOpIter iter(c.env(), c.d);
|
||||
|
|
|
@ -536,6 +536,9 @@ AddressOf(SymbolicAddress imm, ABIFunctionType* abiType)
|
|||
case SymbolicAddress::CallImport_F64:
|
||||
*abiType = Args_General4;
|
||||
return FuncCast(Instance::callImport_f64, *abiType);
|
||||
case SymbolicAddress::CallImport_Ref:
|
||||
*abiType = Args_General4;
|
||||
return FuncCast(Instance::callImport_ref, *abiType);
|
||||
case SymbolicAddress::CoerceInPlace_ToInt32:
|
||||
*abiType = Args_General1;
|
||||
return FuncCast(CoerceInPlace_ToInt32, *abiType);
|
||||
|
@ -690,6 +693,7 @@ wasm::NeedsBuiltinThunk(SymbolicAddress sym)
|
|||
case SymbolicAddress::CallImport_I32:
|
||||
case SymbolicAddress::CallImport_I64:
|
||||
case SymbolicAddress::CallImport_F64:
|
||||
case SymbolicAddress::CallImport_Ref:
|
||||
case SymbolicAddress::CoerceInPlace_ToInt32: // GenerateImportJitExit
|
||||
case SymbolicAddress::CoerceInPlace_ToNumber:
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
|
|
|
@ -609,22 +609,25 @@ LazyStubSegment::addStubs(size_t codeLength, const Uint32Vector& funcExportIndic
|
|||
return false;
|
||||
|
||||
size_t i = 0;
|
||||
for (DebugOnly<uint32_t> funcExportIndex : funcExportIndices) {
|
||||
for (uint32_t funcExportIndex : funcExportIndices) {
|
||||
const CodeRange& interpRange = codeRanges[i];
|
||||
MOZ_ASSERT(interpRange.isInterpEntry());
|
||||
MOZ_ASSERT(interpRange.funcIndex() == funcExports[funcExportIndex].funcIndex());
|
||||
|
||||
codeRanges_.infallibleAppend(interpRange);
|
||||
codeRanges_.back().offsetBy(offsetInSegment);
|
||||
i++;
|
||||
|
||||
const CodeRange& jitRange = codeRanges[i + 1];
|
||||
if (funcExports[funcExportIndex].sig().temporarilyUnsupportedAnyRef())
|
||||
continue;
|
||||
|
||||
const CodeRange& jitRange = codeRanges[i];
|
||||
MOZ_ASSERT(jitRange.isJitEntry());
|
||||
MOZ_ASSERT(jitRange.funcIndex() == interpRange.funcIndex());
|
||||
|
||||
codeRanges_.infallibleAppend(jitRange);
|
||||
codeRanges_.back().offsetBy(offsetInSegment);
|
||||
|
||||
i += 2;
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -658,8 +661,8 @@ struct ProjectLazyFuncIndex
|
|||
static constexpr unsigned LAZY_STUB_LIFO_DEFAULT_CHUNK_SIZE = 8 * 1024;
|
||||
|
||||
bool
|
||||
LazyStubTier::createMany(const Uint32Vector& funcExportIndices, const CodeTier& codeTier,
|
||||
size_t* stubSegmentIndex)
|
||||
LazyStubTier::createMany(HasGcTypes gcTypesEnabled, const Uint32Vector& funcExportIndices,
|
||||
const CodeTier& codeTier, size_t* stubSegmentIndex)
|
||||
{
|
||||
MOZ_ASSERT(funcExportIndices.length());
|
||||
|
||||
|
@ -673,16 +676,21 @@ LazyStubTier::createMany(const Uint32Vector& funcExportIndices, const CodeTier&
|
|||
uint8_t* moduleSegmentBase = codeTier.segment().base();
|
||||
|
||||
CodeRangeVector codeRanges;
|
||||
DebugOnly<uint32_t> numExpectedRanges = 0;
|
||||
for (uint32_t funcExportIndex : funcExportIndices) {
|
||||
const FuncExport& fe = funcExports[funcExportIndex];
|
||||
numExpectedRanges += fe.sig().temporarilyUnsupportedAnyRef() ? 1 : 2;
|
||||
void* calleePtr = moduleSegmentBase +
|
||||
moduleRanges[fe.interpCodeRangeIndex()].funcNormalEntry();
|
||||
Maybe<ImmPtr> callee;
|
||||
callee.emplace(calleePtr, ImmPtr::NoCheckToken());
|
||||
if (!GenerateEntryStubs(masm, funcExportIndex, fe, callee, /* asmjs*/ false, &codeRanges))
|
||||
if (!GenerateEntryStubs(masm, funcExportIndex, fe, callee, /* asmjs */ false,
|
||||
gcTypesEnabled, &codeRanges))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(codeRanges.length() == 2 * funcExportIndices.length(), "two entries per function");
|
||||
MOZ_ASSERT(codeRanges.length() == numExpectedRanges, "incorrect number of entries per function");
|
||||
|
||||
masm.finish();
|
||||
|
||||
|
@ -743,7 +751,9 @@ LazyStubTier::createMany(const Uint32Vector& funcExportIndices, const CodeTier&
|
|||
fe.funcIndex(), &exportIndex));
|
||||
MOZ_ALWAYS_TRUE(exports_.insert(exports_.begin() + exportIndex, Move(lazyExport)));
|
||||
|
||||
interpRangeIndex += 2;
|
||||
// Functions with anyref in their sig have only one entry (interp).
|
||||
// All other functions get an extra jit entry.
|
||||
interpRangeIndex += fe.sig().temporarilyUnsupportedAnyRef() ? 1 : 2;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -757,12 +767,22 @@ LazyStubTier::createOne(uint32_t funcExportIndex, const CodeTier& codeTier)
|
|||
return false;
|
||||
|
||||
size_t stubSegmentIndex;
|
||||
if (!createMany(funcExportIndexes, codeTier, &stubSegmentIndex))
|
||||
if (!createMany(codeTier.code().metadata().temporaryHasGcTypes, funcExportIndexes, codeTier,
|
||||
&stubSegmentIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const UniqueLazyStubSegment& segment = stubSegments_[stubSegmentIndex];
|
||||
const CodeRangeVector& codeRanges = segment->codeRanges();
|
||||
|
||||
// Functions that have anyref in their sig don't get a jit entry.
|
||||
if (codeTier.metadata().funcExports[funcExportIndex].sig().temporarilyUnsupportedAnyRef()) {
|
||||
MOZ_ASSERT(codeRanges.length() >= 1);
|
||||
MOZ_ASSERT(codeRanges.back().isInterpEntry());
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(codeRanges.length() >= 2);
|
||||
MOZ_ASSERT(codeRanges[codeRanges.length() - 2].isInterpEntry());
|
||||
|
||||
|
@ -774,14 +794,14 @@ LazyStubTier::createOne(uint32_t funcExportIndex, const CodeTier& codeTier)
|
|||
}
|
||||
|
||||
bool
|
||||
LazyStubTier::createTier2(const Uint32Vector& funcExportIndices, const CodeTier& codeTier,
|
||||
Maybe<size_t>* outStubSegmentIndex)
|
||||
LazyStubTier::createTier2(HasGcTypes gcTypesEnabled, const Uint32Vector& funcExportIndices,
|
||||
const CodeTier& codeTier, Maybe<size_t>* outStubSegmentIndex)
|
||||
{
|
||||
if (!funcExportIndices.length())
|
||||
return true;
|
||||
|
||||
size_t stubSegmentIndex;
|
||||
if (!createMany(funcExportIndices, codeTier, &stubSegmentIndex))
|
||||
if (!createMany(gcTypesEnabled, funcExportIndices, codeTier, &stubSegmentIndex))
|
||||
return false;
|
||||
|
||||
outStubSegmentIndex->emplace(stubSegmentIndex);
|
||||
|
|
|
@ -400,6 +400,7 @@ struct MetadataCacheablePod
|
|||
{
|
||||
ModuleKind kind;
|
||||
MemoryUsage memoryUsage;
|
||||
HasGcTypes temporaryHasGcTypes;
|
||||
uint32_t minMemoryLength;
|
||||
uint32_t globalDataLength;
|
||||
Maybe<uint32_t> maxMemoryLength;
|
||||
|
@ -408,6 +409,7 @@ struct MetadataCacheablePod
|
|||
explicit MetadataCacheablePod(ModuleKind kind)
|
||||
: kind(kind),
|
||||
memoryUsage(MemoryUsage::None),
|
||||
temporaryHasGcTypes(HasGcTypes::False),
|
||||
minMemoryLength(0),
|
||||
globalDataLength(0)
|
||||
{}
|
||||
|
@ -572,8 +574,8 @@ class LazyStubTier
|
|||
LazyFuncExportVector exports_;
|
||||
size_t lastStubSegmentIndex_;
|
||||
|
||||
bool createMany(const Uint32Vector& funcExportIndices, const CodeTier& codeTier,
|
||||
size_t* stubSegmentIndex);
|
||||
bool createMany(HasGcTypes gcTypesEnabled, const Uint32Vector& funcExportIndices,
|
||||
const CodeTier& codeTier, size_t* stubSegmentIndex);
|
||||
|
||||
public:
|
||||
LazyStubTier() : lastStubSegmentIndex_(0) {}
|
||||
|
@ -593,8 +595,8 @@ class LazyStubTier
|
|||
// them in a single stub. Jit entries won't be used until
|
||||
// setJitEntries() is actually called, after the Code owner has committed
|
||||
// tier2.
|
||||
bool createTier2(const Uint32Vector& funcExportIndices, const CodeTier& codeTier,
|
||||
Maybe<size_t>* stubSegmentIndex);
|
||||
bool createTier2(HasGcTypes gcTypesEnabled, const Uint32Vector& funcExportIndices,
|
||||
const CodeTier& codeTier, Maybe<size_t>* stubSegmentIndex);
|
||||
void setJitEntries(const Maybe<size_t>& stubSegmentIndex, const Code& code);
|
||||
|
||||
void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data) const;
|
||||
|
|
|
@ -87,10 +87,17 @@ DecodeCodeSection(const ModuleEnvironment& env, DecoderT& d, ModuleGenerator& mg
|
|||
bool
|
||||
CompileArgs::initFromContext(JSContext* cx, ScriptedCaller&& scriptedCaller)
|
||||
{
|
||||
baselineEnabled = cx->options().wasmBaseline();
|
||||
ionEnabled = cx->options().wasmIon();
|
||||
#ifdef ENABLE_WASM_GC
|
||||
bool gcEnabled = cx->options().wasmGc();
|
||||
#else
|
||||
bool gcEnabled = false;
|
||||
#endif
|
||||
|
||||
baselineEnabled = cx->options().wasmBaseline() || gcEnabled;
|
||||
ionEnabled = cx->options().wasmIon() && !gcEnabled;
|
||||
sharedMemoryEnabled = cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled();
|
||||
testTiering = cx->options().testWasmAwaitTier2() || JitOptions.wasmDelayTier2;
|
||||
gcTypesEnabled = gcEnabled ? HasGcTypes::True : HasGcTypes::False;
|
||||
testTiering = (cx->options().testWasmAwaitTier2() || JitOptions.wasmDelayTier2) && !gcEnabled;
|
||||
|
||||
// Debug information such as source view or debug traps will require
|
||||
// additional memory and permanently stay in baseline code, so we try to
|
||||
|
@ -424,7 +431,7 @@ wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, Uni
|
|||
DebugEnabled debug;
|
||||
InitialCompileFlags(args, d, &mode, &tier, &debug);
|
||||
|
||||
ModuleEnvironment env(mode, tier, debug,
|
||||
ModuleEnvironment env(mode, tier, debug, args.gcTypesEnabled,
|
||||
args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
|
||||
if (!DecodeModuleEnvironment(d, &env))
|
||||
return nullptr;
|
||||
|
@ -450,7 +457,9 @@ wasm::CompileTier2(const CompileArgs& args, Module& module, Atomic<bool>* cancel
|
|||
UniqueChars error;
|
||||
Decoder d(module.bytecode().bytes, 0, &error);
|
||||
|
||||
ModuleEnvironment env(CompileMode::Tier2, Tier::Ion, DebugEnabled::False,
|
||||
MOZ_ASSERT(args.gcTypesEnabled == HasGcTypes::False, "can't ion-compile with gc types yet");
|
||||
|
||||
ModuleEnvironment env(CompileMode::Tier2, Tier::Ion, DebugEnabled::False, HasGcTypes::False,
|
||||
args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
|
||||
if (!DecodeModuleEnvironment(d, &env))
|
||||
return false;
|
||||
|
@ -572,7 +581,7 @@ wasm::CompileStreaming(const CompileArgs& args,
|
|||
DebugEnabled debug;
|
||||
InitialCompileFlags(args, d, &mode, &tier, &debug);
|
||||
|
||||
env.emplace(mode, tier, debug,
|
||||
env.emplace(mode, tier, debug, args.gcTypesEnabled,
|
||||
args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
|
||||
if (!DecodeModuleEnvironment(d, env.ptr()))
|
||||
return nullptr;
|
||||
|
|
|
@ -50,6 +50,7 @@ struct CompileArgs : ShareableBase<CompileArgs>
|
|||
bool debugEnabled;
|
||||
bool ionEnabled;
|
||||
bool sharedMemoryEnabled;
|
||||
HasGcTypes gcTypesEnabled;
|
||||
bool testTiering;
|
||||
|
||||
CompileArgs(Assumptions&& assumptions, ScriptedCaller&& scriptedCaller)
|
||||
|
@ -59,6 +60,7 @@ struct CompileArgs : ShareableBase<CompileArgs>
|
|||
debugEnabled(false),
|
||||
ionEnabled(false),
|
||||
sharedMemoryEnabled(false),
|
||||
gcTypesEnabled(HasGcTypes::False),
|
||||
testTiering(false)
|
||||
{}
|
||||
|
||||
|
|
|
@ -542,7 +542,7 @@ DebugState::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t
|
|||
size_t offsetInModule = range.funcLineOrBytecode();
|
||||
Decoder d(maybeBytecode_->begin() + offsetInModule, maybeBytecode_->end(),
|
||||
offsetInModule, /* error = */ nullptr);
|
||||
return DecodeLocalEntries(d, metadata().kind, locals);
|
||||
return DecodeLocalEntries(d, metadata().kind, metadata().temporaryHasGcTypes, locals);
|
||||
}
|
||||
|
||||
ExprType
|
||||
|
|
|
@ -1139,6 +1139,7 @@ ThunkedNativeToDescription(SymbolicAddress func)
|
|||
case SymbolicAddress::CallImport_I32:
|
||||
case SymbolicAddress::CallImport_I64:
|
||||
case SymbolicAddress::CallImport_F64:
|
||||
case SymbolicAddress::CallImport_Ref:
|
||||
case SymbolicAddress::CoerceInPlace_ToInt32:
|
||||
case SymbolicAddress::CoerceInPlace_ToNumber:
|
||||
MOZ_ASSERT(!NeedsBuiltinThunk(func), "not in sync with NeedsBuiltinThunk");
|
||||
|
|
|
@ -840,6 +840,7 @@ ModuleGenerator::finishMetadata(const ShareableBytes& bytecode)
|
|||
// Copy over data from the ModuleEnvironment.
|
||||
|
||||
metadata_->memoryUsage = env_->memoryUsage;
|
||||
metadata_->temporaryHasGcTypes = env_->gcTypesEnabled;
|
||||
metadata_->minMemoryLength = env_->minMemoryLength;
|
||||
metadata_->maxMemoryLength = env_->maxMemoryLength;
|
||||
metadata_->startFuncIndex = env_->startFuncIndex;
|
||||
|
|
|
@ -133,6 +133,10 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con
|
|||
case ValType::F64:
|
||||
args[i].set(JS::CanonicalizedDoubleValue(*(double*)&argv[i]));
|
||||
break;
|
||||
case ValType::AnyRef: {
|
||||
args[i].set(ObjectOrNullValue(*(JSObject**)&argv[i]));
|
||||
break;
|
||||
}
|
||||
case ValType::I64:
|
||||
case ValType::I8x16:
|
||||
case ValType::I16x8:
|
||||
|
@ -188,23 +192,28 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con
|
|||
if (!TypeScript::ThisTypes(script)->hasType(TypeSet::UndefinedType()))
|
||||
return true;
|
||||
|
||||
// Functions with anyref in signature don't have a jit exit at the moment.
|
||||
if (fi.sig().temporarilyUnsupportedAnyRef())
|
||||
return true;
|
||||
|
||||
const ValTypeVector& importArgs = fi.sig().args();
|
||||
|
||||
size_t numKnownArgs = Min(importArgs.length(), importFun->nargs());
|
||||
for (uint32_t i = 0; i < numKnownArgs; i++) {
|
||||
TypeSet::Type type = TypeSet::UnknownType();
|
||||
switch (importArgs[i]) {
|
||||
case ValType::I32: type = TypeSet::Int32Type(); break;
|
||||
case ValType::F32: type = TypeSet::DoubleType(); break;
|
||||
case ValType::F64: type = TypeSet::DoubleType(); break;
|
||||
case ValType::I64: MOZ_CRASH("NYI");
|
||||
case ValType::I8x16: MOZ_CRASH("NYI");
|
||||
case ValType::I16x8: MOZ_CRASH("NYI");
|
||||
case ValType::I32x4: MOZ_CRASH("NYI");
|
||||
case ValType::F32x4: MOZ_CRASH("NYI");
|
||||
case ValType::B8x16: MOZ_CRASH("NYI");
|
||||
case ValType::B16x8: MOZ_CRASH("NYI");
|
||||
case ValType::B32x4: MOZ_CRASH("NYI");
|
||||
case ValType::I32: type = TypeSet::Int32Type(); break;
|
||||
case ValType::F32: type = TypeSet::DoubleType(); break;
|
||||
case ValType::F64: type = TypeSet::DoubleType(); break;
|
||||
case ValType::AnyRef: MOZ_CRASH("case guarded above");
|
||||
case ValType::I64: MOZ_CRASH("NYI");
|
||||
case ValType::I8x16: MOZ_CRASH("NYI");
|
||||
case ValType::I16x8: MOZ_CRASH("NYI");
|
||||
case ValType::I32x4: MOZ_CRASH("NYI");
|
||||
case ValType::F32x4: MOZ_CRASH("NYI");
|
||||
case ValType::B8x16: MOZ_CRASH("NYI");
|
||||
case ValType::B16x8: MOZ_CRASH("NYI");
|
||||
case ValType::B32x4: MOZ_CRASH("NYI");
|
||||
}
|
||||
if (!TypeScript::ArgTypes(script, i)->hasType(type))
|
||||
return true;
|
||||
|
@ -265,6 +274,31 @@ Instance::callImport_f64(Instance* instance, int32_t funcImportIndex, int32_t ar
|
|||
return ToNumber(cx, rval, (double*)argv);
|
||||
}
|
||||
|
||||
static bool
|
||||
ToRef(JSContext* cx, HandleValue val, void* addr)
|
||||
{
|
||||
if (val.isNull()) {
|
||||
*(JSObject**)addr = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject* obj = ToObject(cx, val);
|
||||
if (!obj)
|
||||
return false;
|
||||
*(JSObject**)addr = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
Instance::callImport_ref(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
|
||||
{
|
||||
JSContext* cx = TlsContext.get();
|
||||
RootedValue rval(cx);
|
||||
if (!instance->callImport(cx, funcImportIndex, argc, argv, &rval))
|
||||
return false;
|
||||
return ToRef(cx, rval, argv);
|
||||
}
|
||||
|
||||
/* static */ uint32_t
|
||||
Instance::growMemory_i32(Instance* instance, uint32_t delta)
|
||||
{
|
||||
|
@ -672,6 +706,11 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
|
|||
if (!ToNumber(cx, v, (double*)&exportArgs[i]))
|
||||
return false;
|
||||
break;
|
||||
case ValType::AnyRef: {
|
||||
if (!ToRef(cx, v, &exportArgs[i]))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ValType::I8x16: {
|
||||
SimdConstant simd;
|
||||
if (!ToSimdConstant<Int8x16>(cx, v, &simd))
|
||||
|
@ -755,6 +794,8 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
|
|||
}
|
||||
|
||||
void* retAddr = &exportArgs[0];
|
||||
|
||||
bool expectsObject = false;
|
||||
JSObject* retObj = nullptr;
|
||||
switch (func.sig().ret()) {
|
||||
case ExprType::Void:
|
||||
|
@ -771,6 +812,10 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
|
|||
case ExprType::F64:
|
||||
args.rval().set(NumberValue(*(double*)retAddr));
|
||||
break;
|
||||
case ExprType::AnyRef:
|
||||
retObj = *(JSObject**)retAddr;
|
||||
expectsObject = true;
|
||||
break;
|
||||
case ExprType::I8x16:
|
||||
retObj = CreateSimd<Int8x16>(cx, (int8_t*)retAddr);
|
||||
if (!retObj)
|
||||
|
@ -810,7 +855,9 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
|
|||
MOZ_CRASH("Limit");
|
||||
}
|
||||
|
||||
if (retObj)
|
||||
if (expectsObject)
|
||||
args.rval().set(ObjectOrNullValue(retObj));
|
||||
else if (retObj)
|
||||
args.rval().set(ObjectValue(*retObj));
|
||||
|
||||
return true;
|
||||
|
|
|
@ -164,6 +164,7 @@ class Instance
|
|||
static int32_t callImport_i32(Instance*, int32_t, int32_t, uint64_t*);
|
||||
static int32_t callImport_i64(Instance*, int32_t, int32_t, uint64_t*);
|
||||
static int32_t callImport_f64(Instance*, int32_t, int32_t, uint64_t*);
|
||||
static int32_t callImport_ref(Instance*, int32_t, int32_t, uint64_t*);
|
||||
static uint32_t growMemory_i32(Instance* instance, uint32_t delta);
|
||||
static uint32_t currentMemory_i32(Instance* instance);
|
||||
static int32_t wait_i32(Instance* instance, uint32_t byteOffset, int32_t value, int64_t timeout);
|
||||
|
|
|
@ -219,6 +219,9 @@ class FunctionCompiler
|
|||
case ValType::F64:
|
||||
ins = MConstant::New(alloc(), DoubleValue(0.0), MIRType::Double);
|
||||
break;
|
||||
case ValType::AnyRef:
|
||||
MOZ_CRASH("ion support for anyref locale default value NYI");
|
||||
break;
|
||||
case ValType::I8x16:
|
||||
ins = MSimdConstant::New(alloc(), SimdConstant::SplatX16(0), MIRType::Int8x16);
|
||||
break;
|
||||
|
@ -2980,6 +2983,7 @@ SimdToLaneType(ValType type)
|
|||
case ValType::I64:
|
||||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
case ValType::AnyRef:
|
||||
break;
|
||||
}
|
||||
MOZ_CRASH("bad simd type");
|
||||
|
@ -3260,6 +3264,7 @@ EmitSimdCtor(FunctionCompiler& f, ValType type)
|
|||
case ValType::I64:
|
||||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
case ValType::AnyRef:
|
||||
break;
|
||||
}
|
||||
MOZ_CRASH("unexpected SIMD type");
|
||||
|
@ -3973,6 +3978,11 @@ EmitBodyExprs(FunctionCompiler& f)
|
|||
case uint16_t(Op::F64ReinterpretI64):
|
||||
CHECK(EmitReinterpret(f, ValType::F64, ValType::I64, MIRType::Double));
|
||||
|
||||
// GC types are NYI in Ion.
|
||||
case uint16_t(Op::RefNull):
|
||||
case uint16_t(Op::RefIsNull):
|
||||
return f.iter().unrecognizedOpcode(&op);
|
||||
|
||||
// Sign extensions
|
||||
#ifdef ENABLE_WASM_SIGNEXTEND_OPS
|
||||
case uint16_t(Op::I32Extend8S):
|
||||
|
@ -4386,7 +4396,7 @@ wasm::IonCompileFunctions(const ModuleEnvironment& env, LifoAlloc& lifo,
|
|||
ValTypeVector locals;
|
||||
if (!locals.appendAll(env.funcSigs[func.index]->args()))
|
||||
return false;
|
||||
if (!DecodeLocalEntries(d, env.kind, &locals))
|
||||
if (!DecodeLocalEntries(d, env.kind, env.gcTypesEnabled, &locals))
|
||||
return false;
|
||||
|
||||
// Set up for Ion compilation.
|
||||
|
|
|
@ -1291,11 +1291,23 @@ WasmInstanceObject::getExportedFunction(JSContext* cx, HandleWasmInstanceObject
|
|||
RootedAtom name(cx, NumberToAtom(cx, funcIndex));
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
// Functions with anyref don't have jit entries yet, so they should
|
||||
// mostly behave like asm.js functions. Pretend it's the case, until
|
||||
// jit entries are implemented.
|
||||
JSFunction::Flags flags = sig.temporarilyUnsupportedAnyRef()
|
||||
? JSFunction::ASMJS_NATIVE
|
||||
: JSFunction::WASM_FUN;
|
||||
|
||||
fun.set(NewNativeFunction(cx, WasmCall, numArgs, name, gc::AllocKind::FUNCTION_EXTENDED,
|
||||
SingletonObject, JSFunction::WASM_FUN));
|
||||
SingletonObject, flags));
|
||||
if (!fun)
|
||||
return false;
|
||||
fun->setWasmJitEntry(instance.code().getAddressOfJitEntry(funcIndex));
|
||||
|
||||
if (sig.temporarilyUnsupportedAnyRef())
|
||||
fun->setAsmJSIndex(funcIndex);
|
||||
else
|
||||
fun->setWasmJitEntry(instance.code().getAddressOfJitEntry(funcIndex));
|
||||
}
|
||||
|
||||
fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, ObjectValue(*instanceObj));
|
||||
|
|
|
@ -271,8 +271,10 @@ Module::finishTier2(UniqueLinkDataTier linkData2, UniqueCodeTier tier2, ModuleEn
|
|||
return false;
|
||||
}
|
||||
|
||||
HasGcTypes gcTypesEnabled = code().metadata().temporaryHasGcTypes;
|
||||
|
||||
Maybe<size_t> stub2Index;
|
||||
if (!stubs2->createTier2(funcExportIndices, *tier2, &stub2Index))
|
||||
if (!stubs2->createTier2(gcTypesEnabled, funcExportIndices, *tier2, &stub2Index))
|
||||
return false;
|
||||
|
||||
// Install the data in the data structures. They will not be visible
|
||||
|
|
|
@ -92,6 +92,10 @@ SetupABIArguments(MacroAssembler& masm, const FuncExport& fe, Register argv, Reg
|
|||
masm.load32(src, iter->gpr());
|
||||
else if (type == MIRType::Int64)
|
||||
masm.load64(src, iter->gpr64());
|
||||
else if (type == MIRType::Pointer)
|
||||
masm.loadPtr(src, iter->gpr());
|
||||
else
|
||||
MOZ_CRASH("unknown GPR type");
|
||||
break;
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
case ABIArg::GPR_PAIR:
|
||||
|
@ -148,6 +152,10 @@ SetupABIArguments(MacroAssembler& masm, const FuncExport& fe, Register argv, Reg
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
case MIRType::Pointer:
|
||||
masm.loadPtr(src, scratch);
|
||||
masm.storePtr(scratch, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
|
||||
break;
|
||||
case MIRType::Double:
|
||||
masm.loadDouble(src, ScratchDoubleReg);
|
||||
masm.storeDouble(ScratchDoubleReg,
|
||||
|
@ -204,6 +212,9 @@ StoreABIReturn(MacroAssembler& masm, const FuncExport& fe, Register argv)
|
|||
masm.canonicalizeDouble(ReturnDoubleReg);
|
||||
masm.storeDouble(ReturnDoubleReg, Address(argv, 0));
|
||||
break;
|
||||
case ExprType::AnyRef:
|
||||
masm.storePtr(ReturnReg, Address(argv, 0));
|
||||
break;
|
||||
case ExprType::I8x16:
|
||||
case ExprType::I16x8:
|
||||
case ExprType::I32x4:
|
||||
|
@ -255,13 +266,20 @@ static const unsigned NonVolatileRegsPushSize = NonVolatileRegs.gprs().size() *
|
|||
NonVolatileRegs.fpus().getPushSizeInBytes();
|
||||
#endif
|
||||
|
||||
#if defined(JS_CODEGEN_ARM64)
|
||||
// Stacks are 16-byte aligned, hence the extra word.
|
||||
static const unsigned FramePushedBeforeAlign = NonVolatileRegsPushSize + 2 * sizeof(void*);
|
||||
#ifdef ENABLE_WASM_GC
|
||||
static const unsigned NumExtraPushed = 2; // tls and argv
|
||||
#else
|
||||
static const unsigned FramePushedBeforeAlign = NonVolatileRegsPushSize + sizeof(void*);
|
||||
static const unsigned NumExtraPushed = 1; // argv
|
||||
#endif
|
||||
|
||||
#ifdef JS_CODEGEN_ARM64
|
||||
static const unsigned WasmPushSize = 16;
|
||||
#else
|
||||
static const unsigned WasmPushSize = sizeof(void*);
|
||||
#endif
|
||||
|
||||
static const unsigned FramePushedBeforeAlign = NonVolatileRegsPushSize + NumExtraPushed * WasmPushSize;
|
||||
|
||||
static void
|
||||
AssertExpectedSP(const MacroAssembler& masm)
|
||||
{
|
||||
|
@ -276,7 +294,7 @@ WasmPush(MacroAssembler& masm, const Operand& op)
|
|||
{
|
||||
#ifdef JS_CODEGEN_ARM64
|
||||
// Allocate a pad word so that SP can remain properly aligned.
|
||||
masm.reserveStack(16);
|
||||
masm.reserveStack(WasmPushSize);
|
||||
masm.storePtr(op, Address(masm.getStackPointer(), 0));
|
||||
#else
|
||||
masm.Push(op);
|
||||
|
@ -289,7 +307,7 @@ WasmPop(MacroAssembler& masm, Register r)
|
|||
#ifdef JS_CODEGEN_ARM64
|
||||
// Also pop the pad word allocated by WasmPush.
|
||||
masm.loadPtr(Address(masm.getStackPointer(), 0), r);
|
||||
masm.freeStack(16);
|
||||
masm.freeStack(WasmPushSize);
|
||||
#else
|
||||
masm.Pop(r);
|
||||
#endif
|
||||
|
@ -303,6 +321,17 @@ MoveSPForJitABI(MacroAssembler& masm)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
static void
|
||||
SuppressGC(MacroAssembler& masm, int32_t increment, Register scratch)
|
||||
{
|
||||
masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, cx)), scratch);
|
||||
masm.add32(Imm32(increment),
|
||||
Address(scratch, offsetof(JSContext, suppressGC) +
|
||||
js::ThreadLocalData<int32_t>::offsetOfValue()));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
CallFuncExport(MacroAssembler& masm, const FuncExport& fe, const Maybe<ImmPtr>& funcPtr)
|
||||
{
|
||||
|
@ -319,7 +348,7 @@ CallFuncExport(MacroAssembler& masm, const FuncExport& fe, const Maybe<ImmPtr>&
|
|||
// must map from the ABI of ExportFuncPtr to the export's signature's ABI.
|
||||
static bool
|
||||
GenerateInterpEntry(MacroAssembler& masm, const FuncExport& fe, const Maybe<ImmPtr>& funcPtr,
|
||||
Offsets* offsets)
|
||||
HasGcTypes gcTypesEnabled, Offsets* offsets)
|
||||
{
|
||||
AssertExpectedSP(masm);
|
||||
masm.haltingAlign(CodeAlignment);
|
||||
|
@ -372,6 +401,12 @@ GenerateInterpEntry(MacroAssembler& masm, const FuncExport& fe, const Maybe<ImmP
|
|||
else
|
||||
masm.loadPtr(Address(masm.getStackPointer(), argBase + arg.offsetFromArgBase()), WasmTlsReg);
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
WasmPush(masm, WasmTlsReg);
|
||||
if (gcTypesEnabled == HasGcTypes::True)
|
||||
SuppressGC(masm, 1, scratch);
|
||||
#endif
|
||||
|
||||
// Save 'argv' on the stack so that we can recover it after the call.
|
||||
WasmPush(masm, argv);
|
||||
|
||||
|
@ -425,6 +460,12 @@ GenerateInterpEntry(MacroAssembler& masm, const FuncExport& fe, const Maybe<ImmP
|
|||
// Recover the 'argv' pointer which was saved before aligning the stack.
|
||||
WasmPop(masm, argv);
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
WasmPop(masm, WasmTlsReg);
|
||||
if (gcTypesEnabled == HasGcTypes::True)
|
||||
SuppressGC(masm, -1, WasmTlsReg);
|
||||
#endif
|
||||
|
||||
// Store the return value in argv[0].
|
||||
StoreABIReturn(masm, fe, argv);
|
||||
|
||||
|
@ -451,7 +492,7 @@ GenerateInterpEntry(MacroAssembler& masm, const FuncExport& fe, const Maybe<ImmP
|
|||
MOZ_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
#if defined(JS_CODEGEN_ARM64)
|
||||
masm.setFramePushed(16);
|
||||
masm.setFramePushed(WasmPushSize);
|
||||
WasmPop(masm, lr);
|
||||
masm.abiret();
|
||||
#else
|
||||
|
@ -528,7 +569,7 @@ GenerateJitEntryThrow(MacroAssembler& masm, unsigned frameSize)
|
|||
|
||||
static bool
|
||||
GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex, const FuncExport& fe,
|
||||
const Maybe<ImmPtr>& funcPtr, Offsets* offsets)
|
||||
const Maybe<ImmPtr>& funcPtr, HasGcTypes gcTypesEnabled, Offsets* offsets)
|
||||
{
|
||||
AssertExpectedSP(masm);
|
||||
|
||||
|
@ -540,7 +581,15 @@ GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex, const FuncExport&
|
|||
// left):
|
||||
// <-- retAddr | descriptor | callee | argc | this | arg1..N
|
||||
|
||||
unsigned normalBytesNeeded = StackArgBytes(fe.sig().args());
|
||||
#ifdef ENABLE_WASM_GC
|
||||
// Save WasmTlsReg in the uppermost part of the reserved area, because we
|
||||
// need it directly after the call.
|
||||
unsigned savedTlsSize = AlignBytes(sizeof(void*), WasmStackAlignment);
|
||||
#else
|
||||
unsigned savedTlsSize = 0;
|
||||
#endif
|
||||
|
||||
unsigned normalBytesNeeded = StackArgBytes(fe.sig().args()) + savedTlsSize;
|
||||
|
||||
MIRTypeVector coerceArgTypes;
|
||||
MOZ_ALWAYS_TRUE(coerceArgTypes.append(MIRType::Int32));
|
||||
|
@ -554,6 +603,10 @@ GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex, const FuncExport&
|
|||
// instruction.
|
||||
unsigned frameSize = StackDecrementForCall(WasmStackAlignment, 0, bytesNeeded);
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
unsigned savedTlsOffset = frameSize - sizeof(void*);
|
||||
#endif
|
||||
|
||||
// Reserve stack space for wasm ABI arguments, set up like this:
|
||||
// <-- ABI args | padding
|
||||
masm.reserveStack(frameSize);
|
||||
|
@ -726,12 +779,26 @@ GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex, const FuncExport&
|
|||
// Setup wasm register state.
|
||||
masm.loadWasmPinnedRegsFromTls();
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
if (gcTypesEnabled == HasGcTypes::True) {
|
||||
masm.storePtr(WasmTlsReg, Address(sp, savedTlsOffset));
|
||||
SuppressGC(masm, 1, ScratchIonEntry);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Call into the real function. Note that, due to the throw stub, fp, tls
|
||||
// and pinned registers may be clobbered.
|
||||
masm.assertStackAlignment(WasmStackAlignment);
|
||||
CallFuncExport(masm, fe, funcPtr);
|
||||
masm.assertStackAlignment(WasmStackAlignment);
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
if (gcTypesEnabled == HasGcTypes::True) {
|
||||
masm.loadPtr(Address(sp, savedTlsOffset), WasmTlsReg);
|
||||
SuppressGC(masm, -1, WasmTlsReg);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If fp is equal to the FailFP magic value (set by the throw stub), then
|
||||
// report the exception to the JIT caller by jumping into the exception
|
||||
// stub; otherwise the FP value is still set to the parent ion frame value.
|
||||
|
@ -758,6 +825,9 @@ GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex, const FuncExport&
|
|||
masm.canonicalizeDouble(ReturnDoubleReg);
|
||||
masm.boxDouble(ReturnDoubleReg, JSReturnOperand, ScratchDoubleReg);
|
||||
break;
|
||||
case ExprType::AnyRef:
|
||||
MOZ_CRASH("return anyref in jitentry NYI");
|
||||
break;
|
||||
case ExprType::I64:
|
||||
case ExprType::I8x16:
|
||||
case ExprType::I16x8:
|
||||
|
@ -845,6 +915,9 @@ StackCopy(MacroAssembler& masm, MIRType type, Register scratch, Address src, Add
|
|||
masm.load64(src, scratch64);
|
||||
masm.store64(scratch64, dst);
|
||||
#endif
|
||||
} else if (type == MIRType::Pointer) {
|
||||
masm.loadPtr(src, scratch);
|
||||
masm.storePtr(scratch, dst);
|
||||
} else if (type == MIRType::Float32) {
|
||||
masm.loadFloat32(src, ScratchFloat32Reg);
|
||||
masm.storeFloat32(ScratchFloat32Reg, dst);
|
||||
|
@ -878,8 +951,10 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO
|
|||
masm.breakpoint();
|
||||
else
|
||||
masm.store64(i->gpr64(), dst);
|
||||
} else {
|
||||
MOZ_CRASH("unexpected input type?");
|
||||
} else if (type == MIRType::Pointer) {
|
||||
if (toValue)
|
||||
MOZ_CRASH("generating a jit exit for anyref NYI");
|
||||
masm.storePtr(i->gpr(), dst);
|
||||
}
|
||||
break;
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
|
@ -926,6 +1001,8 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO
|
|||
} else if (type == MIRType::Int64) {
|
||||
// We can't box int64 into Values (yet).
|
||||
masm.breakpoint();
|
||||
} else if (type == MIRType::Pointer) {
|
||||
MOZ_CRASH("generating a jit exit for anyref NYI");
|
||||
} else {
|
||||
MOZ_ASSERT(IsFloatingPointType(type));
|
||||
if (type == MIRType::Float32) {
|
||||
|
@ -1122,6 +1199,11 @@ GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint32_t fu
|
|||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.loadDouble(argv, ReturnDoubleReg);
|
||||
break;
|
||||
case ExprType::AnyRef:
|
||||
masm.call(SymbolicAddress::CallImport_Ref);
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.loadPtr(argv, ReturnReg);
|
||||
break;
|
||||
case ExprType::I8x16:
|
||||
case ExprType::I16x8:
|
||||
case ExprType::I32x4:
|
||||
|
@ -1297,6 +1379,9 @@ GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLa
|
|||
case ExprType::F64:
|
||||
masm.convertValueToDouble(JSReturnOperand, ReturnDoubleReg, &oolConvert);
|
||||
break;
|
||||
case ExprType::AnyRef:
|
||||
MOZ_CRASH("anyref returned by import (jit exit) NYI");
|
||||
break;
|
||||
case ExprType::I8x16:
|
||||
case ExprType::I16x8:
|
||||
case ExprType::I32x4:
|
||||
|
@ -1701,21 +1786,22 @@ GenerateDebugTrapStub(MacroAssembler& masm, Label* throwLabel, CallableOffsets*
|
|||
|
||||
bool
|
||||
wasm::GenerateEntryStubs(MacroAssembler& masm, size_t funcExportIndex, const FuncExport& fe,
|
||||
const Maybe<ImmPtr>& callee, bool isAsmJS, CodeRangeVector* codeRanges)
|
||||
const Maybe<ImmPtr>& callee, bool isAsmJS, HasGcTypes gcTypesEnabled,
|
||||
CodeRangeVector* codeRanges)
|
||||
{
|
||||
MOZ_ASSERT(!callee == fe.hasEagerStubs());
|
||||
MOZ_ASSERT_IF(isAsmJS, fe.hasEagerStubs());
|
||||
|
||||
Offsets offsets;
|
||||
if (!GenerateInterpEntry(masm, fe, callee, &offsets))
|
||||
if (!GenerateInterpEntry(masm, fe, callee, gcTypesEnabled, &offsets))
|
||||
return false;
|
||||
if (!codeRanges->emplaceBack(CodeRange::InterpEntry, fe.funcIndex(), offsets))
|
||||
return false;
|
||||
|
||||
if (isAsmJS)
|
||||
if (isAsmJS || fe.sig().temporarilyUnsupportedAnyRef())
|
||||
return true;
|
||||
|
||||
if (!GenerateJitEntry(masm, funcExportIndex, fe, callee, &offsets))
|
||||
if (!GenerateJitEntry(masm, funcExportIndex, fe, callee, gcTypesEnabled, &offsets))
|
||||
return false;
|
||||
if (!codeRanges->emplaceBack(CodeRange::JitEntry, fe.funcIndex(), offsets))
|
||||
return false;
|
||||
|
@ -1748,6 +1834,9 @@ wasm::GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& import
|
|||
if (!code->codeRanges.emplaceBack(CodeRange::ImportInterpExit, funcIndex, interpOffsets))
|
||||
return false;
|
||||
|
||||
if (fi.sig().temporarilyUnsupportedAnyRef())
|
||||
continue;
|
||||
|
||||
JitExitOffsets jitOffsets;
|
||||
if (!GenerateImportJitExit(masm, fi, &throwLabel, &jitOffsets))
|
||||
return false;
|
||||
|
@ -1762,8 +1851,11 @@ wasm::GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& import
|
|||
const FuncExport& fe = exports[i];
|
||||
if (!fe.hasEagerStubs())
|
||||
continue;
|
||||
if (!GenerateEntryStubs(masm, i, fe, noAbsolute, env.isAsmJS(), &code->codeRanges))
|
||||
if (!GenerateEntryStubs(masm, i, fe, noAbsolute, env.isAsmJS(),
|
||||
env.gcTypesEnabled, &code->codeRanges))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting wasm exit stubs");
|
||||
|
|
|
@ -39,7 +39,7 @@ GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& imports,
|
|||
extern bool
|
||||
GenerateEntryStubs(jit::MacroAssembler& masm, size_t funcExportIndex,
|
||||
const FuncExport& funcExport, const Maybe<jit::ImmPtr>& callee,
|
||||
bool isAsmJS, CodeRangeVector* codeRanges);
|
||||
bool isAsmJS, HasGcTypes gcTypesEnabled, CodeRangeVector* codeRanges);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
|
|
@ -115,6 +115,7 @@ class WasmToken
|
|||
Offset,
|
||||
OpenParen,
|
||||
Param,
|
||||
RefNull,
|
||||
Result,
|
||||
Return,
|
||||
SetGlobal,
|
||||
|
@ -331,6 +332,7 @@ class WasmToken
|
|||
case Load:
|
||||
case Loop:
|
||||
case Nop:
|
||||
case RefNull:
|
||||
case Return:
|
||||
case SetGlobal:
|
||||
case SetLocal:
|
||||
|
@ -888,6 +890,8 @@ WasmTokenStream::next()
|
|||
return WasmToken(WasmToken::Align, begin, cur_);
|
||||
if (consume(u"anyfunc"))
|
||||
return WasmToken(WasmToken::AnyFunc, begin, cur_);
|
||||
if (consume(u"anyref"))
|
||||
return WasmToken(WasmToken::ValueType, ValType::AnyRef, begin, cur_);
|
||||
#ifdef ENABLE_WASM_THREAD_OPS
|
||||
if (consume(u"atomic.wake"))
|
||||
return WasmToken(WasmToken::Wake, ThreadOp::Wake, begin, cur_);
|
||||
|
@ -1665,6 +1669,13 @@ WasmTokenStream::next()
|
|||
return WasmToken(WasmToken::Result, begin, cur_);
|
||||
if (consume(u"return"))
|
||||
return WasmToken(WasmToken::Return, begin, cur_);
|
||||
if (consume(u"ref.")) {
|
||||
if (consume(u"null"))
|
||||
return WasmToken(WasmToken::RefNull, begin, cur_);
|
||||
if (consume(u"is_null"))
|
||||
return WasmToken(WasmToken::UnaryOpcode, Op::RefIsNull, begin, cur_);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
@ -2932,6 +2943,19 @@ ParseGrowMemory(WasmParseContext& c, bool inParens)
|
|||
return new(c.lifo) AstGrowMemory(operand);
|
||||
}
|
||||
|
||||
static AstExpr*
|
||||
ParseRefNull(WasmParseContext& c)
|
||||
{
|
||||
WasmToken token;
|
||||
if (!c.ts.match(WasmToken::ValueType, &token, c.error))
|
||||
return nullptr;
|
||||
if (token.valueType() != ValType::AnyRef) {
|
||||
c.ts.generateError(token, "only anyref is supported for nullref", c.error);
|
||||
return nullptr;
|
||||
}
|
||||
return new(c.lifo) AstRefNull(ValType::AnyRef);
|
||||
}
|
||||
|
||||
static AstExpr*
|
||||
ParseExprBody(WasmParseContext& c, WasmToken token, bool inParens)
|
||||
{
|
||||
|
@ -3008,6 +3032,8 @@ ParseExprBody(WasmParseContext& c, WasmToken token, bool inParens)
|
|||
return new(c.lifo) AstCurrentMemory();
|
||||
case WasmToken::GrowMemory:
|
||||
return ParseGrowMemory(c, inParens);
|
||||
case WasmToken::RefNull:
|
||||
return ParseRefNull(c);
|
||||
default:
|
||||
c.ts.generateError(token, c.error);
|
||||
return nullptr;
|
||||
|
@ -4325,6 +4351,7 @@ ResolveExpr(Resolver& r, AstExpr& expr)
|
|||
case AstExprKind::Pop:
|
||||
case AstExprKind::Unreachable:
|
||||
case AstExprKind::CurrentMemory:
|
||||
case AstExprKind::RefNull:
|
||||
return true;
|
||||
case AstExprKind::Drop:
|
||||
return ResolveDropOperator(r, expr.as<AstDrop>());
|
||||
|
@ -4929,6 +4956,13 @@ EncodeWake(Encoder& e, AstWake& s)
|
|||
EncodeLoadStoreFlags(e, s.address());
|
||||
}
|
||||
|
||||
static bool
|
||||
EncodeRefNull(Encoder& e, AstRefNull& s)
|
||||
{
|
||||
return e.writeOp(Op::RefNull) &&
|
||||
e.writeValType(s.refType());
|
||||
}
|
||||
|
||||
static bool
|
||||
EncodeExpr(Encoder& e, AstExpr& expr)
|
||||
{
|
||||
|
@ -4939,6 +4973,8 @@ EncodeExpr(Encoder& e, AstExpr& expr)
|
|||
return e.writeOp(Op::Nop);
|
||||
case AstExprKind::Unreachable:
|
||||
return e.writeOp(Op::Unreachable);
|
||||
case AstExprKind::RefNull:
|
||||
return EncodeRefNull(e, expr.as<AstRefNull>());
|
||||
case AstExprKind::BinaryOperator:
|
||||
return EncodeBinaryOperator(e, expr.as<AstBinaryOperator>());
|
||||
case AstExprKind::Block:
|
||||
|
|
|
@ -72,6 +72,9 @@ Val::writePayload(uint8_t* dst) const
|
|||
case ValType::B32x4:
|
||||
memcpy(dst, &u, jit::Simd128DataSize);
|
||||
return;
|
||||
case ValType::AnyRef:
|
||||
// TODO
|
||||
MOZ_CRASH("writing imported value of AnyRef in global NYI");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +175,7 @@ static const unsigned sTotalBits = sizeof(ImmediateType) * 8;
|
|||
static const unsigned sTagBits = 1;
|
||||
static const unsigned sReturnBit = 1;
|
||||
static const unsigned sLengthBits = 4;
|
||||
static const unsigned sTypeBits = 2;
|
||||
static const unsigned sTypeBits = 3;
|
||||
static const unsigned sMaxTypes = (sTotalBits - sTagBits - sReturnBit - sLengthBits) / sTypeBits;
|
||||
|
||||
static bool
|
||||
|
@ -183,6 +186,7 @@ IsImmediateType(ValType vt)
|
|||
case ValType::I64:
|
||||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
case ValType::AnyRef:
|
||||
return true;
|
||||
case ValType::I8x16:
|
||||
case ValType::I16x8:
|
||||
|
@ -199,7 +203,7 @@ IsImmediateType(ValType vt)
|
|||
static unsigned
|
||||
EncodeImmediateType(ValType vt)
|
||||
{
|
||||
static_assert(3 < (1 << sTypeBits), "fits");
|
||||
static_assert(4 < (1 << sTypeBits), "fits");
|
||||
switch (vt) {
|
||||
case ValType::I32:
|
||||
return 0;
|
||||
|
@ -209,6 +213,8 @@ EncodeImmediateType(ValType vt)
|
|||
return 2;
|
||||
case ValType::F64:
|
||||
return 3;
|
||||
case ValType::AnyRef:
|
||||
return 4;
|
||||
case ValType::I8x16:
|
||||
case ValType::I16x8:
|
||||
case ValType::I32x4:
|
||||
|
|
|
@ -183,9 +183,10 @@ SizeOf(ValType vt)
|
|||
case ValType::B16x8:
|
||||
case ValType::B32x4:
|
||||
return 16;
|
||||
default:
|
||||
MOZ_CRASH("Invalid ValType");
|
||||
case ValType::AnyRef:
|
||||
MOZ_CRASH("unexpected anyref");
|
||||
}
|
||||
MOZ_CRASH("Invalid ValType");
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
@ -275,21 +276,34 @@ static inline jit::MIRType
|
|||
ToMIRType(ValType vt)
|
||||
{
|
||||
switch (vt) {
|
||||
case ValType::I32: return jit::MIRType::Int32;
|
||||
case ValType::I64: return jit::MIRType::Int64;
|
||||
case ValType::F32: return jit::MIRType::Float32;
|
||||
case ValType::F64: return jit::MIRType::Double;
|
||||
case ValType::I8x16: return jit::MIRType::Int8x16;
|
||||
case ValType::I16x8: return jit::MIRType::Int16x8;
|
||||
case ValType::I32x4: return jit::MIRType::Int32x4;
|
||||
case ValType::F32x4: return jit::MIRType::Float32x4;
|
||||
case ValType::B8x16: return jit::MIRType::Bool8x16;
|
||||
case ValType::B16x8: return jit::MIRType::Bool16x8;
|
||||
case ValType::B32x4: return jit::MIRType::Bool32x4;
|
||||
case ValType::I32: return jit::MIRType::Int32;
|
||||
case ValType::I64: return jit::MIRType::Int64;
|
||||
case ValType::F32: return jit::MIRType::Float32;
|
||||
case ValType::F64: return jit::MIRType::Double;
|
||||
case ValType::AnyRef: return jit::MIRType::Pointer;
|
||||
case ValType::I8x16: return jit::MIRType::Int8x16;
|
||||
case ValType::I16x8: return jit::MIRType::Int16x8;
|
||||
case ValType::I32x4: return jit::MIRType::Int32x4;
|
||||
case ValType::F32x4: return jit::MIRType::Float32x4;
|
||||
case ValType::B8x16: return jit::MIRType::Bool8x16;
|
||||
case ValType::B16x8: return jit::MIRType::Bool16x8;
|
||||
case ValType::B32x4: return jit::MIRType::Bool32x4;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type");
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsRefType(ValType vt)
|
||||
{
|
||||
return vt == ValType::AnyRef;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsNumberType(ValType vt)
|
||||
{
|
||||
return !IsRefType(vt);
|
||||
}
|
||||
|
||||
// The ExprType enum represents the type of a WebAssembly expression or return
|
||||
// value and may either be a value type or void. Soon, expression types will be
|
||||
// generalized to a list of ValType and this enum will go away, replaced,
|
||||
|
@ -297,22 +311,23 @@ ToMIRType(ValType vt)
|
|||
|
||||
enum class ExprType
|
||||
{
|
||||
Void = uint8_t(TypeCode::BlockVoid),
|
||||
Void = uint8_t(TypeCode::BlockVoid),
|
||||
|
||||
I32 = uint8_t(TypeCode::I32),
|
||||
I64 = uint8_t(TypeCode::I64),
|
||||
F32 = uint8_t(TypeCode::F32),
|
||||
F64 = uint8_t(TypeCode::F64),
|
||||
I32 = uint8_t(TypeCode::I32),
|
||||
I64 = uint8_t(TypeCode::I64),
|
||||
F32 = uint8_t(TypeCode::F32),
|
||||
F64 = uint8_t(TypeCode::F64),
|
||||
AnyRef = uint8_t(TypeCode::AnyRef),
|
||||
|
||||
I8x16 = uint8_t(TypeCode::I8x16),
|
||||
I16x8 = uint8_t(TypeCode::I16x8),
|
||||
I32x4 = uint8_t(TypeCode::I32x4),
|
||||
F32x4 = uint8_t(TypeCode::F32x4),
|
||||
B8x16 = uint8_t(TypeCode::B8x16),
|
||||
B16x8 = uint8_t(TypeCode::B16x8),
|
||||
B32x4 = uint8_t(TypeCode::B32x4),
|
||||
I8x16 = uint8_t(TypeCode::I8x16),
|
||||
I16x8 = uint8_t(TypeCode::I16x8),
|
||||
I32x4 = uint8_t(TypeCode::I32x4),
|
||||
F32x4 = uint8_t(TypeCode::F32x4),
|
||||
B8x16 = uint8_t(TypeCode::B8x16),
|
||||
B16x8 = uint8_t(TypeCode::B16x8),
|
||||
B32x4 = uint8_t(TypeCode::B32x4),
|
||||
|
||||
Limit = uint8_t(TypeCode::Limit)
|
||||
Limit = uint8_t(TypeCode::Limit)
|
||||
};
|
||||
|
||||
static inline bool
|
||||
|
@ -350,18 +365,19 @@ static inline const char*
|
|||
ToCString(ExprType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ExprType::Void: return "void";
|
||||
case ExprType::I32: return "i32";
|
||||
case ExprType::I64: return "i64";
|
||||
case ExprType::F32: return "f32";
|
||||
case ExprType::F64: return "f64";
|
||||
case ExprType::I8x16: return "i8x16";
|
||||
case ExprType::I16x8: return "i16x8";
|
||||
case ExprType::I32x4: return "i32x4";
|
||||
case ExprType::F32x4: return "f32x4";
|
||||
case ExprType::B8x16: return "b8x16";
|
||||
case ExprType::B16x8: return "b16x8";
|
||||
case ExprType::B32x4: return "b32x4";
|
||||
case ExprType::Void: return "void";
|
||||
case ExprType::I32: return "i32";
|
||||
case ExprType::I64: return "i64";
|
||||
case ExprType::F32: return "f32";
|
||||
case ExprType::F64: return "f64";
|
||||
case ExprType::AnyRef: return "anyref";
|
||||
case ExprType::I8x16: return "i8x16";
|
||||
case ExprType::I16x8: return "i16x8";
|
||||
case ExprType::I32x4: return "i32x4";
|
||||
case ExprType::F32x4: return "f32x4";
|
||||
case ExprType::B8x16: return "b8x16";
|
||||
case ExprType::B16x8: return "b16x8";
|
||||
case ExprType::B32x4: return "b32x4";
|
||||
case ExprType::Limit:;
|
||||
}
|
||||
MOZ_CRASH("bad expression type");
|
||||
|
@ -450,6 +466,12 @@ enum class Shareable
|
|||
True
|
||||
};
|
||||
|
||||
enum class HasGcTypes
|
||||
{
|
||||
False,
|
||||
True
|
||||
};
|
||||
|
||||
// The Val class represents a single WebAssembly value of a given value type,
|
||||
// mostly for the purpose of numeric literals and initializers. A Val does not
|
||||
// directly map to a JS value since there is not (currently) a precise
|
||||
|
@ -569,8 +591,17 @@ class Sig
|
|||
bool hasI64ArgOrRet() const {
|
||||
if (ret() == ExprType::I64)
|
||||
return true;
|
||||
for (ValType a : args()) {
|
||||
if (a == ValType::I64)
|
||||
for (ValType arg : args()) {
|
||||
if (arg == ValType::I64)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool temporarilyUnsupportedAnyRef() const {
|
||||
if (ret() == ExprType::AnyRef)
|
||||
return true;
|
||||
for (ValType arg : args()) {
|
||||
if (arg == ValType::AnyRef)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1437,6 +1468,7 @@ enum class SymbolicAddress
|
|||
CallImport_I32,
|
||||
CallImport_I64,
|
||||
CallImport_F64,
|
||||
CallImport_Ref,
|
||||
CoerceInPlace_ToInt32,
|
||||
CoerceInPlace_ToNumber,
|
||||
CoerceInPlace_JitEntry,
|
||||
|
|
|
@ -302,7 +302,7 @@ wasm::EncodeLocalEntries(Encoder& e, const ValTypeVector& locals)
|
|||
}
|
||||
|
||||
static bool
|
||||
DecodeValType(Decoder& d, ModuleKind kind, ValType* type)
|
||||
DecodeValType(Decoder& d, ModuleKind kind, HasGcTypes gcTypesEnabled, ValType* type)
|
||||
{
|
||||
uint8_t unchecked;
|
||||
if (!d.readValType(&unchecked))
|
||||
|
@ -315,6 +315,11 @@ DecodeValType(Decoder& d, ModuleKind kind, ValType* type)
|
|||
case uint8_t(ValType::I64):
|
||||
*type = ValType(unchecked);
|
||||
return true;
|
||||
case uint8_t(ValType::AnyRef):
|
||||
if (gcTypesEnabled == HasGcTypes::False)
|
||||
break;
|
||||
*type = ValType(unchecked);
|
||||
return true;
|
||||
case uint8_t(ValType::I8x16):
|
||||
case uint8_t(ValType::I16x8):
|
||||
case uint8_t(ValType::I32x4):
|
||||
|
@ -333,7 +338,8 @@ DecodeValType(Decoder& d, ModuleKind kind, ValType* type)
|
|||
}
|
||||
|
||||
bool
|
||||
wasm::DecodeLocalEntries(Decoder& d, ModuleKind kind, ValTypeVector* locals)
|
||||
wasm::DecodeLocalEntries(Decoder& d, ModuleKind kind, HasGcTypes gcTypesEnabled,
|
||||
ValTypeVector* locals)
|
||||
{
|
||||
uint32_t numLocalEntries;
|
||||
if (!d.readVarU32(&numLocalEntries))
|
||||
|
@ -348,7 +354,7 @@ wasm::DecodeLocalEntries(Decoder& d, ModuleKind kind, ValTypeVector* locals)
|
|||
return d.fail("too many locals");
|
||||
|
||||
ValType type;
|
||||
if (!DecodeValType(d, kind, &type))
|
||||
if (!DecodeValType(d, kind, gcTypesEnabled, &type))
|
||||
return false;
|
||||
|
||||
if (!locals->appendN(type, count))
|
||||
|
@ -742,6 +748,20 @@ DecodeFunctionBodyExprs(const ModuleEnvironment& env, const Sig& sig, const ValT
|
|||
return iter.unrecognizedOpcode(&op);
|
||||
#endif
|
||||
}
|
||||
#ifdef ENABLE_WASM_GC
|
||||
case uint16_t(Op::RefNull): {
|
||||
if (env.gcTypesEnabled == HasGcTypes::False)
|
||||
return iter.unrecognizedOpcode(&op);
|
||||
CHECK(iter.readRefNull());
|
||||
break;
|
||||
}
|
||||
case uint16_t(Op::RefIsNull): {
|
||||
if (env.gcTypesEnabled == HasGcTypes::False)
|
||||
return iter.unrecognizedOpcode(&op);
|
||||
CHECK(iter.readConversion(ValType::AnyRef, ValType::I32, ¬hing));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case uint16_t(Op::ThreadPrefix): {
|
||||
#ifdef ENABLE_WASM_THREAD_OPS
|
||||
switch (op.b1) {
|
||||
|
@ -936,7 +956,7 @@ wasm::ValidateFunctionBody(const ModuleEnvironment& env, uint32_t funcIndex, uin
|
|||
|
||||
const uint8_t* bodyBegin = d.currentPosition();
|
||||
|
||||
if (!DecodeLocalEntries(d, ModuleKind::Wasm, &locals))
|
||||
if (!DecodeLocalEntries(d, ModuleKind::Wasm, env.gcTypesEnabled, &locals))
|
||||
return false;
|
||||
|
||||
if (!DecodeFunctionBodyExprs(env, sig, locals, bodyBegin + bodySize, &d))
|
||||
|
@ -1001,7 +1021,7 @@ DecodeTypeSection(Decoder& d, ModuleEnvironment* env)
|
|||
return false;
|
||||
|
||||
for (uint32_t i = 0; i < numArgs; i++) {
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, &args[i]))
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, env->gcTypesEnabled, &args[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1016,7 +1036,7 @@ DecodeTypeSection(Decoder& d, ModuleEnvironment* env)
|
|||
|
||||
if (numRets == 1) {
|
||||
ValType type;
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, &type))
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, env->gcTypesEnabled, &type))
|
||||
return false;
|
||||
|
||||
result = ToExprType(type);
|
||||
|
@ -1161,7 +1181,8 @@ GlobalIsJSCompatible(Decoder& d, ValType type, bool isMutable)
|
|||
static bool
|
||||
DecodeGlobalType(Decoder& d, ValType* type, bool* isMutable)
|
||||
{
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, type))
|
||||
// No gc types in globals at the moment.
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, HasGcTypes::False, type))
|
||||
return false;
|
||||
|
||||
uint8_t flags;
|
||||
|
@ -1980,7 +2001,13 @@ wasm::Validate(JSContext* cx, const ShareableBytes& bytecode, UniqueChars* error
|
|||
{
|
||||
Decoder d(bytecode.bytes, 0, error);
|
||||
|
||||
ModuleEnvironment env(CompileMode::Once, Tier::Ion, DebugEnabled::False,
|
||||
#ifdef ENABLE_WASM_GC
|
||||
HasGcTypes gcSupport = cx->options().wasmGc() ? HasGcTypes::True : HasGcTypes::False;
|
||||
#else
|
||||
HasGcTypes gcSupport = HasGcTypes::False;
|
||||
#endif
|
||||
|
||||
ModuleEnvironment env(CompileMode::Once, Tier::Ion, DebugEnabled::False, gcSupport,
|
||||
cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled()
|
||||
? Shareable::True
|
||||
: Shareable::False);
|
||||
|
|
|
@ -60,6 +60,7 @@ struct ModuleEnvironment
|
|||
const ModuleKind kind;
|
||||
const CompileMode mode;
|
||||
const Shareable sharedMemoryEnabled;
|
||||
const HasGcTypes gcTypesEnabled;
|
||||
const Tier tier;
|
||||
|
||||
// Module fields decoded from the module environment (or initialized while
|
||||
|
@ -87,12 +88,14 @@ struct ModuleEnvironment
|
|||
explicit ModuleEnvironment(CompileMode mode,
|
||||
Tier tier,
|
||||
DebugEnabled debug,
|
||||
HasGcTypes hasGcTypes,
|
||||
Shareable sharedMemoryEnabled,
|
||||
ModuleKind kind = ModuleKind::Wasm)
|
||||
: debug(debug),
|
||||
kind(kind),
|
||||
mode(mode),
|
||||
sharedMemoryEnabled(sharedMemoryEnabled),
|
||||
gcTypesEnabled(hasGcTypes),
|
||||
tier(tier),
|
||||
memoryUsage(MemoryUsage::None),
|
||||
minMemoryLength(0)
|
||||
|
@ -696,7 +699,7 @@ MOZ_MUST_USE bool
|
|||
EncodeLocalEntries(Encoder& d, const ValTypeVector& locals);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
DecodeLocalEntries(Decoder& d, ModuleKind kind, ValTypeVector* locals);
|
||||
DecodeLocalEntries(Decoder& d, ModuleKind kind, HasGcTypes gcTypesEnabled, ValTypeVector* locals);
|
||||
|
||||
// Returns whether the given [begin, end) prefix of a module's bytecode starts a
|
||||
// code section and, if so, returns the SectionRange of that code section.
|
||||
|
|
|
@ -773,6 +773,9 @@ ReloadPrefsCallback(const char* pref, void* data)
|
|||
bool useWasm = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm");
|
||||
bool useWasmIon = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_ionjit");
|
||||
bool useWasmBaseline = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_baselinejit");
|
||||
#ifdef ENABLE_WASM_GC
|
||||
bool useWasmGc = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_gc");
|
||||
#endif
|
||||
bool throwOnAsmJSValidationFailure = Preferences::GetBool(JS_OPTIONS_DOT_STR
|
||||
"throw_on_asmjs_validation_failure");
|
||||
bool useNativeRegExp = Preferences::GetBool(JS_OPTIONS_DOT_STR "native_regexp");
|
||||
|
@ -844,6 +847,9 @@ ReloadPrefsCallback(const char* pref, void* data)
|
|||
.setWasm(useWasm)
|
||||
.setWasmIon(useWasmIon)
|
||||
.setWasmBaseline(useWasmBaseline)
|
||||
#ifdef ENABLE_WASM_GC
|
||||
.setWasmGc(useWasmGc)
|
||||
#endif
|
||||
.setThrowOnAsmJSValidationFailure(throwOnAsmJSValidationFailure)
|
||||
.setNativeRegExp(useNativeRegExp)
|
||||
.setAsyncStack(useAsyncStack)
|
||||
|
|
|
@ -63,3 +63,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
|
||||
CXXFLAGS += ['-Wno-shadow', '-Werror=format']
|
||||
|
||||
if CONFIG['NIGHTLY_BUILD']:
|
||||
DEFINES['ENABLE_WASM_GC'] = True
|
||||
|
|
|
@ -636,7 +636,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
|||
// This overrides the initial values specified in fontStyle, to avoid
|
||||
// inconsistencies in which attributes allow CSS changes and which do not.
|
||||
if (mFlags & MATH_FONT_WEIGHT_BOLD) {
|
||||
font.weight = NS_FONT_WEIGHT_BOLD;
|
||||
font.weight = FontWeight::Bold();
|
||||
if (mFlags & MATH_FONT_STYLING_NORMAL) {
|
||||
font.style = NS_FONT_STYLE_NORMAL;
|
||||
} else {
|
||||
|
@ -644,7 +644,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
|||
}
|
||||
} else if (mFlags & MATH_FONT_STYLING_NORMAL) {
|
||||
font.style = NS_FONT_STYLE_NORMAL;
|
||||
font.weight = NS_FONT_WEIGHT_NORMAL;
|
||||
font.weight = FontWeight::Normal();
|
||||
} else {
|
||||
mathVar = NS_MATHML_MATHVARIANT_ITALIC;
|
||||
}
|
||||
|
@ -723,20 +723,20 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
|||
|
||||
if (mathVar == NS_MATHML_MATHVARIANT_BOLD && doMathvariantStyling) {
|
||||
font.style = NS_FONT_STYLE_NORMAL;
|
||||
font.weight = NS_FONT_WEIGHT_BOLD;
|
||||
font.weight = FontWeight::Bold();
|
||||
} else if (mathVar == NS_MATHML_MATHVARIANT_ITALIC && doMathvariantStyling) {
|
||||
font.style = NS_FONT_STYLE_ITALIC;
|
||||
font.weight = NS_FONT_WEIGHT_NORMAL;
|
||||
font.weight = FontWeight::Normal();
|
||||
} else if (mathVar == NS_MATHML_MATHVARIANT_BOLD_ITALIC &&
|
||||
doMathvariantStyling) {
|
||||
font.style = NS_FONT_STYLE_ITALIC;
|
||||
font.weight = NS_FONT_WEIGHT_BOLD;
|
||||
font.weight = FontWeight::Bold();
|
||||
} else if (mathVar != NS_MATHML_MATHVARIANT_NONE) {
|
||||
// Mathvariant overrides fontstyle and fontweight
|
||||
// Need to check to see if mathvariant is actually applied as this function
|
||||
// is used for other purposes.
|
||||
font.style = NS_FONT_STYLE_NORMAL;
|
||||
font.weight = NS_FONT_WEIGHT_NORMAL;
|
||||
font.weight = FontWeight::Normal();
|
||||
}
|
||||
gfxFontGroup* newFontGroup = nullptr;
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче