author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Tue, 13 Oct 2015 12:00:54 +0200 | |
changeset 267410 | 607a236c229994df99766c005f9ec729532d7747 |
parent 267355 | afa71e48a9f1ec9f96c5bc107560659d3b15c96e (current diff) |
parent 267409 | 09f71d26b0e31fd69fcb6558bb25252d7ed73a2f (diff) |
child 267411 | 2387ada864282880d3a498d643abe3d8b887ee59 |
child 267418 | b2f57376ca0aa750c43e137b6923953b52563f6b |
child 267480 | 36a317c63ba4697bf845cc81f64f603484329718 |
child 267524 | 3dff8d76c46e087cfa5a7c8be005773fb9a71378 |
push id | 29517 |
push user | cbook@mozilla.com |
push date | Tue, 13 Oct 2015 10:01:04 +0000 |
treeherder | mozilla-central@607a236c2299 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 44.0a1 |
first release with | nightly linux32
607a236c2299
/
44.0a1
/
20151013030225
/
files
nightly linux64
607a236c2299
/
44.0a1
/
20151013030225
/
files
nightly mac
607a236c2299
/
44.0a1
/
20151013030225
/
files
nightly win32
607a236c2299
/
44.0a1
/
20151013030225
/
files
nightly win64
607a236c2299
/
44.0a1
/
20151013030225
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
44.0a1
/
20151013030225
/
pushlog to previous
nightly linux64
44.0a1
/
20151013030225
/
pushlog to previous
nightly mac
44.0a1
/
20151013030225
/
pushlog to previous
nightly win32
44.0a1
/
20151013030225
/
pushlog to previous
nightly win64
44.0a1
/
20151013030225
/
pushlog to previous
|
--- a/browser/components/extensions/test/browser/browser_ext_simple.js +++ b/browser/components/extensions/test/browser/browser_ext_simple.js @@ -1,19 +1,51 @@ add_task(function* test_simple() { - let extension = ExtensionTestUtils.loadExtension("simple"); + let extensionData = { + manifest: { + "name": "Simple extension test", + "version": "1.0", + "manifest_version": 2, + "description": "" + } + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); info("load complete"); yield extension.startup(); info("startup complete"); yield extension.unload(); info("extension unloaded successfully"); }); add_task(function* test_background() { - let extension = ExtensionTestUtils.loadExtension("background"); + function backgroundScript() { + browser.test.log("running background script"); + + browser.test.onMessage.addListener((x, y) => { + browser.test.assertEq(x, 10, "x is 10"); + browser.test.assertEq(y, 20, "y is 20"); + + browser.test.notifyPass("background test passed"); + }); + + browser.test.sendMessage("running", 1); + } + + let extensionData = { + background: "(" + backgroundScript.toString() + ")()", + manifest: { + "name": "Simple extension test", + "version": "1.0", + "manifest_version": 2, + "description": "" + } + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); info("load complete"); let [, x] = yield Promise.all([extension.startup(), extension.awaitMessage("running")]); is(x, 1, "got correct value from extension"); info("startup complete"); extension.sendMessage(10, 20); yield extension.awaitFinish(); info("test complete"); yield extension.unload();
--- a/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js +++ b/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js @@ -104,18 +104,18 @@ function getFilePath(aName, aAllowMissin if (aUsePlatformPathSeparator && path.match(/^\w:/)) { path = path.replace(/\//g, "\\"); } return path; } -function saveNewHeapSnapshot() { - const filePath = ChromeUtils.saveHeapSnapshot({ runtime: true }); +function saveNewHeapSnapshot(opts = { runtime: true }) { + const filePath = ChromeUtils.saveHeapSnapshot(opts); ok(filePath, "Should get a file path to save the core dump to."); ok(true, "Saved a heap snapshot to " + filePath); return filePath; } /** * Save a heap snapshot to the file with the given name in the current * directory, read it back as a HeapSnapshot instance, and then take a census of
new file mode 100644 --- /dev/null +++ b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_04.js @@ -0,0 +1,118 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that the HeapAnalyses{Client,Worker} can send SavedFrame stacks from +// by-allocation-stack reports from the worker. + +function run_test() { + run_next_test(); +} + +add_task(function* test() { + const client = new HeapAnalysesClient(); + + // Track some allocation stacks. + + const g = newGlobal(); + const dbg = new Debugger(g); + g.eval(` // 1 + this.log = []; // 2 + function f() { this.log.push(allocationMarker()); } // 3 + function g() { this.log.push(allocationMarker()); } // 4 + function h() { this.log.push(allocationMarker()); } // 5 + `); // 6 + + // Create one allocationMarker with tracking turned off, + // so it will have no associated stack. + g.f(); + + dbg.memory.allocationSamplingProbability = 1; + + for (let [func, n] of [ [g.f, 20], + [g.g, 10], + [g.h, 5] ]) { + for (let i = 0; i < n; i++) { + dbg.memory.trackingAllocationSites = true; + // All allocations of allocationMarker occur with this line as the oldest + // stack frame. + func(); + dbg.memory.trackingAllocationSites = false; + } + } + + // Take a heap snapshot. + + const snapshotFilePath = saveNewHeapSnapshot({ debugger: dbg }); + yield client.readHeapSnapshot(snapshotFilePath); + ok(true, "Should have read the heap snapshot"); + + // Run a census broken down by class name -> allocation stack so we can grab + // only the AllocationMarker objects we have complete control over. + + const report = yield client.takeCensus(snapshotFilePath, { + breakdown: { by: 'objectClass', + then: { by: 'allocationStack', + then: { by: 'count', + bytes: true, + count: true + }, + noStack: { by: 'count', + bytes: true, + count: true + } + } + } + }); + + // Test the generated report. + + ok(report, "Should get a report"); + + const map = report.AllocationMarker; + ok(map, "Should get AllocationMarkers in the report."); + // From a module with a different global, and therefore a different Map + // constructor, so we can't use instanceof. + equal(map.__proto__.constructor.name, "Map"); + + equal(map.size, 4, "Should have 4 allocation stacks (including the lack of a stack)") + + // Gather the stacks we are expecting to appear as keys, and + // check that there are no unexpected keys. + let stacks = {}; + + map.forEach((v, k) => { + if (k === 'noStack') { + // No need to save this key. + } else if (k.functionDisplayName === 'f' && + k.parent.functionDisplayName === 'test') { + stacks.f = k; + } else if (k.functionDisplayName === 'g' && + k.parent.functionDisplayName === 'test') { + stacks.g = k; + } else if (k.functionDisplayName === 'h' && + k.parent.functionDisplayName === 'test') { + stacks.h = k; + } else { + dumpn("Unexpected allocation stack:") + k.toString().split(/\n/g).forEach(s => dumpn(s)); + ok(false); + } + }); + + ok(map.get('noStack')); + equal(map.get('noStack').count, 1); + + ok(stacks.f); + ok(map.get(stacks.f)); + equal(map.get(stacks.f).count, 20); + + ok(stacks.g); + ok(map.get(stacks.g)); + equal(map.get(stacks.g).count, 10); + + ok(stacks.h); + ok(map.get(stacks.h)); + equal(map.get(stacks.h).count, 5); + + client.destroy(); +});
--- a/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini +++ b/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini @@ -11,16 +11,17 @@ support-files = [test_census-tree-node-01.js] [test_census-tree-node-02.js] [test_census-tree-node-03.js] [test_HeapAnalyses_readHeapSnapshot_01.js] [test_HeapAnalyses_takeCensus_01.js] [test_HeapAnalyses_takeCensus_02.js] [test_HeapAnalyses_takeCensus_03.js] +[test_HeapAnalyses_takeCensus_04.js] [test_HeapSnapshot_takeCensus_01.js] [test_HeapSnapshot_takeCensus_02.js] [test_HeapSnapshot_takeCensus_03.js] [test_HeapSnapshot_takeCensus_04.js] [test_HeapSnapshot_takeCensus_05.js] [test_HeapSnapshot_takeCensus_06.js] [test_HeapSnapshot_takeCensus_07.js] [test_HeapSnapshot_takeCensus_08.js]
--- a/docshell/test/chrome/chrome.ini +++ b/docshell/test/chrome/chrome.ini @@ -75,17 +75,16 @@ skip-if = toolkit == "gtk2" [test_bug565388.xul] skip-if = os == 'linux' || os == 'mac' # Bug 1026815 [test_bug582176.xul] [test_bug608669.xul] [test_bug662200.xul] [test_bug690056.xul] [test_bug789773.xul] [test_bug846906.xul] -skip-if = (os == 'linux' && asan) || debug # Bug 1207161 [test_bug89419.xul] [test_bug909218.html] [test_bug92598.xul] [test_mozFrameType.xul] [test_principalInherit.xul] [test_private_hidden_window.html] [test_viewsource_forbidden_in_iframe.xul] skip-if = true # bug 1019315
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -2705,16 +2705,19 @@ nsContentUtils::GenerateStateKey(nsICont // static nsIPrincipal* nsContentUtils::SubjectPrincipal() { MOZ_ASSERT(IsInitialized()); MOZ_ASSERT(NS_IsMainThread()); JSContext* cx = GetCurrentJSContext(); if (!cx) { +#ifndef RELEASE_BUILD + MOZ_CRASH("Accessing the Subject Principal without an AutoJSAPI on the stack is forbidden"); +#endif Telemetry::Accumulate(Telemetry::SUBJECT_PRINCIPAL_ACCESSED_WITHOUT_SCRIPT_ON_STACK, true); return GetSystemPrincipal(); } JSCompartment *compartment = js::GetContextCompartment(cx); // When an AutoJSAPI is instantiated, we are in a null compartment until the // first JSAutoCompartment, which is kind of a purgatory as far as permissions
--- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1977,16 +1977,17 @@ public: , mIsRefocus(aIsRefocus) { } NS_IMETHOD Run() { InternalFocusEvent event(true, mEventMessage); event.mFlags.mBubbles = false; + event.mFlags.mCancelable = false; event.fromRaise = mWindowRaised; event.isRefocus = mIsRefocus; return EventDispatcher::Dispatch(mTarget, mContext, &event); } nsCOMPtr<nsISupports> mTarget; nsRefPtr<nsPresContext> mContext; EventMessage mEventMessage;
--- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -1069,23 +1069,16 @@ nsINode::IsEqualNode(nsINode* aOther) } // System ID docType1->GetSystemId(string1); docType2->GetSystemId(string2); if (!string1.Equals(string2)) { return false; } - - // Internal subset - docType1->GetInternalSubset(string1); - docType2->GetInternalSubset(string2); - if (!string1.Equals(string2)) { - return false; - } break; } default: MOZ_ASSERT(false, "Unknown node type"); } nsINode* nextNode = node1->GetFirstChild();
--- a/dom/base/test/test_createHTMLDocument.html +++ b/dom/base/test/test_createHTMLDocument.html @@ -33,18 +33,17 @@ function checkDoc(title, expectedtitle, // Doesn't always work out in WebKit. ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node."); is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle); } else { is(doc.documentElement.firstChild.childNodes.length, 0); } isElement(doc.documentElement.lastChild, "body"); is(doc.documentElement.lastChild.childNodes.length, 0); - ((!title || title.indexOf("\f") === -1) ? is : todo_is) - (doc.title, normalizedtitle); + is(doc.title, normalizedtitle); doc.body.innerHTML = "foo"; is(doc.body.innerHTML, "foo", "innerHTML should work in HTML data documents!"); } checkDoc("", "", ""); checkDoc(null, "null", "null"); checkDoc(undefined, "", ""); checkDoc("foo bar baz", "foo bar baz", "foo bar baz"); checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz");
--- a/dom/imptests/failures/html/dom/nodes/mochitest.ini +++ b/dom/imptests/failures/html/dom/nodes/mochitest.ini @@ -1,14 +1,13 @@ # THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT [DEFAULT] support-files = [test_Document-createElement-namespace.html.json] [test_Document-createElementNS.html.json] [test_Document-getElementsByTagName.html.json] -[test_Node-isEqualNode.xhtml.json] [test_Node-properties.html.json] [test_attributes.html.json] [test_case.html.json] [test_getElementsByClassName-10.xml.json] [test_getElementsByClassName-11.xml.json]
deleted file mode 100644 --- a/dom/imptests/failures/html/dom/nodes/test_Node-isEqualNode.xhtml.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEqualNode should return true when only the internal subsets of DocumentTypes differ.": true -}
--- a/dom/imptests/failures/html/html/dom/documents/dta/mochitest.ini +++ b/dom/imptests/failures/html/html/dom/documents/dta/mochitest.ini @@ -1,14 +1,11 @@ # THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT [DEFAULT] support-files = -[test_document.title-03.html.json] -[test_document.title-04.xhtml.json] [test_document.title-06.html.json] -[test_document.title-07.html.json] [test_nameditem-02.html.json] [test_nameditem-03.html.json] [test_nameditem-04.html.json] [test_nameditem-05.html.json] [test_nameditem-06.html.json]
deleted file mode 100644 --- a/dom/imptests/failures/html/html/dom/documents/dta/test_document.title-03.html.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - " document.title and space normalization ": true -}
deleted file mode 100644 --- a/dom/imptests/failures/html/html/dom/documents/dta/test_document.title-04.xhtml.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - " document.title and space normalization ": true -}
deleted file mode 100644 --- a/dom/imptests/failures/html/html/dom/documents/dta/test_document.title-07.html.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Document.title and DOMImplementation.createHTMLDocument 6": true -}
deleted file mode 100644 --- a/dom/imptests/failures/html/html/semantics/forms/the-option-element/mochitest.ini +++ /dev/null @@ -1,6 +0,0 @@ -# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT -[DEFAULT] -support-files = - - -[test_option-text-spaces.html.json]
deleted file mode 100644 --- a/dom/imptests/failures/html/html/semantics/forms/the-option-element/test_option-text-spaces.html.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "option.text should strip leading space characters (\"\\f\")": true, - "option.text should strip trailing space characters (\"\\f\")": true, - "option.text should strip leading and trailing space characters (\"\\f\")": true, - "option.text should replace single internal space characters (\"\\f\")": true, - "option.text should replace multiple internal space characters (\" \", \"\\f\")": true, - "option.text should replace multiple internal space characters (\"\\t\", \"\\f\")": true, - "option.text should replace multiple internal space characters (\"\\n\", \"\\f\")": true, - "option.text should replace multiple internal space characters (\"\\f\", \" \")": true, - "option.text should replace multiple internal space characters (\"\\f\", \"\\t\")": true, - "option.text should replace multiple internal space characters (\"\\f\", \"\\n\")": true, - "option.text should replace multiple internal space characters (\"\\f\", \"\\f\")": true, - "option.text should replace multiple internal space characters (\"\\f\", \"\\r\")": true, - "option.text should replace multiple internal space characters (\"\\r\", \"\\f\")": true -}
--- a/dom/imptests/moz.build +++ b/dom/imptests/moz.build @@ -19,17 +19,16 @@ MOCHITEST_MANIFESTS += [ 'failures/html/dom/mochitest.ini', 'failures/html/dom/nodes/mochitest.ini', 'failures/html/dom/ranges/mochitest.ini', 'failures/html/html/browsers/the-window-object/mochitest.ini', 'failures/html/html/browsers/the-window-object/named-access-on-the-window-object/mochitest.ini', 'failures/html/html/dom/documents/dta/doc.gEBN/mochitest.ini', 'failures/html/html/dom/documents/dta/mochitest.ini', 'failures/html/html/obsolete/implreq/oeaaa/mochitest.ini', - 'failures/html/html/semantics/forms/the-option-element/mochitest.ini', 'failures/html/html/semantics/forms/the-select-element/mochitest.ini', 'failures/html/html/semantics/scripting-1/the-script-element/mochitest.ini', 'failures/html/html/semantics/tabular-data/the-table-element/mochitest.ini', 'failures/html/html/webappapis/atob/mochitest.ini', 'failures/html/js/builtins/mochitest.ini', 'failures/html/microdata/microdata-dom-api/mochitest.ini', 'failures/html/typedarrays/mochitest.ini', 'failures/webapps/WebStorage/tests/submissions/Infraware/mochitest.ini',
--- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -141,21 +141,21 @@ class TransactionDatabaseOperationBase; class VersionChangeTransaction; /******************************************************************************* * Constants ******************************************************************************/ // If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major // schema version. -static_assert(JS_STRUCTURED_CLONE_VERSION == 5, +static_assert(JS_STRUCTURED_CLONE_VERSION == 6, "Need to update the major schema version."); // Major schema version. Bump for almost everything. -const uint32_t kMajorSchemaVersion = 21; +const uint32_t kMajorSchemaVersion = 22; // Minor schema version. Should almost always be 0 (maybe bump on release // branches if we have to). const uint32_t kMinorSchemaVersion = 0; // The schema version we store in the SQLite database is a (signed) 32-bit // integer. The major version is left-shifted 4 bits so the max value is // 0xFFFFFFF. The minor version occupies the lower 4 bits and its max is 0xF. @@ -4062,16 +4062,29 @@ UpgradeSchemaFrom20_0To21_0(mozIStorageC if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; } nsresult +UpgradeSchemaFrom21_0To22_0(mozIStorageConnection* aConnection) +{ + // The only change between 21 and 22 was a different structured clone format, + // but it's backwards-compatible. + nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(22, 0)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +nsresult GetDatabaseFileURL(nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, uint32_t aTelemetryId, nsIFileURL** aResult) { MOZ_ASSERT(aDatabaseFile); @@ -4553,17 +4566,17 @@ CreateStorageConnection(nsIFile* aDBFile } rv = stmt->Execute(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { // This logic needs to change next time we change the schema! - static_assert(kSQLiteSchemaVersion == int32_t((21 << 4) + 0), + static_assert(kSQLiteSchemaVersion == int32_t((22 << 4) + 0), "Upgrade function needed due to schema version increase."); while (schemaVersion != kSQLiteSchemaVersion) { if (schemaVersion == 4) { rv = UpgradeSchemaFrom4To5(connection); } else if (schemaVersion == 5) { rv = UpgradeSchemaFrom5To6(connection); } else if (schemaVersion == 6) { @@ -4593,16 +4606,18 @@ CreateStorageConnection(nsIFile* aDBFile rv = UpgradeSchemaFrom17_0To18_0(connection, aOrigin); vacuumNeeded = true; } else if (schemaVersion == MakeSchemaVersion(18, 0)) { rv = UpgradeSchemaFrom18_0To19_0(connection); } else if (schemaVersion == MakeSchemaVersion(19, 0)) { rv = UpgradeSchemaFrom19_0To20_0(aFMDirectory, connection); } else if (schemaVersion == MakeSchemaVersion(20, 0)) { rv = UpgradeSchemaFrom20_0To21_0(connection); + } else if (schemaVersion == MakeSchemaVersion(21, 0)) { + rv = UpgradeSchemaFrom21_0To22_0(connection); } else { IDB_WARNING("Unable to open IndexedDB database, no upgrade path is " "available!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
--- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -252,16 +252,20 @@ HangMonitorChild::HangMonitorChild(Proce mShutdownDone(false), mIPCOpen(true) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); } HangMonitorChild::~HangMonitorChild() { + // For some reason IPDL doesn't automatically delete the channel for a + // bridged protocol (bug 1090570). So we have to do it ourselves. + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask<Transport>(GetTransport())); + MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_ASSERT(sInstance == this); sInstance = nullptr; } void HangMonitorChild::Shutdown() { @@ -464,17 +468,17 @@ DeleteMinidump(const uint32_t& aPluginId CrashReporter::DeleteMinidumpFilesForID(aCrashId); } #endif return PL_DHASH_NEXT; } HangMonitorParent::~HangMonitorParent() { - // For some reason IPDL doesn't autmatically delete the channel for a + // For some reason IPDL doesn't automatically delete the channel for a // bridged protocol (bug 1090570). So we have to do it ourselves. XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask<Transport>(GetTransport())); MutexAutoLock lock(mBrowserCrashDumpHashLock); mBrowserCrashDumpIds.EnumerateRead(DeleteMinidump, nullptr); } void
--- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -156,17 +156,17 @@ PluginModuleChild::PluginModuleChild(boo mac_plugin_interposing::child::SetUpCocoaInterposing(); } #endif } PluginModuleChild::~PluginModuleChild() { if (mTransport) { - // For some reason IPDL doesn't autmatically delete the channel for a + // For some reason IPDL doesn't automatically delete the channel for a // bridged protocol (bug 1090570). So we have to do it ourselves. This // code is only invoked for PluginModuleChild instances created via // bridging; otherwise mTransport is null. XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask<Transport>(mTransport)); } if (mIsChrome) { MOZ_ASSERT(gChromeInstance == this);
--- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -685,16 +685,19 @@ PluginModuleParent::~PluginModuleParent( PluginModuleContentParent::PluginModuleContentParent(bool aAllowAsyncInit) : PluginModuleParent(false, aAllowAsyncInit) { Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref, this); } PluginModuleContentParent::~PluginModuleContentParent() { + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, + new DeleteTask<Transport>(GetTransport())); + Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this); } bool PluginModuleChromeParent::sInstantiated = false; PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId, int32_t aSandboxLevel,
--- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -91,26 +91,22 @@ NS_NewXMLContentSink(nsIXMLContentSink** nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel); NS_ENSURE_SUCCESS(rv, rv); it.forget(aResult); return NS_OK; } nsXMLContentSink::nsXMLContentSink() - : mConstrainSize(true), - mPrettyPrintXML(true) + : mPrettyPrintXML(true) { } nsXMLContentSink::~nsXMLContentSink() { - if (mText) { - PR_Free(mText); // Doesn't null out, unlike PR_FREEIF - } } nsresult nsXMLContentSink::Init(nsIDocument* aDoc, nsIURI* aURI, nsISupports* aContainer, nsIChannel* aChannel) { @@ -470,17 +466,16 @@ nsXMLContentSink::CreateElement(const ch NS_ENSURE_SUCCESS(rv, rv); if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG) ) { nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content); sele->SetScriptLineNumber(aLineNumber); sele->SetCreatorParser(GetParser()); - mConstrainSize = false; } // XHTML needs some special attention if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { mPrettyPrintHasFactoredElements = true; } else { // If we care, find out if we just used a special factory. @@ -547,17 +542,16 @@ nsXMLContentSink::CloseElement(nsIConten if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) && !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) { return NS_OK; } if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG) ) { - mConstrainSize = true; nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent); if (mPreventScriptExecution) { sele->PreventExecution(); return NS_OK; } // Always check the clock in nsContentSink right after a script @@ -773,53 +767,44 @@ nsXMLContentSink::IsScriptExecuting() nsresult nsXMLContentSink::FlushText(bool aReleaseTextNode) { nsresult rv = NS_OK; if (mTextLength != 0) { if (mLastTextNode) { - if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) { - mLastTextNodeSize = 0; - mLastTextNode = nullptr; - FlushText(aReleaseTextNode); - } else { - bool notify = HaveNotifiedForCurrentContent(); - // We could probably always increase mInNotification here since - // if AppendText doesn't notify it shouldn't trigger evil code. - // But just in case it does, we don't want to mask any notifications. - if (notify) { - ++mInNotification; - } - rv = mLastTextNode->AppendText(mText, mTextLength, notify); - if (notify) { - --mInNotification; - } + bool notify = HaveNotifiedForCurrentContent(); + // We could probably always increase mInNotification here since + // if AppendText doesn't notify it shouldn't trigger evil code. + // But just in case it does, we don't want to mask any notifications. + if (notify) { + ++mInNotification; + } + rv = mLastTextNode->AppendText(mText, mTextLength, notify); + if (notify) { + --mInNotification; + } - mLastTextNodeSize += mTextLength; - mTextLength = 0; - } + mTextLength = 0; } else { nsRefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager); mLastTextNode = textContent; // Set the text in the text node textContent->SetText(mText, mTextLength, false); - mLastTextNodeSize += mTextLength; mTextLength = 0; // Add text to its parent rv = AddContentAsLeaf(textContent); } } if (aReleaseTextNode) { - mLastTextNodeSize = 0; mLastTextNode = nullptr; } return rv; } nsIContent* nsXMLContentSink::GetCurrentContent() @@ -1432,51 +1417,29 @@ nsXMLContentSink::AddAttributes(const ch } #define NS_ACCUMULATION_BUFFER_SIZE 4096 nsresult nsXMLContentSink::AddText(const char16_t* aText, int32_t aLength) { - // Create buffer when we first need it - if (0 == mTextSize) { - mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE); - if (nullptr == mText) { - return NS_ERROR_OUT_OF_MEMORY; - } - mTextSize = NS_ACCUMULATION_BUFFER_SIZE; - } - - // Copy data from string into our buffer; flush buffer when it fills up + // Copy data from string into our buffer; flush buffer when it fills up. int32_t offset = 0; while (0 != aLength) { - int32_t amount = mTextSize - mTextLength; + int32_t amount = NS_ACCUMULATION_BUFFER_SIZE - mTextLength; if (0 == amount) { - // XSLT wants adjacent textnodes merged. - if (mConstrainSize && !mXSLTProcessor) { - nsresult rv = FlushText(); - if (NS_OK != rv) { - return rv; - } - - amount = mTextSize - mTextLength; + nsresult rv = FlushText(false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } - else { - mTextSize += aLength; - mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize); - if (nullptr == mText) { - mTextSize = 0; + MOZ_ASSERT(mTextLength == 0); + amount = NS_ACCUMULATION_BUFFER_SIZE; + } - return NS_ERROR_OUT_OF_MEMORY; - } - - amount = aLength; - } - } if (amount > aLength) { amount = aLength; } memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount); mTextLength += amount; offset += amount; aLength -= amount; }
--- a/dom/xml/nsXMLContentSink.h +++ b/dom/xml/nsXMLContentSink.h @@ -166,34 +166,35 @@ protected: uint32_t aAttsCount, uint32_t aLineNumber, bool aInterruptable); nsresult HandleEndElement(const char16_t *aName, bool aInterruptable); nsresult HandleCharacterData(const char16_t *aData, uint32_t aLength, bool aInterruptable); nsCOMPtr<nsIContent> mDocElement; nsCOMPtr<nsIContent> mCurrentHead; // When set, we're in an XHTML <haed> - char16_t* mText; XMLContentSinkState mState; + // The length of the valid data in mText. int32_t mTextLength; - int32_t mTextSize; int32_t mNotifyLevel; nsCOMPtr<nsIContent> mLastTextNode; - int32_t mLastTextNodeSize; - uint8_t mConstrainSize : 1; uint8_t mPrettyPrintXML : 1; uint8_t mPrettyPrintHasSpecialRoot : 1; uint8_t mPrettyPrintHasFactoredElements : 1; uint8_t mPrettyPrinting : 1; // True if we called PrettyPrint() and it // decided we should in fact prettyprint. // True to call prevent script execution in the fragment mode. uint8_t mPreventScriptExecution : 1; nsTArray<StackNode> mContentStack; nsCOMPtr<nsIDocumentTransformer> mXSLTProcessor; + + static const int NS_ACCUMULATION_BUFFER_SIZE = 4096; + // Our currently accumulated text that we have not flushed to a textnode yet. + char16_t mText[NS_ACCUMULATION_BUFFER_SIZE]; }; #endif // nsXMLContentSink_h__
--- a/gfx/2d/DrawingJob.h +++ b/gfx/2d/DrawingJob.h @@ -8,16 +8,17 @@ #include <stdint.h> #include "mozilla/RefPtr.h" #include "mozilla/Assertions.h" #include "mozilla/gfx/Matrix.h" #include "mozilla/gfx/JobScheduler.h" #include "mozilla/gfx/IterableArena.h" +#include "mozilla/RefCounted.h" #include "DrawCommand.h" namespace mozilla { namespace gfx { class DrawingCommand; class PrintCommand; class SignalCommand;
--- a/gfx/2d/JobScheduler.h +++ b/gfx/2d/JobScheduler.h @@ -3,16 +3,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZILLA_GFX_TASKSCHEDULER_H_ #define MOZILLA_GFX_TASKSCHEDULER_H_ #include "mozilla/RefPtr.h" #include "mozilla/gfx/Types.h" +#include "mozilla/RefCounted.h" #ifdef WIN32 #include "mozilla/gfx/JobScheduler_win32.h" #else #include "mozilla/gfx/JobScheduler_posix.h" #endif #include <vector> @@ -242,9 +243,9 @@ protected: virtual void SetName(const char* aName) {} MultiThreadedJobQueue* mQueue; }; } // namespace } // namespace -#endif \ No newline at end of file +#endif
--- a/gfx/2d/JobScheduler_posix.h +++ b/gfx/2d/JobScheduler_posix.h @@ -12,16 +12,17 @@ #include <list> #include <pthread.h> #include <stdint.h> #include <stdio.h> #include "mozilla/RefPtr.h" #include "mozilla/DebugOnly.h" #include "mozilla/gfx/CriticalSection.h" +#include "mozilla/RefCounted.h" namespace mozilla { namespace gfx { class Job; class PosixCondVar; class WorkerThread;
--- a/gfx/2d/JobScheduler_win32.h +++ b/gfx/2d/JobScheduler_win32.h @@ -7,16 +7,17 @@ #ifndef MOZILLA_GFX_TASKSCHEDULER_WIN32_H_ #define MOZILLA_GFX_TASKSCHEDULER_WIN32_H_ #include <windows.h> #include <list> #include "mozilla/RefPtr.h" #include "mozilla/gfx/CriticalSection.h" +#include "mozilla/RefCounted.h" namespace mozilla { namespace gfx { class WorkerThread; class Job; // The public interface of this class must remain identical to its equivalent
--- a/gfx/2d/MacIOSurface.h +++ b/gfx/2d/MacIOSurface.h @@ -40,16 +40,17 @@ typedef IOSurfacePtr (*IOSurfaceContextG typedef IOSurfacePtr (*CVPixelBufferGetIOSurfaceFunc)( CVPixelBufferRef pixelBuffer); typedef OSType (*IOSurfacePixelFormatFunc)(IOSurfacePtr io_surface); #import <OpenGL/OpenGL.h> #include "2D.h" #include "mozilla/RefPtr.h" +#include "mozilla/RefCounted.h" struct _CGLContextObject; typedef _CGLContextObject* CGLContextObj; typedef struct CGContext* CGContextRef; typedef struct CGImage* CGImageRef; typedef uint32_t IOSurfaceID;
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -96,21 +96,23 @@ DCFromDrawTarget::DCFromDrawTarget(DrawT mNeedsRelease = false; SaveDC(mDC); cairo_t* ctx = (cairo_t*) aDrawTarget.GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT); cairo_scaled_font_t* scaled = cairo_get_scaled_font(ctx); cairo_win32_scaled_font_select_font(scaled, mDC); } } - if (!mDC) { - mDC = GetDC(nullptr); - SetGraphicsMode(mDC, GM_ADVANCED); - mNeedsRelease = true; - } + } + + if (!mDC) { + // Get the whole screen DC: + mDC = GetDC(nullptr); + SetGraphicsMode(mDC, GM_ADVANCED); + mNeedsRelease = true; } } #ifdef CAIRO_HAS_D2D_SURFACE static const char *kFeatureLevelPref = "gfx.direct3d.last_used_feature_level_idx"; static const int kSupportedFeatureLevels[] = @@ -679,20 +681,23 @@ gfxWindowsPlatform::VerifyD2DDevice(bool } #endif } gfxPlatformFontList* gfxWindowsPlatform::CreatePlatformFontList() { gfxPlatformFontList *pfl; + #ifdef CAIRO_HAS_DWRITE_FONT // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd // crashers so blacklist them altogether - if (IsNotWin7PreRTM() && GetDWriteFactory()) { + if (IsNotWin7PreRTM() && GetDWriteFactory() && + // Skia doesn't support DirectWrite fonts yet. + (gfxPlatform::GetDefaultContentBackend() != BackendType::SKIA)) { pfl = new gfxDWriteFontList(); if (NS_SUCCEEDED(pfl->InitFontList())) { return pfl; } // DWrite font initialization failed! Don't know why this would happen, // but apparently it can - see bug 594865. // So we're going to fall back to GDI fonts & rendering. gfxPlatformFontList::Shutdown();
--- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -1216,19 +1216,16 @@ VectorImage::OnSVGDocumentLoaded() EvaluateAnimation(); } void VectorImage::OnSVGDocumentError() { CancelAllListeners(); - // XXXdholbert Need to do something more for the parsing failed case -- right - // now, this just makes us draw the "object" icon, rather than the (jagged) - // "broken image" icon. See bug 594505. mError = true; if (mProgressTracker) { // Notify observers about the error and unblock page load. Progress progress = FLAG_DECODE_COMPLETE | FLAG_ONLOAD_UNBLOCKED | FLAG_HAS_ERROR;
--- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -116,17 +116,17 @@ typedef bool (*TransferStructuredCloneOp // assert in a debug build if it does.) typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership, void* content, uint64_t extraData, void* closure); // The maximum supported structured-clone serialization format version. // Increment this when anything at all changes in the serialization format. // (Note that this does not need to be bumped for Transferable-only changes, // since they are never saved to persistent storage.) -#define JS_STRUCTURED_CLONE_VERSION 5 +#define JS_STRUCTURED_CLONE_VERSION 6 struct JSStructuredCloneCallbacks { ReadStructuredCloneOp read; WriteStructuredCloneOp write; StructuredCloneErrorOp reportError; ReadTransferStructuredCloneOp readTransfer; TransferStructuredCloneOp writeTransfer; FreeTransferStructuredCloneOp freeTransfer;
--- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -2211,16 +2211,25 @@ IonCache::disable() void GetPropertyIC::maybeDisable(bool emitted) { if (emitted) { failedUpdates_ = 0; return; } + if (!canAttachStub() && id().constant()) { + // Don't disable the cache (and discard stubs) if we have a GETPROP and + // attached the maximum number of stubs. This can happen when JS code + // uses an AST-like data structure and accesses a field of a "base + // class", like node.nodeType. This should be temporary until we handle + // this case better, see bug 1107515. + return; + } + if (!canAttachStub() || (stubCount_ == 0 && failedUpdates_ > MAX_FAILED_UPDATES)) { JitSpew(JitSpew_IonIC, "Disable inline cache"); disable(); } } void IonCache::reset(ReprotectCode reprotect)
--- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -2334,32 +2334,32 @@ MacroAssemblerARMCompat::store32(Imm32 s AutoRegisterScope scratch2(asMasm(), secondScratchReg_); move32(src, scratch2); storePtr(scratch2, address); } void MacroAssemblerARMCompat::store32(Imm32 imm, const BaseIndex& dest) { - AutoRegisterScope scratch2(asMasm(), secondScratchReg_); - ma_mov(imm, scratch2); - store32(scratch2, dest); + ScratchRegisterScope scratch(asMasm()); + ma_mov(imm, scratch); + store32(scratch, dest); } void MacroAssemblerARMCompat::store32(Register src, const BaseIndex& dest) { Register base = dest.base; uint32_t scale = Imm32::ShiftOf(dest.scale).value; - ScratchRegisterScope scratch(asMasm()); + AutoRegisterScope scratch2(asMasm(), secondScratchReg_); if (dest.offset != 0) { - ma_add(base, Imm32(dest.offset), scratch); - base = scratch; + ma_add(base, Imm32(dest.offset), scratch2); + base = scratch2; } ma_str(src, DTRAddr(base, DtrRegImmShift(dest.index, LSL, scale))); } void MacroAssemblerARMCompat::store32_NoSecondScratch(Imm32 src, const Address& address) { // move32() needs to use the ScratchRegister internally, but there is no additional
--- a/js/src/jit/mips-shared/Assembler-mips-shared.cpp +++ b/js/src/jit/mips-shared/Assembler-mips-shared.cpp @@ -476,46 +476,89 @@ AssemblerMIPSShared::as_addu(Register rd BufferOffset AssemblerMIPSShared::as_addiu(Register rd, Register rs, int32_t j) { MOZ_ASSERT(Imm16::IsInSignedRange(j)); return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode()); } BufferOffset +AssemblerMIPSShared::as_daddu(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_daddu).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_daddiu(Register rd, Register rs, int32_t j) +{ + MOZ_ASSERT(Imm16::IsInSignedRange(j)); + return writeInst(InstImm(op_daddiu, rs, rd, Imm16(j)).encode()); +} + +BufferOffset AssemblerMIPSShared::as_subu(Register rd, Register rs, Register rt) { return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode()); } BufferOffset +AssemblerMIPSShared::as_dsubu(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_dsubu).encode()); +} + +BufferOffset AssemblerMIPSShared::as_mult(Register rs, Register rt) { return writeInst(InstReg(op_special, rs, rt, ff_mult).encode()); } BufferOffset AssemblerMIPSShared::as_multu(Register rs, Register rt) { return writeInst(InstReg(op_special, rs, rt, ff_multu).encode()); } BufferOffset +AssemblerMIPSShared::as_dmult(Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, ff_dmult).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dmultu(Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, ff_dmultu).encode()); +} + +BufferOffset AssemblerMIPSShared::as_div(Register rs, Register rt) { return writeInst(InstReg(op_special, rs, rt, ff_div).encode()); } BufferOffset AssemblerMIPSShared::as_divu(Register rs, Register rt) { return writeInst(InstReg(op_special, rs, rt, ff_divu).encode()); } BufferOffset +AssemblerMIPSShared::as_ddiv(Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, ff_ddiv).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ddivu(Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, ff_ddivu).encode()); +} + +BufferOffset AssemblerMIPSShared::as_mul(Register rd, Register rs, Register rt) { return writeInst(InstReg(op_special2, rs, rt, rd, ff_mul).encode()); } BufferOffset AssemblerMIPSShared::as_lui(Register rd, int32_t j) { @@ -527,60 +570,140 @@ AssemblerMIPSShared::as_lui(Register rd, BufferOffset AssemblerMIPSShared::as_sll(Register rd, Register rt, uint16_t sa) { MOZ_ASSERT(sa < 32); return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode()); } BufferOffset +AssemblerMIPSShared::as_dsll(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(sa < 32); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsll).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dsll32(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(31 < sa && sa < 64); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsll32).encode()); +} + +BufferOffset AssemblerMIPSShared::as_sllv(Register rd, Register rt, Register rs) { return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode()); } BufferOffset +AssemblerMIPSShared::as_dsllv(Register rd, Register rt, Register rs) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_dsllv).encode()); +} + +BufferOffset AssemblerMIPSShared::as_srl(Register rd, Register rt, uint16_t sa) { MOZ_ASSERT(sa < 32); return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode()); } BufferOffset +AssemblerMIPSShared::as_dsrl(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(sa < 32); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsrl).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dsrl32(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(31 < sa && sa < 64); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsrl32).encode()); +} + +BufferOffset AssemblerMIPSShared::as_srlv(Register rd, Register rt, Register rs) { return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode()); } BufferOffset +AssemblerMIPSShared::as_dsrlv(Register rd, Register rt, Register rs) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrlv).encode()); +} + +BufferOffset AssemblerMIPSShared::as_sra(Register rd, Register rt, uint16_t sa) { MOZ_ASSERT(sa < 32); return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode()); } BufferOffset +AssemblerMIPSShared::as_dsra(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(sa < 32); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsra).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dsra32(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(31 < sa && sa < 64); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsra32).encode()); +} + +BufferOffset AssemblerMIPSShared::as_srav(Register rd, Register rt, Register rs) { return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode()); } BufferOffset +AssemblerMIPSShared::as_dsrav(Register rd, Register rt, Register rs) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrav).encode()); +} + +BufferOffset AssemblerMIPSShared::as_rotr(Register rd, Register rt, uint16_t sa) { MOZ_ASSERT(sa < 32); return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode()); } BufferOffset +AssemblerMIPSShared::as_drotr(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(sa < 32); + return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_dsrl).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_drotr32(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(31 < sa && sa < 64); + return writeInst(InstReg(op_special, rs_one, rt, rd, sa - 32, ff_dsrl32).encode()); +} + +BufferOffset AssemblerMIPSShared::as_rotrv(Register rd, Register rt, Register rs) { return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode()); } +BufferOffset +AssemblerMIPSShared::as_drotrv(Register rd, Register rt, Register rs) +{ + return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_dsrlv).encode()); +} + // Load and store instructions BufferOffset AssemblerMIPSShared::as_lb(Register rd, Register rs, int16_t off) { return writeInst(InstImm(op_lb, rs, rd, Imm16(off)).encode()); } BufferOffset @@ -603,28 +726,58 @@ AssemblerMIPSShared::as_lhu(Register rd, BufferOffset AssemblerMIPSShared::as_lw(Register rd, Register rs, int16_t off) { return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode()); } BufferOffset +AssemblerMIPSShared::as_lwu(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_lwu, rs, rd, Imm16(off)).encode()); +} + +BufferOffset AssemblerMIPSShared::as_lwl(Register rd, Register rs, int16_t off) { return writeInst(InstImm(op_lwl, rs, rd, Imm16(off)).encode()); } BufferOffset AssemblerMIPSShared::as_lwr(Register rd, Register rs, int16_t off) { return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode()); } BufferOffset +AssemblerMIPSShared::as_ll(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_ll, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ld(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_ld, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ldl(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_ldl, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ldr(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_ldr, rs, rd, Imm16(off)).encode()); +} + +BufferOffset AssemblerMIPSShared::as_sb(Register rd, Register rs, int16_t off) { return writeInst(InstImm(op_sb, rs, rd, Imm16(off)).encode()); } BufferOffset AssemblerMIPSShared::as_sh(Register rd, Register rs, int16_t off) { @@ -644,16 +797,40 @@ AssemblerMIPSShared::as_swl(Register rd, } BufferOffset AssemblerMIPSShared::as_swr(Register rd, Register rs, int16_t off) { return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode()); } +BufferOffset +AssemblerMIPSShared::as_sc(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_sc, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sd(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_sd, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sdl(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_sdl, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sdr(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_sdr, rs, rd, Imm16(off)).encode()); +} + // Move from HI/LO register. BufferOffset AssemblerMIPSShared::as_mfhi(Register rd) { return writeInst(InstReg(op_special, rd, ff_mfhi).encode()); } BufferOffset @@ -721,33 +898,106 @@ AssemblerMIPSShared::as_movf(Register rd // Bit twiddling. BufferOffset AssemblerMIPSShared::as_clz(Register rd, Register rs) { return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode()); } BufferOffset +AssemblerMIPSShared::as_dclz(Register rd, Register rs) +{ + return writeInst(InstReg(op_special2, rs, rd, rd, ff_dclz).encode()); +} + +BufferOffset AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size) { MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32); Register rd; rd = Register::FromCode(pos + size - 1); return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode()); } BufferOffset +AssemblerMIPSShared::as_dins(Register rt, Register rs, uint16_t pos, uint16_t size) +{ + MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32); + Register rd; + rd = Register::FromCode(pos + size - 1); + return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dins).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size) +{ + MOZ_ASSERT(pos < 32 && size >= 2 && size <= 64 && pos + size > 32 && pos + size <= 64); + Register rd; + rd = Register::FromCode(pos + size - 1 - 32); + return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dinsm).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size) +{ + MOZ_ASSERT(pos >= 32 && pos < 64 && size >= 1 && size <= 32 && pos + size > 32 && pos + size <= 64); + Register rd; + rd = Register::FromCode(pos + size - 1 - 32); + return writeInst(InstReg(op_special3, rs, rt, rd, pos - 32, ff_dinsu).encode()); +} + +BufferOffset AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size) { MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32); Register rd; rd = Register::FromCode(size - 1); return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode()); } +// Sign extend +BufferOffset +AssemblerMIPSShared::as_seb(Register rd, Register rt) +{ + return writeInst(InstReg(op_special3, zero, rt, rd, 16, ff_bshfl).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_seh(Register rd, Register rt) +{ + return writeInst(InstReg(op_special3, zero, rt, rd, 24, ff_bshfl).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dext(Register rt, Register rs, uint16_t pos, uint16_t size) +{ + MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 63); + Register rd; + rd = Register::FromCode(size - 1); + return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dext).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size) +{ + MOZ_ASSERT(pos < 32 && size > 32 && size <= 64 && pos + size > 32 && pos + size <= 64); + Register rd; + rd = Register::FromCode(size - 1 - 32); + return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dextm).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size) +{ + MOZ_ASSERT(pos >= 32 && pos < 64 && size != 0 && size <= 32 && pos + size > 32 && pos + size <= 64); + Register rd; + rd = Register::FromCode(size - 1); + return writeInst(InstReg(op_special3, rs, rt, rd, pos - 32, ff_dextu).encode()); +} + // FP instructions BufferOffset AssemblerMIPSShared::as_ld(FloatRegister fd, Register base, int32_t off) { MOZ_ASSERT(Imm16::IsInSignedRange(off)); return writeInst(InstImm(op_ldc1, base, fd, Imm16(off)).encode()); } @@ -791,16 +1041,40 @@ AssemblerMIPSShared::as_mtc1(Register rt } BufferOffset AssemblerMIPSShared::as_mfc1(Register rt, FloatRegister fs) { return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode()); } +BufferOffset +AssemblerMIPSShared::as_mthc1(Register rt, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_mthc1, rt, fs).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_mfhc1(Register rt, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_mfhc1, rt, fs).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dmtc1(Register rt, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_dmtc1, rt, fs).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_dmfc1(Register rt, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_dmfc1, rt, fs).encode()); +} + // FP convert instructions BufferOffset AssemblerMIPSShared::as_ceilws(FloatRegister fd, FloatRegister fs) { return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_w_fmt).encode()); } BufferOffset @@ -841,16 +1115,22 @@ AssemblerMIPSShared::as_roundwd(FloatReg BufferOffset AssemblerMIPSShared::as_truncwd(FloatRegister fd, FloatRegister fs) { return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode()); } BufferOffset +AssemblerMIPSShared::as_cvtdl(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_d_fmt).encode()); +} + +BufferOffset AssemblerMIPSShared::as_cvtds(FloatRegister fd, FloatRegister fs) { return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_d_fmt).encode()); } BufferOffset AssemblerMIPSShared::as_cvtdw(FloatRegister fd, FloatRegister fs) {
--- a/js/src/jit/mips-shared/Assembler-mips-shared.h +++ b/js/src/jit/mips-shared/Assembler-mips-shared.h @@ -25,24 +25,28 @@ namespace jit { static MOZ_CONSTEXPR_VAR Register zero = { Registers::zero }; static MOZ_CONSTEXPR_VAR Register at = { Registers::at }; static MOZ_CONSTEXPR_VAR Register v0 = { Registers::v0 }; static MOZ_CONSTEXPR_VAR Register v1 = { Registers::v1 }; static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 }; static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 }; static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 }; static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 }; +static MOZ_CONSTEXPR_VAR Register a4 = { Registers::ta0 }; +static MOZ_CONSTEXPR_VAR Register a5 = { Registers::ta1 }; +static MOZ_CONSTEXPR_VAR Register a6 = { Registers::ta2 }; +static MOZ_CONSTEXPR_VAR Register a7 = { Registers::ta3 }; static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 }; static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 }; static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 }; static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 }; -static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 }; -static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 }; -static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 }; -static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 }; +static MOZ_CONSTEXPR_VAR Register t4 = { Registers::ta0 }; +static MOZ_CONSTEXPR_VAR Register t5 = { Registers::ta1 }; +static MOZ_CONSTEXPR_VAR Register t6 = { Registers::ta2 }; +static MOZ_CONSTEXPR_VAR Register t7 = { Registers::ta3 }; static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 }; static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 }; static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 }; static MOZ_CONSTEXPR_VAR Register s3 = { Registers::s3 }; static MOZ_CONSTEXPR_VAR Register s4 = { Registers::s4 }; static MOZ_CONSTEXPR_VAR Register s5 = { Registers::s5 }; static MOZ_CONSTEXPR_VAR Register s6 = { Registers::s6 }; static MOZ_CONSTEXPR_VAR Register s7 = { Registers::s7 }; @@ -80,16 +84,20 @@ static MOZ_CONSTEXPR_VAR Register CallTe static MOZ_CONSTEXPR_VAR Register CallTempReg1 = t1; static MOZ_CONSTEXPR_VAR Register CallTempReg2 = t2; static MOZ_CONSTEXPR_VAR Register CallTempReg3 = t3; static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0; static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1; static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2; static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3; +static MOZ_CONSTEXPR_VAR Register IntArgReg4 = a4; +static MOZ_CONSTEXPR_VAR Register IntArgReg5 = a5; +static MOZ_CONSTEXPR_VAR Register IntArgReg6 = a6; +static MOZ_CONSTEXPR_VAR Register IntArgReg7 = a7; static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = CALL_TEMP_NON_ARG_REGS; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1; static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg }; @@ -241,47 +249,62 @@ enum Opcode { op_cop1 = 17 << OpcodeShift, op_cop1x = 19 << OpcodeShift, op_beql = 20 << OpcodeShift, op_bnel = 21 << OpcodeShift, op_blezl = 22 << OpcodeShift, op_bgtzl = 23 << OpcodeShift, + op_daddi = 24 << OpcodeShift, + op_daddiu = 25 << OpcodeShift, + + op_ldl = 26 << OpcodeShift, + op_ldr = 27 << OpcodeShift, + op_special2 = 28 << OpcodeShift, op_special3 = 31 << OpcodeShift, op_lb = 32 << OpcodeShift, op_lh = 33 << OpcodeShift, op_lwl = 34 << OpcodeShift, op_lw = 35 << OpcodeShift, op_lbu = 36 << OpcodeShift, op_lhu = 37 << OpcodeShift, op_lwr = 38 << OpcodeShift, + op_lwu = 39 << OpcodeShift, op_sb = 40 << OpcodeShift, op_sh = 41 << OpcodeShift, op_swl = 42 << OpcodeShift, op_sw = 43 << OpcodeShift, + op_sdl = 44 << OpcodeShift, + op_sdr = 45 << OpcodeShift, op_swr = 46 << OpcodeShift, + op_ll = 48 << OpcodeShift, op_lwc1 = 49 << OpcodeShift, op_ldc1 = 53 << OpcodeShift, + op_ld = 55 << OpcodeShift, + op_sc = 56 << OpcodeShift, op_swc1 = 57 << OpcodeShift, - op_sdc1 = 61 << OpcodeShift + op_sdc1 = 61 << OpcodeShift, + op_sd = 63 << OpcodeShift, }; enum RSField { rs_zero = 0 << RSShift, // cop1 encoding of RS field. rs_mfc1 = 0 << RSShift, rs_one = 1 << RSShift, + rs_dmfc1 = 1 << RSShift, rs_cfc1 = 2 << RSShift, rs_mfhc1 = 3 << RSShift, rs_mtc1 = 4 << RSShift, + rs_dmtc1 = 5 << RSShift, rs_ctc1 = 6 << RSShift, rs_mthc1 = 7 << RSShift, rs_bc1 = 8 << RSShift, rs_s = 16 << RSShift, rs_d = 17 << RSShift, rs_w = 20 << RSShift, rs_l = 21 << RSShift, rs_ps = 22 << RSShift @@ -311,48 +334,74 @@ enum FunctionField { ff_movz = 10, ff_movn = 11, ff_break = 13, ff_sync = 15, ff_mfhi = 16, ff_mflo = 18, + ff_dsllv = 20, + ff_dsrlv = 22, + ff_dsrav = 23, + ff_mult = 24, ff_multu = 25, ff_div = 26, ff_divu = 27, + ff_dmult = 28, + ff_dmultu = 29, + ff_ddiv = 30, + ff_ddivu = 31, ff_add = 32, ff_addu = 33, ff_sub = 34, ff_subu = 35, ff_and = 36, ff_or = 37, ff_xor = 38, ff_nor = 39, ff_slt = 42, ff_sltu = 43, + ff_dadd = 44, + ff_daddu = 45, + ff_dsub = 46, + ff_dsubu = 47, ff_tge = 48, ff_tgeu = 49, ff_tlt = 50, ff_tltu = 51, ff_teq = 52, ff_tne = 54, + ff_dsll = 56, + ff_dsrl = 58, + ff_dsra = 59, + ff_dsll32 = 60, + ff_dsrl32 = 62, + ff_dsra32 = 63, // special2 encoding of function field. ff_mul = 2, ff_clz = 32, ff_clo = 33, + ff_dclz = 36, // special3 encoding of function field. ff_ext = 0, + ff_dextm = 1, + ff_dextu = 2, + ff_dext = 3, ff_ins = 4, + ff_dinsm = 5, + ff_dinsu = 6, + ff_dins = 7, + ff_bshfl = 32, // cop1 encoding of function field. ff_add_fmt = 0, ff_sub_fmt = 1, ff_mul_fmt = 2, ff_div_fmt = 3, ff_sqrt_fmt = 4, ff_abs_fmt = 5, @@ -807,58 +856,86 @@ class AssemblerMIPSShared : public Assem BufferOffset as_jal(JOffImm26 off); BufferOffset as_jr(Register rs); BufferOffset as_jalr(Register rs); // Arithmetic instructions BufferOffset as_addu(Register rd, Register rs, Register rt); BufferOffset as_addiu(Register rd, Register rs, int32_t j); + BufferOffset as_daddu(Register rd, Register rs, Register rt); + BufferOffset as_daddiu(Register rd, Register rs, int32_t j); BufferOffset as_subu(Register rd, Register rs, Register rt); + BufferOffset as_dsubu(Register rd, Register rs, Register rt); BufferOffset as_mult(Register rs, Register rt); BufferOffset as_multu(Register rs, Register rt); + BufferOffset as_dmult(Register rs, Register rt); + BufferOffset as_dmultu(Register rs, Register rt); BufferOffset as_div(Register rs, Register rt); BufferOffset as_divu(Register rs, Register rt); BufferOffset as_mul(Register rd, Register rs, Register rt); + BufferOffset as_ddiv(Register rs, Register rt); + BufferOffset as_ddivu(Register rs, Register rt); // Logical instructions BufferOffset as_and(Register rd, Register rs, Register rt); BufferOffset as_or(Register rd, Register rs, Register rt); BufferOffset as_xor(Register rd, Register rs, Register rt); BufferOffset as_nor(Register rd, Register rs, Register rt); BufferOffset as_andi(Register rd, Register rs, int32_t j); BufferOffset as_ori(Register rd, Register rs, int32_t j); BufferOffset as_xori(Register rd, Register rs, int32_t j); BufferOffset as_lui(Register rd, int32_t j); // Shift instructions // as_sll(zero, zero, x) instructions are reserved as nop BufferOffset as_sll(Register rd, Register rt, uint16_t sa); + BufferOffset as_dsll(Register rd, Register rt, uint16_t sa); + BufferOffset as_dsll32(Register rd, Register rt, uint16_t sa); BufferOffset as_sllv(Register rd, Register rt, Register rs); + BufferOffset as_dsllv(Register rd, Register rt, Register rs); BufferOffset as_srl(Register rd, Register rt, uint16_t sa); + BufferOffset as_dsrl(Register rd, Register rt, uint16_t sa); + BufferOffset as_dsrl32(Register rd, Register rt, uint16_t sa); BufferOffset as_srlv(Register rd, Register rt, Register rs); + BufferOffset as_dsrlv(Register rd, Register rt, Register rs); BufferOffset as_sra(Register rd, Register rt, uint16_t sa); + BufferOffset as_dsra(Register rd, Register rt, uint16_t sa); + BufferOffset as_dsra32(Register rd, Register rt, uint16_t sa); BufferOffset as_srav(Register rd, Register rt, Register rs); BufferOffset as_rotr(Register rd, Register rt, uint16_t sa); BufferOffset as_rotrv(Register rd, Register rt, Register rs); + BufferOffset as_dsrav(Register rd, Register rt, Register rs); + BufferOffset as_drotr(Register rd, Register rt, uint16_t sa); + BufferOffset as_drotr32(Register rd, Register rt, uint16_t sa); + BufferOffset as_drotrv(Register rd, Register rt, Register rs); // Load and store instructions BufferOffset as_lb(Register rd, Register rs, int16_t off); BufferOffset as_lbu(Register rd, Register rs, int16_t off); BufferOffset as_lh(Register rd, Register rs, int16_t off); BufferOffset as_lhu(Register rd, Register rs, int16_t off); BufferOffset as_lw(Register rd, Register rs, int16_t off); + BufferOffset as_lwu(Register rd, Register rs, int16_t off); BufferOffset as_lwl(Register rd, Register rs, int16_t off); BufferOffset as_lwr(Register rd, Register rs, int16_t off); + BufferOffset as_ll(Register rd, Register rs, int16_t off); + BufferOffset as_ld(Register rd, Register rs, int16_t off); + BufferOffset as_ldl(Register rd, Register rs, int16_t off); + BufferOffset as_ldr(Register rd, Register rs, int16_t off); BufferOffset as_sb(Register rd, Register rs, int16_t off); BufferOffset as_sh(Register rd, Register rs, int16_t off); BufferOffset as_sw(Register rd, Register rs, int16_t off); BufferOffset as_swl(Register rd, Register rs, int16_t off); BufferOffset as_swr(Register rd, Register rs, int16_t off); + BufferOffset as_sc(Register rd, Register rs, int16_t off); + BufferOffset as_sd(Register rd, Register rs, int16_t off); + BufferOffset as_sdl(Register rd, Register rs, int16_t off); + BufferOffset as_sdr(Register rd, Register rs, int16_t off); // Move from HI/LO register. BufferOffset as_mfhi(Register rd); BufferOffset as_mflo(Register rd); // Set on less than. BufferOffset as_slt(Register rd, Register rs, Register rt); BufferOffset as_sltu(Register rd, Register rs, Register rt); @@ -868,18 +945,29 @@ class AssemblerMIPSShared : public Assem // Conditional move. BufferOffset as_movz(Register rd, Register rs, Register rt); BufferOffset as_movn(Register rd, Register rs, Register rt); BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0); BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0); // Bit twiddling. BufferOffset as_clz(Register rd, Register rs); + BufferOffset as_dclz(Register rd, Register rs); BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size); + BufferOffset as_dins(Register rt, Register rs, uint16_t pos, uint16_t size); + BufferOffset as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size); + BufferOffset as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size); BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size); + BufferOffset as_dext(Register rt, Register rs, uint16_t pos, uint16_t size); + BufferOffset as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size); + BufferOffset as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size); + + // Sign extend + BufferOffset as_seb(Register rd, Register rt); + BufferOffset as_seh(Register rd, Register rt); // FP instructions // Use these two functions only when you are sure address is aligned. // Otherwise, use ma_ld and ma_sd. BufferOffset as_ld(FloatRegister fd, Register base, int32_t off); BufferOffset as_sd(FloatRegister fd, Register base, int32_t off); @@ -887,16 +975,20 @@ class AssemblerMIPSShared : public Assem BufferOffset as_ss(FloatRegister fd, Register base, int32_t off); BufferOffset as_movs(FloatRegister fd, FloatRegister fs); BufferOffset as_movd(FloatRegister fd, FloatRegister fs); BufferOffset as_mtc1(Register rt, FloatRegister fs); BufferOffset as_mfc1(Register rt, FloatRegister fs); + BufferOffset as_mthc1(Register rt, FloatRegister fs); + BufferOffset as_mfhc1(Register rt, FloatRegister fs); + BufferOffset as_dmtc1(Register rt, FloatRegister fs); + BufferOffset as_dmfc1(Register rt, FloatRegister fs); public: // FP convert instructions BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs); BufferOffset as_floorws(FloatRegister fd, FloatRegister fs); BufferOffset as_roundws(FloatRegister fd, FloatRegister fs); BufferOffset as_truncws(FloatRegister fd, FloatRegister fs); @@ -967,17 +1059,18 @@ class AssemblerMIPSShared : public Assem void call(Label* label); void call(void* target); void as_break(uint32_t code); void as_sync(uint32_t stype = 0); public: static bool SupportsFloatingPoint() { -#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || defined(JS_SIMULATOR_MIPS32) +#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || \ + defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64) return true; #else return false; #endif } static bool SupportsSimd() { return js::jit::SupportsSimd; }
--- a/js/src/jit/mips32/Trampoline-mips32.cpp +++ b/js/src/jit/mips32/Trampoline-mips32.cpp @@ -205,16 +205,17 @@ JitRuntime::generateEnterJIT(JSContext* CodeLabel returnLabel; if (type == EnterJitBaseline) { // Handle OSR. AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); regs.take(OsrFrameReg); regs.take(BaselineFrameReg); regs.take(reg_code); + regs.take(ReturnReg); const Address slotNumStackValues(BaselineFrameReg, sizeof(EnterJITRegs) + offsetof(EnterJITArgs, numStackValues)); const Address slotScopeChain(BaselineFrameReg, sizeof(EnterJITRegs) + offsetof(EnterJITArgs, scopeChain)); Label notOsr; masm.ma_b(OsrFrameReg, OsrFrameReg, ¬Osr, Assembler::Zero, ShortJump); @@ -260,20 +261,17 @@ JitRuntime::generateEnterJIT(JSContext* masm.setupUnalignedABICall(scratch); masm.passABIArg(BaselineFrameReg); // BaselineFrame masm.passABIArg(OsrFrameReg); // InterpreterFrame masm.passABIArg(numStackValues); masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr)); regs.add(OsrFrameReg); - regs.add(scratch); - regs.add(numStackValues); regs.take(JSReturnOperand); - regs.take(ReturnReg); Register jitcode = regs.takeAny(); masm.loadPtr(Address(StackPointer, 0), jitcode); masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), framePtr); masm.freeStack(2 * sizeof(uintptr_t)); Label error; masm.freeStack(ExitFrameLayout::SizeWithFooter()); masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
new file mode 100644 --- /dev/null +++ b/js/src/jit/mips64/Assembler-mips64.cpp @@ -0,0 +1,493 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/mips64/Assembler-mips64.h" + +#include "mozilla/DebugOnly.h" + +using mozilla::DebugOnly; + +using namespace js; +using namespace js::jit; + +ABIArgGenerator::ABIArgGenerator() + : usedArgSlots_(0), + firstArgFloat(false), + current_() +{} + +ABIArg +ABIArgGenerator::next(MIRType type) +{ + switch (type) { + case MIRType_Int32: + case MIRType_Pointer: { + Register destReg; + if (GetIntArgReg(usedArgSlots_, &destReg)) + current_ = ABIArg(destReg); + else + current_ = ABIArg(GetArgStackDisp(usedArgSlots_)); + usedArgSlots_++; + break; + } + case MIRType_Float32: + case MIRType_Double: { + FloatRegister destFReg; + FloatRegister::ContentType contentType; + if (!usedArgSlots_) + firstArgFloat = true; + contentType = (type == MIRType_Double) ? + FloatRegisters::Double : FloatRegisters::Single; + if (GetFloatArgReg(usedArgSlots_, &destFReg)) + current_ = ABIArg(FloatRegister(destFReg.id(), contentType)); + else + current_ = ABIArg(GetArgStackDisp(usedArgSlots_)); + usedArgSlots_++; + break; + } + default: + MOZ_CRASH("Unexpected argument type"); + } + return current_; +} + +const Register ABIArgGenerator::NonArgReturnReg0 = t0; +const Register ABIArgGenerator::NonArgReturnReg1 = t1; +const Register ABIArgGenerator::NonArg_VolatileReg = v0; +const Register ABIArgGenerator::NonReturn_VolatileReg0 = a0; +const Register ABIArgGenerator::NonReturn_VolatileReg1 = a1; + +uint32_t +js::jit::RT(FloatRegister r) +{ + MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys); + return r.id() << RTShift; +} + +uint32_t +js::jit::RD(FloatRegister r) +{ + MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys); + return r.id() << RDShift; +} + +uint32_t +js::jit::SA(FloatRegister r) +{ + MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys); + return r.id() << SAShift; +} + +// Used to patch jumps created by MacroAssemblerMIPS64Compat::jumpWithPatch. +void +jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, ReprotectCode reprotect) +{ + Instruction* inst = (Instruction*)jump_.raw(); + + // Six instructions used in load 64-bit imm. + MaybeAutoWritableJitCode awjc(inst, 6 * sizeof(uint32_t), reprotect); + Assembler::UpdateLoad64Value(inst, (uint64_t)label.raw()); + + AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t)); +} + +// For more infromation about backedges look at comment in +// MacroAssemblerMIPS64Compat::backedgeJump() +void +jit::PatchBackedge(CodeLocationJump& jump, CodeLocationLabel label, + JitRuntime::BackedgeTarget target) +{ + uintptr_t sourceAddr = (uintptr_t)jump.raw(); + uintptr_t targetAddr = (uintptr_t)label.raw(); + InstImm* branch = (InstImm*)jump.raw(); + + MOZ_ASSERT(branch->extractOpcode() == (uint32_t(op_beq) >> OpcodeShift)); + + if (BOffImm16::IsInRange(targetAddr - sourceAddr)) { + branch->setBOffImm16(BOffImm16(targetAddr - sourceAddr)); + } else { + if (target == JitRuntime::BackedgeLoopHeader) { + Instruction* inst = &branch[1]; + Assembler::UpdateLoad64Value(inst, targetAddr); + // Jump to first ori. The lui will be executed in delay slot. + branch->setBOffImm16(BOffImm16(2 * sizeof(uint32_t))); + } else { + Instruction* inst = &branch[6]; + Assembler::UpdateLoad64Value(inst, targetAddr); + // Jump to first ori of interrupt loop. + branch->setBOffImm16(BOffImm16(6 * sizeof(uint32_t))); + } + } +} + +void +Assembler::executableCopy(uint8_t* buffer) +{ + MOZ_ASSERT(isFinished); + m_buffer.executableCopy(buffer); + + // Patch all long jumps during code copy. + for (size_t i = 0; i < longJumps_.length(); i++) { + Instruction* inst = (Instruction*) ((uintptr_t)buffer + longJumps_[i]); + + uint64_t value = Assembler::ExtractLoad64Value(inst); + Assembler::UpdateLoad64Value(inst, (uint64_t)buffer + value); + } + + AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size()); +} + +uintptr_t +Assembler::GetPointer(uint8_t* instPtr) +{ + Instruction* inst = (Instruction*)instPtr; + return Assembler::ExtractLoad64Value(inst); +} + +static JitCode * +CodeFromJump(Instruction* jump) +{ + uint8_t* target = (uint8_t*)Assembler::ExtractLoad64Value(jump); + return JitCode::FromExecutable(target); +} + +void +Assembler::TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader) +{ + while (reader.more()) { + JitCode* child = CodeFromJump((Instruction*)(code->raw() + reader.readUnsigned())); + TraceManuallyBarrieredEdge(trc, &child, "rel32"); + } +} + +static void +TraceOneDataRelocation(JSTracer* trc, Instruction* inst) +{ + void* ptr = (void*)Assembler::ExtractLoad64Value(inst); + void* prior = ptr; + + // All pointers on MIPS64 will have the top bits cleared. If those bits + // are not cleared, this must be a Value. + uintptr_t word = reinterpret_cast<uintptr_t>(ptr); + if (word >> JSVAL_TAG_SHIFT) { + jsval_layout layout; + layout.asBits = word; + Value v = IMPL_TO_JSVAL(layout); + TraceManuallyBarrieredEdge(trc, &v, "ion-masm-value"); + ptr = (void*)JSVAL_TO_IMPL(v).asBits; + } else { + // No barrier needed since these are constants. + TraceManuallyBarrieredGenericPointerEdge(trc, reinterpret_cast<gc::Cell**>(&ptr), + "ion-masm-ptr"); + } + + if (ptr != prior) { + Assembler::UpdateLoad64Value(inst, uint64_t(ptr)); + AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t)); + } +} + +static void +TraceDataRelocations(JSTracer* trc, uint8_t* buffer, CompactBufferReader& reader) +{ + while (reader.more()) { + size_t offset = reader.readUnsigned(); + Instruction* inst = (Instruction*)(buffer + offset); + TraceOneDataRelocation(trc, inst); + } +} + +static void +TraceDataRelocations(JSTracer* trc, MIPSBuffer* buffer, CompactBufferReader& reader) +{ + while (reader.more()) { + BufferOffset bo (reader.readUnsigned()); + MIPSBuffer::AssemblerBufferInstIterator iter(bo, buffer); + TraceOneDataRelocation(trc, iter.cur()); + } +} + +void +Assembler::TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader) +{ + ::TraceDataRelocations(trc, code->raw(), reader); +} + +void +Assembler::trace(JSTracer* trc) +{ + for (size_t i = 0; i < jumps_.length(); i++) { + RelativePatch& rp = jumps_[i]; + if (rp.kind == Relocation::JITCODE) { + JitCode* code = JitCode::FromExecutable((uint8_t*)rp.target); + TraceManuallyBarrieredEdge(trc, &code, "masmrel32"); + MOZ_ASSERT(code == JitCode::FromExecutable((uint8_t*)rp.target)); + } + } + if (dataRelocations_.length()) { + CompactBufferReader reader(dataRelocations_); + ::TraceDataRelocations(trc, &m_buffer, reader); + } +} + +int64_t +Assembler::ExtractCodeLabelOffset(uint8_t* code) +{ + Instruction* inst = (Instruction*)code; + return Assembler::ExtractLoad64Value(inst); +} + +void +Assembler::Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address) +{ + if (label->used()) { + int64_t src = label->offset(); + do { + Instruction* inst = (Instruction*) (rawCode + src); + uint64_t next = Assembler::ExtractLoad64Value(inst); + Assembler::UpdateLoad64Value(inst, (uint64_t)address); + src = next; + } while (src != AbsoluteLabel::INVALID_OFFSET); + } + label->bind(); +} + +void +Assembler::bind(InstImm* inst, uint64_t branch, uint64_t target) +{ + int64_t offset = target - branch; + InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0)); + InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0)); + + // If encoded offset is 4, then the jump must be short + if (BOffImm16(inst[0]).decode() == 4) { + MOZ_ASSERT(BOffImm16::IsInRange(offset)); + inst[0].setBOffImm16(BOffImm16(offset)); + inst[1].makeNop(); + return; + } + + // Generate the long jump for calls because return address has to be the + // address after the reserved block. + if (inst[0].encode() == inst_bgezal.encode()) { + addLongJump(BufferOffset(branch)); + Assembler::WriteLoad64Instructions(inst, ScratchRegister, target); + inst[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode(); + // There is 1 nop after this. + return; + } + + if (BOffImm16::IsInRange(offset)) { + bool conditional = (inst[0].encode() != inst_bgezal.encode() && + inst[0].encode() != inst_beq.encode()); + + inst[0].setBOffImm16(BOffImm16(offset)); + inst[1].makeNop(); + + // Skip the trailing nops in conditional branches. + // FIXME: On Loongson3 platform, the branch degrade performance. + if (0 && conditional) { + inst[2] = InstImm(op_regimm, zero, rt_bgez, BOffImm16(5 * sizeof(uint32_t))).encode(); + // There are 4 nops after this + } + return; + } + + if (inst[0].encode() == inst_beq.encode()) { + // Handle long unconditional jump. + addLongJump(BufferOffset(branch)); + Assembler::WriteLoad64Instructions(inst, ScratchRegister, target); + inst[4] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode(); + // There is 1 nop after this. + } else { + // Handle long conditional jump. + inst[0] = invertBranch(inst[0], BOffImm16(7 * sizeof(uint32_t))); + // No need for a "nop" here because we can clobber scratch. + addLongJump(BufferOffset(branch + sizeof(uint32_t))); + Assembler::WriteLoad64Instructions(&inst[1], ScratchRegister, target); + inst[5] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode(); + // There is 1 nop after this. + } +} + +void +Assembler::bind(RepatchLabel* label) +{ + BufferOffset dest = nextOffset(); + if (label->used()) { + // If the label has a use, then change this use to refer to + // the bound label; + BufferOffset b(label->offset()); + InstImm* inst1 = (InstImm*)editSrc(b); + + // If first instruction is branch, then this is a loop backedge. + if (inst1->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift)) { + // Backedges are short jumps when bound, but can become long + // when patched. + uint64_t offset = dest.getOffset() - label->offset(); + MOZ_ASSERT(BOffImm16::IsInRange(offset)); + inst1->setBOffImm16(BOffImm16(offset)); + } else { + Assembler::UpdateLoad64Value(inst1, dest.getOffset()); + } + + } + label->bind(dest.getOffset()); +} + +uint32_t +Assembler::PatchWrite_NearCallSize() +{ + // Load an address needs 4 instructions, and a jump with a delay slot. + return (4 + 2) * sizeof(uint32_t); +} + +void +Assembler::PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall) +{ + Instruction* inst = (Instruction*) start.raw(); + uint8_t* dest = toCall.raw(); + + // Overwrite whatever instruction used to be here with a call. + // Always use long jump for two reasons: + // - Jump has to be the same size because of PatchWrite_NearCallSize. + // - Return address has to be at the end of replaced block. + // Short jump wouldn't be more efficient. + Assembler::WriteLoad64Instructions(inst, ScratchRegister, (uint64_t)dest); + inst[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr); + inst[5] = InstNOP(); + + // Ensure everyone sees the code that was just written into memory. + AutoFlushICache::flush(uintptr_t(inst), PatchWrite_NearCallSize()); +} + +uint64_t +Assembler::ExtractLoad64Value(Instruction* inst0) +{ + InstImm* i0 = (InstImm*) inst0; + InstImm* i1 = (InstImm*) i0->next(); + InstReg* i2 = (InstReg*) i1->next(); + InstImm* i3 = (InstImm*) i2->next(); + InstImm* i5 = (InstImm*) i3->next()->next(); + + MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift)); + MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); + MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); + + if ((i2->extractOpcode() == ((uint32_t)op_special >> OpcodeShift)) && + (i2->extractFunctionField() == ff_dsrl32)) + { + uint64_t value = (uint64_t(i0->extractImm16Value()) << 32) | + (uint64_t(i1->extractImm16Value()) << 16) | + uint64_t(i3->extractImm16Value()); + return uint64_t((int64_t(value) <<16) >> 16); + } + + MOZ_ASSERT(i5->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); + uint64_t value = (uint64_t(i0->extractImm16Value()) << 48) | + (uint64_t(i1->extractImm16Value()) << 32) | + (uint64_t(i3->extractImm16Value()) << 16) | + uint64_t(i5->extractImm16Value()); + return value; +} + +void +Assembler::UpdateLoad64Value(Instruction* inst0, uint64_t value) +{ + InstImm* i0 = (InstImm*) inst0; + InstImm* i1 = (InstImm*) i0->next(); + InstReg* i2 = (InstReg*) i1->next(); + InstImm* i3 = (InstImm*) i2->next(); + InstImm* i5 = (InstImm*) i3->next()->next(); + + MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift)); + MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); + MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); + + if ((i2->extractOpcode() == ((uint32_t)op_special >> OpcodeShift)) && + (i2->extractFunctionField() == ff_dsrl32)) + { + i0->setImm16(Imm16::Lower(Imm32(value >> 32))); + i1->setImm16(Imm16::Upper(Imm32(value))); + i3->setImm16(Imm16::Lower(Imm32(value))); + return; + } + + MOZ_ASSERT(i5->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); + + i0->setImm16(Imm16::Upper(Imm32(value >> 32))); + i1->setImm16(Imm16::Lower(Imm32(value >> 32))); + i3->setImm16(Imm16::Upper(Imm32(value))); + i5->setImm16(Imm16::Lower(Imm32(value))); +} + +void +Assembler::WriteLoad64Instructions(Instruction* inst0, Register reg, uint64_t value) +{ + Instruction* inst1 = inst0->next(); + Instruction* inst2 = inst1->next(); + Instruction* inst3 = inst2->next(); + + *inst0 = InstImm(op_lui, zero, reg, Imm16::Lower(Imm32(value >> 32))); + *inst1 = InstImm(op_ori, reg, reg, Imm16::Upper(Imm32(value))); + *inst2 = InstReg(op_special, rs_one, reg, reg, 48 - 32, ff_dsrl32); + *inst3 = InstImm(op_ori, reg, reg, Imm16::Lower(Imm32(value))); +} + +void +Assembler::PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue, + PatchedImmPtr expectedValue) +{ + Instruction* inst = (Instruction*) label.raw(); + + // Extract old Value + DebugOnly<uint64_t> value = Assembler::ExtractLoad64Value(inst); + MOZ_ASSERT(value == uint64_t(expectedValue.value)); + + // Replace with new value + Assembler::UpdateLoad64Value(inst, uint64_t(newValue.value)); + + AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t)); +} + +void +Assembler::PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm) +{ + InstImm* inst = (InstImm*)code; + Assembler::UpdateLoad64Value(inst, (uint64_t)imm.value); +} + +void +Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled) +{ + Instruction* inst = (Instruction*)inst_.raw(); + InstImm* i0 = (InstImm*) inst; + InstImm* i1 = (InstImm*) i0->next(); + InstImm* i3 = (InstImm*) i1->next()->next(); + Instruction* i4 = (Instruction*) i3->next(); + + MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift)); + MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); + MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); + + if (enabled) { + MOZ_ASSERT(i4->extractOpcode() != ((uint32_t)op_lui >> OpcodeShift)); + InstReg jalr = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr); + *i4 = jalr; + } else { + InstNOP nop; + *i4 = nop; + } + + AutoFlushICache::flush(uintptr_t(i4), sizeof(uint32_t)); +} + +void +Assembler::UpdateBoundsCheck(uint64_t heapSize, Instruction* inst) +{ + // Replace with new value + Assembler::UpdateLoad64Value(inst, heapSize); +}
new file mode 100644 --- /dev/null +++ b/js/src/jit/mips64/Assembler-mips64.h @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_mips64_Assembler_mips64_h +#define jit_mips64_Assembler_mips64_h + +// NOTE: Don't use these macros directly +// CallTempNonArgRegs +#define CALL_TEMP_NON_ARG_REGS \ + { t0, t1, t2, t3 }; +// NumIntArgRegs +#define NUM_INT_ARG_REGS 8; + +#include "jit/mips-shared/Assembler-mips-shared.h" + +#include "jit/mips64/Architecture-mips64.h" + +namespace js { +namespace jit { + +static MOZ_CONSTEXPR_VAR Register CallTempReg4 = a4; +static MOZ_CONSTEXPR_VAR Register CallTempReg5 = a5; + +class ABIArgGenerator +{ + unsigned usedArgSlots_; + bool firstArgFloat; + ABIArg current_; + + public: + ABIArgGenerator(); + ABIArg next(MIRType argType); + ABIArg& current() { return current_; } + + uint32_t stackBytesConsumedSoFar() const { + if (usedArgSlots_ <= 8) + return 0; + + return (usedArgSlots_ - 8) * sizeof(int64_t); + } + + static const Register NonArgReturnReg0; + static const Register NonArgReturnReg1; + static const Register NonArg_VolatileReg; + static const Register NonReturn_VolatileReg0; + static const Register NonReturn_VolatileReg1; +}; + +static MOZ_CONSTEXPR_VAR Register JSReturnReg = v1; +static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = JSReturnReg; +static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = JSReturnReg; +static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::f0, FloatRegisters::Single }; +static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::f0, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::f23, FloatRegisters::Single }; +static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::f23, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloat32Reg = { FloatRegisters::f21, FloatRegisters::Single }; +static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchDoubleReg = { FloatRegisters::f21, FloatRegisters::Double }; + +// Registers used in the GenerateFFIIonExit Disable Activation block. +// None of these may be the second scratch register (t8). +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = JSReturnReg_Data; +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = JSReturnReg_Type; + +static MOZ_CONSTEXPR_VAR FloatRegister f0 = { FloatRegisters::f0, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f1 = { FloatRegisters::f1, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f2 = { FloatRegisters::f2, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f3 = { FloatRegisters::f3, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f4 = { FloatRegisters::f4, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f5 = { FloatRegisters::f5, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f6 = { FloatRegisters::f6, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f7 = { FloatRegisters::f7, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f8 = { FloatRegisters::f8, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f9 = { FloatRegisters::f9, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f10 = { FloatRegisters::f10, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f11 = { FloatRegisters::f11, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f12 = { FloatRegisters::f12, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f13 = { FloatRegisters::f13, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f14 = { FloatRegisters::f14, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f15 = { FloatRegisters::f15, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f16 = { FloatRegisters::f16, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f17 = { FloatRegisters::f17, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f18 = { FloatRegisters::f18, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f19 = { FloatRegisters::f19, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f20 = { FloatRegisters::f20, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f21 = { FloatRegisters::f21, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f22 = { FloatRegisters::f22, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f23 = { FloatRegisters::f23, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f24 = { FloatRegisters::f24, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f25 = { FloatRegisters::f25, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f26 = { FloatRegisters::f26, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f27 = { FloatRegisters::f27, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f28 = { FloatRegisters::f28, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f29 = { FloatRegisters::f29, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f30 = { FloatRegisters::f30, FloatRegisters::Double }; +static MOZ_CONSTEXPR_VAR FloatRegister f31 = { FloatRegisters::f31, FloatRegisters::Double }; + +// MIPS64 CPUs can only load multibyte data that is "naturally" +// eight-byte-aligned, sp register should be sixteen-byte-aligned. +static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 16; +static MOZ_CONSTEXPR_VAR uint32_t JitStackAlignment = 16; + +static MOZ_CONSTEXPR_VAR uint32_t JitStackValueAlignment = JitStackAlignment / sizeof(Value); +static_assert(JitStackAlignment % sizeof(Value) == 0 && JitStackValueAlignment >= 1, + "Stack alignment should be a non-zero multiple of sizeof(Value)"); + +// TODO this is just a filler to prevent a build failure. The MIPS SIMD +// alignment requirements still need to be explored. +// TODO Copy the static_asserts from x64/x86 assembler files. +static MOZ_CONSTEXPR_VAR uint32_t SimdMemoryAlignment = 16; + +static MOZ_CONSTEXPR_VAR uint32_t AsmJSStackAlignment = SimdMemoryAlignment; + +static MOZ_CONSTEXPR_VAR Scale ScalePointer = TimesEight; + +class Assembler : public AssemblerMIPSShared +{ + public: + Assembler() + : AssemblerMIPSShared() + { } + + // MacroAssemblers hold onto gcthings, so they are traced by the GC. + void trace(JSTracer* trc); + + static uintptr_t GetPointer(uint8_t*); + + using AssemblerMIPSShared::bind; + using AssemblerMIPSShared::PatchDataWithValueCheck; + + void bind(RepatchLabel* label); + void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address); + + static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); + static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); + + void bind(InstImm* inst, uint64_t branch, uint64_t target); + + // Copy the assembly code to the given buffer, and perform any pending + // relocations relying on the target address. + void executableCopy(uint8_t* buffer); + + static uint32_t PatchWrite_NearCallSize(); + + static uint64_t ExtractLoad64Value(Instruction* inst0); + static void UpdateLoad64Value(Instruction* inst0, uint64_t value); + static void WriteLoad64Instructions(Instruction* inst0, Register reg, uint64_t value); + + + static void PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall); + static void PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue, + PatchedImmPtr expectedValue); + + static void PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm); + + static void ToggleCall(CodeLocationLabel inst_, bool enabled); + + static void UpdateBoundsCheck(uint64_t logHeapSize, Instruction* inst); + static int64_t ExtractCodeLabelOffset(uint8_t* code); +}; // Assembler + +static const uint32_t NumFloatArgRegs = NumIntArgRegs; + +static inline bool +GetFloatArgReg(uint32_t usedArgSlots, FloatRegister* out) +{ + if (usedArgSlots < NumFloatArgRegs) { + *out = FloatRegister::FromCode(f12.code() + usedArgSlots); + return true; + } + return false; +} + +static inline uint32_t +GetArgStackDisp(uint32_t usedArgSlots) +{ + MOZ_ASSERT(usedArgSlots >= NumIntArgRegs); + return (usedArgSlots - NumIntArgRegs) * sizeof(int64_t); +} + +} // namespace jit +} // namespace js + +#endif /* jit_mips64_Assembler_mips64_h */
new file mode 100644 --- /dev/null +++ b/js/src/jit/mips64/Bailouts-mips64.cpp @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jscntxt.h" +#include "jscompartment.h" + +#include "jit/mips-shared/Bailouts-mips-shared.h" + +using namespace js; +using namespace js::jit; + +BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations, + BailoutStack* bailout) + : machine_(bailout->machine()) +{ + uint8_t* sp = bailout->parentStackPointer(); + framePointer_ = sp + bailout->frameSize(); + topFrameSize_ = framePointer_ - sp; + + JSScript* script = ScriptFromCalleeToken(((JitFrameLayout*) framePointer_)->calleeToken()); + topIonScript_ = script->ionScript(); + + attachOnJitActivation(activations); + snapshotOffset_ = bailout->snapshotOffset(); +}
new file mode 100644 --- /dev/null +++ b/js/src/jit/mips64/BaselineCompiler-mips64.cpp @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/mips64/BaselineCompiler-mips64.h" + +using namespace js; +using namespace js::jit; + +BaselineCompilerMIPS64::BaselineCompilerMIPS64(JSContext* cx, TempAllocator& alloc, + JSScript* script) + : BaselineCompilerMIPSShared(cx, alloc, script) +{ +}
new file mode 100644 --- /dev/null +++ b/js/src/jit/mips64/BaselineCompiler-mips64.h @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_mips64_BaselineCompiler_mips64_h +#define jit_mips64_BaselineCompiler_mips64_h + +#include "jit/mips-shared/BaselineCompiler-mips-shared.h" + +namespace js { +namespace jit { + +class BaselineCompilerMIPS64 : public BaselineCompilerMIPSShared +{ + protected: + BaselineCompilerMIPS64(JSContext* cx, TempAllocator& alloc, JSScript* script); +}; + +typedef BaselineCompilerMIPS64 BaselineCompilerSpecific; + +} // namespace jit +} // namespace js + +#endif /* jit_mips64_BaselineCompiler_mips64_h */
new file mode 100644 --- /dev/null +++ b/js/src/jit/mips64/BaselineIC-mips64.cpp @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/BaselineCompiler.h" +#include "jit/BaselineIC.h" +#include "jit/BaselineJIT.h" +#include "jit/Linker.h" +#include "jit/SharedICHelpers.h" + +using namespace js; +using namespace js::jit; + +namespace js { +namespace jit { + +// ICCompare_Int32 + +bool +ICCompare_Int32::Compiler::generateStubCode(MacroAssembler& masm) +{ + // Guard that R0 is an integer and R1 is an integer. + Label failure; + Label conditionTrue; + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); + masm.branchTestInt32(Assembler::NotEqual, R1, &failure); + + // Compare payload regs of R0 and R1. + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); + masm.ma_cmp_set(R0.valueReg(), ExtractTemp0, ExtractTemp1, cond); + + masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.valueReg(), R0); + EmitReturnFromIC(masm); + + // Failure case - jump to next stub + masm.bind(&failure); + EmitStubGuardFailure(masm); + + return true; +} + +} // namespace jit +} // namespace js
--- a/js/src/jsapi-tests/testStructuredClone.cpp +++ b/js/src/jsapi-tests/testStructuredClone.cpp @@ -73,8 +73,156 @@ BEGIN_TEST(testStructuredClone_string) JS::RootedValue expected(cx, JS::StringValue( JS_NewStringCopyZ(cx, "Hello World!"))); CHECK_SAME(v2, expected); } return true; } END_TEST(testStructuredClone_string) + +struct StructuredCloneTestPrincipals final : public JSPrincipals { + uint32_t rank; + + explicit StructuredCloneTestPrincipals(uint32_t rank, int32_t rc = 1) : rank(rank) { + this->refcount = rc; + } + + bool write(JSContext* cx, JSStructuredCloneWriter* writer) override { + return JS_WriteUint32Pair(writer, rank, 0); + } + + static bool read(JSContext* cx, JSStructuredCloneReader *reader, JSPrincipals** outPrincipals) { + uint32_t rank; + uint32_t unused; + if (!JS_ReadUint32Pair(reader, &rank, &unused)) + return false; + + *outPrincipals = new StructuredCloneTestPrincipals(rank); + return !!*outPrincipals; + } + + static void destroy(JSPrincipals* p) { + auto p1 = static_cast<StructuredCloneTestPrincipals*>(p); + delete p1; + } + + static uint32_t getRank(JSPrincipals* p) { + if (!p) + return 0; + return static_cast<StructuredCloneTestPrincipals*>(p)->rank; + } + + static bool subsumes(JSPrincipals* a, JSPrincipals* b) { + return getRank(a) > getRank(b); + } + + static JSSecurityCallbacks securityCallbacks; + + static StructuredCloneTestPrincipals testPrincipals; +}; + +JSSecurityCallbacks StructuredCloneTestPrincipals::securityCallbacks = { + nullptr, // contentSecurityPolicyAllows + subsumes +}; + +BEGIN_TEST(testStructuredClone_SavedFrame) +{ + JS_SetSecurityCallbacks(rt, &StructuredCloneTestPrincipals::securityCallbacks); + JS_InitDestroyPrincipalsCallback(rt, StructuredCloneTestPrincipals::destroy); + JS_InitReadPrincipalsCallback(rt, StructuredCloneTestPrincipals::read); + + auto testPrincipals = new StructuredCloneTestPrincipals(42, 0); + CHECK(testPrincipals); + + auto DONE = (JSPrincipals*) 0xDEADBEEF; + + struct { + const char* name; + JSPrincipals* principals; + } principalsToTest[] = { + { "IsSystem", &js::ReconstructedSavedFramePrincipals::IsSystem }, + { "IsNotSystem", &js::ReconstructedSavedFramePrincipals::IsNotSystem }, + { "testPrincipals", testPrincipals }, + { "nullptr principals", nullptr }, + { "DONE", DONE } + }; + + const char* FILENAME = "filename.js"; + + for (auto* pp = principalsToTest; pp->principals != DONE; pp++) { + fprintf(stderr, "Testing with principals '%s'\n", pp->name); + + JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), pp->principals, + JS::FireOnNewGlobalHook)); + CHECK(g); + JSAutoCompartment ac(cx, g); + + CHECK(js::DefineTestingFunctions(cx, g, false, false)); + + JS::RootedValue srcVal(cx); + CHECK(evaluate("(function one() { \n" // 1 + " return (function two() { \n" // 2 + " return (function three() { \n" // 3 + " return saveStack(); \n" // 4 + " }()); \n" // 5 + " }()); \n" // 6 + "}()); \n", // 7 + FILENAME, + 1, + &srcVal)); + + CHECK(srcVal.isObject()); + JS::RootedObject srcObj(cx, &srcVal.toObject()); + + CHECK(srcObj->is<js::SavedFrame>()); + js::RootedSavedFrame srcFrame(cx, &srcObj->as<js::SavedFrame>()); + + CHECK(srcFrame->getPrincipals() == pp->principals); + + JS::RootedValue destVal(cx); + CHECK(JS_StructuredClone(cx, srcVal, &destVal, nullptr, nullptr)); + + CHECK(destVal.isObject()); + JS::RootedObject destObj(cx, &destVal.toObject()); + + CHECK(destObj->is<js::SavedFrame>()); + auto destFrame = &destObj->as<js::SavedFrame>(); + + size_t framesCopied = 0; + for (auto& f : *destFrame) { + framesCopied++; + + CHECK(&f != srcFrame); + + if (pp->principals == testPrincipals) { + // We shouldn't get a pointer to the same + // StructuredCloneTestPrincipals instance since we should have + // serialized and then deserialized it into a new instance. + CHECK(f.getPrincipals() != pp->principals); + + // But it should certainly have the same rank. + CHECK(StructuredCloneTestPrincipals::getRank(f.getPrincipals()) == + StructuredCloneTestPrincipals::getRank(pp->principals)); + } else { + // For our singleton principals, we should always get the same + // pointer back. + CHECK(js::ReconstructedSavedFramePrincipals::is(pp->principals) || + pp->principals == nullptr); + CHECK(f.getPrincipals() == pp->principals); + } + + CHECK(EqualStrings(f.getSource(), srcFrame->getSource())); + CHECK(f.getLine() == srcFrame->getLine()); + CHECK(f.getColumn() == srcFrame->getColumn()); + CHECK(EqualStrings(f.getFunctionDisplayName(), srcFrame->getFunctionDisplayName())); + + srcFrame = srcFrame->getParent(); + } + + // Four function frames + one global frame. + CHECK(framesCopied == 4); + } + + return true; +} +END_TEST(testStructuredClone_SavedFrame)
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1959,44 +1959,16 @@ JS_SetPrivate(JSObject* obj, void* data) JS_PUBLIC_API(void*) JS_GetInstancePrivate(JSContext* cx, HandleObject obj, const JSClass* clasp, CallArgs* args) { if (!JS_InstanceOf(cx, obj, clasp, args)) return nullptr; return obj->as<NativeObject>().getPrivate(); } -JS_PUBLIC_API(bool) -JS_GetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> protop) -{ - return GetPrototype(cx, obj, protop); -} - -JS_PUBLIC_API(bool) -JS_SetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> proto) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, proto); - - return SetPrototype(cx, obj, proto); -} - -JS_PUBLIC_API(bool) -JS_IsExtensible(JSContext* cx, HandleObject obj, bool* extensible) -{ - return IsExtensible(cx, obj, extensible); -} - -JS_PUBLIC_API(bool) -JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, ObjectOpResult& result) -{ - return PreventExtensions(cx, obj, result); -} - JS_PUBLIC_API(JSObject*) JS_GetConstructor(JSContext* cx, HandleObject proto) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, proto); RootedValue cval(cx); @@ -2161,159 +2133,128 @@ JS_IsNative(JSObject* obj) } JS_PUBLIC_API(JSRuntime*) JS_GetObjectRuntime(JSObject* obj) { return obj->compartment()->runtimeFromMainThread(); } -JS_PUBLIC_API(bool) -JS_FreezeObject(JSContext* cx, HandleObject obj) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - return FreezeObject(cx, obj); -} - -JS_PUBLIC_API(bool) -JS_DeepFreezeObject(JSContext* cx, HandleObject obj) + +/*** Standard internal methods *******************************************************************/ + +JS_PUBLIC_API(bool) +JS_GetPrototype(JSContext* cx, HandleObject obj, MutableHandleObject result) +{ + return GetPrototype(cx, obj, result); +} + +JS_PUBLIC_API(bool) +JS_SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - - /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */ - bool extensible; - if (!IsExtensible(cx, obj, &extensible)) - return false; - if (!extensible) - return true; - - if (!FreezeObject(cx, obj)) - return false; - - /* Walk slots in obj and if any value is a non-null object, seal it. */ - if (obj->isNative()) { - for (uint32_t i = 0, n = obj->as<NativeObject>().slotSpan(); i < n; ++i) { - const Value& v = obj->as<NativeObject>().getSlot(i); - if (v.isPrimitive()) - continue; - RootedObject obj(cx, &v.toObject()); - if (!JS_DeepFreezeObject(cx, obj)) - return false; - } - } - - return true; -} - -JS_PUBLIC_API(bool) -JS_HasPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) + assertSameCompartment(cx, obj, proto); + + return SetPrototype(cx, obj, proto); +} + +JS_PUBLIC_API(bool) +JS_IsExtensible(JSContext* cx, HandleObject obj, bool* extensible) +{ + return IsExtensible(cx, obj, extensible); +} + +JS_PUBLIC_API(bool) +JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, ObjectOpResult& result) +{ + return PreventExtensions(cx, obj, result); +} + +JS_PUBLIC_API(bool) +JS_SetImmutablePrototype(JSContext *cx, JS::HandleObject obj, bool *succeeded) +{ + return SetImmutablePrototype(cx, obj, succeeded); +} + +JS_PUBLIC_API(bool) +JS_GetOwnPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, + MutableHandle<JSPropertyDescriptor> desc) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - return HasProperty(cx, obj, id, foundp); -} - -JS_PUBLIC_API(bool) -JS_HasElement(JSContext* cx, HandleObject obj, uint32_t index, bool* foundp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - RootedId id(cx); - if (!IndexToId(cx, index, &id)) - return false; - return JS_HasPropertyById(cx, obj, id, foundp); -} - -JS_PUBLIC_API(bool) -JS_HasProperty(JSContext* cx, HandleObject obj, const char* name, bool* foundp) + return GetOwnPropertyDescriptor(cx, obj, id, desc); +} + +JS_PUBLIC_API(bool) +JS_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, + MutableHandle<JSPropertyDescriptor> desc) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) return false; RootedId id(cx, AtomToId(atom)); - return JS_HasPropertyById(cx, obj, id, foundp); -} - -#define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) - -JS_PUBLIC_API(bool) -JS_HasUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, bool* foundp) -{ - JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); +} + +JS_PUBLIC_API(bool) +JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, + MutableHandle<JSPropertyDescriptor> desc) +{ + JSAtom* atom = AtomizeChars(cx, name, js_strlen(name)); if (!atom) return false; RootedId id(cx, AtomToId(atom)); - return JS_HasPropertyById(cx, obj, id, foundp); -} - -JS_PUBLIC_API(bool) -JS_AlreadyHasOwnPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id); - - if (!obj->isNative()) - return js::HasOwnProperty(cx, obj, id, foundp); - - RootedNativeObject nativeObj(cx, &obj->as<NativeObject>()); - RootedShape prop(cx); - NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop); - *foundp = !!prop; - return true; -} - -JS_PUBLIC_API(bool) -JS_AlreadyHasOwnElement(JSContext* cx, HandleObject obj, uint32_t index, bool* foundp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - RootedId id(cx); - if (!IndexToId(cx, index, &id)) - return false; - return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); -} - -JS_PUBLIC_API(bool) -JS_AlreadyHasOwnProperty(JSContext* cx, HandleObject obj, const char* name, bool* foundp) + return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); +} + +JS_PUBLIC_API(bool) +JS_GetPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, + MutableHandle<JSPropertyDescriptor> desc) +{ + return GetPropertyDescriptor(cx, obj, id, desc); +} + +JS_PUBLIC_API(bool) +JS_GetPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, + MutableHandle<JSPropertyDescriptor> desc) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) return false; RootedId id(cx, AtomToId(atom)); - return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); -} - -JS_PUBLIC_API(bool) -JS_AlreadyHasOwnUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - bool* foundp) -{ - JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); -} - -/* - * Wrapper functions to create wrappers with no corresponding JSJitInfo from API - * function arguments. - */ -static JSNativeWrapper -NativeOpWrapper(Native native) -{ - JSNativeWrapper ret; - ret.op = native; - ret.info = nullptr; - return ret; + return atom && JS_GetPropertyDescriptorById(cx, obj, id, desc); +} + +static bool +DefinePropertyByDescriptor(JSContext* cx, HandleObject obj, HandleId id, + Handle<JSPropertyDescriptor> desc, ObjectOpResult& result) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id, desc); + return DefineProperty(cx, obj, id, desc.value(), desc.getter(), desc.setter(), + desc.attributes(), result); +} + +JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, + Handle<JSPropertyDescriptor> desc, ObjectOpResult& result) +{ + return DefinePropertyByDescriptor(cx, obj, id, desc, result); +} + +JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, + Handle<JSPropertyDescriptor> desc) +{ + ObjectOpResult result; + return DefinePropertyByDescriptor(cx, obj, id, desc, result) && + result.checkStrict(cx, obj, id); } static bool DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, HandleValue value, const JSNativeWrapper& get, const JSNativeWrapper& set, unsigned attrs, unsigned flags) { JSGetterOp getter = JS_CAST_NATIVE_TO(get.op, JSGetterOp); @@ -2401,16 +2342,29 @@ DefinePropertyById(JSContext* cx, Handle } if (getter == JS_PropertyStub) getter = nullptr; if (setter == JS_StrictPropertyStub) setter = nullptr; return DefineProperty(cx, obj, id, value, getter, setter, attrs); } +/* + * Wrapper functions to create wrappers with no corresponding JSJitInfo from API + * function arguments. + */ +static JSNativeWrapper +NativeOpWrapper(Native native) +{ + JSNativeWrapper ret; + ret.op = native; + ret.info = nullptr; + return ret; +} + JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, HandleValue value, unsigned attrs, Native getter, Native setter) { return DefinePropertyById(cx, obj, id, value, NativeOpWrapper(getter), NativeOpWrapper(setter), attrs, 0); } @@ -2458,43 +2412,183 @@ JS_DefinePropertyById(JSContext* cx, Han unsigned attrs, Native getter, Native setter) { Value value = NumberValue(valueArg); return DefinePropertyById(cx, obj, id, HandleValue::fromMarkedLocation(&value), NativeOpWrapper(getter), NativeOpWrapper(setter), attrs, 0); } static bool -DefinePropertyByDescriptor(JSContext* cx, HandleObject obj, HandleId id, - Handle<JSPropertyDescriptor> desc, ObjectOpResult& result) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id, desc); - return DefineProperty(cx, obj, id, desc.value(), desc.getter(), desc.setter(), - desc.attributes(), result); -} - -JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, - Handle<JSPropertyDescriptor> desc, ObjectOpResult& result) -{ +DefineProperty(JSContext* cx, HandleObject obj, const char* name, HandleValue value, + const JSNativeWrapper& getter, const JSNativeWrapper& setter, + unsigned attrs, unsigned flags) +{ + AutoRooterGetterSetter gsRoot(cx, attrs, const_cast<JSNative*>(&getter.op), + const_cast<JSNative*>(&setter.op)); + + JSAtom* atom = Atomize(cx, name, strlen(name)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + + return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags); +} + +JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, HandleValue value, + unsigned attrs, + Native getter /* = nullptr */, Native setter /* = nullptr */) +{ + return DefineProperty(cx, obj, name, value, NativeOpWrapper(getter), NativeOpWrapper(setter), + attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, HandleObject valueArg, + unsigned attrs, + Native getter /* = nullptr */, Native setter /* = nullptr */) +{ + RootedValue value(cx, ObjectValue(*valueArg)); + return DefineProperty(cx, obj, name, value, NativeOpWrapper(getter), NativeOpWrapper(setter), + attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, HandleString valueArg, + unsigned attrs, + Native getter /* = nullptr */, Native setter /* = nullptr */) +{ + RootedValue value(cx, StringValue(valueArg)); + return DefineProperty(cx, obj, name, value, NativeOpWrapper(getter), NativeOpWrapper(setter), + attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, int32_t valueArg, + unsigned attrs, + Native getter /* = nullptr */, Native setter /* = nullptr */) +{ + Value value = Int32Value(valueArg); + return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), + NativeOpWrapper(getter), NativeOpWrapper(setter), attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, uint32_t valueArg, + unsigned attrs, + Native getter /* = nullptr */, Native setter /* = nullptr */) +{ + Value value = NumberValue(valueArg); + return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), + NativeOpWrapper(getter), NativeOpWrapper(setter), attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, double valueArg, + unsigned attrs, + Native getter /* = nullptr */, Native setter /* = nullptr */) +{ + Value value = NumberValue(valueArg); + return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), + NativeOpWrapper(getter), NativeOpWrapper(setter), attrs, 0); +} + +#define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + Handle<JSPropertyDescriptor> desc, + ObjectOpResult& result) +{ + JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); return DefinePropertyByDescriptor(cx, obj, id, desc, result); } JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, - Handle<JSPropertyDescriptor> desc) -{ +JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + Handle<JSPropertyDescriptor> desc) +{ + JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); ObjectOpResult result; return DefinePropertyByDescriptor(cx, obj, id, desc, result) && result.checkStrict(cx, obj, id); } static bool +DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + const Value& value_, Native getter, Native setter, unsigned attrs, + unsigned flags) +{ + RootedValue value(cx, value_); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); + JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return DefinePropertyById(cx, obj, id, value, NativeOpWrapper(getter), NativeOpWrapper(setter), + attrs, flags); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + HandleValue value, unsigned attrs, Native getter, Native setter) +{ + return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + HandleObject valueArg, unsigned attrs, Native getter, Native setter) +{ + RootedValue value(cx, ObjectValue(*valueArg)); + return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + HandleString valueArg, unsigned attrs, Native getter, Native setter) +{ + RootedValue value(cx, StringValue(valueArg)); + return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + int32_t valueArg, unsigned attrs, Native getter, Native setter) +{ + Value value = Int32Value(valueArg); + return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), + getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + uint32_t valueArg, unsigned attrs, Native getter, Native setter) +{ + Value value = NumberValue(valueArg); + return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), + getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + double valueArg, unsigned attrs, Native getter, Native setter) +{ + Value value = NumberValue(valueArg); + return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), + getter, setter, attrs, 0); +} + +static bool DefineElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue value, unsigned attrs, Native getter, Native setter) { AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); AssertHeapIsIdle(cx); CHECK_REQUEST(cx); RootedId id(cx); if (!IndexToId(cx, index, &id)) @@ -2549,30 +2643,546 @@ JS_PUBLIC_API(bool) JS_DefineElement(JSContext* cx, HandleObject obj, uint32_t index, double valueArg, unsigned attrs, Native getter, Native setter) { Value value = NumberValue(valueArg); return DefineElement(cx, obj, index, HandleValue::fromMarkedLocation(&value), attrs, getter, setter); } +JS_PUBLIC_API(bool) +JS_HasPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + + return HasProperty(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_HasProperty(JSContext* cx, HandleObject obj, const char* name, bool* foundp) +{ + JSAtom* atom = Atomize(cx, name, strlen(name)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_HasPropertyById(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_HasUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, bool* foundp) +{ + JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_HasPropertyById(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_HasElement(JSContext* cx, HandleObject obj, uint32_t index, bool* foundp) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + RootedId id(cx); + if (!IndexToId(cx, index, &id)) + return false; + return JS_HasPropertyById(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_HasOwnPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + + return HasOwnProperty(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_HasOwnProperty(JSContext* cx, HandleObject obj, const char* name, bool* foundp) +{ + JSAtom* atom = Atomize(cx, name, strlen(name)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_HasOwnPropertyById(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_ForwardGetPropertyTo(JSContext* cx, HandleObject obj, HandleId id, HandleValue receiver, + MutableHandleValue vp) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id, receiver); + + return GetProperty(cx, obj, receiver, id, vp); +} + +JS_PUBLIC_API(bool) +JS_ForwardGetElementTo(JSContext* cx, HandleObject obj, uint32_t index, HandleObject receiver, + MutableHandleValue vp) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + return GetElement(cx, obj, receiver, index, vp); +} + +JS_PUBLIC_API(bool) +JS_GetPropertyById(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp) +{ + RootedValue receiver(cx, ObjectValue(*obj)); + return JS_ForwardGetPropertyTo(cx, obj, id, receiver, vp); +} + +JS_PUBLIC_API(bool) +JS_GetProperty(JSContext* cx, HandleObject obj, const char* name, MutableHandleValue vp) +{ + JSAtom* atom = Atomize(cx, name, strlen(name)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_GetPropertyById(cx, obj, id, vp); +} + +JS_PUBLIC_API(bool) +JS_GetUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + MutableHandleValue vp) +{ + JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_GetPropertyById(cx, obj, id, vp); +} + +JS_PUBLIC_API(bool) +JS_GetElement(JSContext* cx, HandleObject objArg, uint32_t index, MutableHandleValue vp) +{ + return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp); +} + +JS_PUBLIC_API(bool) +JS_ForwardSetPropertyTo(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, + HandleValue receiver, ObjectOpResult& result) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id, receiver); + + return SetProperty(cx, obj, id, v, receiver, result); +} + +JS_PUBLIC_API(bool) +JS_SetPropertyById(JSContext* cx, HandleObject obj, HandleId id, HandleValue v) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + + RootedValue receiver(cx, ObjectValue(*obj)); + ObjectOpResult ignored; + return SetProperty(cx, obj, id, v, receiver, ignored); +} + +JS_PUBLIC_API(bool) +JS_SetProperty(JSContext* cx, HandleObject obj, const char* name, HandleValue v) +{ + JSAtom* atom = Atomize(cx, name, strlen(name)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_SetPropertyById(cx, obj, id, v); +} + +JS_PUBLIC_API(bool) +JS_SetUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + HandleValue v) +{ + JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_SetPropertyById(cx, obj, id, v); +} + static bool -DefineProperty(JSContext* cx, HandleObject obj, const char* name, HandleValue value, - const JSNativeWrapper& getter, const JSNativeWrapper& setter, - unsigned attrs, unsigned flags) -{ - AutoRooterGetterSetter gsRoot(cx, attrs, const_cast<JSNative*>(&getter.op), - const_cast<JSNative*>(&setter.op)); +SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, v); + + RootedValue receiver(cx, ObjectValue(*obj)); + ObjectOpResult ignored; + return SetElement(cx, obj, index, v, receiver, ignored); +} + +JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v) +{ + return SetElement(cx, obj, index, v); +} + +JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleObject v) +{ + RootedValue value(cx, ObjectOrNullValue(v)); + return SetElement(cx, obj, index, value); +} + +JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleString v) +{ + RootedValue value(cx, StringValue(v)); + return SetElement(cx, obj, index, value); +} + +JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, int32_t v) +{ + RootedValue value(cx, NumberValue(v)); + return SetElement(cx, obj, index, value); +} + +JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, uint32_t v) +{ + RootedValue value(cx, NumberValue(v)); + return SetElement(cx, obj, index, value); +} + +JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, double v) +{ + RootedValue value(cx, NumberValue(v)); + return SetElement(cx, obj, index, value); +} + +JS_PUBLIC_API(bool) +JS_DeletePropertyById(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + + return DeleteProperty(cx, obj, id, result); +} + +JS_PUBLIC_API(bool) +JS_DeleteProperty(JSContext* cx, HandleObject obj, const char* name, ObjectOpResult& result) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) return false; RootedId id(cx, AtomToId(atom)); - - return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags); + return DeleteProperty(cx, obj, id, result); +} + +JS_PUBLIC_API(bool) +JS_DeleteUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + ObjectOpResult& result) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return DeleteProperty(cx, obj, id, result); +} + +JS_PUBLIC_API(bool) +JS_DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& result) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + return DeleteElement(cx, obj, index, result); +} + +JS_PUBLIC_API(bool) +JS_DeletePropertyById(JSContext* cx, HandleObject obj, HandleId id) +{ + ObjectOpResult ignored; + return JS_DeletePropertyById(cx, obj, id, ignored); +} + +JS_PUBLIC_API(bool) +JS_DeleteProperty(JSContext* cx, HandleObject obj, const char* name) +{ + ObjectOpResult ignored; + return JS_DeleteProperty(cx, obj, name, ignored); +} + +JS_PUBLIC_API(bool) +JS_DeleteElement(JSContext* cx, HandleObject obj, uint32_t index) +{ + ObjectOpResult ignored; + return JS_DeleteElement(cx, obj, index, ignored); +} + +JS_PUBLIC_API(bool) +JS_Enumerate(JSContext* cx, HandleObject obj, JS::MutableHandle<IdVector> props) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + MOZ_ASSERT(props.empty()); + + AutoIdVector ids(cx); + if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids)) + return false; + + return props.append(ids.begin(), ids.end()); +} + +JS_PUBLIC_API(bool) +JS::IsCallable(JSObject* obj) +{ + return obj->isCallable(); +} + +JS_PUBLIC_API(bool) +JS::IsConstructor(JSObject* obj) +{ + return obj->isConstructor(); +} + +struct AutoLastFrameCheck +{ + explicit AutoLastFrameCheck(JSContext* cx + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : cx(cx) + { + MOZ_ASSERT(cx); + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + ~AutoLastFrameCheck() { + if (cx->isExceptionPending() && + !JS_IsRunning(cx) && + (!cx->options().dontReportUncaught() && !cx->options().autoJSAPIOwnsErrorReporting())) { + ReportUncaughtException(cx); + } + } + + private: + JSContext* cx; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +JS_PUBLIC_API(bool) +JS_CallFunctionValue(JSContext* cx, HandleObject obj, HandleValue fval, const HandleValueArray& args, + MutableHandleValue rval) +{ + MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, fval, args); + AutoLastFrameCheck lfc(cx); + + return Invoke(cx, ObjectOrNullValue(obj), fval, args.length(), args.begin(), rval); +} + +JS_PUBLIC_API(bool) +JS_CallFunction(JSContext* cx, HandleObject obj, HandleFunction fun, const HandleValueArray& args, + MutableHandleValue rval) +{ + MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, fun, args); + AutoLastFrameCheck lfc(cx); + + return Invoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), args.length(), args.begin(), rval); +} + +JS_PUBLIC_API(bool) +JS_CallFunctionName(JSContext* cx, HandleObject obj, const char* name, const HandleValueArray& args, + MutableHandleValue rval) +{ + MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, args); + AutoLastFrameCheck lfc(cx); + + JSAtom* atom = Atomize(cx, name, strlen(name)); + if (!atom) + return false; + + RootedValue v(cx); + RootedId id(cx, AtomToId(atom)); + if (!GetProperty(cx, obj, obj, id, &v)) + return false; + + return Invoke(cx, ObjectOrNullValue(obj), v, args.length(), args.begin(), rval); +} + +JS_PUBLIC_API(bool) +JS::Call(JSContext* cx, HandleValue thisv, HandleValue fval, const JS::HandleValueArray& args, + MutableHandleValue rval) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, thisv, fval, args); + AutoLastFrameCheck lfc(cx); + + return Invoke(cx, thisv, fval, args.length(), args.begin(), rval); +} + +JS_PUBLIC_API(bool) +JS::Construct(JSContext* cx, HandleValue fval, HandleObject newTarget, const JS::HandleValueArray& args, + MutableHandleValue rval) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, fval, newTarget, args); + AutoLastFrameCheck lfc(cx); + + if (!IsConstructor(fval)) { + ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr); + return false; + } + + RootedValue newTargetVal(cx, ObjectValue(*newTarget)); + if (!IsConstructor(newTargetVal)) { + ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, newTargetVal, nullptr); + return false; + } + + ConstructArgs cargs(cx); + if (!FillArgumentsFromArraylike(cx, cargs, args)) + return false; + + return js::Construct(cx, fval, cargs, newTargetVal, rval); +} + +JS_PUBLIC_API(bool) +JS::Construct(JSContext* cx, HandleValue fval, const JS::HandleValueArray& args, + MutableHandleValue rval) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, fval, args); + AutoLastFrameCheck lfc(cx); + + if (!IsConstructor(fval)) { + ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr); + return false; + } + + ConstructArgs cargs(cx); + if (!FillArgumentsFromArraylike(cx, cargs, args)) + return false; + + return js::Construct(cx, fval, cargs, fval, rval); +} + + +/* * */ + +JS_PUBLIC_API(bool) +JS_AlreadyHasOwnPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + + if (!obj->isNative()) + return js::HasOwnProperty(cx, obj, id, foundp); + + RootedNativeObject nativeObj(cx, &obj->as<NativeObject>()); + RootedShape prop(cx); + NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop); + *foundp = !!prop; + return true; +} + +JS_PUBLIC_API(bool) +JS_AlreadyHasOwnProperty(JSContext* cx, HandleObject obj, const char* name, bool* foundp) +{ + JSAtom* atom = Atomize(cx, name, strlen(name)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_AlreadyHasOwnUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + bool* foundp) +{ + JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_AlreadyHasOwnElement(JSContext* cx, HandleObject obj, uint32_t index, bool* foundp) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + RootedId id(cx); + if (!IndexToId(cx, index, &id)) + return false; + return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); +} + +JS_PUBLIC_API(bool) +JS_FreezeObject(JSContext* cx, HandleObject obj) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + return FreezeObject(cx, obj); +} + +JS_PUBLIC_API(bool) +JS_DeepFreezeObject(JSContext* cx, HandleObject obj) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */ + bool extensible; + if (!IsExtensible(cx, obj, &extensible)) + return false; + if (!extensible) + return true; + + if (!FreezeObject(cx, obj)) + return false; + + /* Walk slots in obj and if any value is a non-null object, seal it. */ + if (obj->isNative()) { + for (uint32_t i = 0, n = obj->as<NativeObject>().slotSpan(); i < n; ++i) { + const Value& v = obj->as<NativeObject>().getSlot(i); + if (v.isPrimitive()) + continue; + RootedObject obj(cx, &v.toObject()); + if (!JS_DeepFreezeObject(cx, obj)) + return false; + } + } + + return true; } static bool DefineSelfHostedProperty(JSContext* cx, HandleObject obj, HandleId id, const char* getterName, const char* setterName, unsigned attrs, unsigned flags) { JSAtom* getterNameAtom = Atomize(cx, getterName, strlen(getterName)); @@ -2612,171 +3222,16 @@ DefineSelfHostedProperty(JSContext* cx, } JSNative setterOp = JS_DATA_TO_FUNC_PTR(JSNative, setterFunc.get()); return DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue, NativeOpWrapper(getterOp), NativeOpWrapper(setterOp), attrs, flags); } -JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, HandleValue value, - unsigned attrs, - Native getter /* = nullptr */, Native setter /* = nullptr */) -{ - return DefineProperty(cx, obj, name, value, NativeOpWrapper(getter), NativeOpWrapper(setter), - attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, HandleObject valueArg, - unsigned attrs, - Native getter /* = nullptr */, Native setter /* = nullptr */) -{ - RootedValue value(cx, ObjectValue(*valueArg)); - return DefineProperty(cx, obj, name, value, NativeOpWrapper(getter), NativeOpWrapper(setter), - attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, HandleString valueArg, - unsigned attrs, - Native getter /* = nullptr */, Native setter /* = nullptr */) -{ - RootedValue value(cx, StringValue(valueArg)); - return DefineProperty(cx, obj, name, value, NativeOpWrapper(getter), NativeOpWrapper(setter), - attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, int32_t valueArg, - unsigned attrs, - Native getter /* = nullptr */, Native setter /* = nullptr */) -{ - Value value = Int32Value(valueArg); - return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), - NativeOpWrapper(getter), NativeOpWrapper(setter), attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, uint32_t valueArg, - unsigned attrs, - Native getter /* = nullptr */, Native setter /* = nullptr */) -{ - Value value = NumberValue(valueArg); - return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), - NativeOpWrapper(getter), NativeOpWrapper(setter), attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, double valueArg, - unsigned attrs, - Native getter /* = nullptr */, Native setter /* = nullptr */) -{ - Value value = NumberValue(valueArg); - return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), - NativeOpWrapper(getter), NativeOpWrapper(setter), attrs, 0); -} - -static bool -DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - const Value& value_, Native getter, Native setter, unsigned attrs, - unsigned flags) -{ - RootedValue value(cx, value_); - AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); - JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return DefinePropertyById(cx, obj, id, value, NativeOpWrapper(getter), NativeOpWrapper(setter), - attrs, flags); -} - -JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - HandleValue value, unsigned attrs, - Native getter, Native setter) -{ - return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - HandleObject valueArg, unsigned attrs, - Native getter, Native setter) -{ - RootedValue value(cx, ObjectValue(*valueArg)); - return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - HandleString valueArg, unsigned attrs, - Native getter, Native setter) -{ - RootedValue value(cx, StringValue(valueArg)); - return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - int32_t valueArg, unsigned attrs, - Native getter, Native setter) -{ - Value value = Int32Value(valueArg); - return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), - getter, setter, attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - uint32_t valueArg, unsigned attrs, - Native getter, Native setter) -{ - Value value = NumberValue(valueArg); - return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), - getter, setter, attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - double valueArg, unsigned attrs, - Native getter, Native setter) -{ - Value value = NumberValue(valueArg); - return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), - getter, setter, attrs, 0); -} - -JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - Handle<JSPropertyDescriptor> desc, - ObjectOpResult& result) -{ - JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return DefinePropertyByDescriptor(cx, obj, id, desc, result); -} - -JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - Handle<JSPropertyDescriptor> desc) -{ - JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - ObjectOpResult result; - return DefinePropertyByDescriptor(cx, obj, id, desc, result) && - result.checkStrict(cx, obj, id); -} - JS_PUBLIC_API(JSObject*) JS_DefineObject(JSContext* cx, HandleObject obj, const char* name, const JSClass* jsclasp, unsigned attrs) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); @@ -2907,314 +3362,16 @@ JS::ObjectToCompletePropertyDescriptor(J { if (!ToPropertyDescriptor(cx, descObj, true, desc)) return false; CompletePropertyDescriptor(desc); desc.object().set(obj); return true; } -JS_PUBLIC_API(bool) -JS_GetOwnPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle<JSPropertyDescriptor> desc) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - - return GetOwnPropertyDescriptor(cx, obj, id, desc); -} - -JS_PUBLIC_API(bool) -JS_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, - MutableHandle<JSPropertyDescriptor> desc) -{ - JSAtom* atom = Atomize(cx, name, strlen(name)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); -} - -JS_PUBLIC_API(bool) -JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, - MutableHandle<JSPropertyDescriptor> desc) -{ - JSAtom* atom = AtomizeChars(cx, name, js_strlen(name)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); -} - -JS_PUBLIC_API(bool) -JS_HasOwnPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id); - - return HasOwnProperty(cx, obj, id, foundp); -} - -JS_PUBLIC_API(bool) -JS_HasOwnProperty(JSContext* cx, HandleObject obj, const char* name, bool* foundp) -{ - JSAtom* atom = Atomize(cx, name, strlen(name)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return JS_HasOwnPropertyById(cx, obj, id, foundp); -} - -JS_PUBLIC_API(bool) -JS_GetPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle<JSPropertyDescriptor> desc) -{ - return GetPropertyDescriptor(cx, obj, id, desc); -} - -JS_PUBLIC_API(bool) -JS_GetPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, - MutableHandle<JSPropertyDescriptor> desc) -{ - JSAtom* atom = Atomize(cx, name, strlen(name)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return atom && JS_GetPropertyDescriptorById(cx, obj, id, desc); -} - -JS_PUBLIC_API(bool) -JS_GetPropertyById(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id); - - return GetProperty(cx, obj, obj, id, vp); -} - -JS_PUBLIC_API(bool) -JS_ForwardGetPropertyTo(JSContext* cx, HandleObject obj, HandleId id, HandleValue onBehalfOf, - MutableHandleValue vp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id, onBehalfOf); - - return GetProperty(cx, obj, onBehalfOf, id, vp); -} - -JS_PUBLIC_API(bool) -JS_GetElement(JSContext* cx, HandleObject obj, uint32_t index, MutableHandleValue vp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - - return GetElement(cx, obj, obj, index, vp); -} - -JS_PUBLIC_API(bool) -JS_ForwardGetElementTo(JSContext* cx, HandleObject obj, uint32_t index, HandleObject onBehalfOf, - MutableHandleValue vp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - - return GetElement(cx, obj, onBehalfOf, index, vp); -} - -JS_PUBLIC_API(bool) -JS_GetProperty(JSContext* cx, HandleObject obj, const char* name, MutableHandleValue vp) -{ - JSAtom* atom = Atomize(cx, name, strlen(name)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return JS_GetPropertyById(cx, obj, id, vp); -} - -JS_PUBLIC_API(bool) -JS_GetUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - MutableHandleValue vp) -{ - JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return JS_GetPropertyById(cx, obj, id, vp); -} - -JS_PUBLIC_API(bool) -JS_SetPropertyById(JSContext* cx, HandleObject obj, HandleId id, HandleValue v) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id); - - RootedValue receiver(cx, ObjectValue(*obj)); - ObjectOpResult ignored; - return SetProperty(cx, obj, id, v, receiver, ignored); -} - -JS_PUBLIC_API(bool) -JS_ForwardSetPropertyTo(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id, receiver); - - return SetProperty(cx, obj, id, v, receiver, result); -} - -static bool -SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, v); - - RootedValue receiver(cx, ObjectValue(*obj)); - ObjectOpResult ignored; - return SetElement(cx, obj, index, v, receiver, ignored); -} - -JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v) -{ - return SetElement(cx, obj, index, v); -} - -JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleObject v) -{ - RootedValue value(cx, ObjectOrNullValue(v)); - return SetElement(cx, obj, index, value); -} - -JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleString v) -{ - RootedValue value(cx, StringValue(v)); - return SetElement(cx, obj, index, value); -} - -JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, int32_t v) -{ - RootedValue value(cx, NumberValue(v)); - return SetElement(cx, obj, index, value); -} - -JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, uint32_t v) -{ - RootedValue value(cx, NumberValue(v)); - return SetElement(cx, obj, index, value); -} - -JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, HandleObject obj, uint32_t index, double v) -{ - RootedValue value(cx, NumberValue(v)); - return SetElement(cx, obj, index, value); -} - -JS_PUBLIC_API(bool) -JS_SetProperty(JSContext* cx, HandleObject obj, const char* name, HandleValue v) -{ - JSAtom* atom = Atomize(cx, name, strlen(name)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return JS_SetPropertyById(cx, obj, id, v); -} - -JS_PUBLIC_API(bool) -JS_SetUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - HandleValue v) -{ - JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return JS_SetPropertyById(cx, obj, id, v); -} - -JS_PUBLIC_API(bool) -JS_DeletePropertyById(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id); - - return DeleteProperty(cx, obj, id, result); -} - -JS_PUBLIC_API(bool) -JS_DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& result) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - - return DeleteElement(cx, obj, index, result); -} - -JS_PUBLIC_API(bool) -JS_DeleteProperty(JSContext* cx, HandleObject obj, const char* name, ObjectOpResult& result) -{ - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - - JSAtom* atom = Atomize(cx, name, strlen(name)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return DeleteProperty(cx, obj, id, result); -} - -JS_PUBLIC_API(bool) -JS_DeleteUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - ObjectOpResult& result) -{ - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - - JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - return DeleteProperty(cx, obj, id, result); -} - -JS_PUBLIC_API(bool) -JS_DeletePropertyById(JSContext* cx, HandleObject obj, HandleId id) -{ - ObjectOpResult ignored; - return JS_DeletePropertyById(cx, obj, id, ignored); -} - -JS_PUBLIC_API(bool) -JS_DeleteElement(JSContext* cx, HandleObject obj, uint32_t index) -{ - ObjectOpResult ignored; - return JS_DeleteElement(cx, obj, index, ignored); -} - -JS_PUBLIC_API(bool) -JS_DeleteProperty(JSContext* cx, HandleObject obj, const char* name) -{ - ObjectOpResult ignored; - return JS_DeleteProperty(cx, obj, name, ignored); -} - JS_PUBLIC_API(void) JS_SetAllNonReservedSlotsToUndefined(JSContext* cx, JSObject* objArg) { RootedObject obj(cx, objArg); AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); @@ -3223,31 +3380,16 @@ JS_SetAllNonReservedSlotsToUndefined(JSC const Class* clasp = obj->getClass(); unsigned numReserved = JSCLASS_RESERVED_SLOTS(clasp); unsigned numSlots = obj->as<NativeObject>().slotSpan(); for (unsigned i = numReserved; i < numSlots; i++) obj->as<NativeObject>().setSlot(i, UndefinedValue()); } -JS_PUBLIC_API(bool) -JS_Enumerate(JSContext* cx, HandleObject obj, JS::MutableHandle<IdVector> props) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - MOZ_ASSERT(props.empty()); - - AutoIdVector ids(cx); - if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids)) - return false; - - return props.append(ids.begin(), ids.end()); -} - JS_PUBLIC_API(Value) JS_GetReservedSlot(JSObject* obj, uint32_t index) { return obj->as<NativeObject>().getReservedSlot(index); } JS_PUBLIC_API(void) JS_SetReservedSlot(JSObject* obj, uint32_t index, Value value) @@ -3639,32 +3781,16 @@ JS_GetFunctionDisplayId(JSFunction* fun) } JS_PUBLIC_API(uint16_t) JS_GetFunctionArity(JSFunction* fun) { return fun->nargs(); } -namespace JS { - -JS_PUBLIC_API(bool) -IsCallable(JSObject* obj) -{ - return obj->isCallable(); -} - -JS_PUBLIC_API(bool) -IsConstructor(JSObject* obj) -{ - return obj->isConstructor(); -} - -} /* namespace JS */ - JS_PUBLIC_API(bool) JS_ObjectIsFunction(JSContext* cx, JSObject* obj) { return obj->is<JSFunction>(); } JS_PUBLIC_API(bool) JS_IsNativeFunction(JSObject* funobj, JSNative call) @@ -3829,39 +3955,16 @@ JS_DefineFunctionById(JSContext* cx, Han { MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); return DefineFunction(cx, obj, id, call, nargs, attrs); } -struct AutoLastFrameCheck -{ - explicit AutoLastFrameCheck(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : cx(cx) - { - MOZ_ASSERT(cx); - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - ~AutoLastFrameCheck() { - if (cx->isExceptionPending() && - !JS_IsRunning(cx) && - (!cx->options().dontReportUncaught() && !cx->options().autoJSAPIOwnsErrorReporting())) { - ReportUncaughtException(cx); - } - } - - private: - JSContext* cx; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - /* Use the fastest available getc. */ #if defined(HAVE_GETC_UNLOCKED) # define fast_getc getc_unlocked #elif defined(HAVE__GETC_NOLOCK) # define fast_getc _getc_nolock #else # define fast_getc getc #endif @@ -4704,124 +4807,16 @@ JS::Evaluate(JSContext* cx, AutoObjectVe JS_PUBLIC_API(bool) JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, const char* filename, MutableHandleValue rval) { return ::Evaluate(cx, optionsArg, filename, rval); } -JS_PUBLIC_API(bool) -JS_CallFunction(JSContext* cx, HandleObject obj, HandleFunction fun, const HandleValueArray& args, - MutableHandleValue rval) -{ - MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, fun, args); - AutoLastFrameCheck lfc(cx); - - return Invoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), args.length(), args.begin(), rval); -} - -JS_PUBLIC_API(bool) -JS_CallFunctionName(JSContext* cx, HandleObject obj, const char* name, const HandleValueArray& args, - MutableHandleValue rval) -{ - MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, args); - AutoLastFrameCheck lfc(cx); - - JSAtom* atom = Atomize(cx, name, strlen(name)); - if (!atom) - return false; - - RootedValue v(cx); - RootedId id(cx, AtomToId(atom)); - if (!GetProperty(cx, obj, obj, id, &v)) - return false; - - return Invoke(cx, ObjectOrNullValue(obj), v, args.length(), args.begin(), rval); -} - -JS_PUBLIC_API(bool) -JS_CallFunctionValue(JSContext* cx, HandleObject obj, HandleValue fval, const HandleValueArray& args, - MutableHandleValue rval) -{ - MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, fval, args); - AutoLastFrameCheck lfc(cx); - - return Invoke(cx, ObjectOrNullValue(obj), fval, args.length(), args.begin(), rval); -} - -JS_PUBLIC_API(bool) -JS::Call(JSContext* cx, HandleValue thisv, HandleValue fval, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, thisv, fval, args); - AutoLastFrameCheck lfc(cx); - - return Invoke(cx, thisv, fval, args.length(), args.begin(), rval); -} - -JS_PUBLIC_API(bool) -JS::Construct(JSContext* cx, HandleValue fval, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, fval, args); - AutoLastFrameCheck lfc(cx); - - if (!IsConstructor(fval)) { - ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr); - return false; - } - - ConstructArgs cargs(cx); - if (!FillArgumentsFromArraylike(cx, cargs, args)) - return false; - - return js::Construct(cx, fval, cargs, fval, rval); -} - -JS_PUBLIC_API(bool) -JS::Construct(JSContext* cx, HandleValue fval, HandleObject newTarget, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, fval, newTarget, args); - AutoLastFrameCheck lfc(cx); - - if (!IsConstructor(fval)) { - ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr); - return false; - } - - RootedValue newTargetVal(cx, ObjectValue(*newTarget)); - if (!IsConstructor(newTargetVal)) { - ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, newTargetVal, nullptr); - return false; - } - - ConstructArgs cargs(cx); - if (!FillArgumentsFromArraylike(cx, cargs, args)) - return false; - - return js::Construct(cx, fval, cargs, newTargetVal, rval); -} - static JSObject* JS_NewHelper(JSContext* cx, HandleObject ctor, const JS::HandleValueArray& inputArgs) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, ctor, inputArgs); RootedValue ctorVal(cx, ObjectValue(*ctor)); @@ -6385,22 +6380,16 @@ JS_DecodeInterpretedFunction(JSContext* { XDRDecoder decoder(cx, data, length); RootedFunction funobj(cx); if (!decoder.codeFunction(&funobj)) return nullptr; return funobj; } -JS_PUBLIC_API(bool) -JS_SetImmutablePrototype(JSContext *cx, JS::HandleObject obj, bool *succeeded) -{ - return SetImmutablePrototype(cx, obj, succeeded); -} - JS_PUBLIC_API(void) JS::SetAsmJSCacheOps(JSRuntime* rt, const JS::AsmJSCacheOps* ops) { rt->asmJSCacheOps = *ops; } char* JSAutoByteString::encodeLatin1(ExclusiveContext* cx, JSString* str) @@ -6444,9 +6433,8 @@ JS::GetObjectZone(JSObject* obj) JS_PUBLIC_API(void) JS::ResetTimeZone() { #if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT) icu::TimeZone::recreateDefault(); #endif } -
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2181,22 +2181,16 @@ JS_GetPrivate(JSObject* obj); extern JS_PUBLIC_API(void) JS_SetPrivate(JSObject* obj, void* data); extern JS_PUBLIC_API(void*) JS_GetInstancePrivate(JSContext* cx, JS::Handle<JSObject*> obj, const JSClass* clasp, JS::CallArgs* args); -extern JS_PUBLIC_API(bool) -JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject protop); - -extern JS_PUBLIC_API(bool) -JS_SetPrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); - extern JS_PUBLIC_API(JSObject*) JS_GetConstructor(JSContext* cx, JS::Handle<JSObject*> proto); namespace JS { enum ZoneSpecifier { FreshZone = 0, SystemZone = 1 @@ -2412,20 +2406,16 @@ extern JS_PUBLIC_API(void) JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global); extern JS_PUBLIC_API(void) JS_FireOnNewGlobalObject(JSContext* cx, JS::HandleObject global); extern JS_PUBLIC_API(JSObject*) JS_NewObject(JSContext* cx, const JSClass* clasp); -/* Queries the [[Extensible]] property of the object. */ -extern JS_PUBLIC_API(bool) -JS_IsExtensible(JSContext* cx, JS::HandleObject obj, bool* extensible); - extern JS_PUBLIC_API(bool) JS_IsNative(JSObject* obj); extern JS_PUBLIC_API(JSRuntime*) JS_GetObjectRuntime(JSObject* obj); /* * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default @@ -2447,39 +2437,16 @@ extern JS_PUBLIC_API(bool) JS_DeepFreezeObject(JSContext* cx, JS::Handle<JSObject*> obj); /* * Freezes an object; see ES5's Object.freeze(obj) method. */ extern JS_PUBLIC_API(bool) JS_FreezeObject(JSContext* cx, JS::Handle<JSObject*> obj); -/* - * Attempt to make |obj| non-extensible. If an error occurs while making the - * attempt, return false (with a pending exception set, depending upon the - * nature of the error). If no error occurs, return true with |result| set - * to indicate whether the attempt successfully set the [[Extensible]] property - * to false. - */ -extern JS_PUBLIC_API(bool) -JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result); - -/* - * Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt - * to modify it will fail. If an error occurs during the attempt, return false - * (with a pending exception set, depending upon the nature of the error). If - * no error occurs, return true with |*succeeded| set to indicate whether the - * attempt successfully made the [[Prototype]] immutable. - */ -extern JS_PUBLIC_API(bool) -JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded); - -extern JS_PUBLIC_API(JSObject*) -JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args); - /*** Property descriptors ************************************************************************/ struct JSPropertyDescriptor : public JS::Traceable { JSObject* obj; unsigned attrs; JSGetterOp getter; JSSetterOp setter; @@ -2763,183 +2730,203 @@ extern JS_PUBLIC_API(bool) ObjectToCompletePropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleValue descriptor, JS::MutableHandle<JSPropertyDescriptor> desc); } // namespace JS -/*** [[DefineOwnProperty]] and variations ********************************************************/ - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleObject value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleString value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, int32_t value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, uint32_t value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, double value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleString value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, int32_t value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, uint32_t value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, double value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle<JSPropertyDescriptor> desc, - JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle<JSPropertyDescriptor> desc); - -extern JS_PUBLIC_API(JSObject*) -JS_DefineObject(JSContext* cx, JS::HandleObject obj, const char* name, - const JSClass* clasp = nullptr, unsigned attrs = 0); - -extern JS_PUBLIC_API(bool) -JS_DefineConstDoubles(JSContext* cx, JS::HandleObject obj, const JSConstDoubleSpec* cds); - -extern JS_PUBLIC_API(bool) -JS_DefineConstIntegers(JSContext* cx, JS::HandleObject obj, const JSConstIntegerSpec* cis); - -extern JS_PUBLIC_API(bool) -JS_DefineProperties(JSContext* cx, JS::HandleObject obj, const JSPropertySpec* ps); - - -/* * */ - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, - bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_HasProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_HasPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); - - +/*** Standard internal methods ******************************************************************** + * + * The functions below are the fundamental operations on objects. + * + * ES6 specifies 14 internal methods that define how objects behave. The + * standard is actually quite good on this topic, though you may have to read + * it a few times. See ES6 sections 6.1.7.2 and 6.1.7.3. + * + * When 'obj' is an ordinary object, these functions have boring standard + * behavior as specified by ES6 section 9.1; see the section about internal + * methods in js/src/vm/NativeObject.h. + * + * Proxies override the behavior of internal methods. So when 'obj' is a proxy, + * any one of the functions below could do just about anything. See + * js/public/Proxy.h. + */ + +/** + * Get the prototype of obj, storing it in result. + * + * Implements: ES6 [[GetPrototypeOf]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject result); + +/** + * Change the prototype of obj. + * + * Implements: ES6 [[SetPrototypeOf]] internal method. + * + * In cases where ES6 [[SetPrototypeOf]] returns false without an exception, + * JS_SetPrototype throws a TypeError and returns false. + * + * Performance warning: JS_SetPrototype is very bad for performance. It may + * cause compiled jit-code to be invalidated. It also causes not only obj but + * all other objects in the same "group" as obj to be permanently deoptimized. + * It's better to create the object with the right prototype from the start. + */ +extern JS_PUBLIC_API(bool) +JS_SetPrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); + +/** + * Determine whether obj is extensible. Extensible objects can have new + * properties defined on them. Inextensible objects can't, and their + * [[Prototype]] slot is fixed as well. + * + * Implements: ES6 [[IsExtensible]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_IsExtensible(JSContext* cx, JS::HandleObject obj, bool* extensible); + +/** + * Attempt to make |obj| non-extensible. + * + * Not all failures are treated as errors. See the comment on + * JS::ObjectOpResult in js/public/Class.h. + * + * Implements: ES6 [[PreventExtensions]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result); + +/** + * Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt + * to modify it will fail. If an error occurs during the attempt, return false + * (with a pending exception set, depending upon the nature of the error). If + * no error occurs, return true with |*succeeded| set to indicate whether the + * attempt successfully made the [[Prototype]] immutable. + * + * This is a nonstandard internal method. + */ +extern JS_PUBLIC_API(bool) +JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded); + +/** + * Get a description of one of obj's own properties. If no such property exists + * on obj, return true with desc.object() set to null. + * + * Implements: ES6 [[GetOwnProperty]] internal method. + */ extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandle<JSPropertyDescriptor> desc); extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandle<JSPropertyDescriptor> desc); extern JS_PUBLIC_API(bool) JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, JS::MutableHandle<JSPropertyDescriptor> desc); -extern JS_PUBLIC_API(bool) -JS_HasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp); - -/* - * Like JS_GetOwnPropertyDescriptorById but will return a property on - * an object on the prototype chain (returned in desc->obj). If desc->obj is null, - * then this property was not found on the prototype chain. +/** + * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain + * if no own property is found directly on obj. The object on which the + * property is found is returned in desc.object(). If the property is not found + * on the prototype chain, this returns true with desc.object() set to null. */ extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandle<JSPropertyDescriptor> desc); extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandle<JSPropertyDescriptor> desc); -extern JS_PUBLIC_API(bool) -JS_GetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_GetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf, - JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_SetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue v); - -extern JS_PUBLIC_API(bool) -JS_SetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v); - -extern JS_PUBLIC_API(bool) -JS_ForwardSetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, - JS::HandleValue receiver, JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name); - -extern JS_PUBLIC_API(bool) -JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name, - JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, jsid id); - -extern JS_PUBLIC_API(bool) -JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, +/** + * Define a property on obj. + * + * This function uses JS::ObjectOpResult to indicate conditions that ES6 + * specifies as non-error failures. This is inconvenient at best, so use this + * function only if you are implementing a proxy handler's defineProperty() + * method. For all other purposes, use one of the many DefineProperty functions + * below that throw an exception in all failure cases. + * + * Implements: ES6 [[DefineOwnProperty]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::Handle<JSPropertyDescriptor> desc, JS::ObjectOpResult& result); +/** + * Define a property on obj, throwing a TypeError if the attempt fails. + * This is the C++ equivalent of `Object.defineProperty(obj, id, desc)`. + */ +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::Handle<JSPropertyDescriptor> desc); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleString value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, int32_t value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, uint32_t value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, double value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleObject value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleString value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, int32_t value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, uint32_t value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, double value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::Handle<JSPropertyDescriptor> desc, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::Handle<JSPropertyDescriptor> desc); + extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::HandleValue value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::HandleObject value, unsigned attrs, @@ -2961,46 +2948,380 @@ JS_DefineUCProperty(JSContext* cx, JS::H JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, double value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::Handle<JSPropertyDescriptor> desc, +JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double value, + unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); + +/** + * Compute the expression `id in obj`. + * + * If obj has an own or inherited property obj[id], set *foundp = true and + * return true. If not, set *foundp = false and return true. On error, return + * false with an exception pending. + * + * Implements: ES6 [[Has]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_HasPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); + +extern JS_PUBLIC_API(bool) +JS_HasProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp); + +extern JS_PUBLIC_API(bool) +JS_HasUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + bool* vp); + +extern JS_PUBLIC_API(bool) +JS_HasElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp); + +/** + * Determine whether obj has an own property with the key `id`. + * + * Implements: ES6 7.3.11 HasOwnProperty(O, P). + */ +extern JS_PUBLIC_API(bool) +JS_HasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); + +extern JS_PUBLIC_API(bool) +JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp); + +/** + * Get the value of the property `obj[id]`, or undefined if no such property + * exists. This is the C++ equivalent of `vp = Reflect.get(obj, id, receiver)`. + * + * Most callers don't need the `receiver` argument. Consider using + * JS_GetProperty instead. (But if you're implementing a proxy handler's set() + * method, it's often correct to call this function and pass the receiver + * through.) + * + * Implements: ES6 [[Get]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::HandleValue receiver, JS::MutableHandleValue vp); + +extern JS_PUBLIC_API(bool) +JS_ForwardGetElementTo(JSContext* cx, JS::HandleObject obj, uint32_t index, + JS::HandleObject receiver, JS::MutableHandleValue vp); + +/** + * Get the value of the property `obj[id]`, or undefined if no such property + * exists. The result is stored in vp. + * + * Implements: ES6 7.3.1 Get(O, P). + */ +extern JS_PUBLIC_API(bool) +JS_GetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API(bool) +JS_GetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandleValue vp); + +extern JS_PUBLIC_API(bool) +JS_GetUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API(bool) +JS_GetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); + +/** + * Perform the same property assignment as `Reflect.set(obj, id, v, receiver)`. + * + * This function has a `receiver` argument that most callers don't need. + * Consider using JS_SetProperty instead. + * + * Implements: ES6 [[Set]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_ForwardSetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, + JS::HandleValue receiver, JS::ObjectOpResult& result); + +/** + * Perform the assignment `obj[id] = v`. + * + * This function performs non-strict assignment, so if the property is + * read-only, nothing happens and no error is thrown. + */ +extern JS_PUBLIC_API(bool) +JS_SetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v); + +extern JS_PUBLIC_API(bool) +JS_SetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue v); + +extern JS_PUBLIC_API(bool) +JS_SetUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleValue v); + +extern JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue v); + +extern JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject v); + +extern JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString v); + +extern JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t v); + +extern JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t v); + +extern JS_PUBLIC_API(bool) +JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double v); + +/** + * Delete a property. This is the C++ equivalent of + * `result = Reflect.deleteProperty(obj, id)`. + * + * This function has a `result` out parameter that most callers don't need. + * Unless you can pass through an ObjectOpResult provided by your caller, it's + * probably best to use the JS_DeletePropertyById signature with just 3 + * arguments. + * + * Implements: ES6 [[Delete]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API(bool) +JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API(bool) +JS_DeleteUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::ObjectOpResult& result); extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::Handle<JSPropertyDescriptor> desc); +JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::ObjectOpResult& result); + +/** + * Delete a property, ignoring strict failures. This is the C++ equivalent of + * the JS `delete obj[id]` in non-strict mode code. + */ +extern JS_PUBLIC_API(bool) +JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, jsid id); + +extern JS_PUBLIC_API(bool) +JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name); + +extern JS_PUBLIC_API(bool) +JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index); + +/** + * Get an array of the non-symbol enumerable properties of obj. + * This function is roughly equivalent to: + * + * var result = []; + * for (key in obj) + * result.push(key); + * return result; + * + * This is the closest thing we currently have to the ES6 [[Enumerate]] + * internal method. + * + * The JSIdArray returned by JS_Enumerate must be rooted to protect its + * contents from garbage collection. Use JS::AutoIdArray. + */ +extern JS_PUBLIC_API(bool) +JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle<JS::IdVector> props); + +/* + * API for determining callability and constructability. [[Call]] and + * [[Construct]] are internal methods that aren't present on all objects, so it + * is useful to ask if they are there or not. The standard itself asks these + * questions routinely. + */ +namespace JS { + +/** + * Return true if the given object is callable. In ES6 terms, an object is + * callable if it has a [[Call]] internal method. + * + * Implements: ES6 7.2.3 IsCallable(argument). + * + * Functions are callable. A scripted proxy or wrapper is callable if its + * target is callable. Most other objects aren't callable. + */ +extern JS_PUBLIC_API(bool) +IsCallable(JSObject* obj); + +/** + * Return true if the given object is a constructor. In ES6 terms, an object is + * a constructor if it has a [[Construct]] internal method. The expression + * `new obj()` throws a TypeError if obj is not a constructor. + * + * Implements: ES6 7.2.4 IsConstructor(argument). + * + * JS functions and classes are constructors. Arrow functions and most builtin + * functions are not. A scripted proxy or wrapper is a constructor if its + * target is a constructor. + */ +extern JS_PUBLIC_API(bool) +IsConstructor(JSObject* obj); + +} /* namespace JS */ + +/** + * Call a function, passing a this-value and arguments. This is the C++ + * equivalent of `rval = Reflect.apply(fun, obj, args)`. + * + * Implements: ES6 7.3.12 Call(F, V, [argumentsList]). + * Use this function to invoke the [[Call]] internal method. + */ +extern JS_PUBLIC_API(bool) +JS_CallFunctionValue(JSContext* cx, JS::HandleObject obj, JS::HandleValue fval, + const JS::HandleValueArray& args, JS::MutableHandleValue rval); + +extern JS_PUBLIC_API(bool) +JS_CallFunction(JSContext* cx, JS::HandleObject obj, JS::HandleFunction fun, + const JS::HandleValueArray& args, JS::MutableHandleValue rval); + +/** + * Perform the method call `rval = obj[name](args)`. + */ +extern JS_PUBLIC_API(bool) +JS_CallFunctionName(JSContext* cx, JS::HandleObject obj, const char* name, + const JS::HandleValueArray& args, JS::MutableHandleValue rval); + +namespace JS { + +static inline bool +Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleFunction fun, + const JS::HandleValueArray& args, MutableHandleValue rval) +{ + return !!JS_CallFunction(cx, thisObj, fun, args, rval); +} + +static inline bool +Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleValue fun, const JS::HandleValueArray& args, + MutableHandleValue rval) +{ + return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval); +} + +static inline bool +Call(JSContext* cx, JS::HandleObject thisObj, const char* name, const JS::HandleValueArray& args, + MutableHandleValue rval) +{ + return !!JS_CallFunctionName(cx, thisObj, name, args, rval); +} + +extern JS_PUBLIC_API(bool) +Call(JSContext* cx, JS::HandleValue thisv, JS::HandleValue fun, const JS::HandleValueArray& args, + MutableHandleValue rval); + +static inline bool +Call(JSContext* cx, JS::HandleValue thisv, JS::HandleObject funObj, const JS::HandleValueArray& args, + MutableHandleValue rval) +{ + MOZ_ASSERT(funObj); + JS::RootedValue fun(cx, JS::ObjectValue(*funObj)); + return Call(cx, thisv, fun, args, rval); +} + +/** + * Invoke a constructor. This is the C++ equivalent of + * `rval = Reflect.construct(fun, args, newTarget)`. + * + * JS::Construct() takes a `newTarget` argument that most callers don't need. + * Consider using the four-argument Construct signature instead. (But if you're + * implementing a subclass or a proxy handler's construct() method, this is the + * right function to call.) + * + * Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]). + * Use this function to invoke the [[Construct]] internal method. + */ +extern JS_PUBLIC_API(bool) +Construct(JSContext* cx, JS::HandleValue fun, HandleObject newTarget, + const JS::HandleValueArray &args, MutableHandleValue rval); + +/** + * Invoke a constructor. This is the C++ equivalent of + * `rval = new fun(...args)`. + * + * The value left in rval on success is always an object in practice, + * though at the moment this is not enforced by the C++ type system. + * + * Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]), when + * newTarget is omitted. + */ +extern JS_PUBLIC_API(bool) +Construct(JSContext* cx, JS::HandleValue fun, const JS::HandleValueArray& args, + MutableHandleValue rval); + +} /* namespace JS */ + +/** + * Invoke a constructor, like the JS expression `new ctor(...args)`. Returns + * the new object, or null on error. + */ +extern JS_PUBLIC_API(JSObject*) +JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args); + + +/*** Other property-defining functions ***********************************************************/ + +extern JS_PUBLIC_API(JSObject*) +JS_DefineObject(JSContext* cx, JS::HandleObject obj, const char* name, + const JSClass* clasp = nullptr, unsigned attrs = 0); + +extern JS_PUBLIC_API(bool) +JS_DefineConstDoubles(JSContext* cx, JS::HandleObject obj, const JSConstDoubleSpec* cds); + +extern JS_PUBLIC_API(bool) +JS_DefineConstIntegers(JSContext* cx, JS::HandleObject obj, const JSConstIntegerSpec* cis); + +extern JS_PUBLIC_API(bool) +JS_DefineProperties(JSContext* cx, JS::HandleObject obj, const JSPropertySpec* ps); + + +/* * */ + +extern JS_PUBLIC_API(bool) +JS_AlreadyHasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + bool* foundp); + +extern JS_PUBLIC_API(bool) +JS_AlreadyHasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, + bool* foundp); extern JS_PUBLIC_API(bool) JS_AlreadyHasOwnUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, bool* foundp); extern JS_PUBLIC_API(bool) -JS_HasUCProperty(JSContext* cx, JS::HandleObject obj, - const char16_t* name, size_t namelen, - bool* vp); - -extern JS_PUBLIC_API(bool) -JS_GetUCProperty(JSContext* cx, JS::HandleObject obj, - const char16_t* name, size_t namelen, - JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_SetUCProperty(JSContext* cx, JS::HandleObject obj, - const char16_t* name, size_t namelen, - JS::HandleValue v); - -extern JS_PUBLIC_API(bool) -JS_DeleteUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::ObjectOpResult& result); +JS_AlreadyHasOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp); extern JS_PUBLIC_API(JSObject*) JS_NewArrayObject(JSContext* cx, const JS::HandleValueArray& contents); extern JS_PUBLIC_API(JSObject*) JS_NewArrayObject(JSContext* cx, size_t length); // Returns true and sets |*isArray| indicating whether |value| is an Array @@ -3020,83 +3341,16 @@ extern JS_PUBLIC_API(bool) JS_IsArrayObject(JSContext* cx, JS::HandleObject obj, bool* isArray); extern JS_PUBLIC_API(bool) JS_GetArrayLength(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t* lengthp); extern JS_PUBLIC_API(bool) JS_SetArrayLength(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t length); -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double value, - unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_HasElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_GetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_ForwardGetElementTo(JSContext* cx, JS::HandleObject obj, uint32_t index, - JS::HandleObject onBehalfOf, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue v); - -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject v); - -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString v); - -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t v); - -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t v); - -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double v); - -extern JS_PUBLIC_API(bool) -JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index); - -extern JS_PUBLIC_API(bool) -JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::ObjectOpResult& result); - /* * Assign 'undefined' to all of the object's non-reserved slots. Note: this is * done for all slots, regardless of the associated property descriptor. */ JS_PUBLIC_API(void) JS_SetAllNonReservedSlotsToUndefined(JSContext* cx, JSObject* objArg); /* @@ -3136,25 +3390,23 @@ JS_CreateMappedArrayBufferContents(int f * object is created. * If a new object has been created by JS_NewMappedArrayBufferWithContents() * with this content, then JS_NeuterArrayBuffer() should be used instead to * release the resource used by the object. */ extern JS_PUBLIC_API(void) JS_ReleaseMappedArrayBufferContents(void* contents, size_t length); -extern JS_PUBLIC_API(bool) -JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle<JS::IdVector> props); - extern JS_PUBLIC_API(JS::Value) JS_GetReservedSlot(JSObject* obj, uint32_t index); extern JS_PUBLIC_API(void) JS_SetReservedSlot(JSObject* obj, uint32_t index, JS::Value v); + /************************************************************************/ /* * Functions and scripts. */ extern JS_PUBLIC_API(JSFunction*) JS_NewFunction(JSContext* cx, JSNative call, unsigned nargs, unsigned flags, const char* name); @@ -3202,30 +3454,16 @@ JS_GetFunctionDisplayId(JSFunction* fun) /* * Return the arity (length) of fun. */ extern JS_PUBLIC_API(uint16_t) JS_GetFunctionArity(JSFunction* fun); /* - * API for determining callability and constructability. This does the right - * thing for proxies. - */ -namespace JS { - -extern JS_PUBLIC_API(bool) -IsCallable(JSObject* obj); - -extern JS_PUBLIC_API(bool) -IsConstructor(JSObject* obj); - -} /* namespace JS */ - -/* * Infallible predicate to test whether obj is a function object (faster than * comparing obj's class name to "Function", but equivalent unless someone has * overwritten the "Function" identifier with a different constructor and then * created instances using that constructor that might be passed in as obj). */ extern JS_PUBLIC_API(bool) JS_ObjectIsFunction(JSContext* cx, JSObject* obj); @@ -3914,76 +4152,16 @@ Evaluate(JSContext* cx, const ReadOnlyCo */ extern JS_PUBLIC_API(bool) Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, JS::MutableHandleValue rval); } /* namespace JS */ extern JS_PUBLIC_API(bool) -JS_CallFunction(JSContext* cx, JS::HandleObject obj, JS::HandleFunction fun, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); - -extern JS_PUBLIC_API(bool) -JS_CallFunctionName(JSContext* cx, JS::HandleObject obj, const char* name, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); - -extern JS_PUBLIC_API(bool) -JS_CallFunctionValue(JSContext* cx, JS::HandleObject obj, JS::HandleValue fval, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); - -namespace JS { - -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleFunction fun, - const JS::HandleValueArray& args, MutableHandleValue rval) -{ - return !!JS_CallFunction(cx, thisObj, fun, args, rval); -} - -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, const char* name, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - return !!JS_CallFunctionName(cx, thisObj, name, args, rval); -} - -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleValue fun, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval); -} - -extern JS_PUBLIC_API(bool) -Call(JSContext* cx, JS::HandleValue thisv, JS::HandleValue fun, const JS::HandleValueArray& args, - MutableHandleValue rval); - -static inline bool -Call(JSContext* cx, JS::HandleValue thisv, JS::HandleObject funObj, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - MOZ_ASSERT(funObj); - JS::RootedValue fun(cx, JS::ObjectValue(*funObj)); - return Call(cx, thisv, fun, args, rval); -} - -extern JS_PUBLIC_API(bool) -Construct(JSContext* cx, JS::HandleValue fun, - const JS::HandleValueArray& args, - MutableHandleValue rval); - -extern JS_PUBLIC_API(bool) -Construct(JSContext* cx, JS::HandleValue fun, - HandleObject newTarget, const JS::HandleValueArray &args, - MutableHandleValue rval); - -} /* namespace JS */ - -extern JS_PUBLIC_API(bool) JS_CheckForInterrupt(JSContext* cx); /* * These functions allow setting an interrupt callback that will be called * from the JS thread some time after any thread triggered the callback using * JS_RequestInterruptCallback(rt). * * To schedule the GC and for other activities the engine internally triggers
--- a/js/src/moz.build +++ b/js/src/moz.build @@ -504,16 +504,20 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONF ] if CONFIG['JS_SIMULATOR_MIPS32']: UNIFIED_SOURCES += [ 'jit/mips32/Simulator-mips32.cpp' ] elif CONFIG['JS_CODEGEN_MIPS64']: UNIFIED_SOURCES += [ 'jit/mips64/Architecture-mips64.cpp', + 'jit/mips64/Assembler-mips64.cpp', + 'jit/mips64/Bailouts-mips64.cpp', + 'jit/mips64/BaselineCompiler-mips64.cpp', + 'jit/mips64/BaselineIC-mips64.cpp', ] if CONFIG['OS_ARCH'] == 'WINNT': SOURCES += [ 'jit/ExecutableAllocatorWin.cpp', ] # _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s() DEFINES['_CRT_RAND_S'] = True
--- a/js/src/vm/SavedFrame.h +++ b/js/src/vm/SavedFrame.h @@ -2,22 +2,25 @@ * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef vm_SavedFrame_h #define vm_SavedFrame_h +#include "jswrapper.h" + #include "js/UbiNode.h" namespace js { class SavedFrame : public NativeObject { friend class SavedStacks; + friend struct ::JSStructuredCloneReader; public: static const Class class_; static const JSPropertySpec protoAccessors[]; static const JSFunctionSpec protoFunctions[]; static const JSFunctionSpec staticFunctions[]; // Prototype methods and properties to be exposed to JS. @@ -115,16 +118,23 @@ class SavedFrame : public NativeObject { RootedIterator end() { return RootedIterator(); } }; static bool isSavedFrameAndNotProto(JSObject& obj) { return obj.is<SavedFrame>() && !obj.as<SavedFrame>().getReservedSlot(JSSLOT_SOURCE).isNull(); } + static bool isSavedFrameOrWrapperAndNotProto(JSObject& obj) { + auto unwrapped = CheckedUnwrap(&obj); + if (!unwrapped) + return false; + return isSavedFrameAndNotProto(*unwrapped); + } + struct Lookup; struct HashPolicy; typedef HashSet<js::ReadBarriered<SavedFrame*>, HashPolicy, SystemAllocPolicy> Set; class AutoLookupVector; @@ -137,18 +147,27 @@ class SavedFrame : public NativeObject { explicit HandleLookup(Lookup& lookup) : lookup(lookup) { } public: inline Lookup& get() { return lookup; } inline Lookup* operator->() { return &lookup; } }; private: + static SavedFrame* create(JSContext* cx); static bool finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject proto); void initFromLookup(HandleLookup lookup); + void initSource(JSAtom* source); + void initLine(uint32_t line); + void initColumn(uint32_t column); + void initFunctionDisplayName(JSAtom* maybeName); + void initAsyncCause(JSAtom* maybeCause); + void initParent(SavedFrame* maybeParent); + void initPrincipalsAlreadyHeld(JSPrincipals* principals); + void initPrincipals(JSPrincipals* principals); enum { // The reserved slots in the SavedFrame class. JSSLOT_SOURCE, JSSLOT_LINE, JSSLOT_COLUMN, JSSLOT_FUNCTIONDISPLAYNAME, JSSLOT_ASYNCCAUSE,
--- a/js/src/vm/SavedStacks-inl.h +++ b/js/src/vm/SavedStacks-inl.h @@ -17,18 +17,12 @@ // SavedFrame objects and the SavedFrame accessors themselves handle wrappers // and use the original caller's compartment's principals to determine what // level of data to present. Unwrapping and entering the referent's compartment // would mess that up. See the module level documentation in // `js/src/vm/SavedStacks.h` as well as the comments in `js/src/jsapi.h`. inline void js::AssertObjectIsSavedFrameOrWrapper(JSContext* cx, HandleObject stack) { -#ifdef DEBUG - if (stack) { - RootedObject savedFrameObj(cx, CheckedUnwrap(stack)); - MOZ_ASSERT(savedFrameObj); - MOZ_ASSERT(js::SavedFrame::isSavedFrameAndNotProto(*savedFrameObj)); - } -#endif + MOZ_ASSERT_IF(stack, js::SavedFrame::isSavedFrameOrWrapperAndNotProto(*stack)); } #endif // vm_SavedStacksInl_h
--- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -402,38 +402,100 @@ SavedFrame::getPrincipals() { const Value& v = getReservedSlot(JSSLOT_PRINCIPALS); if (v.isUndefined()) return nullptr; return static_cast<JSPrincipals*>(v.toPrivate()); } void +SavedFrame::initSource(JSAtom* source) +{ + MOZ_ASSERT(source); + initReservedSlot(JSSLOT_SOURCE, StringValue(source)); +} + +void +SavedFrame::initLine(uint32_t line) +{ + initReservedSlot(JSSLOT_LINE, PrivateUint32Value(line)); +} + +void +SavedFrame::initColumn(uint32_t column) +{ + initReservedSlot(JSSLOT_COLUMN, PrivateUint32Value(column)); +} + +void +SavedFrame::initPrincipals(JSPrincipals* principals) +{ + if (principals) + JS_HoldPrincipals(principals); + initPrincipalsAlreadyHeld(principals); +} + +void +SavedFrame::initPrincipalsAlreadyHeld(JSPrincipals* principals) +{ + MOZ_ASSERT_IF(principals, principals->refcount > 0); + initReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(principals)); +} + +void +SavedFrame::initFunctionDisplayName(JSAtom* maybeName) +{ + initReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME, maybeName ? StringValue(maybeName) : NullValue()); +} + +void +SavedFrame::initAsyncCause(JSAtom* maybeCause) +{ + initReservedSlot(JSSLOT_ASYNCCAUSE, maybeCause ? StringValue(maybeCause) : NullValue()); +} + +void +SavedFrame::initParent(SavedFrame* maybeParent) +{ + initReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(maybeParent)); +} + +void SavedFrame::initFromLookup(SavedFrame::HandleLookup lookup) { - MOZ_ASSERT(lookup->source); - MOZ_ASSERT(getReservedSlot(JSSLOT_SOURCE).isUndefined()); - setReservedSlot(JSSLOT_SOURCE, StringValue(lookup->source)); + initSource(lookup->source); + initLine(lookup->line); + initColumn(lookup->column); + initFunctionDisplayName(lookup->functionDisplayName); + initAsyncCause(lookup->asyncCause); + initParent(lookup->parent); + initPrincipals(lookup->principals); +} + +/* static */ SavedFrame* +SavedFrame::create(JSContext* cx) +{ + RootedGlobalObject global(cx, cx->global()); + assertSameCompartment(cx, global); - setReservedSlot(JSSLOT_LINE, PrivateUint32Value(lookup->line)); - setReservedSlot(JSSLOT_COLUMN, PrivateUint32Value(lookup->column)); - setReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME, - lookup->functionDisplayName - ? StringValue(lookup->functionDisplayName) - : NullValue()); - setReservedSlot(JSSLOT_ASYNCCAUSE, - lookup->asyncCause - ? StringValue(lookup->asyncCause) - : NullValue()); - setReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(lookup->parent)); + // Ensure that we don't try to capture the stack again in the + // `SavedStacksMetadataCallback` for this new SavedFrame object, and + // accidentally cause O(n^2) behavior. + SavedStacks::AutoReentrancyGuard guard(cx->compartment()->savedStacks()); - MOZ_ASSERT(getReservedSlot(JSSLOT_PRINCIPALS).isUndefined()); - if (lookup->principals) - JS_HoldPrincipals(lookup->principals); - setReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(lookup->principals)); + RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global)); + if (!proto) + return nullptr; + assertSameCompartment(cx, proto); + + RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto)); + if (!frameObj) + return nullptr; + + return &frameObj->as<SavedFrame>(); } bool SavedFrame::isSelfHosted() { JSAtom* source = getSource(); return StringEqualsAscii(source, "self-hosted"); } @@ -1217,40 +1279,25 @@ SavedStacks::getOrCreateSavedFrame(JSCon return nullptr; return frame; } SavedFrame* SavedStacks::createFrameFromLookup(JSContext* cx, SavedFrame::HandleLookup lookup) { - RootedGlobalObject global(cx, cx->global()); - assertSameCompartment(cx, global); - - // Ensure that we don't try to capture the stack again in the - // `SavedStacksMetadataCallback` for this new SavedFrame object, and - // accidentally cause O(n^2) behavior. - SavedStacks::AutoReentrancyGuard guard(*this); + RootedSavedFrame frame(cx, SavedFrame::create(cx)); + if (!frame) + return nullptr; + frame->initFromLookup(lookup); - RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global)); - if (!proto) - return nullptr; - assertSameCompartment(cx, proto); - - RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto)); - if (!frameObj) + if (!FreezeObject(cx, frame)) return nullptr; - RootedSavedFrame f(cx, &frameObj->as<SavedFrame>()); - f->initFromLookup(lookup); - - if (!FreezeObject(cx, frameObj)) - return nullptr; - - return f.get(); + return frame; } /* * Remove entries from the table whose JSScript is being collected. */ void SavedStacks::sweepPCLocationMap() {
--- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -143,16 +143,17 @@ namespace js { // // In the case of z, the `SavedFrame` accessors are called with the `SavedFrame` // object in the `this` value, and the content compartment as the cx's current // compartment. Similar to the case of y, only the B and C frames are exposed // because the cx's current compartment's principals do not subsume A's captured // principals. class SavedStacks { + friend class SavedFrame; friend JSObject* SavedStacksMetadataCallback(JSContext* cx, JSObject* target); friend bool JS::ubi::ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& ubiFrame, MutableHandleObject outSavedFrameStack); public: SavedStacks() : frames(),
--- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -37,16 +37,17 @@ #include "jsapi.h" #include "jscntxt.h" #include "jsdate.h" #include "jswrapper.h" #include "builtin/MapObject.h" #include "js/Date.h" #include "js/TraceableHashTable.h" +#include "vm/SavedFrame.h" #include "vm/SharedArrayObject.h" #include "vm/TypedArrayObject.h" #include "vm/WrapperObject.h" #include "jscntxtinlines.h" #include "jsobjinlines.h" using namespace js; @@ -87,16 +88,22 @@ enum StructuredDataType : uint32_t { SCTAG_DO_NOT_USE_1, // Required for backwards compatibility SCTAG_DO_NOT_USE_2, // Required for backwards compatibility SCTAG_TYPED_ARRAY_OBJECT, SCTAG_MAP_OBJECT, SCTAG_SET_OBJECT, SCTAG_END_OF_KEYS, SCTAG_SHARED_TYPED_ARRAY_OBJECT, SCTAG_DATA_VIEW_OBJECT, + SCTAG_SAVED_FRAME_OBJECT, + + SCTAG_JSPRINCIPALS, + SCTAG_NULL_JSPRINCIPALS, + SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM, + SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM, SCTAG_TYPED_ARRAY_V1_MIN = 0xFFFF0100, SCTAG_TYPED_ARRAY_V1_INT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int8, SCTAG_TYPED_ARRAY_V1_UINT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint8, SCTAG_TYPED_ARRAY_V1_INT16 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int16, SCTAG_TYPED_ARRAY_V1_UINT16 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint16, SCTAG_TYPED_ARRAY_V1_INT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int32, SCTAG_TYPED_ARRAY_V1_UINT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint32, @@ -238,16 +245,17 @@ struct JSStructuredCloneReader { bool checkDouble(double d); bool readTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp, bool v1Read = false); bool readDataView(uint32_t byteLength, MutableHandleValue vp); bool readSharedTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp); bool readArrayBuffer(uint32_t nbytes, MutableHandleValue vp); bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp); + JSObject* readSavedFrame(uint32_t principalsTag); bool startRead(MutableHandleValue vp); SCInput& in; // Stack of objects with properties remaining to be read. AutoValueVector objs; // Stack of all objects read during this deserialization @@ -300,16 +308,17 @@ struct JSStructuredCloneWriter { bool writeDataView(HandleObject obj); bool writeSharedArrayBuffer(HandleObject obj); bool writeSharedTypedArray(HandleObject obj); bool startObject(HandleObject obj, bool* backref); bool startWrite(HandleValue v); bool traverseObject(HandleObject obj); bool traverseMap(HandleObject obj); bool traverseSet(HandleObject obj); + bool traverseSavedFrame(HandleObject obj); bool parseTransferable(); bool reportErrorTransferable(uint32_t errorId); bool transferOwnership(); inline void checkStack(); SCOutput out; @@ -319,19 +328,20 @@ struct JSStructuredCloneWriter { // NB: These can span multiple compartments, so the compartment must be // entered before any manipulation is performed. AutoValueVector objs; // counts[i] is the number of entries of objs[i] remaining to be written. // counts.length() == objs.length() and sum(counts) == entries.length(). Vector<size_t> counts; - // For JSObject: Propery IDs as value - // For Map: Key followed by value. + // For JSObject: Property IDs as value + // For Map: Key followed by value // For Set: Key + // For SavedFrame: parent SavedFrame AutoValueVector entries; // The "memory" list described in the HTML5 internal structured cloning algorithm. // memory is a superset of objs; items are never removed from Memory // until a serialization operation is finished using CloneMemory = TraceableHashMap<JSObject*, uint32_t>; Rooted<CloneMemory> memory; @@ -1032,16 +1042,113 @@ JSStructuredCloneWriter::traverseSet(Han return false; checkStack(); /* Write the header for obj. */ return out.writePair(SCTAG_SET_OBJECT, 0); } +// Objects are written as a "preorder" traversal of the object graph: object +// "headers" (the class tag and any data needed for initial construction) are +// visited first, then the children are recursed through (where children are +// properties, Set or Map entries, etc.). So for example +// +// m = new Map(); +// m.set(key1 = {}, value1 = {}) +// +// would be stored as +// +// <Map tag> +// <key1 class tag> +// <value1 class tag> +// <end-of-children marker for key1> +// <end-of-children marker for value1> +// <end-of-children marker for Map> +// +// Notice how the end-of-children marker for key1 is sandwiched between the +// value1 beginning and end. +bool +JSStructuredCloneWriter::traverseSavedFrame(HandleObject obj) +{ + RootedObject unwrapped(context(), js::CheckedUnwrap(obj)); + MOZ_ASSERT(unwrapped && unwrapped->is<SavedFrame>()); + + RootedSavedFrame savedFrame(context(), &unwrapped->as<SavedFrame>()); + + RootedObject parent(context(), savedFrame->getParent()); + if (!context()->compartment()->wrap(context(), &parent)) + return false; + + if (!objs.append(ObjectValue(*obj)) || + !entries.append(parent ? ObjectValue(*parent) : NullValue()) || + !counts.append(1)) + { + return false; + } + + checkStack(); + + // Write the SavedFrame tag and the SavedFrame's principals. + + if (savedFrame->getPrincipals() == &ReconstructedSavedFramePrincipals::IsSystem) { + if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT, + SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM)) + { + return false; + }; + } else if (savedFrame->getPrincipals() == &ReconstructedSavedFramePrincipals::IsNotSystem) { + if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT, + SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM)) + { + return false; + } + } else { + if (auto principals = savedFrame->getPrincipals()) { + if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT, SCTAG_JSPRINCIPALS) || + !principals->write(context(), this)) + { + return false; + } + } else { + if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT, SCTAG_NULL_JSPRINCIPALS)) + return false; + } + } + + // Write the SavedFrame's reserved slots, except for the parent, which is + // queued on objs for further traversal. + + RootedValue val(context()); + + val = StringValue(savedFrame->getSource()); + if (!startWrite(val)) + return false; + + val = NumberValue(savedFrame->getLine()); + if (!startWrite(val)) + return false; + + val = NumberValue(savedFrame->getColumn()); + if (!startWrite(val)) + return false; + + auto name = savedFrame->getFunctionDisplayName(); + val = name ? StringValue(name) : NullValue(); + if (!startWrite(val)) + return false; + + auto cause = savedFrame->getAsyncCause(); + val = cause ? StringValue(cause) : NullValue(); + if (!startWrite(val)) + return false; + + return true; +} + bool JSStructuredCloneWriter::startWrite(HandleValue v) { assertSameCompartment(context(), v); if (v.isString()) { return writeString(SCTAG_STRING, v.toString()); } else if (v.isInt32()) { @@ -1106,16 +1213,18 @@ JSStructuredCloneWriter::startWrite(Hand RootedValue unboxed(context()); if (!Unbox(context(), obj, &unboxed)) return false; return writeString(SCTAG_STRING_OBJECT, unboxed.toString()); } else if (cls == ESClass_Map) { return traverseMap(obj); } else if (cls == ESClass_Set) { return traverseSet(obj); + } else if (SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) { + return traverseSavedFrame(obj); } if (callbacks && callbacks->write) return callbacks->write(context(), this, obj, closure); /* else fall through */ } JS_ReportErrorNumber(context(), GetErrorMessage, nullptr, JSMSG_SC_UNSUPPORTED_TYPE); @@ -1263,17 +1372,17 @@ JSStructuredCloneWriter::write(HandleVal if (cls == ESClass_Map) { counts.back()--; RootedValue val(context(), entries.back()); entries.popBack(); checkStack(); if (!startWrite(key) || !startWrite(val)) return false; - } else if (cls == ESClass_Set) { + } else if (cls == ESClass_Set || SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) { if (!startWrite(key)) return false; } else { RootedId id(context()); if (!ValueToId<CanGC>(context(), key, &id)) return false; MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id)); @@ -1772,16 +1881,24 @@ JSStructuredCloneReader::startRead(Mutab case SCTAG_SET_OBJECT: { JSObject* obj = SetObject::create(context()); if (!obj || !objs.append(ObjectValue(*obj))) return false; vp.setObject(*obj); break; } + case SCTAG_SAVED_FRAME_OBJECT: { + auto obj = readSavedFrame(data); + if (!obj || !objs.append(ObjectValue(*obj))) + return false; + vp.setObject(*obj); + break; + } + default: { if (tag <= SCTAG_FLOAT_MAX) { double d = ReinterpretPairAsDouble(tag, data); if (!checkDouble(d)) return false; vp.setNumber(d); break; } @@ -1889,63 +2006,186 @@ JSStructuredCloneReader::readTransferMap MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_HEADER); MOZ_ASSERT(TransferableMapHeader(data) != SCTAG_TM_TRANSFERRED); #endif *headerPos = PairToUInt64(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRED); return true; } +JSObject* +JSStructuredCloneReader::readSavedFrame(uint32_t principalsTag) +{ + RootedSavedFrame savedFrame(context(), SavedFrame::create(context())); + if (!savedFrame) + return nullptr; + + JSPrincipals* principals; + if (principalsTag == SCTAG_JSPRINCIPALS) { + if (!context()->runtime()->readPrincipals) { + JS_ReportErrorNumber(context(), GetErrorMessage, nullptr, + JSMSG_SC_UNSUPPORTED_TYPE); + return nullptr; + } + + if (!context()->runtime()->readPrincipals(context(), this, &principals)) + return nullptr; + } else if (principalsTag == SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM) { + principals = &ReconstructedSavedFramePrincipals::IsSystem; + principals->refcount++; + } else if (principalsTag == SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM) { + principals = &ReconstructedSavedFramePrincipals::IsNotSystem; + principals->refcount++; + } else if (principalsTag == SCTAG_NULL_JSPRINCIPALS) { + principals = nullptr; + } else { + JS_ReportErrorNumber(context(), GetErrorMessage, nullptr, + JSMSG_SC_BAD_SERIALIZED_DATA, "bad SavedFrame principals"); + return nullptr; + } + savedFrame->initPrincipalsAlreadyHeld(principals); + + RootedValue source(context()); + if (!startRead(&source) || !source.isString()) + return nullptr; + auto atomSource = AtomizeString(context(), source.toString()); + if (!atomSource) + return nullptr; + savedFrame->initSource(atomSource); + + RootedValue lineVal(context()); + uint32_t line; + if (!startRead(&lineVal) || !lineVal.isNumber() || !ToUint32(context(), lineVal, &line)) + return nullptr; + savedFrame->initLine(line); + + RootedValue columnVal(context()); + uint32_t column; + if (!startRead(&columnVal) || !columnVal.isNumber() || !ToUint32(context(), columnVal, &column)) + return nullptr; + savedFrame->initColumn(column); + + RootedValue name(context()); + if (!startRead(&name) || !(name.isString() || name.isNull())) + return nullptr; + JSAtom* atomName = nullptr; + if (name.isString()) { + atomName = AtomizeString(context(), name.toString()); + if (!atomName) + return nullptr; + } + savedFrame->initFunctionDisplayName(atomName); + + RootedValue cause(context()); + if (!startRead(&cause) || !(cause.isString() || cause.isNull())) + return nullptr; + JSAtom* atomCause = nullptr; + if (cause.isString()) { + atomCause = AtomizeString(context(), cause.toString()); + if (!atomCause) + return nullptr; + } + savedFrame->initAsyncCause(atomCause); + + return savedFrame; +} + +// Perform the whole recursive reading procedure. bool JSStructuredCloneReader::read(MutableHandleValue vp) { if (!readTransferMap()) return false; + // Start out by reading in the main object and pushing it onto the 'objs' + // stack. The data related to this object and its descendants extends from + // here to the SCTAG_END_OF_KEYS at the end of the stream. if (!startRead(vp)) return false; + // Stop when the stack shows that all objects have been read. while (objs.length() != 0) { + // What happens depends on the top obj on the objs stack. RootedObject obj(context(), &objs.back().toObject()); uint32_t tag, data; if (!in.getPair(&tag, &data)) return false; if (tag == SCTAG_END_OF_KEYS) { + // Pop the current obj off the stack, since we are done with it and + // its children. MOZ_ALWAYS_TRUE(in.readPair(&tag, &data)); objs.popBack(); continue; } + // The input stream contains a sequence of "child" values, whose + // interpretation depends on the type of obj. These values can be + // anything, and startRead() will push onto 'objs' for any non-leaf + // value (i.e., anything that may contain children). + // + // startRead() will allocate the (empty) object, but note that when + // startRead() returns, 'key' is not yet initialized with any of its + // properties. Those will be filled in by returning to the head of this + // loop, processing the first child obj, and continuing until all + // children have been fully created. + // + // Note that this means the ordering in the stream is a little funky + // for things like Map. See the comment above startWrite() for an + // example. RootedValue key(context()); if (!startRead(&key)) return false; - if (key.isNull() && !(obj->is<MapObject>() || obj->is<SetObject>())) { - // Backwards compatibility: Null used to indicate - // the end of object properties. + if (key.isNull() && + !(obj->is<MapObject>() || obj->is<SetObject>() || obj->is<SavedFrame>())) + { + // Backwards compatibility: Null formerly indicated the end of + // object properties. objs.popBack(); continue; } + // Set object: the values between obj header (from startRead()) and + // SCTAG_END_OF_KEYS are all interpreted as values to add to the set. if (obj->is<SetObject>()) { if (!SetObject::add(context(), obj, key)) return false; continue; } + // SavedFrame object: there is one following value, the parent + // SavedFrame, which is either null or another SavedFrame object. + if (obj->is<SavedFrame>()) { + SavedFrame* parentFrame; + if (key.isNull()) + parentFrame = nullptr; + else if (key.isObject() && key.toObject().is<SavedFrame>()) + parentFrame = &key.toObject().as<SavedFrame>(); + else + return false; + + obj->as<SavedFrame>().initParent(parentFrame); + continue; + } + + // Everything else uses a series of key,value,key,value,... Value + // objects. RootedValue val(context()); if (!startRead(&val)) return false; if (obj->is<MapObject>()) { + // For a Map, store those <key,value> pairs in the contained map + // data structure. if (!MapObject::set(context(), obj, key, val)) return false; } else { + // For any other Object, interpret them as plain properties. RootedId id(context()); if (!ValueToId<CanGC>(context(), key, &id)) return false; if (!DefineProperty(context(), obj, id, val)) return false; } }
--- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -284,17 +284,17 @@ public: * for the purposes of clipping, and its scrollbars will be hidden. We use * this to allow RenderOffscreen to render a whole document without beign * clipped by the viewport or drawing the viewport scrollbars. */ void SetIgnoreScrollFrame(nsIFrame* aFrame) { mIgnoreScrollFrame = aFrame; } /** * Get the scrollframe to ignore, if any. */ - nsIFrame* GetIgnoreScrollFrame() const { return mIgnoreScrollFrame; } + nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; } /** * Get the ViewID of the nearest scrolling ancestor frame. */ ViewID GetCurrentScrollParentId() const { return mCurrentScrollParentId; } /** * Get and set the flag that indicates if scroll parents should have layers * forcibly created. This flag is set when a deeply nested scrollframe has * a displayport, and for scroll handoff to work properly the ancestor
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3033,35 +3033,16 @@ nsLayoutUtils::CalculateAndSetDisplayPor ScreenMargin displayportMargins = APZCTreeManager::CalculatePendingDisplayPort( metrics, ParentLayerPoint(0.0f, 0.0f), 0.0); nsIPresShell* presShell = frame->PresContext()->GetPresShell(); return nsLayoutUtils::SetDisplayPortMargins( content, presShell, displayportMargins, 0, aRepaintMode); } bool -nsLayoutUtils::WantDisplayPort(const nsDisplayListBuilder* aBuilder, - nsIFrame* aScrollFrame) -{ - nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame); - if (!scrollableFrame) { - return false; - } - - // We perform an optimization where we ensure that at least one - // async-scrollable frame (i.e. one that WantAsyncScroll()) has a displayport. - // If that's not the case yet, and we are async-scrollable, we will get a - // displayport. - return aBuilder->IsPaintingToWindow() && - nsLayoutUtils::AsyncPanZoomEnabled(aScrollFrame) && - !aBuilder->HaveScrollableDisplayPort() && - scrollableFrame->WantAsyncScroll(); -} - -bool nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder, nsIFrame* aScrollFrame, nsRect aDisplayPortBase, nsRect* aOutDisplayport) { nsIContent* content = aScrollFrame->GetContent(); nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame); if (!content || !scrollableFrame) { return false; @@ -3069,17 +3050,27 @@ nsLayoutUtils::GetOrMaybeCreateDisplayPo // Set the base rect. Note that this will not influence 'haveDisplayPort', // which is based on either the whole rect or margins being set, but it // will affect what is returned in 'aOutDisplayPort' if margins are set. SetDisplayPortBase(content, aDisplayPortBase); bool haveDisplayPort = GetDisplayPort(content, aOutDisplayport); - if (WantDisplayPort(&aBuilder, aScrollFrame)) { + // We perform an optimization where we ensure that at least one + // async-scrollable frame (i.e. one that WantsAsyncScroll()) has a displayport. + // If that's not the case yet, and we are async-scrollable, we will get a + // displayport. + // Note: we only do this in processes where we do subframe scrolling to + // begin with (i.e., not in the parent process on B2G). + if (aBuilder.IsPaintingToWindow() && + nsLayoutUtils::AsyncPanZoomEnabled(aScrollFrame) && + !aBuilder.HaveScrollableDisplayPort() && + scrollableFrame->WantAsyncScroll()) { + // If we don't already have a displayport, calculate and set one. if (!haveDisplayPort) { CalculateAndSetDisplayPortMargins(scrollableFrame, nsLayoutUtils::RepaintMode::DoNotRepaint); haveDisplayPort = GetDisplayPort(content, aOutDisplayport); NS_ASSERTION(haveDisplayPort, "should have a displayport after having just set it"); } // Record that the we now have a scrollable display port. @@ -3137,24 +3128,26 @@ nsLayoutUtils::PaintFrame(nsRenderingCon } if (aFlags & PAINT_IGNORE_SUPPRESSION) { builder.IgnorePaintSuppression(); } nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); bool usingDisplayPort = false; nsRect displayport; - if (rootScrollFrame && !aFrame->GetParent() && - builder.IsPaintingToWindow() && - gfxPrefs::LayoutUseContainersForRootFrames()) { - nsRect displayportBase( - nsPoint(0,0), - nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)); - usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort( - builder, rootScrollFrame, displayportBase, &displayport); + if (rootScrollFrame && !aFrame->GetParent()) { + nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable(); + MOZ_ASSERT(rootScrollableFrame); + displayport = aFrame->GetVisualOverflowRectRelativeToSelf(); + usingDisplayPort = rootScrollableFrame->DecideScrollableLayer(&builder, + &displayport, /* aAllowCreateDisplayPort = */ true); + + if (!gfxPrefs::LayoutUseContainersForRootFrames()) { + usingDisplayPort = false; + } } nsDisplayList hoistedScrollItemStorage; if (builder.IsPaintingToWindow()) { builder.SetCommittedScrollInfoItemList(&hoistedScrollItemStorage); } nsRegion visibleRegion;
--- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2647,22 +2647,16 @@ public: * mode provided is passed through to the call to SetDisplayPortMargins. * The |aScrollFrame| parameter must be non-null and queryable to an nsIFrame. * @return true iff the call to SetDisplayPortMargins returned true. */ static bool CalculateAndSetDisplayPortMargins(nsIScrollableFrame* aScrollFrame, RepaintMode aRepaintMode); /** - * Return true if GetOrMaybeCreateDisplayPort would create a displayport. - */ - static bool WantDisplayPort(const nsDisplayListBuilder* aBuilder, - nsIFrame* aScrollFrame); - - /** * Get the display port for |aScrollFrame|'s content. If |aScrollFrame| * WantsAsyncScroll() and we don't have a scrollable displayport yet (as * tracked by |aBuilder|), calculate and set a display port. Returns true if * there is (now) a displayport, and if so the displayport is returned in * |aOutDisplayport|. * * Note that a displayport can either be stored as a rect, or as a base * rect + margins. If it is stored as a base rect + margins, the base rect
--- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -5846,51 +5846,38 @@ PresShell::UpdateImageVisibility() list.DeleteAll(); #endif } bool PresShell::AssumeAllImagesVisible() { static bool sImageVisibilityEnabled = true; - static bool sImageVisibilityEnabledForBrowserElementsOnly = false; static bool sImageVisibilityPrefCached = false; if (!sImageVisibilityPrefCached) { Preferences::AddBoolVarCache(&sImageVisibilityEnabled, "layout.imagevisibility.enabled", true); - Preferences::AddBoolVarCache(&sImageVisibilityEnabledForBrowserElementsOnly, - "layout.imagevisibility.enabled_for_browser_elements_only", false); sImageVisibilityPrefCached = true; } - if ((!sImageVisibilityEnabled && - !sImageVisibilityEnabledForBrowserElementsOnly) || - !mPresContext || !mDocument) { + if (!sImageVisibilityEnabled || !mPresContext || !mDocument) { return true; } // We assume all images are visible in print, print preview, chrome, xul, and // resource docs and don't keep track of them. if (mPresContext->Type() == nsPresContext::eContext_PrintPreview || mPresContext->Type() == nsPresContext::eContext_Print || mPresContext->IsChrome() || mDocument->IsResourceDoc() || mDocument->IsXULDocument()) { return true; } - if (!sImageVisibilityEnabled && - sImageVisibilityEnabledForBrowserElementsOnly) { - nsCOMPtr<nsIDocShell> docshell(mPresContext->GetDocShell()); - if (!docshell || !docshell->GetIsInBrowserElement()) { - return true; - } - } - return false; } void PresShell::ScheduleImageVisibilityUpdate() { if (AssumeAllImagesVisible()) return;
--- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -56,16 +56,17 @@ #include "nsIFrameInlines.h" #include "gfxPlatform.h" #include "gfxPrefs.h" #include "AsyncScrollBase.h" #include "UnitTransforms.h" #include "nsPluginFrame.h" #include <mozilla/layers/AxisPhysicsModel.h> #include <mozilla/layers/AxisPhysicsMSDModel.h> +#include "mozilla/unused.h" #include <algorithm> #include <cstdlib> // for std::abs(int/long) #include <cmath> // for std::abs(float/double) using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::layout; @@ -1840,17 +1841,17 @@ ScrollFrameHelper::ScrollFrameHelper(nsC , mHadNonInitialReflow(false) , mHorizontalOverflow(false) , mVerticalOverflow(false) , mPostedReflowCallback(false) , mMayHaveDirtyFixedChildren(false) , mUpdateScrollbarAttributes(false) , mHasBeenScrolledRecently(false) , mCollapsedResizer(false) - , mShouldBuildScrollableLayer(false) + , mWillBuildScrollableLayer(false) , mIsScrollableLayerInRootContainer(false) , mHasBeenScrolled(false) , mIsResolutionSet(false) , mIgnoreMomentumScroll(false) , mScaleToResolution(false) , mTransformingByAPZ(false) , mZoomableByAPZ(false) , mVelocityQueue(aOuter->PresContext()) @@ -2819,63 +2820,16 @@ ClipListsExceptCaret(nsDisplayListCollec ClipItemsExceptCaret(aLists->BorderBackground(), aBuilder, aClipFrame, clip, aUsingDisplayPort); ClipItemsExceptCaret(aLists->BlockBorderBackgrounds(), aBuilder, aClipFrame, clip, aUsingDisplayPort); ClipItemsExceptCaret(aLists->Floats(), aBuilder, aClipFrame, clip, aUsingDisplayPort); ClipItemsExceptCaret(aLists->PositionedDescendants(), aBuilder, aClipFrame, clip, aUsingDisplayPort); ClipItemsExceptCaret(aLists->Outlines(), aBuilder, aClipFrame, clip, aUsingDisplayPort); ClipItemsExceptCaret(aLists->Content(), aBuilder, aClipFrame, clip, aUsingDisplayPort); } -bool -ScrollFrameHelper::IsUsingDisplayPort(const nsDisplayListBuilder* aBuilder) const -{ - return aBuilder->IsPaintingToWindow() && - nsLayoutUtils::GetDisplayPort(mOuter->GetContent()); -} - -bool -ScrollFrameHelper::WillUseDisplayPort(const nsDisplayListBuilder* aBuilder) const -{ - bool wantsDisplayPort = nsLayoutUtils::WantDisplayPort(aBuilder, mOuter); - - if (mIsRoot && gfxPrefs::LayoutUseContainersForRootFrames()) { - // This condition mirrors the calls to GetOrMaybeCreateDisplayPort in - // nsSubDocumentFrame::BuildDisplayList and nsLayoutUtils::PaintFrame. - if (wantsDisplayPort) { - return true; - } - } - - // The following conditions mirror the checks in BuildDisplayList - - if (IsUsingDisplayPort(aBuilder)) { - return true; - } - - if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) { - return false; - } - - return wantsDisplayPort; -} - -bool -ScrollFrameHelper::WillBuildScrollableLayer(const nsDisplayListBuilder* aBuilder) const -{ - if (WillUseDisplayPort(aBuilder)) { - return true; - } - - if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) { - return false; - } - - return nsContentUtils::HasScrollgrab(mOuter->GetContent()); -} - void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { if (aBuilder->IsForImageVisibility()) { mLastUpdateImagesPos = GetScrollPosition(); } @@ -2906,31 +2860,24 @@ ScrollFrameHelper::BuildDisplayList(nsDi // they're not scrolled with the rest of the document. But when both // scrollbars are visible, the layer's visible rectangle would be the size // of the viewport, so most layer implementations would create a layer buffer // that's much larger than necessary. Creating independent layers for each // scrollbar works around the problem. bool createLayersForScrollbars = mIsRoot && mOuter->PresContext()->IsRootContentDocument(); - bool usingDisplayPort = IsUsingDisplayPort(aBuilder); - mShouldBuildScrollableLayer = WillBuildScrollableLayer(aBuilder); - if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) { + bool usingDisplayPort = aBuilder->IsPaintingToWindow() && + nsLayoutUtils::GetDisplayPort(mOuter->GetContent()); + // Root scrollframes have FrameMetrics and clipping on their container // layers, so don't apply clipping again. mAddClipRectToLayer = false; - if (usingDisplayPort) { - // There is a display port for this frame, so we want to appear as having - // active scrolling, so that animated geometry roots are assigned correctly. - MOZ_ASSERT(mShouldBuildScrollableLayer); - mIsScrollableLayerInRootContainer = true; - } - // If we are a root scroll frame that has a display port we want to add // scrollbars, they will be children of the scrollable layer, but they get // adjusted by the APZC automatically. bool addScrollBars = mIsRoot && usingDisplayPort && !aBuilder->IsForEventDelivery(); if (addScrollBars) { // Add classic scrollbars. AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, usingDisplayPort, @@ -2962,63 +2909,32 @@ ScrollFrameHelper::BuildDisplayList(nsDi // non-moving frames. // Not all our descendants will be clipped by overflow clipping, but all // the ones that aren't clipped will be out of flow frames that have already // had dirty rects saved for them by their parent frames calling // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our // dirty rect here. nsRect dirtyRect = aDirtyRect.Intersect(mScrollPort); - nsRect displayPort; - if (aBuilder->IsPaintingToWindow()) { - bool wasUsingDisplayPort = usingDisplayPort; - - if (mIsRoot && gfxPrefs::LayoutUseContainersForRootFrames()) { - // For a root frame in a container, just get the value of the existing - // display port if any. - usingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort); - } else { - // Override the value of the display port base rect, and possibly create a - // display port if there isn't one already. - nsRect displayportBase = dirtyRect; - if (mIsRoot && mOuter->PresContext()->IsRootContentDocument()) { - displayportBase = - nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter)); - } - usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort( - *aBuilder, mOuter, displayportBase, &displayPort); - } - - // Override the dirty rectangle if the displayport has been set. - if (usingDisplayPort) { - dirtyRect = displayPort; - - // The cached animated geometry root for the display builder is out of - // date if we just introduced a new animated geometry root. - if (!wasUsingDisplayPort) { - aBuilder->RecomputeCurrentAnimatedGeometryRoot(); - } - } - } - - // Since making new layers is expensive, only use nsDisplayScrollLayer - // if the area is scrollable and we're the content process (unless we're on - // B2G, where we support async scrolling for scrollable elements in the - // parent process as well). - // When a displayport is being used, force building of a layer so that - // CompositorParent can always find the scrollable layer for the root content - // document. - // If the element is marked 'scrollgrab', also force building of a layer - // so that APZ can implement scroll grabbing. - MOZ_ASSERT(mShouldBuildScrollableLayer == (usingDisplayPort || nsContentUtils::HasScrollgrab(mOuter->GetContent()))); - bool shouldBuildLayer = false; - if (mShouldBuildScrollableLayer) { - shouldBuildLayer = true; + unused << DecideScrollableLayer(aBuilder, &dirtyRect, + /* aAllowCreateDisplayPort = */ !mIsRoot); + + bool usingDisplayPort = aBuilder->IsPaintingToWindow() && + nsLayoutUtils::GetDisplayPort(mOuter->GetContent()); + + // Whether we might want to build a scrollable layer for this scroll frame + // at some point in the future. This controls whether we add the information + // to the layer tree (a scroll info layer if necessary, and add the right + // area to the dispatch to content layer event regions) necessary to activate + // a scroll frame so it creates a scrollable layer. + bool couldBuildLayer = false; + if (mWillBuildScrollableLayer) { + couldBuildLayer = true; } else { - shouldBuildLayer = + couldBuildLayer = nsLayoutUtils::AsyncPanZoomEnabled(mOuter) && WantAsyncScroll() && // If we are using containers for root frames, and we are the root // scroll frame for the display root, then we don't need a scroll // info layer. nsDisplayList::PaintForFrame already calls // ComputeFrameMetrics for us. (!(gfxPrefs::LayoutUseContainersForRootFrames() && mIsRoot) || (aBuilder->RootReferenceFrame()->PresContext() != mOuter->PresContext())); @@ -3078,17 +2994,17 @@ ScrollFrameHelper::BuildDisplayList(nsDi { // Note that setting the current scroll parent id here means that positioned children // of this scroll info layer will pick up the scroll info layer as their scroll handoff // parent. This is intentional because that is what happens for positioned children // of scroll layers, and we want to maintain consistent behaviour between scroll layers // and scroll info layers. nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter( aBuilder, - shouldBuildLayer && mScrolledFrame->GetContent() + couldBuildLayer && mScrolledFrame->GetContent() ? nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent()) : aBuilder->GetCurrentScrollParentId()); // We need to apply at least one clip, potentially more, and each needs to be applied // through a separate DisplayListClipState::AutoSaveRestore object. // clipStatePtr will always point to the innermost used one. DisplayListClipState::AutoSaveRestore clipState(aBuilder); DisplayListClipState::AutoSaveRestore* clipStatePtr = &clipState; @@ -3157,37 +3073,36 @@ ScrollFrameHelper::BuildDisplayList(nsDi if (idSetter.ShouldForceLayerForScrollParent() && !gfxPrefs::LayoutUseContainersForRootFrames()) { // Note that forcing layerization of scroll parents follows the scroll // handoff chain which is subject to the out-of-flow-frames caveat noted // above (where the idSetter variable is created). // // This is not compatible when using containes for root scrollframes. - MOZ_ASSERT(shouldBuildLayer && mScrolledFrame->GetContent()); - mShouldBuildScrollableLayer = true; + MOZ_ASSERT(couldBuildLayer && mScrolledFrame->GetContent()); + mWillBuildScrollableLayer = true; } } - if (mShouldBuildScrollableLayer && !gfxPrefs::LayoutUseContainersForRootFrames()) { + if (mWillBuildScrollableLayer && !gfxPrefs::LayoutUseContainersForRootFrames()) { aBuilder->ForceLayerForScrollParent(); } if (contentBoxClipForNonCaretContent) { ClipListsExceptCaret(&scrolledContent, aBuilder, mScrolledFrame, *contentBoxClipForNonCaretContent, usingDisplayPort); } - if (shouldBuildLayer) { + if (couldBuildLayer) { // Make sure that APZ will dispatch events back to content so we can create // a displayport for this frame. We'll add the item later on. nsDisplayLayerEventRegions* inactiveRegionItem = nullptr; if (aBuilder->IsPaintingToWindow() && - !mShouldBuildScrollableLayer && - shouldBuildLayer && + !mWillBuildScrollableLayer && aBuilder->IsBuildingLayerEventRegions()) { inactiveRegionItem = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, mScrolledFrame); inactiveRegionItem->AddInactiveScrollPort(mScrollPort + aBuilder->ToReferenceFrame(mOuter)); } if (inactiveRegionItem) { nsDisplayList* positionedDescendants = scrolledContent.PositionedDescendants(); @@ -3209,34 +3124,92 @@ ScrollFrameHelper::BuildDisplayList(nsDi } } // Now display overlay scrollbars and the resizer, if we have one. AppendScrollPartsTo(aBuilder, aDirtyRect, scrolledContent, usingDisplayPort, createLayersForScrollbars, true); scrolledContent.MoveTo(aLists); } +bool +ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder, + nsRect* aDirtyRect, + bool aAllowCreateDisplayPort) +{ + bool usingDisplayPort = false; + nsIContent* content = mOuter->GetContent(); + if (aBuilder->IsPaintingToWindow()) { + bool wasUsingDisplayPort = nsLayoutUtils::GetDisplayPort(content); + + nsRect displayportBase = *aDirtyRect; + nsPresContext* pc = mOuter->PresContext(); + if (mIsRoot && (pc->IsRootContentDocument() || !pc->GetParentPresContext())) { + displayportBase = + nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter)); + } + + nsRect displayPort; + if (aAllowCreateDisplayPort) { + // Provide the value of the display port base rect, and possibly create a + // display port if there isn't one already. + usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort( + *aBuilder, mOuter, displayportBase, &displayPort); + } else { + // We should have already been called with aAllowCreateDisplayPort == true + // which should have set a displayport base. + MOZ_ASSERT(content->GetProperty(nsGkAtoms::DisplayPortBase)); + usingDisplayPort = nsLayoutUtils::GetDisplayPort(content, &displayPort); + } + + // Override the dirty rectangle if the displayport has been set. + if (usingDisplayPort) { + *aDirtyRect = displayPort; + + // The cached animated geometry root for the display builder is out of + // date if we just introduced a new animated geometry root. + if (!wasUsingDisplayPort) { + aBuilder->RecomputeCurrentAnimatedGeometryRoot(); + } + } + } + + // Since making new layers is expensive, only create a scrollable layer + // for some scroll frames. + // When a displayport is being used, force building of a layer so that + // the compositor can find the scrollable layer for async scrolling. + // If the element is marked 'scrollgrab', also force building of a layer + // so that APZ can implement scroll grabbing. + mWillBuildScrollableLayer = usingDisplayPort || nsContentUtils::HasScrollgrab(content); + + if (gfxPrefs::LayoutUseContainersForRootFrames() && mWillBuildScrollableLayer && mIsRoot) { + mIsScrollableLayerInRootContainer = true; + } + + return mWillBuildScrollableLayer; +} + + Maybe<DisplayItemClip> ScrollFrameHelper::ComputeScrollClip(bool aIsForCaret) const { const Maybe<DisplayItemClip>& ancestorClip = aIsForCaret ? mAncestorClipForCaret : mAncestorClip; - if (!mShouldBuildScrollableLayer || mIsScrollableLayerInRootContainer) { + if (!mWillBuildScrollableLayer || mIsScrollableLayerInRootContainer) { return Nothing(); } return ancestorClip; } Maybe<FrameMetricsAndClip> ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer, nsIFrame* aContainerReferenceFrame, const ContainerLayerParameters& aParameters, bool aIsForCaret) const { - if (!mShouldBuildScrollableLayer || mIsScrollableLayerInRootContainer) { + if (!mWillBuildScrollableLayer || mIsScrollableLayerInRootContainer) { return Nothing(); } bool needsParentLayerClip = true; if (gfxPrefs::LayoutUseContainersForRootFrames() && !mAddClipRectToLayer) { // For containerful frames, the clip is on the container frame. needsParentLayerClip = false; } @@ -4493,32 +4466,31 @@ ScrollFrameHelper::IsMaybeScrollingActiv { const nsStyleDisplay* disp = mOuter->StyleDisplay(); if (disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL)) { return true; } return mHasBeenScrolledRecently || IsAlwaysActive() || - mShouldBuildScrollableLayer; + mWillBuildScrollableLayer; } bool ScrollFrameHelper::IsScrollingActive(nsDisplayListBuilder* aBuilder) const { const nsStyleDisplay* disp = mOuter->StyleDisplay(); if (disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL) && aBuilder->IsInWillChangeBudget(mOuter, GetScrollPositionClampingScrollPortSize())) { return true; } return mHasBeenScrolledRecently || IsAlwaysActive() || - mShouldBuildScrollableLayer || - WillBuildScrollableLayer(aBuilder); + mWillBuildScrollableLayer; } /** * Reflow the scroll area if it needs it and return its size. Also determine if the reflow will * cause any of the scrollbars to need to be reflowed. */ nsresult nsXULScrollFrame::Layout(nsBoxLayoutState& aState)
--- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -76,20 +76,16 @@ public: void AppendScrollPartsTo(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists, bool aUsingDisplayPort, bool aCreateLayer, bool aPositioned); - bool IsUsingDisplayPort(const nsDisplayListBuilder* aBuilder) const; - bool WillUseDisplayPort(const nsDisplayListBuilder* aBuilder) const; - bool WillBuildScrollableLayer(const nsDisplayListBuilder* aBuilder) const; - bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea, Sides aSkipSides, nscoord aRadii[8]) const; // nsIReflowCallback virtual bool ReflowFinished() override; virtual void ReflowCallbackCanceled() override; /** @@ -365,16 +361,20 @@ public: } bool IsTransformingByAPZ() const { return mTransformingByAPZ; } void SetZoomableByAPZ(bool aZoomable); bool UsesContainerScrolling() const; + bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, + nsRect* aDirtyRect, + bool aAllowCreateDisplayPort); + void ScheduleSyntheticMouseMove(); static void ScrollActivityCallback(nsITimer *aTimer, void* anInstance); void HandleScrollbarStyleSwitching(); nsIAtom* LastScrollOrigin() const { return mLastScrollOrigin; } nsIAtom* LastSmoothScrollOrigin() const { return mLastSmoothScrollOrigin; } uint32_t CurrentScrollGeneration() const { return mScrollGeneration; } @@ -385,17 +385,17 @@ public: mLastSmoothScrollOrigin = nullptr; } } bool WantAsyncScroll() const; Maybe<FrameMetricsAndClip> ComputeFrameMetrics( Layer* aLayer, nsIFrame* aContainerReferenceFrame, const ContainerLayerParameters& aParameters, bool aIsForCaret) const; - virtual mozilla::Maybe<mozilla::DisplayItemClip> ComputeScrollClip(bool aIsForCaret) const; + mozilla::Maybe<mozilla::DisplayItemClip> ComputeScrollClip(bool aIsForCaret) const; // nsIScrollbarMediator void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection, nsIScrollbarMediator::ScrollSnapMode aSnap = nsIScrollbarMediator::DISABLE_SNAP); void ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection, nsIScrollbarMediator::ScrollSnapMode aSnap = nsIScrollbarMediator::DISABLE_SNAP); @@ -505,19 +505,19 @@ public: // reflow callback. bool mUpdateScrollbarAttributes:1; // If true, we should be prepared to scroll using this scrollframe // by placing descendant content into its own layer(s) bool mHasBeenScrolledRecently:1; // If true, the resizer is collapsed and not displayed bool mCollapsedResizer:1; - // If true, the layer should always be active because we always build a - // scrollable layer. Used for asynchronous scrolling. - bool mShouldBuildScrollableLayer:1; + // If true, the scroll frame should always be active because we always build + // a scrollable layer. Used for asynchronous scrolling. + bool mWillBuildScrollableLayer:1; // Whether we are the root scroll frame that is used for containerful // scrolling with a display port. If true, the scrollable frame // shouldn't attach frame metrics to its layers because the container // will already have the necessary frame metrics. bool mIsScrollableLayerInRootContainer:1; // If true, add clipping in ScrollFrameHelper::ComputeFrameMetrics. @@ -872,16 +872,21 @@ public: return mHelper.IsIgnoringViewportClipping(); } virtual void MarkScrollbarsDirtyForReflow() const override { mHelper.MarkScrollbarsDirtyForReflow(); } virtual bool UsesContainerScrolling() const override { return mHelper.UsesContainerScrolling(); } + virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, + nsRect* aDirtyRect, + bool aAllowCreateDisplayPort) override { + return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort); + } // nsIStatefulFrame NS_IMETHOD SaveState(nsPresState** aState) override { NS_ENSURE_ARG_POINTER(aState); *aState = mHelper.SaveState(); return NS_OK; } NS_IMETHOD RestoreState(nsPresState* aState) override { @@ -1350,16 +1355,22 @@ public: return mHelper.UsesContainerScrolling(); } bool IsTransformingByAPZ() const override { return mHelper.IsTransformingByAPZ(); } void SetZoomableByAPZ(bool aZoomable) override { mHelper.SetZoomableByAPZ(aZoomable); } + virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, + nsRect* aDirtyRect, + bool aAllowCreateDisplayPort) override { + return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort); + } + #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; #endif protected: nsXULScrollFrame(nsStyleContext* aContext, bool aIsRoot, bool aClipAllDescendants);
--- a/layout/generic/nsIScrollableFrame.h +++ b/layout/generic/nsIScrollableFrame.h @@ -450,11 +450,24 @@ public: virtual void SetZoomableByAPZ(bool aZoomable) = 0; /** * Whether or not this frame uses containerful scrolling. */ virtual bool UsesContainerScrolling() const = 0; virtual mozilla::Maybe<mozilla::DisplayItemClip> ComputeScrollClip(bool aIsForCaret) const = 0; + + /** + * Determine if we should build a scrollable layer for this scroll frame and + * return the result. It will also record this result on the scroll frame. + * Pass the dirty rect in aDirtyRect. On return it will be set to the + * displayport if there is one (ie the dirty rect that should be used). + * This function may create a display port where one did not exist before if + * aAllowCreateDisplayPort is true. It is only allowed to be false if there + * has been a call with it set to true before on the same paint. + */ + virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, + nsRect* aDirtyRect, + bool aAllowCreateDisplayPort) = 0; }; #endif
--- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -411,28 +411,23 @@ nsSubDocumentFrame::BuildDisplayList(nsD nsIFrame* savedIgnoreScrollFrame = nullptr; if (subdocRootFrame) { // get the dirty rect relative to the root frame of the subdoc dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); // and convert into the appunits of the subdoc dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD); if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) { - if (gfxPrefs::LayoutUseContainersForRootFrames()) { - // for root content documents we want the base to be the composition bounds - nsRect displayportBase = presContext->IsRootContentDocument() ? - nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)) : - dirty.Intersect(nsRect(nsPoint(0,0), subdocRootFrame->GetSize())); - nsRect displayPort; - if (aBuilder->IsPaintingToWindow() && - nsLayoutUtils::GetOrMaybeCreateDisplayPort( - *aBuilder, rootScrollFrame, displayportBase, &displayPort)) { - haveDisplayPort = true; - dirty = displayPort; - } + nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable(); + MOZ_ASSERT(rootScrollableFrame); + haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder, + &dirty, /* aAllowCreateDisplayPort = */ true); + + if (!gfxPrefs::LayoutUseContainersForRootFrames()) { + haveDisplayPort = false; } ignoreViewportScrolling = presShell->IgnoringViewportScrolling(); if (ignoreViewportScrolling) { savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame(); aBuilder->SetIgnoreScrollFrame(rootScrollFrame); if (aBuilder->IsForImageVisibility()) {
--- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -13,16 +13,27 @@ #include "mozilla/css/Loader.h" #include "nsIFile.h" #include "nsNetUtil.h" #include "nsIObserverService.h" #include "nsServiceManagerUtils.h" #include "nsIXULRuntime.h" #include "nsPrintfCString.h" +// Includes for the crash report annotation in ErrorLoadingBuiltinSheet. +#ifdef MOZ_CRASHREPORTER +#include "mozilla/Omnijar.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsExceptionHandler.h" +#include "nsIChromeRegistry.h" +#include "nsISimpleEnumerator.h" +#include "nsISubstitutingProtocolHandler.h" +#endif + using namespace mozilla; static bool sNumberControlEnabled; #define NUMBER_CONTROL_PREF "dom.forms.number" NS_IMPL_ISUPPORTS( nsLayoutStylesheetCache, nsIObserver, nsIMemoryReporter) @@ -449,19 +460,259 @@ nsLayoutStylesheetCache::LoadSheetFile(n if (!exists) return; nsCOMPtr<nsIURI> uri; NS_NewFileURI(getter_AddRefs(uri), aFile); LoadSheet(uri, aSheet, false); } +#ifdef MOZ_CRASHREPORTER +static void +ListInterestingFiles(nsString& aAnnotation, nsIFile* aFile, + const nsTArray<nsString>& aInterestingFilenames) +{ + nsString filename; + aFile->GetLeafName(filename); + for (const nsString& interestingFilename : aInterestingFilenames) { + if (interestingFilename == filename) { + nsString path; + aFile->GetPath(path); + aAnnotation.AppendLiteral(" "); + aAnnotation.Append(path); + aAnnotation.AppendLiteral(" ("); + int64_t size; + if (NS_SUCCEEDED(aFile->GetFileSize(&size))) { + aAnnotation.AppendPrintf("%ld", size); + } else { + aAnnotation.AppendLiteral("???"); + } + aAnnotation.AppendLiteral(" bytes)\n"); + return; + } + } + + bool isDir = false; + aFile->IsDirectory(&isDir); + + if (!isDir) { + return; + } + + nsCOMPtr<nsISimpleEnumerator> entries; + if (NS_FAILED(aFile->GetDirectoryEntries(getter_AddRefs(entries)))) { + aAnnotation.AppendLiteral(" (failed to enumerated directory)\n"); + return; + } + + for (;;) { + bool hasMore = false; + if (NS_FAILED(entries->HasMoreElements(&hasMore))) { + aAnnotation.AppendLiteral(" (failed during directory enumeration)\n"); + return; + } + if (!hasMore) { + break; + } + + nsCOMPtr<nsISupports> entry; + if (NS_FAILED(entries->GetNext(getter_AddRefs(entry)))) { + aAnnotation.AppendLiteral(" (failed during directory enumeration)\n"); + return; + } + + nsCOMPtr<nsIFile> file = do_QueryInterface(entry); + if (file) { + ListInterestingFiles(aAnnotation, file, aInterestingFilenames); + } + } +} + +// Generate a crash report annotation to help debug issues with style +// sheets failing to load (bug 1194856). +static void +AnnotateCrashReport(nsIURI* aURI) +{ + nsAutoCString spec; + nsAutoCString scheme; + nsDependentCSubstring filename; + if (aURI) { + aURI->GetSpec(spec); + aURI->GetScheme(scheme); + int32_t i = spec.RFindChar('/'); + if (i != -1) { + filename.Rebind(spec, i + 1); + } + } + + nsString annotation; + + // The URL of the sheet that failed to load. + annotation.AppendLiteral("Error loading sheet: "); + annotation.Append(NS_ConvertUTF8toUTF16(spec).get()); + annotation.Append('\n'); + + // The jar: or file: URL that the sheet's resource: or chrome: URL + // resolves to. + if (scheme.EqualsLiteral("resource")) { + annotation.AppendLiteral("Real location: "); + nsCOMPtr<nsISubstitutingProtocolHandler> handler; + nsCOMPtr<nsIIOService> io(do_GetIOService()); + if (io) { + nsCOMPtr<nsIProtocolHandler> ph; + io->GetProtocolHandler(scheme.get(), getter_AddRefs(ph)); + if (ph) { + handler = do_QueryInterface(ph); + } + } + if (!handler) { + annotation.AppendLiteral("(ResolveURI failed)\n"); + } else { + nsAutoCString resolvedSpec; + handler->ResolveURI(aURI, resolvedSpec); + annotation.Append(NS_ConvertUTF8toUTF16(resolvedSpec)); + annotation.Append('\n'); + } + } else if (scheme.EqualsLiteral("chrome")) { + annotation.AppendLiteral("Real location: "); + nsCOMPtr<nsIChromeRegistry> reg = + mozilla::services::GetChromeRegistryService(); + if (!reg) { + annotation.AppendLiteral("(no chrome registry)\n"); + } else { + nsCOMPtr<nsIURI> resolvedURI; + reg->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI)); + if (!resolvedURI) { + annotation.AppendLiteral("(ConvertChromeURL failed)\n"); + } else { + nsAutoCString resolvedSpec; + resolvedURI->GetSpec(resolvedSpec); + annotation.Append(NS_ConvertUTF8toUTF16(resolvedSpec)); + annotation.Append('\n'); + } + } + } + + nsTArray<nsString> interestingFiles; + interestingFiles.AppendElement(NS_LITERAL_STRING("chrome.manifest")); + interestingFiles.AppendElement(NS_LITERAL_STRING("omni.ja")); + interestingFiles.AppendElement(NS_ConvertUTF8toUTF16(filename)); + + annotation.AppendLiteral("GRE directory: "); + nsCOMPtr<nsIFile> file; + nsDirectoryService::gService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), + getter_AddRefs(file)); + if (file) { + // The Firefox installation directory. + nsString path; + file->GetPath(path); + annotation.Append(path); + annotation.Append('\n'); + + // List interesting files -- any chrome.manifest or omni.ja file or any file + // whose name is the sheet's filename -- under the Firefox installation + // directory. + annotation.AppendLiteral("Interesting files in the GRE directory:\n"); + ListInterestingFiles(annotation, file, interestingFiles); + + // If the Firefox installation directory has a chrome.manifest file, let's + // see what's in it. + file->Append(NS_LITERAL_STRING("chrome.manifest")); + bool exists = false; + file->Exists(&exists); + if (exists) { + annotation.AppendLiteral("Contents of chrome.manifest:\n[[[\n"); + PRFileDesc* fd; + if (NS_SUCCEEDED(file->OpenNSPRFileDesc(PR_RDONLY, 0, &fd))) { + nsCString contents; + char buf[512]; + int32_t n; + while ((n = PR_Read(fd, buf, sizeof(buf))) > 0) { + contents.Append(buf, n); + } + if (n < 0) { + annotation.AppendLiteral(" (error while reading)\n"); + } else { + annotation.Append(NS_ConvertUTF8toUTF16(contents)); + } + PR_Close(fd); + } + annotation.AppendLiteral("]]]\n"); + } + } else { + annotation.AppendLiteral("(none)\n"); + } + + // The jar: or file: URL prefix that chrome: and resource: URLs get translated + // to. + annotation.AppendLiteral("GRE omnijar URI string: "); + nsCString uri; + nsresult rv = Omnijar::GetURIString(Omnijar::GRE, uri); + if (NS_FAILED(rv)) { + annotation.AppendLiteral("(failed)\n"); + } else { + annotation.Append(NS_ConvertUTF8toUTF16(uri)); + annotation.Append('\n'); + } + + nsRefPtr<nsZipArchive> zip = Omnijar::GetReader(Omnijar::GRE); + if (zip) { + // List interesting files in the GRE omnijar. + annotation.AppendLiteral("Interesting files in the GRE omnijar:\n"); + nsZipFind* find; + rv = zip->FindInit(nullptr, &find); + if (NS_FAILED(rv)) { + annotation.AppendPrintf(" (FindInit failed with 0x%08x)\n", rv); + } else if (!find) { + annotation.AppendLiteral(" (FindInit returned null)\n"); + } else { + const char* result; + uint16_t len; + while (NS_SUCCEEDED(find->FindNext(&result, &len))) { + nsCString itemPathname; + nsString itemFilename; + itemPathname.Append(result, len); + int32_t i = itemPathname.RFindChar('/'); + if (i != -1) { + itemFilename = NS_ConvertUTF8toUTF16(Substring(itemPathname, i + 1)); + } + for (const nsString& interestingFile : interestingFiles) { + if (interestingFile == itemFilename) { + annotation.AppendLiteral(" "); + annotation.Append(NS_ConvertUTF8toUTF16(itemPathname)); + nsZipItem* item = zip->GetItem(itemPathname.get()); + if (!item) { + annotation.AppendLiteral(" (GetItem failed)\n"); + } else { + annotation.AppendPrintf(" (%d bytes, crc32 = 0x%08x)\n", + item->RealSize(), + item->CRC32()); + } + break; + } + } + } + delete find; + } + } else { + annotation.AppendLiteral("No GRE omnijar\n"); + } + + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("SheetLoadFailure"), + NS_ConvertUTF16toUTF8(annotation)); +} +#endif + static void ErrorLoadingBuiltinSheet(nsIURI* aURI, const char* aMsg) { +#ifdef MOZ_CRASHREPORTER + AnnotateCrashReport(aURI); +#endif + nsAutoCString spec; if (aURI) { aURI->GetSpec(spec); } NS_RUNTIMEABORT(nsPrintfCString("%s loading built-in stylesheet '%s'", aMsg, spec.get()).get()); }
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -927,20 +927,16 @@ pref("nglayout.debug.paint_flashing_chro pref("nglayout.debug.widget_update_flashing", false); // Enable/disable display list invalidation logging --- useful for debugging. pref("nglayout.debug.invalidation", false); // Whether image visibility is enabled globally (ie we will try to unlock images // that are not visible). pref("layout.imagevisibility.enabled", true); -// Whether image visibility is enabled in documents that are within a browser -// element as defined by nsDocShell::FrameType and GetInheritedFrameType. This -// pref only has an effect if layout.imagevisibility.enabled is false. -pref("layout.imagevisibility.enabled_for_browser_elements_only", false); pref("layout.imagevisibility.numscrollportwidths", 0); pref("layout.imagevisibility.numscrollportheights", 1); // scrollbar snapping region // 0 - off // 1 and higher - slider thickness multiple pref("slider.snapMultiplier", 0);
--- a/mozglue/linker/ElfLoader.h +++ b/mozglue/linker/ElfLoader.h @@ -3,16 +3,17 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef ElfLoader_h #define ElfLoader_h #include <vector> #include <dlfcn.h> #include <signal.h> +#include "mozilla/RefCounted.h" #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" #include "Zip.h" #include "Elfxx.h" #include "Mappable.h" /** * dlfcn.h replacement functions
--- a/mozglue/linker/Zip.h +++ b/mozglue/linker/Zip.h @@ -6,16 +6,17 @@ #define Zip_h #include <cstring> #include <stdint.h> #include <vector> #include <zlib.h> #include "Utils.h" #include "mozilla/Assertions.h" +#include "mozilla/RefCounted.h" #include "mozilla/RefPtr.h" /** * Helper class wrapping z_stream to avoid malloc() calls during * inflate. Do not use for deflate. * inflateInit allocates two buffers: * - one for its internal state, which is "approximately 10K bytes" according * to inflate.h from zlib.
--- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -2581,19 +2581,16 @@ def run_test_harness(options): if key.startswith('log') or key == 'valgrind' } runner = Mochitest(logger_options) options.runByDir = False if runner.getTestFlavor(options) == 'mochitest': options.runByDir = True - if mozinfo.info['asan'] and options.e10s: - options.runByDir = False - if runner.getTestFlavor(options) == 'browser-chrome': options.runByDir = True if runner.getTestFlavor(options) == 'chrome': options.runByDir = True if mozinfo.info.get('buildapp') == 'mulet': options.runByDir = False
deleted file mode 100644 --- a/testing/web-platform/meta/dom/nodes/Node-isEqualNode.xhtml.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Node-isEqualNode.xhtml] - type: testharness - [isEqualNode should return true when only the internal subsets of DocumentTypes differ.] - expected: FAIL -
deleted file mode 100644 --- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.title-03.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[document.title-03.html] - type: testharness - [ document.title and space normalization ] - expected: FAIL -
deleted file mode 100644 --- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.title-04.xhtml.ini +++ /dev/null @@ -1,5 +0,0 @@ -[document.title-04.xhtml] - type: testharness - [ document.title and space normalization ] - expected: FAIL -
deleted file mode 100644 --- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.title-07.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[document.title-07.html] - type: testharness - [createHTMLDocument test 6: "foo\\f\\fbar baz","foo\\f\\fbar baz","foo bar baz"] - expected: FAIL -
--- a/testing/web-platform/meta/html/editing/focus/focus-management/focus-events.html.ini +++ b/testing/web-platform/meta/html/editing/focus/focus-management/focus-events.html.ini @@ -5,16 +5,14 @@ if e10s and (os == "linux"): https://bugzilla.mozilla.org/show_bug.cgi?id=1203917 expected: if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT [focusing on a focusable element fires a focus event at the element] expected: if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): NOTRUN if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): NOTRUN - FAIL [focusing on a focusable element fires a blur event at the previous focussed element] expected: if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): NOTRUN if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): NOTRUN - FAIL
deleted file mode 100644 --- a/testing/web-platform/meta/html/semantics/forms/the-option-element/option-text-spaces.html.ini +++ /dev/null @@ -1,41 +0,0 @@ -[option-text-spaces.html] - type: testharness - [option.text should strip leading space characters ("\\f")] - expected: FAIL - - [option.text should strip trailing space characters ("\\f")] - expected: FAIL - - [option.text should strip leading and trailing space characters ("\\f")] - expected: FAIL - - [option.text should replace single internal space characters ("\\f")] - expected: FAIL - - [option.text should replace multiple internal space characters (" ", "\\f")] - expected: FAIL - - [option.text should replace multiple internal space characters ("\\t", "\\f")] - expected: FAIL - - [option.text should replace multiple internal space characters ("\\n", "\\f")] - expected: FAIL - - [option.text should replace multiple internal space characters ("\\f", " ")] - expected: FAIL - - [option.text should replace multiple internal space characters ("\\f", "\\t")] - expected: FAIL - - [option.text should replace multiple internal space characters ("\\f", "\\n")] - expected: FAIL - - [option.text should replace multiple internal space characters ("\\f", "\\f")] - expected: FAIL - - [option.text should replace multiple internal space characters ("\\f", "\\r")] - expected: FAIL - - [option.text should replace multiple internal space characters ("\\r", "\\f")] - expected: FAIL -
--- a/toolkit/components/extensions/ext-webRequest.js +++ b/toolkit/components/extensions/ext-webRequest.js @@ -89,16 +89,39 @@ function WebRequestEventManager(context, return SingletonEventManager.call(this, context, name, register); } WebRequestEventManager.prototype = Object.create(SingletonEventManager.prototype); extensions.registerPrivilegedAPI("webRequest", (extension, context) => { return { webRequest: { + ResourceType: { + MAIN_FRAME: "main_frame", + SUB_FRAME: "sub_frame", + STYLESHEET: "stylesheet", + SCRIPT: "script", + IMAGE: "image", + OBJECT: "object", + OBJECT_SUBREQUEST: "object_subrequest", + XMLHTTPREQUEST: "xmlhttprequest", + XBL: "xbl", + XSLT: "xslt", + PING: "ping", + BEACON: "beacon", + XML_DTD: "xml_dtd", + FONT: "font", + MEDIA: "media", + WEBSOCKET: "websocket", + CSP_REPORT: "csp_report", + IMAGESET: "imageset", + WEB_MANIFEST: "web_manifest", + OTHER: "other", + }, + onBeforeRequest: new WebRequestEventManager(context, "onBeforeRequest").api(), onBeforeSendHeaders: new WebRequestEventManager(context, "onBeforeSendHeaders").api(), onSendHeaders: new WebRequestEventManager(context, "onSendHeaders").api(), onHeadersReceived: new WebRequestEventManager(context, "onHeadersReceived").api(), onResponseStarted: new WebRequestEventManager(context, "onResponseStarted").api(), onCompleted: new WebRequestEventManager(context, "onCompleted").api(), handlerBehaviorChanged: function() { // TODO: Flush all caches.
--- a/toolkit/components/extensions/moz.build +++ b/toolkit/components/extensions/moz.build @@ -10,10 +10,8 @@ EXTRA_JS_MODULES += [ 'ExtensionManagement.jsm', 'ExtensionStorage.jsm', 'ExtensionUtils.jsm', ] JAR_MANIFESTS += ['jar.mn'] MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini'] - -DIRS += ['test/extensions']
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/background/background.js +++ /dev/null @@ -1,10 +0,0 @@ -browser.test.log("running background script"); - -browser.test.onMessage.addListener((x, y) => { - browser.test.assertEq(x, 10, "x is 10"); - browser.test.assertEq(y, 20, "y is 20"); - - browser.test.notifyPass("background test passed"); -}); - -browser.test.sendMessage("running", 1);
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/background/manifest.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "Simple extension test", - "version": "1.0", - "manifest_version": 2, - "description": "", - "background": { - "scripts": ["background.js"] - } -}
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/background/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -TESTING_JS_MODULES.extensions.background += [ - 'background.js', - 'manifest.json', -]
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/content_script/background.js +++ /dev/null @@ -1,10 +0,0 @@ -browser.runtime.onMessage.addListener(([msg, expectedState, readyState], sender) => { - if (msg == "chrome-namespace-ok") { - browser.test.sendMessage(msg); - return; - } - - browser.test.assertEq(msg, "script-run", "message type is correct"); - browser.test.assertEq(readyState, expectedState, "readyState is correct"); - browser.test.sendMessage("script-run-" + expectedState); -});
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/content_script/content_script.js +++ /dev/null @@ -1,1 +0,0 @@ -chrome.runtime.sendMessage(["chrome-namespace-ok"]);
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/content_script/content_script_end.js +++ /dev/null @@ -1,1 +0,0 @@ -browser.runtime.sendMessage(["script-run", "interactive", document.readyState]);
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/content_script/content_script_idle.js +++ /dev/null @@ -1,1 +0,0 @@ -browser.runtime.sendMessage(["script-run", "complete", document.readyState]);
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/content_script/content_script_start.js +++ /dev/null @@ -1,1 +0,0 @@ -browser.runtime.sendMessage(["script-run", "loading", document.readyState]);
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/content_script/manifest.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "Content script extension test", - "version": "1.0", - "manifest_version": 2, - "description": "", - - "content_scripts": [ - { - "matches": ["http://mochi.test/*/file_sample.html"], - "js": ["content_script_start.js"], - "run_at": "document_start" - }, - { - "matches": ["http://mochi.test/*/file_sample.html"], - "js": ["content_script_end.js"], - "run_at": "document_end" - }, - { - "matches": ["http://mochi.test/*/file_sample.html"], - "js": ["content_script_idle.js"], - "run_at": "document_idle" - }, - { - "matches": ["http://mochi.test/*/file_sample.html"], - "js": ["content_script.js"], - "run_at": "document_idle" - } - ], - - "background": { - "scripts": ["background.js"] - } -}
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/content_script/moz.build +++ /dev/null @@ -1,14 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -TESTING_JS_MODULES.extensions.content_script += [ - 'background.js', - 'content_script.js', - 'content_script_end.js', - 'content_script_idle.js', - 'content_script_start.js', - 'manifest.json', -]
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/moz.build +++ /dev/null @@ -1,13 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += [ - 'background', - 'content_script', - 'simple', - 'notifications', - 'webrequest', -]
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/notifications/background.js +++ /dev/null @@ -1,9 +0,0 @@ -browser.test.log("running background script"); - -var opts = {title: "Testing Notification", message: "Carry on"}; - -browser.notifications.create("5", opts, function(id){ - browser.test.sendMessage("running", id); - browser.test.notifyPass("background test passed"); -}); -
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/notifications/manifest.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "Notifications Test", - "version": "1.0", - "manifest_version": 2, - "description": "", - "background": { - "scripts": ["background.js"] - }, - "permissions": [ - "notifications" - ] -}
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/notifications/moz.build +++ /dev/null @@ -1,9 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -TESTING_JS_MODULES.extensions.notifications += [ - 'background.js', - 'manifest.json', -]
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/simple/manifest.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Simple extension test", - "version": "1.0", - "manifest_version": 2, - "description": "" -}
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/simple/moz.build +++ /dev/null @@ -1,9 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -TESTING_JS_MODULES.extensions.simple += [ - 'manifest.json', -]
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/webrequest/background.js +++ /dev/null @@ -1,97 +0,0 @@ -const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest"; - -var savedTabId = -1; - -function checkType(details) -{ - var expected_type = "???"; - if (details.url.indexOf("style") != -1) { - expected_type = "stylesheet"; - } else if (details.url.indexOf("image") != -1) { - expected_type = "image"; - } else if (details.url.indexOf("script") != -1) { - expected_type = "script"; - } else if (details.url.indexOf("page1") != -1) { - expected_type = "main_frame"; - } else if (details.url.indexOf("page2") != -1) { - expected_type = "sub_frame"; - } else if (details.url.indexOf("xhr") != -1) { - expected_type = "xmlhttprequest"; - } - browser.test.assertEq(details.type, expected_type, "resource type is correct"); -} - -var frameIDs = new Map(); - -var requested = []; - -function onBeforeRequest(details) -{ - browser.test.log(`onBeforeRequest ${details.url}`); - if (details.url.startsWith(BASE)) { - requested.push(details.url); - - if (savedTabId == -1) { - browser.test.assertTrue(details.tabId !== undefined, "tab ID defined"); - savedTabId = details.tabId; - } - - browser.test.assertEq(details.tabId, savedTabId, "correct tab ID"); - checkType(details); - - frameIDs.set(details.url, details.frameId); - if (details.url.indexOf("page1") != -1) { - browser.test.assertEq(details.frameId, 0, "frame ID correct"); - browser.test.assertEq(details.parentFrameId, -1, "parent frame ID correct"); - } - if (details.url.indexOf("page2") != -1) { - browser.test.assertTrue(details.frameId != 0, "sub-frame gets its own frame ID"); - browser.test.assertTrue(details.frameId !== undefined, "sub-frame ID defined"); - browser.test.assertEq(details.parentFrameId, 0, "parent frame id is correct"); - } - } - if (details.url.indexOf("_bad.") != -1) { - return {cancel: true}; - } -} - -var sendHeaders = []; - -function onBeforeSendHeaders(details) -{ - browser.test.log(`onBeforeSendHeaders ${details.url}`); - if (details.url.startsWith(BASE)) { - sendHeaders.push(details.url); - - browser.test.assertEq(details.tabId, savedTabId, "correct tab ID"); - checkType(details); - - var id = frameIDs.get(details.url); - browser.test.assertEq(id, details.frameId, "frame ID same in onBeforeSendHeaders as onBeforeRequest"); - } - if (details.url.indexOf("_redirect.") != -1) { - return {redirectUrl: details.url.replace("_redirect.", "_good.")}; - } -} - -var headersReceived = []; - -function onResponseStarted(details) -{ - if (details.url.startsWith(BASE)) { - headersReceived.push(details.url); - } -} - -browser.webRequest.onBeforeRequest.addListener(onBeforeRequest, {urls: "<all_urls>"}, ["blocking"]); -browser.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {urls: "<all_urls>"}, ["blocking"]); -browser.webRequest.onResponseStarted.addListener(onResponseStarted, {urls: "<all_urls>"}); - -function onTestMessage() -{ - browser.test.sendMessage("results", [requested, sendHeaders, headersReceived]); -} - -browser.test.onMessage.addListener(onTestMessage); - -browser.test.sendMessage("ready");
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/webrequest/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "webRequest extension test", - "version": "1.0", - "manifest_version": 2, - "description": "", - "background": { - "scripts": ["background.js"] - }, - "permissions": [ - "webRequest", - "webRequestBlocking" - ] -}
deleted file mode 100644 --- a/toolkit/components/extensions/test/extensions/webrequest/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -TESTING_JS_MODULES.extensions.webrequest += [ - 'background.js', - 'manifest.json', -]
--- a/toolkit/components/extensions/test/mochitest/test_ext_contentscript.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_contentscript.html @@ -10,17 +10,79 @@ </head> <body> <script type="application/javascript;version=1.8"> "use strict"; add_task(function* test_contentscript() { - let extension = ExtensionTestUtils.loadExtension("content_script"); + function backgroundScript() { + browser.runtime.onMessage.addListener(([msg, expectedState, readyState], sender) => { + if (msg == "chrome-namespace-ok") { + browser.test.sendMessage(msg); + return; + } + + browser.test.assertEq(msg, "script-run", "message type is correct"); + browser.test.assertEq(readyState, expectedState, "readyState is correct"); + browser.test.sendMessage("script-run-" + expectedState); + }); + } + + function contentScriptStart() { + browser.runtime.sendMessage(["script-run", "loading", document.readyState]); + } + function contentScriptEnd() { + browser.runtime.sendMessage(["script-run", "interactive", document.readyState]); + } + function contentScriptIdle() { + browser.runtime.sendMessage(["script-run", "complete", document.readyState]); + } + + function contentScript() { + chrome.runtime.sendMessage(["chrome-namespace-ok"]); + } + + let extensionData = { + manifest: { + content_scripts: [ + { + "matches": ["http://mochi.test/*/file_sample.html"], + "js": ["content_script_start.js"], + "run_at": "document_start" + }, + { + "matches": ["http://mochi.test/*/file_sample.html"], + "js": ["content_script_end.js"], + "run_at": "document_end" + }, + { + "matches": ["http://mochi.test/*/file_sample.html"], + "js": ["content_script_idle.js"], + "run_at": "document_idle" + }, + { + "matches": ["http://mochi.test/*/file_sample.html"], + "js": ["content_script.js"], + "run_at": "document_idle" + } + ], + }, + background: "(" + backgroundScript.toString() + ")()", + + files: { + "content_script_start.js": "(" + contentScriptStart.toString() + ")()", + "content_script_end.js": "(" + contentScriptEnd.toString() + ")()", + "content_script_idle.js": "(" + contentScriptIdle.toString() + ")()", + "content_script.js": "(" + contentScript.toString() + ")()", + }, + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); let loadingCount = 0; let interactiveCount = 0; let completeCount = 0; extension.onMessage("script-run-loading", () => { loadingCount++; }); extension.onMessage("script-run-interactive", () => { interactiveCount++; }); let completePromise = new Promise(resolve => {
--- a/toolkit/components/extensions/test/mochitest/test_ext_notifications.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_notifications.html @@ -7,17 +7,35 @@ <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> </head> <body> <script type="application/javascript;version=1.8"> add_task(function* test_notifications() { - let extension = ExtensionTestUtils.loadExtension("notifications"); + function backgroundScript() { + browser.test.log("running background script"); + + var opts = {title: "Testing Notification", message: "Carry on"}; + + browser.notifications.create("5", opts, function(id) { + browser.test.sendMessage("running", id); + browser.test.notifyPass("background test passed"); + }); + } + + let extensionData = { + manifest: { + permissions: ["notifications"] + }, + background: "(" + backgroundScript.toString() + ")()" + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); info("load complete"); yield extension.startup(); info("startup complete"); let x = yield extension.awaitMessage("running"); is(x, "5", "got correct value from extension"); yield extension.awaitFinish(); info("test complete"); yield extension.unload();
--- a/toolkit/components/extensions/test/mochitest/test_ext_simple.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_simple.html @@ -8,26 +8,58 @@ <script type="text/javascript" src="head.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> </head> <body> <script type="application/javascript;version=1.8"> add_task(function* test_simple() { - let extension = ExtensionTestUtils.loadExtension("simple"); + let extensionData = { + manifest: { + "name": "Simple extension test", + "version": "1.0", + "manifest_version": 2, + "description": "" + } + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); info("load complete"); yield extension.startup(); info("startup complete"); yield extension.unload(); info("extension unloaded successfully"); }); add_task(function* test_background() { - let extension = ExtensionTestUtils.loadExtension("background"); + function backgroundScript() { + browser.test.log("running background script"); + + browser.test.onMessage.addListener((x, y) => { + browser.test.assertEq(x, 10, "x is 10"); + browser.test.assertEq(y, 20, "y is 20"); + + browser.test.notifyPass("background test passed"); + }); + + browser.test.sendMessage("running", 1); + } + + let extensionData = { + background: "(" + backgroundScript.toString() + ")()", + manifest: { + "name": "Simple extension test", + "version": "1.0", + "manifest_version": 2, + "description": "" + } + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); info("load complete"); let [, x] = yield Promise.all([extension.startup(), extension.awaitMessage("running")]); is(x, 1, "got correct value from extension"); info("startup complete"); extension.sendMessage(10, 20); yield extension.awaitFinish(); info("test complete"); yield extension.unload();
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html @@ -37,24 +37,24 @@ const expected_sendHeaders = [BASE + "/f BASE + "/file_image_redirect.png", BASE + "/file_script_good.js", BASE + "/file_script_redirect.js", BASE + "/file_script_xhr.js", BASE + "/file_WebRequest_page2.html", BASE + "/nonexistent_script_url.js", BASE + "/xhr_resource"]; -const expected_headersReceived = [BASE + "/file_WebRequest_page1.html", - BASE + "/file_style_good.css", - BASE + "/file_image_good.png", - BASE + "/file_script_good.js", - BASE + "/file_script_xhr.js", - BASE + "/file_WebRequest_page2.html", - BASE + "/nonexistent_script_url.js", - BASE + "/xhr_resource"]; +const expected_complete = [BASE + "/file_WebRequest_page1.html", + BASE + "/file_style_good.css", + BASE + "/file_image_good.png", + BASE + "/file_script_good.js", + BASE + "/file_script_xhr.js", + BASE + "/file_WebRequest_page2.html", + BASE + "/nonexistent_script_url.js", + BASE + "/xhr_resource"]; function removeDupes(list) { let j = 0; for (let i = 1; i < list.length; i++) { if (list[i] != list[j]) { j++; if (i != j) { @@ -69,22 +69,151 @@ function compareLists(list1, list2, kind { list1.sort(); removeDupes(list1); list2.sort(); removeDupes(list2); is(String(list1), String(list2), `${kind} URLs correct`); } +function backgroundScript() +{ + const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest"; + + var savedTabId = -1; + + function checkType(details) + { + var expected_type = "???"; + if (details.url.indexOf("style") != -1) { + expected_type = "stylesheet"; + } else if (details.url.indexOf("image") != -1) { + expected_type = "image"; + } else if (details.url.indexOf("script") != -1) { + expected_type = "script"; + } else if (details.url.indexOf("page1") != -1) { + expected_type = "main_frame"; + } else if (details.url.indexOf("page2") != -1) { + expected_type = "sub_frame"; + } else if (details.url.indexOf("xhr") != -1) { + expected_type = "xmlhttprequest"; + } + browser.test.assertEq(details.type, expected_type, "resource type is correct"); + } + + var frameIDs = new Map(); + + var recorded = {requested: [], + beforeSendHeaders: [], + sendHeaders: [], + responseStarted: [], + completed: []}; + + function checkResourceType(type) + { + var key = type.toUpperCase(); + browser.test.assertTrue(key in browser.webRequest.ResourceType); + } + + function onBeforeRequest(details) + { + browser.test.log(`onBeforeRequest ${details.url}`); + checkResourceType(details.type); + if (details.url.startsWith(BASE)) { + recorded.requested.push(details.url); + + if (savedTabId == -1) { + browser.test.assertTrue(details.tabId !== undefined, "tab ID defined"); + savedTabId = details.tabId; + } + + browser.test.assertEq(details.tabId, savedTabId, "correct tab ID"); + checkType(details); + + frameIDs.set(details.url, details.frameId); + if (details.url.indexOf("page1") != -1) { + browser.test.assertEq(details.frameId, 0, "frame ID correct"); + browser.test.assertEq(details.parentFrameId, -1, "parent frame ID correct"); + } + if (details.url.indexOf("page2") != -1) { + browser.test.assertTrue(details.frameId != 0, "sub-frame gets its own frame ID"); + browser.test.assertTrue(details.frameId !== undefined, "sub-frame ID defined"); + browser.test.assertEq(details.parentFrameId, 0, "parent frame id is correct"); + } + } + if (details.url.indexOf("_bad.") != -1) { + return {cancel: true}; + } + return {}; + } + + function onBeforeSendHeaders(details) + { + browser.test.log(`onBeforeSendHeaders ${details.url}`); + checkResourceType(details.type); + if (details.url.startsWith(BASE)) { + recorded.beforeSendHeaders.push(details.url); + + browser.test.assertEq(details.tabId, savedTabId, "correct tab ID"); + checkType(details); + + var id = frameIDs.get(details.url); + browser.test.assertEq(id, details.frameId, "frame ID same in onBeforeSendHeaders as onBeforeRequest"); + } + if (details.url.indexOf("_redirect.") != -1) { + return {redirectUrl: details.url.replace("_redirect.", "_good.")}; + } + return {}; + } + + function onRecord(kind, details) + { + checkResourceType(details.type); + if (details.url.startsWith(BASE)) { + recorded[kind].push(details.url); + } + } + + browser.webRequest.onBeforeRequest.addListener(onBeforeRequest, {urls: "<all_urls>"}, ["blocking"]); + browser.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {urls: "<all_urls>"}, ["blocking"]); + browser.webRequest.onSendHeaders.addListener(onRecord.bind(null, "sendHeaders"), {urls: "<all_urls>"}); + browser.webRequest.onResponseStarted.addListener(onRecord.bind(null, "responseStarted"), {urls: "<all_urls>"}); + browser.webRequest.onCompleted.addListener(onRecord.bind(null, "completed"), {urls: "<all_urls>"}); + + function onTestMessage() + { + browser.test.sendMessage("results", recorded); + } + + browser.test.onMessage.addListener(onTestMessage); + + browser.test.sendMessage("ready", browser.webRequest.ResourceType); +} + function* test_once() { - let extension = ExtensionTestUtils.loadExtension("webrequest"); - yield Promise.all([extension.startup(), extension.awaitMessage("ready")]); + let extensionData = { + manifest: { + permissions: [ + "webRequest", + "webRequestBlocking" + ], + }, + background: "(" + backgroundScript.toString() + ")()", + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); + let [, resourceTypes] = yield Promise.all([extension.startup(), extension.awaitMessage("ready")]); info("webrequest extension loaded"); + for (var key in resourceTypes) { + var value = resourceTypes[key]; + is(key, value.toUpperCase()); + } + yield new Promise(resolve => { setTimeout(resolve, 0); }); let win = window.open(); // Clear the image cache, since it gets in the way otherwise. var imgTools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService(SpecialPowers.Ci.imgITools); var cache = imgTools.getImgCacheForDocument(win.document); cache.clearCache(false); @@ -101,21 +230,23 @@ function* test_once() is(win.failure, undefined, "Failure script didn't run"); let style = win.getComputedStyle(win.document.getElementById("test"), null); is(style.getPropertyValue("color"), "rgb(255, 0, 0)", "Good CSS loaded"); win.close(); extension.sendMessage("getResults"); - let [requested, sendHeaders, headersReceived] = yield extension.awaitMessage("results"); + let recorded = yield extension.awaitMessage("results"); - compareLists(requested, expected_requested, "requested"); - compareLists(sendHeaders, expected_sendHeaders, "sendHeaders"); - compareLists(headersReceived, expected_headersReceived, "headersReceived"); + compareLists(recorded.requested, expected_requested, "requested"); + compareLists(recorded.beforeSendHeaders, expected_sendHeaders, "beforeSendHeaders"); + compareLists(recorded.sendHeaders, expected_complete, "sendHeaders"); + compareLists(recorded.responseStarted, expected_complete, "responseStarted"); + compareLists(recorded.completed, expected_complete, "completed"); yield extension.unload(); info("webrequest extension unloaded"); } // Run the test twice to make sure it works with caching. add_task(test_once); add_task(test_once);
--- a/toolkit/modules/addons/WebRequest.jsm +++ b/toolkit/modules/addons/WebRequest.jsm @@ -117,35 +117,36 @@ var ContentPolicyManager = { this.policyData.delete(id); this.idMap.delete(callback); this.policies.delete(id); }, }; ContentPolicyManager.init(); -function StartStopListener(manager) +function StartStopListener(manager, loadContext) { this.manager = manager; + this.loadContext = loadContext; this.orig = null; } StartStopListener.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver, Ci.nsIStreamListener, Ci.nsISupports]), onStartRequest: function(request, context) { - this.manager.onStartRequest(request); + this.manager.onStartRequest(request, this.loadContext); return this.orig.onStartRequest(request, context); }, onStopRequest(request, context, statusCode) { let result = this.orig.onStopRequest(request, context, statusCode); - this.manager.onStopRequest(request); + this.manager.onStopRequest(request, this.loadContext); return result; }, onDataAvailable(...args) { return this.orig.onDataAvailable(...args); } }; @@ -224,34 +225,34 @@ var HttpObserverManager = { Ci.nsISupports]), }; channel[method](visitor); return headers; }, observe(subject, topic, data) { + let channel = subject.QueryInterface(Ci.nsIHttpChannel); + if (topic == "http-on-modify-request") { - this.modify(subject, topic, data); + this.modify(channel, topic, data); } else if (topic == "http-on-examine-response" || topic == "http-on-examine-cached-response" || topic == "http-on-examine-merged-response") { - this.examine(subject, topic, data); + this.examine(channel, topic, data); } }, shouldRunListener(policyType, uri, filter) { return WebRequestCommon.typeMatches(policyType, filter.types) && WebRequestCommon.urlMatches(uri, filter.urls); }, - runChannelListener(request, kind) { + runChannelListener(channel, loadContext, kind) { let listeners = this.listeners[kind]; - let channel = request.QueryInterface(Ci.nsIHttpChannel); - let loadContext = this.getLoadContext(channel); let browser = loadContext ? loadContext.topFrameElement : null; let loadInfo = channel.loadInfo; let policyType = loadInfo.contentPolicyType; let requestHeaders; let responseHeaders; let includeStatus = kind == "headersReceived" || kind == "onStart" || kind == "onStop"; @@ -319,43 +320,48 @@ var HttpObserverManager = { channel.setResponseHeader(name, "", false); } for (let {name, value} of result.responseHeaders) { channel.setResponseHeader(name, value, false); } } } + + return true; }, - modify(subject, topic, data) { - if (this.runChannelListener(subject, "modify")) { - this.runChannelListener(subject, "afterModify"); + modify(channel, topic, data) { + let loadContext = this.getLoadContext(channel); + + if (this.runChannelListener(channel, loadContext, "modify")) { + this.runChannelListener(channel, loadContext, "afterModify"); } }, - examine(subject, topic, data) { - let channel = subject.QueryInterface(Ci.nsIHttpChannel); + examine(channel, topic, data) { + let loadContext = this.getLoadContext(channel); + if (this.listeners.onStart.size || this.listeners.onStop.size) { if (channel instanceof Components.interfaces.nsITraceableChannel) { - let listener = new StartStopListener(this); - let orig = subject.setNewListener(listener); + let listener = new StartStopListener(this, loadContext); + let orig = channel.setNewListener(listener); listener.orig = orig; } } - this.runChannelListener(subject, "headersReceived"); + this.runChannelListener(channel, loadContext, "headersReceived"); }, - onStartRequest(request) { - this.runChannelListener(request, "onStart"); + onStartRequest(channel, loadContext) { + this.runChannelListener(channel, loadContext, "onStart"); }, - onStopRequest(request) { - this.runChannelListener(request, "onStop"); + onStopRequest(channel, loadContext) { + this.runChannelListener(channel, loadContext, "onStop"); }, }; var onBeforeRequest = { addListener(callback, filter = null, opt_extraInfoSpec = null) { // FIXME: Add requestBody support. let opts = parseExtra(opt_extraInfoSpec, ["blocking"]); opts.filter = parseFilter(filter);
--- a/toolkit/modules/addons/WebRequestCommon.jsm +++ b/toolkit/modules/addons/WebRequestCommon.jsm @@ -13,18 +13,29 @@ var WebRequestCommon = { typeForPolicyType(type) { switch (type) { case Ci.nsIContentPolicy.TYPE_DOCUMENT: return "main_frame"; case Ci.nsIContentPolicy.TYPE_SUBDOCUMENT: return "sub_frame"; case Ci.nsIContentPolicy.TYPE_STYLESHEET: return "stylesheet"; case Ci.nsIContentPolicy.TYPE_SCRIPT: return "script"; case Ci.nsIContentPolicy.TYPE_IMAGE: return "image"; case Ci.nsIContentPolicy.TYPE_OBJECT: return "object"; - case Ci.nsIContentPolicy.TYPE_OBJECT_SUBREQUEST: return "object"; + case Ci.nsIContentPolicy.TYPE_OBJECT_SUBREQUEST: return "object_subrequest"; case Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST: return "xmlhttprequest"; + case Ci.nsIContentPolicy.TYPE_XBL: return "xbl"; + case Ci.nsIContentPolicy.TYPE_XSLT: return "xslt"; + case Ci.nsIContentPolicy.TYPE_PING: return "ping"; + case Ci.nsIContentPolicy.TYPE_BEACON: return "beacon"; + case Ci.nsIContentPolicy.TYPE_DTD: return "xml_dtd"; + case Ci.nsIContentPolicy.TYPE_FONT: return "font"; + case Ci.nsIContentPolicy.TYPE_MEDIA: return "media"; + case Ci.nsIContentPolicy.TYPE_WEBSOCKET: return "websocket"; + case Ci.nsIContentPolicy.TYPE_CSP_REPORT: return "csp_report"; + case Ci.nsIContentPolicy.TYPE_IMAGESET: return "imageset"; + case Ci.nsIContentPolicy.TYPE_WEB_MANIFEST: return "web_manifest"; default: return "other"; } }, typeMatches(policyType, filterTypes) { if (filterTypes === null) { return true; }
--- a/view/nsView.cpp +++ b/view/nsView.cpp @@ -131,17 +131,22 @@ void nsView::DestroyWidget() mWindow->SetAttachedWidgetListener(nullptr); } else { mWindow->SetWidgetListener(nullptr); nsCOMPtr<nsIRunnable> widgetDestroyer = new DestroyWidgetRunnable(mWindow); - NS_DispatchToMainThread(widgetDestroyer); + // Don't leak if we happen to arrive here after the main thread + // has disappeared. + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + if (mainThread) { + mainThread->Dispatch(widgetDestroyer.forget(), NS_DISPATCH_NORMAL); + } } mWindow = nullptr; } } nsView* nsView::GetViewFor(nsIWidget* aWidget) {
--- a/xpcom/string/nsStringObsolete.cpp +++ b/xpcom/string/nsStringObsolete.cpp @@ -535,17 +535,17 @@ StripChars2(char16_t* aString,uint32_t a } *to = 0; } return to - (char16_t*)aString; } /* ***** END RICKG BLOCK ***** */ -static const char* kWhitespace="\b\t\r\n "; +static const char* kWhitespace="\f\t\r\n "; // This function is used to implement FindCharInSet and friends template <class CharT> #ifndef __SUNPRO_CC static #endif /* !__SUNPRO_CC */ CharT GetFindInSetFilter( const CharT* set)
--- a/xpcom/tests/external/TestMinStringAPI.cpp +++ b/xpcom/tests/external/TestMinStringAPI.cpp @@ -260,17 +260,17 @@ static bool test_replace() "crazy", "oh"); if (!rv) return rv; return true; } -static const char* kWhitespace="\b\t\r\n "; +static const char* kWhitespace="\f\t\r\n "; static void CompressWhitespace(nsACString &str) { const char *p; int32_t i, len = (int32_t) NS_CStringGetData(str, &p); // trim leading whitespace