mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Merge inbound to mozilla-central a=merge
This commit is contained in:
commit
c0b26c4076
@ -4,7 +4,6 @@ support-files =
|
||||
head.js
|
||||
|
||||
[browser_ext_autocompletepopup.js]
|
||||
[browser_ext_legacy_extension_context_contentscript.js]
|
||||
[browser_ext_windows_allowScriptsToClose.js]
|
||||
|
||||
[include:browser-common.ini]
|
||||
|
@ -1,173 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
LegacyExtensionContext,
|
||||
} = ChromeUtils.import("resource://gre/modules/LegacyExtensionsUtils.jsm", {});
|
||||
|
||||
function promiseAddonStartup(extension) {
|
||||
const {Management} = ChromeUtils.import("resource://gre/modules/Extension.jsm", {});
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let listener = (evt, extensionInstance) => {
|
||||
Management.off("startup", listener);
|
||||
resolve(extensionInstance);
|
||||
};
|
||||
Management.on("startup", listener);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This test case ensures that the LegacyExtensionContext can receive a connection
|
||||
* from a content script and that the received port contains the expected sender
|
||||
* tab info.
|
||||
*/
|
||||
add_task(async function test_legacy_extension_context_contentscript_connection() {
|
||||
function backgroundScript() {
|
||||
// Extract the assigned uuid from the background page url and send it
|
||||
// in a test message.
|
||||
let uuid = window.location.hostname;
|
||||
|
||||
browser.test.onMessage.addListener(async msg => {
|
||||
if (msg == "open-test-tab") {
|
||||
let tab = await browser.tabs.create({url: "http://example.com/"});
|
||||
browser.test.sendMessage("get-expected-sender-info",
|
||||
{uuid, tab});
|
||||
} else if (msg == "close-current-tab") {
|
||||
try {
|
||||
let [tab] = await browser.tabs.query({active: true});
|
||||
await browser.tabs.remove(tab.id);
|
||||
browser.test.sendMessage("current-tab-closed", true);
|
||||
} catch (e) {
|
||||
browser.test.sendMessage("current-tab-closed", false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
browser.runtime.sendMessage("webextension -> legacy_extension message", (reply) => {
|
||||
browser.test.assertEq("legacy_extension -> webextension reply", reply,
|
||||
"Got the expected reply from the LegacyExtensionContext");
|
||||
browser.test.sendMessage("got-reply-message");
|
||||
});
|
||||
|
||||
let port = browser.runtime.connect();
|
||||
|
||||
port.onMessage.addListener(msg => {
|
||||
browser.test.assertEq("legacy_extension -> webextension port message", msg,
|
||||
"Got the expected message from the LegacyExtensionContext");
|
||||
port.postMessage("webextension -> legacy_extension port message");
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background: `new ${backgroundScript}`,
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
matches: ["http://example.com/*"],
|
||||
js: ["content-script.js"],
|
||||
},
|
||||
],
|
||||
},
|
||||
files: {
|
||||
"content-script.js": `new ${contentScript}`,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
let waitForExtensionReady = extension.awaitMessage("ready");
|
||||
|
||||
let waitForExtensionInstance = promiseAddonStartup(extension);
|
||||
|
||||
extension.startup();
|
||||
|
||||
let extensionInstance = await waitForExtensionInstance;
|
||||
|
||||
// Connect to the target extension.id as an external context
|
||||
// using the given custom sender info.
|
||||
let legacyContext = new LegacyExtensionContext(extensionInstance);
|
||||
|
||||
let waitConnectPort = new Promise(resolve => {
|
||||
let {browser} = legacyContext.api;
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
resolve(port);
|
||||
});
|
||||
});
|
||||
|
||||
let waitMessage = new Promise(resolve => {
|
||||
let {browser} = legacyContext.api;
|
||||
browser.runtime.onMessage.addListener((singleMsg, msgSender, sendReply) => {
|
||||
sendReply("legacy_extension -> webextension reply");
|
||||
resolve({singleMsg, msgSender});
|
||||
});
|
||||
});
|
||||
|
||||
is(legacyContext.envType, "legacy_extension",
|
||||
"LegacyExtensionContext instance has the expected type");
|
||||
|
||||
ok(legacyContext.api, "Got the API object");
|
||||
|
||||
await waitForExtensionReady;
|
||||
|
||||
extension.sendMessage("open-test-tab");
|
||||
|
||||
let {tab} = await extension.awaitMessage("get-expected-sender-info");
|
||||
|
||||
let {singleMsg, msgSender} = await waitMessage;
|
||||
is(singleMsg, "webextension -> legacy_extension message",
|
||||
"Got the expected message");
|
||||
ok(msgSender, "Got a message sender object");
|
||||
|
||||
is(msgSender.id, extension.id, "The sender has the expected id property");
|
||||
is(msgSender.url, "http://example.com/", "The sender has the expected url property");
|
||||
ok(msgSender.tab, "The sender has a tab property");
|
||||
is(msgSender.tab.id, tab.id, "The port sender has the expected tab.id");
|
||||
|
||||
// Wait confirmation that the reply has been received.
|
||||
await extension.awaitMessage("got-reply-message");
|
||||
|
||||
let port = await waitConnectPort;
|
||||
|
||||
ok(port, "Got the Port API object");
|
||||
ok(port.sender, "The port has a sender property");
|
||||
|
||||
is(port.sender.id, extension.id, "The port sender has an id property");
|
||||
is(port.sender.url, "http://example.com/", "The port sender has the expected url property");
|
||||
ok(port.sender.tab, "The port sender has a tab property");
|
||||
is(port.sender.tab.id, tab.id, "The port sender has the expected tab.id");
|
||||
|
||||
let waitPortMessage = new Promise(resolve => {
|
||||
port.onMessage.addListener((msg) => {
|
||||
resolve(msg);
|
||||
});
|
||||
});
|
||||
|
||||
port.postMessage("legacy_extension -> webextension port message");
|
||||
|
||||
let msg = await waitPortMessage;
|
||||
|
||||
is(msg, "webextension -> legacy_extension port message",
|
||||
"LegacyExtensionContext received the expected message from the webextension");
|
||||
|
||||
let waitForDisconnect = new Promise(resolve => {
|
||||
port.onDisconnect.addListener(resolve);
|
||||
});
|
||||
|
||||
let waitForTestDone = extension.awaitMessage("current-tab-closed");
|
||||
|
||||
extension.sendMessage("close-current-tab");
|
||||
|
||||
await waitForDisconnect;
|
||||
|
||||
info("Got the disconnect event on tab closed");
|
||||
|
||||
let success = await waitForTestDone;
|
||||
|
||||
ok(success, "Test completed successfully");
|
||||
|
||||
await extension.unload();
|
||||
});
|
@ -2,20 +2,10 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
function add_tasks(task) {
|
||||
add_task(task.bind(null, {embedded: false}));
|
||||
|
||||
add_task(task.bind(null, {embedded: true}));
|
||||
}
|
||||
|
||||
async function loadExtension(options) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
|
||||
embedded: options.embedded,
|
||||
|
||||
manifest: Object.assign({
|
||||
"permissions": ["tabs"],
|
||||
}, options.manifest),
|
||||
@ -69,12 +59,12 @@ async function loadExtension(options) {
|
||||
return extension;
|
||||
}
|
||||
|
||||
add_tasks(async function test_inline_options(extraOptions) {
|
||||
info(`Test options opened inline (${JSON.stringify(extraOptions)})`);
|
||||
add_task(async function test_inline_options() {
|
||||
info(`Test options opened inline`);
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
|
||||
|
||||
let extension = await loadExtension(Object.assign({}, extraOptions, {
|
||||
let extension = await loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id: "inline_options@tests.mozilla.org"}},
|
||||
"options_ui": {
|
||||
@ -194,7 +184,7 @@ add_tasks(async function test_inline_options(extraOptions) {
|
||||
browser.test.notifyFail("options-ui");
|
||||
}
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
extension.awaitMessage("options-html-inbound-pong"),
|
||||
@ -212,12 +202,12 @@ add_tasks(async function test_inline_options(extraOptions) {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_tasks(async function test_tab_options(extraOptions) {
|
||||
info(`Test options opened in a tab (${JSON.stringify(extraOptions)})`);
|
||||
add_task(async function test_tab_options() {
|
||||
info(`Test options opened in a tab`);
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
|
||||
|
||||
let extension = await loadExtension(Object.assign({}, extraOptions, {
|
||||
let extension = await loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id: "tab_options@tests.mozilla.org"}},
|
||||
"options_ui": {
|
||||
@ -307,7 +297,7 @@ add_tasks(async function test_tab_options(extraOptions) {
|
||||
browser.test.notifyFail("options-ui-tab");
|
||||
}
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
await extension.awaitFinish("options-ui-tab");
|
||||
await extension.unload();
|
||||
@ -315,10 +305,10 @@ add_tasks(async function test_tab_options(extraOptions) {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_tasks(async function test_options_no_manifest(extraOptions) {
|
||||
info(`Test with no manifest key (${JSON.stringify(extraOptions)})`);
|
||||
add_task(async function test_options_no_manifest() {
|
||||
info(`Test with no manifest key`);
|
||||
|
||||
let extension = await loadExtension(Object.assign({}, extraOptions, {
|
||||
let extension = await loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id: "no_options@tests.mozilla.org"}},
|
||||
},
|
||||
@ -333,7 +323,7 @@ add_tasks(async function test_options_no_manifest(extraOptions) {
|
||||
|
||||
browser.test.notifyPass("options-no-manifest");
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
await extension.awaitFinish("options-no-manifest");
|
||||
await extension.unload();
|
||||
|
@ -28,4 +28,7 @@ DOM_WEBIDL_PREF(dom_netinfo_enabled)
|
||||
DOM_WEBIDL_PREF(dom_fetchObserver_enabled)
|
||||
DOM_WEBIDL_PREF(dom_enable_performance_observer)
|
||||
DOM_WEBIDL_PREF(dom_performance_enable_scheduler_timing)
|
||||
DOM_WEBIDL_PREF(dom_reporting_enabled)
|
||||
DOM_WEBIDL_PREF(dom_reporting_testing_enabled)
|
||||
DOM_WEBIDL_PREF(dom_reporting_featurePolicy_enabled)
|
||||
DOM_WEBIDL_PREF(javascript_options_streams)
|
||||
|
@ -52,6 +52,8 @@ nsDOMNavigationTiming::Clear()
|
||||
mDOMContentLoadedEventStart = TimeStamp();
|
||||
mDOMContentLoadedEventEnd = TimeStamp();
|
||||
mDOMComplete = TimeStamp();
|
||||
mContentfulPaint = TimeStamp();
|
||||
mNonBlankPaint = TimeStamp();
|
||||
|
||||
mDocShellHasBeenActiveSinceNavigationStart = false;
|
||||
}
|
||||
@ -308,7 +310,7 @@ nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer)
|
||||
{
|
||||
// Check TTI: see if it's been 5 seconds since the last Long Task
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
MOZ_RELEASE_ASSERT(!mNonBlankPaint.IsNull(), "TTI timeout with no non-blank-paint?");
|
||||
MOZ_RELEASE_ASSERT(!mContentfulPaint.IsNull(), "TTI timeout with no contentful-paint?");
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
TimeStamp lastLongTaskEnded;
|
||||
@ -323,11 +325,10 @@ nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer)
|
||||
return;
|
||||
}
|
||||
}
|
||||
// To correctly implement TTI/TTFI as proposed, we'd need to use
|
||||
// FirstContentfulPaint (FCP, which we have not yet implemented) instead
|
||||
// of FirstNonBlankPaing (FNBP) to start at, and not fire it until there
|
||||
// are no more than 2 network loads. By the proposed definition, without
|
||||
// that we're closer to TimeToFirstInteractive.
|
||||
// To correctly implement TTI/TTFI as proposed, we'd need to not
|
||||
// fire it until there are no more than 2 network loads. By the
|
||||
// proposed definition, without that we're closer to
|
||||
// TimeToFirstInteractive.
|
||||
|
||||
// XXX check number of network loads, and if > 2 mark to check if loads
|
||||
// decreases to 2 (or record that point and let the normal timer here
|
||||
@ -341,7 +342,7 @@ nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer)
|
||||
mTTFI = MaxWithinWindowBeginningAtMin(lastLongTaskEnded, mDOMContentLoadedEventEnd,
|
||||
TimeDuration::FromMilliseconds(TTI_WINDOW_SIZE_MS));
|
||||
if (mTTFI.IsNull()) {
|
||||
mTTFI = mNonBlankPaint;
|
||||
mTTFI = mContentfulPaint;
|
||||
}
|
||||
}
|
||||
// XXX Implement TTI via check number of network loads, and if > 2 mark
|
||||
@ -399,15 +400,6 @@ nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument()
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mTTITimer) {
|
||||
mTTITimer = NS_NewTimer();
|
||||
}
|
||||
|
||||
// TTI is first checked 5 seconds after the FCP (non-blank-paint is very close to FCP).
|
||||
mTTITimer->InitWithNamedFuncCallback(TTITimeoutCallback, this, TTI_WINDOW_SIZE_MS,
|
||||
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
|
||||
"nsDOMNavigationTiming::TTITimeout");
|
||||
|
||||
if (mDocShellHasBeenActiveSinceNavigationStart) {
|
||||
if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization(mNavigationStart)) {
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_NETOPT_MS,
|
||||
@ -425,6 +417,42 @@ nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyContentfulPaintForRootContentDocument()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mNavigationStart.IsNull());
|
||||
|
||||
if (!mContentfulPaint.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mContentfulPaint = TimeStamp::Now();
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (profiler_is_active()) {
|
||||
TimeDuration elapsed = mContentfulPaint - mNavigationStart;
|
||||
nsAutoCString spec;
|
||||
if (mLoadedURI) {
|
||||
mLoadedURI->GetSpec(spec);
|
||||
}
|
||||
nsPrintfCString marker("Contentful paint after %dms for URL %s, %s",
|
||||
int(elapsed.ToMilliseconds()), spec.get(),
|
||||
mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and first non-blank paint");
|
||||
profiler_add_marker(marker.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mTTITimer) {
|
||||
mTTITimer = NS_NewTimer();
|
||||
}
|
||||
|
||||
// TTI is first checked 5 seconds after the FCP (non-blank-paint is very close to FCP).
|
||||
mTTITimer->InitWithNamedFuncCallback(TTITimeoutCallback, this, TTI_WINDOW_SIZE_MS,
|
||||
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
|
||||
"nsDOMNavigationTiming::TTITimeout");
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyDOMContentFlushedForRootContentDocument()
|
||||
{
|
||||
|
@ -97,6 +97,10 @@ public:
|
||||
{
|
||||
return TimeStampToDOM(mNonBlankPaint);
|
||||
}
|
||||
DOMTimeMilliSec GetTimeToContentfulPaint() const
|
||||
{
|
||||
return TimeStampToDOM(mContentfulPaint);
|
||||
}
|
||||
DOMTimeMilliSec GetTimeToTTFI() const
|
||||
{
|
||||
return TimeStampToDOM(mTTFI);
|
||||
@ -174,6 +178,7 @@ public:
|
||||
|
||||
void NotifyLongTask(mozilla::TimeStamp aWhen);
|
||||
void NotifyNonBlankPaintForRootContentDocument();
|
||||
void NotifyContentfulPaintForRootContentDocument();
|
||||
void NotifyDOMContentFlushedForRootContentDocument();
|
||||
void NotifyDocShellStateChanged(DocShellState aDocShellState);
|
||||
|
||||
@ -209,6 +214,7 @@ private:
|
||||
DOMHighResTimeStamp mNavigationStartHighRes;
|
||||
mozilla::TimeStamp mNavigationStart;
|
||||
mozilla::TimeStamp mNonBlankPaint;
|
||||
mozilla::TimeStamp mContentfulPaint;
|
||||
mozilla::TimeStamp mDOMContentFlushed;
|
||||
|
||||
mozilla::TimeStamp mBeforeUnloadStart;
|
||||
|
@ -44,6 +44,9 @@ DEPRECATED_OPERATION(IDBOpenDBOptions_StorageType)
|
||||
DEPRECATED_OPERATION(DOMAttrModifiedEvent)
|
||||
DEPRECATED_OPERATION(MozBoxOrInlineBoxDisplay)
|
||||
DEPRECATED_OPERATION(DOMQuadBoundsAttr)
|
||||
DEPRECATED_OPERATION(DeprecatedTestingInterface)
|
||||
DEPRECATED_OPERATION(DeprecatedTestingMethod)
|
||||
DEPRECATED_OPERATION(DeprecatedTestingAttribute)
|
||||
DEPRECATED_OPERATION(CreateImageBitmapCanvasRenderingContext2D)
|
||||
DEPRECATED_OPERATION(MozRequestFullScreenDeprecatedPrefix)
|
||||
DEPRECATED_OPERATION(MozfullscreenchangeDeprecatedPrefix)
|
||||
|
@ -3044,6 +3044,11 @@ nsIDocument::InitFeaturePolicy(nsIChannel* aChannel)
|
||||
mFeaturePolicy->InheritPolicy(parentPolicy);
|
||||
}
|
||||
|
||||
// We don't want to parse the http Feature-Policy header if this pref is off.
|
||||
if (!StaticPrefs::dom_security_featurePolicy_header_enabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel;
|
||||
nsresult rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "xpcpublic.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/JSON.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -1391,13 +1391,17 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
dataStringBuf, dataStringLength);
|
||||
}
|
||||
|
||||
JS::SourceBufferHolder srcBuf(dataStringBuf, dataStringLength,
|
||||
JS::SourceBufferHolder::GiveOwnership);
|
||||
|
||||
if (!dataStringBuf || dataStringLength == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::UniqueTwoByteChars srcChars(dataStringBuf);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, std::move(srcChars), dataStringLength)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
options.setFileAndLine(url.get(), 1);
|
||||
options.setNoScriptRval(true);
|
||||
|
@ -237,6 +237,8 @@
|
||||
#include "mozilla/dom/ImageBitmap.h"
|
||||
#include "mozilla/dom/ImageBitmapBinding.h"
|
||||
#include "mozilla/dom/InstallTriggerBinding.h"
|
||||
#include "mozilla/dom/Report.h"
|
||||
#include "mozilla/dom/ReportingObserver.h"
|
||||
#include "mozilla/dom/ServiceWorker.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistration.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
|
||||
@ -337,6 +339,9 @@ using mozilla::dom::cache::CacheStorage;
|
||||
// Min idle notification time in seconds.
|
||||
#define MIN_IDLE_NOTIFICATION_TIME_S 1
|
||||
|
||||
// Max number of Report objects
|
||||
#define MAX_REPORT_RECORDS 100
|
||||
|
||||
static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner");
|
||||
|
||||
static bool gIdleObserversAPIFuzzTimeDisabled = false;
|
||||
@ -1471,6 +1476,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInstallTrigger)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReportRecords)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReportingObservers)
|
||||
|
||||
tmp->TraverseHostObjectURIs(cb);
|
||||
|
||||
@ -1560,6 +1567,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstallTrigger)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReportRecords)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReportingObservers)
|
||||
|
||||
tmp->UnlinkHostObjectURIs();
|
||||
|
||||
@ -5669,6 +5678,7 @@ nsGlobalWindowInner::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
if (!nsCRT::strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
|
||||
if (mPerformance) {
|
||||
mPerformance->MemoryPressure();
|
||||
mReportRecords.Clear();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -8086,6 +8096,62 @@ nsPIDOMWindowInner::nsPIDOMWindowInner(nsPIDOMWindowOuter *aOuterWindow)
|
||||
MOZ_ASSERT(aOuterWindow);
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::RegisterReportingObserver(ReportingObserver* aObserver,
|
||||
bool aBuffered)
|
||||
{
|
||||
MOZ_ASSERT(aObserver);
|
||||
|
||||
if (mReportingObservers.Contains(aObserver)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mReportingObservers.AppendElement(aObserver, fallible))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aBuffered) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Report* report : mReportRecords) {
|
||||
aObserver->MaybeReport(report);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::UnregisterReportingObserver(ReportingObserver* aObserver)
|
||||
{
|
||||
MOZ_ASSERT(aObserver);
|
||||
mReportingObservers.RemoveElement(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::BroadcastReport(Report* aReport)
|
||||
{
|
||||
MOZ_ASSERT(aReport);
|
||||
|
||||
for (ReportingObserver* observer : mReportingObservers) {
|
||||
observer->MaybeReport(aReport);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mReportRecords.AppendElement(aReport, fallible))) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (mReportRecords.Length() > MAX_REPORT_RECORDS) {
|
||||
mReportRecords.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::NotifyReportingObservers()
|
||||
{
|
||||
for (ReportingObserver* observer : mReportingObservers) {
|
||||
observer->MaybeNotify();
|
||||
}
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner::~nsPIDOMWindowInner() {}
|
||||
|
||||
#undef FORWARD_TO_OUTER
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/OffThreadScriptCompilation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptElement.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
@ -96,9 +96,16 @@ nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
|
||||
}
|
||||
|
||||
// Compile.
|
||||
const nsPromiseFlatString& flatBody = PromiseFlatString(aBody);
|
||||
|
||||
JS::SourceText<char16_t> source;
|
||||
if (!source.init(cx, flatBody.get(), flatBody.Length(),
|
||||
JS::SourceOwnership::Borrowed))
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JS::Rooted<JSFunction*> fun(cx);
|
||||
JS::SourceBufferHolder source(PromiseFlatString(aBody).get(), aBody.Length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
if (!JS::CompileFunction(cx, aScopeChain, aOptions,
|
||||
PromiseFlatCString(aName).get(),
|
||||
aArgCount, aArgArray,
|
||||
@ -217,7 +224,7 @@ nsJSUtils::ExecutionContext::JoinAndExec(JS::OffThreadToken** aOffThreadToken,
|
||||
|
||||
nsresult
|
||||
nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
|
||||
JS::SourceBufferHolder& aSrcBuf,
|
||||
JS::SourceText<char16_t>& aSrcBuf,
|
||||
JS::MutableHandle<JSScript*> aScript)
|
||||
{
|
||||
if (mSkip) {
|
||||
@ -270,8 +277,15 @@ nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
|
||||
}
|
||||
|
||||
const nsPromiseFlatString& flatScript = PromiseFlatString(aScript);
|
||||
JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(mCx, flatScript.get(), flatScript.Length(),
|
||||
JS::SourceOwnership::Borrowed))
|
||||
{
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
JS::Rooted<JSScript*> script(mCx);
|
||||
return CompileAndExec(aCompileOptions, srcBuf, &script);
|
||||
}
|
||||
@ -473,7 +487,7 @@ nsJSUtils::ExecutionContext::ExtractReturnValue(JS::MutableHandle<JS::Value> aRe
|
||||
|
||||
nsresult
|
||||
nsJSUtils::CompileModule(JSContext* aCx,
|
||||
JS::SourceBufferHolder& aSrcBuf,
|
||||
JS::SourceText<char16_t>& aSrcBuf,
|
||||
JS::Handle<JSObject*> aEvaluationGlobal,
|
||||
JS::CompileOptions &aCompileOptions,
|
||||
JS::MutableHandle<JSObject*> aModule)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#include "nsString.h"
|
||||
|
||||
@ -157,9 +158,9 @@ public:
|
||||
MOZ_MUST_USE nsresult JoinAndExec(JS::OffThreadToken** aOffThreadToken,
|
||||
JS::MutableHandle<JSScript*> aScript);
|
||||
|
||||
// Compile a script contained in a SourceBuffer, and execute it.
|
||||
// Compile a script contained in a SourceText, and execute it.
|
||||
nsresult CompileAndExec(JS::CompileOptions& aCompileOptions,
|
||||
JS::SourceBufferHolder& aSrcBuf,
|
||||
JS::SourceText<char16_t>& aSrcBuf,
|
||||
JS::MutableHandle<JSScript*> aScript);
|
||||
|
||||
// Compile a script contained in a string, and execute it.
|
||||
@ -186,7 +187,7 @@ public:
|
||||
};
|
||||
|
||||
static nsresult CompileModule(JSContext* aCx,
|
||||
JS::SourceBufferHolder& aSrcBuf,
|
||||
JS::SourceText<char16_t>& aSrcBuf,
|
||||
JS::Handle<JSObject*> aEvaluationGlobal,
|
||||
JS::CompileOptions &aCompileOptions,
|
||||
JS::MutableHandle<JSObject*> aModule);
|
||||
|
@ -58,6 +58,9 @@ class Element;
|
||||
class MozIdleObserver;
|
||||
class Navigator;
|
||||
class Performance;
|
||||
class Report;
|
||||
class ReportBody;
|
||||
class ReportingObserver;
|
||||
class Selection;
|
||||
class ServiceWorker;
|
||||
class ServiceWorkerDescriptor;
|
||||
@ -628,6 +631,19 @@ public:
|
||||
already_AddRefed<mozilla::AutoplayPermissionManager>
|
||||
GetAutoplayPermissionManager();
|
||||
|
||||
void
|
||||
RegisterReportingObserver(mozilla::dom::ReportingObserver* aObserver,
|
||||
bool aBuffered);
|
||||
|
||||
void
|
||||
UnregisterReportingObserver(mozilla::dom::ReportingObserver* aObserver);
|
||||
|
||||
void
|
||||
BroadcastReport(mozilla::dom::Report* aReport);
|
||||
|
||||
void
|
||||
NotifyReportingObservers();
|
||||
|
||||
protected:
|
||||
void CreatePerformanceObjectIfNeeded();
|
||||
|
||||
@ -722,6 +738,10 @@ protected:
|
||||
// The event dispatch code sets and unsets this while keeping
|
||||
// the event object alive.
|
||||
mozilla::dom::Event* mEvent;
|
||||
|
||||
// List of Report objects for ReportingObservers.
|
||||
nsTArray<RefPtr<mozilla::dom::ReportingObserver>> mReportingObservers;
|
||||
nsTArray<RefPtr<mozilla::dom::Report>> mReportRecords;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMWindowInner, NS_PIDOMWINDOWINNER_IID)
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/UseCounter.h"
|
||||
|
||||
@ -29,6 +30,7 @@
|
||||
#include "nsINode.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsUTF8Utils.h"
|
||||
#include "WorkerPrivate.h"
|
||||
@ -43,6 +45,7 @@
|
||||
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/CustomElementRegistry.h"
|
||||
#include "mozilla/dom/DeprecationReportBody.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/ElementBinding.h"
|
||||
#include "mozilla/dom/HTMLObjectElement.h"
|
||||
@ -50,6 +53,7 @@
|
||||
#include "mozilla/dom/HTMLEmbedElement.h"
|
||||
#include "mozilla/dom/HTMLElementBinding.h"
|
||||
#include "mozilla/dom/HTMLEmbedElementBinding.h"
|
||||
#include "mozilla/dom/ReportingUtils.h"
|
||||
#include "mozilla/dom/XULElementBinding.h"
|
||||
#include "mozilla/dom/XULFrameElementBinding.h"
|
||||
#include "mozilla/dom/XULMenuElementBinding.h"
|
||||
@ -2200,7 +2204,7 @@ GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
}
|
||||
|
||||
*isXray = true;
|
||||
return xpc::EnsureXrayExpandoObject(cx, obj);;
|
||||
return xpc::EnsureXrayExpandoObject(cx, obj);
|
||||
}
|
||||
|
||||
DEFINE_XRAY_EXPANDO_CLASS(, DefaultXrayExpandoObjectClass, 0);
|
||||
@ -4103,11 +4107,95 @@ SetDocumentAndPageUseCounter(JSObject* aObject, UseCounter aUseCounter)
|
||||
|
||||
namespace {
|
||||
|
||||
#define DEPRECATED_OPERATION(_op) #_op,
|
||||
static const char* kDeprecatedOperations[] = {
|
||||
#include "nsDeprecatedOperationList.h"
|
||||
nullptr
|
||||
};
|
||||
#undef DEPRECATED_OPERATION
|
||||
|
||||
void
|
||||
ReportDeprecation(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
|
||||
nsIDocument::DeprecatedOperations aOperation,
|
||||
const nsAString& aFileName,
|
||||
const Nullable<uint32_t>& aLineNumber,
|
||||
const Nullable<uint32_t>& aColumnNumber)
|
||||
{
|
||||
MOZ_ASSERT(aURI);
|
||||
|
||||
// Anonymize the URL.
|
||||
// Strip the URL of any possible username/password and make it ready to be
|
||||
// presented in the UI.
|
||||
nsCOMPtr<nsIURIFixup> urifixup = services::GetURIFixup();
|
||||
if (NS_WARN_IF(!urifixup)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> exposableURI;
|
||||
nsresult rv = urifixup->CreateExposableURI(aURI, getter_AddRefs(exposableURI));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = exposableURI->GetSpec(spec);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString type;
|
||||
type.AssignASCII(kDeprecatedOperations[aOperation]);
|
||||
|
||||
nsAutoCString key;
|
||||
key.AssignASCII(kDeprecatedOperations[aOperation]);
|
||||
key.AppendASCII("Warning");
|
||||
|
||||
nsAutoString msg;
|
||||
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
key.get(), msg);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<DeprecationReportBody> body =
|
||||
new DeprecationReportBody(aWindow, type, Nullable<Date>(),
|
||||
msg, aFileName, aLineNumber, aColumnNumber);
|
||||
|
||||
ReportingUtils::Report(aWindow, nsGkAtoms::deprecation,
|
||||
NS_ConvertUTF8toUTF16(spec), body);
|
||||
}
|
||||
|
||||
void
|
||||
MaybeReportDeprecation(nsPIDOMWindowInner* aWindow,
|
||||
nsIDocument::DeprecatedOperations aOperation,
|
||||
const nsAString& aFileName,
|
||||
const Nullable<uint32_t>& aLineNumber,
|
||||
const Nullable<uint32_t>& aColumnNumber)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
if (!StaticPrefs::dom_reporting_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!aWindow->GetExtantDoc())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = aWindow->GetExtantDoc()->GetDocumentURI();
|
||||
if (NS_WARN_IF(!uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReportDeprecation(aWindow, uri, aOperation, aFileName, aLineNumber,
|
||||
aColumnNumber);
|
||||
}
|
||||
|
||||
// This runnable is used to write a deprecation message from a worker to the
|
||||
// console running on the main-thread.
|
||||
class DeprecationWarningRunnable final : public WorkerProxyToMainThreadRunnable
|
||||
{
|
||||
nsIDocument::DeprecatedOperations mOperation;
|
||||
const nsIDocument::DeprecatedOperations mOperation;
|
||||
|
||||
public:
|
||||
explicit DeprecationWarningRunnable(nsIDocument::DeprecatedOperations aOperation)
|
||||
@ -4161,6 +4249,21 @@ DeprecationWarning(const GlobalObject& aGlobal,
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (window && window->GetExtantDoc()) {
|
||||
window->GetExtantDoc()->WarnOnceAbout(aOperation);
|
||||
|
||||
nsAutoCString fileName;
|
||||
Nullable<uint32_t> lineNumber;
|
||||
Nullable<uint32_t> columnNumber;
|
||||
uint32_t line = 0;
|
||||
uint32_t column = 0;
|
||||
if (nsJSUtils::GetCallingLocation(aGlobal.Context(), fileName,
|
||||
&line, &column)) {
|
||||
lineNumber.SetValue(line);
|
||||
columnNumber.SetValue(column);
|
||||
}
|
||||
|
||||
MaybeReportDeprecation(window, aOperation,
|
||||
NS_ConvertUTF8toUTF16(fileName), lineNumber,
|
||||
columnNumber);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -396,6 +396,7 @@ NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver)
|
||||
HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
|
||||
: nsGenericHTMLElement(std::move(aNodeInfo)),
|
||||
mResetLayer(true) ,
|
||||
mMaybeModified(false) ,
|
||||
mWriteOnly(false)
|
||||
{}
|
||||
|
||||
@ -1010,6 +1011,7 @@ HTMLCanvasElement::GetContext(const nsAString& aContextId,
|
||||
nsISupports** aContext)
|
||||
{
|
||||
ErrorResult rv;
|
||||
mMaybeModified = true; // For FirstContentfulPaint
|
||||
*aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
@ -1024,6 +1026,7 @@ HTMLCanvasElement::GetContext(JSContext* aCx,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mMaybeModified = true; // For FirstContentfulPaint
|
||||
return CanvasRenderingContextHelper::GetContext(aCx, aContextId,
|
||||
aContextOptions.isObject() ? aContextOptions : JS::NullHandleValue,
|
||||
aRv);
|
||||
|
@ -349,6 +349,8 @@ public:
|
||||
|
||||
already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
|
||||
|
||||
bool MaybeModified() const { return mMaybeModified; };
|
||||
|
||||
protected:
|
||||
virtual ~HTMLCanvasElement();
|
||||
|
||||
@ -387,6 +389,7 @@ protected:
|
||||
AsyncCanvasRenderer* GetAsyncCanvasRenderer();
|
||||
|
||||
bool mResetLayer;
|
||||
bool mMaybeModified; // we fetched the context, so we may have written to the canvas
|
||||
RefPtr<HTMLCanvasElement> mOriginalCanvas;
|
||||
RefPtr<PrintCallback> mPrintCallback;
|
||||
RefPtr<HTMLCanvasPrintState> mPrintState;
|
||||
|
@ -48,7 +48,10 @@ var gTestWindows = [
|
||||
{ test: "file_fullscreen-lenient-setters.html" },
|
||||
{ test: "file_fullscreen-table.html" },
|
||||
{ test: "file_fullscreen-event-order.html" },
|
||||
{ test: "file_fullscreen-featurePolicy.html", prefs: [["dom.security.featurePolicy.enabled", true]] },
|
||||
{ test: "file_fullscreen-featurePolicy.html",
|
||||
prefs: [["dom.security.featurePolicy.enabled", true],
|
||||
["dom.security.featurePolicy.header.enabled", true],
|
||||
["dom.security.featurePolicy.webidl.enabled", true]] },
|
||||
];
|
||||
|
||||
var testWindow = null;
|
||||
|
@ -353,6 +353,13 @@ AmbientLightEventWarning=Use of the ambient light sensor is deprecated.
|
||||
IDBOpenDBOptions_StorageTypeWarning=The ‘storage’ attribute in options passed to indexedDB.open is deprecated and will soon be removed. To get persistent storage, please use navigator.storage.persist() instead.
|
||||
DOMQuadBoundsAttrWarning=DOMQuad.bounds is deprecated in favor of DOMQuad.getBounds()
|
||||
UnsupportedEntryTypesIgnored=Ignoring unsupported entryTypes: %S.
|
||||
|
||||
#LOCALIZATION NOTE(DeprecatedTestingInterfaceWarning): Do not translate this message. It's just testing only.
|
||||
DeprecatedTestingInterfaceWarning=TestingDeprecatedInterface is a testing-only interface and this is its testing deprecation message.
|
||||
#LOCALIZATION NOTE(DeprecatedTestingMethodWarning): Do not translate this message. It's just testing only.
|
||||
DeprecatedTestingMethodWarning=TestingDeprecatedInterface.deprecatedMethod() is a testing-only method and this is its testing deprecation message.
|
||||
#LOCALIZATION NOTE(DeprecatedTestingAttributeWarning): Do not translate this message. It's just testing only.
|
||||
DeprecatedTestingAttributeWarning=TestingDeprecatedInterface.deprecatedAttribute is a testing-only attribute and this is its testing deprecation message.
|
||||
# LOCALIZATION NOTE (CreateImageBitmapCanvasRenderingContext2DWarning): Do not translate CanvasRenderingContext2D and createImageBitmap.
|
||||
CreateImageBitmapCanvasRenderingContext2DWarning=Use of CanvasRenderingContext2D in createImageBitmap is deprecated.
|
||||
# LOCALIZATION NOTE (MozRequestFullScreenDeprecatedPrefixWarning): Do not translate mozRequestFullScreen.
|
||||
|
@ -102,6 +102,7 @@ DIRS += [
|
||||
'websocket',
|
||||
'serviceworkers',
|
||||
'simpledb',
|
||||
'reporting',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_LIBPRIO']:
|
||||
|
@ -440,6 +440,20 @@ public:
|
||||
mPerformance->GetRandomTimelineSeed());
|
||||
}
|
||||
|
||||
DOMTimeMilliSec TimeToContentfulPaint() const
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() ||
|
||||
nsContentUtils::ShouldResistFingerprinting()) {
|
||||
return 0;
|
||||
}
|
||||
if (mPerformance->IsSystemPrincipal()) {
|
||||
return GetDOMTiming()->GetTimeToContentfulPaint();
|
||||
}
|
||||
return nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
GetDOMTiming()->GetTimeToContentfulPaint(),
|
||||
mPerformance->GetRandomTimelineSeed());
|
||||
}
|
||||
|
||||
DOMTimeMilliSec TimeToDOMContentFlushed() const
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() ||
|
||||
|
76
dom/reporting/DeprecationReportBody.cpp
Normal file
76
dom/reporting/DeprecationReportBody.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/DeprecationReportBody.h"
|
||||
#include "mozilla/dom/ReportingBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
DeprecationReportBody::DeprecationReportBody(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aId,
|
||||
const Nullable<Date>& aDate,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aSourceFile,
|
||||
const Nullable<uint32_t>& aLineNumber,
|
||||
const Nullable<uint32_t>& aColumnNumber)
|
||||
: ReportBody(aWindow)
|
||||
, mId(aId)
|
||||
, mDate(aDate)
|
||||
, mMessage(aMessage)
|
||||
, mSourceFile(aSourceFile)
|
||||
, mLineNumber(aLineNumber)
|
||||
, mColumnNumber(aColumnNumber)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
}
|
||||
|
||||
DeprecationReportBody::~DeprecationReportBody() = default;
|
||||
|
||||
JSObject*
|
||||
DeprecationReportBody::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return DeprecationReportBody_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
DeprecationReportBody::GetId(nsAString& aId) const
|
||||
{
|
||||
aId = mId;
|
||||
}
|
||||
|
||||
Nullable<Date>
|
||||
DeprecationReportBody::GetAnticipatedRemoval() const
|
||||
{
|
||||
return mDate;
|
||||
}
|
||||
|
||||
void
|
||||
DeprecationReportBody::GetMessage(nsAString& aMessage) const
|
||||
{
|
||||
aMessage = mMessage;
|
||||
}
|
||||
|
||||
void
|
||||
DeprecationReportBody::GetSourceFile(nsAString& aSourceFile) const
|
||||
{
|
||||
aSourceFile = mSourceFile;
|
||||
}
|
||||
|
||||
Nullable<uint32_t>
|
||||
DeprecationReportBody::GetLineNumber() const
|
||||
{
|
||||
return mLineNumber;
|
||||
}
|
||||
|
||||
Nullable<uint32_t>
|
||||
DeprecationReportBody::GetColumnNumber() const
|
||||
{
|
||||
return mColumnNumber;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
62
dom/reporting/DeprecationReportBody.h
Normal file
62
dom/reporting/DeprecationReportBody.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_DeprecationReportBody_h
|
||||
#define mozilla_dom_DeprecationReportBody_h
|
||||
|
||||
#include "mozilla/dom/ReportBody.h"
|
||||
#include "mozilla/dom/Date.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DeprecationReportBody final : public ReportBody
|
||||
{
|
||||
public:
|
||||
DeprecationReportBody(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aId,
|
||||
const Nullable<Date>& aDate,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aSourceFile,
|
||||
const Nullable<uint32_t>& aLineNumber,
|
||||
const Nullable<uint32_t>& aColumnNumber);
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void
|
||||
GetId(nsAString& aId) const;
|
||||
|
||||
Nullable<Date>
|
||||
GetAnticipatedRemoval() const;
|
||||
|
||||
void
|
||||
GetMessage(nsAString& aMessage) const;
|
||||
|
||||
void
|
||||
GetSourceFile(nsAString& aSourceFile) const;
|
||||
|
||||
Nullable<uint32_t>
|
||||
GetLineNumber() const;
|
||||
|
||||
Nullable<uint32_t>
|
||||
GetColumnNumber() const;
|
||||
|
||||
private:
|
||||
~DeprecationReportBody();
|
||||
|
||||
const nsString mId;
|
||||
const Nullable<Date> mDate;
|
||||
const nsString mMessage;
|
||||
const nsString mSourceFile;
|
||||
const Nullable<uint32_t> mLineNumber;
|
||||
const Nullable<uint32_t> mColumnNumber;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_DeprecationReportBody_h
|
66
dom/reporting/FeaturePolicyViolationReportBody.cpp
Normal file
66
dom/reporting/FeaturePolicyViolationReportBody.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/FeaturePolicyViolationReportBody.h"
|
||||
#include "mozilla/dom/FeaturePolicyBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
FeaturePolicyViolationReportBody::FeaturePolicyViolationReportBody(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aFeatureId,
|
||||
const nsAString& aSourceFile,
|
||||
const Nullable<int32_t>& aLineNumber,
|
||||
const Nullable<int32_t>& aColumnNumber,
|
||||
const nsAString& aDisposition)
|
||||
: ReportBody(aWindow)
|
||||
, mFeatureId(aFeatureId)
|
||||
, mSourceFile(aSourceFile)
|
||||
, mLineNumber(aLineNumber)
|
||||
, mColumnNumber(aColumnNumber)
|
||||
, mDisposition(aDisposition)
|
||||
{}
|
||||
|
||||
FeaturePolicyViolationReportBody::~FeaturePolicyViolationReportBody() = default;
|
||||
|
||||
JSObject*
|
||||
FeaturePolicyViolationReportBody::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return FeaturePolicyViolationReportBody_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
FeaturePolicyViolationReportBody::GetFeatureId(nsAString& aFeatureId) const
|
||||
{
|
||||
aFeatureId = mFeatureId;
|
||||
}
|
||||
|
||||
void
|
||||
FeaturePolicyViolationReportBody::GetSourceFile(nsAString& aSourceFile) const
|
||||
{
|
||||
aSourceFile = mSourceFile;
|
||||
}
|
||||
|
||||
Nullable<int32_t>
|
||||
FeaturePolicyViolationReportBody::GetLineNumber() const
|
||||
{
|
||||
return mLineNumber;
|
||||
}
|
||||
|
||||
Nullable<int32_t>
|
||||
FeaturePolicyViolationReportBody::GetColumnNumber() const
|
||||
{
|
||||
return mColumnNumber;
|
||||
}
|
||||
|
||||
void
|
||||
FeaturePolicyViolationReportBody::GetDisposition(nsAString& aDisposition) const
|
||||
{
|
||||
aDisposition = mDisposition;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
57
dom/reporting/FeaturePolicyViolationReportBody.h
Normal file
57
dom/reporting/FeaturePolicyViolationReportBody.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_FeaturePolicyViolationReportBody_h
|
||||
#define mozilla_dom_FeaturePolicyViolationReportBody_h
|
||||
|
||||
#include "mozilla/dom/ReportBody.h"
|
||||
#include "mozilla/dom/Date.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FeaturePolicyViolationReportBody final : public ReportBody
|
||||
{
|
||||
public:
|
||||
FeaturePolicyViolationReportBody(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aFeatureId,
|
||||
const nsAString& aSourceFile,
|
||||
const Nullable<int32_t>& aLineNumber,
|
||||
const Nullable<int32_t>& aColumnNumber,
|
||||
const nsAString& aDisposition);
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void
|
||||
GetFeatureId(nsAString& aFeatureId) const;
|
||||
|
||||
void
|
||||
GetSourceFile(nsAString& aSourceFile) const;
|
||||
|
||||
Nullable<int32_t>
|
||||
GetLineNumber() const;
|
||||
|
||||
Nullable<int32_t>
|
||||
GetColumnNumber() const;
|
||||
|
||||
void
|
||||
GetDisposition(nsAString& aDisposition) const;
|
||||
|
||||
private:
|
||||
~FeaturePolicyViolationReportBody();
|
||||
|
||||
const nsString mFeatureId;
|
||||
const nsString mSourceFile;
|
||||
const Nullable<int32_t> mLineNumber;
|
||||
const Nullable<int32_t> mColumnNumber;
|
||||
const nsString mDisposition;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_FeaturePolicyViolationReportBody_h
|
70
dom/reporting/Report.cpp
Normal file
70
dom/reporting/Report.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/Report.h"
|
||||
#include "mozilla/dom/ReportBody.h"
|
||||
#include "mozilla/dom/ReportingBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Report, mWindow, mBody)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Report)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(Report)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Report)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
Report::Report(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aType,
|
||||
const nsAString& aURL,
|
||||
ReportBody* aBody)
|
||||
: mWindow(aWindow)
|
||||
, mType(aType)
|
||||
, mURL(aURL)
|
||||
, mBody(aBody)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
}
|
||||
|
||||
Report::~Report() = default;
|
||||
|
||||
already_AddRefed<Report>
|
||||
Report::Clone()
|
||||
{
|
||||
RefPtr<Report> report =
|
||||
new Report(mWindow, mType, mURL, mBody);
|
||||
return report.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
Report::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return Report_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
Report::GetType(nsAString& aType) const
|
||||
{
|
||||
aType = mType;
|
||||
}
|
||||
|
||||
void
|
||||
Report::GetUrl(nsAString& aURL) const
|
||||
{
|
||||
aURL = mURL;
|
||||
}
|
||||
|
||||
ReportBody*
|
||||
Report::GetBody() const
|
||||
{
|
||||
return mBody;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
66
dom/reporting/Report.h
Normal file
66
dom/reporting/Report.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_Report_h
|
||||
#define mozilla_dom_Report_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ReportBody;
|
||||
|
||||
class Report final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Report)
|
||||
|
||||
Report(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aType,
|
||||
const nsAString& aURL,
|
||||
ReportBody* aBody);
|
||||
|
||||
already_AddRefed<Report>
|
||||
Clone();
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsPIDOMWindowInner*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
void
|
||||
GetType(nsAString& aType) const;
|
||||
|
||||
void
|
||||
GetUrl(nsAString& aURL) const;
|
||||
|
||||
ReportBody*
|
||||
GetBody() const;
|
||||
|
||||
private:
|
||||
~Report();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
|
||||
const nsString mType;
|
||||
const nsString mURL;
|
||||
RefPtr<ReportBody> mBody;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_Report_h
|
38
dom/reporting/ReportBody.cpp
Normal file
38
dom/reporting/ReportBody.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/ReportBody.h"
|
||||
#include "mozilla/dom/ReportingBinding.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ReportBody, mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ReportBody)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ReportBody)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReportBody)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ReportBody::ReportBody(nsPIDOMWindowInner* aWindow)
|
||||
: mWindow(aWindow)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
}
|
||||
|
||||
ReportBody::~ReportBody() = default;
|
||||
|
||||
JSObject*
|
||||
ReportBody::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return ReportBody_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
47
dom/reporting/ReportBody.h
Normal file
47
dom/reporting/ReportBody.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_ReportBody_h
|
||||
#define mozilla_dom_ReportBody_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ReportBody : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ReportBody)
|
||||
|
||||
explicit ReportBody(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsPIDOMWindowInner*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~ReportBody();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_ReportBody_h
|
197
dom/reporting/ReportingObserver.cpp
Normal file
197
dom/reporting/ReportingObserver.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/ReportingObserver.h"
|
||||
#include "mozilla/dom/ReportingBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindowInner.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(ReportingObserver)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ReportingObserver)
|
||||
tmp->Shutdown();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReports)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ReportingObserver)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReports)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(ReportingObserver)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ReportingObserver)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ReportingObserver)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReportingObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
/* static */ already_AddRefed<ReportingObserver>
|
||||
ReportingObserver::Constructor(const GlobalObject& aGlobal,
|
||||
ReportingObserverCallback& aCallback,
|
||||
const ReportingObserverOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(window);
|
||||
|
||||
nsTArray<nsString> types;
|
||||
if (aOptions.mTypes.WasPassed()) {
|
||||
types = aOptions.mTypes.Value();
|
||||
}
|
||||
|
||||
RefPtr<ReportingObserver> ro =
|
||||
new ReportingObserver(window, aCallback, types, aOptions.mBuffered);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aRv = obs->AddObserver(ro, "memory-pressure", true);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ro.forget();
|
||||
}
|
||||
|
||||
ReportingObserver::ReportingObserver(nsPIDOMWindowInner* aWindow,
|
||||
ReportingObserverCallback& aCallback,
|
||||
const nsTArray<nsString>& aTypes,
|
||||
bool aBuffered)
|
||||
: mWindow(aWindow)
|
||||
, mCallback(&aCallback)
|
||||
, mTypes(aTypes)
|
||||
, mBuffered(aBuffered)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
}
|
||||
|
||||
ReportingObserver::~ReportingObserver()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
ReportingObserver::Shutdown()
|
||||
{
|
||||
Disconnect();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "memory-pressure");
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
ReportingObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return ReportingObserver_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
ReportingObserver::Observe()
|
||||
{
|
||||
mWindow->RegisterReportingObserver(this, mBuffered);
|
||||
}
|
||||
|
||||
void
|
||||
ReportingObserver::Disconnect()
|
||||
{
|
||||
if (mWindow) {
|
||||
mWindow->UnregisterReportingObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReportingObserver::TakeRecords(nsTArray<RefPtr<Report>>& aRecords)
|
||||
{
|
||||
mReports.SwapElements(aRecords);
|
||||
}
|
||||
|
||||
void
|
||||
ReportingObserver::MaybeReport(Report* aReport)
|
||||
{
|
||||
MOZ_ASSERT(aReport);
|
||||
|
||||
if (!mTypes.IsEmpty()) {
|
||||
nsAutoString type;
|
||||
aReport->GetType(type);
|
||||
|
||||
if (!mTypes.Contains(type)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool wasEmpty = mReports.IsEmpty();
|
||||
|
||||
RefPtr<Report> report = aReport->Clone();
|
||||
MOZ_ASSERT(report);
|
||||
|
||||
if (NS_WARN_IF(!mReports.AppendElement(report, fallible))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = mWindow;
|
||||
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableFunction(
|
||||
"ReportingObserver::MaybeReport",
|
||||
[window]() {
|
||||
window->NotifyReportingObservers();
|
||||
});
|
||||
|
||||
NS_DispatchToCurrentThread(r);
|
||||
}
|
||||
|
||||
void
|
||||
ReportingObserver::MaybeNotify()
|
||||
{
|
||||
if (mReports.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's take the ownership of the reports.
|
||||
nsTArray<RefPtr<Report>> list;
|
||||
list.SwapElements(mReports);
|
||||
|
||||
Sequence<OwningNonNull<Report>> reports;
|
||||
for (Report* report : list) {
|
||||
if (NS_WARN_IF(!reports.AppendElement(*report, fallible))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We should report if this throws exception. But where?
|
||||
mCallback->Call(reports, *this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReportingObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(!strcmp(aTopic, "memory-pressure"));
|
||||
mReports.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
89
dom/reporting/ReportingObserver.h
Normal file
89
dom/reporting/ReportingObserver.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_ReportingObserver_h
|
||||
#define mozilla_dom_ReportingObserver_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Report;
|
||||
class ReportingObserverCallback;
|
||||
struct ReportingObserverOptions;
|
||||
|
||||
class ReportingObserver final : public nsIObserver
|
||||
, public nsWrapperCache
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(ReportingObserver,
|
||||
nsIObserver)
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static already_AddRefed<ReportingObserver>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
ReportingObserverCallback& aCallback,
|
||||
const ReportingObserverOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
ReportingObserver(nsPIDOMWindowInner* aWindow,
|
||||
ReportingObserverCallback& aCallback,
|
||||
const nsTArray<nsString>& aTypes,
|
||||
bool aBuffered);
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsPIDOMWindowInner*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
void
|
||||
Observe();
|
||||
|
||||
void
|
||||
Disconnect();
|
||||
|
||||
void
|
||||
TakeRecords(nsTArray<RefPtr<Report>>& aRecords);
|
||||
|
||||
void
|
||||
MaybeReport(Report* aReport);
|
||||
|
||||
void
|
||||
MaybeNotify();
|
||||
|
||||
private:
|
||||
~ReportingObserver();
|
||||
|
||||
void
|
||||
Shutdown();
|
||||
|
||||
nsTArray<RefPtr<Report>> mReports;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
RefPtr<ReportingObserverCallback> mCallback;
|
||||
nsTArray<nsString> mTypes;
|
||||
bool mBuffered;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_ReportingObserver_h
|
33
dom/reporting/ReportingUtils.cpp
Normal file
33
dom/reporting/ReportingUtils.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/ReportingUtils.h"
|
||||
#include "mozilla/dom/ReportBody.h"
|
||||
#include "mozilla/dom/Report.h"
|
||||
#include "nsAtom.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ void
|
||||
ReportingUtils::Report(nsPIDOMWindowInner* aWindow,
|
||||
nsAtom* aType,
|
||||
const nsAString& aURL,
|
||||
ReportBody* aBody)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aBody);
|
||||
|
||||
RefPtr<mozilla::dom::Report> report =
|
||||
new mozilla::dom::Report(aWindow, nsDependentAtomString(aType), aURL,
|
||||
aBody);
|
||||
aWindow->BroadcastReport(report);
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
32
dom/reporting/ReportingUtils.h
Normal file
32
dom/reporting/ReportingUtils.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_ReportingUtils_h
|
||||
#define mozilla_dom_ReportingUtils_h
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIPDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ReportBody;
|
||||
|
||||
class ReportingUtils final
|
||||
{
|
||||
public:
|
||||
static void
|
||||
Report(nsPIDOMWindowInner* aWindow,
|
||||
nsAtom* aType,
|
||||
const nsAString& aURL,
|
||||
ReportBody* aBody);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ReportingUtils_h
|
59
dom/reporting/TestingDeprecatedInterface.cpp
Normal file
59
dom/reporting/TestingDeprecatedInterface.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/TestingDeprecatedInterface.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TestingDeprecatedInterface, mGlobal)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(TestingDeprecatedInterface)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(TestingDeprecatedInterface)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TestingDeprecatedInterface)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
/* static */ already_AddRefed<TestingDeprecatedInterface>
|
||||
TestingDeprecatedInterface::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
RefPtr<TestingDeprecatedInterface> obj =
|
||||
new TestingDeprecatedInterface(global);
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
TestingDeprecatedInterface::TestingDeprecatedInterface(nsIGlobalObject* aGlobal)
|
||||
: mGlobal(aGlobal)
|
||||
{}
|
||||
|
||||
|
||||
TestingDeprecatedInterface::~TestingDeprecatedInterface() = default;
|
||||
|
||||
JSObject*
|
||||
TestingDeprecatedInterface::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return TestingDeprecatedInterface_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
TestingDeprecatedInterface::DeprecatedMethod() const
|
||||
{}
|
||||
|
||||
bool
|
||||
TestingDeprecatedInterface::DeprecatedAttribute() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
55
dom/reporting/TestingDeprecatedInterface.h
Normal file
55
dom/reporting/TestingDeprecatedInterface.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_TestingDeprecatedInterface_h
|
||||
#define mozilla_dom_TestingDeprecatedInterface_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class TestingDeprecatedInterface final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TestingDeprecatedInterface)
|
||||
|
||||
static already_AddRefed<TestingDeprecatedInterface>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsIGlobalObject*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mGlobal;
|
||||
}
|
||||
|
||||
void
|
||||
DeprecatedMethod() const;
|
||||
|
||||
bool
|
||||
DeprecatedAttribute() const;
|
||||
|
||||
private:
|
||||
explicit TestingDeprecatedInterface(nsIGlobalObject* aGlobal);
|
||||
~TestingDeprecatedInterface();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_TestingDeprecatedInterface_h
|
||||
|
34
dom/reporting/moz.build
Normal file
34
dom/reporting/moz.build
Normal file
@ -0,0 +1,34 @@
|
||||
# -*- Mode: python; 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/.
|
||||
|
||||
EXPORTS.mozilla.dom = [
|
||||
'DeprecationReportBody.h',
|
||||
'FeaturePolicyViolationReportBody.h',
|
||||
'Report.h',
|
||||
'ReportBody.h',
|
||||
'ReportingObserver.h',
|
||||
'ReportingUtils.h',
|
||||
'TestingDeprecatedInterface.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DeprecationReportBody.cpp',
|
||||
'FeaturePolicyViolationReportBody.cpp',
|
||||
'Report.cpp',
|
||||
'ReportBody.cpp',
|
||||
'ReportingObserver.cpp',
|
||||
'ReportingUtils.cpp',
|
||||
'TestingDeprecatedInterface.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('DOM', 'Security')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
|
7
dom/reporting/tests/.eslintrc.js
Normal file
7
dom/reporting/tests/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/mochitest-test",
|
||||
],
|
||||
};
|
7
dom/reporting/tests/mochitest.ini
Normal file
7
dom/reporting/tests/mochitest.ini
Normal file
@ -0,0 +1,7 @@
|
||||
[DEFAULT]
|
||||
prefs =
|
||||
dom.reporting.enabled=true
|
||||
dom.reporting.testing.enabled=true
|
||||
|
||||
[test_deprecated.html]
|
||||
[test_memoryPressure.html]
|
143
dom/reporting/tests/test_deprecated.html
Normal file
143
dom/reporting/tests/test_deprecated.html
Normal file
@ -0,0 +1,143 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Deprecated reports</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
let testingInterface;
|
||||
|
||||
(new Promise(resolve => {
|
||||
info("Testing DeprecatedTestingInterface report");
|
||||
let obs = new ReportingObserver((reports, o) => {
|
||||
is(obs, o, "Same observer!");
|
||||
ok(reports.length == 1, "We have 1 report");
|
||||
|
||||
let report = reports[0];
|
||||
is(report.type, "deprecation", "Deprecation report received");
|
||||
is(report.url, location.href, "URL is window.location");
|
||||
ok(!!report.body, "The report has a body");
|
||||
ok(report.body instanceof DeprecationReportBody, "Correct type for the body");
|
||||
is(report.body.id, "DeprecatedTestingInterface", "report.body.id matches DeprecatedTestingMethod");
|
||||
ok(!report.body.anticipatedRemoval, "We don't have a anticipatedRemoval");
|
||||
ok(report.body.message.includes("TestingDeprecatedInterface"), "We have a message");
|
||||
is(report.body.sourceFile, location.href, "We have a sourceFile");
|
||||
is(report.body.lineNumber, 40, "We have a lineNumber");
|
||||
is(report.body.columnNumber, 21, "We have a columnNumber");
|
||||
|
||||
obs.disconnect();
|
||||
resolve();
|
||||
});
|
||||
ok(!!obs, "ReportingObserver is a thing");
|
||||
|
||||
obs.observe();
|
||||
ok(true, "ReportingObserver.observe() is callable");
|
||||
|
||||
testingInterface = new TestingDeprecatedInterface();
|
||||
ok(true, "Created a deprecated interface");
|
||||
}))
|
||||
|
||||
.then(() => {
|
||||
info("Testing DeprecatedTestingMethod report");
|
||||
return new Promise(resolve => {
|
||||
let obs = new ReportingObserver((reports, o) => {
|
||||
is(obs, o, "Same observer!");
|
||||
ok(reports.length == 1, "We have 1 report");
|
||||
|
||||
let report = reports[0];
|
||||
is(report.type, "deprecation", "Deprecation report received");
|
||||
is(report.url, location.href, "URL is window.location");
|
||||
ok(!!report.body, "The report has a body");
|
||||
ok(report.body instanceof DeprecationReportBody, "Correct type for the body");
|
||||
is(report.body.id, "DeprecatedTestingMethod", "report.body.id matches DeprecatedTestingMethod");
|
||||
ok(!report.body.anticipatedRemoval, "We don't have a anticipatedRemoval");
|
||||
ok(report.body.message.includes("TestingDeprecatedInterface.deprecatedMethod"), "We have a message");
|
||||
is(report.body.sourceFile, location.href, "We have a sourceFile");
|
||||
is(report.body.lineNumber, 71, "We have a lineNumber");
|
||||
is(report.body.columnNumber, 4, "We have a columnNumber");
|
||||
|
||||
obs.disconnect();
|
||||
resolve();
|
||||
});
|
||||
ok(!!obs, "ReportingObserver is a thing");
|
||||
|
||||
obs.observe();
|
||||
ok(true, "ReportingObserver.observe() is callable");
|
||||
|
||||
testingInterface.deprecatedMethod();
|
||||
ok(true, "Run a deprecated method.");
|
||||
});
|
||||
})
|
||||
|
||||
.then(() => {
|
||||
info("Testing DeprecatedTestingAttribute report");
|
||||
return new Promise(resolve => {
|
||||
let obs = new ReportingObserver((reports, o) => {
|
||||
is(obs, o, "Same observer!");
|
||||
ok(reports.length == 1, "We have 1 report");
|
||||
|
||||
let report = reports[0];
|
||||
is(report.type, "deprecation", "Deprecation report received");
|
||||
is(report.url, location.href, "URL is window.location");
|
||||
ok(!!report.body, "The report has a body");
|
||||
ok(report.body instanceof DeprecationReportBody, "Correct type for the body");
|
||||
is(report.body.id, "DeprecatedTestingAttribute", "report.body.id matches DeprecatedTestingAttribute");
|
||||
ok(!report.body.anticipatedRemoval, "We don't have a anticipatedRemoval");
|
||||
ok(report.body.message.includes("TestingDeprecatedInterface.deprecatedAttribute"), "We have a message");
|
||||
is(report.body.sourceFile, location.href, "We have a sourceFile");
|
||||
is(report.body.lineNumber, 103, "We have a lineNumber");
|
||||
is(report.body.columnNumber, 4, "We have a columnNumber");
|
||||
|
||||
obs.disconnect();
|
||||
resolve();
|
||||
});
|
||||
ok(!!obs, "ReportingObserver is a thing");
|
||||
|
||||
obs.observe();
|
||||
ok(true, "ReportingObserver.observe() is callable");
|
||||
|
||||
ok(testingInterface.deprecatedAttribute, "Attributed called");
|
||||
});
|
||||
})
|
||||
|
||||
.then(() => {
|
||||
info("Testing ReportingObserver.takeRecords()");
|
||||
let p = new Promise(resolve => {
|
||||
let obs = new ReportingObserver((reports, o) => {
|
||||
is(obs, o, "Same observer!");
|
||||
resolve(obs);
|
||||
});
|
||||
ok(!!obs, "ReportingObserver is a thing");
|
||||
|
||||
obs.observe();
|
||||
ok(true, "ReportingObserver.observe() is callable");
|
||||
|
||||
testingInterface.deprecatedMethod();
|
||||
ok(true, "Run a deprecated method.");
|
||||
});
|
||||
|
||||
return p.then(obs => {
|
||||
let reports = obs.takeRecords();
|
||||
is(reports.length, 0, "No reports after an callback");
|
||||
|
||||
testingInterface.deprecatedAttribute + 1;
|
||||
|
||||
reports = obs.takeRecords();
|
||||
ok(reports.length >= 1, "We have at least 1 report");
|
||||
|
||||
reports = obs.takeRecords();
|
||||
is(reports.length, 0, "No more reports");
|
||||
});
|
||||
})
|
||||
|
||||
.then(() => { SimpleTest.finish(); });
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
33
dom/reporting/tests/test_memoryPressure.html
Normal file
33
dom/reporting/tests/test_memoryPressure.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for ReportingObserver + memory-pressure</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
info("Testing TakeRecords() without memory-pressure");
|
||||
let o = new ReportingObserver(() => {});
|
||||
o.observe();
|
||||
|
||||
new TestingDeprecatedInterface();
|
||||
let r = o.takeRecords();
|
||||
is(r.length, 1, "We have 1 report");
|
||||
|
||||
r = o.takeRecords();
|
||||
is(r.length, 0, "We have 0 reports after a takeRecords()");
|
||||
|
||||
info("Testing DeprecatedTestingMethod report");
|
||||
|
||||
new TestingDeprecatedInterface();
|
||||
SpecialPowers.Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
|
||||
|
||||
r = o.takeRecords();
|
||||
is(r.length, 0, "We have 0 reports after a memory-pressure");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -16,7 +16,7 @@
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/OffThreadScriptCompilation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/Utility.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
@ -68,7 +68,7 @@
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
using JS::SourceBufferHolder;
|
||||
using JS::SourceText;
|
||||
|
||||
using mozilla::Telemetry::LABELS_DOM_SCRIPT_PRELOAD_RESULT;
|
||||
|
||||
@ -1933,11 +1933,11 @@ ScriptLoader::CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest)
|
||||
return ProcessRequest(aRequest);
|
||||
}
|
||||
|
||||
mozilla::Maybe<SourceBufferHolder>
|
||||
mozilla::Maybe<SourceText<char16_t>>
|
||||
ScriptLoader::GetScriptSource(JSContext* aCx, ScriptLoadRequest* aRequest)
|
||||
{
|
||||
// Return a SourceBufferHolder object holding the script's source text.
|
||||
// Ownership of the buffer is transferred to the resulting SourceBufferHolder.
|
||||
// Return a SourceText<char16_t> object holding the script's source text.
|
||||
// Ownership of the buffer is transferred to the resulting holder.
|
||||
|
||||
// If there's no script text, we try to get it from the element
|
||||
if (aRequest->mIsInline) {
|
||||
@ -1951,12 +1951,28 @@ ScriptLoader::GetScriptSource(JSContext* aCx, ScriptLoadRequest* aRequest)
|
||||
}
|
||||
|
||||
memcpy(chars.get(), inlineData.get(), nbytes);
|
||||
return Some(SourceBufferHolder(std::move(chars), inlineData.Length()));
|
||||
|
||||
SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(aCx, std::move(chars), inlineData.Length())) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(SourceText<char16_t>(std::move(srcBuf)));
|
||||
}
|
||||
|
||||
size_t length = aRequest->ScriptText().length();
|
||||
JS::UniqueTwoByteChars chars(aRequest->ScriptText().extractOrCopyRawBuffer());
|
||||
return Some(SourceBufferHolder(std::move(chars), length));
|
||||
if (!chars) {
|
||||
JS_ReportOutOfMemory(aCx);
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(aCx, std::move(chars), length)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(SourceText<char16_t>(std::move(srcBuf)));
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -32,7 +32,9 @@
|
||||
class nsIURI;
|
||||
|
||||
namespace JS {
|
||||
class SourceBufferHolder;
|
||||
|
||||
template<typename UnitT> class SourceText;
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace mozilla {
|
||||
@ -507,8 +509,8 @@ private:
|
||||
|
||||
void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
|
||||
|
||||
mozilla::Maybe<JS::SourceBufferHolder> GetScriptSource(JSContext* aCx,
|
||||
ScriptLoadRequest* aRequest);
|
||||
mozilla::Maybe<JS::SourceText<char16_t>>
|
||||
GetScriptSource(JSContext* aCx, ScriptLoadRequest* aRequest);
|
||||
|
||||
void SetModuleFetchStarted(ModuleLoadRequest *aRequest);
|
||||
void SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest* aRequest,
|
||||
|
@ -50,6 +50,9 @@
|
||||
*
|
||||
* From a C++ point of view, use FeaturePolicyUtils to obtain the list of
|
||||
* features and to check if they are allowed in the current context.
|
||||
*
|
||||
* dom.security.featurePolicy.header.enabled pref can be used to disable the
|
||||
* HTTP header support.
|
||||
**/
|
||||
|
||||
class nsIDocument;
|
||||
|
@ -6,8 +6,11 @@
|
||||
|
||||
#include "FeaturePolicyUtils.h"
|
||||
#include "mozilla/dom/FeaturePolicy.h"
|
||||
#include "mozilla/dom/FeaturePolicyViolationReportBody.h"
|
||||
#include "mozilla/dom/ReportingUtils.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIURIFixup.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -87,7 +90,72 @@ FeaturePolicyUtils::IsFeatureAllowed(nsIDocument* aDocument,
|
||||
FeaturePolicy* policy = aDocument->Policy();
|
||||
MOZ_ASSERT(policy);
|
||||
|
||||
return policy->AllowsFeatureInternal(aFeatureName, policy->DefaultOrigin());
|
||||
if (policy->AllowsFeatureInternal(aFeatureName, policy->DefaultOrigin())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ReportViolation(aDocument, aFeatureName);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
FeaturePolicyUtils::ReportViolation(nsIDocument* aDocument,
|
||||
const nsAString& aFeatureName)
|
||||
{
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
|
||||
if (NS_WARN_IF(!uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Strip the URL of any possible username/password and make it ready to be
|
||||
// presented in the UI.
|
||||
nsCOMPtr<nsIURIFixup> urifixup = services::GetURIFixup();
|
||||
if (NS_WARN_IF(!urifixup)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> exposableURI;
|
||||
nsresult rv = urifixup->CreateExposableURI(uri, getter_AddRefs(exposableURI));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = exposableURI->GetSpec(spec);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
||||
if (NS_WARN_IF(!cx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString fileName;
|
||||
Nullable<int32_t> lineNumber;
|
||||
Nullable<int32_t> columnNumber;
|
||||
uint32_t line = 0;
|
||||
uint32_t column = 0;
|
||||
if (nsJSUtils::GetCallingLocation(cx, fileName, &line, &column)) {
|
||||
lineNumber.SetValue(static_cast<int32_t>(line));
|
||||
columnNumber.SetValue(static_cast<int32_t>(column));
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* window = aDocument->GetInnerWindow();
|
||||
if (NS_WARN_IF(!window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<FeaturePolicyViolationReportBody> body =
|
||||
new FeaturePolicyViolationReportBody(window, aFeatureName,
|
||||
NS_ConvertUTF8toUTF16(fileName),
|
||||
lineNumber, columnNumber,
|
||||
NS_LITERAL_STRING("enforce"));
|
||||
|
||||
ReportingUtils::Report(window,
|
||||
nsGkAtoms::featurePolicyViolation,
|
||||
NS_ConvertUTF8toUTF16(spec), body);
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
|
@ -48,6 +48,11 @@ public:
|
||||
// Returns the default policy value for aFeatureName.
|
||||
static FeaturePolicyValue
|
||||
DefaultAllowListFeature(const nsAString& aFeatureName);
|
||||
|
||||
private:
|
||||
static void
|
||||
ReportViolation(nsIDocument* aDocument,
|
||||
const nsAString& aFeatureName);
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
|
@ -1,6 +1,8 @@
|
||||
[DEFAULT]
|
||||
prefs =
|
||||
dom.security.featurePolicy.enabled=true
|
||||
dom.security.featurePolicy.header.enabled=true
|
||||
dom.security.featurePolicy.webidl.enabled=true
|
||||
support-files =
|
||||
empty.html
|
||||
test_parser.html^headers^
|
||||
|
@ -809,12 +809,14 @@ StripURIForReporting(nsIURI* aURI,
|
||||
// 1) If the origin of uri is a globally unique identifier (for example,
|
||||
// aURI has a scheme of data, blob, or filesystem), then return the
|
||||
// ASCII serialization of uri’s scheme.
|
||||
bool isHttpOrFtp =
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("http", &isHttpOrFtp)) && isHttpOrFtp) ||
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("https", &isHttpOrFtp)) && isHttpOrFtp) ||
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("ftp", &isHttpOrFtp)) && isHttpOrFtp);
|
||||
bool isHttpFtpOrWs =
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("http", &isHttpFtpOrWs)) && isHttpFtpOrWs) ||
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("https", &isHttpFtpOrWs)) && isHttpFtpOrWs) ||
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("ftp", &isHttpFtpOrWs)) && isHttpFtpOrWs) ||
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("ws", &isHttpFtpOrWs)) && isHttpFtpOrWs) ||
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("wss", &isHttpFtpOrWs)) && isHttpFtpOrWs);
|
||||
|
||||
if (!isHttpOrFtp) {
|
||||
if (!isHttpFtpOrWs) {
|
||||
// not strictly spec compliant, but what we really care about is
|
||||
// http/https and also ftp. If it's not http/https or ftp, then treat aURI
|
||||
// as if it's a globally unique identifier and just return the scheme.
|
||||
|
@ -45,7 +45,11 @@ function nextTest() {
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.security.featurePolicy.enabled", true]]}).then(nextTest);
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.security.featurePolicy.enabled", true],
|
||||
["dom.security.featurePolicy.header.enabled", true],
|
||||
["dom.security.featurePolicy.webidl.enabled", true],
|
||||
]}).then(nextTest);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -550,6 +550,6 @@ Document implements DocumentOrShadowRoot;
|
||||
|
||||
// https://wicg.github.io/feature-policy/#policy
|
||||
partial interface Document {
|
||||
[SameObject, Pref="dom.security.featurePolicy.enabled"]
|
||||
[SameObject, Pref="dom.security.featurePolicy.webidl.enabled"]
|
||||
readonly attribute Policy policy;
|
||||
};
|
||||
|
@ -13,3 +13,12 @@ interface Policy {
|
||||
sequence<DOMString> allowedFeatures();
|
||||
sequence<DOMString> getAllowlistForFeature(DOMString feature);
|
||||
};
|
||||
|
||||
[Func="mozilla::dom::DOMPrefs::dom_reporting_featurePolicy_enabled"]
|
||||
interface FeaturePolicyViolationReportBody : ReportBody {
|
||||
readonly attribute DOMString featureId;
|
||||
readonly attribute DOMString? sourceFile;
|
||||
readonly attribute long? lineNumber;
|
||||
readonly attribute long? columnNumber;
|
||||
readonly attribute DOMString disposition;
|
||||
};
|
||||
|
@ -72,7 +72,7 @@ HTMLIFrameElement implements BrowserElement;
|
||||
|
||||
// https://wicg.github.io/feature-policy/#policy
|
||||
partial interface HTMLIFrameElement {
|
||||
[SameObject, Pref="dom.security.featurePolicy.enabled"]
|
||||
[SameObject, Pref="dom.security.featurePolicy.webidl.enabled"]
|
||||
readonly attribute Policy policy;
|
||||
|
||||
[CEReactions, SetterThrows, Pure, Pref="dom.security.featurePolicy.enabled"]
|
||||
|
@ -39,6 +39,10 @@ interface PerformanceTiming {
|
||||
[Pref="dom.performance.time_to_non_blank_paint.enabled"]
|
||||
readonly attribute unsigned long long timeToNonBlankPaint;
|
||||
|
||||
// Returns 0 if a contentful paint has not happened.
|
||||
[Pref="dom.performance.time_to_contentful_paint.enabled"]
|
||||
readonly attribute unsigned long long timeToContentfulPaint;
|
||||
|
||||
// This is a Mozilla proprietary extension and not part of the
|
||||
// performance/navigation timing specification. It marks the
|
||||
// completion of the first presentation flush after DOMContentLoaded.
|
||||
|
57
dom/webidl/Reporting.webidl
Normal file
57
dom/webidl/Reporting.webidl
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/reporting/#interface-reporting-observer
|
||||
*/
|
||||
|
||||
[Func="mozilla::dom::DOMPrefs::dom_reporting_enabled"]
|
||||
interface ReportBody {
|
||||
};
|
||||
|
||||
[Func="mozilla::dom::DOMPrefs::dom_reporting_enabled"]
|
||||
interface Report {
|
||||
readonly attribute DOMString type;
|
||||
readonly attribute DOMString url;
|
||||
readonly attribute ReportBody? body;
|
||||
};
|
||||
|
||||
[Constructor(ReportingObserverCallback callback, optional ReportingObserverOptions options),
|
||||
Func="mozilla::dom::DOMPrefs::dom_reporting_enabled"]
|
||||
interface ReportingObserver {
|
||||
void observe();
|
||||
void disconnect();
|
||||
ReportList takeRecords();
|
||||
};
|
||||
|
||||
callback ReportingObserverCallback = void (sequence<Report> reports, ReportingObserver observer);
|
||||
|
||||
dictionary ReportingObserverOptions {
|
||||
sequence<DOMString> types;
|
||||
boolean buffered = false;
|
||||
};
|
||||
|
||||
typedef sequence<Report> ReportList;
|
||||
|
||||
[Func="mozilla::dom::DOMPrefs::dom_reporting_enabled"]
|
||||
interface DeprecationReportBody : ReportBody {
|
||||
readonly attribute DOMString id;
|
||||
readonly attribute Date? anticipatedRemoval;
|
||||
readonly attribute DOMString message;
|
||||
readonly attribute DOMString? sourceFile;
|
||||
readonly attribute unsigned long? lineNumber;
|
||||
readonly attribute unsigned long? columnNumber;
|
||||
};
|
||||
|
||||
[Constructor(), Deprecated="DeprecatedTestingInterface",
|
||||
Func="mozilla::dom::DOMPrefs::dom_reporting_testing_enabled",
|
||||
Exposed=(Window,DedicatedWorker)]
|
||||
interface TestingDeprecatedInterface {
|
||||
[Deprecated="DeprecatedTestingMethod"]
|
||||
void deprecatedMethod();
|
||||
|
||||
[Deprecated="DeprecatedTestingAttribute"]
|
||||
readonly attribute boolean deprecatedAttribute;
|
||||
};
|
@ -740,6 +740,7 @@ WEBIDL_FILES = [
|
||||
'PushSubscriptionOptions.webidl',
|
||||
'RadioNodeList.webidl',
|
||||
'Range.webidl',
|
||||
'Reporting.webidl',
|
||||
'Request.webidl',
|
||||
'Response.webidl',
|
||||
'RTCStatsReport.webidl',
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "ScriptLoader.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
@ -26,7 +28,7 @@
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "nsError.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -2124,11 +2126,19 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
MOZ_ASSERT(loadInfo.mMutedErrorFlag.isSome());
|
||||
options.setMutedErrors(loadInfo.mMutedErrorFlag.valueOr(true));
|
||||
|
||||
JS::SourceBufferHolder srcBuf(loadInfo.mScriptTextBuf,
|
||||
loadInfo.mScriptTextLength,
|
||||
JS::SourceBufferHolder::GiveOwnership);
|
||||
loadInfo.mScriptTextBuf = nullptr;
|
||||
loadInfo.mScriptTextLength = 0;
|
||||
// Pass ownership of the data, first to local variables, then to the
|
||||
// UniqueTwoByteChars moved into the |init| function.
|
||||
size_t dataLength = 0;
|
||||
char16_t* data = nullptr;
|
||||
|
||||
std::swap(dataLength, loadInfo.mScriptTextLength);
|
||||
std::swap(data, loadInfo.mScriptTextBuf);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(aCx, JS::UniqueTwoByteChars(data), dataLength)) {
|
||||
mScriptLoader.mRv.StealExceptionFromJSContext(aCx);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Our ErrorResult still shouldn't be a failure.
|
||||
MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/LocaleSensitive.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "MessageEventRunnable.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
@ -4902,12 +4902,15 @@ WorkerPrivate::RunExpiredTimeouts(JSContext* aCx)
|
||||
|
||||
JS::Rooted<JS::Value> unused(aes.cx());
|
||||
|
||||
JS::SourceBufferHolder srcBuf(script.BeginReading(), script.Length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
if (!JS::Evaluate(aes.cx(), options, srcBuf, &unused) &&
|
||||
!JS_IsExceptionPending(aCx)) {
|
||||
retval = false;
|
||||
break;
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(aes.cx(), script.BeginReading(), script.Length(),
|
||||
JS::SourceOwnership::Borrowed) ||
|
||||
!JS::Evaluate(aes.cx(), options, srcBuf, &unused))
|
||||
{
|
||||
if (!JS_IsExceptionPending(aCx)) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ErrorResult rv;
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "mozilla/dom/ScriptLoader.h"
|
||||
#include "mozilla/dom/WorkletImpl.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "nsIInputStreamPump.h"
|
||||
#include "nsIThreadRetargetableRequest.h"
|
||||
#include "nsNetUtil.h"
|
||||
@ -401,10 +401,10 @@ ExecutionRunnable::RunOnWorkletThread()
|
||||
|
||||
JSAutoRealm ar(cx, globalObj);
|
||||
|
||||
JS::SourceBufferHolder buffer(mScriptBuffer.release(), mScriptLength,
|
||||
JS::SourceBufferHolder::GiveOwnership);
|
||||
JS::Rooted<JS::Value> unused(cx);
|
||||
if (!JS::Evaluate(cx, compileOptions, buffer, &unused)) {
|
||||
JS::SourceText<char16_t> buffer;
|
||||
if (!buffer.init(cx, std::move(mScriptBuffer), mScriptLength) ||
|
||||
!JS::Evaluate(cx, compileOptions, buffer, &unused)) {
|
||||
ErrorResult error;
|
||||
error.MightThrowJSException();
|
||||
error.StealExceptionFromJSContext(cx);
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "XULDocument.h"
|
||||
|
||||
#include "nsError.h"
|
||||
@ -89,7 +91,7 @@
|
||||
#include "nsTextNode.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "mozilla/dom/URL.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
@ -1283,22 +1285,19 @@ XULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
mOffThreadCompileStringBuf,
|
||||
mOffThreadCompileStringLength);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Attempt to give ownership of the buffer to the JS engine. If
|
||||
// we hit offthread compilation, however, we will have to take it
|
||||
// back below in order to keep the memory alive until compilation
|
||||
// completes.
|
||||
JS::SourceBufferHolder srcBuf(mOffThreadCompileStringBuf,
|
||||
mOffThreadCompileStringLength,
|
||||
JS::SourceBufferHolder::GiveOwnership);
|
||||
mOffThreadCompileStringBuf = nullptr;
|
||||
mOffThreadCompileStringLength = 0;
|
||||
// Pass ownership of the buffer, carefully emptying the existing
|
||||
// fields in the process. Note that the |Compile| function called
|
||||
// below always takes ownership of the buffer.
|
||||
char16_t* units = nullptr;
|
||||
size_t unitsLength = 0;
|
||||
|
||||
rv = mCurrentScriptProto->Compile(srcBuf, uri, 1, this, this);
|
||||
std::swap(units, mOffThreadCompileStringBuf);
|
||||
std::swap(unitsLength, mOffThreadCompileStringLength);
|
||||
|
||||
rv = mCurrentScriptProto->Compile(units, unitsLength,
|
||||
JS::SourceOwnership::TakeOwnership,
|
||||
uri, 1, this, this);
|
||||
if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->HasScriptObject()) {
|
||||
// We will be notified via OnOffThreadCompileComplete when the
|
||||
// compile finishes. The JS engine has taken ownership of the
|
||||
// source buffer.
|
||||
MOZ_RELEASE_ASSERT(!srcBuf.ownsChars());
|
||||
mOffThreadCompiling = true;
|
||||
BlockOnload();
|
||||
return NS_OK;
|
||||
|
@ -505,9 +505,11 @@ XULContentSinkImpl::HandleEndElement(const char16_t *aName)
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
|
||||
|
||||
script->mOutOfLine = false;
|
||||
if (doc)
|
||||
script->Compile(mText, mTextLength, mDocumentURL,
|
||||
if (doc) {
|
||||
script->Compile(mText, mTextLength,
|
||||
JS::SourceOwnership::Borrowed, mDocumentURL,
|
||||
script->mLineNo, doc);
|
||||
}
|
||||
}
|
||||
|
||||
FlushText(false);
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/DeclarationBlock.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsHTMLStyleSheet.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
@ -2278,7 +2278,9 @@ OffThreadScriptReceiverCallback(JS::OffThreadToken* aToken, void* aCallbackData)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
|
||||
nsXULPrototypeScript::Compile(const char16_t* aText,
|
||||
size_t aTextLength,
|
||||
JS::SourceOwnership aOwnership,
|
||||
nsIURI* aURI, uint32_t aLineNo,
|
||||
nsIDocument* aDocument,
|
||||
nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
|
||||
@ -2286,10 +2288,21 @@ nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
|
||||
// We'll compile the script in the compilation scope.
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(xpc::CompilationScope())) {
|
||||
if (aOwnership == JS::SourceOwnership::TakeOwnership) {
|
||||
// In this early-exit case -- before the |srcBuf.init| call will
|
||||
// own |aText| -- we must relinquish ownership manually.
|
||||
js_free(const_cast<char16_t*>(aText));
|
||||
}
|
||||
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (NS_WARN_IF(!srcBuf.init(cx, aText, aTextLength, aOwnership))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoCString urlspec;
|
||||
nsresult rv = aURI->GetSpec(urlspec);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -2309,9 +2322,8 @@ nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
|
||||
JS::ExposeObjectToActiveJS(scope);
|
||||
}
|
||||
|
||||
if (aOffThreadReceiver && JS::CanCompileOffThread(cx, options, aSrcBuf.length())) {
|
||||
if (!JS::CompileOffThread(cx, options,
|
||||
aSrcBuf,
|
||||
if (aOffThreadReceiver && JS::CanCompileOffThread(cx, options, aTextLength)) {
|
||||
if (!JS::CompileOffThread(cx, options, srcBuf,
|
||||
OffThreadScriptReceiverCallback,
|
||||
static_cast<void*>(aOffThreadReceiver))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@ -2319,26 +2331,13 @@ nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
|
||||
NotifyOffThreadScriptCompletedRunnable::NoteReceiver(aOffThreadReceiver);
|
||||
} else {
|
||||
JS::Rooted<JSScript*> script(cx);
|
||||
if (!JS::Compile(cx, options, aSrcBuf, &script))
|
||||
if (!JS::Compile(cx, options, srcBuf, &script))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
Set(script);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::Compile(const char16_t* aText,
|
||||
int32_t aTextLength,
|
||||
nsIURI* aURI,
|
||||
uint32_t aLineNo,
|
||||
nsIDocument* aDocument,
|
||||
nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
|
||||
{
|
||||
JS::SourceBufferHolder srcBuf(aText, aTextLength,
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
return Compile(srcBuf, aURI, aLineNo, aDocument, aOffThreadReceiver);
|
||||
}
|
||||
|
||||
void
|
||||
nsXULPrototypeScript::UnlinkJSObjects()
|
||||
{
|
||||
|
@ -12,6 +12,7 @@
|
||||
#ifndef nsXULElement_h__
|
||||
#define nsXULElement_h__
|
||||
|
||||
#include "js/SourceText.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIServiceManager.h"
|
||||
@ -52,10 +53,6 @@ enum class CallerType : uint32_t;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
namespace JS {
|
||||
class SourceBufferHolder;
|
||||
} // namespace JS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
|
||||
@ -218,12 +215,8 @@ public:
|
||||
nsresult DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
||||
nsXULPrototypeDocument* aProtoDoc);
|
||||
|
||||
nsresult Compile(JS::SourceBufferHolder& aSrcBuf,
|
||||
nsIURI* aURI, uint32_t aLineNo,
|
||||
nsIDocument* aDocument,
|
||||
nsIOffThreadScriptReceiver *aOffThreadReceiver = nullptr);
|
||||
|
||||
nsresult Compile(const char16_t* aText, int32_t aTextLength,
|
||||
nsresult Compile(const char16_t* aText, size_t aTextLength,
|
||||
JS::SourceOwnership aOwnership,
|
||||
nsIURI* aURI, uint32_t aLineNo,
|
||||
nsIDocument* aDocument,
|
||||
nsIOffThreadScriptReceiver *aOffThreadReceiver = nullptr);
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "jsapi.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
|
||||
#include "xpcpublic.h"
|
||||
|
||||
@ -492,9 +492,14 @@ XPCShellEnvironment::EvaluateString(const nsString& aString,
|
||||
JS::CompileOptions options(cx);
|
||||
options.setFileAndLine("typein", 0);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, aString.get(), aString.Length(),
|
||||
JS::SourceOwnership::Borrowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSScript*> script(cx);
|
||||
JS::SourceBufferHolder srcBuf(aString.get(), aString.Length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
if (!JS::Compile(cx, options, srcBuf, &script))
|
||||
{
|
||||
return false;
|
||||
|
@ -82,6 +82,12 @@ class UTF8Chars : public mozilla::Range<unsigned char>
|
||||
UTF8Chars(const char* aBytes, size_t aLength)
|
||||
: Base(reinterpret_cast<unsigned char*>(const_cast<char*>(aBytes)), aLength)
|
||||
{}
|
||||
UTF8Chars(mozilla::Utf8Unit* aUnits, size_t aLength)
|
||||
: UTF8Chars(reinterpret_cast<char*>(aUnits), aLength)
|
||||
{}
|
||||
UTF8Chars(const mozilla::Utf8Unit* aUnits, size_t aLength)
|
||||
: UTF8Chars(reinterpret_cast<const char*>(aUnits), aLength)
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
@ -108,6 +114,10 @@ class UTF8CharsZ : public mozilla::RangedPtr<unsigned char>
|
||||
MOZ_ASSERT(aBytes[aLength] == '\0');
|
||||
}
|
||||
|
||||
UTF8CharsZ(mozilla::Utf8Unit* aUnits, size_t aLength)
|
||||
: UTF8CharsZ(reinterpret_cast<char*>(aUnits), aLength)
|
||||
{}
|
||||
|
||||
using Base::operator=;
|
||||
|
||||
char* c_str() { return reinterpret_cast<char*>(get()); }
|
||||
|
@ -26,7 +26,7 @@ namespace JS {
|
||||
|
||||
template<typename T> class AutoVector;
|
||||
|
||||
class SourceBufferHolder;
|
||||
template<typename UnitT> class SourceText;
|
||||
|
||||
} // namespace JS
|
||||
|
||||
@ -107,7 +107,7 @@ CloneAndExecuteScript(JSContext* cx, AutoVector<JSObject*>& envChain, Handle<JSS
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, MutableHandle<Value> rval);
|
||||
SourceText<char16_t>& srcBuf, MutableHandle<Value> rval);
|
||||
|
||||
/**
|
||||
* As above, but providing an explicit scope chain. envChain must not include
|
||||
@ -116,7 +116,7 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Evaluate(JSContext* cx, AutoVector<JSObject*>& envChain, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, MutableHandle<Value> rval);
|
||||
SourceText<char16_t>& srcBuf, MutableHandle<Value> rval);
|
||||
|
||||
/**
|
||||
* Evaluate the provided UTF-8 data in the scope of the current global of |cx|,
|
||||
@ -154,7 +154,7 @@ EvaluateUtf8Path(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, MutableHandle<JSScript*> script);
|
||||
SourceText<char16_t>& srcBuf, MutableHandle<JSScript*> script);
|
||||
|
||||
/**
|
||||
* Compile the provided UTF-8 data into a script. If the data contains invalid
|
||||
@ -166,6 +166,20 @@ extern JS_PUBLIC_API(bool)
|
||||
CompileUtf8(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
const char* bytes, size_t length, MutableHandle<JSScript*> script);
|
||||
|
||||
/**
|
||||
* Compile the provided UTF-8 data into a script. If the data contains invalid
|
||||
* UTF-8, an error is reported.
|
||||
*
|
||||
* |script| is always set to the compiled script or to null in case of error.
|
||||
*
|
||||
* NOTE: This function DOES NOT INFLATE the UTF-8 bytes to UTF-16 before
|
||||
* compiling them. UTF-8 compilation is currently experimental and has
|
||||
* known bugs. Use only if you're willing to tolerate unspecified bugs!
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CompileUtf8DontInflate(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
const char* bytes, size_t length, MutableHandle<JSScript*> script);
|
||||
|
||||
/**
|
||||
* Compile the provided Latin-1 data (i.e. each byte directly corresponds to
|
||||
* the same Unicode code point) into a script.
|
||||
@ -189,6 +203,20 @@ extern JS_PUBLIC_API(bool)
|
||||
CompileUtf8File(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
FILE* file, MutableHandle<JSScript*> script);
|
||||
|
||||
/**
|
||||
* Compile the UTF-8 contents of the given file into a script. If the contents
|
||||
* contain any malformed UTF-8, an error is reported.
|
||||
*
|
||||
* |script| is always set to the compiled script or to null in case of error.
|
||||
*
|
||||
* NOTE: This function DOES NOT INFLATE the UTF-8 bytes to UTF-16 before
|
||||
* compiling them. UTF-8 compilation is currently experimental and has
|
||||
* known bugs. Use only if you're willing to tolerate unspecified bugs!
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CompileUtf8FileDontInflate(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
FILE* file, MutableHandle<JSScript*> script);
|
||||
|
||||
/**
|
||||
* Compile the UTF-8 contents of the file at the given path into a script.
|
||||
* (The path itself is in the system encoding, not [necessarily] UTF-8.) If
|
||||
@ -202,7 +230,7 @@ CompileUtf8Path(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, MutableHandle<JSScript*> script);
|
||||
SourceText<char16_t>& srcBuf, MutableHandle<JSScript*> script);
|
||||
|
||||
/**
|
||||
* Compile the given Latin-1 data for non-syntactic scope.
|
||||
@ -227,7 +255,7 @@ extern JS_PUBLIC_API(bool)
|
||||
CompileFunction(JSContext* cx, AutoVector<JSObject*>& envChain,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
const char* name, unsigned nargs, const char* const* argnames,
|
||||
SourceBufferHolder& srcBuf, MutableHandle<JSFunction*> fun);
|
||||
SourceText<char16_t>& srcBuf, MutableHandle<JSFunction*> fun);
|
||||
|
||||
/**
|
||||
* Same as above, but taking UTF-8 encoded const char* for the function body.
|
||||
|
@ -27,7 +27,7 @@ class JSScript;
|
||||
|
||||
namespace JS {
|
||||
|
||||
class SourceBufferHolder;
|
||||
template<typename UnitT> class SourceText;
|
||||
|
||||
} // namespace JS
|
||||
|
||||
@ -61,8 +61,9 @@ CanDecodeOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t
|
||||
*/
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf,
|
||||
OffThreadCompileCallback callback, void* callbackData);
|
||||
CompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceText<char16_t>& srcBuf, OffThreadCompileCallback callback,
|
||||
void* callbackData);
|
||||
|
||||
extern JS_PUBLIC_API(JSScript*)
|
||||
FinishOffThreadScript(JSContext* cx, OffThreadToken* token);
|
||||
@ -72,7 +73,7 @@ CancelOffThreadScript(JSContext* cx, OffThreadToken* token);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, OffThreadCompileCallback callback,
|
||||
SourceText<char16_t>& srcBuf, OffThreadCompileCallback callback,
|
||||
void* callbackData);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
|
@ -1,141 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* SourceBufferHolder groups buffer and length values and provides a way to
|
||||
* optionally pass ownership of the buffer to the JS engine without copying.
|
||||
*
|
||||
* Rules for use:
|
||||
*
|
||||
* 1) The data array must be allocated with js_malloc() or js_realloc() if
|
||||
* ownership is being granted to the SourceBufferHolder.
|
||||
* 2) If ownership is not given to the SourceBufferHolder, then the memory
|
||||
* must be kept alive until the JS compilation is complete.
|
||||
* 3) Any code calling SourceBufferHolder::take() must guarantee to keep the
|
||||
* memory alive until JS compilation completes. Normally only the JS
|
||||
* engine should be calling take().
|
||||
*
|
||||
* Example use:
|
||||
*
|
||||
* size_t length = 512;
|
||||
* char16_t* chars = js_pod_malloc<char16_t>(length);
|
||||
* JS::SourceBufferHolder srcBuf(chars, length, JS::SourceBufferHolder::GiveOwnership);
|
||||
* JS::Compile(cx, options, srcBuf);
|
||||
*/
|
||||
|
||||
#ifndef js_SourceBufferHolder_h
|
||||
#define js_SourceBufferHolder_h
|
||||
|
||||
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#include "js/Utility.h" // JS::UniqueTwoByteChars
|
||||
|
||||
namespace JS {
|
||||
|
||||
class SourceBufferHolder final
|
||||
{
|
||||
private:
|
||||
const char16_t* data_;
|
||||
size_t length_;
|
||||
bool ownsChars_;
|
||||
|
||||
private:
|
||||
void fixEmptyBuffer() {
|
||||
// Ensure that null buffers properly return an unowned, empty,
|
||||
// null-terminated string.
|
||||
static const char16_t NullChar_ = 0;
|
||||
if (!data_) {
|
||||
data_ = &NullChar_;
|
||||
length_ = 0;
|
||||
ownsChars_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
enum Ownership {
|
||||
NoOwnership,
|
||||
GiveOwnership
|
||||
};
|
||||
|
||||
SourceBufferHolder(const char16_t* data, size_t dataLength, Ownership ownership)
|
||||
: data_(data),
|
||||
length_(dataLength),
|
||||
ownsChars_(ownership == GiveOwnership)
|
||||
{
|
||||
fixEmptyBuffer();
|
||||
}
|
||||
|
||||
SourceBufferHolder(UniqueTwoByteChars&& data, size_t dataLength)
|
||||
: data_(data.release()),
|
||||
length_(dataLength),
|
||||
ownsChars_(true)
|
||||
{
|
||||
fixEmptyBuffer();
|
||||
}
|
||||
|
||||
SourceBufferHolder(SourceBufferHolder&& other)
|
||||
: data_(other.data_),
|
||||
length_(other.length_),
|
||||
ownsChars_(other.ownsChars_)
|
||||
{
|
||||
other.data_ = nullptr;
|
||||
other.length_ = 0;
|
||||
other.ownsChars_ = false;
|
||||
}
|
||||
|
||||
~SourceBufferHolder() {
|
||||
if (ownsChars_) {
|
||||
js_free(const_cast<char16_t*>(data_));
|
||||
}
|
||||
}
|
||||
|
||||
/** Access the underlying source buffer without affecting ownership. */
|
||||
const char16_t* get() const {
|
||||
return data_;
|
||||
}
|
||||
|
||||
/** Length of the source buffer in char16_t code units (not bytes). */
|
||||
size_t length() const {
|
||||
return length_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the SourceBufferHolder owns the buffer and will free it
|
||||
* upon destruction. If true, it is legal to call take().
|
||||
*/
|
||||
bool ownsChars() const {
|
||||
return ownsChars_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve and take ownership of the underlying data buffer. The caller
|
||||
* is now responsible for calling js_free() on the returned value, *but
|
||||
* only after JS script compilation has completed*.
|
||||
*
|
||||
* After the buffer has been taken the SourceBufferHolder functions as if
|
||||
* it had been constructed on an unowned buffer; get() and length() still
|
||||
* work. In order for this to be safe the taken buffer must be kept alive
|
||||
* until after JS script compilation completes as noted above.
|
||||
*
|
||||
* It's the caller's responsibility to check ownsChars() before taking the
|
||||
* buffer. Taking and then free'ing an unowned buffer will have dire
|
||||
* consequences.
|
||||
*/
|
||||
char16_t* take() {
|
||||
MOZ_ASSERT(ownsChars_);
|
||||
ownsChars_ = false;
|
||||
return const_cast<char16_t*>(data_);
|
||||
}
|
||||
|
||||
private:
|
||||
SourceBufferHolder(SourceBufferHolder&) = delete;
|
||||
SourceBufferHolder& operator=(SourceBufferHolder&) = delete;
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif /* js_SourceBufferHolder_h */
|
282
js/public/SourceText.h
Normal file
282
js/public/SourceText.h
Normal file
@ -0,0 +1,282 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* SourceText encapsulates a count of char16_t (UTF-16) or Utf8Unit (UTF-8)
|
||||
* code units (note: code *units*, not bytes or code points) and those code
|
||||
* units ("source units"). (Latin-1 is not supported: all places where Latin-1
|
||||
* must be compiled first convert to a supported encoding.)
|
||||
*
|
||||
* A SourceText either observes without owning, or takes ownership of, source
|
||||
* units passed to |SourceText::init|. Thus SourceText can be used to
|
||||
* efficiently avoid copying.
|
||||
*
|
||||
* Rules for use:
|
||||
*
|
||||
* 1) The passed-in source units must be allocated with js_malloc(),
|
||||
* js_calloc(), or js_realloc() if |SourceText::init| is instructed to take
|
||||
* ownership of the source units.
|
||||
* 2) If |SourceText::init| merely borrows the source units, the user must
|
||||
* keep them alive until associated JS compilation is complete.
|
||||
* 3) Code that calls |SourceText::take{Chars,Units}()| must keep the source
|
||||
* units alive until JS compilation completes. Normally only the JS engine
|
||||
* should call |SourceText::take{Chars,Units}()|.
|
||||
* 4) Use the appropriate SourceText parameterization depending on the source
|
||||
* units encoding.
|
||||
*
|
||||
* Example use:
|
||||
*
|
||||
* size_t length = 512;
|
||||
* char16_t* chars = js_pod_malloc<char16_t>(length);
|
||||
* if (!chars) {
|
||||
* JS_ReportOutOfMemory(cx);
|
||||
* return false;
|
||||
* }
|
||||
* JS::SourceText<char16_t> srcBuf;
|
||||
* if (!srcBuf.init(cx, chars, length, JS::SourceOwnership::TakeOwnership)) {
|
||||
* return false;
|
||||
* }
|
||||
* JS::Rooted<JSScript*> script(cx);
|
||||
* if (!JS::Compile(cx, options, srcBuf, &script)) {
|
||||
* return false;
|
||||
* }
|
||||
*/
|
||||
|
||||
#ifndef js_SourceText_h
|
||||
#define js_SourceText_h
|
||||
|
||||
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
||||
#include "mozilla/Attributes.h" // MOZ_COLD, MOZ_IS_CLASS_INIT, MOZ_MUST_USE
|
||||
#include "mozilla/Likely.h" // MOZ_UNLIKELY
|
||||
#include "mozilla/Utf8.h" // mozilla::Utf8Unit
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h> // UINT32_MAX
|
||||
#include <type_traits> // std::conditional, std::is_same
|
||||
|
||||
#include "js/UniquePtr.h" // js::UniquePtr
|
||||
#include "js/Utility.h" // JS::FreePolicy
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
MOZ_COLD extern JS_PUBLIC_API(void)
|
||||
ReportSourceTooLong(JSContext* cx);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
enum class SourceOwnership
|
||||
{
|
||||
Borrowed,
|
||||
TakeOwnership,
|
||||
};
|
||||
|
||||
template<typename Unit>
|
||||
class SourceText final
|
||||
{
|
||||
private:
|
||||
static_assert(std::is_same<Unit, mozilla::Utf8Unit>::value ||
|
||||
std::is_same<Unit, char16_t>::value,
|
||||
"Unit must be either char16_t or Utf8Unit for "
|
||||
"SourceText<Unit>");
|
||||
|
||||
/** |char16_t| or |Utf8Unit| source units of uncertain validity. */
|
||||
const Unit* units_ = nullptr;
|
||||
|
||||
/** The length in code units of |units_|. */
|
||||
uint32_t length_ = 0;
|
||||
|
||||
/**
|
||||
* Whether this owns |units_| or merely observes source units owned by some
|
||||
* other object.
|
||||
*/
|
||||
bool ownsUnits_ = false;
|
||||
|
||||
public:
|
||||
// A C++ character type that can represent the source units -- suitable for
|
||||
// passing to C++ string functions.
|
||||
using CharT =
|
||||
typename std::conditional<std::is_same<Unit, char16_t>::value,
|
||||
char16_t,
|
||||
char>::type;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a SourceText. It must be initialized using |init()| before it
|
||||
* can be used as compilation source text.
|
||||
*/
|
||||
SourceText() = default;
|
||||
|
||||
/**
|
||||
* Construct a SourceText from contents extracted from |other|. This
|
||||
* SourceText will then act exactly as |other| would have acted, had it
|
||||
* not been passed to this function. |other| will return to its default-
|
||||
* constructed state and must have |init()| called on it to use it.
|
||||
*/
|
||||
SourceText(SourceText&& other)
|
||||
: units_(other.units_),
|
||||
length_(other.length_),
|
||||
ownsUnits_(other.ownsUnits_)
|
||||
{
|
||||
other.units_ = nullptr;
|
||||
other.length_ = 0;
|
||||
other.ownsUnits_ = false;
|
||||
}
|
||||
|
||||
~SourceText() {
|
||||
if (ownsUnits_) {
|
||||
js_free(const_cast<Unit*>(units_));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this with source unit data: |char16_t| for UTF-16 source
|
||||
* units, or |Utf8Unit| for UTF-8 source units.
|
||||
*
|
||||
* If |ownership == TakeOwnership|, *this function* takes ownership of
|
||||
* |units|, *even if* this function fails, and you MUST NOT free |units|
|
||||
* yourself. This single-owner-friendly approach reduces risk of leaks on
|
||||
* failure.
|
||||
*
|
||||
* |units| may be null if |unitsLength == 0|; if so, this will silently be
|
||||
* initialized using non-null, unowned units.
|
||||
*/
|
||||
MOZ_IS_CLASS_INIT MOZ_MUST_USE bool
|
||||
init(JSContext* cx, const Unit* units, size_t unitsLength, SourceOwnership ownership) {
|
||||
MOZ_ASSERT_IF(units == nullptr, unitsLength == 0);
|
||||
|
||||
// Ideally we'd use |Unit| and not cast below, but the risk of a static
|
||||
// initializer is too great.
|
||||
static const CharT emptyString[] = { '\0' };
|
||||
|
||||
// Initialize all fields *before* checking length. This ensures that
|
||||
// if |ownership == SourceOwnership::TakeOwnership|, |units| will be
|
||||
// freed when |this|'s destructor is called.
|
||||
if (units) {
|
||||
units_ = units;
|
||||
length_ = static_cast<uint32_t>(unitsLength);
|
||||
ownsUnits_ = ownership == SourceOwnership::TakeOwnership;
|
||||
} else {
|
||||
units_ = reinterpret_cast<const Unit*>(emptyString);
|
||||
length_ = 0;
|
||||
ownsUnits_ = false;
|
||||
}
|
||||
|
||||
// IMPLEMENTATION DETAIL, DO NOT RELY ON: This limit is used so we can
|
||||
// store offsets in |JSScript|s as |uint32_t|. It could be lifted
|
||||
// fairly easily if desired, as the compiler uses |size_t| internally.
|
||||
if (MOZ_UNLIKELY(unitsLength > UINT32_MAX)) {
|
||||
detail::ReportSourceTooLong(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exactly identical to the |init()| overload above that accepts
|
||||
* |const Unit*|, but instead takes character data: |const CharT*|.
|
||||
*
|
||||
* (We can't just write this to accept |const CharT*|, because then in the
|
||||
* UTF-16 case this overload and the one above would be identical. So we
|
||||
* use SFINAE to expose the |CharT| overload only if it's different.)
|
||||
*/
|
||||
template<typename Char,
|
||||
typename =
|
||||
typename std::enable_if<std::is_same<Char, CharT>::value &&
|
||||
!std::is_same<Char, Unit>::value>::type>
|
||||
MOZ_IS_CLASS_INIT MOZ_MUST_USE bool
|
||||
init(JSContext* cx, const Char* chars, size_t charsLength, SourceOwnership ownership) {
|
||||
return init(cx, reinterpret_cast<const Unit*>(chars), charsLength, ownership);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this using source units transferred out of |data|.
|
||||
*/
|
||||
MOZ_MUST_USE bool init(JSContext* cx,
|
||||
js::UniquePtr<CharT[], JS::FreePolicy> data,
|
||||
size_t dataLength)
|
||||
{
|
||||
return init(cx, data.release(), dataLength, SourceOwnership::TakeOwnership);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the encapsulated data using a code unit type.
|
||||
*
|
||||
* This function is useful for code that wants to interact with source text
|
||||
* as *code units*, not as string data. This doesn't matter for UTF-16,
|
||||
* but it's a crucial distinction for UTF-8. When UTF-8 source text is
|
||||
* encapsulated, |Unit| being |mozilla::Utf8Unit| unambiguously indicates
|
||||
* that the code units are UTF-8. In contrast |const char*| returned by
|
||||
* |get()| below could hold UTF-8 (or its ASCII subset) or Latin-1 or (in
|
||||
* particularly cursed embeddings) EBCDIC or some other legacy character
|
||||
* set. Prefer this function to |get()| wherever possible.
|
||||
*/
|
||||
const Unit* units() const { return units_; }
|
||||
|
||||
/**
|
||||
* Access the encapsulated data using a character type.
|
||||
*
|
||||
* This function is useful for interactions with character-centric actions
|
||||
* like interacting with UniqueChars/UniqueTwoByteChars or printing out
|
||||
* text in a debugger, that only work with |CharT|. But as |CharT| loses
|
||||
* encoding specificity when UTF-8 source text is encapsulated, prefer
|
||||
* |units()| to this function.
|
||||
*/
|
||||
const CharT* get() const { return reinterpret_cast<const CharT*>(units_); }
|
||||
|
||||
/**
|
||||
* Returns true if this owns the source units and will free them on
|
||||
* destruction. If true, it is legal to call |take{Chars,Units}()|.
|
||||
*/
|
||||
bool ownsUnits() const {
|
||||
return ownsUnits_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count of the underlying source units -- code units, not bytes or code
|
||||
* points -- in this.
|
||||
*/
|
||||
uint32_t length() const {
|
||||
return length_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve and take ownership of the underlying source units. The caller
|
||||
* is now responsible for calling js_free() on the returned value, *but
|
||||
* only after JS script compilation has completed*.
|
||||
*
|
||||
* After underlying source units have been taken, this will continue to
|
||||
* refer to the same data -- it just won't own the data. get() and
|
||||
* length() will return the same values, but ownsUnits() will be false.
|
||||
* The taken source units must be kept alive until after JS script
|
||||
* compilation completes, as noted above, for this to be safe.
|
||||
*
|
||||
* The caller must check ownsUnits() before calling takeUnits(). Taking
|
||||
* and then free'ing an unowned buffer will have dire consequences.
|
||||
*/
|
||||
Unit* takeUnits() {
|
||||
MOZ_ASSERT(ownsUnits_);
|
||||
ownsUnits_ = false;
|
||||
return const_cast<Unit*>(units_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Akin to |takeUnits()| in all respects, but returns characters rather
|
||||
* than units.
|
||||
*/
|
||||
CharT* takeChars() {
|
||||
return reinterpret_cast<CharT*>(takeUnits());
|
||||
}
|
||||
|
||||
private:
|
||||
SourceText(const SourceText&) = delete;
|
||||
void operator=(const SourceText&) = delete;
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif /* js_SourceText_h */
|
@ -227,7 +227,7 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
|
||||
"JS::ServoSizes",
|
||||
"js::shadow::Object",
|
||||
"js::shadow::ObjectGroup",
|
||||
"JS::SourceBufferHolder",
|
||||
"JS::SourceText",
|
||||
"js::StackFormat",
|
||||
"JSStructuredCloneCallbacks",
|
||||
"JS::Symbol",
|
||||
|
@ -18,7 +18,7 @@ typedef uint32_t HashNumber;
|
||||
#include "js/Conversions.h"
|
||||
#include "js/Initialization.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
// Replacements for types that are too difficult for rust-bindgen.
|
||||
|
@ -232,10 +232,11 @@ impl Runtime {
|
||||
let _ar = AutoRealm::with_obj(self.cx(), glob.get());
|
||||
let options = CompileOptionsWrapper::new(self.cx(), filename_cstr.as_ptr(), line_num);
|
||||
|
||||
let mut srcBuf = JS::SourceBufferHolder {
|
||||
data_: ptr,
|
||||
let mut srcBuf = JS::SourceText {
|
||||
units_: ptr,
|
||||
length_: len as _,
|
||||
ownsChars_: false
|
||||
ownsUnits_: false,
|
||||
_phantom_0: marker::PhantomData
|
||||
};
|
||||
if !JS::Evaluate(self.cx(), options.ptr, &mut srcBuf, rval) {
|
||||
debug!("...err!");
|
||||
|
@ -38,7 +38,7 @@ using ValueVector = JS::GCVector<JS::Value>;
|
||||
using IdVector = JS::GCVector<jsid>;
|
||||
using ScriptVector = JS::GCVector<JSScript*>;
|
||||
|
||||
class SourceBufferHolder;
|
||||
template<typename UnitT> class SourceText;
|
||||
|
||||
class HandleValueArray;
|
||||
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/Range.h"
|
||||
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "frontend/BytecodeCompilation.h"
|
||||
#include "gc/HashUtil.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
@ -29,7 +29,8 @@ using mozilla::RangedPtr;
|
||||
using JS::AutoCheckCannotGC;
|
||||
using JS::AutoStableStringChars;
|
||||
using JS::CompileOptions;
|
||||
using JS::SourceBufferHolder;
|
||||
using JS::SourceOwnership;
|
||||
using JS::SourceText;
|
||||
|
||||
// We should be able to assert this for *any* fp->environmentChain().
|
||||
static void
|
||||
@ -317,12 +318,18 @@ EvalKernel(JSContext* cx, HandleValue v, EvalType evalType, AbstractFramePtr cal
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceText<char16_t> srcBuf;
|
||||
|
||||
const char16_t* chars = linearChars.twoByteRange().begin().get();
|
||||
SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller()
|
||||
? SourceBufferHolder::GiveOwnership
|
||||
: SourceBufferHolder::NoOwnership;
|
||||
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
|
||||
JSScript* compiled = frontend::CompileEvalScript(cx, env, enclosing, options, srcBuf);
|
||||
SourceOwnership ownership = linearChars.maybeGiveOwnershipToCaller()
|
||||
? SourceOwnership::TakeOwnership
|
||||
: SourceOwnership::Borrowed;
|
||||
if (!srcBuf.init(cx, chars, linearStr->length(), ownership)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
frontend::EvalScriptInfo info(cx, options, env, enclosing);
|
||||
JSScript* compiled = frontend::CompileEvalScript(info, srcBuf);
|
||||
if (!compiled) {
|
||||
return false;
|
||||
}
|
||||
@ -401,12 +408,18 @@ js::DirectEvalStringFromIon(JSContext* cx,
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceText<char16_t> srcBuf;
|
||||
|
||||
const char16_t* chars = linearChars.twoByteRange().begin().get();
|
||||
SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller()
|
||||
? SourceBufferHolder::GiveOwnership
|
||||
: SourceBufferHolder::NoOwnership;
|
||||
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
|
||||
JSScript* compiled = frontend::CompileEvalScript(cx, env, enclosing, options, srcBuf);
|
||||
SourceOwnership ownership = linearChars.maybeGiveOwnershipToCaller()
|
||||
? SourceOwnership::TakeOwnership
|
||||
: SourceOwnership::Borrowed;
|
||||
if (!srcBuf.init(cx, chars, linearStr->length(), ownership)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
frontend::EvalScriptInfo info(cx, options, env, enclosing);
|
||||
JSScript* compiled = frontend::CompileEvalScript(info, srcBuf);
|
||||
if (!compiled) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1287,10 +1287,10 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global)
|
||||
// ModuleBuilder
|
||||
|
||||
ModuleBuilder::ModuleBuilder(JSContext* cx, HandleModuleObject module,
|
||||
const frontend::TokenStreamAnyChars& tokenStream)
|
||||
const frontend::EitherParser& eitherParser)
|
||||
: cx_(cx),
|
||||
module_(cx, module),
|
||||
tokenStream_(tokenStream),
|
||||
eitherParser_(eitherParser),
|
||||
requestedModuleSpecifiers_(cx, AtomSet(cx)),
|
||||
requestedModules_(cx, RequestedModuleVector(cx)),
|
||||
importEntries_(cx, ImportEntryMap(cx)),
|
||||
@ -1418,7 +1418,7 @@ ModuleBuilder::processImport(frontend::BinaryNode* importNode)
|
||||
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
tokenStream_.lineAndColumnAt(importNameNode->pn_pos.begin, &line, &column);
|
||||
eitherParser_.computeLineAndColumn(importNameNode->pn_pos.begin, &line, &column);
|
||||
|
||||
RootedImportEntryObject importEntry(cx_);
|
||||
importEntry = ImportEntryObject::create(cx_, module, importName, localName, line, column);
|
||||
@ -1686,7 +1686,7 @@ ModuleBuilder::appendExportEntry(HandleAtom exportName, HandleAtom localName,
|
||||
uint32_t line = 0;
|
||||
uint32_t column = 0;
|
||||
if (node) {
|
||||
tokenStream_.lineAndColumnAt(node->pn_pos.begin, &line, &column);
|
||||
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
||||
}
|
||||
|
||||
Rooted<ExportEntryObject*> exportEntry(cx_);
|
||||
@ -1701,7 +1701,7 @@ ModuleBuilder::appendExportFromEntry(HandleAtom exportName, HandleAtom moduleReq
|
||||
{
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
tokenStream_.lineAndColumnAt(node->pn_pos.begin, &line, &column);
|
||||
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
||||
|
||||
Rooted<ExportEntryObject*> exportEntry(cx_);
|
||||
exportEntry = ExportEntryObject::create(cx_, exportName, moduleRequest, importName, nullptr,
|
||||
@ -1729,7 +1729,7 @@ ModuleBuilder::maybeAppendRequestedModule(HandleAtom specifier, frontend::ParseN
|
||||
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
tokenStream_.lineAndColumnAt(node->pn_pos.begin, &line, &column);
|
||||
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
||||
|
||||
JSContext* cx = cx_;
|
||||
RootedRequestedModuleObject req(cx, RequestedModuleObject::create(cx, specifier, line, column));
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "builtin/SelfHostingDefines.h"
|
||||
#include "frontend/EitherParser.h"
|
||||
#include "gc/Zone.h"
|
||||
#include "js/GCVector.h"
|
||||
#include "js/Id.h"
|
||||
@ -29,7 +30,6 @@ namespace frontend {
|
||||
class BinaryNode;
|
||||
class ListNode;
|
||||
class ParseNode;
|
||||
class TokenStreamAnyChars;
|
||||
} /* namespace frontend */
|
||||
|
||||
typedef Rooted<ModuleObject*> RootedModuleObject;
|
||||
@ -355,9 +355,14 @@ class ModuleObject : public NativeObject
|
||||
// creating a ModuleObject.
|
||||
class MOZ_STACK_CLASS ModuleBuilder
|
||||
{
|
||||
public:
|
||||
explicit ModuleBuilder(JSContext* cx, HandleModuleObject module,
|
||||
const frontend::TokenStreamAnyChars& tokenStream);
|
||||
const frontend::EitherParser& eitherParser);
|
||||
|
||||
public:
|
||||
template<class Parser>
|
||||
explicit ModuleBuilder(JSContext* cx, HandleModuleObject module, Parser* parser)
|
||||
: ModuleBuilder(cx, module, frontend::EitherParser(parser))
|
||||
{}
|
||||
|
||||
bool processImport(frontend::BinaryNode* importNode);
|
||||
bool processExport(frontend::ParseNode* exportNode);
|
||||
@ -384,7 +389,7 @@ class MOZ_STACK_CLASS ModuleBuilder
|
||||
|
||||
JSContext* cx_;
|
||||
RootedModuleObject module_;
|
||||
const frontend::TokenStreamAnyChars& tokenStream_;
|
||||
frontend::EitherParser eitherParser_;
|
||||
RootedAtomSet requestedModuleSpecifiers_;
|
||||
RootedRequestedModuleVector requestedModules_;
|
||||
RootedImportEntryMap importEntries_;
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
#include "builtin/Array.h"
|
||||
#include "builtin/Reflect.h"
|
||||
#include "frontend/ModuleSharedContext.h"
|
||||
#include "frontend/ParseNode.h"
|
||||
#include "frontend/Parser.h"
|
||||
#include "frontend/TokenStream.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#include "vm/JSAtom.h"
|
||||
@ -238,7 +238,7 @@ class NodeBuilder
|
||||
typedef AutoValueArray<AST_LIMIT> CallbackArray;
|
||||
|
||||
JSContext* cx;
|
||||
TokenStreamAnyChars* tokenStream;
|
||||
frontend::Parser<frontend::FullParseHandler, char16_t>* parser;
|
||||
bool saveLoc; /* save source location information? */
|
||||
char const* src; /* source filename or null */
|
||||
RootedValue srcval; /* source filename JS value or null */
|
||||
@ -247,8 +247,13 @@ class NodeBuilder
|
||||
|
||||
public:
|
||||
NodeBuilder(JSContext* c, bool l, char const* s)
|
||||
: cx(c), tokenStream(nullptr), saveLoc(l), src(s), srcval(c), callbacks(cx),
|
||||
userv(c)
|
||||
: cx(c),
|
||||
parser(nullptr),
|
||||
saveLoc(l),
|
||||
src(s),
|
||||
srcval(c),
|
||||
callbacks(cx),
|
||||
userv(c)
|
||||
{}
|
||||
|
||||
MOZ_MUST_USE bool init(HandleObject userobj = nullptr) {
|
||||
@ -299,8 +304,8 @@ class NodeBuilder
|
||||
return true;
|
||||
}
|
||||
|
||||
void setTokenStream(TokenStreamAnyChars* ts) {
|
||||
tokenStream = ts;
|
||||
void setParser(frontend::Parser<frontend::FullParseHandler, char16_t>* p) {
|
||||
parser = p;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -706,8 +711,8 @@ NodeBuilder::newNodeLoc(TokenPos* pos, MutableHandleValue dst)
|
||||
|
||||
uint32_t startLineNum, startColumnIndex;
|
||||
uint32_t endLineNum, endColumnIndex;
|
||||
tokenStream->srcCoords.lineNumAndColumnIndex(pos->begin, &startLineNum, &startColumnIndex);
|
||||
tokenStream->srcCoords.lineNumAndColumnIndex(pos->end, &endLineNum, &endColumnIndex);
|
||||
parser->anyChars.srcCoords.lineNumAndColumnIndex(pos->begin, &startLineNum, &startColumnIndex);
|
||||
parser->anyChars.srcCoords.lineNumAndColumnIndex(pos->end, &endLineNum, &endColumnIndex);
|
||||
|
||||
if (!newObject(&to)) {
|
||||
return false;
|
||||
@ -1833,9 +1838,9 @@ class ASTSerializer
|
||||
return builder.init(userobj);
|
||||
}
|
||||
|
||||
void setParser(Parser<FullParseHandler, char16_t>* p) {
|
||||
void setParser(frontend::Parser<frontend::FullParseHandler, char16_t>* p) {
|
||||
parser = p;
|
||||
builder.setTokenStream(&p->anyChars);
|
||||
builder.setParser(p);
|
||||
}
|
||||
|
||||
bool program(ListNode* node, MutableHandleValue dst);
|
||||
@ -2017,7 +2022,12 @@ ASTSerializer::blockStatement(ListNode* node, MutableHandleValue dst)
|
||||
bool
|
||||
ASTSerializer::program(ListNode* node, MutableHandleValue dst)
|
||||
{
|
||||
MOZ_ASSERT(parser->anyChars.srcCoords.lineNum(node->pn_pos.begin) == lineno);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
const auto& srcCoords = parser->anyChars.srcCoords;
|
||||
MOZ_ASSERT(srcCoords.lineNum(node->pn_pos.begin) == lineno);
|
||||
}
|
||||
#endif
|
||||
|
||||
NodeVector stmts(cx);
|
||||
return statements(node, stmts) &&
|
||||
@ -3818,7 +3828,7 @@ reflect_parse(JSContext* cx, uint32_t argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
ModuleBuilder builder(cx, module, parser.anyChars);
|
||||
ModuleBuilder builder(cx, module, &parser);
|
||||
|
||||
ModuleSharedContext modulesc(cx, module, &cx->global()->emptyGlobalScope(), builder);
|
||||
pn = parser.moduleBody(&modulesc);
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include "js/Debug.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/LocaleSensitive.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "js/UbiNode.h"
|
||||
@ -93,7 +93,8 @@ using mozilla::Maybe;
|
||||
|
||||
using JS::AutoStableStringChars;
|
||||
using JS::CompileOptions;
|
||||
using JS::SourceBufferHolder;
|
||||
using JS::SourceOwnership;
|
||||
using JS::SourceText;
|
||||
|
||||
// If fuzzingSafe is set, remove functionality that could cause problems with
|
||||
// fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
|
||||
@ -4033,7 +4034,11 @@ EvalReturningScope(JSContext* cx, unsigned argc, Value* vp)
|
||||
options.setFileAndLine(filename.get(), lineno);
|
||||
options.setNoScriptRval(true);
|
||||
|
||||
JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, src, srclen, SourceOwnership::Borrowed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedScript script(cx);
|
||||
if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) {
|
||||
return false;
|
||||
@ -4134,7 +4139,11 @@ ShellCloneAndExecuteScript(JSContext* cx, unsigned argc, Value* vp)
|
||||
options.setFileAndLine(filename.get(), lineno);
|
||||
options.setNoScriptRval(true);
|
||||
|
||||
JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, src, srclen, SourceOwnership::Borrowed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedScript script(cx);
|
||||
if (!JS::Compile(cx, options, srcBuf, &script)) {
|
||||
return false;
|
||||
@ -5558,9 +5567,13 @@ js::TestingFunctionArgumentToScript(JSContext* cx,
|
||||
}
|
||||
const char16_t* chars = linearChars.twoByteRange().begin().get();
|
||||
|
||||
SourceText<char16_t> source;
|
||||
if (!source.init(cx, chars, len, SourceOwnership::Borrowed)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedScript script(cx);
|
||||
CompileOptions options(cx);
|
||||
SourceBufferHolder source(chars, len, SourceBufferHolder::NoOwnership);
|
||||
if (!JS::Compile(cx, options, source, &script)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
189
js/src/frontend/BytecodeCompilation.h
Normal file
189
js/src/frontend/BytecodeCompilation.h
Normal file
@ -0,0 +1,189 @@
|
||||
/* -*- 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 frontend_BytecodeCompilation_h
|
||||
#define frontend_BytecodeCompilation_h
|
||||
|
||||
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
||||
#include "mozilla/Attributes.h" // MOZ_MUST_USE, MOZ_STACK_CLASS
|
||||
#include "mozilla/Maybe.h" // mozilla::Maybe, mozilla::Nothing
|
||||
#include "mozilla/Utf8.h" // mozilla::Utf8Unit
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include "frontend/EitherParser.h" // js::frontend::EitherParser
|
||||
#include "frontend/ParseContext.h" // js::frontend::UsedNameTracker
|
||||
#include "frontend/SharedContext.h" // js::frontend::Directives, js::frontend::{,Eval,Global}SharedContext
|
||||
#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions
|
||||
#include "js/RootingAPI.h" // JS::{,Mutable}Handle, JS::Rooted
|
||||
#include "js/SourceText.h" // JS::SourceText
|
||||
#include "vm/JSContext.h" // js::AutoKeepAtoms
|
||||
#include "vm/JSScript.h" // js::{FunctionAsync,Generator}Kind, js::LazyScript, JSScript, js::ScriptSource, js::ScriptSourceObject
|
||||
#include "vm/Scope.h" // js::ScopeKind
|
||||
|
||||
class JSFunction;
|
||||
class JSObject;
|
||||
|
||||
namespace js {
|
||||
|
||||
namespace frontend {
|
||||
|
||||
template<typename Unit> class SourceAwareCompiler;
|
||||
template<typename Unit> class ScriptCompiler;
|
||||
template<typename Unit> class ModuleCompiler;
|
||||
template<typename Unit> class StandaloneFunctionCompiler;
|
||||
|
||||
// The BytecodeCompiler class contains resources common to compiling scripts and
|
||||
// function bodies.
|
||||
class MOZ_STACK_CLASS BytecodeCompiler
|
||||
{
|
||||
protected:
|
||||
AutoKeepAtoms keepAtoms;
|
||||
|
||||
JSContext* cx;
|
||||
const JS::ReadOnlyCompileOptions& options;
|
||||
|
||||
JS::Rooted<ScriptSourceObject*> sourceObject;
|
||||
ScriptSource* scriptSource = nullptr;
|
||||
|
||||
mozilla::Maybe<UsedNameTracker> usedNames;
|
||||
|
||||
Directives directives;
|
||||
|
||||
JS::Rooted<JSScript*> script;
|
||||
|
||||
protected:
|
||||
BytecodeCompiler(JSContext* cx, const JS::ReadOnlyCompileOptions& options);
|
||||
|
||||
template<typename Unit> friend class SourceAwareCompiler;
|
||||
template<typename Unit> friend class ScriptCompiler;
|
||||
template<typename Unit> friend class ModuleCompiler;
|
||||
template<typename Unit> friend class StandaloneFunctionCompiler;
|
||||
|
||||
public:
|
||||
JSContext* context() const {
|
||||
return cx;
|
||||
}
|
||||
|
||||
ScriptSourceObject* sourceObjectPtr() const {
|
||||
return sourceObject.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
void assertSourceCreated() const {
|
||||
MOZ_ASSERT(sourceObject != nullptr);
|
||||
MOZ_ASSERT(scriptSource != nullptr);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool createScriptSource(const mozilla::Maybe<uint32_t>& parameterListEnd);
|
||||
|
||||
void createUsedNames() {
|
||||
usedNames.emplace(cx);
|
||||
}
|
||||
|
||||
// Create a script for source of the given length, using the explicitly-
|
||||
// provided toString offsets as the created script's offsets in the source.
|
||||
MOZ_MUST_USE bool internalCreateScript(uint32_t toStringStart, uint32_t toStringEnd,
|
||||
uint32_t sourceBufferLength);
|
||||
|
||||
MOZ_MUST_USE bool emplaceEmitter(mozilla::Maybe<BytecodeEmitter>& emitter,
|
||||
const EitherParser& parser, SharedContext* sharedContext);
|
||||
|
||||
// This function lives here, not in SourceAwareCompiler, because it mostly
|
||||
// uses fields in *this* class.
|
||||
template<typename Unit>
|
||||
MOZ_MUST_USE bool assignSource(JS::SourceText<Unit>& sourceBuffer);
|
||||
|
||||
bool canLazilyParse() const;
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
deoptimizeArgumentsInEnclosingScripts(JSContext* cx, JS::Handle<JSObject*> environment);
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS GlobalScriptInfo final
|
||||
: public BytecodeCompiler
|
||||
{
|
||||
GlobalSharedContext globalsc_;
|
||||
|
||||
public:
|
||||
GlobalScriptInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options, ScopeKind scopeKind)
|
||||
: BytecodeCompiler(cx, options),
|
||||
globalsc_(cx, scopeKind, directives, options.extraWarningsOption)
|
||||
{
|
||||
MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
|
||||
}
|
||||
|
||||
GlobalSharedContext* sharedContext() {
|
||||
return &globalsc_;
|
||||
}
|
||||
};
|
||||
|
||||
extern JSScript*
|
||||
CompileGlobalScript(GlobalScriptInfo& info, JS::SourceText<char16_t>& srcBuf,
|
||||
ScriptSourceObject** sourceObjectOut = nullptr);
|
||||
|
||||
extern JSScript*
|
||||
CompileGlobalScript(GlobalScriptInfo& info, JS::SourceText<mozilla::Utf8Unit>& srcBuf,
|
||||
ScriptSourceObject** sourceObjectOut = nullptr);
|
||||
|
||||
class MOZ_STACK_CLASS EvalScriptInfo final
|
||||
: public BytecodeCompiler
|
||||
{
|
||||
JS::Handle<JSObject*> environment_;
|
||||
EvalSharedContext evalsc_;
|
||||
|
||||
public:
|
||||
EvalScriptInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
|
||||
JS::Handle<JSObject*> environment, JS::Handle<Scope*> enclosingScope)
|
||||
: BytecodeCompiler(cx, options),
|
||||
environment_(environment),
|
||||
evalsc_(cx, environment_, enclosingScope, directives, options.extraWarningsOption)
|
||||
{}
|
||||
|
||||
HandleObject environment() {
|
||||
return environment_;
|
||||
}
|
||||
|
||||
EvalSharedContext* sharedContext() {
|
||||
return &evalsc_;
|
||||
}
|
||||
};
|
||||
|
||||
extern JSScript*
|
||||
CompileEvalScript(EvalScriptInfo& info, JS::SourceText<char16_t>& srcBuf);
|
||||
|
||||
class MOZ_STACK_CLASS ModuleInfo final
|
||||
: public BytecodeCompiler
|
||||
{
|
||||
public:
|
||||
ModuleInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
|
||||
: BytecodeCompiler(cx, options)
|
||||
{}
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS StandaloneFunctionInfo final
|
||||
: public BytecodeCompiler
|
||||
{
|
||||
public:
|
||||
StandaloneFunctionInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
|
||||
: BytecodeCompiler(cx, options)
|
||||
{}
|
||||
};
|
||||
|
||||
extern MOZ_MUST_USE bool
|
||||
CompileLazyFunction(JSContext* cx, JS::Handle<LazyScript*> lazy,
|
||||
const char16_t* units, size_t length);
|
||||
|
||||
extern MOZ_MUST_USE bool
|
||||
CompileLazyFunction(JSContext* cx, JS::Handle<LazyScript*> lazy,
|
||||
const mozilla::Utf8Unit* units, size_t length);
|
||||
|
||||
} // namespace frontend
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // frontend_BytecodeCompilation_h
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "js/CompileOptions.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "vm/Scope.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
@ -29,12 +30,6 @@ class ErrorReporter;
|
||||
class FunctionBox;
|
||||
class ParseNode;
|
||||
|
||||
JSScript*
|
||||
CompileGlobalScript(JSContext* cx, ScopeKind scopeKind,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
ScriptSourceObject** sourceObjectOut = nullptr);
|
||||
|
||||
#if defined(JS_BUILD_BINAST)
|
||||
|
||||
JSScript*
|
||||
@ -48,25 +43,15 @@ CompileLazyBinASTFunction(JSContext* cx, Handle<LazyScript*> lazy, const uint8_t
|
||||
|
||||
#endif // JS_BUILD_BINAST
|
||||
|
||||
JSScript*
|
||||
CompileEvalScript(JSContext* cx, HandleObject environment,
|
||||
HandleScope enclosingScope,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
ScriptSourceObject** sourceObjectOut = nullptr);
|
||||
ModuleObject*
|
||||
CompileModule(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceText<char16_t>& srcBuf);
|
||||
|
||||
ModuleObject*
|
||||
CompileModule(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf);
|
||||
|
||||
ModuleObject*
|
||||
CompileModule(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
JS::SourceText<char16_t>& srcBuf,
|
||||
ScriptSourceObject** sourceObjectOut);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
|
||||
|
||||
//
|
||||
// Compile a single function. The source in srcBuf must match the ECMA-262
|
||||
// FunctionExpression production.
|
||||
@ -82,26 +67,26 @@ CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* cha
|
||||
MOZ_MUST_USE bool
|
||||
CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
JS::SourceText<char16_t>& srcBuf,
|
||||
const mozilla::Maybe<uint32_t>& parameterListEnd,
|
||||
HandleScope enclosingScope = nullptr);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
JS::SourceText<char16_t>& srcBuf,
|
||||
const mozilla::Maybe<uint32_t>& parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
JS::SourceText<char16_t>& srcBuf,
|
||||
const mozilla::Maybe<uint32_t>& parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
JS::SourceText<char16_t>& srcBuf,
|
||||
const mozilla::Maybe<uint32_t>& parameterListEnd);
|
||||
|
||||
ScriptSourceObject*
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "frontend/ForOfEmitter.h"
|
||||
#include "frontend/ForOfLoopControl.h"
|
||||
#include "frontend/IfEmitter.h"
|
||||
#include "frontend/ModuleSharedContext.h"
|
||||
#include "frontend/NameOpEmitter.h"
|
||||
#include "frontend/ParseNode.h"
|
||||
#include "frontend/Parser.h"
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Tuple.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Utf8.h"
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
#include <utility>
|
||||
@ -99,11 +100,19 @@ struct ParserNewObjectBox
|
||||
struct ParseHandlerMatcher
|
||||
{
|
||||
template<class Parser>
|
||||
frontend::FullParseHandler& match(Parser *parser) {
|
||||
frontend::FullParseHandler& match(Parser* parser) {
|
||||
return parser->handler;
|
||||
}
|
||||
};
|
||||
|
||||
struct AnyCharsMatcher
|
||||
{
|
||||
template<class Parser>
|
||||
frontend::TokenStreamAnyChars& match(Parser* parser) {
|
||||
return parser->anyChars;
|
||||
}
|
||||
};
|
||||
|
||||
struct ParserBaseMatcher
|
||||
{
|
||||
template<class Parser>
|
||||
@ -127,7 +136,8 @@ namespace frontend {
|
||||
class EitherParser : public BCEParserHandle
|
||||
{
|
||||
// Leave this as a variant, to promote good form until 8-bit parser integration.
|
||||
mozilla::Variant<Parser<FullParseHandler, char16_t>* const> parser;
|
||||
mozilla::Variant<Parser<FullParseHandler, char16_t>* const,
|
||||
Parser<FullParseHandler, mozilla::Utf8Unit>* const> parser;
|
||||
|
||||
using Node = typename FullParseHandler::Node;
|
||||
|
||||
@ -164,6 +174,13 @@ class EitherParser : public BCEParserHandle
|
||||
return parser.match(std::move(matcher));
|
||||
}
|
||||
|
||||
const TokenStreamAnyChars& anyChars() const {
|
||||
return parser.match(detail::AnyCharsMatcher());
|
||||
}
|
||||
|
||||
void computeLineAndColumn(uint32_t offset, uint32_t* line, uint32_t* column) const {
|
||||
return anyChars().lineAndColumnAt(offset, line, column);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace frontend */
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "frontend/EmitterScope.h"
|
||||
|
||||
#include "frontend/BytecodeEmitter.h"
|
||||
#include "frontend/ModuleSharedContext.h"
|
||||
#include "frontend/TDZCheckCache.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
|
48
js/src/frontend/ModuleSharedContext.h
Normal file
48
js/src/frontend/ModuleSharedContext.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- 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 frontend_ModuleSharedContext_h
|
||||
#define frontend_ModuleSharedContext_h
|
||||
|
||||
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
||||
#include "mozilla/Attributes.h" // MOZ_STACK_CLASS
|
||||
|
||||
#include "builtin/ModuleObject.h" // js::Module{Builder,Object}
|
||||
#include "frontend/SharedContext.h" // js::frontend::SharedContext
|
||||
#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
|
||||
#include "vm/Scope.h" // js::{Module,}Scope
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
class MOZ_STACK_CLASS ModuleSharedContext
|
||||
: public SharedContext
|
||||
{
|
||||
JS::Rooted<ModuleObject*> module_;
|
||||
JS::Rooted<Scope*> enclosingScope_;
|
||||
|
||||
public:
|
||||
JS::Rooted<ModuleScope::Data*> bindings;
|
||||
ModuleBuilder& builder;
|
||||
|
||||
ModuleSharedContext(JSContext* cx, ModuleObject* module, Scope* enclosingScope,
|
||||
ModuleBuilder& builder);
|
||||
|
||||
JS::Handle<ModuleObject*> module() const { return module_; }
|
||||
Scope* compilationEnclosingScope() const override { return enclosingScope_; }
|
||||
};
|
||||
|
||||
inline ModuleSharedContext*
|
||||
SharedContext::asModuleContext()
|
||||
{
|
||||
MOZ_ASSERT(isModuleContext());
|
||||
return static_cast<ModuleSharedContext*>(this);
|
||||
}
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace js
|
||||
|
||||
#endif /* frontend_ModuleSharedContext_h */
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "frontend/ErrorReporter.h"
|
||||
#include "frontend/NameCollections.h"
|
||||
#include "frontend/SharedContext.h"
|
||||
|
||||
namespace js {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "builtin/SelfHostingDefines.h"
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "frontend/FoldConstants.h"
|
||||
#include "frontend/ModuleSharedContext.h"
|
||||
#include "frontend/ParseNode.h"
|
||||
#include "frontend/TokenStream.h"
|
||||
#include "irregexp/RegExpParser.h"
|
||||
|
@ -5,6 +5,9 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "frontend/SharedContext.h"
|
||||
|
||||
#include "frontend/ModuleSharedContext.h"
|
||||
|
||||
#include "frontend/ParseContext-inl.h"
|
||||
#include "vm/EnvironmentObject-inl.h"
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "jspubtd.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "builtin/ModuleObject.h"
|
||||
#include "ds/InlineTable.h"
|
||||
#include "frontend/ParseNode.h"
|
||||
#include "frontend/TokenStream.h"
|
||||
@ -584,29 +583,6 @@ SharedContext::asFunctionBox()
|
||||
return static_cast<FunctionBox*>(this);
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS ModuleSharedContext : public SharedContext
|
||||
{
|
||||
RootedModuleObject module_;
|
||||
RootedScope enclosingScope_;
|
||||
|
||||
public:
|
||||
Rooted<ModuleScope::Data*> bindings;
|
||||
ModuleBuilder& builder;
|
||||
|
||||
ModuleSharedContext(JSContext* cx, ModuleObject* module, Scope* enclosingScope,
|
||||
ModuleBuilder& builder);
|
||||
|
||||
HandleModuleObject module() const { return module_; }
|
||||
Scope* compilationEnclosingScope() const override { return enclosingScope_; }
|
||||
};
|
||||
|
||||
inline ModuleSharedContext*
|
||||
SharedContext::asModuleContext()
|
||||
{
|
||||
MOZ_ASSERT(isModuleContext());
|
||||
return static_cast<ModuleSharedContext*>(this);
|
||||
}
|
||||
|
||||
// In generators, we treat all bindings as closed so that they get stored on
|
||||
// the heap. This way there is less information to copy off the stack when
|
||||
// suspending, and back on when resuming. It also avoids the need to create
|
||||
|
@ -8,7 +8,6 @@
|
||||
if CONFIG['NIGHTLY_BUILD']:
|
||||
DEFINES['ENABLE_BINARYDATA'] = True
|
||||
DEFINES['ENABLE_WASM_BULKMEM_OPS'] = True
|
||||
DEFINES['ENABLE_WASM_THREAD_OPS'] = True
|
||||
DEFINES['ENABLE_WASM_GC'] = True
|
||||
DEFINES['ENABLE_WASM_GENERALIZED_TABLES'] = True
|
||||
DEFINES['WASM_PRIVATE_REFTYPES'] = True
|
||||
@ -22,9 +21,10 @@ if CONFIG['JS_CODEGEN_X64'] or CONFIG['JS_CODEGEN_ARM64']:
|
||||
if CONFIG['MOZ_DEBUG'] or CONFIG['NIGHTLY_BUILD']:
|
||||
DEFINES['JS_CACHEIR_SPEW'] = True
|
||||
|
||||
# Build with SharedArrayBuffer code.
|
||||
# Build with SharedArrayBuffer/wasm-thread-ops code.
|
||||
# NOTE: This Realm creation options decide if this is exposed to script.
|
||||
DEFINES['ENABLE_SHARED_ARRAY_BUFFER'] = True
|
||||
DEFINES['ENABLE_WASM_THREAD_OPS'] = True
|
||||
|
||||
# CTypes
|
||||
if CONFIG['JS_HAS_CTYPES']:
|
||||
|
@ -22,6 +22,7 @@ UNIFIED_SOURCES += [
|
||||
'testChromeBuffer.cpp',
|
||||
'testCloneScript.cpp',
|
||||
'testCompileNonSyntactic.cpp',
|
||||
'testCompileUtf8.cpp',
|
||||
'testDateToLocaleString.cpp',
|
||||
'testDebugger.cpp',
|
||||
'testDeepFreeze.cpp',
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include "gc/GCInternals.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
#include "vm/Monitor.h"
|
||||
#include "vm/MutexIDs.h"
|
||||
@ -74,9 +74,10 @@ testCompile(bool nonSyntactic)
|
||||
JS::CompileOptions options(cx);
|
||||
options.setNonSyntacticScope(nonSyntactic);
|
||||
|
||||
JS::RootedScript script(cx);
|
||||
JS::SourceText<char16_t> buf;
|
||||
CHECK(buf.init(cx, src_16, length, JS::SourceOwnership::Borrowed));
|
||||
|
||||
JS::SourceBufferHolder buf(src_16, length, JS::SourceBufferHolder::NoOwnership);
|
||||
JS::RootedScript script(cx);
|
||||
|
||||
// Check explicit non-syntactic compilation first to make sure it doesn't
|
||||
// modify our options object.
|
||||
@ -87,7 +88,9 @@ testCompile(bool nonSyntactic)
|
||||
CHECK_EQUAL(script->hasNonSyntacticScope(), true);
|
||||
|
||||
{
|
||||
JS::SourceBufferHolder srcBuf(src_16, length, JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, src_16, length, JS::SourceOwnership::Borrowed));
|
||||
|
||||
CHECK(CompileForNonSyntacticScope(cx, options, srcBuf, &script));
|
||||
CHECK_EQUAL(script->hasNonSyntacticScope(), true);
|
||||
}
|
||||
@ -100,7 +103,9 @@ testCompile(bool nonSyntactic)
|
||||
CHECK_EQUAL(script->hasNonSyntacticScope(), nonSyntactic);
|
||||
|
||||
{
|
||||
JS::SourceBufferHolder srcBuf(src_16, length, JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, src_16, length, JS::SourceOwnership::Borrowed));
|
||||
|
||||
CHECK(Compile(cx, options, srcBuf, &script));
|
||||
CHECK_EQUAL(script->hasNonSyntacticScope(), nonSyntactic);
|
||||
}
|
||||
@ -110,7 +115,9 @@ testCompile(bool nonSyntactic)
|
||||
OffThreadTask task;
|
||||
OffThreadToken* token;
|
||||
|
||||
JS::SourceBufferHolder srcBuf(src_16, length, JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, src_16, length, JS::SourceOwnership::Borrowed));
|
||||
|
||||
CHECK(CompileOffThread(cx, options, srcBuf, task.OffThreadCallback, &task));
|
||||
CHECK(token = task.waitUntilDone(cx));
|
||||
CHECK(script = FinishOffThreadScript(cx, token));
|
||||
|
279
js/src/jsapi-tests/testCompileUtf8.cpp
Normal file
279
js/src/jsapi-tests/testCompileUtf8.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
/* 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 "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/TextUtils.h"
|
||||
#include "mozilla/Utf8.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
#include "vm/ErrorReporting.h"
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::IsAsciiHexDigit;
|
||||
using mozilla::Utf8Unit;
|
||||
|
||||
BEGIN_TEST(testUtf8BadBytes)
|
||||
{
|
||||
static const char badLeadingUnit[] = "var x = \x80";
|
||||
CHECK(testBadUtf8(badLeadingUnit,
|
||||
JSMSG_BAD_LEADING_UTF8_UNIT,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(startsWith(chars, "0x80"));
|
||||
CHECK(isBadLeadUnitMessage(chars));
|
||||
return true;
|
||||
},
|
||||
"0x80"));
|
||||
|
||||
static const char badSecondInTwoByte[] = "var x = \xDF\x20";
|
||||
CHECK(testBadUtf8(badSecondInTwoByte,
|
||||
JSMSG_BAD_TRAILING_UTF8_UNIT,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(isBadTrailingBytesMessage(chars));
|
||||
CHECK(contains(chars, "0x20"));
|
||||
return true;
|
||||
},
|
||||
"0xDF 0x20"));
|
||||
|
||||
static const char badSecondInThreeByte[] = "var x = \xEF\x17\xA7";
|
||||
CHECK(testBadUtf8(badSecondInThreeByte,
|
||||
JSMSG_BAD_TRAILING_UTF8_UNIT,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(isBadTrailingBytesMessage(chars));
|
||||
CHECK(contains(chars, "0x17"));
|
||||
return true;
|
||||
},
|
||||
// Validating stops with the first invalid code unit and
|
||||
// shouldn't go beyond that.
|
||||
"0xEF 0x17"));
|
||||
|
||||
static const char lengthTwoTooShort[] = "var x = \xDF";
|
||||
CHECK(testBadUtf8(lengthTwoTooShort,
|
||||
JSMSG_NOT_ENOUGH_CODE_UNITS,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(isNotEnoughUnitsMessage(chars));
|
||||
CHECK(contains(chars, "0xDF"));
|
||||
CHECK(contains(chars, " 1 byte, but 0 bytes were present"));
|
||||
return true;
|
||||
},
|
||||
"0xDF"));
|
||||
|
||||
static const char forbiddenHighSurrogate[] = "var x = \xED\xA2\x87";
|
||||
CHECK(testBadUtf8(forbiddenHighSurrogate,
|
||||
JSMSG_FORBIDDEN_UTF8_CODE_POINT,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(isSurrogateMessage(chars));
|
||||
CHECK(contains(chars, "0xD887"));
|
||||
return true;
|
||||
},
|
||||
"0xED 0xA2 0x87"));
|
||||
|
||||
static const char forbiddenLowSurrogate[] = "var x = \xED\xB7\xAF";
|
||||
CHECK(testBadUtf8(forbiddenLowSurrogate,
|
||||
JSMSG_FORBIDDEN_UTF8_CODE_POINT,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(isSurrogateMessage(chars));
|
||||
CHECK(contains(chars, "0xDDEF"));
|
||||
return true;
|
||||
},
|
||||
"0xED 0xB7 0xAF"));
|
||||
|
||||
static const char oneTooBig[] = "var x = \xF4\x90\x80\x80";
|
||||
CHECK(testBadUtf8(oneTooBig,
|
||||
JSMSG_FORBIDDEN_UTF8_CODE_POINT,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(isTooBigMessage(chars));
|
||||
CHECK(contains(chars, "0x110000"));
|
||||
return true;
|
||||
},
|
||||
"0xF4 0x90 0x80 0x80"));
|
||||
|
||||
static const char notShortestFormZero[] = "var x = \xC0\x80";
|
||||
CHECK(testBadUtf8(notShortestFormZero,
|
||||
JSMSG_FORBIDDEN_UTF8_CODE_POINT,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(isNotShortestFormMessage(chars));
|
||||
CHECK(startsWith(chars, "0x0 isn't "));
|
||||
return true;
|
||||
},
|
||||
"0xC0 0x80"));
|
||||
|
||||
static const char notShortestFormNonzero[] = "var x = \xE0\x87\x80";
|
||||
CHECK(testBadUtf8(notShortestFormNonzero,
|
||||
JSMSG_FORBIDDEN_UTF8_CODE_POINT,
|
||||
[this](JS::ConstUTF8CharsZ message) {
|
||||
const char* chars = message.c_str();
|
||||
CHECK(isNotShortestFormMessage(chars));
|
||||
CHECK(startsWith(chars, "0x1C0 isn't "));
|
||||
return true;
|
||||
},
|
||||
"0xE0 0x87 0x80"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr size_t LengthOfByte = ArrayLength("0xFF") - 1;
|
||||
|
||||
static bool
|
||||
startsWithByte(const char* str)
|
||||
{
|
||||
return str[0] == '0' &&
|
||||
str[1] == 'x' &&
|
||||
IsAsciiHexDigit(str[2]) &&
|
||||
IsAsciiHexDigit(str[3]);
|
||||
}
|
||||
|
||||
static bool
|
||||
startsWith(const char* str, const char* prefix)
|
||||
{
|
||||
return std::strncmp(prefix, str, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
contains(const char* str, const char* substr)
|
||||
{
|
||||
return std::strstr(str, substr) != nullptr;
|
||||
}
|
||||
|
||||
static bool
|
||||
equals(const char* str, const char* expected)
|
||||
{
|
||||
return std::strcmp(str, expected) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
isBadLeadUnitMessage(const char* str)
|
||||
{
|
||||
return startsWithByte(str) &&
|
||||
equals(str + LengthOfByte,
|
||||
" byte doesn't begin a valid UTF-8 code point");
|
||||
}
|
||||
|
||||
static bool
|
||||
isBadTrailingBytesMessage(const char* str)
|
||||
{
|
||||
return startsWith(str, "bad trailing UTF-8 byte ");
|
||||
}
|
||||
|
||||
static bool
|
||||
isNotEnoughUnitsMessage(const char* str)
|
||||
{
|
||||
return startsWithByte(str) &&
|
||||
startsWith(str + LengthOfByte,
|
||||
" byte in UTF-8 must be followed by ");
|
||||
}
|
||||
|
||||
static bool
|
||||
isForbiddenCodePointMessage(const char* str)
|
||||
{
|
||||
return contains(str, "isn't a valid code point because");
|
||||
}
|
||||
|
||||
static bool
|
||||
isSurrogateMessage(const char* str)
|
||||
{
|
||||
return isForbiddenCodePointMessage(str) &&
|
||||
contains(str, " it's a UTF-16 surrogate");
|
||||
}
|
||||
|
||||
static bool
|
||||
isTooBigMessage(const char* str)
|
||||
{
|
||||
return isForbiddenCodePointMessage(str) &&
|
||||
contains(str, "the maximum code point is U+10FFFF");
|
||||
}
|
||||
|
||||
static bool
|
||||
isNotShortestFormMessage(const char* str)
|
||||
{
|
||||
return isForbiddenCodePointMessage(str) &&
|
||||
contains(str, "it wasn't encoded in shortest possible form");
|
||||
}
|
||||
|
||||
bool
|
||||
compileUtf8(const char* chars, size_t len, JS::MutableHandleScript script)
|
||||
{
|
||||
JS::RealmOptions globalOptions;
|
||||
JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
|
||||
JS::FireOnNewGlobalHook, globalOptions));
|
||||
CHECK(global);
|
||||
|
||||
JSAutoRealm ar(cx, global);
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
return JS::CompileUtf8DontInflate(cx, options, chars, len, script);
|
||||
}
|
||||
|
||||
template<size_t N, typename TestMessage>
|
||||
bool
|
||||
testBadUtf8(const char (&chars)[N], unsigned errorNumber,
|
||||
TestMessage testMessage, const char* badBytes)
|
||||
{
|
||||
JS::Rooted<JSScript*> script(cx);
|
||||
CHECK(!compileUtf8(chars, N - 1, &script));
|
||||
|
||||
JS::RootedValue exn(cx);
|
||||
CHECK(JS_GetPendingException(cx, &exn));
|
||||
JS_ClearPendingException(cx);
|
||||
|
||||
js::ErrorReport report(cx);
|
||||
CHECK(report.init(cx, exn, js::ErrorReport::WithSideEffects));
|
||||
|
||||
const auto* errorReport = report.report();
|
||||
|
||||
CHECK(errorReport->errorNumber == errorNumber);
|
||||
|
||||
CHECK(testMessage(errorReport->message()));
|
||||
|
||||
{
|
||||
const auto& notes = errorReport->notes;
|
||||
CHECK(notes != nullptr);
|
||||
|
||||
auto iter = notes->begin();
|
||||
CHECK(iter != notes->end());
|
||||
|
||||
const char* noteMessage = (*iter)->message().c_str();
|
||||
|
||||
// The prefix ought always be the same.
|
||||
static const char expectedPrefix[] =
|
||||
"the code units comprising this invalid code point were: ";
|
||||
constexpr size_t expectedPrefixLen = ArrayLength(expectedPrefix) - 1;
|
||||
|
||||
CHECK(startsWith(noteMessage, expectedPrefix));
|
||||
|
||||
// The end of the prefix is the bad bytes.
|
||||
CHECK(equals(noteMessage + expectedPrefixLen, badBytes));
|
||||
|
||||
++iter;
|
||||
CHECK(iter == notes->end());
|
||||
}
|
||||
|
||||
static const char16_t expectedContext[] = u"var x = ";
|
||||
constexpr size_t expectedContextLen = ArrayLength(expectedContext) - 1;
|
||||
|
||||
const char16_t* lineOfContext = errorReport->linebuf();
|
||||
size_t lineOfContextLength = errorReport->linebufLength();
|
||||
|
||||
CHECK(lineOfContext[lineOfContextLength] == '\0');
|
||||
CHECK(lineOfContextLength == expectedContextLen);
|
||||
|
||||
CHECK(std::memcmp(lineOfContext, expectedContext, expectedContextLen * sizeof(char16_t)) == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testUtf8BadBytes)
|
@ -5,7 +5,7 @@
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
#include "vm/ErrorReporting.h"
|
||||
|
||||
@ -42,8 +42,11 @@ eval(const char16_t* chars, size_t len, JS::MutableHandleValue rval)
|
||||
CHECK(global);
|
||||
|
||||
JSAutoRealm ar(cx, global);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, chars, len, JS::SourceOwnership::Borrowed));
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
JS::SourceBufferHolder srcBuf(chars, len, JS::SourceBufferHolder::NoOwnership);
|
||||
return JS::Evaluate(cx, options, srcBuf, rval);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
@ -19,7 +19,10 @@ BEGIN_TEST(testJSEvaluateScript)
|
||||
JS::CompileOptions opts(cx);
|
||||
JS::AutoObjectVector scopeChain(cx);
|
||||
CHECK(scopeChain.append(obj));
|
||||
JS::SourceBufferHolder srcBuf(src, ArrayLength(src) - 1, JS::SourceBufferHolder::NoOwnership);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, src, ArrayLength(src) - 1, JS::SourceOwnership::Borrowed));
|
||||
|
||||
CHECK(JS::Evaluate(cx, scopeChain, opts.setFileAndLine(__FILE__, __LINE__),
|
||||
srcBuf, &retval));
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
BEGIN_TEST(testMutedErrors)
|
||||
@ -57,7 +57,9 @@ eval(const char* asciiChars, bool mutedErrors, JS::MutableHandleValue rval)
|
||||
options.setMutedErrors(mutedErrors)
|
||||
.setFileAndLine("", 0);
|
||||
|
||||
JS::SourceBufferHolder srcBuf(chars.get(), len, JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, chars.get(), len, JS::SourceOwnership::Borrowed));
|
||||
|
||||
return JS::Evaluate(cx, options, srcBuf, rval);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
struct ScriptObjectFixture : public JSAPITest {
|
||||
@ -81,8 +81,10 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript)
|
||||
JS::CompileOptions options(cx);
|
||||
options.setFileAndLine(__FILE__, __LINE__);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, uc_code, code_size, JS::SourceOwnership::Borrowed));
|
||||
|
||||
JS::RootedScript script(cx);
|
||||
JS::SourceBufferHolder srcBuf(uc_code, code_size, JS::SourceBufferHolder::NoOwnership);
|
||||
CHECK(JS::Compile(cx, options, srcBuf, &script));
|
||||
|
||||
return tryScript(script);
|
||||
@ -94,8 +96,10 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty)
|
||||
JS::CompileOptions options(cx);
|
||||
options.setFileAndLine(__FILE__, __LINE__);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, uc_code, 0, JS::SourceOwnership::Borrowed));
|
||||
|
||||
JS::RootedScript script(cx);
|
||||
JS::SourceBufferHolder srcBuf(uc_code, 0, JS::SourceBufferHolder::NoOwnership);
|
||||
CHECK(JS::Compile(cx, options, srcBuf, &script));
|
||||
|
||||
return tryScript(script);
|
||||
@ -107,8 +111,10 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipal
|
||||
JS::CompileOptions options(cx);
|
||||
options.setFileAndLine(__FILE__, __LINE__);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
CHECK(srcBuf.init(cx, uc_code, code_size, JS::SourceOwnership::Borrowed));
|
||||
|
||||
JS::RootedScript script(cx);
|
||||
JS::SourceBufferHolder srcBuf(uc_code, code_size, JS::SourceBufferHolder::NoOwnership);
|
||||
CHECK(JS::Compile(cx, options, srcBuf, &script));
|
||||
|
||||
return tryScript(script);
|
||||
|
@ -62,7 +62,7 @@
|
||||
#include "js/LocaleSensitive.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "js/SliceBudget.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "js/Utility.h"
|
||||
@ -114,7 +114,7 @@ using mozilla::Some;
|
||||
using JS::AutoStableStringChars;
|
||||
using JS::CompileOptions;
|
||||
using JS::ReadOnlyCompileOptions;
|
||||
using JS::SourceBufferHolder;
|
||||
using JS::SourceText;
|
||||
|
||||
#ifdef HAVE_VA_LIST_AS_ARRAY
|
||||
#define JS_ADDRESSOF_VA_LIST(ap) ((va_list*)(ap))
|
||||
@ -4162,7 +4162,7 @@ JS::FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, Han
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, JS::MutableHandleObject module)
|
||||
SourceText<char16_t>& srcBuf, JS::MutableHandleObject module)
|
||||
{
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/RangedPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Utf8.h"
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
@ -51,7 +52,8 @@
|
||||
|
||||
namespace JS {
|
||||
|
||||
class SourceBufferHolder;
|
||||
template<typename UnitT> class SourceText;
|
||||
|
||||
class TwoByteChars;
|
||||
|
||||
/** AutoValueArray roots an internal fixed-size array of Values. */
|
||||
@ -3125,7 +3127,7 @@ FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, HandleS
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, JS::MutableHandleObject moduleRecord);
|
||||
SourceText<char16_t>& srcBuf, JS::MutableHandleObject moduleRecord);
|
||||
|
||||
/**
|
||||
* Set a private value associated with a source text module record.
|
||||
|
@ -151,7 +151,7 @@ EXPORTS.js += [
|
||||
'../public/RootingAPI.h',
|
||||
'../public/SavedFrameAPI.h',
|
||||
'../public/SliceBudget.h',
|
||||
'../public/SourceBufferHolder.h',
|
||||
'../public/SourceText.h',
|
||||
'../public/StableStringChars.h',
|
||||
'../public/Stream.h',
|
||||
'../public/StructuredClone.h',
|
||||
|
@ -70,6 +70,7 @@
|
||||
#if defined(JS_BUILD_BINAST)
|
||||
# include "frontend/BinSource.h"
|
||||
#endif // defined(JS_BUILD_BINAST)
|
||||
#include "frontend/ModuleSharedContext.h"
|
||||
#include "frontend/Parser.h"
|
||||
#include "gc/PublicIterators.h"
|
||||
#include "jit/arm/Simulator-arm.h"
|
||||
@ -86,7 +87,7 @@
|
||||
#include "js/Initialization.h"
|
||||
#include "js/JSON.h"
|
||||
#include "js/Printf.h"
|
||||
#include "js/SourceBufferHolder.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "js/SweepingAPI.h"
|
||||
@ -879,8 +880,15 @@ RegisterScriptPathWithModuleLoader(JSContext* cx, HandleScript script, const cha
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class CompileUtf8
|
||||
{
|
||||
InflateToUtf16,
|
||||
DontInflate,
|
||||
};
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
|
||||
RunFile(JSContext* cx, const char* filename, FILE* file, CompileUtf8 compileMethod,
|
||||
bool compileOnly)
|
||||
{
|
||||
SkipUTF8BOM(file);
|
||||
|
||||
@ -906,9 +914,18 @@ RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
|
||||
.setIsRunOnce(true)
|
||||
.setNoScriptRval(true);
|
||||
|
||||
if (!JS::CompileUtf8File(cx, options, file, &script)) {
|
||||
return false;
|
||||
if (compileMethod == CompileUtf8::DontInflate) {
|
||||
fprintf(stderr, "(compiling '%s' as UTF-8 without inflating)\n", filename);
|
||||
|
||||
if (!JS::CompileUtf8FileDontInflate(cx, options, file, &script)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!JS::CompileUtf8File(cx, options, file, &script)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(script);
|
||||
}
|
||||
|
||||
@ -1363,6 +1380,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, bool compileOnly)
|
||||
enum FileKind
|
||||
{
|
||||
FileScript,
|
||||
FileScriptUtf8, // FileScript, but don't inflate to UTF-16 before parsing
|
||||
FileModule,
|
||||
FileBinAST
|
||||
};
|
||||
@ -1385,7 +1403,7 @@ ReportCantOpenErrorUnknownEncoding(JSContext* cx, const char* filename)
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
Process(JSContext* cx, const char* filename, bool forceTTY, FileKind kind = FileScript)
|
||||
Process(JSContext* cx, const char* filename, bool forceTTY, FileKind kind)
|
||||
{
|
||||
FILE* file;
|
||||
if (forceTTY || !filename || strcmp(filename, "-") == 0) {
|
||||
@ -1403,7 +1421,12 @@ Process(JSContext* cx, const char* filename, bool forceTTY, FileKind kind = File
|
||||
// It's not interactive - just execute it.
|
||||
switch (kind) {
|
||||
case FileScript:
|
||||
if (!RunFile(cx, filename, file, compileOnly)) {
|
||||
if (!RunFile(cx, filename, file, CompileUtf8::InflateToUtf16, compileOnly)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case FileScriptUtf8:
|
||||
if (!RunFile(cx, filename, file, CompileUtf8::DontInflate, compileOnly)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@ -2141,8 +2164,13 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
} else {
|
||||
mozilla::Range<const char16_t> chars = codeChars.twoByteRange();
|
||||
JS::SourceBufferHolder srcBuf(chars.begin().get(), chars.length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, chars.begin().get(), chars.length(),
|
||||
JS::SourceOwnership::Borrowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (envChain.length() == 0) {
|
||||
(void) JS::Compile(cx, options, srcBuf, &script);
|
||||
} else {
|
||||
@ -2383,8 +2411,12 @@ Run(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::SourceBufferHolder srcBuf(chars.twoByteRange().begin().get(), str->length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, chars.twoByteRange().begin().get(), str->length(),
|
||||
JS::SourceOwnership::Borrowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedScript script(cx);
|
||||
int64_t startClock = PRMJ_Now();
|
||||
@ -3863,10 +3895,14 @@ EvalInContext(JSContext* cx, unsigned argc, Value* vp)
|
||||
JS_ReportErrorASCII(cx, "Invalid scope argument to evalcx");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::CompileOptions opts(cx);
|
||||
opts.setFileAndLine(filename.get(), lineno);
|
||||
JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership);
|
||||
if (!JS::Evaluate(cx, opts, srcBuf, args.rval())) {
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, src, srclen, JS::SourceOwnership::Borrowed) ||
|
||||
!JS::Evaluate(cx, opts, srcBuf, args.rval()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -3979,9 +4015,11 @@ WorkerMain(WorkerInput* input)
|
||||
|
||||
AutoReportException are(cx);
|
||||
RootedScript script(cx);
|
||||
JS::SourceBufferHolder srcBuf(input->chars.get(), input->length,
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
if (!JS::Compile(cx, options, srcBuf, &script)) {
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, input->chars.get(), input->length,
|
||||
JS::SourceOwnership::Borrowed) ||
|
||||
!JS::Compile(cx, options, srcBuf, &script))
|
||||
{
|
||||
break;
|
||||
}
|
||||
RootedValue result(cx);
|
||||
@ -4656,13 +4694,21 @@ Compile(JSContext* cx, unsigned argc, Value* vp)
|
||||
.setFileAndLine("<string>", 1)
|
||||
.setIsRunOnce(true)
|
||||
.setNoScriptRval(true);
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, stableChars.twoByteRange().begin().get(), scriptContents->length(),
|
||||
JS::SourceOwnership::Borrowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedScript script(cx);
|
||||
JS::SourceBufferHolder srcBuf(stableChars.twoByteRange().begin().get(),
|
||||
scriptContents->length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
bool ok = JS::Compile(cx, options, srcBuf, &script);
|
||||
if (!JS::Compile(cx, options, srcBuf, &script)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return ok;
|
||||
return true;
|
||||
}
|
||||
|
||||
static ShellCompartmentPrivate*
|
||||
@ -4724,8 +4770,10 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
const char16_t* chars = stableChars.twoByteRange().begin().get();
|
||||
JS::SourceBufferHolder srcBuf(chars, scriptContents->length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, chars, scriptContents->length(), JS::SourceOwnership::Borrowed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf));
|
||||
if (!module) {
|
||||
@ -5266,7 +5314,7 @@ Parse(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
ModuleBuilder builder(cx, module, parser.anyChars);
|
||||
ModuleBuilder builder(cx, module, &parser);
|
||||
|
||||
ModuleSharedContext modulesc(cx, module, nullptr, builder);
|
||||
pn = parser.moduleBody(&modulesc);
|
||||
@ -5436,10 +5484,9 @@ OffThreadCompileScript(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::SourceBufferHolder srcBuf(job->sourceChars(), length,
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
if (!JS::CompileOffThread(cx, options, srcBuf,
|
||||
OffThreadCompileScriptCallback, job))
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, job->sourceChars(), length, JS::SourceOwnership::Borrowed) ||
|
||||
!JS::CompileOffThread(cx, options, srcBuf, OffThreadCompileScriptCallback, job))
|
||||
{
|
||||
job->cancel();
|
||||
DeleteOffThreadJob(cx, job);
|
||||
@ -5530,10 +5577,9 @@ OffThreadCompileModule(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::SourceBufferHolder srcBuf(job->sourceChars(), length,
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
if (!JS::CompileOffThreadModule(cx, options, srcBuf,
|
||||
OffThreadCompileScriptCallback, job))
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, job->sourceChars(), length, JS::SourceOwnership::Borrowed) ||
|
||||
!JS::CompileOffThreadModule(cx, options, srcBuf, OffThreadCompileScriptCallback, job))
|
||||
{
|
||||
job->cancel();
|
||||
DeleteOffThreadJob(cx, job);
|
||||
@ -8211,9 +8257,12 @@ EntryPoints(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!stableChars.initTwoByte(cx, codeString)) {
|
||||
return false;
|
||||
}
|
||||
JS::SourceBufferHolder srcBuf(stableChars.twoByteRange().begin().get(),
|
||||
codeString->length(),
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, stableChars.twoByteRange().begin().get(), codeString->length(),
|
||||
JS::SourceOwnership::Borrowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CompileOptions options(cx);
|
||||
options.setIntroductionType("entryPoint eval")
|
||||
@ -10252,6 +10301,7 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
}
|
||||
|
||||
MultiStringRange filePaths = op->getMultiStringOption('f');
|
||||
MultiStringRange utf8FilePaths = op->getMultiStringOption('u');
|
||||
MultiStringRange codeChunks = op->getMultiStringOption('e');
|
||||
MultiStringRange modulePaths = op->getMultiStringOption('m');
|
||||
MultiStringRange binASTPaths(nullptr, nullptr);
|
||||
@ -10260,12 +10310,13 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
#endif // JS_BUILD_BINAST
|
||||
|
||||
if (filePaths.empty() &&
|
||||
utf8FilePaths.empty() &&
|
||||
codeChunks.empty() &&
|
||||
modulePaths.empty() &&
|
||||
binASTPaths.empty() &&
|
||||
!op->getStringArg("script"))
|
||||
{
|
||||
return Process(cx, nullptr, true); /* Interactive. */
|
||||
return Process(cx, nullptr, true, FileScript); /* Interactive. */
|
||||
}
|
||||
|
||||
if (const char* path = op->getStringOption("module-load-path")) {
|
||||
@ -10292,19 +10343,39 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!filePaths.empty() || !codeChunks.empty() || !modulePaths.empty() || !binASTPaths.empty()) {
|
||||
while (!filePaths.empty() ||
|
||||
!utf8FilePaths.empty() ||
|
||||
!codeChunks.empty() ||
|
||||
!modulePaths.empty() ||
|
||||
!binASTPaths.empty())
|
||||
{
|
||||
size_t fpArgno = filePaths.empty() ? SIZE_MAX : filePaths.argno();
|
||||
size_t ufpArgno = utf8FilePaths.empty() ? SIZE_MAX : utf8FilePaths.argno();
|
||||
size_t ccArgno = codeChunks.empty() ? SIZE_MAX : codeChunks.argno();
|
||||
size_t mpArgno = modulePaths.empty() ? SIZE_MAX : modulePaths.argno();
|
||||
size_t baArgno = binASTPaths.empty() ? SIZE_MAX : binASTPaths.argno();
|
||||
|
||||
if (fpArgno < ccArgno && fpArgno < mpArgno && fpArgno < baArgno) {
|
||||
if (fpArgno < ufpArgno && fpArgno < ccArgno && fpArgno < mpArgno && fpArgno < baArgno) {
|
||||
char* path = filePaths.front();
|
||||
if (!Process(cx, path, false, FileScript)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
filePaths.popFront();
|
||||
} else if (ccArgno < fpArgno && ccArgno < mpArgno && ccArgno < baArgno) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ufpArgno < fpArgno && ufpArgno < ccArgno && ufpArgno < mpArgno && ufpArgno < baArgno) {
|
||||
char* path = utf8FilePaths.front();
|
||||
if (!Process(cx, path, false, FileScriptUtf8)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
utf8FilePaths.popFront();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ccArgno < fpArgno && ccArgno < ufpArgno && ccArgno < mpArgno && ccArgno < baArgno) {
|
||||
const char* code = codeChunks.front();
|
||||
|
||||
JS::CompileOptions opts(cx);
|
||||
@ -10321,20 +10392,31 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
if (sc->quitting) {
|
||||
break;
|
||||
}
|
||||
} else if (baArgno < fpArgno && baArgno < ccArgno && baArgno < mpArgno) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (baArgno < fpArgno && baArgno < ufpArgno && baArgno < ccArgno && baArgno < mpArgno) {
|
||||
char* path = binASTPaths.front();
|
||||
if (!Process(cx, path, false, FileBinAST)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
binASTPaths.popFront();
|
||||
} else {
|
||||
MOZ_ASSERT(mpArgno < fpArgno && mpArgno < ccArgno && mpArgno < baArgno);
|
||||
char* path = modulePaths.front();
|
||||
if (!Process(cx, path, false, FileModule)) {
|
||||
return false;
|
||||
}
|
||||
modulePaths.popFront();
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mpArgno < fpArgno &&
|
||||
mpArgno < ufpArgno &&
|
||||
mpArgno < ccArgno &&
|
||||
mpArgno < baArgno);
|
||||
|
||||
char* path = modulePaths.front();
|
||||
if (!Process(cx, path, false, FileModule)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
modulePaths.popFront();
|
||||
}
|
||||
|
||||
if (sc->quitting) {
|
||||
@ -10343,13 +10425,13 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
|
||||
/* The |script| argument is processed after all options. */
|
||||
if (const char* path = op->getStringArg("script")) {
|
||||
if (!Process(cx, path, false)) {
|
||||
if (!Process(cx, path, false, FileScript)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (op->getBoolOption('i')) {
|
||||
if (!Process(cx, nullptr, true)) {
|
||||
if (!Process(cx, nullptr, true, FileScript)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -10957,6 +11039,9 @@ main(int argc, char** argv, char** envp)
|
||||
op.setVersion(JS_GetImplementationVersion());
|
||||
|
||||
if (!op.addMultiStringOption('f', "file", "PATH", "File path to run")
|
||||
|| !op.addMultiStringOption('u', "utf8-file", "PATH",
|
||||
"File path to run, directly parsing file contents as UTF-8 "
|
||||
"without first inflating to UTF-16")
|
||||
|| !op.addMultiStringOption('m', "module", "PATH", "Module path to run")
|
||||
#if defined(JS_BUILD_BINAST)
|
||||
|| !op.addMultiStringOption('B', "binast", "PATH", "BinAST path to run")
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/MaybeOneOf.h"
|
||||
#include "mozilla/Utf8.h"
|
||||
|
||||
#include "js/Vector.h"
|
||||
#include "vm/JSContext.h"
|
||||
@ -159,6 +160,14 @@ class StringBuffer
|
||||
return append(chars, chars + len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpret the provided count of UTF-8 code units as UTF-8, and append
|
||||
* the represented code points to this. If the code units contain invalid
|
||||
* UTF-8, leave the internal buffer in a consistent but unspecified state,
|
||||
* report an error, and return false.
|
||||
*/
|
||||
MOZ_MUST_USE bool append(const mozilla::Utf8Unit* units, size_t len);
|
||||
|
||||
MOZ_MUST_USE bool append(const JS::ConstCharPtr chars, size_t len) {
|
||||
return append(chars.get(), chars.get() + len);
|
||||
}
|
||||
|
@ -8,13 +8,19 @@
|
||||
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/TextUtils.h"
|
||||
#include "mozilla/Utf8.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Unicode.h" // unicode::REPLACEMENT_CHARACTER
|
||||
#include "vm/JSContext.h"
|
||||
|
||||
using mozilla::IsAscii;
|
||||
using mozilla::Utf8Unit;
|
||||
|
||||
using namespace js;
|
||||
|
||||
Latin1CharsZ
|
||||
@ -607,3 +613,68 @@ JS::StringIsASCII(const char* s)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
StringBuffer::append(const Utf8Unit* units, size_t len)
|
||||
{
|
||||
if (isLatin1()) {
|
||||
Latin1CharBuffer& latin1 = latin1Chars();
|
||||
|
||||
while (len > 0) {
|
||||
if (!IsAscii(*units)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!latin1.append(units->toUnsignedChar())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++units;
|
||||
--len;
|
||||
}
|
||||
if (len == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Non-ASCII doesn't *necessarily* mean we couldn't keep appending to
|
||||
// |latin1|, but it's only possible for [U+0080, U+0100) code points,
|
||||
// and handling the full complexity of UTF-8 only for that very small
|
||||
// additional range isn't worth it. Inflate to two-byte storage before
|
||||
// appending the remaining code points.
|
||||
if (!inflateChars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
UTF8Chars remainingUtf8(units, len);
|
||||
|
||||
// Determine how many UTF-16 code units are required to represent the
|
||||
// remaining units.
|
||||
size_t utf16Len = 0;
|
||||
auto countInflated = [&utf16Len](char16_t c) -> LoopDisposition {
|
||||
utf16Len++;
|
||||
return LoopDisposition::Continue;
|
||||
};
|
||||
if (!InflateUTF8ToUTF16<OnUTF8Error::Throw>(cx, remainingUtf8, countInflated)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TwoByteCharBuffer& buf = twoByteChars();
|
||||
|
||||
size_t i = buf.length();
|
||||
if (!buf.growByUninitialized(utf16Len)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(i + utf16Len == buf.length(),
|
||||
"growByUninitialized assumed to increase length immediately");
|
||||
|
||||
char16_t* toFill = &buf[i];
|
||||
auto appendUtf16 = [&toFill](char16_t unit) {
|
||||
*toFill++ = unit;
|
||||
return LoopDisposition::Continue;
|
||||
};
|
||||
|
||||
MOZ_ALWAYS_TRUE(InflateUTF8ToUTF16<OnUTF8Error::Throw>(cx, remainingUtf8, appendUtf16));
|
||||
MOZ_ASSERT(toFill == buf.end());
|
||||
return true;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user