зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team
This commit is contained in:
Коммит
2803b80084
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
|
@ -135,7 +135,7 @@
|
|||
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
|
||||
<project name="kernel/common" path="kernel" revision="0f36762ab0c1d8ce10c6a5eda948b05d5d6cc379"/>
|
||||
<project name="platform/system/core" path="system/core" revision="4b989b1bec28b0838420c4d5bb454c78afa62bea"/>
|
||||
<project name="platform/system/core" path="system/core" revision="4776448ebcd3f07d58b91503c478da9b54cb58a0"/>
|
||||
<project name="u-boot" path="u-boot" revision="f1502910977ac88f43da7bf9277c3523ad4b0b2f"/>
|
||||
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="7d6e1269be7186b2073fa568958b357826692c4b"/>
|
||||
<project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="295ff253b74353751a99aafd687196a28c84a58e"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="25554535ee69d4c0c24a51f6a55bbabe5cb0a6b8"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "0b934d06c04adff2cd9bdd0bc204f974a18b710f",
|
||||
"git_revision": "d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "dee47434923493d57f151448eec00f793f113bfd",
|
||||
"revision": "d382a1ff9028efabb8bbc18812ff7de12759a29e",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="25554535ee69d4c0c24a51f6a55bbabe5cb0a6b8"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0b934d06c04adff2cd9bdd0bc204f974a18b710f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d400cda6bf0f8b30dcf7d7d71bfa61f29a3f1588"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
add_task(function* test_simple() {
|
||||
let extension = ExtensionTestUtils.loadExtension("simple");
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
"name": "Simple extension test",
|
||||
"version": "1.0",
|
||||
"manifest_version": 2,
|
||||
"description": ""
|
||||
}
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
info("load complete");
|
||||
yield extension.startup();
|
||||
info("startup complete");
|
||||
|
@ -8,7 +17,30 @@ add_task(function* test_simple() {
|
|||
});
|
||||
|
||||
add_task(function* test_background() {
|
||||
let extension = ExtensionTestUtils.loadExtension("background");
|
||||
function backgroundScript() {
|
||||
browser.test.log("running background script");
|
||||
|
||||
browser.test.onMessage.addListener((x, y) => {
|
||||
browser.test.assertEq(x, 10, "x is 10");
|
||||
browser.test.assertEq(y, 20, "y is 20");
|
||||
|
||||
browser.test.notifyPass("background test passed");
|
||||
});
|
||||
|
||||
browser.test.sendMessage("running", 1);
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background: "(" + backgroundScript.toString() + ")()",
|
||||
manifest: {
|
||||
"name": "Simple extension test",
|
||||
"version": "1.0",
|
||||
"manifest_version": 2,
|
||||
"description": ""
|
||||
}
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
info("load complete");
|
||||
let [, x] = yield Promise.all([extension.startup(), extension.awaitMessage("running")]);
|
||||
is(x, 1, "got correct value from extension");
|
||||
|
|
|
@ -109,8 +109,8 @@ function getFilePath(aName, aAllowMissing=false, aUsePlatformPathSeparator=false
|
|||
return path;
|
||||
}
|
||||
|
||||
function saveNewHeapSnapshot() {
|
||||
const filePath = ChromeUtils.saveHeapSnapshot({ runtime: true });
|
||||
function saveNewHeapSnapshot(opts = { runtime: true }) {
|
||||
const filePath = ChromeUtils.saveHeapSnapshot(opts);
|
||||
ok(filePath, "Should get a file path to save the core dump to.");
|
||||
ok(true, "Saved a heap snapshot to " + filePath);
|
||||
return filePath;
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can send SavedFrame stacks from
|
||||
// by-allocation-stack reports from the worker.
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test() {
|
||||
const client = new HeapAnalysesClient();
|
||||
|
||||
// Track some allocation stacks.
|
||||
|
||||
const g = newGlobal();
|
||||
const dbg = new Debugger(g);
|
||||
g.eval(` // 1
|
||||
this.log = []; // 2
|
||||
function f() { this.log.push(allocationMarker()); } // 3
|
||||
function g() { this.log.push(allocationMarker()); } // 4
|
||||
function h() { this.log.push(allocationMarker()); } // 5
|
||||
`); // 6
|
||||
|
||||
// Create one allocationMarker with tracking turned off,
|
||||
// so it will have no associated stack.
|
||||
g.f();
|
||||
|
||||
dbg.memory.allocationSamplingProbability = 1;
|
||||
|
||||
for (let [func, n] of [ [g.f, 20],
|
||||
[g.g, 10],
|
||||
[g.h, 5] ]) {
|
||||
for (let i = 0; i < n; i++) {
|
||||
dbg.memory.trackingAllocationSites = true;
|
||||
// All allocations of allocationMarker occur with this line as the oldest
|
||||
// stack frame.
|
||||
func();
|
||||
dbg.memory.trackingAllocationSites = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Take a heap snapshot.
|
||||
|
||||
const snapshotFilePath = saveNewHeapSnapshot({ debugger: dbg });
|
||||
yield client.readHeapSnapshot(snapshotFilePath);
|
||||
ok(true, "Should have read the heap snapshot");
|
||||
|
||||
// Run a census broken down by class name -> allocation stack so we can grab
|
||||
// only the AllocationMarker objects we have complete control over.
|
||||
|
||||
const report = yield client.takeCensus(snapshotFilePath, {
|
||||
breakdown: { by: 'objectClass',
|
||||
then: { by: 'allocationStack',
|
||||
then: { by: 'count',
|
||||
bytes: true,
|
||||
count: true
|
||||
},
|
||||
noStack: { by: 'count',
|
||||
bytes: true,
|
||||
count: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Test the generated report.
|
||||
|
||||
ok(report, "Should get a report");
|
||||
|
||||
const map = report.AllocationMarker;
|
||||
ok(map, "Should get AllocationMarkers in the report.");
|
||||
// From a module with a different global, and therefore a different Map
|
||||
// constructor, so we can't use instanceof.
|
||||
equal(map.__proto__.constructor.name, "Map");
|
||||
|
||||
equal(map.size, 4, "Should have 4 allocation stacks (including the lack of a stack)")
|
||||
|
||||
// Gather the stacks we are expecting to appear as keys, and
|
||||
// check that there are no unexpected keys.
|
||||
let stacks = {};
|
||||
|
||||
map.forEach((v, k) => {
|
||||
if (k === 'noStack') {
|
||||
// No need to save this key.
|
||||
} else if (k.functionDisplayName === 'f' &&
|
||||
k.parent.functionDisplayName === 'test') {
|
||||
stacks.f = k;
|
||||
} else if (k.functionDisplayName === 'g' &&
|
||||
k.parent.functionDisplayName === 'test') {
|
||||
stacks.g = k;
|
||||
} else if (k.functionDisplayName === 'h' &&
|
||||
k.parent.functionDisplayName === 'test') {
|
||||
stacks.h = k;
|
||||
} else {
|
||||
dumpn("Unexpected allocation stack:")
|
||||
k.toString().split(/\n/g).forEach(s => dumpn(s));
|
||||
ok(false);
|
||||
}
|
||||
});
|
||||
|
||||
ok(map.get('noStack'));
|
||||
equal(map.get('noStack').count, 1);
|
||||
|
||||
ok(stacks.f);
|
||||
ok(map.get(stacks.f));
|
||||
equal(map.get(stacks.f).count, 20);
|
||||
|
||||
ok(stacks.g);
|
||||
ok(map.get(stacks.g));
|
||||
equal(map.get(stacks.g).count, 10);
|
||||
|
||||
ok(stacks.h);
|
||||
ok(map.get(stacks.h));
|
||||
equal(map.get(stacks.h).count, 5);
|
||||
|
||||
client.destroy();
|
||||
});
|
|
@ -16,6 +16,7 @@ support-files =
|
|||
[test_HeapAnalyses_takeCensus_01.js]
|
||||
[test_HeapAnalyses_takeCensus_02.js]
|
||||
[test_HeapAnalyses_takeCensus_03.js]
|
||||
[test_HeapAnalyses_takeCensus_04.js]
|
||||
[test_HeapSnapshot_takeCensus_01.js]
|
||||
[test_HeapSnapshot_takeCensus_02.js]
|
||||
[test_HeapSnapshot_takeCensus_03.js]
|
||||
|
|
|
@ -80,7 +80,6 @@ skip-if = os == 'linux' || os == 'mac' # Bug 1026815
|
|||
[test_bug690056.xul]
|
||||
[test_bug789773.xul]
|
||||
[test_bug846906.xul]
|
||||
skip-if = (os == 'linux' && asan) || debug # Bug 1207161
|
||||
[test_bug89419.xul]
|
||||
[test_bug909218.html]
|
||||
[test_bug92598.xul]
|
||||
|
|
|
@ -2710,6 +2710,9 @@ nsContentUtils::SubjectPrincipal()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
JSContext* cx = GetCurrentJSContext();
|
||||
if (!cx) {
|
||||
#ifndef RELEASE_BUILD
|
||||
MOZ_CRASH("Accessing the Subject Principal without an AutoJSAPI on the stack is forbidden");
|
||||
#endif
|
||||
Telemetry::Accumulate(Telemetry::SUBJECT_PRINCIPAL_ACCESSED_WITHOUT_SCRIPT_ON_STACK, true);
|
||||
return GetSystemPrincipal();
|
||||
}
|
||||
|
|
|
@ -1982,6 +1982,7 @@ public:
|
|||
{
|
||||
InternalFocusEvent event(true, mEventMessage);
|
||||
event.mFlags.mBubbles = false;
|
||||
event.mFlags.mCancelable = false;
|
||||
event.fromRaise = mWindowRaised;
|
||||
event.isRefocus = mIsRefocus;
|
||||
return EventDispatcher::Dispatch(mTarget, mContext, &event);
|
||||
|
|
|
@ -1074,13 +1074,6 @@ nsINode::IsEqualNode(nsINode* aOther)
|
|||
if (!string1.Equals(string2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Internal subset
|
||||
docType1->GetInternalSubset(string1);
|
||||
docType2->GetInternalSubset(string2);
|
||||
if (!string1.Equals(string2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -38,8 +38,7 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
|
|||
}
|
||||
isElement(doc.documentElement.lastChild, "body");
|
||||
is(doc.documentElement.lastChild.childNodes.length, 0);
|
||||
((!title || title.indexOf("\f") === -1) ? is : todo_is)
|
||||
(doc.title, normalizedtitle);
|
||||
is(doc.title, normalizedtitle);
|
||||
doc.body.innerHTML = "foo";
|
||||
is(doc.body.innerHTML, "foo", "innerHTML should work in HTML data documents!");
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "BluetoothSocket.h"
|
||||
#include "BluetoothUtils.h"
|
||||
#include "BluetoothUuid.h"
|
||||
#include "ObexBase.h"
|
||||
|
||||
#include "mozilla/dom/BluetoothPbapParametersBinding.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
@ -46,6 +45,31 @@ namespace {
|
|||
}
|
||||
};
|
||||
|
||||
// App parameters to pull phonebook
|
||||
static const AppParameterTag sPhonebookTags[] = {
|
||||
AppParameterTag::Format,
|
||||
AppParameterTag::PropertySelector,
|
||||
AppParameterTag::MaxListCount,
|
||||
AppParameterTag::ListStartOffset,
|
||||
AppParameterTag::vCardSelector
|
||||
};
|
||||
|
||||
// App parameters to pull vCard listing
|
||||
static const AppParameterTag sVCardListingTags[] = {
|
||||
AppParameterTag::Order,
|
||||
AppParameterTag::SearchValue,
|
||||
AppParameterTag::SearchProperty,
|
||||
AppParameterTag::MaxListCount,
|
||||
AppParameterTag::ListStartOffset,
|
||||
AppParameterTag::vCardSelector
|
||||
};
|
||||
|
||||
// App parameters to pull vCard entry
|
||||
static const AppParameterTag sVCardEntryTags[] = {
|
||||
AppParameterTag::Format,
|
||||
AppParameterTag::PropertySelector
|
||||
};
|
||||
|
||||
StaticRefPtr<BluetoothPbapManager> sPbapManager;
|
||||
static bool sInShutdown = false;
|
||||
}
|
||||
|
@ -261,7 +285,7 @@ BluetoothPbapManager::ReceiveSocketData(BluetoothSocket* aSocket,
|
|||
return;
|
||||
}
|
||||
|
||||
uint8_t response = SetPhoneBookPath(data[3], pktHeaders);
|
||||
ObexResponseCode response = SetPhoneBookPath(pktHeaders, data[3]);
|
||||
if (response != ObexResponseCode::Success) {
|
||||
ReplyError(response);
|
||||
return;
|
||||
|
@ -271,18 +295,22 @@ BluetoothPbapManager::ReceiveSocketData(BluetoothSocket* aSocket,
|
|||
break;
|
||||
}
|
||||
case ObexRequestCode::Get:
|
||||
// Section 6.2.2 "OBEX Headers in Multi-Packet Responses", IrOBEX 1.2
|
||||
// All OBEX request messages shall be sent as one OBEX packet containing
|
||||
// all of the headers. I.e. OBEX GET with opcode 0x83 shall always be
|
||||
// used. OBEX GET with opcode 0x03 shall never be used.
|
||||
/*
|
||||
* Section 6.2.2 "OBEX Headers in Multi-Packet Responses", IrOBEX 1.2
|
||||
* All OBEX request messages shall be sent as one OBEX packet containing
|
||||
* all the headers, i.e., OBEX GET with opcode 0x83 shall always be
|
||||
* used, and GET with opcode 0x03 shall never be used.
|
||||
*/
|
||||
BT_LOGR("PBAP shall always use OBEX GetFinal instead of Get.");
|
||||
|
||||
// no break. Treat 'Get' as 'GetFinal' for error tolerance.
|
||||
case ObexRequestCode::GetFinal: {
|
||||
// When |mVCardDataStream| requires multiple response packets to complete,
|
||||
// the client should continue to issue GET requests until the final body
|
||||
// information (i.e., End-of-Body header) arrives, along with
|
||||
// ObexResponseCode::Success
|
||||
/*
|
||||
* When |mVCardDataStream| requires multiple response packets to complete,
|
||||
* the client should continue to issue GET requests until the final body
|
||||
* information (i.e., End-of-Body header) arrives, along with
|
||||
* ObexResponseCode::Success
|
||||
*/
|
||||
if (mVCardDataStream) {
|
||||
if (!ReplyToGet()) {
|
||||
BT_LOGR("Failed to reply to PBAP GET request.");
|
||||
|
@ -300,33 +328,18 @@ BluetoothPbapManager::ReceiveSocketData(BluetoothSocket* aSocket,
|
|||
return;
|
||||
}
|
||||
|
||||
nsString type;
|
||||
pktHeaders.GetContentType(type);
|
||||
|
||||
uint8_t response;
|
||||
if (type.EqualsLiteral("x-bt/vcard-listing")) {
|
||||
response = PullvCardListing(pktHeaders);
|
||||
} else if (type.EqualsLiteral("x-bt/vcard")) {
|
||||
response = PullvCardEntry(pktHeaders);
|
||||
} else if (type.EqualsLiteral("x-bt/phonebook")) {
|
||||
response = PullPhonebook(pktHeaders);
|
||||
} else {
|
||||
response = ObexResponseCode::BadRequest;
|
||||
BT_LOGR("Unknown PBAP request type: %s",
|
||||
NS_ConvertUTF16toUTF8(type).get());
|
||||
}
|
||||
|
||||
// The OBEX success response will be sent after Gaia replies the PBAP
|
||||
// request.
|
||||
ObexResponseCode response = NotifyPbapRequest(pktHeaders);
|
||||
if (response != ObexResponseCode::Success) {
|
||||
ReplyError(response);
|
||||
return;
|
||||
}
|
||||
// OBEX success response will be sent after gaia replies PBAP request
|
||||
break;
|
||||
}
|
||||
case ObexRequestCode::Put:
|
||||
case ObexRequestCode::PutFinal:
|
||||
ReplyError(ObexResponseCode::BadRequest);
|
||||
BT_LOGR("Unsupported ObexRequestCode %x", opCode);
|
||||
break;
|
||||
default:
|
||||
ReplyError(ObexResponseCode::NotImplemented);
|
||||
|
@ -363,9 +376,9 @@ BluetoothPbapManager::CompareHeaderTarget(const ObexHeaderSet& aHeader)
|
|||
return true;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BluetoothPbapManager::SetPhoneBookPath(uint8_t flags,
|
||||
const ObexHeaderSet& aHeader)
|
||||
ObexResponseCode
|
||||
BluetoothPbapManager::SetPhoneBookPath(const ObexHeaderSet& aHeader,
|
||||
uint8_t flags)
|
||||
{
|
||||
// Section 5.2 "SetPhoneBook Function", PBAP 1.2
|
||||
// flags bit 1 must be 1 and bit 2~7 be 0
|
||||
|
@ -424,103 +437,66 @@ BluetoothPbapManager::SetPhoneBookPath(uint8_t flags,
|
|||
return ObexResponseCode::Success;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BluetoothPbapManager::PullPhonebook(const ObexHeaderSet& aHeader)
|
||||
ObexResponseCode
|
||||
BluetoothPbapManager::NotifyPbapRequest(const ObexHeaderSet& aHeader)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
if (!bs) {
|
||||
return ObexResponseCode::PreconditionFailed;
|
||||
}
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> data;
|
||||
|
||||
nsString name;
|
||||
// Get content type and name
|
||||
nsString type, name;
|
||||
aHeader.GetContentType(type);
|
||||
aHeader.GetName(name);
|
||||
|
||||
// Ensure the name of phonebook object is legal
|
||||
if (!IsLegalPhonebookName(name)) {
|
||||
BT_LOGR("Illegal phone book object name [%s]",
|
||||
NS_ConvertUTF16toUTF8(name).get());
|
||||
return ObexResponseCode::NotFound;
|
||||
// Configure request based on content type
|
||||
nsString reqId;
|
||||
uint8_t tagCount;
|
||||
const AppParameterTag* tags;
|
||||
if (type.EqualsLiteral("x-bt/phonebook")) {
|
||||
reqId.AssignLiteral(PULL_PHONEBOOK_REQ_ID);
|
||||
tagCount = MOZ_ARRAY_LENGTH(sPhonebookTags);
|
||||
tags = sPhonebookTags;
|
||||
|
||||
// Ensure the name of phonebook object is legal
|
||||
if (!IsLegalPhonebookName(name)) {
|
||||
BT_LOGR("Illegal phone book object name [%s]",
|
||||
NS_ConvertUTF16toUTF8(name).get());
|
||||
return ObexResponseCode::NotFound;
|
||||
}
|
||||
} else if (type.EqualsLiteral("x-bt/vcard-listing")) {
|
||||
reqId.AssignLiteral(PULL_VCARD_LISTING_REQ_ID);
|
||||
tagCount = MOZ_ARRAY_LENGTH(sVCardListingTags);
|
||||
tags = sVCardListingTags;
|
||||
|
||||
// Section 5.3.3 "Name", PBAP 1.2:
|
||||
// ... PullvCardListing function uses relative paths. An empty name header
|
||||
// may be sent to retrieve the vCard Listing object of the current folder.
|
||||
name = name.IsEmpty() ? mCurrentPath
|
||||
: mCurrentPath + NS_LITERAL_STRING("/") + name;
|
||||
} else if (type.EqualsLiteral("x-bt/vcard")) {
|
||||
reqId.AssignLiteral(PULL_VCARD_ENTRY_REQ_ID);
|
||||
tagCount = MOZ_ARRAY_LENGTH(sVCardEntryTags);
|
||||
tags = sVCardEntryTags;
|
||||
} else {
|
||||
BT_LOGR("Unknown PBAP request type: %s",
|
||||
NS_ConvertUTF16toUTF8(type).get());
|
||||
return ObexResponseCode::BadRequest;
|
||||
}
|
||||
|
||||
AppendNamedValue(data, "name", name);
|
||||
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::Format);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::PropertySelector);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::MaxListCount);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::ListStartOffset);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::vCardSelector);
|
||||
|
||||
bs->DistributeSignal(NS_LITERAL_STRING(PULL_PHONEBOOK_REQ_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
data);
|
||||
|
||||
return ObexResponseCode::Success;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BluetoothPbapManager::PullvCardListing(const ObexHeaderSet& aHeader)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Ensure bluetooth service is available
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
if (!bs) {
|
||||
BT_LOGR("Failed to get Bluetooth service");
|
||||
return ObexResponseCode::PreconditionFailed;
|
||||
}
|
||||
|
||||
// Pack PBAP request
|
||||
InfallibleTArray<BluetoothNamedValue> data;
|
||||
|
||||
nsString folderName;
|
||||
aHeader.GetName(folderName);
|
||||
|
||||
// Section 5.3.3 "Name", PBAP 1.2
|
||||
// ... PullvCardListing function uses relative paths. An empty name header may
|
||||
// be sent to retrieve the vCard Listing object of the current folder.
|
||||
nsString folderPath = mCurrentPath;
|
||||
if (!folderName.IsEmpty()) {
|
||||
folderPath += NS_LITERAL_STRING("/") + folderName;
|
||||
}
|
||||
AppendNamedValue(data, "name", folderPath);
|
||||
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::Order);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::SearchValue);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::SearchProperty);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::MaxListCount);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::ListStartOffset);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::vCardSelector);
|
||||
|
||||
bs->DistributeSignal(NS_LITERAL_STRING(PULL_VCARD_LISTING_REQ_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
data);
|
||||
|
||||
return ObexResponseCode::Success;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BluetoothPbapManager::PullvCardEntry(const ObexHeaderSet& aHeader)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
if (!bs) {
|
||||
return ObexResponseCode::PreconditionFailed;
|
||||
}
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> data;
|
||||
|
||||
nsString name;
|
||||
aHeader.GetName(name);
|
||||
AppendNamedValue(data, "name", name);
|
||||
for (uint8_t i = 0; i < tagCount; i++) {
|
||||
AppendNamedValueByTagId(aHeader, data, tags[i]);
|
||||
}
|
||||
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::Format);
|
||||
AppendNamedValueByTagId(aHeader, data, AppParameterTag::PropertySelector);
|
||||
|
||||
bs->DistributeSignal(NS_LITERAL_STRING(PULL_VCARD_ENTRY_REQ_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
data);
|
||||
bs->DistributeSignal(reqId, NS_LITERAL_STRING(KEY_ADAPTER), data);
|
||||
|
||||
return ObexResponseCode::Success;
|
||||
}
|
||||
|
@ -553,64 +529,41 @@ BluetoothPbapManager::AppendNamedValueByTagId(
|
|||
AppendNamedValue(aValues, "searchKey", searchKey);
|
||||
break;
|
||||
}
|
||||
case AppParameterTag::SearchValue: {
|
||||
case AppParameterTag::SearchValue:
|
||||
// Section 5.3.4.3 "SearchValue {<text string>}", PBAP 1.2
|
||||
// The UTF-8 character set shall be used for <text string>.
|
||||
|
||||
// Use nsCString to store UTF-8 string here to follow the suggestion of
|
||||
// 'MDN:Internal_strings'.
|
||||
nsCString text((char *) buf);
|
||||
|
||||
AppendNamedValue(aValues, "searchText", text);
|
||||
// Store UTF-8 string with nsCString to follow MDN:Internal_strings
|
||||
AppendNamedValue(aValues, "searchText", nsCString((char *) buf));
|
||||
break;
|
||||
}
|
||||
case AppParameterTag::MaxListCount: {
|
||||
uint16_t maxListCount = *((uint16_t *)buf);
|
||||
|
||||
// convert big endian to little endian
|
||||
maxListCount = (maxListCount >> 8) | (maxListCount << 8);
|
||||
|
||||
// Section 5 "Phone Book Access Profile Functions", PBAP 1.2
|
||||
// Replying 'PhonebookSize' is mandatory if 'MaxListCount' parameter is
|
||||
// present in the request with a value of 0, else it is excluded.
|
||||
mPhonebookSizeRequired = !maxListCount;
|
||||
|
||||
uint16_t maxListCount = ReadLittleEndianUInt16(buf);
|
||||
AppendNamedValue(aValues, "maxListCount",
|
||||
static_cast<uint32_t>(maxListCount));
|
||||
|
||||
// Section 5 "Phone Book Access Profile Functions", PBAP 1.2
|
||||
// Replying 'PhonebookSize' is mandatory if 'MaxListCount' parameter
|
||||
// is present in the request with a value of 0, else it is excluded.
|
||||
mPhonebookSizeRequired = !maxListCount;
|
||||
break;
|
||||
}
|
||||
case AppParameterTag::ListStartOffset: {
|
||||
uint16_t listStartOffset = *((uint16_t *)buf);
|
||||
|
||||
// convert big endian to little endian
|
||||
listStartOffset = (listStartOffset >> 8) | (listStartOffset << 8);
|
||||
|
||||
case AppParameterTag::ListStartOffset:
|
||||
AppendNamedValue(aValues, "listStartOffset",
|
||||
static_cast<uint32_t>(listStartOffset));
|
||||
static_cast<uint32_t>(ReadLittleEndianUInt16(buf)));
|
||||
break;
|
||||
}
|
||||
case AppParameterTag::PropertySelector: {
|
||||
InfallibleTArray<uint32_t> props = PackPropertiesMask(buf, 64);
|
||||
|
||||
AppendNamedValue(aValues, "propSelector", props);
|
||||
case AppParameterTag::PropertySelector:
|
||||
AppendNamedValue(aValues, "propSelector", PackPropertiesMask(buf, 64));
|
||||
break;
|
||||
}
|
||||
case AppParameterTag::Format: {
|
||||
bool usevCard3 = buf[0];
|
||||
AppendNamedValue(aValues, "format", usevCard3);
|
||||
case AppParameterTag::Format:
|
||||
AppendNamedValue(aValues, "format", static_cast<bool>(buf[0]));
|
||||
break;
|
||||
}
|
||||
case AppParameterTag::vCardSelector: {
|
||||
InfallibleTArray<uint32_t> props = PackPropertiesMask(buf, 64);
|
||||
|
||||
bool hasVCardSelectorOperator = aHeader.GetAppParameter(
|
||||
bool hasSelectorOperator = aHeader.GetAppParameter(
|
||||
AppParameterTag::vCardSelectorOperator, buf, 64);
|
||||
|
||||
if (hasVCardSelectorOperator && buf[0]) {
|
||||
AppendNamedValue(aValues, "vCardSelector_AND", BluetoothValue(props));
|
||||
} else {
|
||||
AppendNamedValue(aValues, "vCardSelector_OR", BluetoothValue(props));
|
||||
}
|
||||
AppendNamedValue(aValues,
|
||||
hasSelectorOperator && buf[0] ? "vCardSelector_AND"
|
||||
: "vCardSelector_OR",
|
||||
PackPropertiesMask(buf, 64));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -906,10 +859,7 @@ BluetoothPbapManager::ReplyToGet(uint16_t aPhonebookSize)
|
|||
|
||||
if (mPhonebookSizeRequired) {
|
||||
// ---- Part 2: [headerId:1][length:2][PhonebookSize:4] ---- //
|
||||
// convert little endian to big endian
|
||||
uint8_t phonebookSize[2];
|
||||
phonebookSize[0] = (aPhonebookSize & 0xFF00) >> 8;
|
||||
phonebookSize[1] = aPhonebookSize & 0x00FF;
|
||||
uint16_t pbSizeBigEndian = ConvertEndiannessUInt16(aPhonebookSize);
|
||||
|
||||
// Section 6.2.1 "Application Parameters Header", PBAP 1.2
|
||||
// appParameters: [headerId:1][length:2][PhonebookSize:4], where
|
||||
|
@ -917,9 +867,9 @@ BluetoothPbapManager::ReplyToGet(uint16_t aPhonebookSize)
|
|||
uint8_t appParameters[4];
|
||||
AppendAppParameter(appParameters,
|
||||
sizeof(appParameters),
|
||||
(uint8_t) AppParameterTag::PhonebookSize,
|
||||
phonebookSize,
|
||||
sizeof(phonebookSize));
|
||||
static_cast<uint8_t>(AppParameterTag::PhonebookSize),
|
||||
(uint8_t*) &pbSizeBigEndian,
|
||||
sizeof(pbSizeBigEndian));
|
||||
|
||||
index += AppendHeaderAppParameters(&res[index],
|
||||
mRemoteMaxPacketLength,
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#include "BluetoothSocketObserver.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
#include "mozilla/ipc/SocketBase.h"
|
||||
#include "ObexBase.h"
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Blob;
|
||||
|
@ -141,20 +141,18 @@ private:
|
|||
void ReplyToConnect();
|
||||
void ReplyToDisconnectOrAbort();
|
||||
void ReplyToSetPath();
|
||||
bool ReplyToGet(uint16_t aPhonebookSize = 0);
|
||||
void ReplyError(uint8_t aError);
|
||||
void SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize);
|
||||
bool ReplyToGet(uint16_t aPhonebookSize = 0);
|
||||
|
||||
uint8_t SetPhoneBookPath(uint8_t flags, const ObexHeaderSet& aHeader);
|
||||
uint8_t PullPhonebook(const ObexHeaderSet& aHeader);
|
||||
uint8_t PullvCardListing(const ObexHeaderSet& aHeader);
|
||||
uint8_t PullvCardEntry(const ObexHeaderSet& aHeader);
|
||||
void AppendNamedValueByTagId(
|
||||
const ObexHeaderSet& aHeader,
|
||||
InfallibleTArray<BluetoothNamedValue>& aValues,
|
||||
const AppParameterTag aTagId);
|
||||
ObexResponseCode SetPhoneBookPath(const ObexHeaderSet& aHeader,
|
||||
uint8_t flags);
|
||||
ObexResponseCode NotifyPbapRequest(const ObexHeaderSet& aHeader);
|
||||
void AppendNamedValueByTagId(const ObexHeaderSet& aHeader,
|
||||
InfallibleTArray<BluetoothNamedValue>& aValues,
|
||||
const AppParameterTag aTagId);
|
||||
|
||||
InfallibleTArray<uint32_t> PackPropertiesMask(uint8_t* aData, int aSize);
|
||||
InfallibleTArray<uint32_t> PackPropertiesMask(uint8_t* aData, int aSize);
|
||||
bool CompareHeaderTarget(const ObexHeaderSet& aHeader);
|
||||
bool IsLegalPath(const nsAString& aPath);
|
||||
bool IsLegalPhonebookName(const nsAString& aName);
|
||||
|
|
|
@ -604,4 +604,16 @@ InsertNamedValue(InfallibleTArray<BluetoothNamedValue>& aArray,
|
|||
aArray.InsertElementAt(aIndex, BluetoothNamedValue(name, aValue));
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ConvertEndiannessUInt16(uint16_t aValue)
|
||||
{
|
||||
return (aValue >> 8) | (aValue << 8);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ReadLittleEndianUInt16(const uint8_t* aBuf)
|
||||
{
|
||||
return ConvertEndiannessUInt16(*((uint16_t *) aBuf));
|
||||
}
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
|
|
@ -272,6 +272,20 @@ void InsertNamedValue(InfallibleTArray<BluetoothNamedValue>& aArray,
|
|||
uint8_t aIndex, const char* aName,
|
||||
const BluetoothValue& aValue);
|
||||
|
||||
//
|
||||
// Big/Little endianness conversion
|
||||
//
|
||||
|
||||
/**
|
||||
* Convert a big/little endian uint16_t value to little/big endian one.
|
||||
*/
|
||||
uint16_t ConvertEndiannessUInt16(uint16_t aValue);
|
||||
|
||||
/**
|
||||
* Read an uint16_t from array and convert it to little endian one.
|
||||
*/
|
||||
uint16_t ReadLittleEndianUInt16(const uint8_t* aBuf);
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_bluetooth_BluetoothUtils_h
|
||||
|
|
|
@ -6,7 +6,6 @@ support-files =
|
|||
[test_Document-createElement-namespace.html.json]
|
||||
[test_Document-createElementNS.html.json]
|
||||
[test_Document-getElementsByTagName.html.json]
|
||||
[test_Node-isEqualNode.xhtml.json]
|
||||
[test_Node-properties.html.json]
|
||||
[test_attributes.html.json]
|
||||
[test_case.html.json]
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"isEqualNode should return true when only the internal subsets of DocumentTypes differ.": true
|
||||
}
|
|
@ -3,10 +3,7 @@
|
|||
support-files =
|
||||
|
||||
|
||||
[test_document.title-03.html.json]
|
||||
[test_document.title-04.xhtml.json]
|
||||
[test_document.title-06.html.json]
|
||||
[test_document.title-07.html.json]
|
||||
[test_nameditem-02.html.json]
|
||||
[test_nameditem-03.html.json]
|
||||
[test_nameditem-04.html.json]
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
" document.title and space normalization ": true
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
" document.title and space normalization ": true
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"Document.title and DOMImplementation.createHTMLDocument 6": true
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
|
||||
|
||||
[test_option-text-spaces.html.json]
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"option.text should strip leading space characters (\"\\f\")": true,
|
||||
"option.text should strip trailing space characters (\"\\f\")": true,
|
||||
"option.text should strip leading and trailing space characters (\"\\f\")": true,
|
||||
"option.text should replace single internal space characters (\"\\f\")": true,
|
||||
"option.text should replace multiple internal space characters (\" \", \"\\f\")": true,
|
||||
"option.text should replace multiple internal space characters (\"\\t\", \"\\f\")": true,
|
||||
"option.text should replace multiple internal space characters (\"\\n\", \"\\f\")": true,
|
||||
"option.text should replace multiple internal space characters (\"\\f\", \" \")": true,
|
||||
"option.text should replace multiple internal space characters (\"\\f\", \"\\t\")": true,
|
||||
"option.text should replace multiple internal space characters (\"\\f\", \"\\n\")": true,
|
||||
"option.text should replace multiple internal space characters (\"\\f\", \"\\f\")": true,
|
||||
"option.text should replace multiple internal space characters (\"\\f\", \"\\r\")": true,
|
||||
"option.text should replace multiple internal space characters (\"\\r\", \"\\f\")": true
|
||||
}
|
|
@ -24,7 +24,6 @@ MOCHITEST_MANIFESTS += [
|
|||
'failures/html/html/dom/documents/dta/doc.gEBN/mochitest.ini',
|
||||
'failures/html/html/dom/documents/dta/mochitest.ini',
|
||||
'failures/html/html/obsolete/implreq/oeaaa/mochitest.ini',
|
||||
'failures/html/html/semantics/forms/the-option-element/mochitest.ini',
|
||||
'failures/html/html/semantics/forms/the-select-element/mochitest.ini',
|
||||
'failures/html/html/semantics/scripting-1/the-script-element/mochitest.ini',
|
||||
'failures/html/html/semantics/tabular-data/the-table-element/mochitest.ini',
|
||||
|
|
|
@ -146,11 +146,11 @@ class VersionChangeTransaction;
|
|||
|
||||
// If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
|
||||
// schema version.
|
||||
static_assert(JS_STRUCTURED_CLONE_VERSION == 5,
|
||||
static_assert(JS_STRUCTURED_CLONE_VERSION == 6,
|
||||
"Need to update the major schema version.");
|
||||
|
||||
// Major schema version. Bump for almost everything.
|
||||
const uint32_t kMajorSchemaVersion = 21;
|
||||
const uint32_t kMajorSchemaVersion = 22;
|
||||
|
||||
// Minor schema version. Should almost always be 0 (maybe bump on release
|
||||
// branches if we have to).
|
||||
|
@ -4066,6 +4066,19 @@ UpgradeSchemaFrom20_0To21_0(mozIStorageConnection* aConnection)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
UpgradeSchemaFrom21_0To22_0(mozIStorageConnection* aConnection)
|
||||
{
|
||||
// The only change between 21 and 22 was a different structured clone format,
|
||||
// but it's backwards-compatible.
|
||||
nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(22, 0));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetDatabaseFileURL(nsIFile* aDatabaseFile,
|
||||
PersistenceType aPersistenceType,
|
||||
|
@ -4558,7 +4571,7 @@ CreateStorageConnection(nsIFile* aDBFile,
|
|||
}
|
||||
} else {
|
||||
// This logic needs to change next time we change the schema!
|
||||
static_assert(kSQLiteSchemaVersion == int32_t((21 << 4) + 0),
|
||||
static_assert(kSQLiteSchemaVersion == int32_t((22 << 4) + 0),
|
||||
"Upgrade function needed due to schema version increase.");
|
||||
|
||||
while (schemaVersion != kSQLiteSchemaVersion) {
|
||||
|
@ -4598,6 +4611,8 @@ CreateStorageConnection(nsIFile* aDBFile,
|
|||
rv = UpgradeSchemaFrom19_0To20_0(aFMDirectory, connection);
|
||||
} else if (schemaVersion == MakeSchemaVersion(20, 0)) {
|
||||
rv = UpgradeSchemaFrom20_0To21_0(connection);
|
||||
} else if (schemaVersion == MakeSchemaVersion(21, 0)) {
|
||||
rv = UpgradeSchemaFrom21_0To22_0(connection);
|
||||
} else {
|
||||
IDB_WARNING("Unable to open IndexedDB database, no upgrade path is "
|
||||
"available!");
|
||||
|
|
|
@ -299,6 +299,43 @@ PreallocatedProcessManagerImpl::GetSpareProcess()
|
|||
return process.forget();
|
||||
}
|
||||
|
||||
static bool
|
||||
TestCaseEnabled()
|
||||
{
|
||||
return Preferences::GetBool("dom.ipc.preallocatedProcessManager.testMode");
|
||||
}
|
||||
|
||||
static void
|
||||
SendTestOnlyNotification(const char* aMessage)
|
||||
{
|
||||
if (!TestCaseEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
nsString message;
|
||||
message.AppendPrintf("%s", aMessage);
|
||||
|
||||
nsCOMPtr<nsIMessageBroadcaster> ppmm =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
|
||||
mozilla::unused << ppmm->BroadcastAsyncMessage(
|
||||
message, JS::NullHandleValue, JS::NullHandleValue, cx, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
KillOrCloseProcess(ContentParent* aProcess)
|
||||
{
|
||||
if (TestCaseEnabled()) {
|
||||
// KillHard() the process because we don't want the process to abort when we
|
||||
// close the IPC channel while it's still running and creating actors.
|
||||
aProcess->KillHard("Killed by test case.");
|
||||
}
|
||||
else {
|
||||
aProcess->Close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a ContentParent to spare process list.
|
||||
*/
|
||||
|
@ -307,14 +344,7 @@ PreallocatedProcessManagerImpl::PublishSpareProcess(ContentParent* aContent)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (Preferences::GetBool("dom.ipc.preallocatedProcessManager.testMode")) {
|
||||
AutoJSContext cx;
|
||||
nsCOMPtr<nsIMessageBroadcaster> ppmm =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
mozilla::unused << ppmm->BroadcastAsyncMessage(
|
||||
NS_LITERAL_STRING("TEST-ONLY:nuwa-add-new-process"),
|
||||
JS::NullHandleValue, JS::NullHandleValue, cx, 1);
|
||||
}
|
||||
SendTestOnlyNotification("TEST-ONLY:nuwa-add-new-process");
|
||||
|
||||
mSpareProcesses.AppendElement(aContent);
|
||||
}
|
||||
|
@ -333,7 +363,7 @@ PreallocatedProcessManagerImpl::MaybeForgetSpare(ContentParent* aContent)
|
|||
mIsNuwaReady = false;
|
||||
while (mSpareProcesses.Length() > 0) {
|
||||
nsRefPtr<ContentParent> process = mSpareProcesses[mSpareProcesses.Length() - 1];
|
||||
process->Close();
|
||||
KillOrCloseProcess(aContent);
|
||||
mSpareProcesses.RemoveElementAt(mSpareProcesses.Length() - 1);
|
||||
}
|
||||
ScheduleDelayedNuwaFork();
|
||||
|
@ -353,14 +383,8 @@ PreallocatedProcessManagerImpl::OnNuwaReady()
|
|||
ProcessPriorityManager::SetProcessPriority(mPreallocatedAppProcess,
|
||||
hal::PROCESS_PRIORITY_MASTER);
|
||||
mIsNuwaReady = true;
|
||||
if (Preferences::GetBool("dom.ipc.preallocatedProcessManager.testMode")) {
|
||||
AutoJSContext cx;
|
||||
nsCOMPtr<nsIMessageBroadcaster> ppmm =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
mozilla::unused << ppmm->BroadcastAsyncMessage(
|
||||
NS_LITERAL_STRING("TEST-ONLY:nuwa-ready"),
|
||||
JS::NullHandleValue, JS::NullHandleValue, cx, 1);
|
||||
}
|
||||
SendTestOnlyNotification("TEST-ONLY:nuwa-ready");
|
||||
|
||||
NuwaFork();
|
||||
}
|
||||
|
||||
|
@ -370,7 +394,6 @@ PreallocatedProcessManagerImpl::PreallocatedProcessReady()
|
|||
return !mSpareProcesses.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::NuwaFork()
|
||||
{
|
||||
|
@ -399,7 +422,7 @@ PreallocatedProcessManagerImpl::Disable()
|
|||
#ifdef MOZ_NUWA_PROCESS
|
||||
while (mSpareProcesses.Length() > 0){
|
||||
nsRefPtr<ContentParent> process = mSpareProcesses[0];
|
||||
process->Close();
|
||||
KillOrCloseProcess(process);
|
||||
mSpareProcesses.RemoveElementAt(0);
|
||||
}
|
||||
mIsNuwaReady = false;
|
||||
|
|
|
@ -257,6 +257,10 @@ HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
|
|||
|
||||
HangMonitorChild::~HangMonitorChild()
|
||||
{
|
||||
// For some reason IPDL doesn't automatically delete the channel for a
|
||||
// bridged protocol (bug 1090570). So we have to do it ourselves.
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask<Transport>(GetTransport()));
|
||||
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(sInstance == this);
|
||||
sInstance = nullptr;
|
||||
|
@ -469,7 +473,7 @@ DeleteMinidump(const uint32_t& aPluginId, nsString aCrashId, void* aUserData)
|
|||
|
||||
HangMonitorParent::~HangMonitorParent()
|
||||
{
|
||||
// For some reason IPDL doesn't autmatically delete the channel for a
|
||||
// For some reason IPDL doesn't automatically delete the channel for a
|
||||
// bridged protocol (bug 1090570). So we have to do it ourselves.
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask<Transport>(GetTransport()));
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'androi
|
|||
[test_cpow_cookies.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet'
|
||||
[test_NuwaProcessCreation.html]
|
||||
skip-if = true # bug 1166923
|
||||
skip-if = toolkit != 'gonk'
|
||||
[test_NuwaProcessDeadlock.html]
|
||||
skip-if = true # bug 1166923
|
||||
[test_child_docshell.html]
|
||||
|
|
|
@ -14,6 +14,9 @@ Test if Nuwa process created successfully.
|
|||
|
||||
function runTest()
|
||||
{
|
||||
info("Shut down processes by disabling process prelaunch");
|
||||
SpecialPowers.setBoolPref('dom.ipc.processPrelaunch.enabled', false);
|
||||
|
||||
info("Launch the Nuwa process");
|
||||
let cpmm = SpecialPowers.Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsISyncMessageSender);
|
||||
|
@ -22,12 +25,11 @@ function runTest()
|
|||
receiveMessage: function receiveMessage(msg) {
|
||||
msg = SpecialPowers.wrap(msg);
|
||||
if (msg.name == 'TEST-ONLY:nuwa-ready') {
|
||||
ok(true, "Got nuwa-ready");
|
||||
is(seenNuwaReady, false, "Already received nuwa ready");
|
||||
is(seenNuwaReady, false, "The Nuwa process is launched");
|
||||
seenNuwaReady = true;
|
||||
} else if (msg.name == 'TEST-ONLY:nuwa-add-new-process') {
|
||||
ok(true, "Got nuwa-add-new-process");
|
||||
is(seenNuwaReady, true, "Receive nuwa-add-new-process before nuwa-ready");
|
||||
is(seenNuwaReady, true, "The preallocated process is launched from the Nuwa process");
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +58,6 @@ function setup()
|
|||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
'set': [
|
||||
['dom.ipc.processPrelaunch.enabled', false],
|
||||
['dom.ipc.preallocatedProcessManager.testMode', true]
|
||||
]
|
||||
}, runTest);
|
||||
|
|
|
@ -98,7 +98,14 @@ MobileMessageDatabaseService::MarkMessageRead(int32_t aMessageId,
|
|||
bool aSendReadReport,
|
||||
nsIMobileMessageCallback* aRequest)
|
||||
{
|
||||
// TODO: This would need to be implemented as part of Bug 748391
|
||||
if (!AndroidBridge::Bridge()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AndroidBridge::Bridge()->MarkMessageRead(aMessageId,
|
||||
aValue,
|
||||
aSendReadReport,
|
||||
aRequest);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -393,5 +393,36 @@ SmsManager::NotifyCursorDone(int32_t aRequestId)
|
|||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
/*static*/
|
||||
void
|
||||
SmsManager::NotifySmsMarkedAsRead(bool aMarkedAsRead, int32_t aRequestId)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([=]() {
|
||||
nsCOMPtr<nsIMobileMessageCallback> request =
|
||||
AndroidBridge::Bridge()->DequeueSmsRequest(aRequestId);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
||||
request->NotifyMessageMarkedRead(aMarkedAsRead);
|
||||
});
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void
|
||||
SmsManager::NotifySmsMarkAsReadFailed(int32_t aError, int32_t aRequestId)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([=]() {
|
||||
nsCOMPtr<nsIMobileMessageCallback> request =
|
||||
AndroidBridge::Bridge()->DequeueSmsRequest(aRequestId);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
||||
request->NotifyMarkMessageReadFailed(aError);
|
||||
});
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -66,6 +66,8 @@ public:
|
|||
bool aRead,
|
||||
int32_t aRequestId);
|
||||
static void NotifyCursorDone(int32_t aRequestId);
|
||||
static void NotifySmsMarkedAsRead(bool aMarkedAsRead, int32_t aRequestId);
|
||||
static void NotifySmsMarkAsReadFailed(int32_t aError, int32_t aRequestId);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -161,7 +161,7 @@ PluginModuleChild::PluginModuleChild(bool aIsChrome)
|
|||
PluginModuleChild::~PluginModuleChild()
|
||||
{
|
||||
if (mTransport) {
|
||||
// For some reason IPDL doesn't autmatically delete the channel for a
|
||||
// For some reason IPDL doesn't automatically delete the channel for a
|
||||
// bridged protocol (bug 1090570). So we have to do it ourselves. This
|
||||
// code is only invoked for PluginModuleChild instances created via
|
||||
// bridging; otherwise mTransport is null.
|
||||
|
|
|
@ -690,6 +690,9 @@ PluginModuleContentParent::PluginModuleContentParent(bool aAllowAsyncInit)
|
|||
|
||||
PluginModuleContentParent::~PluginModuleContentParent()
|
||||
{
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new DeleteTask<Transport>(GetTransport()));
|
||||
|
||||
Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
|
||||
}
|
||||
|
||||
|
|
|
@ -96,16 +96,12 @@ NS_NewXMLContentSink(nsIXMLContentSink** aResult,
|
|||
}
|
||||
|
||||
nsXMLContentSink::nsXMLContentSink()
|
||||
: mConstrainSize(true),
|
||||
mPrettyPrintXML(true)
|
||||
: mPrettyPrintXML(true)
|
||||
{
|
||||
}
|
||||
|
||||
nsXMLContentSink::~nsXMLContentSink()
|
||||
{
|
||||
if (mText) {
|
||||
PR_Free(mText); // Doesn't null out, unlike PR_FREEIF
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -475,7 +471,6 @@ nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
|
|||
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
|
||||
sele->SetScriptLineNumber(aLineNumber);
|
||||
sele->SetCreatorParser(GetParser());
|
||||
mConstrainSize = false;
|
||||
}
|
||||
|
||||
// XHTML needs some special attention
|
||||
|
@ -552,7 +547,6 @@ nsXMLContentSink::CloseElement(nsIContent* aContent)
|
|||
if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
|
||||
|| nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
|
||||
) {
|
||||
mConstrainSize = true;
|
||||
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
|
||||
|
||||
if (mPreventScriptExecution) {
|
||||
|
@ -778,26 +772,19 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode)
|
|||
|
||||
if (mTextLength != 0) {
|
||||
if (mLastTextNode) {
|
||||
if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) {
|
||||
mLastTextNodeSize = 0;
|
||||
mLastTextNode = nullptr;
|
||||
FlushText(aReleaseTextNode);
|
||||
} else {
|
||||
bool notify = HaveNotifiedForCurrentContent();
|
||||
// We could probably always increase mInNotification here since
|
||||
// if AppendText doesn't notify it shouldn't trigger evil code.
|
||||
// But just in case it does, we don't want to mask any notifications.
|
||||
if (notify) {
|
||||
++mInNotification;
|
||||
}
|
||||
rv = mLastTextNode->AppendText(mText, mTextLength, notify);
|
||||
if (notify) {
|
||||
--mInNotification;
|
||||
}
|
||||
|
||||
mLastTextNodeSize += mTextLength;
|
||||
mTextLength = 0;
|
||||
bool notify = HaveNotifiedForCurrentContent();
|
||||
// We could probably always increase mInNotification here since
|
||||
// if AppendText doesn't notify it shouldn't trigger evil code.
|
||||
// But just in case it does, we don't want to mask any notifications.
|
||||
if (notify) {
|
||||
++mInNotification;
|
||||
}
|
||||
rv = mLastTextNode->AppendText(mText, mTextLength, notify);
|
||||
if (notify) {
|
||||
--mInNotification;
|
||||
}
|
||||
|
||||
mTextLength = 0;
|
||||
} else {
|
||||
nsRefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager);
|
||||
|
||||
|
@ -805,7 +792,6 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode)
|
|||
|
||||
// Set the text in the text node
|
||||
textContent->SetText(mText, mTextLength, false);
|
||||
mLastTextNodeSize += mTextLength;
|
||||
mTextLength = 0;
|
||||
|
||||
// Add text to its parent
|
||||
|
@ -814,7 +800,6 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode)
|
|||
}
|
||||
|
||||
if (aReleaseTextNode) {
|
||||
mLastTextNodeSize = 0;
|
||||
mLastTextNode = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1437,41 +1422,19 @@ nsresult
|
|||
nsXMLContentSink::AddText(const char16_t* aText,
|
||||
int32_t aLength)
|
||||
{
|
||||
// Create buffer when we first need it
|
||||
if (0 == mTextSize) {
|
||||
mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE);
|
||||
if (nullptr == mText) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mTextSize = NS_ACCUMULATION_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Copy data from string into our buffer; flush buffer when it fills up
|
||||
// Copy data from string into our buffer; flush buffer when it fills up.
|
||||
int32_t offset = 0;
|
||||
while (0 != aLength) {
|
||||
int32_t amount = mTextSize - mTextLength;
|
||||
int32_t amount = NS_ACCUMULATION_BUFFER_SIZE - mTextLength;
|
||||
if (0 == amount) {
|
||||
// XSLT wants adjacent textnodes merged.
|
||||
if (mConstrainSize && !mXSLTProcessor) {
|
||||
nsresult rv = FlushText();
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
amount = mTextSize - mTextLength;
|
||||
}
|
||||
else {
|
||||
mTextSize += aLength;
|
||||
mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize);
|
||||
if (nullptr == mText) {
|
||||
mTextSize = 0;
|
||||
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
amount = aLength;
|
||||
nsresult rv = FlushText(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
MOZ_ASSERT(mTextLength == 0);
|
||||
amount = NS_ACCUMULATION_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
if (amount > aLength) {
|
||||
amount = aLength;
|
||||
}
|
||||
|
|
|
@ -171,18 +171,15 @@ protected:
|
|||
|
||||
nsCOMPtr<nsIContent> mDocElement;
|
||||
nsCOMPtr<nsIContent> mCurrentHead; // When set, we're in an XHTML <haed>
|
||||
char16_t* mText;
|
||||
|
||||
XMLContentSinkState mState;
|
||||
|
||||
// The length of the valid data in mText.
|
||||
int32_t mTextLength;
|
||||
int32_t mTextSize;
|
||||
|
||||
int32_t mNotifyLevel;
|
||||
nsCOMPtr<nsIContent> mLastTextNode;
|
||||
int32_t mLastTextNodeSize;
|
||||
|
||||
uint8_t mConstrainSize : 1;
|
||||
uint8_t mPrettyPrintXML : 1;
|
||||
uint8_t mPrettyPrintHasSpecialRoot : 1;
|
||||
uint8_t mPrettyPrintHasFactoredElements : 1;
|
||||
|
@ -194,6 +191,10 @@ protected:
|
|||
nsTArray<StackNode> mContentStack;
|
||||
|
||||
nsCOMPtr<nsIDocumentTransformer> mXSLTProcessor;
|
||||
|
||||
static const int NS_ACCUMULATION_BUFFER_SIZE = 4096;
|
||||
// Our currently accumulated text that we have not flushed to a textnode yet.
|
||||
char16_t mText[NS_ACCUMULATION_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
#endif // nsXMLContentSink_h__
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/gfx/JobScheduler.h"
|
||||
#include "mozilla/gfx/IterableArena.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include "mozilla/gfx/JobScheduler_win32.h"
|
||||
|
@ -247,4 +248,4 @@ protected:
|
|||
} // namespace
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/gfx/CriticalSection.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/gfx/CriticalSection.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef OSType (*IOSurfacePixelFormatFunc)(IOSurfacePtr io_surface);
|
|||
#import <OpenGL/OpenGL.h>
|
||||
#include "2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
struct _CGLContextObject;
|
||||
|
||||
|
|
|
@ -101,11 +101,13 @@ DCFromDrawTarget::DCFromDrawTarget(DrawTarget& aDrawTarget)
|
|||
cairo_win32_scaled_font_select_font(scaled, mDC);
|
||||
}
|
||||
}
|
||||
if (!mDC) {
|
||||
mDC = GetDC(nullptr);
|
||||
SetGraphicsMode(mDC, GM_ADVANCED);
|
||||
mNeedsRelease = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDC) {
|
||||
// Get the whole screen DC:
|
||||
mDC = GetDC(nullptr);
|
||||
SetGraphicsMode(mDC, GM_ADVANCED);
|
||||
mNeedsRelease = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -684,10 +686,13 @@ gfxPlatformFontList*
|
|||
gfxWindowsPlatform::CreatePlatformFontList()
|
||||
{
|
||||
gfxPlatformFontList *pfl;
|
||||
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
// bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd
|
||||
// crashers so blacklist them altogether
|
||||
if (IsNotWin7PreRTM() && GetDWriteFactory()) {
|
||||
if (IsNotWin7PreRTM() && GetDWriteFactory() &&
|
||||
// Skia doesn't support DirectWrite fonts yet.
|
||||
(gfxPlatform::GetDefaultContentBackend() != BackendType::SKIA)) {
|
||||
pfl = new gfxDWriteFontList();
|
||||
if (NS_SUCCEEDED(pfl->InitFontList())) {
|
||||
return pfl;
|
||||
|
|
|
@ -1221,9 +1221,6 @@ VectorImage::OnSVGDocumentError()
|
|||
{
|
||||
CancelAllListeners();
|
||||
|
||||
// XXXdholbert Need to do something more for the parsing failed case -- right
|
||||
// now, this just makes us draw the "object" icon, rather than the (jagged)
|
||||
// "broken image" icon. See bug 594505.
|
||||
mError = true;
|
||||
|
||||
if (mProgressTracker) {
|
||||
|
|
|
@ -121,7 +121,7 @@ typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwne
|
|||
// Increment this when anything at all changes in the serialization format.
|
||||
// (Note that this does not need to be bumped for Transferable-only changes,
|
||||
// since they are never saved to persistent storage.)
|
||||
#define JS_STRUCTURED_CLONE_VERSION 5
|
||||
#define JS_STRUCTURED_CLONE_VERSION 6
|
||||
|
||||
struct JSStructuredCloneCallbacks {
|
||||
ReadStructuredCloneOp read;
|
||||
|
|
|
@ -2216,6 +2216,15 @@ GetPropertyIC::maybeDisable(bool emitted)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!canAttachStub() && id().constant()) {
|
||||
// Don't disable the cache (and discard stubs) if we have a GETPROP and
|
||||
// attached the maximum number of stubs. This can happen when JS code
|
||||
// uses an AST-like data structure and accesses a field of a "base
|
||||
// class", like node.nodeType. This should be temporary until we handle
|
||||
// this case better, see bug 1107515.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canAttachStub() || (stubCount_ == 0 && failedUpdates_ > MAX_FAILED_UPDATES)) {
|
||||
JitSpew(JitSpew_IonIC, "Disable inline cache");
|
||||
disable();
|
||||
|
|
|
@ -2339,9 +2339,9 @@ MacroAssemblerARMCompat::store32(Imm32 src, const Address& address)
|
|||
void
|
||||
MacroAssemblerARMCompat::store32(Imm32 imm, const BaseIndex& dest)
|
||||
{
|
||||
AutoRegisterScope scratch2(asMasm(), secondScratchReg_);
|
||||
ma_mov(imm, scratch2);
|
||||
store32(scratch2, dest);
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
ma_mov(imm, scratch);
|
||||
store32(scratch, dest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2350,11 +2350,11 @@ MacroAssemblerARMCompat::store32(Register src, const BaseIndex& dest)
|
|||
Register base = dest.base;
|
||||
uint32_t scale = Imm32::ShiftOf(dest.scale).value;
|
||||
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
AutoRegisterScope scratch2(asMasm(), secondScratchReg_);
|
||||
|
||||
if (dest.offset != 0) {
|
||||
ma_add(base, Imm32(dest.offset), scratch);
|
||||
base = scratch;
|
||||
ma_add(base, Imm32(dest.offset), scratch2);
|
||||
base = scratch2;
|
||||
}
|
||||
ma_str(src, DTRAddr(base, DtrRegImmShift(dest.index, LSL, scale)));
|
||||
}
|
||||
|
|
|
@ -480,12 +480,31 @@ AssemblerMIPSShared::as_addiu(Register rd, Register rs, int32_t j)
|
|||
return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_daddu(Register rd, Register rs, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_daddu).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_daddiu(Register rd, Register rs, int32_t j)
|
||||
{
|
||||
MOZ_ASSERT(Imm16::IsInSignedRange(j));
|
||||
return writeInst(InstImm(op_daddiu, rs, rd, Imm16(j)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_subu(Register rd, Register rs, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsubu(Register rd, Register rs, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_dsubu).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_mult(Register rs, Register rt)
|
||||
{
|
||||
|
@ -498,6 +517,18 @@ AssemblerMIPSShared::as_multu(Register rs, Register rt)
|
|||
return writeInst(InstReg(op_special, rs, rt, ff_multu).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dmult(Register rs, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, ff_dmult).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dmultu(Register rs, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, ff_dmultu).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_div(Register rs, Register rt)
|
||||
{
|
||||
|
@ -510,6 +541,18 @@ AssemblerMIPSShared::as_divu(Register rs, Register rt)
|
|||
return writeInst(InstReg(op_special, rs, rt, ff_divu).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ddiv(Register rs, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, ff_ddiv).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ddivu(Register rs, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, ff_ddivu).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_mul(Register rd, Register rs, Register rt)
|
||||
{
|
||||
|
@ -531,12 +574,32 @@ AssemblerMIPSShared::as_sll(Register rd, Register rt, uint16_t sa)
|
|||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsll(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
MOZ_ASSERT(sa < 32);
|
||||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsll).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsll32(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
MOZ_ASSERT(31 < sa && sa < 64);
|
||||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsll32).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_sllv(Register rd, Register rt, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsllv(Register rd, Register rt, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_dsllv).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_srl(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
|
@ -544,12 +607,32 @@ AssemblerMIPSShared::as_srl(Register rd, Register rt, uint16_t sa)
|
|||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsrl(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
MOZ_ASSERT(sa < 32);
|
||||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsrl).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsrl32(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
MOZ_ASSERT(31 < sa && sa < 64);
|
||||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsrl32).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_srlv(Register rd, Register rt, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsrlv(Register rd, Register rt, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrlv).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_sra(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
|
@ -557,12 +640,32 @@ AssemblerMIPSShared::as_sra(Register rd, Register rt, uint16_t sa)
|
|||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsra(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
MOZ_ASSERT(sa < 32);
|
||||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsra).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsra32(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
MOZ_ASSERT(31 < sa && sa < 64);
|
||||
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsra32).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_srav(Register rd, Register rt, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dsrav(Register rd, Register rt, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrav).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_rotr(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
|
@ -570,12 +673,32 @@ AssemblerMIPSShared::as_rotr(Register rd, Register rt, uint16_t sa)
|
|||
return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_drotr(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
MOZ_ASSERT(sa < 32);
|
||||
return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_dsrl).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_drotr32(Register rd, Register rt, uint16_t sa)
|
||||
{
|
||||
MOZ_ASSERT(31 < sa && sa < 64);
|
||||
return writeInst(InstReg(op_special, rs_one, rt, rd, sa - 32, ff_dsrl32).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_rotrv(Register rd, Register rt, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_drotrv(Register rd, Register rt, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_dsrlv).encode());
|
||||
}
|
||||
|
||||
// Load and store instructions
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_lb(Register rd, Register rs, int16_t off)
|
||||
|
@ -607,6 +730,12 @@ AssemblerMIPSShared::as_lw(Register rd, Register rs, int16_t off)
|
|||
return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_lwu(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_lwu, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_lwl(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
|
@ -619,6 +748,30 @@ AssemblerMIPSShared::as_lwr(Register rd, Register rs, int16_t off)
|
|||
return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ll(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_ll, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ld(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_ld, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ldl(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_ldl, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ldr(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_ldr, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_sb(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
|
@ -649,6 +802,30 @@ AssemblerMIPSShared::as_swr(Register rd, Register rs, int16_t off)
|
|||
return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_sc(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_sc, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_sd(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_sd, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_sdl(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_sdl, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_sdr(Register rd, Register rs, int16_t off)
|
||||
{
|
||||
return writeInst(InstImm(op_sdr, rs, rd, Imm16(off)).encode());
|
||||
}
|
||||
|
||||
// Move from HI/LO register.
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_mfhi(Register rd)
|
||||
|
@ -725,6 +902,12 @@ AssemblerMIPSShared::as_clz(Register rd, Register rs)
|
|||
return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dclz(Register rd, Register rs)
|
||||
{
|
||||
return writeInst(InstReg(op_special2, rs, rd, rd, ff_dclz).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size)
|
||||
{
|
||||
|
@ -734,6 +917,33 @@ AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos, uint16_t siz
|
|||
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dins(Register rt, Register rs, uint16_t pos, uint16_t size)
|
||||
{
|
||||
MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32);
|
||||
Register rd;
|
||||
rd = Register::FromCode(pos + size - 1);
|
||||
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dins).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size)
|
||||
{
|
||||
MOZ_ASSERT(pos < 32 && size >= 2 && size <= 64 && pos + size > 32 && pos + size <= 64);
|
||||
Register rd;
|
||||
rd = Register::FromCode(pos + size - 1 - 32);
|
||||
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dinsm).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size)
|
||||
{
|
||||
MOZ_ASSERT(pos >= 32 && pos < 64 && size >= 1 && size <= 32 && pos + size > 32 && pos + size <= 64);
|
||||
Register rd;
|
||||
rd = Register::FromCode(pos + size - 1 - 32);
|
||||
return writeInst(InstReg(op_special3, rs, rt, rd, pos - 32, ff_dinsu).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size)
|
||||
{
|
||||
|
@ -743,6 +953,46 @@ AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos, uint16_t siz
|
|||
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
|
||||
}
|
||||
|
||||
// Sign extend
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_seb(Register rd, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special3, zero, rt, rd, 16, ff_bshfl).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_seh(Register rd, Register rt)
|
||||
{
|
||||
return writeInst(InstReg(op_special3, zero, rt, rd, 24, ff_bshfl).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dext(Register rt, Register rs, uint16_t pos, uint16_t size)
|
||||
{
|
||||
MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 63);
|
||||
Register rd;
|
||||
rd = Register::FromCode(size - 1);
|
||||
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dext).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size)
|
||||
{
|
||||
MOZ_ASSERT(pos < 32 && size > 32 && size <= 64 && pos + size > 32 && pos + size <= 64);
|
||||
Register rd;
|
||||
rd = Register::FromCode(size - 1 - 32);
|
||||
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dextm).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size)
|
||||
{
|
||||
MOZ_ASSERT(pos >= 32 && pos < 64 && size != 0 && size <= 32 && pos + size > 32 && pos + size <= 64);
|
||||
Register rd;
|
||||
rd = Register::FromCode(size - 1);
|
||||
return writeInst(InstReg(op_special3, rs, rt, rd, pos - 32, ff_dextu).encode());
|
||||
}
|
||||
|
||||
// FP instructions
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ld(FloatRegister fd, Register base, int32_t off)
|
||||
|
@ -796,6 +1046,30 @@ AssemblerMIPSShared::as_mfc1(Register rt, FloatRegister fs)
|
|||
return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_mthc1(Register rt, FloatRegister fs)
|
||||
{
|
||||
return writeInst(InstReg(op_cop1, rs_mthc1, rt, fs).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_mfhc1(Register rt, FloatRegister fs)
|
||||
{
|
||||
return writeInst(InstReg(op_cop1, rs_mfhc1, rt, fs).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dmtc1(Register rt, FloatRegister fs)
|
||||
{
|
||||
return writeInst(InstReg(op_cop1, rs_dmtc1, rt, fs).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_dmfc1(Register rt, FloatRegister fs)
|
||||
{
|
||||
return writeInst(InstReg(op_cop1, rs_dmfc1, rt, fs).encode());
|
||||
}
|
||||
|
||||
// FP convert instructions
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ceilws(FloatRegister fd, FloatRegister fs)
|
||||
|
@ -845,6 +1119,12 @@ AssemblerMIPSShared::as_truncwd(FloatRegister fd, FloatRegister fs)
|
|||
return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_cvtdl(FloatRegister fd, FloatRegister fs)
|
||||
{
|
||||
return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_d_fmt).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_cvtds(FloatRegister fd, FloatRegister fs)
|
||||
{
|
||||
|
|
|
@ -30,14 +30,18 @@ static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 };
|
|||
static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 };
|
||||
static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 };
|
||||
static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 };
|
||||
static MOZ_CONSTEXPR_VAR Register a4 = { Registers::ta0 };
|
||||
static MOZ_CONSTEXPR_VAR Register a5 = { Registers::ta1 };
|
||||
static MOZ_CONSTEXPR_VAR Register a6 = { Registers::ta2 };
|
||||
static MOZ_CONSTEXPR_VAR Register a7 = { Registers::ta3 };
|
||||
static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 };
|
||||
static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 };
|
||||
static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 };
|
||||
static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 };
|
||||
static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 };
|
||||
static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 };
|
||||
static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 };
|
||||
static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 };
|
||||
static MOZ_CONSTEXPR_VAR Register t4 = { Registers::ta0 };
|
||||
static MOZ_CONSTEXPR_VAR Register t5 = { Registers::ta1 };
|
||||
static MOZ_CONSTEXPR_VAR Register t6 = { Registers::ta2 };
|
||||
static MOZ_CONSTEXPR_VAR Register t7 = { Registers::ta3 };
|
||||
static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 };
|
||||
static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 };
|
||||
static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 };
|
||||
|
@ -85,6 +89,10 @@ static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0;
|
|||
static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1;
|
||||
static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2;
|
||||
static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3;
|
||||
static MOZ_CONSTEXPR_VAR Register IntArgReg4 = a4;
|
||||
static MOZ_CONSTEXPR_VAR Register IntArgReg5 = a5;
|
||||
static MOZ_CONSTEXPR_VAR Register IntArgReg6 = a6;
|
||||
static MOZ_CONSTEXPR_VAR Register IntArgReg7 = a7;
|
||||
static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin
|
||||
static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin
|
||||
static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = CALL_TEMP_NON_ARG_REGS;
|
||||
|
@ -246,6 +254,12 @@ enum Opcode {
|
|||
op_blezl = 22 << OpcodeShift,
|
||||
op_bgtzl = 23 << OpcodeShift,
|
||||
|
||||
op_daddi = 24 << OpcodeShift,
|
||||
op_daddiu = 25 << OpcodeShift,
|
||||
|
||||
op_ldl = 26 << OpcodeShift,
|
||||
op_ldr = 27 << OpcodeShift,
|
||||
|
||||
op_special2 = 28 << OpcodeShift,
|
||||
op_special3 = 31 << OpcodeShift,
|
||||
|
||||
|
@ -256,17 +270,24 @@ enum Opcode {
|
|||
op_lbu = 36 << OpcodeShift,
|
||||
op_lhu = 37 << OpcodeShift,
|
||||
op_lwr = 38 << OpcodeShift,
|
||||
op_lwu = 39 << OpcodeShift,
|
||||
op_sb = 40 << OpcodeShift,
|
||||
op_sh = 41 << OpcodeShift,
|
||||
op_swl = 42 << OpcodeShift,
|
||||
op_sw = 43 << OpcodeShift,
|
||||
op_sdl = 44 << OpcodeShift,
|
||||
op_sdr = 45 << OpcodeShift,
|
||||
op_swr = 46 << OpcodeShift,
|
||||
|
||||
op_ll = 48 << OpcodeShift,
|
||||
op_lwc1 = 49 << OpcodeShift,
|
||||
op_ldc1 = 53 << OpcodeShift,
|
||||
op_ld = 55 << OpcodeShift,
|
||||
|
||||
op_sc = 56 << OpcodeShift,
|
||||
op_swc1 = 57 << OpcodeShift,
|
||||
op_sdc1 = 61 << OpcodeShift
|
||||
op_sdc1 = 61 << OpcodeShift,
|
||||
op_sd = 63 << OpcodeShift,
|
||||
};
|
||||
|
||||
enum RSField {
|
||||
|
@ -274,9 +295,11 @@ enum RSField {
|
|||
// cop1 encoding of RS field.
|
||||
rs_mfc1 = 0 << RSShift,
|
||||
rs_one = 1 << RSShift,
|
||||
rs_dmfc1 = 1 << RSShift,
|
||||
rs_cfc1 = 2 << RSShift,
|
||||
rs_mfhc1 = 3 << RSShift,
|
||||
rs_mtc1 = 4 << RSShift,
|
||||
rs_dmtc1 = 5 << RSShift,
|
||||
rs_ctc1 = 6 << RSShift,
|
||||
rs_mthc1 = 7 << RSShift,
|
||||
rs_bc1 = 8 << RSShift,
|
||||
|
@ -316,10 +339,18 @@ enum FunctionField {
|
|||
ff_mfhi = 16,
|
||||
ff_mflo = 18,
|
||||
|
||||
ff_dsllv = 20,
|
||||
ff_dsrlv = 22,
|
||||
ff_dsrav = 23,
|
||||
|
||||
ff_mult = 24,
|
||||
ff_multu = 25,
|
||||
ff_div = 26,
|
||||
ff_divu = 27,
|
||||
ff_dmult = 28,
|
||||
ff_dmultu = 29,
|
||||
ff_ddiv = 30,
|
||||
ff_ddivu = 31,
|
||||
|
||||
ff_add = 32,
|
||||
ff_addu = 33,
|
||||
|
@ -332,6 +363,10 @@ enum FunctionField {
|
|||
|
||||
ff_slt = 42,
|
||||
ff_sltu = 43,
|
||||
ff_dadd = 44,
|
||||
ff_daddu = 45,
|
||||
ff_dsub = 46,
|
||||
ff_dsubu = 47,
|
||||
|
||||
ff_tge = 48,
|
||||
ff_tgeu = 49,
|
||||
|
@ -339,15 +374,29 @@ enum FunctionField {
|
|||
ff_tltu = 51,
|
||||
ff_teq = 52,
|
||||
ff_tne = 54,
|
||||
ff_dsll = 56,
|
||||
ff_dsrl = 58,
|
||||
ff_dsra = 59,
|
||||
ff_dsll32 = 60,
|
||||
ff_dsrl32 = 62,
|
||||
ff_dsra32 = 63,
|
||||
|
||||
// special2 encoding of function field.
|
||||
ff_mul = 2,
|
||||
ff_clz = 32,
|
||||
ff_clo = 33,
|
||||
ff_dclz = 36,
|
||||
|
||||
// special3 encoding of function field.
|
||||
ff_ext = 0,
|
||||
ff_dextm = 1,
|
||||
ff_dextu = 2,
|
||||
ff_dext = 3,
|
||||
ff_ins = 4,
|
||||
ff_dinsm = 5,
|
||||
ff_dinsu = 6,
|
||||
ff_dins = 7,
|
||||
ff_bshfl = 32,
|
||||
|
||||
// cop1 encoding of function field.
|
||||
ff_add_fmt = 0,
|
||||
|
@ -812,12 +861,19 @@ class AssemblerMIPSShared : public AssemblerShared
|
|||
// Arithmetic instructions
|
||||
BufferOffset as_addu(Register rd, Register rs, Register rt);
|
||||
BufferOffset as_addiu(Register rd, Register rs, int32_t j);
|
||||
BufferOffset as_daddu(Register rd, Register rs, Register rt);
|
||||
BufferOffset as_daddiu(Register rd, Register rs, int32_t j);
|
||||
BufferOffset as_subu(Register rd, Register rs, Register rt);
|
||||
BufferOffset as_dsubu(Register rd, Register rs, Register rt);
|
||||
BufferOffset as_mult(Register rs, Register rt);
|
||||
BufferOffset as_multu(Register rs, Register rt);
|
||||
BufferOffset as_dmult(Register rs, Register rt);
|
||||
BufferOffset as_dmultu(Register rs, Register rt);
|
||||
BufferOffset as_div(Register rs, Register rt);
|
||||
BufferOffset as_divu(Register rs, Register rt);
|
||||
BufferOffset as_mul(Register rd, Register rs, Register rt);
|
||||
BufferOffset as_ddiv(Register rs, Register rt);
|
||||
BufferOffset as_ddivu(Register rs, Register rt);
|
||||
|
||||
// Logical instructions
|
||||
BufferOffset as_and(Register rd, Register rs, Register rt);
|
||||
|
@ -833,13 +889,25 @@ class AssemblerMIPSShared : public AssemblerShared
|
|||
// Shift instructions
|
||||
// as_sll(zero, zero, x) instructions are reserved as nop
|
||||
BufferOffset as_sll(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_dsll(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_dsll32(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_sllv(Register rd, Register rt, Register rs);
|
||||
BufferOffset as_dsllv(Register rd, Register rt, Register rs);
|
||||
BufferOffset as_srl(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_dsrl(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_dsrl32(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_srlv(Register rd, Register rt, Register rs);
|
||||
BufferOffset as_dsrlv(Register rd, Register rt, Register rs);
|
||||
BufferOffset as_sra(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_dsra(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_dsra32(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_srav(Register rd, Register rt, Register rs);
|
||||
BufferOffset as_rotr(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_rotrv(Register rd, Register rt, Register rs);
|
||||
BufferOffset as_dsrav(Register rd, Register rt, Register rs);
|
||||
BufferOffset as_drotr(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_drotr32(Register rd, Register rt, uint16_t sa);
|
||||
BufferOffset as_drotrv(Register rd, Register rt, Register rs);
|
||||
|
||||
// Load and store instructions
|
||||
BufferOffset as_lb(Register rd, Register rs, int16_t off);
|
||||
|
@ -847,13 +915,22 @@ class AssemblerMIPSShared : public AssemblerShared
|
|||
BufferOffset as_lh(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_lhu(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_lw(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_lwu(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_lwl(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_lwr(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_ll(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_ld(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_ldl(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_ldr(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_sb(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_sh(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_sw(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_swl(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_swr(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_sc(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_sd(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_sdl(Register rd, Register rs, int16_t off);
|
||||
BufferOffset as_sdr(Register rd, Register rs, int16_t off);
|
||||
|
||||
// Move from HI/LO register.
|
||||
BufferOffset as_mfhi(Register rd);
|
||||
|
@ -873,8 +950,19 @@ class AssemblerMIPSShared : public AssemblerShared
|
|||
|
||||
// Bit twiddling.
|
||||
BufferOffset as_clz(Register rd, Register rs);
|
||||
BufferOffset as_dclz(Register rd, Register rs);
|
||||
BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
BufferOffset as_dins(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
BufferOffset as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
BufferOffset as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
BufferOffset as_dext(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
BufferOffset as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
BufferOffset as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
|
||||
// Sign extend
|
||||
BufferOffset as_seb(Register rd, Register rt);
|
||||
BufferOffset as_seh(Register rd, Register rt);
|
||||
|
||||
// FP instructions
|
||||
|
||||
|
@ -892,6 +980,10 @@ class AssemblerMIPSShared : public AssemblerShared
|
|||
BufferOffset as_mtc1(Register rt, FloatRegister fs);
|
||||
BufferOffset as_mfc1(Register rt, FloatRegister fs);
|
||||
|
||||
BufferOffset as_mthc1(Register rt, FloatRegister fs);
|
||||
BufferOffset as_mfhc1(Register rt, FloatRegister fs);
|
||||
BufferOffset as_dmtc1(Register rt, FloatRegister fs);
|
||||
BufferOffset as_dmfc1(Register rt, FloatRegister fs);
|
||||
|
||||
public:
|
||||
// FP convert instructions
|
||||
|
@ -972,7 +1064,8 @@ class AssemblerMIPSShared : public AssemblerShared
|
|||
|
||||
public:
|
||||
static bool SupportsFloatingPoint() {
|
||||
#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || defined(JS_SIMULATOR_MIPS32)
|
||||
#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || \
|
||||
defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
|
|
|
@ -210,6 +210,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
|||
regs.take(OsrFrameReg);
|
||||
regs.take(BaselineFrameReg);
|
||||
regs.take(reg_code);
|
||||
regs.take(ReturnReg);
|
||||
|
||||
const Address slotNumStackValues(BaselineFrameReg, sizeof(EnterJITRegs) +
|
||||
offsetof(EnterJITArgs, numStackValues));
|
||||
|
@ -265,10 +266,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
|||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
|
||||
|
||||
regs.add(OsrFrameReg);
|
||||
regs.add(scratch);
|
||||
regs.add(numStackValues);
|
||||
regs.take(JSReturnOperand);
|
||||
regs.take(ReturnReg);
|
||||
Register jitcode = regs.takeAny();
|
||||
masm.loadPtr(Address(StackPointer, 0), jitcode);
|
||||
masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), framePtr);
|
||||
|
|
|
@ -0,0 +1,493 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/mips64/Assembler-mips64.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
using mozilla::DebugOnly;
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
ABIArgGenerator::ABIArgGenerator()
|
||||
: usedArgSlots_(0),
|
||||
firstArgFloat(false),
|
||||
current_()
|
||||
{}
|
||||
|
||||
ABIArg
|
||||
ABIArgGenerator::next(MIRType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIRType_Int32:
|
||||
case MIRType_Pointer: {
|
||||
Register destReg;
|
||||
if (GetIntArgReg(usedArgSlots_, &destReg))
|
||||
current_ = ABIArg(destReg);
|
||||
else
|
||||
current_ = ABIArg(GetArgStackDisp(usedArgSlots_));
|
||||
usedArgSlots_++;
|
||||
break;
|
||||
}
|
||||
case MIRType_Float32:
|
||||
case MIRType_Double: {
|
||||
FloatRegister destFReg;
|
||||
FloatRegister::ContentType contentType;
|
||||
if (!usedArgSlots_)
|
||||
firstArgFloat = true;
|
||||
contentType = (type == MIRType_Double) ?
|
||||
FloatRegisters::Double : FloatRegisters::Single;
|
||||
if (GetFloatArgReg(usedArgSlots_, &destFReg))
|
||||
current_ = ABIArg(FloatRegister(destFReg.id(), contentType));
|
||||
else
|
||||
current_ = ABIArg(GetArgStackDisp(usedArgSlots_));
|
||||
usedArgSlots_++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
return current_;
|
||||
}
|
||||
|
||||
const Register ABIArgGenerator::NonArgReturnReg0 = t0;
|
||||
const Register ABIArgGenerator::NonArgReturnReg1 = t1;
|
||||
const Register ABIArgGenerator::NonArg_VolatileReg = v0;
|
||||
const Register ABIArgGenerator::NonReturn_VolatileReg0 = a0;
|
||||
const Register ABIArgGenerator::NonReturn_VolatileReg1 = a1;
|
||||
|
||||
uint32_t
|
||||
js::jit::RT(FloatRegister r)
|
||||
{
|
||||
MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys);
|
||||
return r.id() << RTShift;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
js::jit::RD(FloatRegister r)
|
||||
{
|
||||
MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys);
|
||||
return r.id() << RDShift;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
js::jit::SA(FloatRegister r)
|
||||
{
|
||||
MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys);
|
||||
return r.id() << SAShift;
|
||||
}
|
||||
|
||||
// Used to patch jumps created by MacroAssemblerMIPS64Compat::jumpWithPatch.
|
||||
void
|
||||
jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, ReprotectCode reprotect)
|
||||
{
|
||||
Instruction* inst = (Instruction*)jump_.raw();
|
||||
|
||||
// Six instructions used in load 64-bit imm.
|
||||
MaybeAutoWritableJitCode awjc(inst, 6 * sizeof(uint32_t), reprotect);
|
||||
Assembler::UpdateLoad64Value(inst, (uint64_t)label.raw());
|
||||
|
||||
AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// For more infromation about backedges look at comment in
|
||||
// MacroAssemblerMIPS64Compat::backedgeJump()
|
||||
void
|
||||
jit::PatchBackedge(CodeLocationJump& jump, CodeLocationLabel label,
|
||||
JitRuntime::BackedgeTarget target)
|
||||
{
|
||||
uintptr_t sourceAddr = (uintptr_t)jump.raw();
|
||||
uintptr_t targetAddr = (uintptr_t)label.raw();
|
||||
InstImm* branch = (InstImm*)jump.raw();
|
||||
|
||||
MOZ_ASSERT(branch->extractOpcode() == (uint32_t(op_beq) >> OpcodeShift));
|
||||
|
||||
if (BOffImm16::IsInRange(targetAddr - sourceAddr)) {
|
||||
branch->setBOffImm16(BOffImm16(targetAddr - sourceAddr));
|
||||
} else {
|
||||
if (target == JitRuntime::BackedgeLoopHeader) {
|
||||
Instruction* inst = &branch[1];
|
||||
Assembler::UpdateLoad64Value(inst, targetAddr);
|
||||
// Jump to first ori. The lui will be executed in delay slot.
|
||||
branch->setBOffImm16(BOffImm16(2 * sizeof(uint32_t)));
|
||||
} else {
|
||||
Instruction* inst = &branch[6];
|
||||
Assembler::UpdateLoad64Value(inst, targetAddr);
|
||||
// Jump to first ori of interrupt loop.
|
||||
branch->setBOffImm16(BOffImm16(6 * sizeof(uint32_t)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::executableCopy(uint8_t* buffer)
|
||||
{
|
||||
MOZ_ASSERT(isFinished);
|
||||
m_buffer.executableCopy(buffer);
|
||||
|
||||
// Patch all long jumps during code copy.
|
||||
for (size_t i = 0; i < longJumps_.length(); i++) {
|
||||
Instruction* inst = (Instruction*) ((uintptr_t)buffer + longJumps_[i]);
|
||||
|
||||
uint64_t value = Assembler::ExtractLoad64Value(inst);
|
||||
Assembler::UpdateLoad64Value(inst, (uint64_t)buffer + value);
|
||||
}
|
||||
|
||||
AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size());
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
Assembler::GetPointer(uint8_t* instPtr)
|
||||
{
|
||||
Instruction* inst = (Instruction*)instPtr;
|
||||
return Assembler::ExtractLoad64Value(inst);
|
||||
}
|
||||
|
||||
static JitCode *
|
||||
CodeFromJump(Instruction* jump)
|
||||
{
|
||||
uint8_t* target = (uint8_t*)Assembler::ExtractLoad64Value(jump);
|
||||
return JitCode::FromExecutable(target);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader)
|
||||
{
|
||||
while (reader.more()) {
|
||||
JitCode* child = CodeFromJump((Instruction*)(code->raw() + reader.readUnsigned()));
|
||||
TraceManuallyBarrieredEdge(trc, &child, "rel32");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TraceOneDataRelocation(JSTracer* trc, Instruction* inst)
|
||||
{
|
||||
void* ptr = (void*)Assembler::ExtractLoad64Value(inst);
|
||||
void* prior = ptr;
|
||||
|
||||
// All pointers on MIPS64 will have the top bits cleared. If those bits
|
||||
// are not cleared, this must be a Value.
|
||||
uintptr_t word = reinterpret_cast<uintptr_t>(ptr);
|
||||
if (word >> JSVAL_TAG_SHIFT) {
|
||||
jsval_layout layout;
|
||||
layout.asBits = word;
|
||||
Value v = IMPL_TO_JSVAL(layout);
|
||||
TraceManuallyBarrieredEdge(trc, &v, "ion-masm-value");
|
||||
ptr = (void*)JSVAL_TO_IMPL(v).asBits;
|
||||
} else {
|
||||
// No barrier needed since these are constants.
|
||||
TraceManuallyBarrieredGenericPointerEdge(trc, reinterpret_cast<gc::Cell**>(&ptr),
|
||||
"ion-masm-ptr");
|
||||
}
|
||||
|
||||
if (ptr != prior) {
|
||||
Assembler::UpdateLoad64Value(inst, uint64_t(ptr));
|
||||
AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TraceDataRelocations(JSTracer* trc, uint8_t* buffer, CompactBufferReader& reader)
|
||||
{
|
||||
while (reader.more()) {
|
||||
size_t offset = reader.readUnsigned();
|
||||
Instruction* inst = (Instruction*)(buffer + offset);
|
||||
TraceOneDataRelocation(trc, inst);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TraceDataRelocations(JSTracer* trc, MIPSBuffer* buffer, CompactBufferReader& reader)
|
||||
{
|
||||
while (reader.more()) {
|
||||
BufferOffset bo (reader.readUnsigned());
|
||||
MIPSBuffer::AssemblerBufferInstIterator iter(bo, buffer);
|
||||
TraceOneDataRelocation(trc, iter.cur());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader)
|
||||
{
|
||||
::TraceDataRelocations(trc, code->raw(), reader);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::trace(JSTracer* trc)
|
||||
{
|
||||
for (size_t i = 0; i < jumps_.length(); i++) {
|
||||
RelativePatch& rp = jumps_[i];
|
||||
if (rp.kind == Relocation::JITCODE) {
|
||||
JitCode* code = JitCode::FromExecutable((uint8_t*)rp.target);
|
||||
TraceManuallyBarrieredEdge(trc, &code, "masmrel32");
|
||||
MOZ_ASSERT(code == JitCode::FromExecutable((uint8_t*)rp.target));
|
||||
}
|
||||
}
|
||||
if (dataRelocations_.length()) {
|
||||
CompactBufferReader reader(dataRelocations_);
|
||||
::TraceDataRelocations(trc, &m_buffer, reader);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t
|
||||
Assembler::ExtractCodeLabelOffset(uint8_t* code)
|
||||
{
|
||||
Instruction* inst = (Instruction*)code;
|
||||
return Assembler::ExtractLoad64Value(inst);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address)
|
||||
{
|
||||
if (label->used()) {
|
||||
int64_t src = label->offset();
|
||||
do {
|
||||
Instruction* inst = (Instruction*) (rawCode + src);
|
||||
uint64_t next = Assembler::ExtractLoad64Value(inst);
|
||||
Assembler::UpdateLoad64Value(inst, (uint64_t)address);
|
||||
src = next;
|
||||
} while (src != AbsoluteLabel::INVALID_OFFSET);
|
||||
}
|
||||
label->bind();
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::bind(InstImm* inst, uint64_t branch, uint64_t target)
|
||||
{
|
||||
int64_t offset = target - branch;
|
||||
InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
|
||||
InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0));
|
||||
|
||||
// If encoded offset is 4, then the jump must be short
|
||||
if (BOffImm16(inst[0]).decode() == 4) {
|
||||
MOZ_ASSERT(BOffImm16::IsInRange(offset));
|
||||
inst[0].setBOffImm16(BOffImm16(offset));
|
||||
inst[1].makeNop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate the long jump for calls because return address has to be the
|
||||
// address after the reserved block.
|
||||
if (inst[0].encode() == inst_bgezal.encode()) {
|
||||
addLongJump(BufferOffset(branch));
|
||||
Assembler::WriteLoad64Instructions(inst, ScratchRegister, target);
|
||||
inst[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode();
|
||||
// There is 1 nop after this.
|
||||
return;
|
||||
}
|
||||
|
||||
if (BOffImm16::IsInRange(offset)) {
|
||||
bool conditional = (inst[0].encode() != inst_bgezal.encode() &&
|
||||
inst[0].encode() != inst_beq.encode());
|
||||
|
||||
inst[0].setBOffImm16(BOffImm16(offset));
|
||||
inst[1].makeNop();
|
||||
|
||||
// Skip the trailing nops in conditional branches.
|
||||
// FIXME: On Loongson3 platform, the branch degrade performance.
|
||||
if (0 && conditional) {
|
||||
inst[2] = InstImm(op_regimm, zero, rt_bgez, BOffImm16(5 * sizeof(uint32_t))).encode();
|
||||
// There are 4 nops after this
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (inst[0].encode() == inst_beq.encode()) {
|
||||
// Handle long unconditional jump.
|
||||
addLongJump(BufferOffset(branch));
|
||||
Assembler::WriteLoad64Instructions(inst, ScratchRegister, target);
|
||||
inst[4] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
|
||||
// There is 1 nop after this.
|
||||
} else {
|
||||
// Handle long conditional jump.
|
||||
inst[0] = invertBranch(inst[0], BOffImm16(7 * sizeof(uint32_t)));
|
||||
// No need for a "nop" here because we can clobber scratch.
|
||||
addLongJump(BufferOffset(branch + sizeof(uint32_t)));
|
||||
Assembler::WriteLoad64Instructions(&inst[1], ScratchRegister, target);
|
||||
inst[5] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
|
||||
// There is 1 nop after this.
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::bind(RepatchLabel* label)
|
||||
{
|
||||
BufferOffset dest = nextOffset();
|
||||
if (label->used()) {
|
||||
// If the label has a use, then change this use to refer to
|
||||
// the bound label;
|
||||
BufferOffset b(label->offset());
|
||||
InstImm* inst1 = (InstImm*)editSrc(b);
|
||||
|
||||
// If first instruction is branch, then this is a loop backedge.
|
||||
if (inst1->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift)) {
|
||||
// Backedges are short jumps when bound, but can become long
|
||||
// when patched.
|
||||
uint64_t offset = dest.getOffset() - label->offset();
|
||||
MOZ_ASSERT(BOffImm16::IsInRange(offset));
|
||||
inst1->setBOffImm16(BOffImm16(offset));
|
||||
} else {
|
||||
Assembler::UpdateLoad64Value(inst1, dest.getOffset());
|
||||
}
|
||||
|
||||
}
|
||||
label->bind(dest.getOffset());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Assembler::PatchWrite_NearCallSize()
|
||||
{
|
||||
// Load an address needs 4 instructions, and a jump with a delay slot.
|
||||
return (4 + 2) * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall)
|
||||
{
|
||||
Instruction* inst = (Instruction*) start.raw();
|
||||
uint8_t* dest = toCall.raw();
|
||||
|
||||
// Overwrite whatever instruction used to be here with a call.
|
||||
// Always use long jump for two reasons:
|
||||
// - Jump has to be the same size because of PatchWrite_NearCallSize.
|
||||
// - Return address has to be at the end of replaced block.
|
||||
// Short jump wouldn't be more efficient.
|
||||
Assembler::WriteLoad64Instructions(inst, ScratchRegister, (uint64_t)dest);
|
||||
inst[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
|
||||
inst[5] = InstNOP();
|
||||
|
||||
// Ensure everyone sees the code that was just written into memory.
|
||||
AutoFlushICache::flush(uintptr_t(inst), PatchWrite_NearCallSize());
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Assembler::ExtractLoad64Value(Instruction* inst0)
|
||||
{
|
||||
InstImm* i0 = (InstImm*) inst0;
|
||||
InstImm* i1 = (InstImm*) i0->next();
|
||||
InstReg* i2 = (InstReg*) i1->next();
|
||||
InstImm* i3 = (InstImm*) i2->next();
|
||||
InstImm* i5 = (InstImm*) i3->next()->next();
|
||||
|
||||
MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
|
||||
MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
|
||||
MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
|
||||
|
||||
if ((i2->extractOpcode() == ((uint32_t)op_special >> OpcodeShift)) &&
|
||||
(i2->extractFunctionField() == ff_dsrl32))
|
||||
{
|
||||
uint64_t value = (uint64_t(i0->extractImm16Value()) << 32) |
|
||||
(uint64_t(i1->extractImm16Value()) << 16) |
|
||||
uint64_t(i3->extractImm16Value());
|
||||
return uint64_t((int64_t(value) <<16) >> 16);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(i5->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
|
||||
uint64_t value = (uint64_t(i0->extractImm16Value()) << 48) |
|
||||
(uint64_t(i1->extractImm16Value()) << 32) |
|
||||
(uint64_t(i3->extractImm16Value()) << 16) |
|
||||
uint64_t(i5->extractImm16Value());
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::UpdateLoad64Value(Instruction* inst0, uint64_t value)
|
||||
{
|
||||
InstImm* i0 = (InstImm*) inst0;
|
||||
InstImm* i1 = (InstImm*) i0->next();
|
||||
InstReg* i2 = (InstReg*) i1->next();
|
||||
InstImm* i3 = (InstImm*) i2->next();
|
||||
InstImm* i5 = (InstImm*) i3->next()->next();
|
||||
|
||||
MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
|
||||
MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
|
||||
MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
|
||||
|
||||
if ((i2->extractOpcode() == ((uint32_t)op_special >> OpcodeShift)) &&
|
||||
(i2->extractFunctionField() == ff_dsrl32))
|
||||
{
|
||||
i0->setImm16(Imm16::Lower(Imm32(value >> 32)));
|
||||
i1->setImm16(Imm16::Upper(Imm32(value)));
|
||||
i3->setImm16(Imm16::Lower(Imm32(value)));
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(i5->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
|
||||
|
||||
i0->setImm16(Imm16::Upper(Imm32(value >> 32)));
|
||||
i1->setImm16(Imm16::Lower(Imm32(value >> 32)));
|
||||
i3->setImm16(Imm16::Upper(Imm32(value)));
|
||||
i5->setImm16(Imm16::Lower(Imm32(value)));
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::WriteLoad64Instructions(Instruction* inst0, Register reg, uint64_t value)
|
||||
{
|
||||
Instruction* inst1 = inst0->next();
|
||||
Instruction* inst2 = inst1->next();
|
||||
Instruction* inst3 = inst2->next();
|
||||
|
||||
*inst0 = InstImm(op_lui, zero, reg, Imm16::Lower(Imm32(value >> 32)));
|
||||
*inst1 = InstImm(op_ori, reg, reg, Imm16::Upper(Imm32(value)));
|
||||
*inst2 = InstReg(op_special, rs_one, reg, reg, 48 - 32, ff_dsrl32);
|
||||
*inst3 = InstImm(op_ori, reg, reg, Imm16::Lower(Imm32(value)));
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
|
||||
PatchedImmPtr expectedValue)
|
||||
{
|
||||
Instruction* inst = (Instruction*) label.raw();
|
||||
|
||||
// Extract old Value
|
||||
DebugOnly<uint64_t> value = Assembler::ExtractLoad64Value(inst);
|
||||
MOZ_ASSERT(value == uint64_t(expectedValue.value));
|
||||
|
||||
// Replace with new value
|
||||
Assembler::UpdateLoad64Value(inst, uint64_t(newValue.value));
|
||||
|
||||
AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm)
|
||||
{
|
||||
InstImm* inst = (InstImm*)code;
|
||||
Assembler::UpdateLoad64Value(inst, (uint64_t)imm.value);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled)
|
||||
{
|
||||
Instruction* inst = (Instruction*)inst_.raw();
|
||||
InstImm* i0 = (InstImm*) inst;
|
||||
InstImm* i1 = (InstImm*) i0->next();
|
||||
InstImm* i3 = (InstImm*) i1->next()->next();
|
||||
Instruction* i4 = (Instruction*) i3->next();
|
||||
|
||||
MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
|
||||
MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
|
||||
MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
|
||||
|
||||
if (enabled) {
|
||||
MOZ_ASSERT(i4->extractOpcode() != ((uint32_t)op_lui >> OpcodeShift));
|
||||
InstReg jalr = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
|
||||
*i4 = jalr;
|
||||
} else {
|
||||
InstNOP nop;
|
||||
*i4 = nop;
|
||||
}
|
||||
|
||||
AutoFlushICache::flush(uintptr_t(i4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::UpdateBoundsCheck(uint64_t heapSize, Instruction* inst)
|
||||
{
|
||||
// Replace with new value
|
||||
Assembler::UpdateLoad64Value(inst, heapSize);
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_mips64_Assembler_mips64_h
|
||||
#define jit_mips64_Assembler_mips64_h
|
||||
|
||||
// NOTE: Don't use these macros directly
|
||||
// CallTempNonArgRegs
|
||||
#define CALL_TEMP_NON_ARG_REGS \
|
||||
{ t0, t1, t2, t3 };
|
||||
// NumIntArgRegs
|
||||
#define NUM_INT_ARG_REGS 8;
|
||||
|
||||
#include "jit/mips-shared/Assembler-mips-shared.h"
|
||||
|
||||
#include "jit/mips64/Architecture-mips64.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
static MOZ_CONSTEXPR_VAR Register CallTempReg4 = a4;
|
||||
static MOZ_CONSTEXPR_VAR Register CallTempReg5 = a5;
|
||||
|
||||
class ABIArgGenerator
|
||||
{
|
||||
unsigned usedArgSlots_;
|
||||
bool firstArgFloat;
|
||||
ABIArg current_;
|
||||
|
||||
public:
|
||||
ABIArgGenerator();
|
||||
ABIArg next(MIRType argType);
|
||||
ABIArg& current() { return current_; }
|
||||
|
||||
uint32_t stackBytesConsumedSoFar() const {
|
||||
if (usedArgSlots_ <= 8)
|
||||
return 0;
|
||||
|
||||
return (usedArgSlots_ - 8) * sizeof(int64_t);
|
||||
}
|
||||
|
||||
static const Register NonArgReturnReg0;
|
||||
static const Register NonArgReturnReg1;
|
||||
static const Register NonArg_VolatileReg;
|
||||
static const Register NonReturn_VolatileReg0;
|
||||
static const Register NonReturn_VolatileReg1;
|
||||
};
|
||||
|
||||
static MOZ_CONSTEXPR_VAR Register JSReturnReg = v1;
|
||||
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = JSReturnReg;
|
||||
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = JSReturnReg;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::f0, FloatRegisters::Single };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::f0, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::f23, FloatRegisters::Single };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::f23, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloat32Reg = { FloatRegisters::f21, FloatRegisters::Single };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchDoubleReg = { FloatRegisters::f21, FloatRegisters::Double };
|
||||
|
||||
// Registers used in the GenerateFFIIonExit Disable Activation block.
|
||||
// None of these may be the second scratch register (t8).
|
||||
static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = JSReturnReg_Data;
|
||||
static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = JSReturnReg_Type;
|
||||
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f0 = { FloatRegisters::f0, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f1 = { FloatRegisters::f1, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f2 = { FloatRegisters::f2, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f3 = { FloatRegisters::f3, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f4 = { FloatRegisters::f4, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f5 = { FloatRegisters::f5, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f6 = { FloatRegisters::f6, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f7 = { FloatRegisters::f7, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f8 = { FloatRegisters::f8, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f9 = { FloatRegisters::f9, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f10 = { FloatRegisters::f10, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f11 = { FloatRegisters::f11, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f12 = { FloatRegisters::f12, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f13 = { FloatRegisters::f13, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f14 = { FloatRegisters::f14, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f15 = { FloatRegisters::f15, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f16 = { FloatRegisters::f16, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f17 = { FloatRegisters::f17, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f18 = { FloatRegisters::f18, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f19 = { FloatRegisters::f19, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f20 = { FloatRegisters::f20, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f21 = { FloatRegisters::f21, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f22 = { FloatRegisters::f22, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f23 = { FloatRegisters::f23, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f24 = { FloatRegisters::f24, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f25 = { FloatRegisters::f25, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f26 = { FloatRegisters::f26, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f27 = { FloatRegisters::f27, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f28 = { FloatRegisters::f28, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f29 = { FloatRegisters::f29, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f30 = { FloatRegisters::f30, FloatRegisters::Double };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister f31 = { FloatRegisters::f31, FloatRegisters::Double };
|
||||
|
||||
// MIPS64 CPUs can only load multibyte data that is "naturally"
|
||||
// eight-byte-aligned, sp register should be sixteen-byte-aligned.
|
||||
static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 16;
|
||||
static MOZ_CONSTEXPR_VAR uint32_t JitStackAlignment = 16;
|
||||
|
||||
static MOZ_CONSTEXPR_VAR uint32_t JitStackValueAlignment = JitStackAlignment / sizeof(Value);
|
||||
static_assert(JitStackAlignment % sizeof(Value) == 0 && JitStackValueAlignment >= 1,
|
||||
"Stack alignment should be a non-zero multiple of sizeof(Value)");
|
||||
|
||||
// TODO this is just a filler to prevent a build failure. The MIPS SIMD
|
||||
// alignment requirements still need to be explored.
|
||||
// TODO Copy the static_asserts from x64/x86 assembler files.
|
||||
static MOZ_CONSTEXPR_VAR uint32_t SimdMemoryAlignment = 16;
|
||||
|
||||
static MOZ_CONSTEXPR_VAR uint32_t AsmJSStackAlignment = SimdMemoryAlignment;
|
||||
|
||||
static MOZ_CONSTEXPR_VAR Scale ScalePointer = TimesEight;
|
||||
|
||||
class Assembler : public AssemblerMIPSShared
|
||||
{
|
||||
public:
|
||||
Assembler()
|
||||
: AssemblerMIPSShared()
|
||||
{ }
|
||||
|
||||
// MacroAssemblers hold onto gcthings, so they are traced by the GC.
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
static uintptr_t GetPointer(uint8_t*);
|
||||
|
||||
using AssemblerMIPSShared::bind;
|
||||
using AssemblerMIPSShared::PatchDataWithValueCheck;
|
||||
|
||||
void bind(RepatchLabel* label);
|
||||
void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address);
|
||||
|
||||
static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
|
||||
static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
|
||||
|
||||
void bind(InstImm* inst, uint64_t branch, uint64_t target);
|
||||
|
||||
// Copy the assembly code to the given buffer, and perform any pending
|
||||
// relocations relying on the target address.
|
||||
void executableCopy(uint8_t* buffer);
|
||||
|
||||
static uint32_t PatchWrite_NearCallSize();
|
||||
|
||||
static uint64_t ExtractLoad64Value(Instruction* inst0);
|
||||
static void UpdateLoad64Value(Instruction* inst0, uint64_t value);
|
||||
static void WriteLoad64Instructions(Instruction* inst0, Register reg, uint64_t value);
|
||||
|
||||
|
||||
static void PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall);
|
||||
static void PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
|
||||
PatchedImmPtr expectedValue);
|
||||
|
||||
static void PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm);
|
||||
|
||||
static void ToggleCall(CodeLocationLabel inst_, bool enabled);
|
||||
|
||||
static void UpdateBoundsCheck(uint64_t logHeapSize, Instruction* inst);
|
||||
static int64_t ExtractCodeLabelOffset(uint8_t* code);
|
||||
}; // Assembler
|
||||
|
||||
static const uint32_t NumFloatArgRegs = NumIntArgRegs;
|
||||
|
||||
static inline bool
|
||||
GetFloatArgReg(uint32_t usedArgSlots, FloatRegister* out)
|
||||
{
|
||||
if (usedArgSlots < NumFloatArgRegs) {
|
||||
*out = FloatRegister::FromCode(f12.code() + usedArgSlots);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
GetArgStackDisp(uint32_t usedArgSlots)
|
||||
{
|
||||
MOZ_ASSERT(usedArgSlots >= NumIntArgRegs);
|
||||
return (usedArgSlots - NumIntArgRegs) * sizeof(int64_t);
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
#endif /* jit_mips64_Assembler_mips64_h */
|
|
@ -0,0 +1,28 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jscompartment.h"
|
||||
|
||||
#include "jit/mips-shared/Bailouts-mips-shared.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
|
||||
BailoutStack* bailout)
|
||||
: machine_(bailout->machine())
|
||||
{
|
||||
uint8_t* sp = bailout->parentStackPointer();
|
||||
framePointer_ = sp + bailout->frameSize();
|
||||
topFrameSize_ = framePointer_ - sp;
|
||||
|
||||
JSScript* script = ScriptFromCalleeToken(((JitFrameLayout*) framePointer_)->calleeToken());
|
||||
topIonScript_ = script->ionScript();
|
||||
|
||||
attachOnJitActivation(activations);
|
||||
snapshotOffset_ = bailout->snapshotOffset();
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/mips64/BaselineCompiler-mips64.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
BaselineCompilerMIPS64::BaselineCompilerMIPS64(JSContext* cx, TempAllocator& alloc,
|
||||
JSScript* script)
|
||||
: BaselineCompilerMIPSShared(cx, alloc, script)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_mips64_BaselineCompiler_mips64_h
|
||||
#define jit_mips64_BaselineCompiler_mips64_h
|
||||
|
||||
#include "jit/mips-shared/BaselineCompiler-mips-shared.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class BaselineCompilerMIPS64 : public BaselineCompilerMIPSShared
|
||||
{
|
||||
protected:
|
||||
BaselineCompilerMIPS64(JSContext* cx, TempAllocator& alloc, JSScript* script);
|
||||
};
|
||||
|
||||
typedef BaselineCompilerMIPS64 BaselineCompilerSpecific;
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
#endif /* jit_mips64_BaselineCompiler_mips64_h */
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/BaselineCompiler.h"
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/Linker.h"
|
||||
#include "jit/SharedICHelpers.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
// ICCompare_Int32
|
||||
|
||||
bool
|
||||
ICCompare_Int32::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
{
|
||||
// Guard that R0 is an integer and R1 is an integer.
|
||||
Label failure;
|
||||
Label conditionTrue;
|
||||
masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
|
||||
masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
|
||||
|
||||
// Compare payload regs of R0 and R1.
|
||||
masm.unboxInt32(R0, ExtractTemp0);
|
||||
masm.unboxInt32(R1, ExtractTemp1);
|
||||
Assembler::Condition cond = JSOpToCondition(op, /* signed = */true);
|
||||
masm.ma_cmp_set(R0.valueReg(), ExtractTemp0, ExtractTemp1, cond);
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.valueReg(), R0);
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
// Failure case - jump to next stub
|
||||
masm.bind(&failure);
|
||||
EmitStubGuardFailure(masm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
|
@ -78,3 +78,151 @@ BEGIN_TEST(testStructuredClone_string)
|
|||
return true;
|
||||
}
|
||||
END_TEST(testStructuredClone_string)
|
||||
|
||||
struct StructuredCloneTestPrincipals final : public JSPrincipals {
|
||||
uint32_t rank;
|
||||
|
||||
explicit StructuredCloneTestPrincipals(uint32_t rank, int32_t rc = 1) : rank(rank) {
|
||||
this->refcount = rc;
|
||||
}
|
||||
|
||||
bool write(JSContext* cx, JSStructuredCloneWriter* writer) override {
|
||||
return JS_WriteUint32Pair(writer, rank, 0);
|
||||
}
|
||||
|
||||
static bool read(JSContext* cx, JSStructuredCloneReader *reader, JSPrincipals** outPrincipals) {
|
||||
uint32_t rank;
|
||||
uint32_t unused;
|
||||
if (!JS_ReadUint32Pair(reader, &rank, &unused))
|
||||
return false;
|
||||
|
||||
*outPrincipals = new StructuredCloneTestPrincipals(rank);
|
||||
return !!*outPrincipals;
|
||||
}
|
||||
|
||||
static void destroy(JSPrincipals* p) {
|
||||
auto p1 = static_cast<StructuredCloneTestPrincipals*>(p);
|
||||
delete p1;
|
||||
}
|
||||
|
||||
static uint32_t getRank(JSPrincipals* p) {
|
||||
if (!p)
|
||||
return 0;
|
||||
return static_cast<StructuredCloneTestPrincipals*>(p)->rank;
|
||||
}
|
||||
|
||||
static bool subsumes(JSPrincipals* a, JSPrincipals* b) {
|
||||
return getRank(a) > getRank(b);
|
||||
}
|
||||
|
||||
static JSSecurityCallbacks securityCallbacks;
|
||||
|
||||
static StructuredCloneTestPrincipals testPrincipals;
|
||||
};
|
||||
|
||||
JSSecurityCallbacks StructuredCloneTestPrincipals::securityCallbacks = {
|
||||
nullptr, // contentSecurityPolicyAllows
|
||||
subsumes
|
||||
};
|
||||
|
||||
BEGIN_TEST(testStructuredClone_SavedFrame)
|
||||
{
|
||||
JS_SetSecurityCallbacks(rt, &StructuredCloneTestPrincipals::securityCallbacks);
|
||||
JS_InitDestroyPrincipalsCallback(rt, StructuredCloneTestPrincipals::destroy);
|
||||
JS_InitReadPrincipalsCallback(rt, StructuredCloneTestPrincipals::read);
|
||||
|
||||
auto testPrincipals = new StructuredCloneTestPrincipals(42, 0);
|
||||
CHECK(testPrincipals);
|
||||
|
||||
auto DONE = (JSPrincipals*) 0xDEADBEEF;
|
||||
|
||||
struct {
|
||||
const char* name;
|
||||
JSPrincipals* principals;
|
||||
} principalsToTest[] = {
|
||||
{ "IsSystem", &js::ReconstructedSavedFramePrincipals::IsSystem },
|
||||
{ "IsNotSystem", &js::ReconstructedSavedFramePrincipals::IsNotSystem },
|
||||
{ "testPrincipals", testPrincipals },
|
||||
{ "nullptr principals", nullptr },
|
||||
{ "DONE", DONE }
|
||||
};
|
||||
|
||||
const char* FILENAME = "filename.js";
|
||||
|
||||
for (auto* pp = principalsToTest; pp->principals != DONE; pp++) {
|
||||
fprintf(stderr, "Testing with principals '%s'\n", pp->name);
|
||||
|
||||
JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), pp->principals,
|
||||
JS::FireOnNewGlobalHook));
|
||||
CHECK(g);
|
||||
JSAutoCompartment ac(cx, g);
|
||||
|
||||
CHECK(js::DefineTestingFunctions(cx, g, false, false));
|
||||
|
||||
JS::RootedValue srcVal(cx);
|
||||
CHECK(evaluate("(function one() { \n" // 1
|
||||
" return (function two() { \n" // 2
|
||||
" return (function three() { \n" // 3
|
||||
" return saveStack(); \n" // 4
|
||||
" }()); \n" // 5
|
||||
" }()); \n" // 6
|
||||
"}()); \n", // 7
|
||||
FILENAME,
|
||||
1,
|
||||
&srcVal));
|
||||
|
||||
CHECK(srcVal.isObject());
|
||||
JS::RootedObject srcObj(cx, &srcVal.toObject());
|
||||
|
||||
CHECK(srcObj->is<js::SavedFrame>());
|
||||
js::RootedSavedFrame srcFrame(cx, &srcObj->as<js::SavedFrame>());
|
||||
|
||||
CHECK(srcFrame->getPrincipals() == pp->principals);
|
||||
|
||||
JS::RootedValue destVal(cx);
|
||||
CHECK(JS_StructuredClone(cx, srcVal, &destVal, nullptr, nullptr));
|
||||
|
||||
CHECK(destVal.isObject());
|
||||
JS::RootedObject destObj(cx, &destVal.toObject());
|
||||
|
||||
CHECK(destObj->is<js::SavedFrame>());
|
||||
auto destFrame = &destObj->as<js::SavedFrame>();
|
||||
|
||||
size_t framesCopied = 0;
|
||||
for (auto& f : *destFrame) {
|
||||
framesCopied++;
|
||||
|
||||
CHECK(&f != srcFrame);
|
||||
|
||||
if (pp->principals == testPrincipals) {
|
||||
// We shouldn't get a pointer to the same
|
||||
// StructuredCloneTestPrincipals instance since we should have
|
||||
// serialized and then deserialized it into a new instance.
|
||||
CHECK(f.getPrincipals() != pp->principals);
|
||||
|
||||
// But it should certainly have the same rank.
|
||||
CHECK(StructuredCloneTestPrincipals::getRank(f.getPrincipals()) ==
|
||||
StructuredCloneTestPrincipals::getRank(pp->principals));
|
||||
} else {
|
||||
// For our singleton principals, we should always get the same
|
||||
// pointer back.
|
||||
CHECK(js::ReconstructedSavedFramePrincipals::is(pp->principals) ||
|
||||
pp->principals == nullptr);
|
||||
CHECK(f.getPrincipals() == pp->principals);
|
||||
}
|
||||
|
||||
CHECK(EqualStrings(f.getSource(), srcFrame->getSource()));
|
||||
CHECK(f.getLine() == srcFrame->getLine());
|
||||
CHECK(f.getColumn() == srcFrame->getColumn());
|
||||
CHECK(EqualStrings(f.getFunctionDisplayName(), srcFrame->getFunctionDisplayName()));
|
||||
|
||||
srcFrame = srcFrame->getParent();
|
||||
}
|
||||
|
||||
// Four function frames + one global frame.
|
||||
CHECK(framesCopied == 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testStructuredClone_SavedFrame)
|
||||
|
|
1510
js/src/jsapi.cpp
1510
js/src/jsapi.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
838
js/src/jsapi.h
838
js/src/jsapi.h
|
@ -2186,12 +2186,6 @@ extern JS_PUBLIC_API(void*)
|
|||
JS_GetInstancePrivate(JSContext* cx, JS::Handle<JSObject*> obj, const JSClass* clasp,
|
||||
JS::CallArgs* args);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject protop);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetPrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_GetConstructor(JSContext* cx, JS::Handle<JSObject*> proto);
|
||||
|
||||
|
@ -2417,10 +2411,6 @@ JS_FireOnNewGlobalObject(JSContext* cx, JS::HandleObject global);
|
|||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_NewObject(JSContext* cx, const JSClass* clasp);
|
||||
|
||||
/* Queries the [[Extensible]] property of the object. */
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_IsExtensible(JSContext* cx, JS::HandleObject obj, bool* extensible);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_IsNative(JSObject* obj);
|
||||
|
||||
|
@ -2452,29 +2442,6 @@ JS_DeepFreezeObject(JSContext* cx, JS::Handle<JSObject*> obj);
|
|||
extern JS_PUBLIC_API(bool)
|
||||
JS_FreezeObject(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
|
||||
/*
|
||||
* Attempt to make |obj| non-extensible. If an error occurs while making the
|
||||
* attempt, return false (with a pending exception set, depending upon the
|
||||
* nature of the error). If no error occurs, return true with |result| set
|
||||
* to indicate whether the attempt successfully set the [[Extensible]] property
|
||||
* to false.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
|
||||
|
||||
/*
|
||||
* Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt
|
||||
* to modify it will fail. If an error occurs during the attempt, return false
|
||||
* (with a pending exception set, depending upon the nature of the error). If
|
||||
* no error occurs, return true with |*succeeded| set to indicate whether the
|
||||
* attempt successfully made the [[Prototype]] immutable.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args);
|
||||
|
||||
|
||||
/*** Property descriptors ************************************************************************/
|
||||
|
||||
|
@ -2768,108 +2735,86 @@ ObjectToCompletePropertyDescriptor(JSContext* cx,
|
|||
} // namespace JS
|
||||
|
||||
|
||||
/*** [[DefineOwnProperty]] and variations ********************************************************/
|
||||
/*** Standard internal methods ********************************************************************
|
||||
*
|
||||
* The functions below are the fundamental operations on objects.
|
||||
*
|
||||
* ES6 specifies 14 internal methods that define how objects behave. The
|
||||
* standard is actually quite good on this topic, though you may have to read
|
||||
* it a few times. See ES6 sections 6.1.7.2 and 6.1.7.3.
|
||||
*
|
||||
* When 'obj' is an ordinary object, these functions have boring standard
|
||||
* behavior as specified by ES6 section 9.1; see the section about internal
|
||||
* methods in js/src/vm/NativeObject.h.
|
||||
*
|
||||
* Proxies override the behavior of internal methods. So when 'obj' is a proxy,
|
||||
* any one of the functions below could do just about anything. See
|
||||
* js/public/Proxy.h.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the prototype of obj, storing it in result.
|
||||
*
|
||||
* Implements: ES6 [[GetPrototypeOf]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject result);
|
||||
|
||||
/**
|
||||
* Change the prototype of obj.
|
||||
*
|
||||
* Implements: ES6 [[SetPrototypeOf]] internal method.
|
||||
*
|
||||
* In cases where ES6 [[SetPrototypeOf]] returns false without an exception,
|
||||
* JS_SetPrototype throws a TypeError and returns false.
|
||||
*
|
||||
* Performance warning: JS_SetPrototype is very bad for performance. It may
|
||||
* cause compiled jit-code to be invalidated. It also causes not only obj but
|
||||
* all other objects in the same "group" as obj to be permanently deoptimized.
|
||||
* It's better to create the object with the right prototype from the start.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleObject value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
JS_SetPrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto);
|
||||
|
||||
/**
|
||||
* Determine whether obj is extensible. Extensible objects can have new
|
||||
* properties defined on them. Inextensible objects can't, and their
|
||||
* [[Prototype]] slot is fixed as well.
|
||||
*
|
||||
* Implements: ES6 [[IsExtensible]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleString value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
JS_IsExtensible(JSContext* cx, JS::HandleObject obj, bool* extensible);
|
||||
|
||||
/**
|
||||
* Attempt to make |obj| non-extensible.
|
||||
*
|
||||
* Not all failures are treated as errors. See the comment on
|
||||
* JS::ObjectOpResult in js/public/Class.h.
|
||||
*
|
||||
* Implements: ES6 [[PreventExtensions]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, int32_t value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
|
||||
|
||||
/**
|
||||
* Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt
|
||||
* to modify it will fail. If an error occurs during the attempt, return false
|
||||
* (with a pending exception set, depending upon the nature of the error). If
|
||||
* no error occurs, return true with |*succeeded| set to indicate whether the
|
||||
* attempt successfully made the [[Prototype]] immutable.
|
||||
*
|
||||
* This is a nonstandard internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, uint32_t value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, double value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleString value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, int32_t value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, uint32_t value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, double value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult& result);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::Handle<JSPropertyDescriptor> desc);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_DefineObject(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
const JSClass* clasp = nullptr, unsigned attrs = 0);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineConstDoubles(JSContext* cx, JS::HandleObject obj, const JSConstDoubleSpec* cds);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineConstIntegers(JSContext* cx, JS::HandleObject obj, const JSConstIntegerSpec* cis);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperties(JSContext* cx, JS::HandleObject obj, const JSPropertySpec* ps);
|
||||
|
||||
|
||||
/* * */
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_AlreadyHasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_AlreadyHasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
|
||||
|
||||
JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
|
||||
|
||||
/**
|
||||
* Get a description of one of obj's own properties. If no such property exists
|
||||
* on obj, return true with desc.object() set to null.
|
||||
*
|
||||
* Implements: ES6 [[GetOwnProperty]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetOwnPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc);
|
||||
|
@ -2882,16 +2827,11 @@ extern JS_PUBLIC_API(bool)
|
|||
JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp);
|
||||
|
||||
/*
|
||||
* Like JS_GetOwnPropertyDescriptorById but will return a property on
|
||||
* an object on the prototype chain (returned in desc->obj). If desc->obj is null,
|
||||
* then this property was not found on the prototype chain.
|
||||
/**
|
||||
* Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain
|
||||
* if no own property is found directly on obj. The object on which the
|
||||
* property is found is returned in desc.object(). If the property is not found
|
||||
* on the prototype chain, this returns true with desc.object() set to null.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
|
@ -2901,40 +2841,87 @@ extern JS_PUBLIC_API(bool)
|
|||
JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc);
|
||||
|
||||
/**
|
||||
* Define a property on obj.
|
||||
*
|
||||
* This function uses JS::ObjectOpResult to indicate conditions that ES6
|
||||
* specifies as non-error failures. This is inconvenient at best, so use this
|
||||
* function only if you are implementing a proxy handler's defineProperty()
|
||||
* method. For all other purposes, use one of the many DefineProperty functions
|
||||
* below that throw an exception in all failure cases.
|
||||
*
|
||||
* Implements: ES6 [[DefineOwnProperty]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ForwardSetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult& result);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
JS::ObjectOpResult& result);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, jsid id);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult& result);
|
||||
|
||||
/**
|
||||
* Define a property on obj, throwing a TypeError if the attempt fails.
|
||||
* This is the C++ equivalent of `Object.defineProperty(obj, id, desc)`.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::Handle<JSPropertyDescriptor> desc);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleString value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, int32_t value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, uint32_t value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, double value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleObject value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleString value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, int32_t value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, uint32_t value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, double value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult& result);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::Handle<JSPropertyDescriptor> desc);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::HandleValue value, unsigned attrs,
|
||||
|
@ -2966,36 +2953,370 @@ JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, s
|
|||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double value,
|
||||
unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
/**
|
||||
* Compute the expression `id in obj`.
|
||||
*
|
||||
* If obj has an own or inherited property obj[id], set *foundp = true and
|
||||
* return true. If not, set *foundp = false and return true. On error, return
|
||||
* false with an exception pending.
|
||||
*
|
||||
* Implements: ES6 [[Has]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
bool* vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp);
|
||||
|
||||
/**
|
||||
* Determine whether obj has an own property with the key `id`.
|
||||
*
|
||||
* Implements: ES6 7.3.11 HasOwnProperty(O, P).
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp);
|
||||
|
||||
/**
|
||||
* Get the value of the property `obj[id]`, or undefined if no such property
|
||||
* exists. This is the C++ equivalent of `vp = Reflect.get(obj, id, receiver)`.
|
||||
*
|
||||
* Most callers don't need the `receiver` argument. Consider using
|
||||
* JS_GetProperty instead. (But if you're implementing a proxy handler's set()
|
||||
* method, it's often correct to call this function and pass the receiver
|
||||
* through.)
|
||||
*
|
||||
* Implements: ES6 [[Get]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::HandleValue receiver, JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ForwardGetElementTo(JSContext* cx, JS::HandleObject obj, uint32_t index,
|
||||
JS::HandleObject receiver, JS::MutableHandleValue vp);
|
||||
|
||||
/**
|
||||
* Get the value of the property `obj[id]`, or undefined if no such property
|
||||
* exists. The result is stored in vp.
|
||||
*
|
||||
* Implements: ES6 7.3.1 Get(O, P).
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp);
|
||||
|
||||
/**
|
||||
* Perform the same property assignment as `Reflect.set(obj, id, v, receiver)`.
|
||||
*
|
||||
* This function has a `receiver` argument that most callers don't need.
|
||||
* Consider using JS_SetProperty instead.
|
||||
*
|
||||
* Implements: ES6 [[Set]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ForwardSetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult& result);
|
||||
|
||||
/**
|
||||
* Perform the assignment `obj[id] = v`.
|
||||
*
|
||||
* This function performs non-strict assignment, so if the property is
|
||||
* read-only, nothing happens and no error is thrown.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::HandleValue v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double v);
|
||||
|
||||
/**
|
||||
* Delete a property. This is the C++ equivalent of
|
||||
* `result = Reflect.deleteProperty(obj, id)`.
|
||||
*
|
||||
* This function has a `result` out parameter that most callers don't need.
|
||||
* Unless you can pass through an ObjectOpResult provided by your caller, it's
|
||||
* probably best to use the JS_DeletePropertyById signature with just 3
|
||||
* arguments.
|
||||
*
|
||||
* Implements: ES6 [[Delete]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::ObjectOpResult& result);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
JS::ObjectOpResult& result);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::ObjectOpResult& result);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::Handle<JSPropertyDescriptor> desc);
|
||||
JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::ObjectOpResult& result);
|
||||
|
||||
/**
|
||||
* Delete a property, ignoring strict failures. This is the C++ equivalent of
|
||||
* the JS `delete obj[id]` in non-strict mode code.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, jsid id);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index);
|
||||
|
||||
/**
|
||||
* Get an array of the non-symbol enumerable properties of obj.
|
||||
* This function is roughly equivalent to:
|
||||
*
|
||||
* var result = [];
|
||||
* for (key in obj)
|
||||
* result.push(key);
|
||||
* return result;
|
||||
*
|
||||
* This is the closest thing we currently have to the ES6 [[Enumerate]]
|
||||
* internal method.
|
||||
*
|
||||
* The JSIdArray returned by JS_Enumerate must be rooted to protect its
|
||||
* contents from garbage collection. Use JS::AutoIdArray.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle<JS::IdVector> props);
|
||||
|
||||
/*
|
||||
* API for determining callability and constructability. [[Call]] and
|
||||
* [[Construct]] are internal methods that aren't present on all objects, so it
|
||||
* is useful to ask if they are there or not. The standard itself asks these
|
||||
* questions routinely.
|
||||
*/
|
||||
namespace JS {
|
||||
|
||||
/**
|
||||
* Return true if the given object is callable. In ES6 terms, an object is
|
||||
* callable if it has a [[Call]] internal method.
|
||||
*
|
||||
* Implements: ES6 7.2.3 IsCallable(argument).
|
||||
*
|
||||
* Functions are callable. A scripted proxy or wrapper is callable if its
|
||||
* target is callable. Most other objects aren't callable.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsCallable(JSObject* obj);
|
||||
|
||||
/**
|
||||
* Return true if the given object is a constructor. In ES6 terms, an object is
|
||||
* a constructor if it has a [[Construct]] internal method. The expression
|
||||
* `new obj()` throws a TypeError if obj is not a constructor.
|
||||
*
|
||||
* Implements: ES6 7.2.4 IsConstructor(argument).
|
||||
*
|
||||
* JS functions and classes are constructors. Arrow functions and most builtin
|
||||
* functions are not. A scripted proxy or wrapper is a constructor if its
|
||||
* target is a constructor.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsConstructor(JSObject* obj);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/**
|
||||
* Call a function, passing a this-value and arguments. This is the C++
|
||||
* equivalent of `rval = Reflect.apply(fun, obj, args)`.
|
||||
*
|
||||
* Implements: ES6 7.3.12 Call(F, V, [argumentsList]).
|
||||
* Use this function to invoke the [[Call]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_CallFunctionValue(JSContext* cx, JS::HandleObject obj, JS::HandleValue fval,
|
||||
const JS::HandleValueArray& args, JS::MutableHandleValue rval);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_CallFunction(JSContext* cx, JS::HandleObject obj, JS::HandleFunction fun,
|
||||
const JS::HandleValueArray& args, JS::MutableHandleValue rval);
|
||||
|
||||
/**
|
||||
* Perform the method call `rval = obj[name](args)`.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_CallFunctionName(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
const JS::HandleValueArray& args, JS::MutableHandleValue rval);
|
||||
|
||||
namespace JS {
|
||||
|
||||
static inline bool
|
||||
Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleFunction fun,
|
||||
const JS::HandleValueArray& args, MutableHandleValue rval)
|
||||
{
|
||||
return !!JS_CallFunction(cx, thisObj, fun, args, rval);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleValue fun, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Call(JSContext* cx, JS::HandleObject thisObj, const char* name, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
return !!JS_CallFunctionName(cx, thisObj, name, args, rval);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Call(JSContext* cx, JS::HandleValue thisv, JS::HandleValue fun, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval);
|
||||
|
||||
static inline bool
|
||||
Call(JSContext* cx, JS::HandleValue thisv, JS::HandleObject funObj, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
MOZ_ASSERT(funObj);
|
||||
JS::RootedValue fun(cx, JS::ObjectValue(*funObj));
|
||||
return Call(cx, thisv, fun, args, rval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a constructor. This is the C++ equivalent of
|
||||
* `rval = Reflect.construct(fun, args, newTarget)`.
|
||||
*
|
||||
* JS::Construct() takes a `newTarget` argument that most callers don't need.
|
||||
* Consider using the four-argument Construct signature instead. (But if you're
|
||||
* implementing a subclass or a proxy handler's construct() method, this is the
|
||||
* right function to call.)
|
||||
*
|
||||
* Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]).
|
||||
* Use this function to invoke the [[Construct]] internal method.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Construct(JSContext* cx, JS::HandleValue fun, HandleObject newTarget,
|
||||
const JS::HandleValueArray &args, MutableHandleValue rval);
|
||||
|
||||
/**
|
||||
* Invoke a constructor. This is the C++ equivalent of
|
||||
* `rval = new fun(...args)`.
|
||||
*
|
||||
* The value left in rval on success is always an object in practice,
|
||||
* though at the moment this is not enforced by the C++ type system.
|
||||
*
|
||||
* Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]), when
|
||||
* newTarget is omitted.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Construct(JSContext* cx, JS::HandleValue fun, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/**
|
||||
* Invoke a constructor, like the JS expression `new ctor(...args)`. Returns
|
||||
* the new object, or null on error.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args);
|
||||
|
||||
|
||||
/*** Other property-defining functions ***********************************************************/
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_DefineObject(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
const JSClass* clasp = nullptr, unsigned attrs = 0);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineConstDoubles(JSContext* cx, JS::HandleObject obj, const JSConstDoubleSpec* cds);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineConstIntegers(JSContext* cx, JS::HandleObject obj, const JSConstIntegerSpec* cis);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProperties(JSContext* cx, JS::HandleObject obj, const JSPropertySpec* ps);
|
||||
|
||||
|
||||
/* * */
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_AlreadyHasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_AlreadyHasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_AlreadyHasOwnUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name,
|
||||
size_t namelen, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasUCProperty(JSContext* cx, JS::HandleObject obj,
|
||||
const char16_t* name, size_t namelen,
|
||||
bool* vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetUCProperty(JSContext* cx, JS::HandleObject obj,
|
||||
const char16_t* name, size_t namelen,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetUCProperty(JSContext* cx, JS::HandleObject obj,
|
||||
const char16_t* name, size_t namelen,
|
||||
JS::HandleValue v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
|
||||
JS::ObjectOpResult& result);
|
||||
JS_AlreadyHasOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_NewArrayObject(JSContext* cx, const JS::HandleValueArray& contents);
|
||||
|
@ -3025,73 +3346,6 @@ JS_GetArrayLength(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t* lengthp);
|
|||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetArrayLength(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t length);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double value,
|
||||
unsigned attrs,
|
||||
JSNative getter = nullptr, JSNative setter = nullptr);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_AlreadyHasOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ForwardGetElementTo(JSContext* cx, JS::HandleObject obj, uint32_t index,
|
||||
JS::HandleObject onBehalfOf, JS::MutableHandleValue vp);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double v);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::ObjectOpResult& result);
|
||||
|
||||
/*
|
||||
* Assign 'undefined' to all of the object's non-reserved slots. Note: this is
|
||||
* done for all slots, regardless of the associated property descriptor.
|
||||
|
@ -3141,15 +3395,13 @@ JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length);
|
|||
extern JS_PUBLIC_API(void)
|
||||
JS_ReleaseMappedArrayBufferContents(void* contents, size_t length);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle<JS::IdVector> props);
|
||||
|
||||
extern JS_PUBLIC_API(JS::Value)
|
||||
JS_GetReservedSlot(JSObject* obj, uint32_t index);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetReservedSlot(JSObject* obj, uint32_t index, JS::Value v);
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -3206,20 +3458,6 @@ JS_GetFunctionDisplayId(JSFunction* fun);
|
|||
extern JS_PUBLIC_API(uint16_t)
|
||||
JS_GetFunctionArity(JSFunction* fun);
|
||||
|
||||
/*
|
||||
* API for determining callability and constructability. This does the right
|
||||
* thing for proxies.
|
||||
*/
|
||||
namespace JS {
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsCallable(JSObject* obj);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsConstructor(JSObject* obj);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/*
|
||||
* Infallible predicate to test whether obj is a function object (faster than
|
||||
* comparing obj's class name to "Function", but equivalent unless someone has
|
||||
|
@ -3918,66 +4156,6 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
|
|||
|
||||
} /* namespace JS */
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_CallFunction(JSContext* cx, JS::HandleObject obj, JS::HandleFunction fun,
|
||||
const JS::HandleValueArray& args, JS::MutableHandleValue rval);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_CallFunctionName(JSContext* cx, JS::HandleObject obj, const char* name,
|
||||
const JS::HandleValueArray& args, JS::MutableHandleValue rval);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_CallFunctionValue(JSContext* cx, JS::HandleObject obj, JS::HandleValue fval,
|
||||
const JS::HandleValueArray& args, JS::MutableHandleValue rval);
|
||||
|
||||
namespace JS {
|
||||
|
||||
static inline bool
|
||||
Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleFunction fun,
|
||||
const JS::HandleValueArray& args, MutableHandleValue rval)
|
||||
{
|
||||
return !!JS_CallFunction(cx, thisObj, fun, args, rval);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Call(JSContext* cx, JS::HandleObject thisObj, const char* name, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
return !!JS_CallFunctionName(cx, thisObj, name, args, rval);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleValue fun, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Call(JSContext* cx, JS::HandleValue thisv, JS::HandleValue fun, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval);
|
||||
|
||||
static inline bool
|
||||
Call(JSContext* cx, JS::HandleValue thisv, JS::HandleObject funObj, const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
MOZ_ASSERT(funObj);
|
||||
JS::RootedValue fun(cx, JS::ObjectValue(*funObj));
|
||||
return Call(cx, thisv, fun, args, rval);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Construct(JSContext* cx, JS::HandleValue fun,
|
||||
const JS::HandleValueArray& args,
|
||||
MutableHandleValue rval);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
Construct(JSContext* cx, JS::HandleValue fun,
|
||||
HandleObject newTarget, const JS::HandleValueArray &args,
|
||||
MutableHandleValue rval);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_CheckForInterrupt(JSContext* cx);
|
||||
|
||||
|
|
|
@ -509,6 +509,10 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']:
|
|||
elif CONFIG['JS_CODEGEN_MIPS64']:
|
||||
UNIFIED_SOURCES += [
|
||||
'jit/mips64/Architecture-mips64.cpp',
|
||||
'jit/mips64/Assembler-mips64.cpp',
|
||||
'jit/mips64/Bailouts-mips64.cpp',
|
||||
'jit/mips64/BaselineCompiler-mips64.cpp',
|
||||
'jit/mips64/BaselineIC-mips64.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
|
|
|
@ -7,12 +7,15 @@
|
|||
#ifndef vm_SavedFrame_h
|
||||
#define vm_SavedFrame_h
|
||||
|
||||
#include "jswrapper.h"
|
||||
|
||||
#include "js/UbiNode.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class SavedFrame : public NativeObject {
|
||||
friend class SavedStacks;
|
||||
friend struct ::JSStructuredCloneReader;
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
|
@ -120,6 +123,13 @@ class SavedFrame : public NativeObject {
|
|||
!obj.as<SavedFrame>().getReservedSlot(JSSLOT_SOURCE).isNull();
|
||||
}
|
||||
|
||||
static bool isSavedFrameOrWrapperAndNotProto(JSObject& obj) {
|
||||
auto unwrapped = CheckedUnwrap(&obj);
|
||||
if (!unwrapped)
|
||||
return false;
|
||||
return isSavedFrameAndNotProto(*unwrapped);
|
||||
}
|
||||
|
||||
struct Lookup;
|
||||
struct HashPolicy;
|
||||
|
||||
|
@ -142,8 +152,17 @@ class SavedFrame : public NativeObject {
|
|||
};
|
||||
|
||||
private:
|
||||
static SavedFrame* create(JSContext* cx);
|
||||
static bool finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject proto);
|
||||
void initFromLookup(HandleLookup lookup);
|
||||
void initSource(JSAtom* source);
|
||||
void initLine(uint32_t line);
|
||||
void initColumn(uint32_t column);
|
||||
void initFunctionDisplayName(JSAtom* maybeName);
|
||||
void initAsyncCause(JSAtom* maybeCause);
|
||||
void initParent(SavedFrame* maybeParent);
|
||||
void initPrincipalsAlreadyHeld(JSPrincipals* principals);
|
||||
void initPrincipals(JSPrincipals* principals);
|
||||
|
||||
enum {
|
||||
// The reserved slots in the SavedFrame class.
|
||||
|
|
|
@ -22,13 +22,7 @@
|
|||
inline void
|
||||
js::AssertObjectIsSavedFrameOrWrapper(JSContext* cx, HandleObject stack)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (stack) {
|
||||
RootedObject savedFrameObj(cx, CheckedUnwrap(stack));
|
||||
MOZ_ASSERT(savedFrameObj);
|
||||
MOZ_ASSERT(js::SavedFrame::isSavedFrameAndNotProto(*savedFrameObj));
|
||||
}
|
||||
#endif
|
||||
MOZ_ASSERT_IF(stack, js::SavedFrame::isSavedFrameOrWrapperAndNotProto(*stack));
|
||||
}
|
||||
|
||||
#endif // vm_SavedStacksInl_h
|
||||
|
|
|
@ -406,29 +406,91 @@ SavedFrame::getPrincipals()
|
|||
return static_cast<JSPrincipals*>(v.toPrivate());
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initSource(JSAtom* source)
|
||||
{
|
||||
MOZ_ASSERT(source);
|
||||
initReservedSlot(JSSLOT_SOURCE, StringValue(source));
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initLine(uint32_t line)
|
||||
{
|
||||
initReservedSlot(JSSLOT_LINE, PrivateUint32Value(line));
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initColumn(uint32_t column)
|
||||
{
|
||||
initReservedSlot(JSSLOT_COLUMN, PrivateUint32Value(column));
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initPrincipals(JSPrincipals* principals)
|
||||
{
|
||||
if (principals)
|
||||
JS_HoldPrincipals(principals);
|
||||
initPrincipalsAlreadyHeld(principals);
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initPrincipalsAlreadyHeld(JSPrincipals* principals)
|
||||
{
|
||||
MOZ_ASSERT_IF(principals, principals->refcount > 0);
|
||||
initReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(principals));
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initFunctionDisplayName(JSAtom* maybeName)
|
||||
{
|
||||
initReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME, maybeName ? StringValue(maybeName) : NullValue());
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initAsyncCause(JSAtom* maybeCause)
|
||||
{
|
||||
initReservedSlot(JSSLOT_ASYNCCAUSE, maybeCause ? StringValue(maybeCause) : NullValue());
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initParent(SavedFrame* maybeParent)
|
||||
{
|
||||
initReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(maybeParent));
|
||||
}
|
||||
|
||||
void
|
||||
SavedFrame::initFromLookup(SavedFrame::HandleLookup lookup)
|
||||
{
|
||||
MOZ_ASSERT(lookup->source);
|
||||
MOZ_ASSERT(getReservedSlot(JSSLOT_SOURCE).isUndefined());
|
||||
setReservedSlot(JSSLOT_SOURCE, StringValue(lookup->source));
|
||||
initSource(lookup->source);
|
||||
initLine(lookup->line);
|
||||
initColumn(lookup->column);
|
||||
initFunctionDisplayName(lookup->functionDisplayName);
|
||||
initAsyncCause(lookup->asyncCause);
|
||||
initParent(lookup->parent);
|
||||
initPrincipals(lookup->principals);
|
||||
}
|
||||
|
||||
setReservedSlot(JSSLOT_LINE, PrivateUint32Value(lookup->line));
|
||||
setReservedSlot(JSSLOT_COLUMN, PrivateUint32Value(lookup->column));
|
||||
setReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME,
|
||||
lookup->functionDisplayName
|
||||
? StringValue(lookup->functionDisplayName)
|
||||
: NullValue());
|
||||
setReservedSlot(JSSLOT_ASYNCCAUSE,
|
||||
lookup->asyncCause
|
||||
? StringValue(lookup->asyncCause)
|
||||
: NullValue());
|
||||
setReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(lookup->parent));
|
||||
/* static */ SavedFrame*
|
||||
SavedFrame::create(JSContext* cx)
|
||||
{
|
||||
RootedGlobalObject global(cx, cx->global());
|
||||
assertSameCompartment(cx, global);
|
||||
|
||||
MOZ_ASSERT(getReservedSlot(JSSLOT_PRINCIPALS).isUndefined());
|
||||
if (lookup->principals)
|
||||
JS_HoldPrincipals(lookup->principals);
|
||||
setReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(lookup->principals));
|
||||
// Ensure that we don't try to capture the stack again in the
|
||||
// `SavedStacksMetadataCallback` for this new SavedFrame object, and
|
||||
// accidentally cause O(n^2) behavior.
|
||||
SavedStacks::AutoReentrancyGuard guard(cx->compartment()->savedStacks());
|
||||
|
||||
RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
assertSameCompartment(cx, proto);
|
||||
|
||||
RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto));
|
||||
if (!frameObj)
|
||||
return nullptr;
|
||||
|
||||
return &frameObj->as<SavedFrame>();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1222,30 +1284,15 @@ SavedStacks::getOrCreateSavedFrame(JSContext* cx, SavedFrame::HandleLookup looku
|
|||
SavedFrame*
|
||||
SavedStacks::createFrameFromLookup(JSContext* cx, SavedFrame::HandleLookup lookup)
|
||||
{
|
||||
RootedGlobalObject global(cx, cx->global());
|
||||
assertSameCompartment(cx, global);
|
||||
|
||||
// Ensure that we don't try to capture the stack again in the
|
||||
// `SavedStacksMetadataCallback` for this new SavedFrame object, and
|
||||
// accidentally cause O(n^2) behavior.
|
||||
SavedStacks::AutoReentrancyGuard guard(*this);
|
||||
|
||||
RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
|
||||
if (!proto)
|
||||
RootedSavedFrame frame(cx, SavedFrame::create(cx));
|
||||
if (!frame)
|
||||
return nullptr;
|
||||
assertSameCompartment(cx, proto);
|
||||
frame->initFromLookup(lookup);
|
||||
|
||||
RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto));
|
||||
if (!frameObj)
|
||||
if (!FreezeObject(cx, frame))
|
||||
return nullptr;
|
||||
|
||||
RootedSavedFrame f(cx, &frameObj->as<SavedFrame>());
|
||||
f->initFromLookup(lookup);
|
||||
|
||||
if (!FreezeObject(cx, frameObj))
|
||||
return nullptr;
|
||||
|
||||
return f.get();
|
||||
return frame;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -148,6 +148,7 @@ namespace js {
|
|||
// principals.
|
||||
|
||||
class SavedStacks {
|
||||
friend class SavedFrame;
|
||||
friend JSObject* SavedStacksMetadataCallback(JSContext* cx, JSObject* target);
|
||||
friend bool JS::ubi::ConstructSavedFrameStackSlow(JSContext* cx,
|
||||
JS::ubi::StackFrame& ubiFrame,
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "builtin/MapObject.h"
|
||||
#include "js/Date.h"
|
||||
#include "js/TraceableHashTable.h"
|
||||
#include "vm/SavedFrame.h"
|
||||
#include "vm/SharedArrayObject.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
|
@ -92,6 +93,12 @@ enum StructuredDataType : uint32_t {
|
|||
SCTAG_END_OF_KEYS,
|
||||
SCTAG_SHARED_TYPED_ARRAY_OBJECT,
|
||||
SCTAG_DATA_VIEW_OBJECT,
|
||||
SCTAG_SAVED_FRAME_OBJECT,
|
||||
|
||||
SCTAG_JSPRINCIPALS,
|
||||
SCTAG_NULL_JSPRINCIPALS,
|
||||
SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM,
|
||||
SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM,
|
||||
|
||||
SCTAG_TYPED_ARRAY_V1_MIN = 0xFFFF0100,
|
||||
SCTAG_TYPED_ARRAY_V1_INT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int8,
|
||||
|
@ -243,6 +250,7 @@ struct JSStructuredCloneReader {
|
|||
bool readSharedTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp);
|
||||
bool readArrayBuffer(uint32_t nbytes, MutableHandleValue vp);
|
||||
bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp);
|
||||
JSObject* readSavedFrame(uint32_t principalsTag);
|
||||
bool startRead(MutableHandleValue vp);
|
||||
|
||||
SCInput& in;
|
||||
|
@ -305,6 +313,7 @@ struct JSStructuredCloneWriter {
|
|||
bool traverseObject(HandleObject obj);
|
||||
bool traverseMap(HandleObject obj);
|
||||
bool traverseSet(HandleObject obj);
|
||||
bool traverseSavedFrame(HandleObject obj);
|
||||
|
||||
bool parseTransferable();
|
||||
bool reportErrorTransferable(uint32_t errorId);
|
||||
|
@ -324,9 +333,10 @@ struct JSStructuredCloneWriter {
|
|||
// counts.length() == objs.length() and sum(counts) == entries.length().
|
||||
Vector<size_t> counts;
|
||||
|
||||
// For JSObject: Propery IDs as value
|
||||
// For Map: Key followed by value.
|
||||
// For JSObject: Property IDs as value
|
||||
// For Map: Key followed by value
|
||||
// For Set: Key
|
||||
// For SavedFrame: parent SavedFrame
|
||||
AutoValueVector entries;
|
||||
|
||||
// The "memory" list described in the HTML5 internal structured cloning algorithm.
|
||||
|
@ -1037,6 +1047,103 @@ JSStructuredCloneWriter::traverseSet(HandleObject obj)
|
|||
return out.writePair(SCTAG_SET_OBJECT, 0);
|
||||
}
|
||||
|
||||
// Objects are written as a "preorder" traversal of the object graph: object
|
||||
// "headers" (the class tag and any data needed for initial construction) are
|
||||
// visited first, then the children are recursed through (where children are
|
||||
// properties, Set or Map entries, etc.). So for example
|
||||
//
|
||||
// m = new Map();
|
||||
// m.set(key1 = {}, value1 = {})
|
||||
//
|
||||
// would be stored as
|
||||
//
|
||||
// <Map tag>
|
||||
// <key1 class tag>
|
||||
// <value1 class tag>
|
||||
// <end-of-children marker for key1>
|
||||
// <end-of-children marker for value1>
|
||||
// <end-of-children marker for Map>
|
||||
//
|
||||
// Notice how the end-of-children marker for key1 is sandwiched between the
|
||||
// value1 beginning and end.
|
||||
bool
|
||||
JSStructuredCloneWriter::traverseSavedFrame(HandleObject obj)
|
||||
{
|
||||
RootedObject unwrapped(context(), js::CheckedUnwrap(obj));
|
||||
MOZ_ASSERT(unwrapped && unwrapped->is<SavedFrame>());
|
||||
|
||||
RootedSavedFrame savedFrame(context(), &unwrapped->as<SavedFrame>());
|
||||
|
||||
RootedObject parent(context(), savedFrame->getParent());
|
||||
if (!context()->compartment()->wrap(context(), &parent))
|
||||
return false;
|
||||
|
||||
if (!objs.append(ObjectValue(*obj)) ||
|
||||
!entries.append(parent ? ObjectValue(*parent) : NullValue()) ||
|
||||
!counts.append(1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
checkStack();
|
||||
|
||||
// Write the SavedFrame tag and the SavedFrame's principals.
|
||||
|
||||
if (savedFrame->getPrincipals() == &ReconstructedSavedFramePrincipals::IsSystem) {
|
||||
if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT,
|
||||
SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM))
|
||||
{
|
||||
return false;
|
||||
};
|
||||
} else if (savedFrame->getPrincipals() == &ReconstructedSavedFramePrincipals::IsNotSystem) {
|
||||
if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT,
|
||||
SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (auto principals = savedFrame->getPrincipals()) {
|
||||
if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT, SCTAG_JSPRINCIPALS) ||
|
||||
!principals->write(context(), this))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT, SCTAG_NULL_JSPRINCIPALS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the SavedFrame's reserved slots, except for the parent, which is
|
||||
// queued on objs for further traversal.
|
||||
|
||||
RootedValue val(context());
|
||||
|
||||
val = StringValue(savedFrame->getSource());
|
||||
if (!startWrite(val))
|
||||
return false;
|
||||
|
||||
val = NumberValue(savedFrame->getLine());
|
||||
if (!startWrite(val))
|
||||
return false;
|
||||
|
||||
val = NumberValue(savedFrame->getColumn());
|
||||
if (!startWrite(val))
|
||||
return false;
|
||||
|
||||
auto name = savedFrame->getFunctionDisplayName();
|
||||
val = name ? StringValue(name) : NullValue();
|
||||
if (!startWrite(val))
|
||||
return false;
|
||||
|
||||
auto cause = savedFrame->getAsyncCause();
|
||||
val = cause ? StringValue(cause) : NullValue();
|
||||
if (!startWrite(val))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::startWrite(HandleValue v)
|
||||
{
|
||||
|
@ -1111,6 +1218,8 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
|
|||
return traverseMap(obj);
|
||||
} else if (cls == ESClass_Set) {
|
||||
return traverseSet(obj);
|
||||
} else if (SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
|
||||
return traverseSavedFrame(obj);
|
||||
}
|
||||
|
||||
if (callbacks && callbacks->write)
|
||||
|
@ -1268,7 +1377,7 @@ JSStructuredCloneWriter::write(HandleValue v)
|
|||
|
||||
if (!startWrite(key) || !startWrite(val))
|
||||
return false;
|
||||
} else if (cls == ESClass_Set) {
|
||||
} else if (cls == ESClass_Set || SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
|
||||
if (!startWrite(key))
|
||||
return false;
|
||||
} else {
|
||||
|
@ -1777,6 +1886,14 @@ JSStructuredCloneReader::startRead(MutableHandleValue vp)
|
|||
break;
|
||||
}
|
||||
|
||||
case SCTAG_SAVED_FRAME_OBJECT: {
|
||||
auto obj = readSavedFrame(data);
|
||||
if (!obj || !objs.append(ObjectValue(*obj)))
|
||||
return false;
|
||||
vp.setObject(*obj);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (tag <= SCTAG_FLOAT_MAX) {
|
||||
double d = ReinterpretPairAsDouble(tag, data);
|
||||
|
@ -1894,16 +2011,99 @@ JSStructuredCloneReader::readTransferMap()
|
|||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
JSStructuredCloneReader::readSavedFrame(uint32_t principalsTag)
|
||||
{
|
||||
RootedSavedFrame savedFrame(context(), SavedFrame::create(context()));
|
||||
if (!savedFrame)
|
||||
return nullptr;
|
||||
|
||||
JSPrincipals* principals;
|
||||
if (principalsTag == SCTAG_JSPRINCIPALS) {
|
||||
if (!context()->runtime()->readPrincipals) {
|
||||
JS_ReportErrorNumber(context(), GetErrorMessage, nullptr,
|
||||
JSMSG_SC_UNSUPPORTED_TYPE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!context()->runtime()->readPrincipals(context(), this, &principals))
|
||||
return nullptr;
|
||||
} else if (principalsTag == SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM) {
|
||||
principals = &ReconstructedSavedFramePrincipals::IsSystem;
|
||||
principals->refcount++;
|
||||
} else if (principalsTag == SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM) {
|
||||
principals = &ReconstructedSavedFramePrincipals::IsNotSystem;
|
||||
principals->refcount++;
|
||||
} else if (principalsTag == SCTAG_NULL_JSPRINCIPALS) {
|
||||
principals = nullptr;
|
||||
} else {
|
||||
JS_ReportErrorNumber(context(), GetErrorMessage, nullptr,
|
||||
JSMSG_SC_BAD_SERIALIZED_DATA, "bad SavedFrame principals");
|
||||
return nullptr;
|
||||
}
|
||||
savedFrame->initPrincipalsAlreadyHeld(principals);
|
||||
|
||||
RootedValue source(context());
|
||||
if (!startRead(&source) || !source.isString())
|
||||
return nullptr;
|
||||
auto atomSource = AtomizeString(context(), source.toString());
|
||||
if (!atomSource)
|
||||
return nullptr;
|
||||
savedFrame->initSource(atomSource);
|
||||
|
||||
RootedValue lineVal(context());
|
||||
uint32_t line;
|
||||
if (!startRead(&lineVal) || !lineVal.isNumber() || !ToUint32(context(), lineVal, &line))
|
||||
return nullptr;
|
||||
savedFrame->initLine(line);
|
||||
|
||||
RootedValue columnVal(context());
|
||||
uint32_t column;
|
||||
if (!startRead(&columnVal) || !columnVal.isNumber() || !ToUint32(context(), columnVal, &column))
|
||||
return nullptr;
|
||||
savedFrame->initColumn(column);
|
||||
|
||||
RootedValue name(context());
|
||||
if (!startRead(&name) || !(name.isString() || name.isNull()))
|
||||
return nullptr;
|
||||
JSAtom* atomName = nullptr;
|
||||
if (name.isString()) {
|
||||
atomName = AtomizeString(context(), name.toString());
|
||||
if (!atomName)
|
||||
return nullptr;
|
||||
}
|
||||
savedFrame->initFunctionDisplayName(atomName);
|
||||
|
||||
RootedValue cause(context());
|
||||
if (!startRead(&cause) || !(cause.isString() || cause.isNull()))
|
||||
return nullptr;
|
||||
JSAtom* atomCause = nullptr;
|
||||
if (cause.isString()) {
|
||||
atomCause = AtomizeString(context(), cause.toString());
|
||||
if (!atomCause)
|
||||
return nullptr;
|
||||
}
|
||||
savedFrame->initAsyncCause(atomCause);
|
||||
|
||||
return savedFrame;
|
||||
}
|
||||
|
||||
// Perform the whole recursive reading procedure.
|
||||
bool
|
||||
JSStructuredCloneReader::read(MutableHandleValue vp)
|
||||
{
|
||||
if (!readTransferMap())
|
||||
return false;
|
||||
|
||||
// Start out by reading in the main object and pushing it onto the 'objs'
|
||||
// stack. The data related to this object and its descendants extends from
|
||||
// here to the SCTAG_END_OF_KEYS at the end of the stream.
|
||||
if (!startRead(vp))
|
||||
return false;
|
||||
|
||||
// Stop when the stack shows that all objects have been read.
|
||||
while (objs.length() != 0) {
|
||||
// What happens depends on the top obj on the objs stack.
|
||||
RootedObject obj(context(), &objs.back().toObject());
|
||||
|
||||
uint32_t tag, data;
|
||||
|
@ -1911,36 +2111,76 @@ JSStructuredCloneReader::read(MutableHandleValue vp)
|
|||
return false;
|
||||
|
||||
if (tag == SCTAG_END_OF_KEYS) {
|
||||
// Pop the current obj off the stack, since we are done with it and
|
||||
// its children.
|
||||
MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
|
||||
objs.popBack();
|
||||
continue;
|
||||
}
|
||||
|
||||
// The input stream contains a sequence of "child" values, whose
|
||||
// interpretation depends on the type of obj. These values can be
|
||||
// anything, and startRead() will push onto 'objs' for any non-leaf
|
||||
// value (i.e., anything that may contain children).
|
||||
//
|
||||
// startRead() will allocate the (empty) object, but note that when
|
||||
// startRead() returns, 'key' is not yet initialized with any of its
|
||||
// properties. Those will be filled in by returning to the head of this
|
||||
// loop, processing the first child obj, and continuing until all
|
||||
// children have been fully created.
|
||||
//
|
||||
// Note that this means the ordering in the stream is a little funky
|
||||
// for things like Map. See the comment above startWrite() for an
|
||||
// example.
|
||||
RootedValue key(context());
|
||||
if (!startRead(&key))
|
||||
return false;
|
||||
|
||||
if (key.isNull() && !(obj->is<MapObject>() || obj->is<SetObject>())) {
|
||||
// Backwards compatibility: Null used to indicate
|
||||
// the end of object properties.
|
||||
if (key.isNull() &&
|
||||
!(obj->is<MapObject>() || obj->is<SetObject>() || obj->is<SavedFrame>()))
|
||||
{
|
||||
// Backwards compatibility: Null formerly indicated the end of
|
||||
// object properties.
|
||||
objs.popBack();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set object: the values between obj header (from startRead()) and
|
||||
// SCTAG_END_OF_KEYS are all interpreted as values to add to the set.
|
||||
if (obj->is<SetObject>()) {
|
||||
if (!SetObject::add(context(), obj, key))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// SavedFrame object: there is one following value, the parent
|
||||
// SavedFrame, which is either null or another SavedFrame object.
|
||||
if (obj->is<SavedFrame>()) {
|
||||
SavedFrame* parentFrame;
|
||||
if (key.isNull())
|
||||
parentFrame = nullptr;
|
||||
else if (key.isObject() && key.toObject().is<SavedFrame>())
|
||||
parentFrame = &key.toObject().as<SavedFrame>();
|
||||
else
|
||||
return false;
|
||||
|
||||
obj->as<SavedFrame>().initParent(parentFrame);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Everything else uses a series of key,value,key,value,... Value
|
||||
// objects.
|
||||
RootedValue val(context());
|
||||
if (!startRead(&val))
|
||||
return false;
|
||||
|
||||
if (obj->is<MapObject>()) {
|
||||
// For a Map, store those <key,value> pairs in the contained map
|
||||
// data structure.
|
||||
if (!MapObject::set(context(), obj, key, val))
|
||||
return false;
|
||||
} else {
|
||||
// For any other Object, interpret them as plain properties.
|
||||
RootedId id(context());
|
||||
if (!ValueToId<CanGC>(context(), key, &id))
|
||||
return false;
|
||||
|
|
|
@ -289,7 +289,7 @@ public:
|
|||
/**
|
||||
* Get the scrollframe to ignore, if any.
|
||||
*/
|
||||
nsIFrame* GetIgnoreScrollFrame() const { return mIgnoreScrollFrame; }
|
||||
nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; }
|
||||
/**
|
||||
* Get the ViewID of the nearest scrolling ancestor frame.
|
||||
*/
|
||||
|
|
|
@ -3037,25 +3037,6 @@ nsLayoutUtils::CalculateAndSetDisplayPortMargins(nsIScrollableFrame* aScrollFram
|
|||
content, presShell, displayportMargins, 0, aRepaintMode);
|
||||
}
|
||||
|
||||
bool
|
||||
nsLayoutUtils::WantDisplayPort(const nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aScrollFrame)
|
||||
{
|
||||
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame);
|
||||
if (!scrollableFrame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We perform an optimization where we ensure that at least one
|
||||
// async-scrollable frame (i.e. one that WantAsyncScroll()) has a displayport.
|
||||
// If that's not the case yet, and we are async-scrollable, we will get a
|
||||
// displayport.
|
||||
return aBuilder->IsPaintingToWindow() &&
|
||||
nsLayoutUtils::AsyncPanZoomEnabled(aScrollFrame) &&
|
||||
!aBuilder->HaveScrollableDisplayPort() &&
|
||||
scrollableFrame->WantAsyncScroll();
|
||||
}
|
||||
|
||||
bool
|
||||
nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
||||
nsIFrame* aScrollFrame,
|
||||
|
@ -3074,7 +3055,17 @@ nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
|||
|
||||
bool haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
|
||||
|
||||
if (WantDisplayPort(&aBuilder, aScrollFrame)) {
|
||||
// We perform an optimization where we ensure that at least one
|
||||
// async-scrollable frame (i.e. one that WantsAsyncScroll()) has a displayport.
|
||||
// If that's not the case yet, and we are async-scrollable, we will get a
|
||||
// displayport.
|
||||
// Note: we only do this in processes where we do subframe scrolling to
|
||||
// begin with (i.e., not in the parent process on B2G).
|
||||
if (aBuilder.IsPaintingToWindow() &&
|
||||
nsLayoutUtils::AsyncPanZoomEnabled(aScrollFrame) &&
|
||||
!aBuilder.HaveScrollableDisplayPort() &&
|
||||
scrollableFrame->WantAsyncScroll()) {
|
||||
|
||||
// If we don't already have a displayport, calculate and set one.
|
||||
if (!haveDisplayPort) {
|
||||
CalculateAndSetDisplayPortMargins(scrollableFrame, nsLayoutUtils::RepaintMode::DoNotRepaint);
|
||||
|
@ -3142,14 +3133,16 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
|||
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
||||
bool usingDisplayPort = false;
|
||||
nsRect displayport;
|
||||
if (rootScrollFrame && !aFrame->GetParent() &&
|
||||
builder.IsPaintingToWindow() &&
|
||||
gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
nsRect displayportBase(
|
||||
nsPoint(0,0),
|
||||
nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame));
|
||||
usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
|
||||
builder, rootScrollFrame, displayportBase, &displayport);
|
||||
if (rootScrollFrame && !aFrame->GetParent()) {
|
||||
nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
|
||||
MOZ_ASSERT(rootScrollableFrame);
|
||||
displayport = aFrame->GetVisualOverflowRectRelativeToSelf();
|
||||
usingDisplayPort = rootScrollableFrame->DecideScrollableLayer(&builder,
|
||||
&displayport, /* aAllowCreateDisplayPort = */ true);
|
||||
|
||||
if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
usingDisplayPort = false;
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayList hoistedScrollItemStorage;
|
||||
|
|
|
@ -2651,12 +2651,6 @@ public:
|
|||
static bool CalculateAndSetDisplayPortMargins(nsIScrollableFrame* aScrollFrame,
|
||||
RepaintMode aRepaintMode);
|
||||
|
||||
/**
|
||||
* Return true if GetOrMaybeCreateDisplayPort would create a displayport.
|
||||
*/
|
||||
static bool WantDisplayPort(const nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aScrollFrame);
|
||||
|
||||
/**
|
||||
* Get the display port for |aScrollFrame|'s content. If |aScrollFrame|
|
||||
* WantsAsyncScroll() and we don't have a scrollable displayport yet (as
|
||||
|
|
|
@ -5851,20 +5851,15 @@ bool
|
|||
PresShell::AssumeAllImagesVisible()
|
||||
{
|
||||
static bool sImageVisibilityEnabled = true;
|
||||
static bool sImageVisibilityEnabledForBrowserElementsOnly = false;
|
||||
static bool sImageVisibilityPrefCached = false;
|
||||
|
||||
if (!sImageVisibilityPrefCached) {
|
||||
Preferences::AddBoolVarCache(&sImageVisibilityEnabled,
|
||||
"layout.imagevisibility.enabled", true);
|
||||
Preferences::AddBoolVarCache(&sImageVisibilityEnabledForBrowserElementsOnly,
|
||||
"layout.imagevisibility.enabled_for_browser_elements_only", false);
|
||||
sImageVisibilityPrefCached = true;
|
||||
}
|
||||
|
||||
if ((!sImageVisibilityEnabled &&
|
||||
!sImageVisibilityEnabledForBrowserElementsOnly) ||
|
||||
!mPresContext || !mDocument) {
|
||||
if (!sImageVisibilityEnabled || !mPresContext || !mDocument) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5878,14 +5873,6 @@ PresShell::AssumeAllImagesVisible()
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!sImageVisibilityEnabled &&
|
||||
sImageVisibilityEnabledForBrowserElementsOnly) {
|
||||
nsCOMPtr<nsIDocShell> docshell(mPresContext->GetDocShell());
|
||||
if (!docshell || !docshell->GetIsInBrowserElement()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "nsPluginFrame.h"
|
||||
#include <mozilla/layers/AxisPhysicsModel.h>
|
||||
#include <mozilla/layers/AxisPhysicsMSDModel.h>
|
||||
#include "mozilla/unused.h"
|
||||
#include <algorithm>
|
||||
#include <cstdlib> // for std::abs(int/long)
|
||||
#include <cmath> // for std::abs(float/double)
|
||||
|
@ -1845,7 +1846,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter,
|
|||
, mUpdateScrollbarAttributes(false)
|
||||
, mHasBeenScrolledRecently(false)
|
||||
, mCollapsedResizer(false)
|
||||
, mShouldBuildScrollableLayer(false)
|
||||
, mWillBuildScrollableLayer(false)
|
||||
, mIsScrollableLayerInRootContainer(false)
|
||||
, mHasBeenScrolled(false)
|
||||
, mIsResolutionSet(false)
|
||||
|
@ -2824,53 +2825,6 @@ ClipListsExceptCaret(nsDisplayListCollection* aLists,
|
|||
ClipItemsExceptCaret(aLists->Content(), aBuilder, aClipFrame, clip, aUsingDisplayPort);
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::IsUsingDisplayPort(const nsDisplayListBuilder* aBuilder) const
|
||||
{
|
||||
return aBuilder->IsPaintingToWindow() &&
|
||||
nsLayoutUtils::GetDisplayPort(mOuter->GetContent());
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::WillUseDisplayPort(const nsDisplayListBuilder* aBuilder) const
|
||||
{
|
||||
bool wantsDisplayPort = nsLayoutUtils::WantDisplayPort(aBuilder, mOuter);
|
||||
|
||||
if (mIsRoot && gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
// This condition mirrors the calls to GetOrMaybeCreateDisplayPort in
|
||||
// nsSubDocumentFrame::BuildDisplayList and nsLayoutUtils::PaintFrame.
|
||||
if (wantsDisplayPort) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// The following conditions mirror the checks in BuildDisplayList
|
||||
|
||||
if (IsUsingDisplayPort(aBuilder)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wantsDisplayPort;
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::WillBuildScrollableLayer(const nsDisplayListBuilder* aBuilder) const
|
||||
{
|
||||
if (WillUseDisplayPort(aBuilder)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return nsContentUtils::HasScrollgrab(mOuter->GetContent());
|
||||
}
|
||||
|
||||
void
|
||||
ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
|
@ -2911,21 +2865,14 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
bool createLayersForScrollbars = mIsRoot &&
|
||||
mOuter->PresContext()->IsRootContentDocument();
|
||||
|
||||
bool usingDisplayPort = IsUsingDisplayPort(aBuilder);
|
||||
mShouldBuildScrollableLayer = WillBuildScrollableLayer(aBuilder);
|
||||
|
||||
if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) {
|
||||
bool usingDisplayPort = aBuilder->IsPaintingToWindow() &&
|
||||
nsLayoutUtils::GetDisplayPort(mOuter->GetContent());
|
||||
|
||||
// Root scrollframes have FrameMetrics and clipping on their container
|
||||
// layers, so don't apply clipping again.
|
||||
mAddClipRectToLayer = false;
|
||||
|
||||
if (usingDisplayPort) {
|
||||
// There is a display port for this frame, so we want to appear as having
|
||||
// active scrolling, so that animated geometry roots are assigned correctly.
|
||||
MOZ_ASSERT(mShouldBuildScrollableLayer);
|
||||
mIsScrollableLayerInRootContainer = true;
|
||||
}
|
||||
|
||||
// If we are a root scroll frame that has a display port we want to add
|
||||
// scrollbars, they will be children of the scrollable layer, but they get
|
||||
// adjusted by the APZC automatically.
|
||||
|
@ -2967,53 +2914,22 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
// dirty rect here.
|
||||
nsRect dirtyRect = aDirtyRect.Intersect(mScrollPort);
|
||||
|
||||
nsRect displayPort;
|
||||
if (aBuilder->IsPaintingToWindow()) {
|
||||
bool wasUsingDisplayPort = usingDisplayPort;
|
||||
unused << DecideScrollableLayer(aBuilder, &dirtyRect,
|
||||
/* aAllowCreateDisplayPort = */ !mIsRoot);
|
||||
|
||||
if (mIsRoot && gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
// For a root frame in a container, just get the value of the existing
|
||||
// display port if any.
|
||||
usingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort);
|
||||
} else {
|
||||
// Override the value of the display port base rect, and possibly create a
|
||||
// display port if there isn't one already.
|
||||
nsRect displayportBase = dirtyRect;
|
||||
if (mIsRoot && mOuter->PresContext()->IsRootContentDocument()) {
|
||||
displayportBase =
|
||||
nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter));
|
||||
}
|
||||
usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
|
||||
*aBuilder, mOuter, displayportBase, &displayPort);
|
||||
}
|
||||
bool usingDisplayPort = aBuilder->IsPaintingToWindow() &&
|
||||
nsLayoutUtils::GetDisplayPort(mOuter->GetContent());
|
||||
|
||||
// Override the dirty rectangle if the displayport has been set.
|
||||
if (usingDisplayPort) {
|
||||
dirtyRect = displayPort;
|
||||
|
||||
// The cached animated geometry root for the display builder is out of
|
||||
// date if we just introduced a new animated geometry root.
|
||||
if (!wasUsingDisplayPort) {
|
||||
aBuilder->RecomputeCurrentAnimatedGeometryRoot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since making new layers is expensive, only use nsDisplayScrollLayer
|
||||
// if the area is scrollable and we're the content process (unless we're on
|
||||
// B2G, where we support async scrolling for scrollable elements in the
|
||||
// parent process as well).
|
||||
// When a displayport is being used, force building of a layer so that
|
||||
// CompositorParent can always find the scrollable layer for the root content
|
||||
// document.
|
||||
// If the element is marked 'scrollgrab', also force building of a layer
|
||||
// so that APZ can implement scroll grabbing.
|
||||
MOZ_ASSERT(mShouldBuildScrollableLayer == (usingDisplayPort || nsContentUtils::HasScrollgrab(mOuter->GetContent())));
|
||||
bool shouldBuildLayer = false;
|
||||
if (mShouldBuildScrollableLayer) {
|
||||
shouldBuildLayer = true;
|
||||
// Whether we might want to build a scrollable layer for this scroll frame
|
||||
// at some point in the future. This controls whether we add the information
|
||||
// to the layer tree (a scroll info layer if necessary, and add the right
|
||||
// area to the dispatch to content layer event regions) necessary to activate
|
||||
// a scroll frame so it creates a scrollable layer.
|
||||
bool couldBuildLayer = false;
|
||||
if (mWillBuildScrollableLayer) {
|
||||
couldBuildLayer = true;
|
||||
} else {
|
||||
shouldBuildLayer =
|
||||
couldBuildLayer =
|
||||
nsLayoutUtils::AsyncPanZoomEnabled(mOuter) &&
|
||||
WantAsyncScroll() &&
|
||||
// If we are using containers for root frames, and we are the root
|
||||
|
@ -3083,7 +2999,7 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
// and scroll info layers.
|
||||
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
|
||||
aBuilder,
|
||||
shouldBuildLayer && mScrolledFrame->GetContent()
|
||||
couldBuildLayer && mScrolledFrame->GetContent()
|
||||
? nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent())
|
||||
: aBuilder->GetCurrentScrollParentId());
|
||||
|
||||
|
@ -3162,12 +3078,12 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
// above (where the idSetter variable is created).
|
||||
//
|
||||
// This is not compatible when using containes for root scrollframes.
|
||||
MOZ_ASSERT(shouldBuildLayer && mScrolledFrame->GetContent());
|
||||
mShouldBuildScrollableLayer = true;
|
||||
MOZ_ASSERT(couldBuildLayer && mScrolledFrame->GetContent());
|
||||
mWillBuildScrollableLayer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mShouldBuildScrollableLayer && !gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
if (mWillBuildScrollableLayer && !gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
aBuilder->ForceLayerForScrollParent();
|
||||
}
|
||||
|
||||
|
@ -3176,13 +3092,12 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
*contentBoxClipForNonCaretContent, usingDisplayPort);
|
||||
}
|
||||
|
||||
if (shouldBuildLayer) {
|
||||
if (couldBuildLayer) {
|
||||
// Make sure that APZ will dispatch events back to content so we can create
|
||||
// a displayport for this frame. We'll add the item later on.
|
||||
nsDisplayLayerEventRegions* inactiveRegionItem = nullptr;
|
||||
if (aBuilder->IsPaintingToWindow() &&
|
||||
!mShouldBuildScrollableLayer &&
|
||||
shouldBuildLayer &&
|
||||
!mWillBuildScrollableLayer &&
|
||||
aBuilder->IsBuildingLayerEventRegions())
|
||||
{
|
||||
inactiveRegionItem = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, mScrolledFrame);
|
||||
|
@ -3214,11 +3129,69 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
scrolledContent.MoveTo(aLists);
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRect* aDirtyRect,
|
||||
bool aAllowCreateDisplayPort)
|
||||
{
|
||||
bool usingDisplayPort = false;
|
||||
nsIContent* content = mOuter->GetContent();
|
||||
if (aBuilder->IsPaintingToWindow()) {
|
||||
bool wasUsingDisplayPort = nsLayoutUtils::GetDisplayPort(content);
|
||||
|
||||
nsRect displayportBase = *aDirtyRect;
|
||||
nsPresContext* pc = mOuter->PresContext();
|
||||
if (mIsRoot && (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
|
||||
displayportBase =
|
||||
nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter));
|
||||
}
|
||||
|
||||
nsRect displayPort;
|
||||
if (aAllowCreateDisplayPort) {
|
||||
// Provide the value of the display port base rect, and possibly create a
|
||||
// display port if there isn't one already.
|
||||
usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
|
||||
*aBuilder, mOuter, displayportBase, &displayPort);
|
||||
} else {
|
||||
// We should have already been called with aAllowCreateDisplayPort == true
|
||||
// which should have set a displayport base.
|
||||
MOZ_ASSERT(content->GetProperty(nsGkAtoms::DisplayPortBase));
|
||||
usingDisplayPort = nsLayoutUtils::GetDisplayPort(content, &displayPort);
|
||||
}
|
||||
|
||||
// Override the dirty rectangle if the displayport has been set.
|
||||
if (usingDisplayPort) {
|
||||
*aDirtyRect = displayPort;
|
||||
|
||||
// The cached animated geometry root for the display builder is out of
|
||||
// date if we just introduced a new animated geometry root.
|
||||
if (!wasUsingDisplayPort) {
|
||||
aBuilder->RecomputeCurrentAnimatedGeometryRoot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since making new layers is expensive, only create a scrollable layer
|
||||
// for some scroll frames.
|
||||
// When a displayport is being used, force building of a layer so that
|
||||
// the compositor can find the scrollable layer for async scrolling.
|
||||
// If the element is marked 'scrollgrab', also force building of a layer
|
||||
// so that APZ can implement scroll grabbing.
|
||||
mWillBuildScrollableLayer = usingDisplayPort || nsContentUtils::HasScrollgrab(content);
|
||||
|
||||
if (gfxPrefs::LayoutUseContainersForRootFrames() && mWillBuildScrollableLayer && mIsRoot) {
|
||||
mIsScrollableLayerInRootContainer = true;
|
||||
}
|
||||
|
||||
return mWillBuildScrollableLayer;
|
||||
}
|
||||
|
||||
|
||||
Maybe<DisplayItemClip>
|
||||
ScrollFrameHelper::ComputeScrollClip(bool aIsForCaret) const
|
||||
{
|
||||
const Maybe<DisplayItemClip>& ancestorClip = aIsForCaret ? mAncestorClipForCaret : mAncestorClip;
|
||||
if (!mShouldBuildScrollableLayer || mIsScrollableLayerInRootContainer) {
|
||||
if (!mWillBuildScrollableLayer || mIsScrollableLayerInRootContainer) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
|
@ -3231,7 +3204,7 @@ ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer,
|
|||
const ContainerLayerParameters& aParameters,
|
||||
bool aIsForCaret) const
|
||||
{
|
||||
if (!mShouldBuildScrollableLayer || mIsScrollableLayerInRootContainer) {
|
||||
if (!mWillBuildScrollableLayer || mIsScrollableLayerInRootContainer) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
|
@ -4498,7 +4471,7 @@ ScrollFrameHelper::IsMaybeScrollingActive() const
|
|||
|
||||
return mHasBeenScrolledRecently ||
|
||||
IsAlwaysActive() ||
|
||||
mShouldBuildScrollableLayer;
|
||||
mWillBuildScrollableLayer;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -4512,8 +4485,7 @@ ScrollFrameHelper::IsScrollingActive(nsDisplayListBuilder* aBuilder) const
|
|||
|
||||
return mHasBeenScrolledRecently ||
|
||||
IsAlwaysActive() ||
|
||||
mShouldBuildScrollableLayer ||
|
||||
WillBuildScrollableLayer(aBuilder);
|
||||
mWillBuildScrollableLayer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,10 +81,6 @@ public:
|
|||
bool aCreateLayer,
|
||||
bool aPositioned);
|
||||
|
||||
bool IsUsingDisplayPort(const nsDisplayListBuilder* aBuilder) const;
|
||||
bool WillUseDisplayPort(const nsDisplayListBuilder* aBuilder) const;
|
||||
bool WillBuildScrollableLayer(const nsDisplayListBuilder* aBuilder) const;
|
||||
|
||||
bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
|
||||
Sides aSkipSides, nscoord aRadii[8]) const;
|
||||
|
||||
|
@ -370,6 +366,10 @@ public:
|
|||
|
||||
bool UsesContainerScrolling() const;
|
||||
|
||||
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRect* aDirtyRect,
|
||||
bool aAllowCreateDisplayPort);
|
||||
|
||||
void ScheduleSyntheticMouseMove();
|
||||
static void ScrollActivityCallback(nsITimer *aTimer, void* anInstance);
|
||||
|
||||
|
@ -390,7 +390,7 @@ public:
|
|||
Layer* aLayer, nsIFrame* aContainerReferenceFrame,
|
||||
const ContainerLayerParameters& aParameters,
|
||||
bool aIsForCaret) const;
|
||||
virtual mozilla::Maybe<mozilla::DisplayItemClip> ComputeScrollClip(bool aIsForCaret) const;
|
||||
mozilla::Maybe<mozilla::DisplayItemClip> ComputeScrollClip(bool aIsForCaret) const;
|
||||
|
||||
// nsIScrollbarMediator
|
||||
void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection,
|
||||
|
@ -510,9 +510,9 @@ public:
|
|||
// If true, the resizer is collapsed and not displayed
|
||||
bool mCollapsedResizer:1;
|
||||
|
||||
// If true, the layer should always be active because we always build a
|
||||
// scrollable layer. Used for asynchronous scrolling.
|
||||
bool mShouldBuildScrollableLayer:1;
|
||||
// If true, the scroll frame should always be active because we always build
|
||||
// a scrollable layer. Used for asynchronous scrolling.
|
||||
bool mWillBuildScrollableLayer:1;
|
||||
|
||||
// Whether we are the root scroll frame that is used for containerful
|
||||
// scrolling with a display port. If true, the scrollable frame
|
||||
|
@ -877,6 +877,11 @@ public:
|
|||
virtual bool UsesContainerScrolling() const override {
|
||||
return mHelper.UsesContainerScrolling();
|
||||
}
|
||||
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRect* aDirtyRect,
|
||||
bool aAllowCreateDisplayPort) override {
|
||||
return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
|
||||
}
|
||||
|
||||
// nsIStatefulFrame
|
||||
NS_IMETHOD SaveState(nsPresState** aState) override {
|
||||
|
@ -1355,6 +1360,12 @@ public:
|
|||
void SetZoomableByAPZ(bool aZoomable) override {
|
||||
mHelper.SetZoomableByAPZ(aZoomable);
|
||||
}
|
||||
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRect* aDirtyRect,
|
||||
bool aAllowCreateDisplayPort) override {
|
||||
return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
||||
|
|
|
@ -455,6 +455,19 @@ public:
|
|||
virtual bool UsesContainerScrolling() const = 0;
|
||||
|
||||
virtual mozilla::Maybe<mozilla::DisplayItemClip> ComputeScrollClip(bool aIsForCaret) const = 0;
|
||||
|
||||
/**
|
||||
* Determine if we should build a scrollable layer for this scroll frame and
|
||||
* return the result. It will also record this result on the scroll frame.
|
||||
* Pass the dirty rect in aDirtyRect. On return it will be set to the
|
||||
* displayport if there is one (ie the dirty rect that should be used).
|
||||
* This function may create a display port where one did not exist before if
|
||||
* aAllowCreateDisplayPort is true. It is only allowed to be false if there
|
||||
* has been a call with it set to true before on the same paint.
|
||||
*/
|
||||
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRect* aDirtyRect,
|
||||
bool aAllowCreateDisplayPort) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -416,18 +416,13 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
|
||||
|
||||
if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
|
||||
if (gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
// for root content documents we want the base to be the composition bounds
|
||||
nsRect displayportBase = presContext->IsRootContentDocument() ?
|
||||
nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)) :
|
||||
dirty.Intersect(nsRect(nsPoint(0,0), subdocRootFrame->GetSize()));
|
||||
nsRect displayPort;
|
||||
if (aBuilder->IsPaintingToWindow() &&
|
||||
nsLayoutUtils::GetOrMaybeCreateDisplayPort(
|
||||
*aBuilder, rootScrollFrame, displayportBase, &displayPort)) {
|
||||
haveDisplayPort = true;
|
||||
dirty = displayPort;
|
||||
}
|
||||
nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
|
||||
MOZ_ASSERT(rootScrollableFrame);
|
||||
haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder,
|
||||
&dirty, /* aAllowCreateDisplayPort = */ true);
|
||||
|
||||
if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
haveDisplayPort = false;
|
||||
}
|
||||
|
||||
ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
|
||||
|
|
|
@ -18,6 +18,17 @@
|
|||
#include "nsIXULRuntime.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
// Includes for the crash report annotation in ErrorLoadingBuiltinSheet.
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "mozilla/Omnijar.h"
|
||||
#include "nsDirectoryService.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsIChromeRegistry.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsISubstitutingProtocolHandler.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static bool sNumberControlEnabled;
|
||||
|
@ -454,9 +465,249 @@ nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, nsRefPtr<CSSStyleSheet>&
|
|||
LoadSheet(uri, aSheet, false);
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
static void
|
||||
ListInterestingFiles(nsString& aAnnotation, nsIFile* aFile,
|
||||
const nsTArray<nsString>& aInterestingFilenames)
|
||||
{
|
||||
nsString filename;
|
||||
aFile->GetLeafName(filename);
|
||||
for (const nsString& interestingFilename : aInterestingFilenames) {
|
||||
if (interestingFilename == filename) {
|
||||
nsString path;
|
||||
aFile->GetPath(path);
|
||||
aAnnotation.AppendLiteral(" ");
|
||||
aAnnotation.Append(path);
|
||||
aAnnotation.AppendLiteral(" (");
|
||||
int64_t size;
|
||||
if (NS_SUCCEEDED(aFile->GetFileSize(&size))) {
|
||||
aAnnotation.AppendPrintf("%ld", size);
|
||||
} else {
|
||||
aAnnotation.AppendLiteral("???");
|
||||
}
|
||||
aAnnotation.AppendLiteral(" bytes)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool isDir = false;
|
||||
aFile->IsDirectory(&isDir);
|
||||
|
||||
if (!isDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
if (NS_FAILED(aFile->GetDirectoryEntries(getter_AddRefs(entries)))) {
|
||||
aAnnotation.AppendLiteral(" (failed to enumerated directory)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bool hasMore = false;
|
||||
if (NS_FAILED(entries->HasMoreElements(&hasMore))) {
|
||||
aAnnotation.AppendLiteral(" (failed during directory enumeration)\n");
|
||||
return;
|
||||
}
|
||||
if (!hasMore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> entry;
|
||||
if (NS_FAILED(entries->GetNext(getter_AddRefs(entry)))) {
|
||||
aAnnotation.AppendLiteral(" (failed during directory enumeration)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
|
||||
if (file) {
|
||||
ListInterestingFiles(aAnnotation, file, aInterestingFilenames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a crash report annotation to help debug issues with style
|
||||
// sheets failing to load (bug 1194856).
|
||||
static void
|
||||
AnnotateCrashReport(nsIURI* aURI)
|
||||
{
|
||||
nsAutoCString spec;
|
||||
nsAutoCString scheme;
|
||||
nsDependentCSubstring filename;
|
||||
if (aURI) {
|
||||
aURI->GetSpec(spec);
|
||||
aURI->GetScheme(scheme);
|
||||
int32_t i = spec.RFindChar('/');
|
||||
if (i != -1) {
|
||||
filename.Rebind(spec, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
nsString annotation;
|
||||
|
||||
// The URL of the sheet that failed to load.
|
||||
annotation.AppendLiteral("Error loading sheet: ");
|
||||
annotation.Append(NS_ConvertUTF8toUTF16(spec).get());
|
||||
annotation.Append('\n');
|
||||
|
||||
// The jar: or file: URL that the sheet's resource: or chrome: URL
|
||||
// resolves to.
|
||||
if (scheme.EqualsLiteral("resource")) {
|
||||
annotation.AppendLiteral("Real location: ");
|
||||
nsCOMPtr<nsISubstitutingProtocolHandler> handler;
|
||||
nsCOMPtr<nsIIOService> io(do_GetIOService());
|
||||
if (io) {
|
||||
nsCOMPtr<nsIProtocolHandler> ph;
|
||||
io->GetProtocolHandler(scheme.get(), getter_AddRefs(ph));
|
||||
if (ph) {
|
||||
handler = do_QueryInterface(ph);
|
||||
}
|
||||
}
|
||||
if (!handler) {
|
||||
annotation.AppendLiteral("(ResolveURI failed)\n");
|
||||
} else {
|
||||
nsAutoCString resolvedSpec;
|
||||
handler->ResolveURI(aURI, resolvedSpec);
|
||||
annotation.Append(NS_ConvertUTF8toUTF16(resolvedSpec));
|
||||
annotation.Append('\n');
|
||||
}
|
||||
} else if (scheme.EqualsLiteral("chrome")) {
|
||||
annotation.AppendLiteral("Real location: ");
|
||||
nsCOMPtr<nsIChromeRegistry> reg =
|
||||
mozilla::services::GetChromeRegistryService();
|
||||
if (!reg) {
|
||||
annotation.AppendLiteral("(no chrome registry)\n");
|
||||
} else {
|
||||
nsCOMPtr<nsIURI> resolvedURI;
|
||||
reg->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI));
|
||||
if (!resolvedURI) {
|
||||
annotation.AppendLiteral("(ConvertChromeURL failed)\n");
|
||||
} else {
|
||||
nsAutoCString resolvedSpec;
|
||||
resolvedURI->GetSpec(resolvedSpec);
|
||||
annotation.Append(NS_ConvertUTF8toUTF16(resolvedSpec));
|
||||
annotation.Append('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<nsString> interestingFiles;
|
||||
interestingFiles.AppendElement(NS_LITERAL_STRING("chrome.manifest"));
|
||||
interestingFiles.AppendElement(NS_LITERAL_STRING("omni.ja"));
|
||||
interestingFiles.AppendElement(NS_ConvertUTF8toUTF16(filename));
|
||||
|
||||
annotation.AppendLiteral("GRE directory: ");
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsDirectoryService::gService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile),
|
||||
getter_AddRefs(file));
|
||||
if (file) {
|
||||
// The Firefox installation directory.
|
||||
nsString path;
|
||||
file->GetPath(path);
|
||||
annotation.Append(path);
|
||||
annotation.Append('\n');
|
||||
|
||||
// List interesting files -- any chrome.manifest or omni.ja file or any file
|
||||
// whose name is the sheet's filename -- under the Firefox installation
|
||||
// directory.
|
||||
annotation.AppendLiteral("Interesting files in the GRE directory:\n");
|
||||
ListInterestingFiles(annotation, file, interestingFiles);
|
||||
|
||||
// If the Firefox installation directory has a chrome.manifest file, let's
|
||||
// see what's in it.
|
||||
file->Append(NS_LITERAL_STRING("chrome.manifest"));
|
||||
bool exists = false;
|
||||
file->Exists(&exists);
|
||||
if (exists) {
|
||||
annotation.AppendLiteral("Contents of chrome.manifest:\n[[[\n");
|
||||
PRFileDesc* fd;
|
||||
if (NS_SUCCEEDED(file->OpenNSPRFileDesc(PR_RDONLY, 0, &fd))) {
|
||||
nsCString contents;
|
||||
char buf[512];
|
||||
int32_t n;
|
||||
while ((n = PR_Read(fd, buf, sizeof(buf))) > 0) {
|
||||
contents.Append(buf, n);
|
||||
}
|
||||
if (n < 0) {
|
||||
annotation.AppendLiteral(" (error while reading)\n");
|
||||
} else {
|
||||
annotation.Append(NS_ConvertUTF8toUTF16(contents));
|
||||
}
|
||||
PR_Close(fd);
|
||||
}
|
||||
annotation.AppendLiteral("]]]\n");
|
||||
}
|
||||
} else {
|
||||
annotation.AppendLiteral("(none)\n");
|
||||
}
|
||||
|
||||
// The jar: or file: URL prefix that chrome: and resource: URLs get translated
|
||||
// to.
|
||||
annotation.AppendLiteral("GRE omnijar URI string: ");
|
||||
nsCString uri;
|
||||
nsresult rv = Omnijar::GetURIString(Omnijar::GRE, uri);
|
||||
if (NS_FAILED(rv)) {
|
||||
annotation.AppendLiteral("(failed)\n");
|
||||
} else {
|
||||
annotation.Append(NS_ConvertUTF8toUTF16(uri));
|
||||
annotation.Append('\n');
|
||||
}
|
||||
|
||||
nsRefPtr<nsZipArchive> zip = Omnijar::GetReader(Omnijar::GRE);
|
||||
if (zip) {
|
||||
// List interesting files in the GRE omnijar.
|
||||
annotation.AppendLiteral("Interesting files in the GRE omnijar:\n");
|
||||
nsZipFind* find;
|
||||
rv = zip->FindInit(nullptr, &find);
|
||||
if (NS_FAILED(rv)) {
|
||||
annotation.AppendPrintf(" (FindInit failed with 0x%08x)\n", rv);
|
||||
} else if (!find) {
|
||||
annotation.AppendLiteral(" (FindInit returned null)\n");
|
||||
} else {
|
||||
const char* result;
|
||||
uint16_t len;
|
||||
while (NS_SUCCEEDED(find->FindNext(&result, &len))) {
|
||||
nsCString itemPathname;
|
||||
nsString itemFilename;
|
||||
itemPathname.Append(result, len);
|
||||
int32_t i = itemPathname.RFindChar('/');
|
||||
if (i != -1) {
|
||||
itemFilename = NS_ConvertUTF8toUTF16(Substring(itemPathname, i + 1));
|
||||
}
|
||||
for (const nsString& interestingFile : interestingFiles) {
|
||||
if (interestingFile == itemFilename) {
|
||||
annotation.AppendLiteral(" ");
|
||||
annotation.Append(NS_ConvertUTF8toUTF16(itemPathname));
|
||||
nsZipItem* item = zip->GetItem(itemPathname.get());
|
||||
if (!item) {
|
||||
annotation.AppendLiteral(" (GetItem failed)\n");
|
||||
} else {
|
||||
annotation.AppendPrintf(" (%d bytes, crc32 = 0x%08x)\n",
|
||||
item->RealSize(),
|
||||
item->CRC32());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete find;
|
||||
}
|
||||
} else {
|
||||
annotation.AppendLiteral("No GRE omnijar\n");
|
||||
}
|
||||
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("SheetLoadFailure"),
|
||||
NS_ConvertUTF16toUTF8(annotation));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ErrorLoadingBuiltinSheet(nsIURI* aURI, const char* aMsg)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
AnnotateCrashReport(aURI);
|
||||
#endif
|
||||
|
||||
nsAutoCString spec;
|
||||
if (aURI) {
|
||||
aURI->GetSpec(spec);
|
||||
|
|
|
@ -2361,6 +2361,15 @@ public class GeckoAppShell
|
|||
SmsManager.getInstance().deleteMessage(aMessageId, aRequestId);
|
||||
}
|
||||
|
||||
@WrapForJNI
|
||||
public static void markMessageRead(int aMessageId, boolean aValue, boolean aSendReadReport, int aRequestId) {
|
||||
if (!SmsManager.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SmsManager.getInstance().markMessageRead(aMessageId, aValue, aSendReadReport, aRequestId);
|
||||
}
|
||||
|
||||
@WrapForJNI(stubName = "CreateMessageCursorWrapper")
|
||||
public static void createMessageCursor(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, String aDelivery, boolean aHasRead, boolean aRead, boolean aHasThreadId, long aThreadId, boolean aReverse, int aRequestId) {
|
||||
if (!SmsManager.isEnabled()) {
|
||||
|
|
|
@ -762,6 +762,48 @@ public class GeckoSmsManager
|
|||
aRequestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markMessageRead(int aMessageId, boolean aValue, boolean aSendReadReport, int aRequestId) {
|
||||
class MarkMessageReadRunnable implements Runnable {
|
||||
private final int mMessageId;
|
||||
private final boolean mValue;
|
||||
private final int mRequestId;
|
||||
|
||||
MarkMessageReadRunnable(int aMessageId, boolean aValue, int aRequestId) {
|
||||
mMessageId = aMessageId;
|
||||
mValue = aValue;
|
||||
mRequestId = aRequestId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ContentResolver cr = GeckoAppShell.getContext().getContentResolver();
|
||||
Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
|
||||
|
||||
ContentValues updatedProps = new ContentValues();
|
||||
updatedProps.put("read", mValue);
|
||||
|
||||
int count = cr.update(message, updatedProps, null, null);
|
||||
|
||||
notifySmsMarkedAsRead(count == 1, mRequestId);
|
||||
} catch (Exception e) {
|
||||
Log.e("GeckoSmsManager", "Error while trying to mark message as read: " + e);
|
||||
notifySmsMarkAsReadFailed(kUnknownError, mRequestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aSendReadReport == true) {
|
||||
Log.w("GeckoSmsManager", "Android SmsManager doesn't suport read receipts for SMS.");
|
||||
}
|
||||
|
||||
if (!SmsIOThread.getInstance().execute(new MarkMessageReadRunnable(aMessageId, aValue, aRequestId))) {
|
||||
Log.e("GeckoSmsManager", "Failed to add MarkMessageReadRunnable to the SmsIOThread");
|
||||
notifySmsMarkAsReadFailed(kUnknownError, aRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createMessageCursor(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, String aDelivery, boolean aHasRead, boolean aRead, boolean aHasThreadId, long aThreadId, boolean aReverse, int aRequestId) {
|
||||
class CreateMessageCursorRunnable implements Runnable {
|
||||
|
@ -1101,6 +1143,10 @@ public class GeckoSmsManager
|
|||
@WrapForJNI
|
||||
private static native void notifySmsDeleteFailed(int aError, int aRequestId);
|
||||
@WrapForJNI
|
||||
private static native void notifySmsMarkedAsRead(boolean aMarkedAsRead, int aRequestId);
|
||||
@WrapForJNI
|
||||
private static native void notifySmsMarkAsReadFailed(int aError, int aRequestId);
|
||||
@WrapForJNI
|
||||
private static native void notifyCursorError(int aError, int aRequestId);
|
||||
@WrapForJNI
|
||||
private static native void notifyThreadCursorResult(long aId, String aLastMessageSubject, String aBody, long aUnreadCount, Object[] aParticipants, long aTimestamp, String aLastMessageType, int aRequestId);
|
||||
|
|
|
@ -31,6 +31,7 @@ public class SmsManager {
|
|||
void send(String aNumber, String aMessage, int aRequestId);
|
||||
void getMessage(int aMessageId, int aRequestId);
|
||||
void deleteMessage(int aMessageId, int aRequestId);
|
||||
void markMessageRead(int aMessageId, boolean aValue, boolean aSendReadReport, int aRequestId);
|
||||
void createMessageCursor(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, String aDelivery, boolean aHasRead, boolean aRead, boolean aHasThreadId, long aThreadId, boolean aReverse, int aRequestId);
|
||||
void createThreadCursor(int aRequestId);
|
||||
void getNextThread(int aRequestId);
|
||||
|
|
|
@ -932,10 +932,6 @@ pref("nglayout.debug.invalidation", false);
|
|||
// Whether image visibility is enabled globally (ie we will try to unlock images
|
||||
// that are not visible).
|
||||
pref("layout.imagevisibility.enabled", true);
|
||||
// Whether image visibility is enabled in documents that are within a browser
|
||||
// element as defined by nsDocShell::FrameType and GetInheritedFrameType. This
|
||||
// pref only has an effect if layout.imagevisibility.enabled is false.
|
||||
pref("layout.imagevisibility.enabled_for_browser_elements_only", false);
|
||||
pref("layout.imagevisibility.numscrollportwidths", 0);
|
||||
pref("layout.imagevisibility.numscrollportheights", 1);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <vector>
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
#include "mozilla/RefCounted.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "Zip.h"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <zlib.h>
|
||||
#include "Utils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -615,7 +615,7 @@ Http2Stream::GenerateOpen()
|
|||
messageSize += Http2Session::kFrameHeaderBytes + 5; // frame header + priority overhead in HEADERS frame
|
||||
messageSize += (numFrames - 1) * Http2Session::kFrameHeaderBytes; // frame header overhead in CONTINUATION frames
|
||||
|
||||
EnsureBuffer(mTxInlineFrame, messageSize,
|
||||
EnsureBuffer(mTxInlineFrame, dataLength + messageSize,
|
||||
mTxInlineFrameUsed, mTxInlineFrameSize);
|
||||
|
||||
mTxInlineFrameUsed += messageSize;
|
||||
|
|
|
@ -2586,9 +2586,6 @@ def run_test_harness(options):
|
|||
if runner.getTestFlavor(options) == 'mochitest':
|
||||
options.runByDir = True
|
||||
|
||||
if mozinfo.info['asan'] and options.e10s:
|
||||
options.runByDir = False
|
||||
|
||||
if runner.getTestFlavor(options) == 'browser-chrome':
|
||||
options.runByDir = True
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ task:
|
|||
--test-suite crashtest
|
||||
--installer-url {{build_url}}
|
||||
--test-packages-url {{test_packages_url}}
|
||||
--xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip
|
||||
--xre-url https://queue.taskcluster.net/v1/task/YNNF94qRSyCXiSU_AQgFOQ/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip
|
||||
--this-chunk {{chunk}}
|
||||
--total-chunk {{total_chunks}}
|
||||
artifacts:
|
||||
|
|
|
@ -19,7 +19,7 @@ task:
|
|||
--test-suite reftest
|
||||
--installer-url {{build_url}}
|
||||
--test-packages-url {{test_packages_url}}
|
||||
--xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip
|
||||
--xre-url https://queue.taskcluster.net/v1/task/YNNF94qRSyCXiSU_AQgFOQ/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip
|
||||
--this-chunk {{chunk}}
|
||||
--total-chunk {{total_chunks}}
|
||||
artifacts:
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[Node-isEqualNode.xhtml]
|
||||
type: testharness
|
||||
[isEqualNode should return true when only the internal subsets of DocumentTypes differ.]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[document.title-03.html]
|
||||
type: testharness
|
||||
[ document.title and space normalization ]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[document.title-04.xhtml]
|
||||
type: testharness
|
||||
[ document.title and space normalization ]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[document.title-07.html]
|
||||
type: testharness
|
||||
[createHTMLDocument test 6: "foo\\f\\fbar baz","foo\\f\\fbar baz","foo bar baz"]
|
||||
expected: FAIL
|
||||
|
|
@ -10,11 +10,9 @@
|
|||
expected:
|
||||
if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): NOTRUN
|
||||
if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): NOTRUN
|
||||
FAIL
|
||||
|
||||
[focusing on a focusable element fires a blur event at the previous focussed element]
|
||||
expected:
|
||||
if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): NOTRUN
|
||||
if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): NOTRUN
|
||||
FAIL
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
[option-text-spaces.html]
|
||||
type: testharness
|
||||
[option.text should strip leading space characters ("\\f")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should strip trailing space characters ("\\f")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should strip leading and trailing space characters ("\\f")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace single internal space characters ("\\f")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters (" ", "\\f")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters ("\\t", "\\f")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters ("\\n", "\\f")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters ("\\f", " ")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters ("\\f", "\\t")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters ("\\f", "\\n")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters ("\\f", "\\f")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters ("\\f", "\\r")]
|
||||
expected: FAIL
|
||||
|
||||
[option.text should replace multiple internal space characters ("\\r", "\\f")]
|
||||
expected: FAIL
|
||||
|
|
@ -94,6 +94,29 @@ WebRequestEventManager.prototype = Object.create(SingletonEventManager.prototype
|
|||
extensions.registerPrivilegedAPI("webRequest", (extension, context) => {
|
||||
return {
|
||||
webRequest: {
|
||||
ResourceType: {
|
||||
MAIN_FRAME: "main_frame",
|
||||
SUB_FRAME: "sub_frame",
|
||||
STYLESHEET: "stylesheet",
|
||||
SCRIPT: "script",
|
||||
IMAGE: "image",
|
||||
OBJECT: "object",
|
||||
OBJECT_SUBREQUEST: "object_subrequest",
|
||||
XMLHTTPREQUEST: "xmlhttprequest",
|
||||
XBL: "xbl",
|
||||
XSLT: "xslt",
|
||||
PING: "ping",
|
||||
BEACON: "beacon",
|
||||
XML_DTD: "xml_dtd",
|
||||
FONT: "font",
|
||||
MEDIA: "media",
|
||||
WEBSOCKET: "websocket",
|
||||
CSP_REPORT: "csp_report",
|
||||
IMAGESET: "imageset",
|
||||
WEB_MANIFEST: "web_manifest",
|
||||
OTHER: "other",
|
||||
},
|
||||
|
||||
onBeforeRequest: new WebRequestEventManager(context, "onBeforeRequest").api(),
|
||||
onBeforeSendHeaders: new WebRequestEventManager(context, "onBeforeSendHeaders").api(),
|
||||
onSendHeaders: new WebRequestEventManager(context, "onSendHeaders").api(),
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче