зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
6fd9e51d9f
|
@ -10,6 +10,7 @@
|
|||
#include "ApplicationAccessibleWrap.h"
|
||||
#include "InterfaceInitFuncs.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "mozilla/a11y/PDocAccessible.h"
|
||||
#include "ProxyAccessible.h"
|
||||
#include "RootAccessible.h"
|
||||
#include "nsMai.h"
|
||||
|
@ -771,7 +772,27 @@ AtkAttributeSet *
|
|||
getAttributesCB(AtkObject *aAtkObj)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
|
||||
return accWrap ? GetAttributeSet(accWrap) : nullptr;
|
||||
if (accWrap)
|
||||
return GetAttributeSet(accWrap);
|
||||
|
||||
ProxyAccessible* proxy = GetProxy(aAtkObj);
|
||||
if (!proxy)
|
||||
return nullptr;
|
||||
|
||||
nsAutoTArray<Attribute, 10> attrs;
|
||||
proxy->Attributes(&attrs);
|
||||
if (attrs.IsEmpty())
|
||||
return nullptr;
|
||||
|
||||
AtkAttributeSet* objAttributeSet = nullptr;
|
||||
for (uint32_t i = 0; i < attrs.Length(); i++) {
|
||||
AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
|
||||
objAttr->name = g_strdup(attrs[i].Name().get());
|
||||
objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(attrs[i].Value()).get());
|
||||
objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
|
||||
}
|
||||
|
||||
return objAttributeSet;
|
||||
}
|
||||
|
||||
const gchar*
|
||||
|
|
|
@ -49,3 +49,5 @@ if CONFIG['MOZ_ENABLE_GTK']:
|
|||
|
||||
if CONFIG['MOZ_ENABLE_DBUS']:
|
||||
CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
#include "Accessible-inl.h"
|
||||
|
||||
#include "nsIPersistentProperties2.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
|
@ -76,5 +79,43 @@ DocAccessibleChild::RecvDescription(const uint64_t& aID, nsString* aDesc)
|
|||
acc->Description(*aDesc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvAttributes(const uint64_t& aID, nsTArray<Attribute>* aAttributes)
|
||||
{
|
||||
Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
|
||||
if (!acc)
|
||||
return true;
|
||||
|
||||
nsCOMPtr<nsIPersistentProperties> props = acc->Attributes();
|
||||
if (!props)
|
||||
return true;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> propEnum;
|
||||
nsresult rv = props->Enumerate(getter_AddRefs(propEnum));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
bool hasMore;
|
||||
while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
|
||||
nsCOMPtr<nsISupports> sup;
|
||||
rv = propEnum->GetNext(getter_AddRefs(sup));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
|
||||
NS_ENSURE_TRUE(propElem, false);
|
||||
|
||||
nsAutoCString name;
|
||||
rv = propElem->GetKey(name);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsAutoString value;
|
||||
rv = propElem->GetValue(value);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
aAttributes->AppendElement(Attribute(name, value));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,8 @@ public:
|
|||
*/
|
||||
virtual bool RecvDescription(const uint64_t& aID, nsString* aDesc) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvAttributes(const uint64_t& aID, nsTArray<Attribute> *aAttributes) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
DocAccessible* mDoc;
|
||||
};
|
||||
|
|
|
@ -23,6 +23,12 @@ struct ShowEventData
|
|||
AccessibleData[] NewTree;
|
||||
};
|
||||
|
||||
struct Attribute
|
||||
{
|
||||
nsCString Name;
|
||||
nsString Value;
|
||||
};
|
||||
|
||||
prio(normal upto high) sync protocol PDocAccessible
|
||||
{
|
||||
manager PContent;
|
||||
|
@ -42,6 +48,7 @@ child:
|
|||
prio(high) sync State(uint64_t aID) returns(uint64_t states);
|
||||
prio(high) sync Name(uint64_t aID) returns(nsString name);
|
||||
prio(high) sync Description(uint64_t aID) returns(nsString desc);
|
||||
prio(high) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -59,5 +59,11 @@ ProxyAccessible::Description(nsString& aDesc) const
|
|||
{
|
||||
unused << mDoc->SendDescription(mID, &aDesc);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::Attributes(nsTArray<Attribute> *aAttrs) const
|
||||
{
|
||||
unused << mDoc->SendAttributes(mID, aAttrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class Attribute;
|
||||
class DocAccessibleParent;
|
||||
|
||||
class ProxyAccessible
|
||||
|
@ -68,6 +69,11 @@ public:
|
|||
*/
|
||||
void Description(nsString& aDesc) const;
|
||||
|
||||
/**
|
||||
* Get the set of attributes on the proxied accessible.
|
||||
*/
|
||||
void Attributes(nsTArray<Attribute> *aAttrs) const;
|
||||
|
||||
/**
|
||||
* Allow the platform to store a pointers worth of data on us.
|
||||
*/
|
||||
|
|
|
@ -7,20 +7,11 @@ module.metadata = {
|
|||
"stability": "experimental"
|
||||
};
|
||||
|
||||
// This is known as @@iterator in the ES6 spec. Until it is bound to
|
||||
// some well-known name, find the @@iterator object by expecting it as
|
||||
// the first property accessed on a for-of iterable.
|
||||
const iteratorSymbol = (function() {
|
||||
try {
|
||||
for (var _ of Proxy.create({get: function(_, name) { throw name; } }))
|
||||
break;
|
||||
} catch (name) {
|
||||
return name;
|
||||
}
|
||||
throw new TypeError;
|
||||
})();
|
||||
|
||||
exports.iteratorSymbol = iteratorSymbol;
|
||||
// This is known as @@iterator in the ES6 spec. In builds that have ES6
|
||||
// Symbols, use Symbol.iterator; otherwise use the legacy method name,
|
||||
// "@@iterator".
|
||||
const JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
exports.iteratorSymbol = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
|
||||
// An adaptor that, given an object that is iterable with for-of, is
|
||||
// suitable for being bound to __iterator__ in order to make the object
|
||||
|
|
|
@ -50,6 +50,13 @@ const kSubviewEvents = [
|
|||
"ViewHiding"
|
||||
];
|
||||
|
||||
/**
|
||||
* The method name to use for ES6 iteration. If Symbols are enabled in
|
||||
* this build, use Symbol.iterator; otherwise "@@iterator".
|
||||
*/
|
||||
const JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
const kIteratorSymbol = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
|
||||
/**
|
||||
* The current version. We can use this to auto-add new default widgets as necessary.
|
||||
* (would be const but isn't because of testing purposes)
|
||||
|
@ -2679,7 +2686,7 @@ this.CustomizableUI = {
|
|||
* for (let window of CustomizableUI.windows) { ... }
|
||||
*/
|
||||
windows: {
|
||||
"@@iterator": function*() {
|
||||
*[kIteratorSymbol]() {
|
||||
for (let [window,] of gBuildWindows)
|
||||
yield window;
|
||||
}
|
||||
|
|
|
@ -3260,10 +3260,15 @@ LineResults.prototype = {
|
|||
|
||||
/**
|
||||
* A generator-iterator over the global, source or line results.
|
||||
*
|
||||
* The method name depends on whether symbols are enabled in
|
||||
* this build. If so, use Symbol.iterator; otherwise "@@iterator".
|
||||
*/
|
||||
GlobalResults.prototype["@@iterator"] =
|
||||
SourceResults.prototype["@@iterator"] =
|
||||
LineResults.prototype["@@iterator"] = function*() {
|
||||
const JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
GlobalResults.prototype[ITERATOR_SYMBOL] =
|
||||
SourceResults.prototype[ITERATOR_SYMBOL] =
|
||||
LineResults.prototype[ITERATOR_SYMBOL] = function*() {
|
||||
yield* this._store;
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,13 @@ const EventEmitter = devtools.require("devtools/toolkit/event-emitter");
|
|||
const FORBIDDEN_IDS = new Set(["toolbox", ""]);
|
||||
const MAX_ORDINAL = 99;
|
||||
|
||||
/**
|
||||
* The method name to use for ES6 iteration. If symbols are enabled in this
|
||||
* build, use Symbol.iterator; otherwise "@@iterator".
|
||||
*/
|
||||
const JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
|
||||
/**
|
||||
* DevTools is a class that represents a set of developer tools, it holds a
|
||||
* set of tools and keeps track of open toolboxes in the browser.
|
||||
|
@ -486,7 +493,7 @@ DevTools.prototype = {
|
|||
/**
|
||||
* Iterator that yields each of the toolboxes.
|
||||
*/
|
||||
'@@iterator': function*() {
|
||||
*[ITERATOR_SYMBOL]() {
|
||||
for (let toolbox of this._toolboxes) {
|
||||
yield toolbox;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,13 @@ const PAGE_SIZE_MAX_JUMPS = 30;
|
|||
const SEARCH_ACTION_MAX_DELAY = 300; // ms
|
||||
const ITEM_FLASH_DURATION = 300 // ms
|
||||
|
||||
/**
|
||||
* The method name to use for ES6 iteration. If symbols are enabled in
|
||||
* this build, use Symbol.iterator; otherwise "@@iterator".
|
||||
*/
|
||||
const JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
|
@ -3056,10 +3063,10 @@ Property.prototype = Heritage.extend(Variable.prototype, {
|
|||
/**
|
||||
* A generator-iterator over the VariablesView, Scopes, Variables and Properties.
|
||||
*/
|
||||
VariablesView.prototype["@@iterator"] =
|
||||
Scope.prototype["@@iterator"] =
|
||||
Variable.prototype["@@iterator"] =
|
||||
Property.prototype["@@iterator"] = function*() {
|
||||
VariablesView.prototype[ITERATOR_SYMBOL] =
|
||||
Scope.prototype[ITERATOR_SYMBOL] =
|
||||
Variable.prototype[ITERATOR_SYMBOL] =
|
||||
Property.prototype[ITERATOR_SYMBOL] = function*() {
|
||||
yield* this._store;
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,13 @@ const PANE_APPEARANCE_DELAY = 50;
|
|||
const PAGE_SIZE_ITEM_COUNT_RATIO = 5;
|
||||
const WIDGET_FOCUSABLE_NODES = new Set(["vbox", "hbox"]);
|
||||
|
||||
/**
|
||||
* The method name to use for ES6 iteration. If symbols are enabled in
|
||||
* this build, use Symbol.iterator; otherwise "@@iterator".
|
||||
*/
|
||||
const JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
@ -1729,7 +1736,7 @@ this.WidgetMethods = {
|
|||
/**
|
||||
* A generator-iterator over all the items in this container.
|
||||
*/
|
||||
Item.prototype["@@iterator"] =
|
||||
WidgetMethods["@@iterator"] = function*() {
|
||||
Item.prototype[ITERATOR_SYMBOL] =
|
||||
WidgetMethods[ITERATOR_SYMBOL] = function*() {
|
||||
yield* this._itemsByElement.values();
|
||||
};
|
||||
|
|
|
@ -6559,6 +6559,9 @@ case "$OS_TARGET:$NIGHTLY_BUILD" in
|
|||
WINNT:1)
|
||||
MOZ_CONTENT_SANDBOX=$MOZ_SANDBOX
|
||||
;;
|
||||
Darwin:1)
|
||||
MOZ_CONTENT_SANDBOX=$MOZ_SANDBOX
|
||||
;;
|
||||
*)
|
||||
MOZ_ARG_ENABLE_BOOL(content-sandbox,
|
||||
[ --enable-content-sandbox Enable sandboxing support for content-processes],
|
||||
|
|
|
@ -815,6 +815,7 @@ class CSPReportSenderRunnable MOZ_FINAL : public nsRunnable
|
|||
, mInnerWindowID(aInnerWindowID)
|
||||
, mCSPContext(aCSPContext)
|
||||
{
|
||||
NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive");
|
||||
// the observer subject is an nsISupports: either an nsISupportsCString
|
||||
// from the arg passed in directly, or if that's empty, it's the blocked
|
||||
// source.
|
||||
|
|
|
@ -927,16 +927,34 @@ nsCSPPolicy::directiveExists(enum CSPDirective aDir) const
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use this function only after ::allows() returned 'false'. Most and
|
||||
* foremost it's used to get the violated directive before sending reports.
|
||||
* The parameter outDirective is the equivalent of 'outViolatedDirective'
|
||||
* for the ::permits() function family.
|
||||
*/
|
||||
void
|
||||
nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType,
|
||||
nsAString& outDirective) const
|
||||
{
|
||||
nsCSPDirective* defaultDir = nullptr;
|
||||
for (uint32_t i = 0; i < mDirectives.Length(); i++) {
|
||||
if (mDirectives[i]->restrictsContentType(aContentType)) {
|
||||
mDirectives[i]->toString(outDirective);
|
||||
return;
|
||||
}
|
||||
if (mDirectives[i]->isDefaultDirective()) {
|
||||
defaultDir = mDirectives[i];
|
||||
}
|
||||
}
|
||||
// if we haven't found a matching directive yet,
|
||||
// the contentType must be restricted by the default directive
|
||||
if (defaultDir) {
|
||||
defaultDir->toString(outDirective);
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(false, "Can not query directive string for contentType!");
|
||||
outDirective.AppendASCII("couldNotQueryViolatedDirective");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -58,9 +58,14 @@
|
|||
ok(data.s === "hello", "string property");
|
||||
ok(data.x.i === 10, "nested property");
|
||||
ok(data.f() === 99, "function call");
|
||||
is(Object.getOwnPropertyDescriptor(data, "doesn't exist"), undefined,
|
||||
"getOwnPropertyDescriptor returns undefined for non-existant properties");
|
||||
ok(Object.getOwnPropertyDescriptor(data, "i").value, 5,
|
||||
"getOwnPropertyDescriptor.value works");
|
||||
let obj = new data.ctor();
|
||||
ok(obj.a === 3, "constructor call");
|
||||
ok(document.title === "Hello, Kitty", "document node");
|
||||
is(typeof document.cookie, "string", "can get document.cookie");
|
||||
|
||||
data.i = 6;
|
||||
data.b = false;
|
||||
|
|
|
@ -19,7 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=548193
|
|||
/*
|
||||
* Description of the test:
|
||||
* We try to load an inline-src using a policy that constrains
|
||||
* all scripts from running (script-src 'none'). We verify that
|
||||
* all scripts from running (default-src 'none'). We verify that
|
||||
* the generated csp-report contains the expceted values. If any
|
||||
* of the JSON is not formatted properly (e.g. not properly escaped)
|
||||
* then JSON.parse will fail, which allows to pinpoint such errors
|
||||
|
@ -29,10 +29,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=548193
|
|||
|
||||
const testfile = "tests/dom/base/test/csp/file_csp_report.html";
|
||||
const reportURI = "http://mochi.test:8888/foo.sjs";
|
||||
const policy = "script-src 'none'; report-uri " + reportURI;
|
||||
const policy = "default-src 'none'; report-uri " + reportURI;
|
||||
const docUri = "http://mochi.test:8888/tests/dom/base/test/csp/file_csp_testserver.sjs" +
|
||||
"?file=tests/dom/base/test/csp/file_csp_report.html" +
|
||||
"&csp=script-src%20%27none%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
|
||||
"&csp=default-src%20%27none%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
|
||||
|
||||
window.checkResults = function(reportObj) {
|
||||
var cspReport = reportObj["csp-report"];
|
||||
|
@ -50,9 +50,9 @@ window.checkResults = function(reportObj) {
|
|||
|
||||
is(cspReport["blocked-uri"], "self", "Incorrect blocked-uri");
|
||||
|
||||
is(cspReport["violated-directive"], "script-src 'none'", "Incorrect violated-directive");
|
||||
is(cspReport["violated-directive"], "default-src 'none'", "Incorrect violated-directive");
|
||||
|
||||
is(cspReport["original-policy"], "script-src 'none'; report-uri http://mochi.test:8888/foo.sjs",
|
||||
is(cspReport["original-policy"], "default-src 'none'; report-uri http://mochi.test:8888/foo.sjs",
|
||||
"Incorrect original-policy");
|
||||
|
||||
is(cspReport["source-file"], docUri, "Incorrect source-file");
|
||||
|
|
|
@ -16,9 +16,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1082672
|
|||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
var sym = Symbol("ponies");
|
||||
Object.defineProperty(window, sym, {configurable: true, value: 3});
|
||||
is(window[sym], 3);
|
||||
if (typeof Symbol === "function") {
|
||||
var sym = Symbol("ponies");
|
||||
Object.defineProperty(window, sym, {configurable: true, value: 3});
|
||||
is(window[sym], 3);
|
||||
} else {
|
||||
ok(true, "no Symbols in this build");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -2014,7 +2014,7 @@ class PropertyDefiner:
|
|||
getAvailableInTestFunc(interfaceMember),
|
||||
descriptor.checkPermissionsIndicesForMembers.get(interfaceMember.identifier.name))
|
||||
|
||||
def generatePrefableArray(self, array, name, specTemplate, specTerminator,
|
||||
def generatePrefableArray(self, array, name, specFormatter, specTerminator,
|
||||
specType, getCondition, getDataTuple, doIdArrays):
|
||||
"""
|
||||
This method generates our various arrays.
|
||||
|
@ -2023,7 +2023,8 @@ class PropertyDefiner:
|
|||
|
||||
name is the name as passed to generateArray
|
||||
|
||||
specTemplate is a template for each entry of the spec array
|
||||
specFormatter is a function that takes a single argument, a tuple,
|
||||
and returns a string, a spec array entry
|
||||
|
||||
specTerminator is a terminator for the spec array (inserted every time
|
||||
our controlling pref changes and at the end of the array)
|
||||
|
@ -2034,7 +2035,7 @@ class PropertyDefiner:
|
|||
returns the corresponding MemberCondition.
|
||||
|
||||
getDataTuple is a callback function that takes an array entry and
|
||||
returns a tuple suitable for substitution into specTemplate.
|
||||
returns a tuple suitable to be passed to specFormatter.
|
||||
"""
|
||||
|
||||
# We want to generate a single list of specs, but with specTerminator
|
||||
|
@ -2077,7 +2078,7 @@ class PropertyDefiner:
|
|||
switchToCondition(self, curCondition)
|
||||
lastCondition = curCondition
|
||||
# And the actual spec
|
||||
specs.append(specTemplate % getDataTuple(member))
|
||||
specs.append(specFormatter(getDataTuple(member)))
|
||||
specs.append(specTerminator)
|
||||
prefableSpecs.append(" { false, nullptr }")
|
||||
|
||||
|
@ -2354,9 +2355,15 @@ class MethodDefiner(PropertyDefiner):
|
|||
|
||||
return (m["name"], accessor, jitinfo, m["length"], flags(m), selfHostedName)
|
||||
|
||||
def formatSpec(fields):
|
||||
if fields[0].startswith("@@"):
|
||||
fields = (fields[0][2:],) + fields[1:]
|
||||
return ' JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)' % fields
|
||||
return ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
|
||||
|
||||
return self.generatePrefableArray(
|
||||
array, name,
|
||||
' JS_FNSPEC("%s", %s, %s, %s, %s, %s)',
|
||||
formatSpec,
|
||||
' JS_FS_END',
|
||||
'JSFunctionSpec',
|
||||
condition, specData, doIdArrays)
|
||||
|
@ -2460,7 +2467,7 @@ class AttrDefiner(PropertyDefiner):
|
|||
|
||||
return self.generatePrefableArray(
|
||||
array, name,
|
||||
' { "%s", %s, %s, %s}',
|
||||
lambda fields: ' { "%s", %s, %s, %s}' % fields,
|
||||
' JS_PS_END',
|
||||
'JSPropertySpec',
|
||||
PropertyDefiner.getControllingCondition, specData, doIdArrays)
|
||||
|
@ -2488,7 +2495,7 @@ class ConstDefiner(PropertyDefiner):
|
|||
|
||||
return self.generatePrefableArray(
|
||||
array, name,
|
||||
' { "%s", %s }',
|
||||
lambda fields: ' { "%s", %s }' % fields,
|
||||
' { 0, JS::UndefinedValue() }',
|
||||
'ConstantSpec',
|
||||
PropertyDefiner.getControllingCondition, specData, doIdArrays)
|
||||
|
|
|
@ -16,18 +16,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1066432
|
|||
var testInterfaceJS = new TestInterfaceJS();
|
||||
ok(testInterfaceJS, "got a TestInterfaceJS object");
|
||||
|
||||
var nonIterableObject = { "@@iterator": 5 };
|
||||
if (typeof Symbol === "function") {
|
||||
// Make this test fail if Symbol.iterator is correctly implemented.
|
||||
// This is here to make sure this test is updated when bug 918828 lands,
|
||||
// at which point the correct code will be:
|
||||
// var JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
// var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
// var nonIterableObject = { [std_iterator]: 5};
|
||||
// Otherwise, fixing bug 918828 would cause this test to silently stop
|
||||
// testing what it's supposed to be testing.
|
||||
nonIterableObject[Symbol.iterator] = Array.prototype[Symbol.iterator];
|
||||
}
|
||||
var JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
var nonIterableObject = {[std_iterator]: 5};
|
||||
|
||||
try {
|
||||
testInterfaceJS.testSequenceOverload(nonIterableObject);
|
||||
|
|
|
@ -444,7 +444,7 @@ HTMLTextAreaElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
|||
NS_IMETHODIMP_(bool)
|
||||
HTMLTextAreaElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry attributes[] {
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::wrap },
|
||||
{ nullptr }
|
||||
};
|
||||
|
|
|
@ -32,7 +32,9 @@ names = [];
|
|||
for (var name in x) {
|
||||
names.push(name);
|
||||
}
|
||||
is(names.length, 10, "Should have 10 enumerated names");
|
||||
var JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
is(names.length, JS_HAS_SYMBOLS ? 9 : 10,
|
||||
"Should have 9 enumerated names (or 10 with '@@iterator')");
|
||||
is(names[0], "0", "Enum entry 1");
|
||||
is(names[1], "1", "Enum entry 2");
|
||||
is(names[2], "2", "Enum entry 3");
|
||||
|
@ -41,8 +43,12 @@ is(names[4], "4", "Enum entry 5");
|
|||
is(names[5], "something", "Enum entry 6");
|
||||
is(names[6], "namedItem", "Enum entry 7");
|
||||
is(names[7], "item", "Enum entry 8");
|
||||
is(names[8], "@@iterator", "Enum entry 9");
|
||||
is(names[9], "length", "Enum entry 10");
|
||||
if (JS_HAS_SYMBOLS) {
|
||||
is(names[8], "length", "Enum entry 9");
|
||||
} else {
|
||||
is(names[8], "@@iterator", "Enum entry 9");
|
||||
is(names[9], "length", "Enum entry 10");
|
||||
}
|
||||
|
||||
names = Object.getOwnPropertyNames(x);
|
||||
is(names.length, 10, "Should have 10 items");
|
||||
|
|
|
@ -28,7 +28,9 @@ var names = [];
|
|||
for (var name in x) {
|
||||
names.push(name);
|
||||
}
|
||||
is(names.length, 9, "Should have 9 enumerated names");
|
||||
var JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
is(names.length, JS_HAS_SYMBOLS ? 8 : 9,
|
||||
"Should have 8 enumerated names (or 9 with '@@iterator')");
|
||||
is(names[0], "0", "Enum entry 1")
|
||||
is(names[1], "1", "Enum entry 2")
|
||||
is(names[2], "2", "Enum entry 3")
|
||||
|
@ -36,8 +38,12 @@ is(names[3], "3", "Enum entry 4")
|
|||
is(names[4], "something", "Enum entry 5")
|
||||
is(names[5], "item", "Enum entry 6")
|
||||
is(names[6], "namedItem", "Enum entry 7")
|
||||
is(names[7], "@@iterator", "Enum entry 8")
|
||||
is(names[8], "length", "Enum entry 9")
|
||||
if (JS_HAS_SYMBOLS) {
|
||||
is(names[7], "length", "Enum entry 8");
|
||||
} else {
|
||||
is(names[7], "@@iterator", "Enum entry 8");
|
||||
is(names[8], "length", "Enum entry 9");
|
||||
}
|
||||
|
||||
names = Object.getOwnPropertyNames(x);
|
||||
is(names.length, 9, "Should have 9 items");
|
||||
|
|
|
@ -42,7 +42,9 @@ var names2 = [];
|
|||
for (var name in opt) {
|
||||
names2.push(name);
|
||||
}
|
||||
is(names2.length, 12, "Should have twelve enumerated names");
|
||||
var JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
is(names2.length, JS_HAS_SYMBOLS ? 11 : 12,
|
||||
"Should have eleven enumerated names (or twelve with '@@iterator')");
|
||||
is(names2[0], "0", "Enum entry 1")
|
||||
is(names2[1], "1", "Enum entry 2")
|
||||
is(names2[2], "2", "Enum entry 3")
|
||||
|
@ -54,7 +56,9 @@ is(names2[7], "length", "Enum entry 8")
|
|||
is(names2[8], "selectedIndex", "Enum entry 9")
|
||||
is(names2[9], "item", "Enum entry 10")
|
||||
is(names2[10], "namedItem", "Enum entry 11")
|
||||
is(names2[11], "@@iterator", "Enum entry 12")
|
||||
if (!JS_HAS_SYMBOLS) {
|
||||
is(names2[11], "@@iterator", "Enum entry 12");
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
|
|
@ -38,7 +38,9 @@ var names = [];
|
|||
for (var name in x) {
|
||||
names.push(name);
|
||||
}
|
||||
is(names.length, 11, "Should have 11 enumerated names");
|
||||
var JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
is(names.length, JS_HAS_SYMBOLS ? 10 : 11,
|
||||
"Should have 10 enumerated names (or 11 with '@@iterator')");
|
||||
is(names[0], "0", "Enum entry 1")
|
||||
is(names[1], "1", "Enum entry 2")
|
||||
is(names[2], "2", "Enum entry 3")
|
||||
|
@ -48,8 +50,12 @@ is(names[5], "5", "Enum entry 6")
|
|||
is(names[6], "something", "Enum entry 7")
|
||||
is(names[7], "item", "Enum entry 8")
|
||||
is(names[8], "namedItem", "Enum entry 9")
|
||||
is(names[9], "@@iterator", "Enum entry 10")
|
||||
is(names[10], "length", "Enum entry 11")
|
||||
if (JS_HAS_SYMBOLS) {
|
||||
is(names[9], "length", "Enum entry 10");
|
||||
} else {
|
||||
is(names[9], "@@iterator", "Enum entry 10");
|
||||
is(names[10], "length", "Enum entry 11");
|
||||
}
|
||||
|
||||
names = Object.getOwnPropertyNames(x);
|
||||
is(names.length, 11, "Should have 11 items");
|
||||
|
|
|
@ -2206,6 +2206,14 @@ SetDefaultPragmas(mozIStorageConnection* aConnection)
|
|||
return rv;
|
||||
}
|
||||
|
||||
if (IndexedDatabaseManager::FullSynchronous()) {
|
||||
rv = aConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("PRAGMA synchronous = FULL;"));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -212,6 +212,7 @@ IndexedDatabaseManager::~IndexedDatabaseManager()
|
|||
}
|
||||
|
||||
bool IndexedDatabaseManager::sIsMainProcess = false;
|
||||
bool IndexedDatabaseManager::sFullSynchronousMode = false;
|
||||
mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
|
||||
|
||||
// static
|
||||
|
@ -299,6 +300,14 @@ IndexedDatabaseManager::Init()
|
|||
Preferences::RegisterCallbackAndCall(TestingPrefChangedCallback,
|
||||
kTestingPref);
|
||||
|
||||
// By default IndexedDB uses SQLite with PRAGMA synchronous = NORMAL. This
|
||||
// guarantees (unlike synchronous = OFF) atomicity and consistency, but not
|
||||
// necessarily durability in situations such as power loss. This preference
|
||||
// allows enabling PRAGMA synchronous = FULL on SQLite, which does guarantee
|
||||
// durability, but with an extra fsync() and the corresponding performance
|
||||
// hit.
|
||||
sFullSynchronousMode = Preferences::GetBool("dom.indexedDB.fullSynchronous");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -502,6 +511,16 @@ IndexedDatabaseManager::InTestingMode()
|
|||
return gTestingMode;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IndexedDatabaseManager::FullSynchronous()
|
||||
{
|
||||
MOZ_ASSERT(gDBManager,
|
||||
"FullSynchronous() called before indexedDB has been initialized!");
|
||||
|
||||
return sFullSynchronousMode;
|
||||
}
|
||||
|
||||
already_AddRefed<FileManager>
|
||||
IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
|
|
|
@ -80,6 +80,9 @@ public:
|
|||
static bool
|
||||
InTestingMode();
|
||||
|
||||
static bool
|
||||
FullSynchronous();
|
||||
|
||||
already_AddRefed<FileManager>
|
||||
GetFileManager(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
|
@ -162,6 +165,7 @@ private:
|
|||
mozilla::Mutex mFileMutex;
|
||||
|
||||
static bool sIsMainProcess;
|
||||
static bool sFullSynchronousMode;
|
||||
static mozilla::Atomic<bool> sLowDiskSpaceMode;
|
||||
};
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
#define TARGET_SANDBOX_EXPORTS
|
||||
#include "mozilla/sandboxTarget.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#elif defined(XP_LINUX)
|
||||
#elif defined(XP_LINUX) || defined(XP_MACOSX)
|
||||
#include "mozilla/Sandbox.h"
|
||||
#endif
|
||||
#endif
|
||||
|
@ -552,6 +552,76 @@ NS_INTERFACE_MAP_BEGIN(ContentChild)
|
|||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
static bool
|
||||
GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath)
|
||||
{
|
||||
nsAutoCString appPath;
|
||||
nsAutoCString appBinaryPath(
|
||||
(CommandLine::ForCurrentProcess()->argv()[0]).c_str());
|
||||
|
||||
nsAutoCString::const_iterator start, end;
|
||||
appBinaryPath.BeginReading(start);
|
||||
appBinaryPath.EndReading(end);
|
||||
if (RFindInReadable(NS_LITERAL_CSTRING(".app/Contents/MacOS/"), start, end)) {
|
||||
end = start;
|
||||
++end; ++end; ++end; ++end;
|
||||
appBinaryPath.BeginReading(start);
|
||||
appPath.Assign(Substring(start, end));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> app, appBinary;
|
||||
nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appPath),
|
||||
true, getter_AddRefs(app));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appBinaryPath),
|
||||
true, getter_AddRefs(appBinary));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isLink;
|
||||
app->IsSymlink(&isLink);
|
||||
if (isLink) {
|
||||
app->GetNativeTarget(aAppPath);
|
||||
} else {
|
||||
app->GetNativePath(aAppPath);
|
||||
}
|
||||
appBinary->IsSymlink(&isLink);
|
||||
if (isLink) {
|
||||
appBinary->GetNativeTarget(aAppBinaryPath);
|
||||
} else {
|
||||
appBinary->GetNativePath(aAppBinaryPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ContentChild::OnChannelConnected(int32_t aPid)
|
||||
{
|
||||
nsAutoCString appPath, appBinaryPath;
|
||||
if (!GetAppPaths(appPath, appBinaryPath)) {
|
||||
MOZ_CRASH("Error resolving child process path");
|
||||
}
|
||||
|
||||
MacSandboxInfo info;
|
||||
info.type = MacSandboxType_Content;
|
||||
info.appPath.Assign(appPath);
|
||||
info.appBinaryPath.Assign(appBinaryPath);
|
||||
|
||||
nsAutoCString err;
|
||||
if (!mozilla::StartMacSandbox(info, err)) {
|
||||
NS_WARNING(err.get());
|
||||
MOZ_CRASH("sandbox_init() failed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
ContentChild::Init(MessageLoop* aIOLoop,
|
||||
base::ProcessHandle aParentHandle,
|
||||
|
@ -586,7 +656,9 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
return false;
|
||||
}
|
||||
|
||||
Open(aChannel, aParentHandle, aIOLoop);
|
||||
if (!Open(aChannel, aParentHandle, aIOLoop)) {
|
||||
return false;
|
||||
}
|
||||
sSingleton = this;
|
||||
|
||||
// Make sure there's an nsAutoScriptBlocker on the stack when dispatching
|
||||
|
|
|
@ -74,6 +74,10 @@ public:
|
|||
nsCString vendor;
|
||||
};
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
void OnChannelConnected(int32_t aPid);
|
||||
#endif
|
||||
|
||||
bool Init(MessageLoop* aIOLoop,
|
||||
base::ProcessHandle aParentHandle,
|
||||
IPC::Channel* aChannel);
|
||||
|
|
|
@ -69,7 +69,7 @@ union MaybeNativeKeyBinding
|
|||
void_t;
|
||||
};
|
||||
|
||||
prio(normal upto high) intr protocol PBrowser
|
||||
prio(normal upto urgent) intr protocol PBrowser
|
||||
{
|
||||
manager PContent or PContentBridge;
|
||||
|
||||
|
@ -141,7 +141,7 @@ parent:
|
|||
* preference Native widget preference for IME updates
|
||||
* seqno Current seqno value on the chrome side
|
||||
*/
|
||||
sync NotifyIMEFocus(bool focus)
|
||||
prio(urgent) sync NotifyIMEFocus(bool focus)
|
||||
returns (nsIMEUpdatePreference preference, uint32_t seqno);
|
||||
|
||||
/**
|
||||
|
@ -157,8 +157,9 @@ parent:
|
|||
* for insertion, offset == end
|
||||
* for deletion, offset == newEnd
|
||||
*/
|
||||
NotifyIMETextChange(uint32_t offset, uint32_t end, uint32_t newEnd,
|
||||
bool causedByComposition);
|
||||
prio(urgent) async NotifyIMETextChange(uint32_t offset, uint32_t end,
|
||||
uint32_t newEnd,
|
||||
bool causedByComposition);
|
||||
|
||||
/**
|
||||
* Notifies chrome that there is a IME compostion rect updated
|
||||
|
@ -168,8 +169,10 @@ parent:
|
|||
* caretOffset The offset of caret position
|
||||
* caretRect The rect of IME caret
|
||||
*/
|
||||
NotifyIMESelectedCompositionRect(uint32_t offset, nsIntRect[] rect,
|
||||
uint32_t caretOffset, nsIntRect caretRect);
|
||||
prio(urgent) async NotifyIMESelectedCompositionRect(uint32_t offset,
|
||||
nsIntRect[] rect,
|
||||
uint32_t caretOffset,
|
||||
nsIntRect caretRect);
|
||||
|
||||
/**
|
||||
* Notifies chrome that there has been a change in selection
|
||||
|
@ -180,22 +183,22 @@ parent:
|
|||
* focus Offset where the caret is
|
||||
* causedByComposition true if the change is caused by composition
|
||||
*/
|
||||
NotifyIMESelection(uint32_t seqno, uint32_t anchor, uint32_t focus,
|
||||
bool causedByComposition);
|
||||
prio(urgent) async NotifyIMESelection(uint32_t seqno, uint32_t anchor,
|
||||
uint32_t focus, bool causedByComposition);
|
||||
|
||||
/**
|
||||
* Notifies chrome to refresh its text cache
|
||||
*
|
||||
* text The entire content of the text field
|
||||
*/
|
||||
NotifyIMETextHint(nsString text);
|
||||
prio(urgent) async NotifyIMETextHint(nsString text);
|
||||
|
||||
/**
|
||||
* Notifies IME of mouse button event on a character in focused editor.
|
||||
*
|
||||
* Returns true if the mouse button event is consumd by IME.
|
||||
*/
|
||||
sync NotifyIMEMouseButtonEvent(IMENotification notification)
|
||||
prio(urgent) sync NotifyIMEMouseButtonEvent(IMENotification notification)
|
||||
returns (bool consumedByIME);
|
||||
|
||||
/**
|
||||
|
@ -209,7 +212,7 @@ parent:
|
|||
* if cancel is PR_FALSE,
|
||||
* widget should return the current composition text
|
||||
*/
|
||||
sync EndIMEComposition(bool cancel) returns (nsString composition);
|
||||
prio(urgent) sync EndIMEComposition(bool cancel) returns (nsString composition);
|
||||
|
||||
/**
|
||||
* Request that the parent process move focus to the browser's frame. If
|
||||
|
@ -217,16 +220,17 @@ parent:
|
|||
*/
|
||||
RequestFocus(bool canRaise);
|
||||
|
||||
sync GetInputContext() returns (int32_t IMEEnabled, int32_t IMEOpen,
|
||||
intptr_t NativeIMEContext);
|
||||
prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
|
||||
int32_t IMEOpen,
|
||||
intptr_t NativeIMEContext);
|
||||
|
||||
SetInputContext(int32_t IMEEnabled,
|
||||
int32_t IMEOpen,
|
||||
nsString type,
|
||||
nsString inputmode,
|
||||
nsString actionHint,
|
||||
int32_t cause,
|
||||
int32_t focusChange);
|
||||
prio(urgent) async SetInputContext(int32_t IMEEnabled,
|
||||
int32_t IMEOpen,
|
||||
nsString type,
|
||||
nsString inputmode,
|
||||
nsString actionHint,
|
||||
int32_t cause,
|
||||
int32_t focusChange);
|
||||
|
||||
sync IsParentWindowMainWidgetVisible() returns (bool visible);
|
||||
|
||||
|
|
|
@ -330,7 +330,7 @@ union MaybeFileDesc {
|
|||
void_t;
|
||||
};
|
||||
|
||||
prio(normal upto high) intr protocol PContent
|
||||
prio(normal upto urgent) intr protocol PContent
|
||||
{
|
||||
parent spawns PPluginModule;
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace dom {
|
|||
* allocate the PContentBridgeChild. This protocol allows these processes to
|
||||
* share PBrowsers and send messages to each other.
|
||||
*/
|
||||
prio(normal upto high) intr protocol PContentBridge
|
||||
prio(normal upto urgent) intr protocol PContentBridge
|
||||
{
|
||||
bridges PContent, PContent;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ UDPSocketChildBase::ReleaseIPDLReference()
|
|||
{
|
||||
MOZ_ASSERT(mIPCOpen);
|
||||
mIPCOpen = false;
|
||||
mSocket = nullptr;
|
||||
this->Release();
|
||||
}
|
||||
|
||||
|
|
|
@ -243,6 +243,14 @@ nsPluginHost::nsPluginHost()
|
|||
// No need to initialize members to nullptr, false etc because this class
|
||||
// has a zeroing operator new.
|
||||
{
|
||||
// Bump the pluginchanged epoch on startup. This insures content gets a
|
||||
// good plugin list the first time it requests it. Normally we'd just
|
||||
// init this to 1, but due to the unique nature of our ctor we need to do
|
||||
// this manually.
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||
IncrementChromeEpoch();
|
||||
}
|
||||
|
||||
// check to see if pref is set at startup to let plugins take over in
|
||||
// full page mode for certain image mime types that we handle internally
|
||||
mOverrideInternalTypes =
|
||||
|
|
|
@ -692,23 +692,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
return true;
|
||||
}
|
||||
|
||||
struct AutoDeferMessages
|
||||
{
|
||||
typedef IPC::Message Message;
|
||||
|
||||
std::deque<Message>& mQueue;
|
||||
mozilla::Vector<Message> mDeferred;
|
||||
|
||||
AutoDeferMessages(std::deque<Message>& queue) : mQueue(queue) {}
|
||||
~AutoDeferMessages() {
|
||||
mQueue.insert(mQueue.begin(), mDeferred.begin(), mDeferred.end());
|
||||
}
|
||||
|
||||
void Defer(Message aMsg) {
|
||||
mDeferred.append(aMsg);
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
MessageChannel::SendAndWait(Message* aMsg, Message* aReply)
|
||||
{
|
||||
|
@ -728,16 +711,28 @@ MessageChannel::SendAndWait(Message* aMsg, Message* aReply)
|
|||
|
||||
mLink->SendMessage(msg.forget());
|
||||
|
||||
AutoDeferMessages defer(mPending);
|
||||
|
||||
while (true) {
|
||||
while (!mPending.empty()) {
|
||||
Message msg = mPending.front();
|
||||
mPending.pop_front();
|
||||
if (ShouldDeferMessage(msg))
|
||||
defer.Defer(msg);
|
||||
else
|
||||
ProcessPendingRequest(msg);
|
||||
// Loop until there aren't any more priority messages to process.
|
||||
for (;;) {
|
||||
mozilla::Vector<Message> toProcess;
|
||||
|
||||
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
|
||||
Message &msg = *it;
|
||||
if (!ShouldDeferMessage(msg)) {
|
||||
toProcess.append(msg);
|
||||
it = mPending.erase(it);
|
||||
continue;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
if (toProcess.empty())
|
||||
break;
|
||||
|
||||
// Processing these messages could result in more messages, so we
|
||||
// loop around to check for more afterwards.
|
||||
for (auto it = toProcess.begin(); it != toProcess.end(); it++)
|
||||
ProcessPendingRequest(*it);
|
||||
}
|
||||
|
||||
// See if we've received a reply.
|
||||
|
@ -860,7 +855,7 @@ MessageChannel::Call(Message* aMsg, Message* aReply)
|
|||
// If the message is not Interrupt, we can dispatch it as normal.
|
||||
if (!recvd.is_interrupt()) {
|
||||
{
|
||||
AutoEnterTransaction transaction(this, &recvd);
|
||||
AutoEnterTransaction transaction(this, recvd);
|
||||
MonitorAutoUnlock unlock(*mMonitor);
|
||||
CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
|
||||
DispatchMessage(recvd);
|
||||
|
@ -947,7 +942,7 @@ MessageChannel::InterruptEventOccurred()
|
|||
}
|
||||
|
||||
bool
|
||||
MessageChannel::ProcessPendingRequest(Message aUrgent)
|
||||
MessageChannel::ProcessPendingRequest(const Message &aUrgent)
|
||||
{
|
||||
AssertWorkerThread();
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
|
@ -965,7 +960,7 @@ MessageChannel::ProcessPendingRequest(Message aUrgent)
|
|||
{
|
||||
// In order to send the parent RPC messages and guarantee it will
|
||||
// wake up, we must re-use its transaction.
|
||||
AutoEnterTransaction transaction(this, &aUrgent);
|
||||
AutoEnterTransaction transaction(this, aUrgent);
|
||||
|
||||
MonitorAutoUnlock unlock(*mMonitor);
|
||||
DispatchMessage(aUrgent);
|
||||
|
@ -1029,7 +1024,7 @@ MessageChannel::OnMaybeDequeueOne()
|
|||
{
|
||||
// We should not be in a transaction yet if we're not blocked.
|
||||
MOZ_ASSERT(mCurrentTransaction == 0);
|
||||
AutoEnterTransaction transaction(this, &recvd);
|
||||
AutoEnterTransaction transaction(this, recvd);
|
||||
|
||||
MonitorAutoUnlock unlock(*mMonitor);
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ class MessageChannel : HasResultCodes
|
|||
{
|
||||
friend class ProcessLink;
|
||||
friend class ThreadLink;
|
||||
friend class AutoEnterRPCTransaction;
|
||||
|
||||
class CxxStackFrame;
|
||||
class InterruptFrame;
|
||||
|
@ -228,7 +227,7 @@ class MessageChannel : HasResultCodes
|
|||
|
||||
bool InterruptEventOccurred();
|
||||
|
||||
bool ProcessPendingRequest(Message aUrgent);
|
||||
bool ProcessPendingRequest(const Message &aUrgent);
|
||||
|
||||
void MaybeUndeferIncall();
|
||||
void EnqueuePendingMessages();
|
||||
|
@ -510,18 +509,18 @@ class MessageChannel : HasResultCodes
|
|||
if (mChan->mCurrentTransaction == 0)
|
||||
mChan->mCurrentTransaction = mChan->NextSeqno();
|
||||
}
|
||||
explicit AutoEnterTransaction(MessageChannel *aChan, Message *message)
|
||||
explicit AutoEnterTransaction(MessageChannel *aChan, const Message &aMessage)
|
||||
: mChan(aChan),
|
||||
mOldTransaction(mChan->mCurrentTransaction)
|
||||
{
|
||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
if (!message->is_sync())
|
||||
if (!aMessage.is_sync())
|
||||
return;
|
||||
|
||||
MOZ_ASSERT_IF(mChan->mSide == ParentSide && mOldTransaction != message->transaction_id(),
|
||||
!mOldTransaction || message->priority() > mChan->AwaitingSyncReplyPriority());
|
||||
mChan->mCurrentTransaction = message->transaction_id();
|
||||
MOZ_ASSERT_IF(mChan->mSide == ParentSide && mOldTransaction != aMessage.transaction_id(),
|
||||
!mOldTransaction || aMessage.priority() > mChan->AwaitingSyncReplyPriority());
|
||||
mChan->mCurrentTransaction = aMessage.transaction_id();
|
||||
}
|
||||
~AutoEnterTransaction() {
|
||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||
|
|
|
@ -678,7 +678,7 @@ function ArrayFrom(arrayLike, mapfn=undefined, thisArg=undefined) {
|
|||
var attrs = ATTR_CONFIGURABLE | ATTR_ENUMERABLE | ATTR_WRITABLE;
|
||||
|
||||
// Steps 6-8.
|
||||
var usingIterator = items["@@iterator"];
|
||||
var usingIterator = items[std_iterator];
|
||||
if (usingIterator !== undefined) {
|
||||
// Steps 8.a-c.
|
||||
var A = IsConstructor(C) ? new C() : [];
|
||||
|
|
|
@ -878,7 +878,7 @@ const Class MapIteratorObject::class_ = {
|
|||
};
|
||||
|
||||
const JSFunctionSpec MapIteratorObject::methods[] = {
|
||||
JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
|
||||
JS_FN("next", next, 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
@ -1076,8 +1076,14 @@ MapObject::initClass(JSContext *cx, JSObject *obj)
|
|||
|
||||
// Define its alias.
|
||||
RootedValue funval(cx, ObjectValue(*fun));
|
||||
#if JS_HAS_SYMBOLS
|
||||
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
|
||||
if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
|
||||
return nullptr;
|
||||
#else
|
||||
if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0))
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
return proto;
|
||||
}
|
||||
|
@ -1528,7 +1534,7 @@ const Class SetIteratorObject::class_ = {
|
|||
};
|
||||
|
||||
const JSFunctionSpec SetIteratorObject::methods[] = {
|
||||
JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
|
||||
JS_FN("next", next, 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
@ -1702,8 +1708,15 @@ SetObject::initClass(JSContext *cx, JSObject *obj)
|
|||
RootedValue funval(cx, ObjectValue(*fun));
|
||||
if (!JS_DefineProperty(cx, proto, "keys", funval, 0))
|
||||
return nullptr;
|
||||
|
||||
#if JS_HAS_SYMBOLS
|
||||
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
|
||||
if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
|
||||
return nullptr;
|
||||
#else
|
||||
if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0))
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
return proto;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
//
|
||||
// The few items below here are either self-hosted or installing them under a
|
||||
// std_Foo name would require ugly contortions, so they just get aliased here.
|
||||
var std_iterator = '@@iterator'; // FIXME: Change to be a symbol.
|
||||
var std_Array_indexOf = ArrayIndexOf;
|
||||
// WeakMap is a bare constructor without properties or methods.
|
||||
var std_WeakMap = WeakMap;
|
||||
|
|
|
@ -2488,11 +2488,6 @@ EmitElemOpBase(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op)
|
|||
if (Emit1(cx, bce, op) < 0)
|
||||
return false;
|
||||
CheckTypeSet(cx, bce, op);
|
||||
|
||||
if (op == JSOP_CALLELEM) {
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4730,9 +4725,16 @@ EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce)
|
|||
// Convert iterable to iterator.
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // OBJ OBJ
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // OBJ @@ITERATOR
|
||||
#ifdef JS_HAS_SYMBOLS
|
||||
if (Emit2(cx, bce, JSOP_SYMBOL, jsbytecode(JS::SymbolCode::iterator)) < 0) // OBJ OBJ @@ITERATOR
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0) // @@ITERATOR OBJ
|
||||
if (!EmitElemOpBase(cx, bce, JSOP_CALLELEM)) // OBJ ITERFN
|
||||
return false;
|
||||
#else
|
||||
if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // OBJ ITERFN
|
||||
return false;
|
||||
#endif
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0) // ITERFN OBJ
|
||||
return false;
|
||||
if (EmitCall(cx, bce, JSOP_CALL, 0) < 0) // ITER
|
||||
return false;
|
||||
|
@ -5598,17 +5600,8 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, Parse
|
|||
|
||||
if (!EmitTree(cx, bce, iter)) // ITERABLE
|
||||
return false;
|
||||
|
||||
// Convert iterable to iterator.
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITERABLE ITERABLE
|
||||
if (!EmitIterator(cx, bce)) // ITER
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // ITERABLE @@ITERATOR
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0) // @@ITERATOR ITERABLE
|
||||
return false;
|
||||
if (EmitCall(cx, bce, JSOP_CALL, 0, iter) < 0) // ITER
|
||||
return false;
|
||||
CheckTypeSet(cx, bce, JSOP_CALL);
|
||||
|
||||
// Initial send value is undefined.
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER RECEIVED
|
||||
|
@ -6052,6 +6045,10 @@ EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
case PNK_ELEM:
|
||||
if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, bce))
|
||||
return false;
|
||||
if (callop) {
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PNK_FUNCTION:
|
||||
/*
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
// FIXME: Import from std::iteration.
|
||||
const std_iterator = '@@iterator';
|
||||
const JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
const std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : '@@iterator';
|
||||
|
||||
if (typeof assertIteratorResult === 'undefined') {
|
||||
var assertIteratorResult = function assertIteratorResult(result, value, done) {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// See bug 763313
|
||||
load(libdir + "iteration.js");
|
||||
function f([a]) a
|
||||
var i = 0;
|
||||
var o = {'@@iterator': function () { i++; return {
|
||||
var o = {[std_iterator]: function () { i++; return {
|
||||
next: function () { i++; return {value: 42, done: false}; }}}};
|
||||
assertEq(f(o), 42);
|
||||
assertEq(i, 2);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
load(libdir + "asserts.js");
|
||||
load(libdir + "iteration.js");
|
||||
|
||||
function check_one(expected, f, err) {
|
||||
var failed = true;
|
||||
|
@ -109,8 +110,11 @@ check("o[- (o)]");
|
|||
// A few one off tests
|
||||
check_one("6", (function () { 6() }), " is not a function");
|
||||
check_one("Array.prototype.reverse.call(...)", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
|
||||
check_one("(intermediate value)['@@iterator'](...).next(...).value", function () { var [{ x }] = [null, {}]; }, " is null");
|
||||
check_one("(intermediate value)['@@iterator'](...).next(...).value", function () { ieval("let (x) { var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
|
||||
var ITERATOR = JS_HAS_SYMBOLS ? "Symbol.iterator" : "'@@iterator'";
|
||||
check_one(`(intermediate value)[${ITERATOR}](...).next(...).value`,
|
||||
function () { var [{ x }] = [null, {}]; }, " is null");
|
||||
check_one(`(intermediate value)[${ITERATOR}](...).next(...).value`,
|
||||
function () { ieval("let (x) { var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
|
||||
|
||||
// Check fallback behavior
|
||||
assertThrowsInstanceOf(function () { for (let x of undefined) {} }, TypeError);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
load(libdir + "asserts.js");
|
||||
load(libdir + "iteration.js");
|
||||
|
||||
function testMethod(name) {
|
||||
var method = WeakSet.prototype[name];
|
||||
|
@ -15,7 +16,7 @@ testMethod("delete");
|
|||
testMethod("clear");
|
||||
|
||||
assertThrowsInstanceOf(function() { var ws = new WeakSet(); ws.add(1); }, TypeError);
|
||||
assertThrowsInstanceOf(function() { new WeakSet({"@@iterator": 2}) }, TypeError);
|
||||
assertEq(typeof []["@@iterator"], "function"); // Make sure we fail when @@iterator is removed
|
||||
assertThrowsInstanceOf(function() { new WeakSet({[std_iterator]: 2}) }, TypeError);
|
||||
assertEq(typeof [][std_iterator], "function");
|
||||
|
||||
assertThrowsInstanceOf(function() { WeakSet(); }, TypeError);
|
||||
|
|
|
@ -7,7 +7,8 @@ function test(constructor) {
|
|||
var proto = Object.getPrototypeOf(constructor()[std_iterator]());
|
||||
var names = Object.getOwnPropertyNames(proto);
|
||||
names.sort();
|
||||
assertDeepEq(names, [std_iterator, 'next']);
|
||||
assertDeepEq(names, JS_HAS_SYMBOLS ? ['next'] : ['@@iterator', 'next']);
|
||||
assertEq(proto.hasOwnProperty(std_iterator), true);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(proto, 'next');
|
||||
assertEq(desc.configurable, true);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
var arr = [1, 2, 3];
|
||||
var y = 0;
|
||||
for (var i = 0; i < 10; i++)
|
||||
for (var x of arr)
|
||||
y += x;
|
||||
assertEq(y, 60);
|
|
@ -8,6 +8,6 @@ load(libdir + "asserts.js");
|
|||
load(libdir + "iteration.js");
|
||||
|
||||
var g = newGlobal();
|
||||
g.eval("var it = [1, 2]['" + std_iterator + "']();");
|
||||
g.eval(`var it = [1, 2][${uneval(std_iterator)}]();`);
|
||||
assertIteratorNext(g.it, 1);
|
||||
assertThrowsInstanceOf([][std_iterator]().next.bind(g.it), TypeError)
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
load(libdir + "iteration.js");
|
||||
|
||||
var g = newGlobal();
|
||||
var it = g.eval("({ '" + std_iterator + "': function () { return this; }, " +
|
||||
"next: function () { return { done: true } } });");
|
||||
for (x of it)
|
||||
g.eval(`
|
||||
var obj = {};
|
||||
obj[${uneval(std_iterator)}] = function () { return this; };
|
||||
obj.next = function () { return { done: true }; };
|
||||
`);
|
||||
for (x of g.obj)
|
||||
throw 'FAIL';
|
||||
|
|
|
@ -57,7 +57,9 @@ var iterProto = Object.getPrototypeOf(iter);
|
|||
assertEq(Object.getPrototypeOf(iterProto), Object.prototype);
|
||||
|
||||
// Own properties for StringIterator.prototype: "next" and @@iterator
|
||||
arraysEqual(Object.getOwnPropertyNames(iterProto).sort(), ["next", std_iterator].sort());
|
||||
arraysEqual(Object.getOwnPropertyNames(iterProto).sort(),
|
||||
JS_HAS_SYMBOLS ? ["next"] : ["@@iterator", "next"]);
|
||||
assertEq(iterProto.hasOwnProperty(std_iterator), true);
|
||||
|
||||
// StringIterator.prototype[@@iterator] is a built-in function
|
||||
assertBuiltinFunction(iterProto, std_iterator, 0);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// |jit-test| error: ReferenceError
|
||||
function eq(e, a) {
|
||||
passed = (a == e);
|
||||
}
|
||||
function f(e, a) {
|
||||
fail();
|
||||
eq(e, a);
|
||||
}
|
||||
try {
|
||||
f();
|
||||
} catch (exc1) {}
|
||||
eq(.1, .1);
|
||||
var sym = Symbol("method");
|
||||
evaluate("f(test, sym, 0)", {compileAndGo: true});
|
|
@ -1259,6 +1259,15 @@ BaselineCompiler::emit_JSOP_STRING()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SYMBOL()
|
||||
{
|
||||
unsigned which = GET_UINT8(pc);
|
||||
JS::Symbol *sym = cx->runtime()->wellKnownSymbols->get(which);
|
||||
frame.push(SymbolValue(sym));
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef NativeObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleNativeObject, NewObjectKind);
|
||||
static const VMFunction DeepCloneObjectLiteralInfo =
|
||||
FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral);
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace jit {
|
|||
_(JSOP_UINT24) \
|
||||
_(JSOP_DOUBLE) \
|
||||
_(JSOP_STRING) \
|
||||
_(JSOP_SYMBOL) \
|
||||
_(JSOP_OBJECT) \
|
||||
_(JSOP_CALLSITEOBJ) \
|
||||
_(JSOP_REGEXP) \
|
||||
|
|
|
@ -3417,8 +3417,8 @@ IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, Shape *shape, bool i
|
|||
}
|
||||
|
||||
static bool
|
||||
IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape, bool *isScripted,
|
||||
bool isDOMProxy=false)
|
||||
IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape,
|
||||
bool *isScripted, bool *isTemporarilyUnoptimizable, bool isDOMProxy=false)
|
||||
{
|
||||
MOZ_ASSERT(isScripted);
|
||||
|
||||
|
@ -3439,8 +3439,10 @@ IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh
|
|||
#ifdef JSGC_GENERATIONAL
|
||||
// Information from get prop call ICs may be used directly from Ion code,
|
||||
// and should not be nursery allocated.
|
||||
if (IsInsideNursery(holder) || IsInsideNursery(func))
|
||||
if (IsInsideNursery(holder) || IsInsideNursery(func)) {
|
||||
*isTemporarilyUnoptimizable = true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (func->isNative()) {
|
||||
|
@ -3448,8 +3450,10 @@ IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!func->hasJITCode())
|
||||
if (!func->hasJITCode()) {
|
||||
*isTemporarilyUnoptimizable = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
*isScripted = true;
|
||||
return true;
|
||||
|
@ -3533,7 +3537,8 @@ IsCacheableSetPropAddSlot(JSContext *cx, HandleObject obj, HandleShape oldShape,
|
|||
}
|
||||
|
||||
static bool
|
||||
IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape, Shape* oldShape, bool *isScripted)
|
||||
IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape,
|
||||
Shape* oldShape, bool *isScripted, bool *isTemporarilyUnoptimizable)
|
||||
{
|
||||
MOZ_ASSERT(isScripted);
|
||||
|
||||
|
@ -3565,8 +3570,10 @@ IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh
|
|||
#ifdef JSGC_GENERATIONAL
|
||||
// Information from set prop call ICs may be used directly from Ion code,
|
||||
// and should not be nursery allocated.
|
||||
if (IsInsideNursery(holder) || IsInsideNursery(func))
|
||||
if (IsInsideNursery(holder) || IsInsideNursery(func)) {
|
||||
*isTemporarilyUnoptimizable = true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (func->isNative()) {
|
||||
|
@ -3574,8 +3581,10 @@ IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!func->hasJITCode())
|
||||
if (!func->hasJITCode()) {
|
||||
*isTemporarilyUnoptimizable = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
*isScripted = true;
|
||||
return true;
|
||||
|
@ -3817,7 +3826,9 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt
|
|||
}
|
||||
|
||||
bool getterIsScripted = false;
|
||||
if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted, /*isDOMProxy=*/false)) {
|
||||
bool isTemporarilyUnoptimizable = false;
|
||||
if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted,
|
||||
&isTemporarilyUnoptimizable, /*isDOMProxy=*/false)) {
|
||||
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
|
||||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
|
@ -4063,6 +4074,9 @@ DoGetElemFallback(JSContext *cx, BaselineFrame *frame, ICGetElem_Fallback *stub_
|
|||
if (!TryAttachGetElemStub(cx, frame->script(), pc, stub, lhs, rhs, res))
|
||||
return false;
|
||||
|
||||
// If we ever add a way to note unoptimizable accesses here, propagate the
|
||||
// isTemporarilyUnoptimizable state from TryAttachNativeGetElemStub to here.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5840,7 +5854,9 @@ TryAttachGlobalNameStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
|||
// changes we need to make sure IonBuilder::getPropTryCommonGetter (which
|
||||
// requires a Baseline stub) handles non-outerized this objects correctly.
|
||||
bool isScripted;
|
||||
if (IsCacheableGetPropCall(cx, global, current, shape, &isScripted) && !isScripted)
|
||||
bool isTemporarilyUnoptimizable = false;
|
||||
if (IsCacheableGetPropCall(cx, global, current, shape, &isScripted, &isTemporarilyUnoptimizable) &&
|
||||
!isScripted)
|
||||
{
|
||||
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
||||
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
|
||||
|
@ -6020,6 +6036,9 @@ DoGetNameFallback(JSContext *cx, BaselineFrame *frame, ICGetName_Fallback *stub_
|
|||
return false;
|
||||
}
|
||||
|
||||
// If we ever add a way to note unoptimizable accesses here, propagate the
|
||||
// isTemporarilyUnoptimizable state from TryAttachGlobalNameStub to here.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6396,9 +6415,11 @@ static bool
|
|||
TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
ICGetProp_Fallback *stub, HandlePropertyName name,
|
||||
HandleValue val, HandleShape oldShape,
|
||||
HandleValue res, bool *attached)
|
||||
HandleValue res, bool *attached,
|
||||
bool *isTemporarilyUnoptimizable)
|
||||
{
|
||||
MOZ_ASSERT(!*attached);
|
||||
MOZ_ASSERT(!*isTemporarilyUnoptimizable);
|
||||
|
||||
if (!val.isObject())
|
||||
return true;
|
||||
|
@ -6459,7 +6480,8 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
|||
}
|
||||
|
||||
bool isScripted = false;
|
||||
bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted, isDOMProxy);
|
||||
bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted,
|
||||
isTemporarilyUnoptimizable, isDOMProxy);
|
||||
|
||||
// Try handling scripted getters.
|
||||
if (cacheableCall && isScripted && !isDOMProxy) {
|
||||
|
@ -6766,6 +6788,11 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
|
|||
}
|
||||
|
||||
bool attached = false;
|
||||
// There are some reasons we can fail to attach a stub that are temporary.
|
||||
// We want to avoid calling noteUnoptimizableAccess() if the reason we
|
||||
// failed to attach a stub is one of those temporary reasons, since we might
|
||||
// end up attaching a stub for the exact same access later.
|
||||
bool isTemporarilyUnoptimizable = false;
|
||||
|
||||
if (op == JSOP_LENGTH) {
|
||||
if (!TryAttachLengthStub(cx, frame->script(), stub, val, res, &attached))
|
||||
|
@ -6782,7 +6809,7 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
|
|||
RootedScript script(cx, frame->script());
|
||||
|
||||
if (!TryAttachNativeGetPropStub(cx, script, pc, stub, name, val, oldShape,
|
||||
res, &attached))
|
||||
res, &attached, &isTemporarilyUnoptimizable))
|
||||
return false;
|
||||
if (attached)
|
||||
return true;
|
||||
|
@ -6803,7 +6830,8 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
|
|||
}
|
||||
|
||||
MOZ_ASSERT(!attached);
|
||||
stub->noteUnoptimizableAccess();
|
||||
if (!isTemporarilyUnoptimizable)
|
||||
stub->noteUnoptimizableAccess();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -7699,9 +7727,11 @@ BaselineScript::noteAccessedGetter(uint32_t pcOffset)
|
|||
static bool
|
||||
TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetProp_Fallback *stub,
|
||||
HandleObject obj, HandleShape oldShape, HandleTypeObject oldType, uint32_t oldSlots,
|
||||
HandlePropertyName name, HandleId id, HandleValue rhs, bool *attached)
|
||||
HandlePropertyName name, HandleId id, HandleValue rhs, bool *attached,
|
||||
bool *isTemporarilyUnoptimizable)
|
||||
{
|
||||
MOZ_ASSERT(!*attached);
|
||||
MOZ_ASSERT(!*isTemporarilyUnoptimizable);
|
||||
|
||||
if (!obj->isNative() || obj->watched())
|
||||
return true;
|
||||
|
@ -7780,7 +7810,8 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
|
|||
}
|
||||
|
||||
bool isScripted = false;
|
||||
bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape, oldShape, &isScripted);
|
||||
bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape, oldShape,
|
||||
&isScripted, isTemporarilyUnoptimizable);
|
||||
|
||||
// Try handling scripted setters.
|
||||
if (cacheableCall && isScripted) {
|
||||
|
@ -7906,8 +7937,13 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
|
|||
}
|
||||
|
||||
bool attached = false;
|
||||
// There are some reasons we can fail to attach a stub that are temporary.
|
||||
// We want to avoid calling noteUnoptimizableAccess() if the reason we
|
||||
// failed to attach a stub is one of those temporary reasons, since we might
|
||||
// end up attaching a stub for the exact same access later.
|
||||
bool isTemporarilyUnoptimizable = false;
|
||||
if (!TryAttachSetPropStub(cx, script, pc, stub, obj, oldShape, oldType, oldSlots,
|
||||
name, id, rhs, &attached))
|
||||
name, id, rhs, &attached, &isTemporarilyUnoptimizable))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -7915,7 +7951,8 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
|
|||
return true;
|
||||
|
||||
MOZ_ASSERT(!attached);
|
||||
stub->noteUnoptimizableAccess();
|
||||
if (!isTemporarilyUnoptimizable)
|
||||
stub->noteUnoptimizableAccess();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
#include "jsapi-tests/tests.h"
|
||||
|
||||
#ifdef JS_HAS_SYMBOLS
|
||||
#define IF_JS_HAS_SYMBOLS(x) x
|
||||
#define STD_ITERATOR "Symbol.iterator"
|
||||
#else
|
||||
#define IF_JS_HAS_SYMBOLS(x)
|
||||
#define STD_ITERATOR "'@@iterator'"
|
||||
#endif
|
||||
|
||||
BEGIN_TEST(testForOfIterator_basicNonIterable)
|
||||
|
@ -18,9 +18,7 @@ BEGIN_TEST(testForOfIterator_basicNonIterable)
|
|||
JS::RootedValue v(cx);
|
||||
// Hack to make it simple to produce an object that has a property
|
||||
// named Symbol.iterator.
|
||||
EVAL("var obj = {'@@iterator': 5"
|
||||
IF_JS_HAS_SYMBOLS(", [Symbol.iterator]: Array.prototype[Symbol.iterator]")
|
||||
"}; obj;", &v);
|
||||
EVAL("({[" STD_ITERATOR "]: 5})", &v);
|
||||
JS::ForOfIterator iter(cx);
|
||||
bool ok = iter.init(v);
|
||||
CHECK(!ok);
|
||||
|
@ -35,9 +33,7 @@ BEGIN_TEST(testForOfIterator_bug515273_part1)
|
|||
|
||||
// Hack to make it simple to produce an object that has a property
|
||||
// named Symbol.iterator.
|
||||
EVAL("var obj = {'@@iterator': 5"
|
||||
IF_JS_HAS_SYMBOLS(", [Symbol.iterator]: Array.prototype[Symbol.iterator]")
|
||||
"}; obj;", &v);
|
||||
EVAL("({[" STD_ITERATOR "]: 5})", &v);
|
||||
|
||||
JS::ForOfIterator iter(cx);
|
||||
bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable);
|
||||
|
|
|
@ -5592,7 +5592,7 @@ JS::GetSymbolCode(Handle<Symbol*> symbol)
|
|||
JS_PUBLIC_API(JS::Symbol *)
|
||||
JS::GetWellKnownSymbol(JSContext *cx, JS::SymbolCode which)
|
||||
{
|
||||
return cx->runtime()->wellKnownSymbols->get(uint32_t(which));
|
||||
return cx->wellKnownSymbols().get(uint32_t(which));
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
@ -2561,7 +2561,8 @@ struct JSFunctionSpec {
|
|||
*
|
||||
* The _SYM variants allow defining a function with a symbol key rather than a
|
||||
* string key. For example, use JS_SYM_FN(iterator, ...) to define an
|
||||
* @@iterator method.
|
||||
* @@iterator method. (In builds without ES6 symbols, it defines a method with
|
||||
* the string id "@@iterator".)
|
||||
*/
|
||||
#define JS_FS(name,call,nargs,flags) \
|
||||
JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr)
|
||||
|
@ -2575,10 +2576,17 @@ struct JSFunctionSpec {
|
|||
JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName)
|
||||
#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \
|
||||
JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName)
|
||||
|
||||
#ifdef JS_HAS_SYMBOLS
|
||||
#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
|
||||
JS_FNSPEC(reinterpret_cast<const char *>( \
|
||||
uint32_t(::JS::SymbolCode::symbol) + 1), \
|
||||
call, info, nargs, flags, selfHostedName)
|
||||
#else
|
||||
#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
|
||||
JS_FNSPEC("@@" #symbol, call, info, nargs, flags, selfHostedName)
|
||||
#endif
|
||||
|
||||
#define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \
|
||||
{name, {call, info}, nargs, flags, selfHostedName}
|
||||
|
||||
|
|
|
@ -3174,7 +3174,7 @@ static const JSFunctionSpec array_methods[] = {
|
|||
|
||||
JS_SELF_HOSTED_FN("fill", "ArrayFill", 3,0),
|
||||
|
||||
JS_SELF_HOSTED_FN("@@iterator", "ArrayValues", 0,0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0,0),
|
||||
JS_SELF_HOSTED_FN("entries", "ArrayEntries", 0,0),
|
||||
JS_SELF_HOSTED_FN("keys", "ArrayKeys", 0,0),
|
||||
JS_FS_END
|
||||
|
|
|
@ -156,7 +156,7 @@ JSRuntime::initializeAtoms(JSContext *cx)
|
|||
if (!wellKnownSymbols)
|
||||
return false;
|
||||
|
||||
ImmutablePropertyNamePtr *descriptions = &commonNames->Symbol_iterator;
|
||||
ImmutablePropertyNamePtr *descriptions = commonNames->wellKnownSymbolDescriptions();
|
||||
ImmutableSymbolPtr *symbols = reinterpret_cast<ImmutableSymbolPtr *>(wellKnownSymbols);
|
||||
for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
|
||||
JS::Symbol *symbol = JS::Symbol::new_(cx, JS::SymbolCode(i), descriptions[i]);
|
||||
|
|
|
@ -886,7 +886,7 @@ iterator_next(JSContext *cx, unsigned argc, Value *vp)
|
|||
}
|
||||
|
||||
static const JSFunctionSpec iterator_methods[] = {
|
||||
JS_SELF_HOSTED_FN("@@iterator", "LegacyIteratorShim", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "LegacyIteratorShim", 0, 0),
|
||||
JS_FN("next", iterator_next, 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
@ -965,7 +965,7 @@ const Class ArrayIteratorObject::class_ = {
|
|||
};
|
||||
|
||||
static const JSFunctionSpec array_iterator_methods[] = {
|
||||
JS_SELF_HOSTED_FN("@@iterator", "ArrayIteratorIdentity", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "ArrayIteratorIdentity", 0, 0),
|
||||
JS_SELF_HOSTED_FN("next", "ArrayIteratorNext", 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
@ -1004,7 +1004,7 @@ const Class StringIteratorObject::class_ = {
|
|||
};
|
||||
|
||||
static const JSFunctionSpec string_iterator_methods[] = {
|
||||
JS_SELF_HOSTED_FN("@@iterator", "StringIteratorIdentity", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "StringIteratorIdentity", 0, 0),
|
||||
JS_SELF_HOSTED_FN("next", "StringIteratorNext", 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
@ -1369,8 +1369,14 @@ ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavio
|
|||
args.setThis(ObjectValue(*iterableObj));
|
||||
|
||||
RootedValue callee(cx);
|
||||
#ifdef JS_HAS_SYMBOLS
|
||||
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
|
||||
if (!JSObject::getGeneric(cx, iterableObj, iterableObj, iteratorId, &callee))
|
||||
return false;
|
||||
#else
|
||||
if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// If obj[@@iterator] is undefined and we were asked to allow non-iterables,
|
||||
// bail out now without setting iterator. This will make valueIsIterable(),
|
||||
|
|
|
@ -1592,6 +1592,13 @@ ExpressionDecompiler::decompilePC(jsbytecode *pc)
|
|||
return sprinter.printf("%d", GetBytecodeInteger(pc)) >= 0;
|
||||
case JSOP_STRING:
|
||||
return quote(loadAtom(pc), '"');
|
||||
case JSOP_SYMBOL: {
|
||||
unsigned i = uint8_t(pc[1]);
|
||||
MOZ_ASSERT(i < JS::WellKnownSymbolLimit);
|
||||
if (i < JS::WellKnownSymbolLimit)
|
||||
return write(cx->names().wellKnownSymbolDescriptions()[i]);
|
||||
break;
|
||||
}
|
||||
case JSOP_UNDEFINED:
|
||||
return write(js_undefined_str);
|
||||
case JSOP_THIS:
|
||||
|
|
|
@ -4204,7 +4204,7 @@ static const JSFunctionSpec string_methods[] = {
|
|||
JS_SELF_HOSTED_FN("fontcolor","String_fontcolor", 1,0),
|
||||
JS_SELF_HOSTED_FN("fontsize", "String_fontsize", 1,0),
|
||||
|
||||
JS_SELF_HOSTED_FN("@@iterator", "String_iterator", 0,0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "String_iterator", 0,0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ function TestChangeArrayIteratorNext() {
|
|||
return M2;
|
||||
}
|
||||
|
||||
var iter = ([])['@@iterator']();
|
||||
var iter = ([])[std_iterator]();
|
||||
var iterProto = Object.getPrototypeOf(iter);
|
||||
var OldNext = iterProto.next;
|
||||
var NewNext = function () {
|
||||
|
|
|
@ -27,7 +27,7 @@ function TestIncreaseArrayLength() {
|
|||
return M2;
|
||||
}
|
||||
|
||||
var iter = ([])['@@iterator']();
|
||||
var iter = ([])[std_iterator]();
|
||||
var iterProto = Object.getPrototypeOf(iter);
|
||||
var OldNext = iterProto.next;
|
||||
var NewNext = function () {
|
||||
|
|
|
@ -26,7 +26,7 @@ function TestDecreaseArrayLength() {
|
|||
return M2;
|
||||
}
|
||||
|
||||
var iter = ([])['@@iterator']();
|
||||
var iter = ([])[std_iterator]();
|
||||
var iterProto = Object.getPrototypeOf(iter);
|
||||
var OldNext = iterProto.next;
|
||||
var NewNext = function () {
|
||||
|
|
|
@ -134,8 +134,8 @@ assertEq(obj instanceof C, true);
|
|||
for (var primitive of [undefined, null, 17]) {
|
||||
assertThrowsInstanceOf(
|
||||
() => Array.from({
|
||||
"@@iterator": () => {
|
||||
next: () => primitive
|
||||
[std_iterator]() {
|
||||
return {next() { return primitive; }};
|
||||
}
|
||||
}),
|
||||
TypeError);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
// If an object has both .length and [@@iterator] properties, [@@iterator] is used.
|
||||
var a = ['a', 'e', 'i', 'o', 'u'];
|
||||
a["@@iterator"] = function* () {
|
||||
a[std_iterator] = function* () {
|
||||
for (var i = 5; i--; )
|
||||
yield this[i];
|
||||
};
|
||||
|
|
|
@ -6,19 +6,19 @@ var log = [];
|
|||
function LoggingProxy(target) {
|
||||
var h = {
|
||||
defineProperty: function (t, id) {
|
||||
log.push("define " + id);
|
||||
log.push("define", id);
|
||||
return undefined;
|
||||
},
|
||||
has: function (t, id) {
|
||||
log.push("has " + id);
|
||||
log.push("has", id);
|
||||
return id in t;
|
||||
},
|
||||
get: function (t, id) {
|
||||
log.push("get " + id);
|
||||
log.push("get", id);
|
||||
return t[id];
|
||||
},
|
||||
set: function (t, id, v) {
|
||||
log.push("set " + id);
|
||||
log.push("set", id);
|
||||
t[id] = v;
|
||||
}
|
||||
};
|
||||
|
@ -30,23 +30,25 @@ function LoggingProxy(target) {
|
|||
// but handler.set to set the length.
|
||||
LoggingProxy.from = Array.from;
|
||||
LoggingProxy.from([3, 4, 5]);
|
||||
assertDeepEq(log, ["define 0", "define 1", "define 2", "set length"]);
|
||||
assertDeepEq(log, ["define", "0", "define", "1", "define", "2", "set", "length"]);
|
||||
|
||||
// When the argument passed to Array.from is a Proxy, Array.from
|
||||
// calls handler.get on it.
|
||||
log = [];
|
||||
assertDeepEq(Array.from(new LoggingProxy([3, 4, 5])), [3, 4, 5]);
|
||||
assertDeepEq(log, ["get @@iterator",
|
||||
"get length", "get 0", "get length", "get 1", "get length", "get 2",
|
||||
"get length"]);
|
||||
assertDeepEq(log, ["get", std_iterator,
|
||||
"get", "length", "get", "0",
|
||||
"get", "length", "get", "1",
|
||||
"get", "length", "get", "2",
|
||||
"get", "length"]);
|
||||
|
||||
// Array-like iteration only gets the length once.
|
||||
log = [];
|
||||
var arr = [5, 6, 7];
|
||||
arr["@@iterator"] = undefined;
|
||||
arr[std_iterator] = undefined;
|
||||
assertDeepEq(Array.from(new LoggingProxy(arr)), [5, 6, 7]);
|
||||
assertDeepEq(log, ["get @@iterator",
|
||||
"get length", "get 0", "get 1", "get 2"]);
|
||||
assertDeepEq(log, ["get", std_iterator,
|
||||
"get", "length", "get", "0", "get", "1", "get", "2"]);
|
||||
|
||||
if (typeof reportCompare === 'function')
|
||||
reportCompare(0, 0);
|
||||
|
|
|
@ -11,11 +11,11 @@ assertDeepEq(Array.from(gclef), [gclef]);
|
|||
assertDeepEq(Array.from(gclef + " G"), [gclef, " ", "G"]);
|
||||
|
||||
// Array.from on a string calls the @@iterator method.
|
||||
String.prototype["@@iterator"] = function* () { yield 1; yield 2; };
|
||||
String.prototype[std_iterator] = function* () { yield 1; yield 2; };
|
||||
assertDeepEq(Array.from("anything"), [1, 2]);
|
||||
|
||||
// If the iterator method is deleted, Strings are still arraylike.
|
||||
delete String.prototype["@@iterator"];
|
||||
delete String.prototype[std_iterator];
|
||||
assertDeepEq(Array.from("works"), ['w', 'o', 'r', 'k', 's']);
|
||||
assertDeepEq(Array.from(gclef), ['\uD834', '\uDD1E']);
|
||||
|
||||
|
|
|
@ -17,8 +17,6 @@ function* g() { yield 1; }
|
|||
var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
|
||||
var GeneratorFunction = GeneratorFunctionPrototype.constructor;
|
||||
var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
|
||||
// FIXME: This should be a symbol.
|
||||
var std_iterator = "@@iterator";
|
||||
|
||||
|
||||
// A generator function should have the same set of properties as any
|
||||
|
@ -66,7 +64,9 @@ function TestGeneratorObjectPrototype() {
|
|||
assertEq(Object.getPrototypeOf((function*(){yield 1}).prototype),
|
||||
GeneratorObjectPrototype);
|
||||
|
||||
var expected_property_names = ["next", "throw", "constructor", std_iterator];
|
||||
var expected_property_names = ["next", "throw", "constructor"];
|
||||
if (!JS_HAS_SYMBOLS)
|
||||
expected_property_names.push(std_iterator);
|
||||
var found_property_names =
|
||||
Object.getOwnPropertyNames(GeneratorObjectPrototype);
|
||||
|
||||
|
|
|
@ -66,10 +66,8 @@ if (typeof Symbol === "function") {
|
|||
assertEq(descs.hasOwnProperty(s1), true);
|
||||
assertEq(descs.hasOwnProperty(s2), true);
|
||||
assertEq(descs.hasOwnProperty(s3), false);
|
||||
assertEq([].hasOwnProperty(Symbol.iterator), false);
|
||||
if (!("@@iterator" in []))
|
||||
throw new Error("Congratulations on implementing Symbol.iterator! Please update this test.");
|
||||
assertEq(Array.prototype.hasOwnProperty(Symbol.iterator), false); // should be true
|
||||
assertEq([].hasOwnProperty(std_iterator), false);
|
||||
assertEq(Array.prototype.hasOwnProperty(std_iterator), true);
|
||||
|
||||
// Object.prototype.propertyIsEnumerable
|
||||
assertEq(n.propertyIsEnumerable(s1), true);
|
||||
|
|
|
@ -26,7 +26,8 @@ function test()
|
|||
var [a, b, [c0, c1]] = [x, x, x];
|
||||
}
|
||||
|
||||
expect = 'TypeError: (intermediate value)[\'@@iterator\'](...).next(...).value is null';
|
||||
var ITERATOR = JS_HAS_SYMBOLS ? "Symbol.iterator" : "'@@iterator'";
|
||||
expect = `TypeError: (intermediate value)[${ITERATOR}](...).next(...).value is null`;
|
||||
actual = 'No Error';
|
||||
try
|
||||
{
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// The decompiler can handle the implicit call to @@iterator in a for-of loop.
|
||||
|
||||
var x;
|
||||
function check(code) {
|
||||
var s = "no exception thrown";
|
||||
try {
|
||||
eval(code);
|
||||
} catch (exc) {
|
||||
s = exc.message;
|
||||
}
|
||||
|
||||
var ITERATOR = JS_HAS_SYMBOLS ? "Symbol.iterator" : "'@@iterator'";
|
||||
assertEq(s, `x[${ITERATOR}] is not a function`);
|
||||
}
|
||||
|
||||
x = {};
|
||||
check("for (var v of x) throw fit;");
|
||||
check("[...x]");
|
||||
check("Math.hypot(...x)");
|
||||
|
||||
x[std_iterator] = "potato";
|
||||
check("for (var v of x) throw fit;");
|
||||
|
||||
x[std_iterator] = {};
|
||||
check("for (var v of x) throw fit;");
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0, "ok");
|
|
@ -876,3 +876,6 @@ function OptLevel( i ) {
|
|||
cx.setOptimizationLevel(i);
|
||||
}
|
||||
/* end of Rhino functions */
|
||||
|
||||
var JS_HAS_SYMBOLS = typeof Symbol === "function";
|
||||
var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
||||
|
|
|
@ -247,7 +247,7 @@ const Class StarGeneratorObject::class_ = {
|
|||
};
|
||||
|
||||
static const JSFunctionSpec star_generator_methods[] = {
|
||||
JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
|
||||
JS_SELF_HOSTED_FN("next", "StarGeneratorNext", 1, 0),
|
||||
JS_SELF_HOSTED_FN("throw", "StarGeneratorThrow", 1, 0),
|
||||
JS_FS_END
|
||||
|
@ -256,7 +256,7 @@ static const JSFunctionSpec star_generator_methods[] = {
|
|||
#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT)
|
||||
|
||||
static const JSFunctionSpec legacy_generator_methods[] = {
|
||||
JS_SELF_HOSTED_FN("@@iterator", "LegacyGeneratorIteratorShim", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "LegacyGeneratorIteratorShim", 0, 0),
|
||||
// "send" is an alias for "next".
|
||||
JS_SELF_HOSTED_FN("next", "LegacyGeneratorNext", 1, JSPROP_ROPERM),
|
||||
JS_SELF_HOSTED_FN("send", "LegacyGeneratorNext", 1, JSPROP_ROPERM),
|
||||
|
|
|
@ -324,7 +324,7 @@ InitBareBuiltinCtor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey prot
|
|||
GlobalObject::initSelfHostingBuiltins(JSContext *cx, Handle<GlobalObject*> global,
|
||||
const JSFunctionSpec *builtins)
|
||||
{
|
||||
/* Define a top-level property 'undefined' with the undefined value. */
|
||||
// Define a top-level property 'undefined' with the undefined value.
|
||||
if (!JSObject::defineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY))
|
||||
|
@ -332,6 +332,20 @@ GlobalObject::initSelfHostingBuiltins(JSContext *cx, Handle<GlobalObject*> globa
|
|||
return false;
|
||||
}
|
||||
|
||||
// Define a top-level property 'std_iterator' with the name of the method
|
||||
// used by for-of loops to create an iterator.
|
||||
RootedValue std_iterator(cx);
|
||||
#ifdef JS_HAS_SYMBOLS
|
||||
std_iterator.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::iterator));
|
||||
#else
|
||||
std_iterator.setString(cx->names().std_iterator);
|
||||
#endif
|
||||
if (!JS_DefineProperty(cx, global, "std_iterator", std_iterator,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
|
||||
InitBareBuiltinCtor(cx, global, JSProto_TypedArray) &&
|
||||
InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) &&
|
||||
|
|
|
@ -1124,6 +1124,7 @@ HandleError(JSContext *cx, InterpreterRegs ®s)
|
|||
#define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b)
|
||||
#define PUSH_DOUBLE(d) REGS.sp++->setDouble(d)
|
||||
#define PUSH_INT32(i) REGS.sp++->setInt32(i)
|
||||
#define PUSH_SYMBOL(s) REGS.sp++->setSymbol(s)
|
||||
#define PUSH_STRING(s) do { REGS.sp++->setString(s); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
|
||||
#define PUSH_OBJECT(obj) do { REGS.sp++->setObject(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
|
||||
#define PUSH_OBJECT_OR_NULL(obj) do { REGS.sp++->setObjectOrNull(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
|
||||
|
@ -1601,7 +1602,6 @@ CASE(EnableInterruptsPseudoOpcode)
|
|||
/* Various 1-byte no-ops. */
|
||||
CASE(JSOP_NOP)
|
||||
CASE(JSOP_UNUSED2)
|
||||
CASE(JSOP_UNUSED45)
|
||||
CASE(JSOP_UNUSED46)
|
||||
CASE(JSOP_UNUSED47)
|
||||
CASE(JSOP_UNUSED48)
|
||||
|
@ -2706,6 +2706,10 @@ CASE(JSOP_TOSTRING)
|
|||
}
|
||||
END_CASE(JSOP_TOSTRING)
|
||||
|
||||
CASE(JSOP_SYMBOL)
|
||||
PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
|
||||
END_CASE(JSOP_SYMBOL)
|
||||
|
||||
CASE(JSOP_OBJECT)
|
||||
{
|
||||
RootedNativeObject &ref = rootNativeObject0;
|
||||
|
|
|
@ -416,7 +416,15 @@
|
|||
*/ \
|
||||
macro(JSOP_DUPAT, 44, "dupat", NULL, 4, 0, 1, JOF_UINT24) \
|
||||
\
|
||||
macro(JSOP_UNUSED45, 45, "unused45", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
/*
|
||||
* Push a well-known symbol onto the operand stack.
|
||||
* Category: Literals
|
||||
* Type: Constants
|
||||
* Operands: uint8_t n, the JS::SymbolCode of the symbol to use
|
||||
* Stack: => symbol
|
||||
*/ \
|
||||
macro(JSOP_SYMBOL, 45, "symbol", NULL, 2, 0, 1, JOF_UINT8) \
|
||||
\
|
||||
macro(JSOP_UNUSED46, 46, "unused46", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED47, 47, "unused47", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED48, 48, "unused48", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
#ifdef JS_HAS_SYMBOLS
|
||||
#define STD_ITERATOR_ID SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)
|
||||
#else
|
||||
#define STD_ITERATOR_ID ::js::NameToId(cx->names().std_iterator)
|
||||
#endif
|
||||
|
||||
bool
|
||||
js::ForOfPIC::Chain::initialize(JSContext *cx)
|
||||
{
|
||||
|
@ -44,8 +50,8 @@ js::ForOfPIC::Chain::initialize(JSContext *cx)
|
|||
// do set disabled_ now, and clear it later when we succeed.
|
||||
disabled_ = true;
|
||||
|
||||
// Look up '@@iterator' on Array.prototype, ensure it's a slotful shape.
|
||||
Shape *iterShape = arrayProto->lookup(cx, cx->names().std_iterator);
|
||||
// Look up Array.prototype[@@iterator], ensure it's a slotful shape.
|
||||
Shape *iterShape = arrayProto->lookup(cx, STD_ITERATOR_ID);
|
||||
if (!iterShape || !iterShape->hasSlot() || !iterShape->hasDefaultGetter())
|
||||
return true;
|
||||
|
||||
|
@ -143,8 +149,8 @@ js::ForOfPIC::Chain::tryOptimizeArray(JSContext *cx, HandleArrayObject array, bo
|
|||
if (!isOptimizableArray(array))
|
||||
return true;
|
||||
|
||||
// Ensure array doesn't define '@@iterator' directly.
|
||||
if (array->lookup(cx, cx->names().std_iterator))
|
||||
// Ensure array doesn't define @@iterator directly.
|
||||
if (array->lookup(cx, STD_ITERATOR_ID))
|
||||
return true;
|
||||
|
||||
// Good to optimize now, create stub to add.
|
||||
|
@ -197,7 +203,7 @@ js::ForOfPIC::Chain::isArrayStateStillSane()
|
|||
if (arrayProto_->lastProperty() != arrayProtoShape_)
|
||||
return false;
|
||||
|
||||
// Ensure that Array.prototype['@@iterator'] contains the
|
||||
// Ensure that Array.prototype[@@iterator] contains the
|
||||
// canonical iterator function.
|
||||
if (arrayProto_->getSlot(arrayProtoIteratorSlot_) != canonicalIteratorFunc_)
|
||||
return false;
|
||||
|
|
|
@ -130,7 +130,7 @@ struct ForOfPIC
|
|||
|
||||
/*
|
||||
* A ForOfPIC has only one kind of stub for now: one that holds the shape
|
||||
* of an array object that does not override its '@@iterator' property.
|
||||
* of an array object that does not override its @@iterator property.
|
||||
*/
|
||||
class Stub : public BaseStub
|
||||
{
|
||||
|
@ -164,8 +164,8 @@ struct ForOfPIC
|
|||
* ArrayIterator.prototype's shape (arrayIteratorProtoShape_)
|
||||
* To ensure that an ArrayIterator.prototype has not been modified.
|
||||
*
|
||||
* Array.prototype's slot number for '@@iterator' (arrayProtoIteratorSlot_)
|
||||
* Array.prototype's canonical value for '@@iterator' (canonicalIteratorFunc_)
|
||||
* Array.prototype's slot number for @@iterator (arrayProtoIteratorSlot_)
|
||||
* Array.prototype's canonical value for @@iterator (canonicalIteratorFunc_)
|
||||
* To quickly retreive and ensure that the iterator constructor
|
||||
* stored in the slot has not changed.
|
||||
*
|
||||
|
@ -182,7 +182,7 @@ struct ForOfPIC
|
|||
HeapPtrNativeObject arrayIteratorProto_;
|
||||
|
||||
// Shape of matching Array.prototype object, and slot containing
|
||||
// the '@@iterator' for it, and the canonical value.
|
||||
// the @@iterator for it, and the canonical value.
|
||||
HeapPtrShape arrayProtoShape_;
|
||||
uint32_t arrayProtoIteratorSlot_;
|
||||
HeapValue canonicalIteratorFunc_;
|
||||
|
|
|
@ -406,6 +406,10 @@ struct JSAtomState
|
|||
#define PROPERTYNAME_FIELD(name, code, init, clasp) js::ImmutablePropertyNamePtr name;
|
||||
JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD)
|
||||
#undef PROPERTYNAME_FIELD
|
||||
|
||||
js::ImmutablePropertyNamePtr *wellKnownSymbolDescriptions() {
|
||||
return &Symbol_iterator;
|
||||
}
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
|
|
@ -1501,6 +1501,12 @@ CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp)
|
|||
if (!clone)
|
||||
return false;
|
||||
vp.setString(clone);
|
||||
} else if (selfHostedValue.isSymbol()) {
|
||||
// Well-known symbols are shared.
|
||||
JS::Symbol *sym = selfHostedValue.toSymbol();
|
||||
MOZ_ASSERT(sym->isWellKnownSymbol());
|
||||
MOZ_ASSERT(cx->wellKnownSymbols().get(size_t(sym->code())) == sym);
|
||||
vp.set(selfHostedValue);
|
||||
} else {
|
||||
MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
|
||||
}
|
||||
|
|
|
@ -760,7 +760,7 @@ TypedArrayObject::subarray(JSContext *cx, unsigned argc, Value *vp)
|
|||
|
||||
/* static */ const JSFunctionSpec
|
||||
TypedArrayObject::protoFunctions[] = {
|
||||
JS_SELF_HOSTED_FN("@@iterator", "ArrayValues", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0, 0), \
|
||||
JS_FN("subarray", TypedArrayObject::subarray, 2, 0),
|
||||
JS_FN("set", TypedArrayObject::set, 2, 0),
|
||||
JS_FN("copyWithin", TypedArrayObject::copyWithin, 2, 0),
|
||||
|
|
|
@ -27,8 +27,21 @@ namespace js {
|
|||
* this wiki page:
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*
|
||||
* === GREETINGS, FELLOW SUBTRAHEND INCREMENTER! ===
|
||||
* For the time being, please increment the subtrahend by 2 each time it
|
||||
* changes, because we have two flavors of bytecode: with JSOP_SYMBOL (in
|
||||
* Nightly) and without (all others). FIXME: Bug 1066322 - Enable ES6 symbols
|
||||
* in all builds.
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 188);
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 190;
|
||||
static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above");
|
||||
static const uint32_t XDR_BYTECODE_VERSION =
|
||||
uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND
|
||||
#ifdef JS_HAS_SYMBOLS
|
||||
+ 1
|
||||
#endif
|
||||
));
|
||||
|
||||
class XDRBuffer {
|
||||
public:
|
||||
|
|
|
@ -146,6 +146,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||
var isNightlyBuild = version.endsWith("a1");
|
||||
var isReleaseBuild = !version.contains("a");
|
||||
const jsHasSymbols = typeof Symbol === "function";
|
||||
const kIteratorSymbol = jsHasSymbols ? Symbol.iterator : "@@iterator";
|
||||
var gPrototypeProperties = {};
|
||||
gPrototypeProperties['Date'] =
|
||||
["getTime", "getTimezoneOffset", "getYear", "getFullYear", "getUTCFullYear",
|
||||
|
@ -168,7 +169,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||
["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
|
||||
"pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
|
||||
"forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
|
||||
"findIndex", "copyWithin", "fill", "@@iterator", "entries", "keys", "constructor"];
|
||||
"findIndex", "copyWithin", "fill", kIteratorSymbol, "entries", "keys", "constructor"];
|
||||
if (isNightlyBuild) {
|
||||
let pjsMethods = ['mapPar', 'reducePar', 'scanPar', 'scatterPar', 'filterPar'];
|
||||
gPrototypeProperties['Array'] = gPrototypeProperties['Array'].concat(pjsMethods);
|
||||
|
@ -177,7 +178,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||
gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT"];
|
||||
}
|
||||
gPrototypeProperties['TypedArray'] =
|
||||
["length", "buffer", "byteLength", "byteOffset", "@@iterator", "subarray",
|
||||
["length", "buffer", "byteLength", "byteOffset", kIteratorSymbol, "subarray",
|
||||
"set", "copyWithin"];
|
||||
|
||||
for (var c of errorObjectClasses) {
|
||||
|
@ -500,10 +501,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||
|
||||
var typedArrayProto = Object.getPrototypeOf(Int8Array.prototype);
|
||||
|
||||
gPrototypeProperties['TypedArray'] =
|
||||
["length", "buffer", "byteLength", "byteOffset", "@@iterator", "subarray",
|
||||
"set", "copyWithin"];
|
||||
|
||||
var desiredInheritedProps = Object.getOwnPropertyNames(typedArrayProto).sort();
|
||||
var inheritedProps =
|
||||
filterOut(desiredInheritedProps, ["BYTES_PER_ELEMENT", "constructor"]);
|
||||
|
|
|
@ -252,24 +252,14 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
|
|||
PR_INIT_CLIST(&mDOMMediaQueryLists);
|
||||
}
|
||||
|
||||
nsPresContext::~nsPresContext()
|
||||
void
|
||||
nsPresContext::Destroy()
|
||||
{
|
||||
NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
|
||||
SetShell(nullptr);
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
|
||||
"must not have media query lists left");
|
||||
|
||||
// Disconnect the refresh driver *after* the transition manager, which
|
||||
// needs it.
|
||||
if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
|
||||
mRefreshDriver->Disconnect();
|
||||
}
|
||||
|
||||
if (mEventManager) {
|
||||
// unclear if these are needed, but can't hurt
|
||||
mEventManager->NotifyDestroyPresContext(this);
|
||||
mEventManager->SetPresContext(nullptr);
|
||||
mEventManager = nullptr;
|
||||
}
|
||||
|
||||
if (mPrefChangedTimer)
|
||||
|
@ -321,6 +311,24 @@ nsPresContext::~nsPresContext()
|
|||
Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
|
||||
"nglayout.debug.paint_flashing_chrome",
|
||||
this);
|
||||
|
||||
// Disconnect the refresh driver *after* the transition manager, which
|
||||
// needs it.
|
||||
if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
|
||||
mRefreshDriver->Disconnect();
|
||||
mRefreshDriver = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsPresContext::~nsPresContext()
|
||||
{
|
||||
NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
|
||||
SetShell(nullptr);
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
|
||||
"must not have media query lists left");
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
|
||||
|
@ -368,13 +376,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext); // worth bothering?
|
||||
if (tmp->mEventManager) {
|
||||
// unclear if these are needed, but can't hurt
|
||||
tmp->mEventManager->NotifyDestroyPresContext(tmp);
|
||||
tmp->mEventManager->SetPresContext(nullptr);
|
||||
tmp->mEventManager = nullptr;
|
||||
}
|
||||
|
||||
// We own only the items in mDOMMediaQueryLists that have listeners;
|
||||
// this reference is managed by their AddListener and RemoveListener
|
||||
// methods.
|
||||
|
@ -387,15 +388,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
|
|||
}
|
||||
|
||||
// NS_RELEASE(tmp->mLanguage); // an atom
|
||||
|
||||
// NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
|
||||
// NS_IMPL_CYCLE_COLLECTION_UNLINK(mLangService); // a service
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
|
||||
if (tmp->mPrefChangedTimer)
|
||||
{
|
||||
tmp->mPrefChangedTimer->Cancel();
|
||||
tmp->mPrefChangedTimer = nullptr;
|
||||
}
|
||||
|
||||
tmp->Destroy();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
||||
|
|
|
@ -1172,6 +1172,9 @@ public:
|
|||
#endif
|
||||
|
||||
protected:
|
||||
// May be called multiple times (unlink, destructor)
|
||||
void Destroy();
|
||||
|
||||
void InvalidatePaintedLayers();
|
||||
void AppUnitsPerDevPixelChanged();
|
||||
|
||||
|
|
|
@ -2956,11 +2956,11 @@ PropertyProvider::ComputeJustifiableCharacters(int32_t aOffset, int32_t aLength)
|
|||
run(mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aLength);
|
||||
run.SetOriginalOffset(aOffset);
|
||||
uint32_t justifiableChars = 0;
|
||||
bool isCJK = IsChineseOrJapanese(mFrame);
|
||||
bool isCJ = IsChineseOrJapanese(mFrame);
|
||||
while (run.NextRun()) {
|
||||
for (int32_t i = 0; i < run.GetRunLength(); ++i) {
|
||||
justifiableChars +=
|
||||
IsJustifiableCharacter(mFrag, run.GetOriginalOffset() + i, isCJK);
|
||||
IsJustifiableCharacter(mFrag, run.GetOriginalOffset() + i, isCJ);
|
||||
}
|
||||
}
|
||||
return justifiableChars;
|
||||
|
@ -3083,7 +3083,7 @@ PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength,
|
|||
gfxFloat halfJustificationSpace = mJustificationSpacing/2;
|
||||
// Scan non-skipped characters and adjust justifiable chars, adding
|
||||
// justification space on either side of the cluster
|
||||
bool isCJK = IsChineseOrJapanese(mFrame);
|
||||
bool isCJ = IsChineseOrJapanese(mFrame);
|
||||
gfxSkipCharsIterator justificationStart(mStart), justificationEnd(mStart);
|
||||
FindJustificationRange(&justificationStart, &justificationEnd);
|
||||
|
||||
|
@ -3094,7 +3094,7 @@ PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength,
|
|||
int32_t runOriginalOffset = run.GetOriginalOffset();
|
||||
for (int32_t i = 0; i < run.GetRunLength(); ++i) {
|
||||
int32_t iterOriginalOffset = runOriginalOffset + i;
|
||||
if (IsJustifiableCharacter(mFrag, iterOriginalOffset, isCJK)) {
|
||||
if (IsJustifiableCharacter(mFrag, iterOriginalOffset, isCJ)) {
|
||||
iter.SetOriginalOffset(iterOriginalOffset);
|
||||
FindClusterStart(mTextRun, runOriginalOffset, &iter);
|
||||
uint32_t clusterFirstChar = iter.GetSkippedOffset();
|
||||
|
@ -8478,13 +8478,13 @@ nsTextFrame::TrimTrailingWhiteSpace(nsRenderingContext* aRC)
|
|||
// Check if any character in the last cluster is justifiable
|
||||
PropertyProvider provider(mTextRun, textStyle, frag, this, start, contentLength,
|
||||
nullptr, 0, nsTextFrame::eInflated);
|
||||
bool isCJK = IsChineseOrJapanese(this);
|
||||
bool isCJ = IsChineseOrJapanese(this);
|
||||
gfxSkipCharsIterator justificationStart(start), justificationEnd(trimmedEndIter);
|
||||
provider.FindJustificationRange(&justificationStart, &justificationEnd);
|
||||
|
||||
for (int32_t i = justificationEnd.GetOriginalOffset();
|
||||
i < trimmed.GetEnd(); ++i) {
|
||||
if (IsJustifiableCharacter(frag, i, isCJK)) {
|
||||
if (IsJustifiableCharacter(frag, i, isCJ)) {
|
||||
result.mLastCharIsJustifiable = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,5 +148,5 @@ fuzzy-if(d2d,47,400) == linear-onestopposition-1.html linear-onestopposition-1-r
|
|||
== bug-916535-background-repeat-linear.html bug-916535-background-repeat-linear-ref.html
|
||||
fuzzy(1,800000) == large-gradient-1.html large-gradient-1-ref.html
|
||||
== large-gradient-2.html large-gradient-2-ref.html
|
||||
fuzzy(1,800000) == large-gradient-3.html large-gradient-3-ref.html
|
||||
== large-gradient-4.html large-gradient-4-ref.html
|
||||
fails-if(browserIsRemote&&!B2G) fuzzy(1,800000) == large-gradient-3.html large-gradient-3-ref.html
|
||||
fails-if(browserIsRemote&&!B2G) == large-gradient-4.html large-gradient-4-ref.html
|
||||
|
|
|
@ -248,10 +248,10 @@ include outline/reftest.list
|
|||
include object/reftest.list
|
||||
|
||||
# ogg-video/
|
||||
include ogg-video/reftest.list
|
||||
skip-if(!B2G&&browserIsRemote) include ogg-video/reftest.list
|
||||
|
||||
# webm-video/
|
||||
include webm-video/reftest.list
|
||||
skip-if(!B2G&&browserIsRemote) include webm-video/reftest.list
|
||||
|
||||
# parser/
|
||||
include ../../parser/htmlparser/tests/reftest/reftest.list
|
||||
|
|
|
@ -37,6 +37,7 @@ generated-files = css_properties.js
|
|||
[test_animations.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_animations_omta.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_animations_omta_start.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1041017
|
||||
[test_animations_pausing.html]
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace net {
|
|||
* @see nsICookiePermission
|
||||
*/
|
||||
|
||||
sync protocol PCookieService
|
||||
prio(normal upto urgent) sync protocol PCookieService
|
||||
{
|
||||
manager PNecko;
|
||||
|
||||
|
@ -60,10 +60,10 @@ parent:
|
|||
*
|
||||
* @return the resulting cookie string.
|
||||
*/
|
||||
sync GetCookieString(URIParams host,
|
||||
bool isForeign,
|
||||
bool fromHttp,
|
||||
SerializedLoadContext loadContext)
|
||||
prio(urgent) sync GetCookieString(URIParams host,
|
||||
bool isForeign,
|
||||
bool fromHttp,
|
||||
SerializedLoadContext loadContext)
|
||||
returns (nsCString result);
|
||||
|
||||
/*
|
||||
|
@ -95,12 +95,12 @@ parent:
|
|||
* @see nsICookieService.setCookieStringFromHttp
|
||||
* @see mozIThirdPartyUtil.isThirdPartyChannel
|
||||
*/
|
||||
SetCookieString(URIParams host,
|
||||
bool isForeign,
|
||||
nsCString cookieString,
|
||||
nsCString serverTime,
|
||||
bool fromHttp,
|
||||
SerializedLoadContext loadContext);
|
||||
prio(urgent) async SetCookieString(URIParams host,
|
||||
bool isForeign,
|
||||
nsCString cookieString,
|
||||
nsCString serverTime,
|
||||
bool fromHttp,
|
||||
SerializedLoadContext loadContext);
|
||||
|
||||
__delete__();
|
||||
};
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace mozilla {
|
|||
namespace net {
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
sync protocol PNecko
|
||||
prio(normal upto urgent) sync protocol PNecko
|
||||
{
|
||||
manager PContent;
|
||||
manages PHttpChannel;
|
||||
|
@ -55,7 +55,7 @@ sync protocol PNecko
|
|||
parent:
|
||||
__delete__();
|
||||
|
||||
PCookieService();
|
||||
prio(urgent) async PCookieService();
|
||||
PHttpChannel(PBrowserOrId browser,
|
||||
SerializedLoadContext loadContext,
|
||||
HttpChannelCreationArgs args);
|
||||
|
|
|
@ -18,7 +18,7 @@ interface nsIX509Cert;
|
|||
* {host:port, cert-fingerprint, allowed-overrides}
|
||||
* that the user wants to accept without further warnings.
|
||||
*/
|
||||
[scriptable, uuid(31738d2a-77d3-4359-84c9-4be2f38fb8c5)]
|
||||
[scriptable, uuid(be019e47-22fc-4355-9f16-9ab047d6742d)]
|
||||
interface nsICertOverrideService : nsISupports {
|
||||
|
||||
/**
|
||||
|
@ -108,15 +108,6 @@ interface nsICertOverrideService : nsISupports {
|
|||
void clearValidityOverride(in ACString aHostName,
|
||||
in int32_t aPort);
|
||||
|
||||
/**
|
||||
* Obtain the full list of hostname:port for which overrides are known.
|
||||
*
|
||||
* @param aCount The number of host:port entries returned
|
||||
* @param aHostsWithPortsArray The array of host:port entries returned
|
||||
*/
|
||||
void getAllOverrideHostsWithPorts(out uint32_t aCount,
|
||||
[array, size_is(aCount)] out wstring aHostsWithPortsArray);
|
||||
|
||||
/**
|
||||
* Is the given cert used in rules?
|
||||
*
|
||||
|
|
|
@ -6,29 +6,24 @@
|
|||
|
||||
#include "nsCertOverrideService.h"
|
||||
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "nsIX509Cert.h"
|
||||
#include "NSSCertDBTrustDomain.h"
|
||||
#include "nsNSSCertificate.h"
|
||||
#include "nsNSSCertHelper.h"
|
||||
#include "nsCRT.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "SharedSSLState.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsILineInputStream.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsNSSCertHelper.h"
|
||||
#include "nsNSSCertificate.h"
|
||||
#include "nsNSSComponent.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsPromiseFlatString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "SharedSSLState.h"
|
||||
|
||||
#include "nspr.h"
|
||||
#include "pk11pub.h"
|
||||
#include "certdb.h"
|
||||
#include "sechash.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "ssl.h" // For SSL_ClearSessionCache
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -106,18 +101,11 @@ nsCertOverrideService::Init()
|
|||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
// Note that the names of these variables would seem to indicate that at one
|
||||
// point another hash algorithm was used and is still supported for backwards
|
||||
// compatibility. This is not the case. It has always been SHA256.
|
||||
mOidTagForStoringNewHashes = SEC_OID_SHA256;
|
||||
|
||||
SECOidData *od = SECOID_FindOIDByTag(mOidTagForStoringNewHashes);
|
||||
if (!od)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
char *dotted_oid = CERT_GetOidString(&od->oid);
|
||||
if (!dotted_oid)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mDottedOidForStoringNewHashes = dotted_oid;
|
||||
PR_smprintf_free(dotted_oid);
|
||||
mDottedOidForStoringNewHashes.Assign("OID.2.16.840.1.101.3.4.2.1");
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
@ -172,7 +160,7 @@ nsCertOverrideService::Observe(nsISupports *,
|
|||
mSettingsFile = nullptr;
|
||||
}
|
||||
Read();
|
||||
|
||||
CountPermanentOverrideTelemetry();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -398,42 +386,6 @@ GetCertFingerprintByOidTag(nsIX509Cert *aCert,
|
|||
return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
|
||||
const nsCString &dottedOid,
|
||||
nsCString &fp)
|
||||
{
|
||||
SECItem oid;
|
||||
oid.data = nullptr;
|
||||
oid.len = 0;
|
||||
SECStatus srv = SEC_StringToOID(nullptr, &oid,
|
||||
dottedOid.get(), dottedOid.Length());
|
||||
if (srv != SECSuccess)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
SECOidTag oid_tag = SECOID_FindOIDTag(&oid);
|
||||
SECITEM_FreeItem(&oid, false);
|
||||
|
||||
if (oid_tag == SEC_OID_UNKNOWN)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return GetCertFingerprintByOidTag(nsscert, oid_tag, fp);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
|
||||
const nsCString &dottedOid,
|
||||
nsCString &fp)
|
||||
{
|
||||
|
||||
ScopedCERTCertificate nsscert(aCert->GetCert());
|
||||
if (!nsscert) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
|
||||
int32_t aPort,
|
||||
|
@ -546,14 +498,17 @@ nsCertOverrideService::HasMatchingOverride(const nsACString & aHostName, int32_t
|
|||
nsAutoCString fpStr;
|
||||
nsresult rv;
|
||||
|
||||
// This code was originally written in a way that suggested that other hash
|
||||
// algorithms are supported for backwards compatibility. However, this was
|
||||
// always unnecessary, because only SHA256 has ever been used here.
|
||||
if (settings.mFingerprintAlgOID.Equals(mDottedOidForStoringNewHashes)) {
|
||||
rv = GetCertFingerprintByOidTag(aCert, mOidTagForStoringNewHashes, fpStr);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
else {
|
||||
rv = GetCertFingerprintByDottedOidString(aCert, settings.mFingerprintAlgOID, fpStr);
|
||||
}
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
*_retval = settings.mFingerprint.Equals(fpStr);
|
||||
return NS_OK;
|
||||
|
@ -649,15 +604,37 @@ nsCertOverrideService::ClearValidityOverride(const nsACString & aHostName, int32
|
|||
mSettingsTable.RemoveEntry(hostPort.get());
|
||||
Write();
|
||||
}
|
||||
SSL_ClearSessionCache();
|
||||
|
||||
if (EnsureNSSInitialized(nssEnsure)) {
|
||||
SSL_ClearSessionCache();
|
||||
} else {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCertOverrideService::GetAllOverrideHostsWithPorts(uint32_t *aCount,
|
||||
char16_t ***aHostsWithPortsArray)
|
||||
static PLDHashOperator
|
||||
CountPermanentEntriesCallback(nsCertOverrideEntry* aEntry, void* aArg)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
uint32_t* overrideCount = reinterpret_cast<uint32_t*>(aArg);
|
||||
if (aEntry && !aEntry->mSettings.mIsTemporary) {
|
||||
*overrideCount = *overrideCount + 1;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsCertOverrideService::CountPermanentOverrideTelemetry()
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(monitor);
|
||||
uint32_t overrideCount = 0;
|
||||
mSettingsTable.EnumerateEntries(CountPermanentEntriesCallback,
|
||||
&overrideCount);
|
||||
Telemetry::Accumulate(Telemetry::SSL_PERMANENT_CERT_ERROR_OVERRIDES,
|
||||
overrideCount);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -738,15 +715,11 @@ FindMatchingCertCallback(nsCertOverrideEntry *aEntry,
|
|||
|
||||
if (still_ok && matchesDBKey(cai->cert, settings.mDBKey.get())) {
|
||||
nsAutoCString cert_fingerprint;
|
||||
nsresult rv;
|
||||
nsresult rv = NS_ERROR_UNEXPECTED;
|
||||
if (settings.mFingerprintAlgOID.Equals(cai->mDottedOidForStoringNewHashes)) {
|
||||
rv = GetCertFingerprintByOidTag(cai->cert,
|
||||
cai->mOidTagForStoringNewHashes, cert_fingerprint);
|
||||
}
|
||||
else {
|
||||
rv = GetCertFingerprintByDottedOidString(cai->cert,
|
||||
settings.mFingerprintAlgOID, cert_fingerprint);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
settings.mFingerprint.Equals(cert_fingerprint)) {
|
||||
cai->counter++;
|
||||
|
@ -808,15 +781,11 @@ EnumerateCertOverridesCallback(nsCertOverrideEntry *aEntry,
|
|||
else {
|
||||
if (matchesDBKey(capac->cert, settings.mDBKey.get())) {
|
||||
nsAutoCString cert_fingerprint;
|
||||
nsresult rv;
|
||||
nsresult rv = NS_ERROR_UNEXPECTED;
|
||||
if (settings.mFingerprintAlgOID.Equals(capac->mDottedOidForStoringNewHashes)) {
|
||||
rv = GetCertFingerprintByOidTag(capac->cert,
|
||||
capac->mOidTagForStoringNewHashes, cert_fingerprint);
|
||||
}
|
||||
else {
|
||||
rv = GetCertFingerprintByDottedOidString(capac->cert,
|
||||
settings.mFingerprintAlgOID, cert_fingerprint);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
settings.mFingerprint.Equals(cert_fingerprint)) {
|
||||
(*capac->enumerator)(settings, capac->userdata);
|
||||
|
@ -860,4 +829,3 @@ nsCertOverrideService::GetHostWithPort(const nsACString & aHostName, int32_t aPo
|
|||
}
|
||||
_retval.Assign(hostPort);
|
||||
}
|
||||
|
||||
|
|
|
@ -165,6 +165,8 @@ protected:
|
|||
SECOidTag mOidTagForStoringNewHashes;
|
||||
nsCString mDottedOidForStoringNewHashes;
|
||||
|
||||
void CountPermanentOverrideTelemetry();
|
||||
|
||||
void RemoveAllFromMemory();
|
||||
nsresult Read();
|
||||
nsresult Write();
|
||||
|
|
|
@ -199,7 +199,6 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsStreamCipher)
|
|||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObject)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObjectFactory)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsDataSignatureVerifier)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsCertOverrideService, Init)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsRandomGenerator)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, nsSSLStatus)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, TransportSecurityInfo)
|
||||
|
@ -207,6 +206,7 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, TransportSecurityInfo)
|
|||
typedef mozilla::psm::NSSErrorsService NSSErrorsService;
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NSSErrorsService, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSVersion)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCertOverrideService, Init)
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_NSSCOMPONENT_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_SSLSOCKETPROVIDER_CID);
|
||||
|
|
|
@ -189,14 +189,6 @@
|
|||
"VeriSign Universal Root Certification Authority",
|
||||
"XRamp Global CA Root"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "facebook",
|
||||
"sha256_hashes": [
|
||||
"Verisign Class 3 Public Primary Certification Authority - G3",
|
||||
"DigiCert High Assurance EV Root CA",
|
||||
"DigiCert ECC Secure Server CA"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
|
@ -234,10 +226,7 @@
|
|||
// twitterCDN. More specific rules take precedence because we search for
|
||||
// exact domain name first.
|
||||
{ "name": "twitter.com", "include_subdomains": true,
|
||||
"pins": "twitterCDN", "test_mode": false },
|
||||
// Facebook (not pinned by Chrome)
|
||||
{ "name": "facebook.com", "include_subdomains": true,
|
||||
"pins": "facebook", "test_mode": true }
|
||||
"pins": "twitterCDN", "test_mode": false }
|
||||
],
|
||||
|
||||
"extra_certificates": [
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
enum MacSandboxType {
|
||||
MacSandboxType_Default = 0,
|
||||
MacSandboxType_Plugin,
|
||||
MacSandboxType_Content,
|
||||
MacSandboxType_Invalid
|
||||
};
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче