From 1b8562b7f2cef4d606156c9a94d3ed11e01cdf61 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 23 Feb 2018 14:41:53 -0600 Subject: [PATCH 01/31] Bug 1410651 - Cleanup GeckoView javadoc generation r=jchen MozReview-Commit-ID: ItS8f9X1moT --- mobile/android/geckoview/build.gradle | 4 +++- .../java/org/mozilla/geckoview/GeckoSession.java | 13 +------------ .../org/mozilla/geckoview/TextInputController.java | 2 +- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/mobile/android/geckoview/build.gradle b/mobile/android/geckoview/build.gradle index b439176f0ccf..abc3903568a5 100644 --- a/mobile/android/geckoview/build.gradle +++ b/mobile/android/geckoview/build.gradle @@ -185,7 +185,8 @@ android.libraryVariants.all { variant -> classpath = files(variant.javaCompile.classpath.files) source = files(variant.javaCompile.source) - exclude '**/R.java', '**/BuildConfig.java', 'com/google/**', 'org/webrtc/**' + exclude '**/R.java', '**/BuildConfig.java' + include 'org/mozilla/geckoview/**' options.addPathOption('sourcepath', ':').setValue( variant.sourceSets.collect({ it.javaDirectories }).flatten() + variant.generateBuildConfig.sourceOutputDir) @@ -196,6 +197,7 @@ android.libraryVariants.all { variant -> file("${System.properties['java.home']}/lib/rt.jar")] + android.bootClasspath options.memberLevel = JavadocMemberLevel.PROTECTED options.source = 7 + options.links("https://d.android.com/reference/") options.docTitle = "GeckoView ${mozconfig.substs.MOZ_APP_VERSION} API" options.header = "GeckoView ${mozconfig.substs.MOZ_APP_VERSION} API" diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java index 58c3608e0bb5..65d14071fcd3 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java @@ -353,7 +353,7 @@ public class GeckoSession extends LayerSession private final Listener mListener = new Listener(); - protected static final class Window extends JNIObject implements IInterface { + /* package */ static final class Window extends JNIObject implements IInterface { private NativeQueue mNativeQueue; private Binder mBinder; @@ -1405,17 +1405,6 @@ public class GeckoSession extends LayerSession } } - enum LoadUriResult { - HANDLED(0), - LOAD_IN_FRAME(1); - - private int mValue; - - private LoadUriResult(int value) { - mValue = value; - } - } - /** * A request to open an URI. * @param session The GeckoSession that initiated the callback. diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java index 18c63f3729cd..7f95bb589c43 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java @@ -107,7 +107,7 @@ public final class TextInputController { mEditable.setDefaultEditableChild(mEditableChild); } - public void onWindowChanged(final GeckoSession.Window window) { + /* package */ void onWindowChanged(final GeckoSession.Window window) { if (mQueue.isReady()) { window.attachEditable(mEditable, mEditableChild); } else { From af0ca40f0c73a933527c6d06ce74c47de9e4ebd5 Mon Sep 17 00:00:00 2001 From: Kim Moir Date: Mon, 26 Feb 2018 14:42:39 -0500 Subject: [PATCH 02/31] Bug 1437695 - Add temporary stylo-only build job r=nfroyd --- browser/config/mozconfigs/linux64/stylo-only | 3 + .../mozconfigs/linux64/stylo-only-debug | 3 + taskcluster/ci/build/linux.yml | 62 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 browser/config/mozconfigs/linux64/stylo-only create mode 100644 browser/config/mozconfigs/linux64/stylo-only-debug diff --git a/browser/config/mozconfigs/linux64/stylo-only b/browser/config/mozconfigs/linux64/stylo-only new file mode 100644 index 000000000000..2e2394a21170 --- /dev/null +++ b/browser/config/mozconfigs/linux64/stylo-only @@ -0,0 +1,3 @@ +. "$topsrcdir/browser/config/mozconfigs/linux64/nightly" + +ac_add_options --enable-stylo=only diff --git a/browser/config/mozconfigs/linux64/stylo-only-debug b/browser/config/mozconfigs/linux64/stylo-only-debug new file mode 100644 index 000000000000..61e8fec3b41e --- /dev/null +++ b/browser/config/mozconfigs/linux64/stylo-only-debug @@ -0,0 +1,3 @@ +. "$topsrcdir/browser/config/mozconfigs/linux64/debug" + +ac_add_options --enable-stylo=only diff --git a/taskcluster/ci/build/linux.yml b/taskcluster/ci/build/linux.yml index e7f341ffb64d..cbb238ee7f41 100644 --- a/taskcluster/ci/build/linux.yml +++ b/taskcluster/ci/build/linux.yml @@ -803,3 +803,65 @@ linux64-add-on-devel/opt: - linux64-gcc - linux64-rust - linux64-sccache + +linux64-stylo-only/opt: + description: "Linux64 Stylo Only Opt" + index: + product: firefox + job-name: linux64-stylo-only-opt + treeherder: + platform: linux64-stylo-only/opt + symbol: B + tier: 2 + worker-type: aws-provisioner-v1/gecko-{level}-b-linux + worker: + max-run-time: 36000 + run: + using: mozharness + actions: [get-secrets build check-test update] + config: + - builds/releng_base_firefox.py + - builds/releng_base_linux_64_builds.py + script: "mozharness/scripts/fx_desktop_build.py" + extra-config: + mozconfig_variant: 'stylo-only' + secrets: true + tooltool-downloads: public + need-xvfb: true + run-on-projects: ['mozilla-central', 'try', 'mozilla-inbound', 'autoland'] + toolchains: + - linux64-clang + - linux64-gcc + - linux64-rust + - linux64-sccache + +linux64-stylo-only/debug: + description: "Linux64 Stylo Only Debug" + index: + product: firefox + job-name: linux64-stylo-only-debug + treeherder: + platform: linux64-stylo-only/debug + symbol: B + tier: 2 + worker-type: aws-provisioner-v1/gecko-{level}-b-linux + worker: + max-run-time: 36000 + run: + using: mozharness + actions: [get-secrets build check-test update] + config: + - builds/releng_base_firefox.py + - builds/releng_base_linux_64_builds.py + script: "mozharness/scripts/fx_desktop_build.py" + extra-config: + mozconfig_variant: 'stylo-only-debug' + secrets: true + tooltool-downloads: public + need-xvfb: true + run-on-projects: ['mozilla-central', 'try', 'mozilla-inbound', 'autoland'] + toolchains: + - linux64-clang + - linux64-gcc + - linux64-rust + - linux64-sccache From aa07c1fb47c8cf3cd0530073e5df67c5595b4d25 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 26 Feb 2018 13:40:01 -0600 Subject: [PATCH 03/31] Bug 1432345 - Baldr: add index masking for 32-bit wasm loads and stores (r=jandem) --HG-- extra : rebase_source : cd2c67df8ce1ecae1199d8142bad0a827d1eaefb --- js/src/jit/Lowering.cpp | 13 ++++++++++--- js/src/jit/MIR.h | 3 +++ js/src/jit/MacroAssembler.h | 6 ++++-- js/src/jit/WasmBCE.cpp | 23 ++++++++++++++++++++++- js/src/jit/arm/MacroAssembler-arm-inl.h | 4 ++++ js/src/jit/shared/LIR-shared.h | 2 +- js/src/jit/x86/MacroAssembler-x86-inl.h | 4 ++++ js/src/wasm/WasmCompile.cpp | 8 +++++++- js/src/wasm/WasmIonCompile.cpp | 8 ++++++-- 9 files changed, 61 insertions(+), 10 deletions(-) diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index bb78da3d47dd..6c482e6694f4 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4532,9 +4532,16 @@ LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) MDefinition* boundsCheckLimit = ins->boundsCheckLimit(); MOZ_ASSERT(boundsCheckLimit->type() == MIRType::Int32); - auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(index), - useRegisterAtStart(boundsCheckLimit)); - add(lir, ins); + + if (JitOptions.spectreIndexMasking) { + auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(index), + useRegister(boundsCheckLimit)); + defineReuseInput(lir, ins, 0); + } else { + auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(index), + useRegisterAtStart(boundsCheckLimit)); + add(lir, ins); + } #endif } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index f318568dce75..1b5f5b7aa9f3 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -14236,6 +14236,9 @@ class MWasmBoundsCheck { // Bounds check is effectful: it throws for OOB. setGuard(); + + if (JitOptions.spectreIndexMasking) + setResultType(MIRType::Int32); } public: diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 00b74fdcdf07..6d3aa79a5950 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1470,8 +1470,10 @@ class MacroAssembler : public MacroAssemblerSpecific void wasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset); - // Emit a bounds check against the wasm heap limit, jumping to 'label' if 'cond' holds. - // Required when WASM_HUGE_MEMORY is not defined. + // Emit a bounds check against the wasm heap limit, jumping to 'label' if + // 'cond' holds. Required when WASM_HUGE_MEMORY is not defined. If + // JitOptions.spectreMaskIndex is true, in speculative executions 'index' is + // saturated in-place to 'boundsCheckLimit'. template inline void wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label) DEFINED_ON(arm, arm64, mips32, mips64, x86); diff --git a/js/src/jit/WasmBCE.cpp b/js/src/jit/WasmBCE.cpp index 424c5441dc72..af5e5f44b684 100644 --- a/js/src/jit/WasmBCE.cpp +++ b/js/src/jit/WasmBCE.cpp @@ -15,6 +15,8 @@ using namespace mozilla; typedef js::HashMap, SystemAllocPolicy> LastSeenMap; +unsigned redundantCount = 0; + // The Wasm Bounds Check Elimination (BCE) pass looks for bounds checks // on SSA values that have already been checked. (in the same block or in a // dominating block). These bounds checks are redundant and thus eliminated. @@ -60,13 +62,25 @@ jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph) uint32_t(addr->toConstant()->toInt32()) < mir->minWasmHeapLength()) { bc->setRedundant(); + redundantCount++; + if (JitOptions.spectreIndexMasking) + bc->replaceAllUsesWith(addr); + else + MOZ_ASSERT(!bc->hasUses()); } else { LastSeenMap::AddPtr ptr = lastSeen.lookupForAdd(addr->id()); if (ptr) { - if (ptr->value()->block()->dominates(block)) + MDefinition* prevCheckOrPhi = ptr->value(); + if (prevCheckOrPhi->block()->dominates(block)) { bc->setRedundant(); + redundantCount++; + if (JitOptions.spectreIndexMasking) + bc->replaceAllUsesWith(prevCheckOrPhi); + else + MOZ_ASSERT(!bc->hasUses()); + } } else { if (!lastSeen.add(ptr, addr->id(), def)) return false; @@ -90,6 +104,13 @@ jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph) for (int i = 0, nOps = phi->numOperands(); i < nOps; i++) { MDefinition* src = phi->getOperand(i); + if (JitOptions.spectreIndexMasking) { + if (src->isWasmBoundsCheck()) + src = src->toWasmBoundsCheck()->index(); + } else { + MOZ_ASSERT(!src->isWasmBoundsCheck()); + } + LastSeenMap::Ptr checkPtr = lastSeen.lookup(src->id()); if (!checkPtr || !checkPtr->value()->block()->dominates(block)) { phiChecked = false; diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index b67636e71e28..fc325d79c03f 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -2301,6 +2301,8 @@ MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Register boundsC { as_cmp(index, O2Reg(boundsCheckLimit)); as_b(label, cond); + if (JitOptions.spectreIndexMasking) + ma_mov(boundsCheckLimit, index, LeaveCC, cond); } template @@ -2312,6 +2314,8 @@ MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Address boundsCh ma_ldr(DTRAddr(boundsCheckLimit.base, DtrOffImm(boundsCheckLimit.offset)), scratch); as_cmp(index, O2Reg(scratch)); as_b(label, cond); + if (JitOptions.spectreIndexMasking) + ma_mov(scratch, index, LeaveCC, cond); } //}}} check_macroassembler_style diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index bd33bd99bd63..92846a917466 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -8428,7 +8428,7 @@ class LWasmAddOffset : public LInstructionHelper<1, 1, 0> } }; -class LWasmBoundsCheck : public LInstructionHelper<0, 2, 0> +class LWasmBoundsCheck : public LInstructionHelper<1, 2, 0> { public: LIR_HEADER(WasmBoundsCheck); diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index 43e5df690faf..5206028a8c24 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -1109,6 +1109,8 @@ MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Register boundsC { cmp32(index, boundsCheckLimit); j(cond, label); + if (JitOptions.spectreIndexMasking) + cmovCCl(cond, Operand(boundsCheckLimit), index); } template @@ -1117,6 +1119,8 @@ MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Address boundsCh { cmp32(index, Operand(boundsCheckLimit)); j(cond, label); + if (JitOptions.spectreIndexMasking) + cmovCCl(cond, Operand(boundsCheckLimit), index); } //}}} check_macroassembler_style diff --git a/js/src/wasm/WasmCompile.cpp b/js/src/wasm/WasmCompile.cpp index 396af8b68a3c..6d957e7f2726 100644 --- a/js/src/wasm/WasmCompile.cpp +++ b/js/src/wasm/WasmCompile.cpp @@ -414,6 +414,8 @@ InitialCompileFlags(const CompileArgs& args, Decoder& d, CompileMode* mode, Tier *debug = debugEnabled ? DebugEnabled::True : DebugEnabled::False; } +extern unsigned redundantCount; + SharedModule wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error) { @@ -441,7 +443,11 @@ wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, Uni if (!DecodeModuleTail(d, &env)) return nullptr; - return mg.finishModule(bytecode); + auto module = mg.finishModule(bytecode); + + printf("# redundant: %u\n", redundantCount); + + return module; } bool diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp index baf00251f0cf..13f34c5e3135 100644 --- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -832,8 +832,12 @@ class FunctionCompiler } MWasmLoadTls* boundsCheckLimit = maybeLoadBoundsCheckLimit(); - if (boundsCheckLimit) - curBlock_->add(MWasmBoundsCheck::New(alloc(), *base, boundsCheckLimit, bytecodeOffset())); + if (boundsCheckLimit) { + auto* ins = MWasmBoundsCheck::New(alloc(), *base, boundsCheckLimit, bytecodeOffset()); + curBlock_->add(ins); + if (JitOptions.spectreIndexMasking) + *base = ins; + } } bool isSmallerAccessForI64(ValType result, const MemoryAccessDesc* access) { From e561f0447232718bf9bec5e541e3481d65f65606 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Mon, 26 Feb 2018 19:48:21 +0000 Subject: [PATCH 04/31] NO BUG - Fix links in Python test docs. r=me DONTBUILD MozReview-Commit-ID: FaVWV2YqSuI --- testing/marionette/doc/PythonTests.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/testing/marionette/doc/PythonTests.md b/testing/marionette/doc/PythonTests.md index 9c6b8dbc9407..f52ea5531b8e 100644 --- a/testing/marionette/doc/PythonTests.md +++ b/testing/marionette/doc/PythonTests.md @@ -7,7 +7,7 @@ automating user interface tests. The in-tree test framework supports tests written in Python, using Python’s [unittest] library. Test cases are written as a subclass -of [`MarionetteTestCase`], with child tests belonging to instance +of `MarionetteTestCase`, with child tests belonging to instance methods that have a name starting with `test_`. You can additionally define [`setUp`] and [`tearDown`] instance @@ -36,9 +36,8 @@ The test structure is illustrated here: # code to execute after all tests are run MarionetteTestCase.tearDown(self) -[remote protocol]: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Protocol +[remote protocol]: Protocol.html [unittest]: https://docs.python.org/2.7/library/unittest.html -[`MarionetteTestCase`]: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/MarionetteTestCase [`setUp`]: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.setUp [`setUpClass`]: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.setUpClass [`tearDown`]: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.tearDown @@ -62,10 +61,9 @@ The API ------- The full API documentation is found at -http://marionette-client.readthedocs.io/en/master/, but the key -objects are: +, but the key objects are: - * [`MarionetteTestCase`]: a subclass for `unittest.TestCase` + * `MarionetteTestCase`: a subclass for `unittest.TestCase` used as a base class for all tests to run. * [`Marionette`]: client that speaks to Firefox. From 0e2204efaaa943e630508240d8e179a604e3dcfa Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Mon, 26 Feb 2018 19:49:24 +0000 Subject: [PATCH 05/31] NO BUG - Improve flow of Marionette introduction. r=me DONTBUILD MozReview-Commit-ID: 6cAeNYwWOio --- testing/marionette/doc/index.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/testing/marionette/doc/index.rst b/testing/marionette/doc/index.rst index 10a3fbc70e10..fcbac9d98541 100644 --- a/testing/marionette/doc/index.rst +++ b/testing/marionette/doc/index.rst @@ -5,11 +5,6 @@ Marionette Marionette is the remote protocol that lets OOP programs communicate with, instrument, and control Gecko. - -Description -=========== - -Marionette is an automation driver for Mozilla’s Gecko engine. It can remotely control either the UI or the internal JavaScript of Gecko-based browsers, such as Firefox and Fennec. It can control both the chrome and the content document, giving a high level of From d8deae7c48c777116939124939fced95a95709b2 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Mon, 26 Feb 2018 19:54:26 +0000 Subject: [PATCH 06/31] NO BUG - Update list of used Selenium atoms. r=me DONTBUILD MozReview-Commit-ID: GCUDKKLVDWb --- testing/marionette/doc/SeleniumAtoms.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/testing/marionette/doc/SeleniumAtoms.md b/testing/marionette/doc/SeleniumAtoms.md index dc3b1c867b9d..ef3eb78db8eb 100644 --- a/testing/marionette/doc/SeleniumAtoms.md +++ b/testing/marionette/doc/SeleniumAtoms.md @@ -7,11 +7,8 @@ specification] they will be removed step by step. Currently the following atoms are in use: -* clearElement -* getText -* isDisplayed -* isEnabled -* isSelected +- `getElementText` +- `isDisplayed` To use one of those atoms Javascript modules will have to import [atom.js]. From 9334cc4497fa528a832e0007e9fa6dd2c654731c Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Mon, 26 Feb 2018 19:54:56 +0000 Subject: [PATCH 07/31] NO BUG - Fix links in Selenium atom docs. r=me DONTBUILD MozReview-Commit-ID: IhgVsxFQBZg --- testing/marionette/doc/SeleniumAtoms.md | 90 ++++++++++++++----------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/testing/marionette/doc/SeleniumAtoms.md b/testing/marionette/doc/SeleniumAtoms.md index ef3eb78db8eb..9e73d079ceaa 100644 --- a/testing/marionette/doc/SeleniumAtoms.md +++ b/testing/marionette/doc/SeleniumAtoms.md @@ -1,72 +1,84 @@ -# Selenium Atoms +Selenium atoms +============== -Marionette uses a small list of [Selenium atoms] to interact with web elements. -Initially those have been added to ensure a better reliablity due to a wider usage -inside the Selenium project. But by adding full support for the [WebDriver -specification] they will be removed step by step. +Marionette uses a small list of [Selenium atoms] to interact with +web elements. Initially those have been added to ensure a better +reliablity due to a wider usage inside the Selenium project. But +by adding full support for the [WebDriver specification] they will +be removed step by step. Currently the following atoms are in use: - `getElementText` - `isDisplayed` -To use one of those atoms Javascript modules will have to import [atom.js]. +To use one of those atoms Javascript modules will have to import +[atom.js]. [Selenium atoms]: https://github.com/SeleniumHQ/selenium/tree/master/javascript/webdriver/atoms [WebDriver specification]: https://w3c.github.io/webdriver/webdriver-spec.html -[atom.js]: ../atom.js +[atom.js]: https://searchfox.org/mozilla-central/source/testing/marionette/atom.js -## Update required Selenium Atoms +Update required Selenium atoms +------------------------------ + +In regular intervals the atoms, which are still in use, have to +be updated. Therefore they have to be exported from the Selenium +repository first, and then updated in [atom.js]. -In regular intervals the atoms, which are still in use, have to be updated. -Therefore they have to be exported from the Selenium repository first, and then -updated in [atom.js]. ### Export Selenium Atoms The canonical GitHub repository for Selenium is - https://github.com/SeleniumHQ/selenium.git + https://github.com/SeleniumHQ/selenium.git -so make sure to have a local copy of it. For the cloning process it is -recommended to specify the `--depth=1` argument, so only the last changeset is -getting downloaded (which itself will already be more than 100 MB). Once the -clone is ready the export of the atoms can be triggered by running the following -commands: +so make sure to have a local copy of it. For the cloning process +it is recommended to specify the `--depth=1` argument, so only the +last changeset is getting downloaded (which itself will already be +more than 100 MB). Once the clone is ready the export of the atoms +can be triggered by running the following commands: - % cd selenium - % ./go - % python buck-out/crazy-fun/%changeset%/buck.pex build --show-output %atom% + % cd selenium + % ./go + % python buck-out/crazy-fun/%changeset%/buck.pex build --show-output %atom% -Hereby `%changeset%` corresponds to the currently used version of buck, and -`%atom%` to the atom to export. The following targets for exporting are available: +Hereby `%changeset%` corresponds to the currently used version of +buck, and `%atom%` to the atom to export. The following targets +for exporting are available: -* //javascript/webdriver/atoms:clear-element-firefox -* //javascript/webdriver/atoms:get-text-firefox -* //javascript/webdriver/atoms:is-displayed-firefox -* //javascript/webdriver/atoms:is-enabled-firefox -* //javascript/webdriver/atoms:is-selected-firefox + - `//javascript/webdriver/atoms:clear-element-firefox` + - `//javascript/webdriver/atoms:get-text-firefox` + - `//javascript/webdriver/atoms:is-displayed-firefox` + - `//javascript/webdriver/atoms:is-enabled-firefox` + - `//javascript/webdriver/atoms:is-selected-firefox` For each of the exported atoms a file can now be found in the folder -`buck-out/gen/javascript/webdriver/atoms/`. They contain all the code including -dependencies for the atom wrapped into a single function. +`buck-out/gen/javascript/webdriver/atoms/`. They contain all the +code including dependencies for the atom wrapped into a single function. + ### Update atom.js To update the atoms for Marionette the `atoms.js` file has to be edited. For each atom to be updated the steps as layed out below have to be performed: -1. Open the Javascript file of the exported atom. See above for its location. -2. Remove the contained license header, which can be found somewhere in the - middle of the file. -3. Update the parameters of the wrapper function (at the very top) so that those - are equal with the used parameters in `atom.js`. -4. Copy the whole content of the file, and replace the existing code for the atom - in `atom.js`. +1. Open the Javascript file of the exported atom. See above for + its location. + +2. Remove the contained license header, which can be found somewhere + in the middle of the file. + +3. Update the parameters of the wrapper function (at the very top) + so that those are equal with the used parameters in `atom.js`. + +4. Copy the whole content of the file, and replace the existing + code for the atom in `atom.js`. + ### Test the changes -To ensure that the update of the atoms doesn't cause a regression a try build -should be run including Marionette unit tests, Firefox ui tests, and all the -web-platform-tests. +To ensure that the update of the atoms doesn't cause a regression +a try build should be run including Marionette unit tests, Firefox +ui tests, and all the web-platform-tests. From 7559e0d07a195be0c7fc9190d7ec42d2fa2e3808 Mon Sep 17 00:00:00 2001 From: Ben Hearsum Date: Mon, 26 Feb 2018 15:24:23 -0500 Subject: [PATCH 08/31] bug 1433461: block push-to-cdns on update verify. r=aki --- taskcluster/ci/beetmover-cdns/kind.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/taskcluster/ci/beetmover-cdns/kind.yml b/taskcluster/ci/beetmover-cdns/kind.yml index 218bb84f61a3..a3a5e0d07f05 100644 --- a/taskcluster/ci/beetmover-cdns/kind.yml +++ b/taskcluster/ci/beetmover-cdns/kind.yml @@ -12,6 +12,7 @@ transforms: kind-dependencies: - release-generate-checksums + - release-update-verify job-defaults: worker-type: From a7801a14042489e8e6c84d75441978169b8aaec9 Mon Sep 17 00:00:00 2001 From: Kim Moir Date: Mon, 26 Feb 2018 15:29:59 -0500 Subject: [PATCH 09/31] Bug 1412906 - Remove config/makefiles/test/ r=nalexander DONTBUILD --- config/makefiles/test/Makefile.in | 98 -------------------- config/makefiles/test/check-arglist.mk | 100 --------------------- config/makefiles/test/check-autotargets.mk | 84 ----------------- config/makefiles/test/check_XinY.mk | 70 --------------- config/makefiles/test/moz.build | 6 -- config/moz.build | 1 - 6 files changed, 359 deletions(-) delete mode 100644 config/makefiles/test/Makefile.in delete mode 100644 config/makefiles/test/check-arglist.mk delete mode 100644 config/makefiles/test/check-autotargets.mk delete mode 100644 config/makefiles/test/check_XinY.mk delete mode 100644 config/makefiles/test/moz.build diff --git a/config/makefiles/test/Makefile.in b/config/makefiles/test/Makefile.in deleted file mode 100644 index 6c66d820e900..000000000000 --- a/config/makefiles/test/Makefile.in +++ /dev/null @@ -1,98 +0,0 @@ -# -*- makefile -*- -# -# 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/. - -STANDALONE_MAKEFILE := 1 -USE_AUTOTARGETS_MK = 1 -MAKEUTILS_UNIT_TEST = 1 -include $(topsrcdir)/config/makefiles/makeutils.mk - -dir-ts = .deps/test -check-arglist = $(dir-ts)/arglist.ts -check-autotargets = $(dir-ts)/autotargets_mk.ts -check-XinY = $(dir-ts)/check_XinY_mk.ts -check-tests =\ - $(check-arglist) \ - $(check-autotargets) \ - $(check-XinY) \ - $(NULL) - - -##------------------_## -##---] TARGETS [---## -##------------------_## -all:: - -clean: - $(RM) $(check-tests) - -########################################################################### -## Logic processed at compile time so be selective about when to test -## $(MAKE) check VERBOSE=1 -ifneq ($(NULL),$(findstring check,$(MAKECMDGOALS))) # - -check-preqs =\ - $(call mkdir_deps,$(dir-ts)) \ - $(check-tests) \ - $(NULL) - -check:: $(check-preqs) - @true - - -ifdef VERBOSE #{ gmake check VERBOSE=1 - $(info ===========================================================================) - $(info Running test: $(MAKECMDGOALS): pwd=$(CURDIR)) - $(info ===========================================================================) -endif #} - -ifndef requiredfunction - $(error requiredfunction is not defined) -endif - - -################## -check-XinY-preqs=\ - $(call mkdir_deps,$(dir-ts)) \ - $(topsrcdir)/config/makefiles/makeutils.mk \ - $(srcdir)/check_XinY.mk \ - $(eval include $(srcdir)/check_XinY.mk) \ - $(NULL) - -$(check-XinY): $(check-XinY-preqs) - @$(TOUCH) $@ -# - - -########################################################################### -## check-arglist.mk always invoked as a compile time test -## maintain real file dependencies for use later on. -check-arglist-preqs=\ - $(call mkdir_deps,$(dir-ts)) \ - $(topsrcdir)/config/makefiles/makeutils.mk \ - $(srcdir)/check-arglist.mk \ - $(eval include $(srcdir)/check-arglist.mk) \ - $(NULL) - -$(check-arglist): $(check-arglist-preqs) - @$(TOUCH) $@ -# - - -########################################################################### -# -check-autotargets-preqs=\ - $(call mkdir_deps,$(dir-ts)) \ - $(topsrcdir)/config/makefiles/makeutils.mk \ - $(topsrcdir)/config/makefiles/autotargets.mk \ - $(srcdir)/check-autotargets.mk \ - $(eval include $(srcdir)/check-autotargets.mk) \ - $(NULL) - -$(check-autotargets): $(check-autotargets-preqs) - @$(TOUCH) $@ -# - -endif #} findstring MAKECMDGOAL diff --git a/config/makefiles/test/check-arglist.mk b/config/makefiles/test/check-arglist.mk deleted file mode 100644 index fb720ee42c0e..000000000000 --- a/config/makefiles/test/check-arglist.mk +++ /dev/null @@ -1,100 +0,0 @@ -# -*- makefile -*- -# -# 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/. - -ifdef VERBOSE - $(warning loading test) -endif - - -$(call requiredfunction,getargv) -$(call requiredfunction,subargv) -$(call requiredfunction,istype isval isvar) - -# arg_scalar = [scalar|literal] -arg_list = foo bar -arg_ref = arg_list - -## Identify type of function argument(s) -######################################## -ifneq (scalar,$(call istype,arg_scalar)) - $(error istype(arg_scalar)=scalar, found [$(call istype,arg_scalar)]) -endif -ifneq (list,$(call istype,arg_list)) - $(error istype(arg_list)=list, found [$(call istype,arg_list)]) -endif -ifneq (list,$(call istype,arg_ref)) - $(error istype(arg_ref)=list, found [$(call istype,arg_ref)]) -endif - -## Type == scalar or a list of values -##################################### -ifneq (true,$(call isval,scalar)) - $(error isval(scalar)=true, found [$(call isval,scalar)]) -endif -ifneq ($(NULL),$(call isval,arg_list)) - $(error isval(arg_list)=null, found [$(call isval,arg_list)]) -endif - -## type == reference: macro=>macro => $($(1)) -############################################# -ifneq ($(NULL),$(call isvar,scalar)) - $(error isvar(scalar)=$(NULL), found [$(call isvar,scalar)]) -endif -ifneq (true,$(call isvar,arg_list)) - $(error isvar(arg_list)=true, found [$(call isvar,arg_list)]) -endif -ifneq (true,$(call isvar,arg_ref)) - $(error isvar(arg_ref)=true, found [$(call isvar,arg_ref)]) -endif - -# Verify getargv expansion -########################## -ifneq (scalar,$(call getargv,scalar)) - $(error getargv(scalar)=scalar, found [$(call getargv,scalar)]) -endif -ifneq ($(arg_list),$(call getargv,arg_list)) - $(error getargv(arg_list)=list, found [$(call getargv,arg_list)]) -endif -ifneq (arg_list,$(call getargv,arg_ref)) - $(error getargv(arg_ref)=list, found [$(call getargv,arg_ref)]) -endif - -########################################################################### -## -########################################################################### -ifdef MANUAL_TEST #{ - # For automated testing a callback is needed that can set an external status - # variable that can be tested. Syntax is tricky to get correct functionality. - ifdef VERBOSE - $(info ) - $(info ===========================================================================) - $(info Running test: checkIfEmpty) - $(info ===========================================================================) - endif - - #status = - #setTRUE =status=true - #setFALSE =status=$(NULL) - #$(call checkIfEmpty,setFALSE NULL) - #$(if $(status),$(error checkIfEmpty(xyz) failed)) - #$(call checkIfEmpty,setTRUE xyz) - #$(if $(status),$(error checkIfEmpty(xyz) failed)) - xyz=abc - $(info STATUS: warnIfEmpty - two vars) - $(call warnIfEmpty,foo xyz bar) - $(info STATUS: errorIfEmpty - on first var) - $(call errorIfEmpty,foo xyz bar) - $(error TEST FAILED: processing should not reach this point) -endif #} - -# Verify subargv expansion -########################## -subargs=foo bar tans fans -subargs_exp=tans fans -subargs_found=$(call subargv,4,$(subargs)) -ifneq ($(subargs_exp),$(subargs_found)) - $(error subargv(4,$(subargs)): expected [$(subargs_exp)] found [$(subargs_found)]) -endif diff --git a/config/makefiles/test/check-autotargets.mk b/config/makefiles/test/check-autotargets.mk deleted file mode 100644 index c103f1d02dbe..000000000000 --- a/config/makefiles/test/check-autotargets.mk +++ /dev/null @@ -1,84 +0,0 @@ -# -*- makefile -*- -# -# 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/. - -ifdef VERBOSE - $(warning loading test) -endif - -space=$(null) $(null) -GENERATED_DIRS = bogus # test data - -undefine USE_AUTOTARGETS_MK -undefine INCLUDED_AUTOTARGETS_MK -include $(topsrcdir)/config/makefiles/autotargets.mk - -ifndef INCLUDED_AUTOTARGETS_MK - $(error autotargets.mk was not included -endif - -$(call requiredfunction,mkdir_deps) - - -# Verify test data populated makefile vars correctly -vars = AUTO_DEPS GARBAGE_DIRS GENERATED_DIRS_DEPS -$(foreach var,$(vars),$(call errorIfEmpty,$(var))) - -# Data should also be valid -ifneq (bogus,$(findstring bogus,$(AUTO_DEPS))) - $(error AUTO_DEPS=[$(AUTO_DEPS)] is not set correctly) -endif - - -# relpath -path := foo/bar.c -exp := foo/.mkdir.done -found := $(call mkdir_deps,$(dir $(path))) -ifneq ($(exp),$(found)) - $(error mkdir_deps($(path))=$(exp) not set correctly [$(found)]) -endif - -# abspath -path := /foo//bar/ -exp := /foo/bar/.mkdir.done -found := $(call mkdir_deps,$(path)) -ifneq ($(exp),$(found)) - $(error mkdir_deps($(path))=$(exp) not set correctly [$(found)]) -endif - - -## verify strip_slash -##################### - -path := a/b//c///d////e///// -exp := a/b/c/d/e/.mkdir.done -found := $(call mkdir_deps,$(path)) -ifneq ($(exp),$(found)) - $(error mkdir_deps($(path))=$(exp) not set correctly [$(found)]) -endif - - -## verify mkdir_stem() -###################### -path := verify/mkdir_stem -pathD = $(call mkdir_deps,$(path)) -pathS = $(call mkdir_stem,$(pathD)) -exp := $(path) - -ifeq ($(pathD),$(pathS)) - $(error mkdir_deps and mkdir_stem should not match [$(pathD)]) -endif -ifneq ($(pathS),$(exp)) - $(error mkdir_stem=[$(pathS)] != exp=[$(exp)]) -endif - - -## Verify embedded whitespace has been protected -path := a/b$(space)c//d -exp := a/b$(space)c/d -found := $(call slash_strip,$(path)) -ifneq ($(exp),$(found)) - $(error slash_strip($(path))=$(exp) not set correctly [$(found)]) -endif diff --git a/config/makefiles/test/check_XinY.mk b/config/makefiles/test/check_XinY.mk deleted file mode 100644 index 1e7a19f0e747..000000000000 --- a/config/makefiles/test/check_XinY.mk +++ /dev/null @@ -1,70 +0,0 @@ -# -*- makefile -*- -# -# 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/. - -# Verify dependencies are available -$(call requiredfunction,getargv subargv is_XinY errorifneq) - -ifdef VERBOSE - $(warning loading test) -endif - -zero := 0 -one := 1 - -# Verify 'invalid' is not matched -val := invalid -$(call errorifneq,$(zero),$(words $(call is_XinY,foo,$(val)))) -$(call errorifneq,$(zero),$(words $(call is_XinY,clean,$(val)))) -$(call errorifneq,$(zero),$(words $(call is_XinY,clean%,$(val)))) - -# verify strcmp('clean') -val := clean -$(call errorifneq,$(zero),$(words $(call is_XinY,foo,$(val)))) -$(call errorifneq,$(one),$(words $(call is_XinY,clean,$(val)))) -$(call errorifneq,$(one),$(words $(call is_XinY,clean%,$(val)))) -$(call errorifneq,$(one),$(words $(call is_XinY,%clean,$(val)))) - -# List match for 'clean' -val := blah clean distclean FcleanG clean-level-1 -wanted := clean distclean clean-level-1 -$(call errorifneq,$(zero),$(words $(call is_XinY_debug,foo,$(val)))) -$(call errorifneq,$(one),$(words $(call is_XinY,clean,$(val)))) -$(call errorifneq,$(one),$(words $(call is_XinY,distclean,$(val)))) - -# pattern match 'clean' -# match: clean, distclean, clean-level-1 -# exclude: FcleanG -TEST_MAKECMDGOALS := $(val) -$(call errorifneq,3,$(words $(call isTargetStemClean))) - -TEST_MAKECMDGOALS := invalid -$(call errorifneq,$(zero),$(words $(call isTargetStemClean))) - - -############################# -ifdef VERBOSE - $(call banner,Unit test: isTargetStem) -endif - -# Verify list argument processing -TEST_MAKECMDGOALS := echo -$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show))) - -TEST_MAKECMDGOALS := echo-123 -$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show))) - -TEST_MAKECMDGOALS := show -$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show))) - -TEST_MAKECMDGOALS := show-123 -$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show))) - -TEST_MAKECMDGOALS := show-123-echo -$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show))) - -TEST_MAKECMDGOALS := invalid -$(call errorifneq,$(zero),$(words $(call isTargetStem,echo,show))) - diff --git a/config/makefiles/test/moz.build b/config/makefiles/test/moz.build deleted file mode 100644 index 28919c271d33..000000000000 --- a/config/makefiles/test/moz.build +++ /dev/null @@ -1,6 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - diff --git a/config/moz.build b/config/moz.build index 7bac5e6fe993..0108b977bff8 100644 --- a/config/moz.build +++ b/config/moz.build @@ -16,7 +16,6 @@ DIST_INSTALL = False NoVisibilityFlags() CONFIGURE_SUBST_FILES += [ - 'makefiles/test/Makefile', 'tests/src-simple/Makefile', ] From 45b95f5cb59c9021ef6004cf0e7f773ca0f98bec Mon Sep 17 00:00:00 2001 From: Kim Moir Date: Mon, 26 Feb 2018 15:33:24 -0500 Subject: [PATCH 10/31] Bug 1412900 - Remove build/Makefile.in r=nalexander --- build/Makefile.in | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 build/Makefile.in diff --git a/build/Makefile.in b/build/Makefile.in deleted file mode 100644 index 2f284c253e24..000000000000 --- a/build/Makefile.in +++ /dev/null @@ -1,20 +0,0 @@ -# -# 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/. - -ifdef MOZTTDIR -# Install the Firefox OS fonts. -include $(MOZTTDIR)/fonts.mk -MOZTT_DEST = $(FINAL_TARGET)/fonts -MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/%,$(subst :, ,$(PRODUCT_COPY_FILES)))) -INSTALL_TARGETS += MOZTT -endif - -include $(topsrcdir)/config/rules.mk - -TARGET_DEPTH = .. -include $(srcdir)/automation-build.mk - -libs:: automation.py - From f1756229b658b38de0a53b79dd2cb91dbde34202 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Mon, 26 Feb 2018 13:58:08 -0700 Subject: [PATCH 11/31] Bug 1412349 - Avoid SETA optimization of SCHEDULES.inclusive suites, like test-verify; r=dustin --- taskcluster/taskgraph/transforms/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taskcluster/taskgraph/transforms/tests.py b/taskcluster/taskgraph/transforms/tests.py index a66c38592377..c131fd405672 100644 --- a/taskcluster/taskgraph/transforms/tests.py +++ b/taskcluster/taskgraph/transforms/tests.py @@ -1018,8 +1018,8 @@ def make_job_description(config, tests): if test.get('when'): jobdesc['when'] = test['when'] - elif config.params['project'] != 'try': - # for non-try branches, include SETA + elif config.params['project'] != 'try' and suite not in INCLUSIVE_COMPONENTS: + # for non-try branches and non-inclusive suites, include SETA jobdesc['optimization'] = {'skip-unless-schedules-or-seta': schedules} else: # otherwise just use skip-unless-schedules From 0544a4cf708836c30c5b6f7f7d9dd8f2388d08b3 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 26 Feb 2018 17:31:58 -0400 Subject: [PATCH 12/31] Bug 1434671 - add a benchmarking macro permitting custom test fixtures; r=ted.mielczarek GTest supports the TEST macro, which just runs a bunch of tests, and the TEST_F macro, which enables writing custom test fixtures to perform per-test setup and teardown. The benchmarking framework we have has a corresponding macro for the former, but no corresponding macro for the latter. If there's significant work to be done during setup and teardown, we certainly don't want to be doing that work during the actual benchmarking! So let's introduce a MOZ_GTEST_BENCH_F macro that works similarly to the TEST_F macro. --- testing/gtest/mozilla/MozGTestBench.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testing/gtest/mozilla/MozGTestBench.h b/testing/gtest/mozilla/MozGTestBench.h index 082a61ad06ac..d7d98c489ab2 100644 --- a/testing/gtest/mozilla/MozGTestBench.h +++ b/testing/gtest/mozilla/MozGTestBench.h @@ -19,4 +19,9 @@ TEST(suite, test) { \ mozilla::GTestBench(#suite, #test, lambdaOrFunc); \ } +#define MOZ_GTEST_BENCH_F(suite, test, lambdaOrFunc) \ +TEST_F(suite, test) { \ + mozilla::GTestBench(#suite, #test, lambdaOrFunc); \ +} + #endif // GTEST_MOZGTESTBENCH_H From 86d581422be1b885860418792c579fe3e572319f Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 26 Feb 2018 22:32:15 +0100 Subject: [PATCH 13/31] Bug 1440941 - FetchDriver should check if the operation has been already aborted when OnStartRequest is called, r=bkelly --- dom/fetch/FetchDriver.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index f00ab1029074..fc5619dd0e43 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -797,6 +797,11 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest, // In that case we will get a simulated OnStartRequest() and then the real // channel will call in with an errored OnStartRequest(). + if (!mChannel) { + MOZ_ASSERT(!mObserver); + return NS_BINDING_ABORTED; + } + nsresult rv; aRequest->GetStatus(&rv); if (NS_FAILED(rv)) { From 5588ef80d11bc4b5b6afc7b95c65e6d2dec8a4a2 Mon Sep 17 00:00:00 2001 From: Masatoshi Kimura Date: Fri, 23 Feb 2018 21:45:41 +0900 Subject: [PATCH 14/31] Bug 1440630 - Reduce nsIFile::ResolveAndStat() calls. r=froydnj --HG-- extra : source : 3dc9a957980918d125d7d3872c4f86bea31da437 extra : amend_source : 1dc4c1b50fe94370abab6d2ece930803fc02bcb5 --- xpcom/io/nsLocalFileWin.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index a2e8e366b55c..3b62e4835ea3 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -1188,7 +1188,7 @@ nsLocalFile::OpenNSPRFileDesc(int32_t aFlags, int32_t aMode, NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char* aMode, FILE** aResult) { - nsresult rv = ResolveAndStat(); + nsresult rv = Resolve(); if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) { return rv; } @@ -1210,7 +1210,7 @@ nsLocalFile::Create(uint32_t aType, uint32_t aAttributes) return NS_ERROR_FILE_UNKNOWN_TYPE; } - nsresult rv = ResolveAndStat(); + nsresult rv = Resolve(); if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) { return rv; } @@ -1625,7 +1625,7 @@ typedef struct NS_IMETHODIMP nsLocalFile::GetVersionInfoField(const char* aField, nsAString& aResult) { - nsresult rv = ResolveAndStat(); + nsresult rv = Resolve(); if (NS_FAILED(rv)) { return rv; } @@ -2312,7 +2312,7 @@ nsLocalFile::SetLastModifiedTime(PRTime aLastModifiedTime) // Check we are correctly initialized. CHECK_mWorkingPath(); - nsresult rv = ResolveAndStat(); + nsresult rv = Resolve(); if (NS_FAILED(rv)) { return rv; } @@ -2458,7 +2458,7 @@ nsLocalFile::SetPermissions(uint32_t aPermissions) // If true, then this will be for the target of the shortcut file, // otherwise it will be for the shortcut file itself (i.e. the same // results as SetPermissionsOfLink) - nsresult rv = ResolveAndStat(); + nsresult rv = Resolve(); if (NS_FAILED(rv)) { return rv; } @@ -2547,7 +2547,7 @@ nsLocalFile::SetFileSize(int64_t aFileSize) // Check we are correctly initialized. CHECK_mWorkingPath(); - nsresult rv = ResolveAndStat(); + nsresult rv = Resolve(); if (NS_FAILED(rv)) { return rv; } @@ -3051,7 +3051,7 @@ nsLocalFile::GetTarget(nsAString& aResult) return NS_ERROR_FILE_INVALID_PATH; } #endif - ResolveAndStat(); + Resolve(); aResult = mResolvedPath; return NS_OK; From 895b88fb04d2a913a2f4beb84625ec8361e16f0d Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 26 Feb 2018 17:20:24 -0500 Subject: [PATCH 15/31] Bug 1441241. Reget a KeyboardEvent constructor on each findbar keypress, because the findbar lives across navigations. r=felipe --- toolkit/modules/RemoteFinder.jsm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/toolkit/modules/RemoteFinder.jsm b/toolkit/modules/RemoteFinder.jsm index b6c5902f96cf..8c107bf1d640 100644 --- a/toolkit/modules/RemoteFinder.jsm +++ b/toolkit/modules/RemoteFinder.jsm @@ -209,10 +209,6 @@ function RemoteFinderListener(global) { this._finder = new Finder(global.docShell); this._finder.addResultListener(this); this._global = global; - this.KeyboardEvent = - global.docShell - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow).KeyboardEvent; for (let msg of this.MESSAGES) { global.addMessageListener(msg, this); @@ -318,7 +314,8 @@ RemoteFinderListener.prototype = { break; case "Finder:KeyPress": - this._finder.keyPress(new this.KeyboardEvent("keypress", data)); + var KeyboardEvent = this._finder._getWindow().KeyboardEvent; + this._finder.keyPress(new KeyboardEvent("keypress", data)); break; case "Finder:MatchesCount": From 933fb5668eea9c89bf13ee18cc8e35af78a3afc4 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 26 Feb 2018 17:27:23 -0500 Subject: [PATCH 16/31] Bug 1438961. Make DOM binding bits build in a debug --disable-tests build. r=qdot --- dom/bindings/moz.build | 2 +- dom/webidl/moz.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build index b814676bbf06..dfe45219913b 100644 --- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -121,7 +121,7 @@ SOURCES += [ # rule stated in the test/ directory, but it's the only way this will work. # Test classes are only built in debug mode, and all tests requiring use of # them are only run in debug mode. -if CONFIG['MOZ_DEBUG']: +if CONFIG['MOZ_DEBUG'] and CONFIG['ENABLE_TESTS']: EXPORTS.mozilla.dom += [ "test/TestFunctions.h", "test/TestInterfaceIterableDouble.h", diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index d5e58ff02567..a4168e825a54 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -1034,7 +1034,7 @@ WEBIDL_FILES += [ # We only expose our prefable test interfaces in debug builds, just to be on # the safe side. -if CONFIG['MOZ_DEBUG']: +if CONFIG['MOZ_DEBUG'] and CONFIG['ENABLE_TESTS']: WEBIDL_FILES += ['TestFunctions.webidl', 'TestInterfaceJS.webidl', 'TestInterfaceJSDictionaries.webidl', From 0b1e4d13e5f86296e9910d997ff416cacf181e97 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 Feb 2018 09:38:18 +1100 Subject: [PATCH 17/31] Back out 633b2c102c95 (bug 1438732) because it increases memory usage. r=erahm The increase was 64 KiB per process on 64-bit, and 32 KiB per process on 32-bit. Not worth it for the small improve in code niceness. --- modules/libpref/Preferences.cpp | 148 +++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 48 deletions(-) diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp index 491aeec95733..487313481571 100644 --- a/modules/libpref/Preferences.cpp +++ b/modules/libpref/Preferences.cpp @@ -326,8 +326,9 @@ static ArenaAllocator<8192, 1> gPrefNameArena; class Pref { public: - explicit Pref() - : mType(static_cast(PrefType::None)) + explicit Pref(const char* aName) + : mName(ArenaStrdup(aName, gPrefNameArena)) + , mType(static_cast(PrefType::None)) , mIsSticky(false) , mIsLocked(false) , mHasDefaultValue(false) @@ -340,10 +341,15 @@ public: ~Pref() { + // There's no need to free mName because it's allocated in memory owned by + // gPrefNameArena. + mDefaultValue.Clear(Type()); mUserValue.Clear(Type()); } + const char* Name() { return mName; } + // Types. PrefType Type() const { return static_cast(mType); } @@ -395,6 +401,15 @@ public: // Other operations. + bool MatchEntry(const char* aPrefName) + { + if (!mName || !aPrefName) { + return false; + } + + return strcmp(mName, aPrefName) == 0; + } + nsresult GetBoolValue(PrefValueKind aKind, bool* aResult) { if (!IsTypeBool()) { @@ -454,16 +469,11 @@ public: return NS_OK; } - // Fills out a dom pref with the values from this pref. - // @param aDomPref The pref to update. - // @param aName Optional. Override the dom pref's name with aName. - void ToDomPref(dom::Pref* aDomPref, const char* aName = nullptr) + void ToDomPref(dom::Pref* aDomPref) { MOZ_ASSERT(XRE_IsParentProcess()); - if (aName) { - aDomPref->name() = aName; - } + aDomPref->name() = mName; aDomPref->isLocked() = mIsLocked; @@ -492,6 +502,7 @@ public: void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged) { MOZ_ASSERT(!XRE_IsParentProcess()); + MOZ_ASSERT(strcmp(mName, aDomPref.name().get()) == 0); mIsLocked = aDomPref.isLocked(); @@ -677,6 +688,7 @@ public: void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) { + // Note: mName is allocated in gPrefNameArena, measured elsewhere. aSizes.mPrefValues += aMallocSizeOf(this); if (IsTypeString()) { if (mHasDefaultValue) { @@ -689,6 +701,8 @@ public: } private: + const char* mName; // allocated in gPrefNameArena + uint32_t mType : 2; uint32_t mIsSticky : 1; uint32_t mIsLocked : 1; @@ -700,6 +714,36 @@ private: PrefValue mUserValue; }; +class PrefEntry : public PLDHashEntryHdr +{ +public: + Pref* mPref; // Note: this is never null in a live entry. + + static bool MatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey) + { + auto entry = static_cast(aEntry); + auto prefName = static_cast(aKey); + + return entry->mPref->MatchEntry(prefName); + } + + static void InitEntry(PLDHashEntryHdr* aEntry, const void* aKey) + { + auto entry = static_cast(aEntry); + auto prefName = static_cast(aKey); + + entry->mPref = new Pref(prefName); + } + + static void ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry) + { + auto entry = static_cast(aEntry); + + delete entry->mPref; + entry->mPref = nullptr; + } +}; + struct CallbackNode { CallbackNode(const char* aDomain, @@ -725,21 +769,7 @@ struct CallbackNode CallbackNode* mNext; }; -// Hash key that allocates its string from the `gPrefNameArena`. The base class -// `nsDepCharHashKey` does not own the string data and no copies are made. -class StringArenaHashKey : public nsDepCharHashKey -{ -public: - explicit StringArenaHashKey(const char* aKey) - : nsDepCharHashKey(ArenaStrdup(aKey, gPrefNameArena)) - { - } -}; - -// Hashtable used to map names to pref objects. StringArenaHashKey is used to -// allocate the strings out of an arena. -using PrefsTable = nsClassHashtable; -static PrefsTable* gHashTable; +static PLDHashTable* gHashTable; // The callback list contains all the priority callbacks followed by the // non-priority callbacks. gLastPriorityNode records where the first part ends. @@ -752,6 +782,14 @@ static bool gIsAnyPrefLocked = false; static bool gCallbacksInProgress = false; static bool gShouldCleanupDeadNodes = false; +static PLDHashTableOps pref_HashTableOps = { + PLDHashTable::HashStringKey, + PrefEntry::MatchEntry, + PLDHashTable::MoveEntryStub, + PrefEntry::ClearEntry, + PrefEntry::InitEntry, +}; + static Pref* pref_HashTableLookup(const char* aPrefName); @@ -765,10 +803,10 @@ pref_savePrefs() { MOZ_ASSERT(NS_IsMainThread()); - PrefSaveData savedPrefs(gHashTable->Count()); + PrefSaveData savedPrefs(gHashTable->EntryCount()); for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { - Pref* pref = iter.Data(); + Pref* pref = static_cast(iter.Get())->mPref; nsAutoCString prefValueStr; if (!pref->UserValueToStringForSaving(prefValueStr)) { @@ -776,7 +814,7 @@ pref_savePrefs() } nsAutoCString prefNameStr; - StrEscape(iter.Key(), prefNameStr); + StrEscape(pref->Name(), prefNameStr); nsPrintfCString str( "user_pref(%s, %s);", prefNameStr.get(), prefValueStr.get()); @@ -827,7 +865,7 @@ IsEarlyPref(const char* aPrefName) #endif // DEBUG -static PrefsTable::LookupResult +static PrefEntry* pref_HashTableLookupInner(const char* aPrefName) { MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal()); @@ -850,14 +888,14 @@ pref_HashTableLookupInner(const char* aPrefName) } #endif - return gHashTable->Lookup(aPrefName); + return static_cast(gHashTable->Search(aPrefName)); } static Pref* pref_HashTableLookup(const char* aPrefName) { - PrefsTable::LookupResult entry = pref_HashTableLookupInner(aPrefName); - return entry ? static_cast(entry.Data()) : nullptr; + PrefEntry* entry = pref_HashTableLookupInner(aPrefName); + return entry ? entry->mPref : nullptr; } static nsresult @@ -874,7 +912,12 @@ pref_SetPref(const char* aPrefName, return NS_ERROR_OUT_OF_MEMORY; } - Pref* pref = gHashTable->LookupOrAdd(aPrefName); + auto entry = static_cast(gHashTable->Add(aPrefName, fallible)); + if (!entry) { + return NS_ERROR_OUT_OF_MEMORY; + } + + Pref* pref = entry->mPref; if (pref->IsTypeNone()) { // New entry. Set the type. pref->SetType(aType); @@ -1987,11 +2030,13 @@ nsPrefBranch::DeleteBranch(const char* aStartingAt) Substring(branchName, 0, branchName.Length() - 1); for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { + Pref* pref = static_cast(iter.Get())->mPref; + // The first disjunct matches branches: e.g. a branch name "foo.bar." // matches a name "foo.bar.baz" (but it won't match "foo.barrel.baz"). // The second disjunct matches leaf nodes: e.g. a branch name "foo.bar." // matches a name "foo.bar" (by ignoring the trailing '.'). - nsDependentCString name(iter.Key()); + nsDependentCString name(pref->Name()); if (StringBeginsWith(name, branchName) || name.Equals(branchNameNoDot)) { iter.Remove(); } @@ -2026,8 +2071,9 @@ nsPrefBranch::GetChildList(const char* aStartingAt, const PrefName& parent = GetPrefName(aStartingAt); size_t parentLen = parent.Length(); for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { - if (strncmp(iter.Key(), parent.get(), parentLen) == 0) { - prefArray.AppendElement(iter.Key()); + Pref* pref = static_cast(iter.Get())->mPref; + if (strncmp(pref->Name(), parent.get(), parentLen) == 0) { + prefArray.AppendElement(pref->Name()); } } @@ -2639,7 +2685,7 @@ PreferenceServiceReporter::CollectReports( if (gHashTable) { sizes.mHashTable += gHashTable->ShallowSizeOfIncludingThis(mallocSizeOf); for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { - Pref* pref = iter.Data(); + Pref* pref = static_cast(iter.Get())->mPref; pref->AddSizeOfIncludingThis(mallocSizeOf, sizes); } } @@ -2832,7 +2878,8 @@ Preferences::GetInstanceForService() sPreferences = new Preferences(); MOZ_ASSERT(!gHashTable); - gHashTable = new PrefsTable(PREF_HASHTABLE_INITIAL_LENGTH); + gHashTable = new PLDHashTable( + &pref_HashTableOps, sizeof(PrefEntry), PREF_HASHTABLE_INITIAL_LENGTH); gTelemetryLoadData = new nsDataHashtable(); @@ -3087,7 +3134,7 @@ Preferences::ResetPrefs() { ENSURE_PARENT_PROCESS("Preferences::ResetPrefs", "all prefs"); - gHashTable->Clear(); + gHashTable->ClearAndPrepareForLength(PREF_HASHTABLE_INITIAL_LENGTH); gPrefNameArena.Clear(); return InitInitialObjects().isOk() ? NS_OK : NS_ERROR_FAILURE; @@ -3102,10 +3149,10 @@ Preferences::ResetUserPrefs() Vector prefNames; for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { - Pref* pref = iter.Data(); + Pref* pref = static_cast(iter.Get())->mPref; if (pref->HasUserValue()) { - if (!prefNames.append(iter.Key())) { + if (!prefNames.append(pref->Name())) { return NS_ERROR_OUT_OF_MEMORY; } @@ -3179,7 +3226,12 @@ Preferences::SetPreference(const dom::Pref& aDomPref) const char* prefName = aDomPref.name().get(); - Pref* pref = gHashTable->LookupOrAdd(prefName); + auto entry = static_cast(gHashTable->Add(prefName, fallible)); + if (!entry) { + return; + } + + Pref* pref = entry->mPref; bool valueChanged = false; pref->FromDomPref(aDomPref, &valueChanged); @@ -3195,7 +3247,7 @@ Preferences::SetPreference(const dom::Pref& aDomPref) // needlessly, but that's ok because this case is rare. // if (!pref->HasDefaultValue() && !pref->HasUserValue()) { - gHashTable->Remove(prefName); + gHashTable->RemoveEntry(entry); } // Note: we don't have to worry about HandleDirty() because we are setting @@ -3223,9 +3275,9 @@ Preferences::GetPreferences(InfallibleTArray* aDomPrefs) MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); - aDomPrefs->SetCapacity(gHashTable->Count()); + aDomPrefs->SetCapacity(gHashTable->EntryCount()); for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { - Pref* pref = iter.Data(); + Pref* pref = static_cast(iter.Get())->mPref; if (!pref->MustSendToContentProcesses()) { // The pref value hasn't changed since it was initialized at startup. @@ -3236,7 +3288,7 @@ Preferences::GetPreferences(InfallibleTArray* aDomPrefs) if (pref->HasAdvisablySizedValues()) { dom::Pref* setting = aDomPrefs->AppendElement(); - pref->ToDomPref(setting, iter.Key()); + pref->ToDomPref(setting); } } } @@ -4132,13 +4184,13 @@ Preferences::ClearUserInAnyProcess(const char* aPrefName) { NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); - PrefsTable::LookupResult entry = pref_HashTableLookupInner(aPrefName); + PrefEntry* entry = pref_HashTableLookupInner(aPrefName); Pref* pref; - if (entry && (pref = entry.Data()) && pref->HasUserValue()) { + if (entry && (pref = entry->mPref) && pref->HasUserValue()) { pref->ClearUserValue(); if (!pref->HasDefaultValue()) { - entry.Remove(); + gHashTable->RemoveEntry(entry); } NotifyCallbacks(aPrefName); From 0342fd54185e2287cf61dcbcb22cc1b994d79691 Mon Sep 17 00:00:00 2001 From: Arthur Edelstein Date: Tue, 13 Feb 2018 12:11:00 +0200 Subject: [PATCH 18/31] Bug 1434772 - Ensure caches.open() throws SecurityError in PBM workers r=ehsan --- .../test/mochitest/browser_cache_pb_window.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dom/cache/test/mochitest/browser_cache_pb_window.js b/dom/cache/test/mochitest/browser_cache_pb_window.js index 81619e5e57f2..09ac5c45df23 100644 --- a/dom/cache/test/mochitest/browser_cache_pb_window.js +++ b/dom/cache/test/mochitest/browser_cache_pb_window.js @@ -70,6 +70,30 @@ function testKeys(browser) { }); } +function testOpen_worker(browser) { + return ContentTask.spawn(browser, {}, function() { + let workerFunctionString = function () { + caches.open("pb-worker-cache").then(function(cacheObject) { + postMessage(cacheObject.toString()); + }, function (reason) { + postMessage(reason.name); + }); + }.toString(); + let workerBlobURL = content.URL.createObjectURL( + new Blob(['(', workerFunctionString, ')()'], + { type : 'application/javascript' })); + let worker = new content.Worker(workerBlobURL); + content.URL.revokeObjectURL(workerBlobURL); + return new Promise(function(resolve, reject) { + worker.addEventListener("message", function (e) { + let isGood = (e.data === "SecurityError"); + ok(isGood, "caches.open() should throw SecurityError from worker"); + isGood ? resolve() : reject(); + }); + }); + }); +} + function test() { let privateWin, privateTab; waitForExplicitFinish(); @@ -88,6 +112,7 @@ function test() { testOpen(privateTab.linkedBrowser), testDelete(privateTab.linkedBrowser), testKeys(privateTab.linkedBrowser), + testOpen_worker(privateTab.linkedBrowser), ]); }).then(() => { return BrowserTestUtils.closeWindow(privateWin); From fb163fbacb892c40ff74c62d63e3d643d71925f0 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Mon, 26 Feb 2018 08:29:00 +0200 Subject: [PATCH 19/31] Bug 1439411 - [mozlog] Document built-in CLI logging options r=jgraham The output formatters provided by mozlog are well-documented in the online help guide, but this information is not available to users in the CLI. The `add_logging_group` method extends the consuming project's command-line interface without referencing mozlog itself. This means consumers may not have a means to discover the additional information, and even in cases where they can infer this connection, there is no indication of the stability of the behavior. Extend the description of the built-in output formatters to explain their origin and reference the relevant documentation. --HG-- extra : histedit_source : 9069af86efc67232e059176f99a877c513644ce2 --- testing/mozbase/mozlog/mozlog/commandline.py | 25 ++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/testing/mozbase/mozlog/mozlog/commandline.py b/testing/mozbase/mozlog/mozlog/commandline.py index 64e25f22c798..456692ec794c 100644 --- a/testing/mozbase/mozlog/mozlog/commandline.py +++ b/testing/mozbase/mozlog/mozlog/commandline.py @@ -15,12 +15,18 @@ from . import formatters from .structuredlog import StructuredLogger, set_default_logger log_formatters = { - 'raw': (formatters.JSONFormatter, "Raw structured log messages"), - 'unittest': (formatters.UnittestFormatter, "Unittest style output"), - 'xunit': (formatters.XUnitFormatter, "xUnit compatible XML"), - 'html': (formatters.HTMLFormatter, "HTML report"), - 'mach': (formatters.MachFormatter, "Human-readable output"), - 'tbpl': (formatters.TbplFormatter, "TBPL style log format"), + 'raw': (formatters.JSONFormatter, "Raw structured log messages " + "(provided by mozlog)"), + 'unittest': (formatters.UnittestFormatter, "Unittest style output " + "(provided by mozlog)"), + 'xunit': (formatters.XUnitFormatter, "xUnit compatible XML " + "(povided by mozlog)"), + 'html': (formatters.HTMLFormatter, "HTML report " + "(provided by mozlog)"), + 'mach': (formatters.MachFormatter, "Human-readable output " + "(provided by mozlog)"), + 'tbpl': (formatters.TbplFormatter, "TBPL style log format " + "(provided by mozlog)"), 'errorsummary': (formatters.ErrorSummaryFormatter, argparse.SUPPRESS), } @@ -28,6 +34,9 @@ TEXT_FORMATTERS = ('raw', 'mach') """a subset of formatters for non test harnesses related applications""" +DOCS_URL = "https://firefox-source-docs.mozilla.org/mozbase/mozlog.html" + + def level_filter_wrapper(formatter, level): return handlers.LogLevelFilter(formatter, level) @@ -121,7 +130,9 @@ def add_logging_group(parser, include_formatters=None): group_name = "Output Logging" group_description = ("Each option represents a possible logging format " "and takes a filename to write that format to, " - "or '-' to write to stdout.") + "or '-' to write to stdout. Some options are " + "provided by the mozlog utility; see %s " + "for extended documentation." % DOCS_URL) if include_formatters is None: include_formatters = list(log_formatters.keys()) From cefa3d13b0620ff36e31b505b33c4fec2f5d20f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Mon, 26 Feb 2018 11:54:30 -0800 Subject: [PATCH 20/31] Bug 1440309: Call String_repeat with int32 values to avoid repeated bailouts. r=jandem --HG-- extra : histedit_source : fd347252fa428ef1f1a5670f9e8d4205283d459b --- js/src/builtin/SelfHostingDefines.h | 3 +++ js/src/builtin/String.js | 25 +++++++++++++++++-------- js/src/vm/Interpreter.cpp | 6 +++--- js/src/vm/SelfHosting.cpp | 7 +++++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h index 5ca1b7514d77..81e51aa34875 100644 --- a/js/src/builtin/SelfHostingDefines.h +++ b/js/src/builtin/SelfHostingDefines.h @@ -23,6 +23,9 @@ // NB: keep this in sync with the copy in vm/ArgumentsObject.h. #define MAX_ARGS_LENGTH (500 * 1000) +// NB: keep this in sync with the copy in vm/String.h. +#define MAX_STRING_LENGTH ((1 << 28) - 1) + // Spread non-empty argument list of up to 15 elements. #define SPREAD(v, n) SPREAD_##n(v) #define SPREAD_1(v) v[0] diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index 8708d16394ae..572dfc88818b 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -68,8 +68,7 @@ function String_generic_match(thisValue, regexp) { * A helper function implementing the logic for both String.prototype.padStart * and String.prototype.padEnd as described in ES7 Draft March 29, 2016 */ -function String_pad(maxLength, fillString, padEnd = false) { - +function String_pad(maxLength, fillString, padEnd) { // Steps 1-2. RequireObjectCoercible(this); let str = ToString(this); @@ -83,21 +82,28 @@ function String_pad(maxLength, fillString, padEnd = false) { return str; // Steps 6-7. - let filler = fillString === undefined ? " " : ToString(fillString); + assert(fillString !== undefined, "never called when fillString is undefined"); + let filler = ToString(fillString); // Step 8. if (filler === "") return str; + // Throw an error if the final string length exceeds the maximum string + // length. Perform this check early so we can use int32 operations below. + if (intMaxLength > MAX_STRING_LENGTH) + ThrowRangeError(JSMSG_RESULTING_STRING_TOO_LARGE); + // Step 9. let fillLen = intMaxLength - strLen; // Step 10. + // Perform an int32 division to ensure String_repeat is not called with a + // double to avoid repeated bailouts in ToInteger. let truncatedStringFiller = callFunction(String_repeat, filler, - fillLen / filler.length); + (fillLen / filler.length) | 0); - truncatedStringFiller += callFunction(String_substr, filler, 0, - fillLen % filler.length); + truncatedStringFiller += Substring(filler, 0, fillLen % filler.length); // Step 11. if (padEnd === true) @@ -503,11 +509,14 @@ function String_repeat(count) { if (n < 0) ThrowRangeError(JSMSG_NEGATIVE_REPETITION_COUNT); - if (!(n * S.length < (1 << 28))) + // Inverted condition to handle |Infinity * 0 = NaN| correctly. + if (!(n * S.length <= MAX_STRING_LENGTH)) ThrowRangeError(JSMSG_RESULTING_STRING_TOO_LARGE); // Communicate |n|'s possible range to the compiler. - n = n & ((1 << 28) - 1); + assert((MAX_STRING_LENGTH & (MAX_STRING_LENGTH + 1)) === 0, + "MAX_STRING_LENGTH can be used as a bitmask"); + n = n & MAX_STRING_LENGTH; // Steps 8-9. var T = ""; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index daa8fb04062e..c6a7383585a7 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1683,11 +1683,11 @@ js::ReportInNotObjectError(JSContext* cx, HandleValue lref, int lindex, HandleValue rref, int rindex) { auto uniqueCharsFromString = [](JSContext* cx, HandleValue ref) -> UniqueChars { - static const size_t MAX_STRING_LENGTH = 16; + static const size_t MaxStringLength = 16; RootedString str(cx, ref.toString()); - if (str->length() > MAX_STRING_LENGTH) { + if (str->length() > MaxStringLength) { StringBuffer buf(cx); - if (!buf.appendSubstring(str, 0, MAX_STRING_LENGTH)) + if (!buf.appendSubstring(str, 0, MaxStringLength)) return nullptr; if (!buf.append("...")) return nullptr; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index bcb633fdfb83..0d93d85053e6 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -42,6 +42,7 @@ #include "js/CharacterEncoding.h" #include "js/Date.h" #include "js/Wrapper.h" +#include "vm/ArgumentsObject.h" #include "vm/Compression.h" #include "vm/GeneratorObject.h" #include "vm/Interpreter.h" @@ -3194,3 +3195,9 @@ js::GetSelfHostedFunctionName(JSFunction* fun) static_assert(JSString::MAX_LENGTH <= INT32_MAX, "StringIteratorNext in builtin/String.js assumes the stored index " "into the string is an Int32Value"); + +static_assert(JSString::MAX_LENGTH == MAX_STRING_LENGTH, + "JSString::MAX_LENGTH matches self-hosted constant for maximum string length"); + +static_assert(ARGS_LENGTH_MAX == MAX_ARGS_LENGTH, + "ARGS_LENGTH_MAX matches self-hosted constant for maximum arguments length"); From 971d3fb47261e74da6b9528805989ae37a0fdb73 Mon Sep 17 00:00:00 2001 From: Jason Laster Date: Mon, 26 Feb 2018 08:54:00 +0200 Subject: [PATCH 21/31] Bug 1440550 - Update Debugger Frontend v19. r=jdescottes --HG-- rename : devtools/client/debugger/new/test/mochitest/browser_dbg-babel.js => devtools/client/debugger/new/test/mochitest/browser_dbg-babel-scopes.js extra : histedit_source : 125177262eb6f63e4075da4bb3e2aec2dce65e69 --- devtools/client/debugger/new/README.mozilla | 4 +- devtools/client/debugger/new/debugger.css | 3 + devtools/client/debugger/new/debugger.js | 454 +++++++++++++----- devtools/client/debugger/new/parser-worker.js | 87 +++- .../debugger/new/test/mochitest/browser.ini | 3 +- ...g-babel.js => browser_dbg-babel-scopes.js} | 0 .../mochitest/browser_dbg-babel-stepping.js | 154 ++++++ .../browser_dbg-breaking-from-console.js | 2 +- .../browser_dbg-sourcemaps-reload.js | 1 - 9 files changed, 583 insertions(+), 125 deletions(-) rename devtools/client/debugger/new/test/mochitest/{browser_dbg-babel.js => browser_dbg-babel-scopes.js} (100%) create mode 100644 devtools/client/debugger/new/test/mochitest/browser_dbg-babel-stepping.js diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla index fb037fa31b08..a7f074d21986 100644 --- a/devtools/client/debugger/new/README.mozilla +++ b/devtools/client/debugger/new/README.mozilla @@ -1,8 +1,8 @@ This is the debugger.html project output. See https://github.com/devtools-html/debugger.html -Version 18.0 -Comparison: https://github.com/devtools-html/debugger.html/compare/release-17...release-18 +Version 19.0 +Comparison: https://github.com/devtools-html/debugger.html/compare/release-18...release-19 Packages: - babel-plugin-transform-es2015-modules-commonjs @6.26.0 diff --git a/devtools/client/debugger/new/debugger.css b/devtools/client/debugger/new/debugger.css index ff31a07fed06..241a8cea38a2 100644 --- a/devtools/client/debugger/new/debugger.css +++ b/devtools/client/debugger/new/debugger.css @@ -1928,6 +1928,9 @@ html .toggle-button.end.vertical svg { .source-footer .mapped-source { color: var(--theme-body-color); padding: 2.5px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } /* 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 diff --git a/devtools/client/debugger/new/debugger.js b/devtools/client/debugger/new/debugger.js index 7f60dd630b04..c74c61448829 100644 --- a/devtools/client/debugger/new/debugger.js +++ b/devtools/client/debugger/new/debugger.js @@ -10102,7 +10102,7 @@ const prefs = new PrefsHelper("devtools", { fileSearchWholeWord: ["Bool", "debugger.file-search-whole-word"], fileSearchRegexMatch: ["Bool", "debugger.file-search-regex-match"], debuggerPrefsSchemaVersion: ["Char", "debugger.prefs-schema-version"], - projectDirectoryRoot: ["Char", "project-directory-root", ""] + projectDirectoryRoot: ["Char", "debugger.project-directory-root", ""] }); /* harmony export (immutable) */ __webpack_exports__["prefs"] = prefs; @@ -17921,7 +17921,7 @@ function createPendingBreakpoint(bp) { Object.defineProperty(exports, "__esModule", { value: true }); -exports.replaceOriginalVariableName = exports.getFramework = exports.hasSyntaxError = exports.clearSources = exports.setSource = exports.hasSource = exports.getEmptyLines = exports.getNextStep = exports.clearASTs = exports.clearScopes = exports.clearSymbols = exports.findOutOfScopeLocations = exports.getVariablesInScope = exports.getScopes = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined; +exports.replaceOriginalVariableName = exports.getFramework = exports.hasSyntaxError = exports.clearSources = exports.setSource = exports.hasSource = exports.getEmptyLines = exports.isInvalidPauseLocation = exports.getNextStep = exports.clearASTs = exports.clearScopes = exports.clearSymbols = exports.findOutOfScopeLocations = exports.getVariablesInScope = exports.getScopes = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined; var _devtoolsUtils = __webpack_require__(1363); @@ -17942,6 +17942,7 @@ const clearSymbols = exports.clearSymbols = dispatcher.task("clearSymbols"); const clearScopes = exports.clearScopes = dispatcher.task("clearScopes"); const clearASTs = exports.clearASTs = dispatcher.task("clearASTs"); const getNextStep = exports.getNextStep = dispatcher.task("getNextStep"); +const isInvalidPauseLocation = exports.isInvalidPauseLocation = dispatcher.task("isInvalidPauseLocation"); const getEmptyLines = exports.getEmptyLines = dispatcher.task("getEmptyLines"); const hasSource = exports.hasSource = dispatcher.task("hasSource"); const setSource = exports.setSource = dispatcher.task("setSource"); @@ -19160,6 +19161,16 @@ const arrowBtn = (onClick, type, className, tooltip) => { class SearchInput extends _react.Component { componentDidMount() { + this.setFocus(); + } + + componentDidUpdate(prevProps) { + if (this.props.shouldFocus && !prevProps.shouldFocus) { + this.setFocus(); + } + } + + setFocus() { if (this.$input) { const input = this.$input; input.focus(); @@ -19953,15 +19964,15 @@ var _selectors = __webpack_require__(1352); var _ui = __webpack_require__(1421); -/* 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 . */ +var _source = __webpack_require__(1356); function setContextMenu(type, event) { return ({ dispatch }) => { dispatch({ type: "SET_CONTEXT_MENU", contextMenu: { type, event } }); }; -} +} /* 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 . */ function setPrimaryPaneTab(tabName) { return { type: "SET_PRIMARY_PANE_TAB", tabName }; @@ -19981,6 +19992,10 @@ function setActiveSearch(activeSearch) { return; } + if ((0, _selectors.getQuickOpenEnabled)(getState())) { + dispatch({ type: "CLOSE_QUICK_OPEN" }); + } + dispatch({ type: "TOGGLE_ACTIVE_SEARCH", value: activeSearch @@ -20009,7 +20024,7 @@ function showSource(sourceId) { dispatch({ type: "SHOW_SOURCE", - sourceUrl: source.get("url") + sourceUrl: (0, _source.getRawSourceURL)(source.get("url")) }); }; } @@ -20330,6 +20345,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument exports.getPauseReason = getPauseReason; exports.isStepping = isStepping; exports.isPaused = isPaused; +exports.getPreviousPauseFrameLocation = getPreviousPauseFrameLocation; exports.isEvaluatingExpression = isEvaluatingExpression; exports.getPopupObjectProperties = getPopupObjectProperties; exports.getIsWaitingOnBreak = getIsWaitingOnBreak; @@ -20368,7 +20384,8 @@ const createPauseState = exports.createPauseState = () => ({ shouldIgnoreCaughtExceptions: _prefs.prefs.ignoreCaughtExceptions, canRewind: false, debuggeeUrl: "", - command: "" + command: "", + previousLocation: null }); const emptyPauseState = { @@ -20379,7 +20396,8 @@ const emptyPauseState = { original: {} }, selectedFrameId: null, - loadedObjects: {} + loadedObjects: {}, + previousLocation: null }; function update(state = createPauseState(), action) { @@ -20485,7 +20503,12 @@ function update(state = createPauseState(), action) { }); case "COMMAND": - return action.status === "start" ? _extends({}, state, emptyPauseState, { command: action.command }) : _extends({}, state, { command: "" }); + { + return action.status === "start" ? _extends({}, state, emptyPauseState, { + command: action.command, + previousLocation: buildPreviousLocation(state, action) + }) : _extends({}, state, { command: "" }); + } case "RESUME": // We clear why on resume because we need it to decide if @@ -20504,6 +20527,24 @@ function update(state = createPauseState(), action) { return state; } +function buildPreviousLocation(state, action) { + const { frames, previousLocation } = state; + + if (action.command !== "stepOver") { + return null; + } + + const frame = frames && frames.length > 0 ? frames[0] : null; + if (!frame) { + return previousLocation; + } + + return { + location: frame.location, + generatedLocation: frame.generatedLocation + }; +} + // Selectors // Unfortunately, it's really hard to make these functions accept just @@ -20531,6 +20572,10 @@ function isPaused(state) { return !!getFrames(state); } +function getPreviousPauseFrameLocation(state) { + return state.pause.previousLocation; +} + function isEvaluatingExpression(state) { return state.pause.command === "expression"; } @@ -21329,74 +21374,7 @@ function setOutOfScopeLocations() { } /***/ }), -/* 1400 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getPauseReason = getPauseReason; -exports.isException = isException; -exports.isInterrupted = isInterrupted; -exports.inDebuggerEval = inDebuggerEval; - - -// Map protocol pause "why" reason to a valid L10N key -// These are the known unhandled reasons: -// "breakpointConditionThrown", "clientEvaluated" -// "interrupted", "attached" -const reasons = { - debuggerStatement: "whyPaused.debuggerStatement", - breakpoint: "whyPaused.breakpoint", - exception: "whyPaused.exception", - resumeLimit: "whyPaused.resumeLimit", - pauseOnDOMEvents: "whyPaused.pauseOnDOMEvents", - breakpointConditionThrown: "whyPaused.breakpointConditionThrown", - - // V8 - DOM: "whyPaused.breakpoint", - EventListener: "whyPaused.pauseOnDOMEvents", - XHR: "whyPaused.xhr", - promiseRejection: "whyPaused.promiseRejection", - assert: "whyPaused.assert", - debugCommand: "whyPaused.debugCommand", - other: "whyPaused.other" -}; /* 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 . */ - -function getPauseReason(why) { - if (!why) { - return null; - } - - const reasonType = why.type; - if (!reasons[reasonType]) { - console.log("Please file an issue: reasonType=", reasonType); - } - return reasons[reasonType]; -} - -function isException(why) { - return why && why.type && why.type === "exception"; -} - -function isInterrupted(why) { - return why && why.type && why.type === "interrupted"; -} - -function inDebuggerEval(why) { - if (why && why.type === "exception" && why.exception && why.exception.preview && why.exception.preview.fileName) { - return why.exception.preview.fileName === "debugger eval code"; - } - - return false; -} - -/***/ }), +/* 1400 */, /* 1401 */ /***/ (function(module, exports, __webpack_require__) { @@ -35210,30 +35188,33 @@ class SearchBar extends _react.Component { }; this.closeSearch = e => { - const { editor, searchOn } = this.props; - + const { closeFileSearch, editor, searchOn } = this.props; if (editor && searchOn) { this.clearSearch(); - this.props.closeFileSearch(editor); + closeFileSearch(editor); e.stopPropagation(); e.preventDefault(); } + this.setState({ query: "", inputFocused: false }); }; this.toggleSearch = e => { e.stopPropagation(); e.preventDefault(); - const { editor } = this.props; + const { editor, searchOn, setActiveSearch } = this.props; - if (!this.props.searchOn) { - this.props.setActiveSearch("file"); + if (!searchOn) { + setActiveSearch("file"); } - if (this.props.searchOn && editor) { - const selection = editor.codeMirror.getSelection(); - this.setState({ query: selection }); - if (selection !== "") { - this.doSearch(selection); + if (searchOn && editor) { + const query = editor.codeMirror.getSelection() || this.state.query; + + if (query !== "") { + this.setState({ query, inputFocused: true }); + this.doSearch(query); + } else { + this.setState({ query: "", inputFocused: true }); } } }; @@ -35274,6 +35255,10 @@ class SearchBar extends _react.Component { return this.doSearch(e.target.value); }; + this.onBlur = e => { + this.setState({ inputFocused: false }); + }; + this.onKeyDown = e => { if (e.key !== "Enter" && e.key !== "F3") { return; @@ -35338,7 +35323,8 @@ class SearchBar extends _react.Component { query: props.query, selectedResultIndex: 0, count: 0, - index: -1 + index: -1, + inputFocused: false }; } @@ -35422,11 +35408,13 @@ class SearchBar extends _react.Component { placeholder: L10N.getStr("sourceSearch.search.placeholder"), summaryMsg: this.buildSummaryMsg(), onChange: this.onChange, + onBlur: this.onBlur, showErrorEmoji: this.shouldShowErrorEmoji(), onKeyDown: this.onKeyDown, handleNext: e => this.traverseResults(e, false), handlePrev: e => this.traverseResults(e, true), - handleClose: this.closeSearch + handleClose: this.closeSearch, + shouldFocus: this.state.inputFocused }), _react2.default.createElement( "div", @@ -39255,7 +39243,7 @@ var _editor = __webpack_require__(1358); var _source = __webpack_require__(1356); -var _pause = __webpack_require__(1400); +var _pause = __webpack_require__(2419); var _indentation = __webpack_require__(1438); @@ -39727,7 +39715,7 @@ function getMenuItems(event, { id: "node-menu-show-source", label: revealInTreeLabel, accesskey: revealInTreeKey, - disabled: isPrettyPrinted, + disabled: false, click: () => showSource(sourceId) }; @@ -40454,7 +40442,7 @@ var _source = __webpack_require__(1356); var _selectors = __webpack_require__(1352); -var _pause = __webpack_require__(1400); +var _pause = __webpack_require__(2419); var _breakpoint = __webpack_require__(1364); @@ -41221,7 +41209,7 @@ var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); -var _pause = __webpack_require__(1400); +var _pause = __webpack_require__(2419); __webpack_require__(1337); @@ -43363,7 +43351,9 @@ function hasAwait(source, pauseLocation) { return false; } - return source.text.split("\n")[line - 1].slice(column, column + 200).match(/(yield|await)/); + const snippet = source.text.split("\n")[line - 1].slice(column - 50, column + 50); + + return !!snippet.match(/(yield|await)/); } /** @@ -43382,6 +43372,7 @@ function astCommand(stepType) { // This type definition is ambiguous: const frame = (0, _selectors.getTopFrame)(getState()); const source = (0, _selectors.getSelectedSource)(getState()).toJS(); + if (source && hasAwait(source, frame.location)) { const nextLocation = await (0, _parser.getNextStep)(source.id, frame.location); if (nextLocation) { @@ -43593,8 +43584,17 @@ var _sources = __webpack_require__(1797); var _ui = __webpack_require__(1385); +var _commands = __webpack_require__(1637); + +var _pause = __webpack_require__(2419); + +var _mapFrames = __webpack_require__(1804); + var _fetchScopes = __webpack_require__(1655); +async function getOriginalSourceForFrame(state, frame) { + return (0, _selectors.getSources)(state).get(frame.location.sourceId); +} /** * Debugger has just paused * @@ -43609,12 +43609,26 @@ var _fetchScopes = __webpack_require__(1655); function paused(pauseInfo) { return async function ({ dispatch, getState, client, sourceMaps }) { const { frames, why, loadedObjects } = pauseInfo; + const rootFrame = frames.length > 0 ? frames[0] : null; + + if (rootFrame) { + const mappedFrame = await (0, _mapFrames.updateFrameLocation)(rootFrame, sourceMaps); + const source = await getOriginalSourceForFrame(getState(), mappedFrame); + + // Ensure that the original file has loaded if there is one. + await dispatch((0, _sources.loadSourceText)(source)); + + if (await (0, _pause.shouldStep)(mappedFrame, getState(), sourceMaps)) { + dispatch((0, _commands.command)("stepOver")); + return; + } + } dispatch({ type: "PAUSED", why, frames, - selectedFrameId: frames[0] ? frames[0].id : undefined, + selectedFrameId: rootFrame ? rootFrame.id : undefined, loadedObjects: loadedObjects || [] }); @@ -43657,7 +43671,7 @@ var _selectors = __webpack_require__(1352); var _expressions = __webpack_require__(1398); -var _pause = __webpack_require__(1400); +var _pause = __webpack_require__(2419); /** * Debugger has just resumed @@ -44001,7 +44015,7 @@ class QuickOpenModal extends _react.Component { return; } - if (query == "") { + if (query == "" && !this.isShortcutQuery()) { return this.showTopSources(); } @@ -48484,6 +48498,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument * @module actions/sources */ +exports.loadSourceMap = loadSourceMap; exports.newSource = newSource; exports.newSources = newSources; @@ -48510,25 +48525,25 @@ function createOriginalSource(originalUrl, generatedSource, sourceMaps) { }; } -// TODO: It would be nice to make getOriginalURLs a safer api -async function loadOriginalSourceUrls(sourceMaps, generatedSource) { - try { - return await sourceMaps.getOriginalURLs(generatedSource); - } catch (e) { - console.error(e); - return null; - } -} - /** * @memberof actions/sources * @static */ function loadSourceMap(generatedSource) { return async function ({ dispatch, getState, sourceMaps }) { - const urls = await loadOriginalSourceUrls(sourceMaps, generatedSource); + let urls; + try { + urls = await sourceMaps.getOriginalURLs(generatedSource); + } catch (e) { + console.error(e); + urls = null; + } if (!urls) { - // If this source doesn't have a sourcemap, do nothing. + // If this source doesn't have a sourcemap, enable it for pretty printing + dispatch({ + type: "UPDATE_SOURCE", + source: _extends({}, generatedSource, { sourceMapURL: "" }) + }); return; } @@ -48836,6 +48851,7 @@ Object.defineProperty(exports, "__esModule", { var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +exports.updateFrameLocation = updateFrameLocation; exports.mapFrames = mapFrames; var _selectors = __webpack_require__(1352); @@ -50361,6 +50377,7 @@ class ProjectSearch extends _react.Component { if (this.isProjectSearchEnabled()) { return closeProjectSearch(); } + return setActiveSearch("project"); }; @@ -50880,11 +50897,11 @@ class Tab extends _react.PureComponent { }) }]; - if (!isPrettySource) { - items.push({ - item: _extends({}, tabMenuItems.showSource, { click: () => showSource(tab) }) - }); + items.push({ + item: _extends({}, tabMenuItems.showSource, { click: () => showSource(tab) }) + }); + if (!isPrettySource) { items.push({ item: _extends({}, tabMenuItems.prettyPrint, { click: () => togglePrettyPrint(tab) @@ -52110,6 +52127,213 @@ function getExpressionFromCoords(cm, coord) { return { expression, location }; } +/***/ }), +/* 2361 */, +/* 2362 */, +/* 2363 */, +/* 2364 */, +/* 2365 */, +/* 2366 */, +/* 2367 */, +/* 2368 */, +/* 2369 */, +/* 2370 */, +/* 2371 */, +/* 2372 */, +/* 2373 */, +/* 2374 */, +/* 2375 */, +/* 2376 */, +/* 2377 */, +/* 2378 */, +/* 2379 */, +/* 2380 */, +/* 2381 */, +/* 2382 */, +/* 2383 */, +/* 2384 */, +/* 2385 */, +/* 2386 */, +/* 2387 */, +/* 2388 */, +/* 2389 */, +/* 2390 */, +/* 2391 */, +/* 2392 */, +/* 2393 */, +/* 2394 */, +/* 2395 */, +/* 2396 */, +/* 2397 */, +/* 2398 */, +/* 2399 */, +/* 2400 */, +/* 2401 */, +/* 2402 */, +/* 2403 */, +/* 2404 */, +/* 2405 */, +/* 2406 */, +/* 2407 */, +/* 2408 */, +/* 2409 */, +/* 2410 */, +/* 2411 */, +/* 2412 */, +/* 2413 */, +/* 2414 */, +/* 2415 */, +/* 2416 */, +/* 2417 */, +/* 2418 */, +/* 2419 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _why = __webpack_require__(2420); + +Object.keys(_why).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _why[key]; + } + }); +}); + +var _stepping = __webpack_require__(2421); + +Object.keys(_stepping).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _stepping[key]; + } + }); +}); + +/***/ }), +/* 2420 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getPauseReason = getPauseReason; +exports.isException = isException; +exports.isInterrupted = isInterrupted; +exports.inDebuggerEval = inDebuggerEval; + + +// Map protocol pause "why" reason to a valid L10N key +// These are the known unhandled reasons: +// "breakpointConditionThrown", "clientEvaluated" +// "interrupted", "attached" +const reasons = { + debuggerStatement: "whyPaused.debuggerStatement", + breakpoint: "whyPaused.breakpoint", + exception: "whyPaused.exception", + resumeLimit: "whyPaused.resumeLimit", + pauseOnDOMEvents: "whyPaused.pauseOnDOMEvents", + breakpointConditionThrown: "whyPaused.breakpointConditionThrown", + + // V8 + DOM: "whyPaused.breakpoint", + EventListener: "whyPaused.pauseOnDOMEvents", + XHR: "whyPaused.xhr", + promiseRejection: "whyPaused.promiseRejection", + assert: "whyPaused.assert", + debugCommand: "whyPaused.debugCommand", + other: "whyPaused.other" +}; /* 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 . */ + +function getPauseReason(why) { + if (!why) { + return null; + } + + const reasonType = why.type; + if (!reasons[reasonType]) { + console.log("Please file an issue: reasonType=", reasonType); + } + return reasons[reasonType]; +} + +function isException(why) { + return why && why.type && why.type === "exception"; +} + +function isInterrupted(why) { + return why && why.type && why.type === "interrupted"; +} + +function inDebuggerEval(why) { + if (why && why.type === "exception" && why.exception && why.exception.preview && why.exception.preview.fileName) { + return why.exception.preview.fileName === "debugger eval code"; + } + + return false; +} + +/***/ }), +/* 2421 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shouldStep = shouldStep; + +var _lodash = __webpack_require__(2); + +var _devtoolsSourceMap = __webpack_require__(1360); + +var _selectors = __webpack_require__(1352); + +var _parser = __webpack_require__(1365); + +/* 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 . */ + +async function shouldStep(rootFrame, state, sourceMaps) { + if (!rootFrame) { + return false; + } + + const selectedSource = (0, _selectors.getSelectedSource)(state); + const previousFrameInfo = (0, _selectors.getPreviousPauseFrameLocation)(state); + + let previousFrameLoc; + let currentFrameLoc; + + if (selectedSource && (0, _devtoolsSourceMap.isOriginalId)(selectedSource.get("id"))) { + currentFrameLoc = rootFrame.location; + previousFrameLoc = previousFrameInfo && previousFrameInfo.location; + } else { + currentFrameLoc = rootFrame.generatedLocation; + previousFrameLoc = previousFrameInfo && previousFrameInfo.generatedLocation; + } + + return (0, _devtoolsSourceMap.isOriginalId)(currentFrameLoc.sourceId) && (previousFrameLoc && (0, _lodash.isEqual)(previousFrameLoc, currentFrameLoc) || (await (0, _parser.isInvalidPauseLocation)(currentFrameLoc))); +} + /***/ }) /******/ ]); }); \ No newline at end of file diff --git a/devtools/client/debugger/new/parser-worker.js b/devtools/client/debugger/new/parser-worker.js index 2b2faeab3d8c..e90ee9f6d2a8 100644 --- a/devtools/client/debugger/new/parser-worker.js +++ b/devtools/client/debugger/new/parser-worker.js @@ -34597,15 +34597,15 @@ var _validate = __webpack_require__(1629); var _frameworks = __webpack_require__(1703); +var _pauseLocation = __webpack_require__(2422); + var _devtoolsUtils = __webpack_require__(1363); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -/* 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 . */ - -const { workerHandler } = _devtoolsUtils.workerUtils; +const { workerHandler } = _devtoolsUtils.workerUtils; /* 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 . */ self.onmessage = workerHandler({ getClosestExpression: _closest.getClosestExpression, @@ -34618,6 +34618,7 @@ self.onmessage = workerHandler({ hasSource: _sources.hasSource, setSource: _sources.setSource, clearSources: _sources.clearSources, + isInvalidPauseLocation: _pauseLocation.isInvalidPauseLocation, getVariablesInScope: _scopes.getVariablesInScope, getNextStep: _steps.getNextStep, getEmptyLines: _getEmptyLines2.default, @@ -60818,6 +60819,82 @@ function stripModuleScope(rootScope) { }); } +/***/ }), +/* 2415 */, +/* 2416 */, +/* 2417 */, +/* 2418 */, +/* 2419 */, +/* 2420 */, +/* 2421 */, +/* 2422 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.isInvalidPauseLocation = isInvalidPauseLocation; + +var _types = __webpack_require__(2268); + +var t = _interopRequireWildcard(_types); + +var _ast = __webpack_require__(1375); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +/* 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 . */ + +const STOP = {}; + +function isInvalidPauseLocation(location) { + const state = { + invalid: false, + location + }; + + try { + (0, _ast.fastTraverseAst)(location.sourceId, { enter: invalidLocationVisitor }, state); + } catch (e) { + if (e !== STOP) { + throw e; + } + } + + return state.invalid; +} + +function invalidLocationVisitor(node, ancestors, state) { + const { location } = state; + + if (node.loc.end.line < location.line) { + return; + } + if (node.loc.start.line > location.line) { + throw STOP; + } + + if (location.line === node.loc.start.line && location.column >= node.loc.start.column && t.isFunction(node) && !t.isArrowFunctionExpression(node) && (location.line < node.body.loc.start.line || location.line === node.body.loc.start.line && location.column <= node.body.loc.start.column)) { + // Disallow pausing _inside_ in function arguments to avoid pausing inside + // of destructuring and other logic. + state.invalid = true; + throw STOP; + } + + if (location.line === node.loc.start.line && location.column === node.loc.start.column && t.isBlockStatement(node)) { + // Disallow pausing directly before the opening curly of a block statement. + // Babel occasionally maps statements with unknown original positions to + // this location. + state.invalid = true; + throw STOP; + } +} + /***/ }) /******/ ]); }); \ No newline at end of file diff --git a/devtools/client/debugger/new/test/mochitest/browser.ini b/devtools/client/debugger/new/test/mochitest/browser.ini index 381d9b9395a9..04245303e25e 100644 --- a/devtools/client/debugger/new/test/mochitest/browser.ini +++ b/devtools/client/debugger/new/test/mochitest/browser.ini @@ -117,8 +117,9 @@ support-files = [browser_dbg-asm.js] [browser_dbg-async-stepping.js] -[browser_dbg-babel.js] +[browser_dbg-babel-scopes.js] skip-if = (os == "win" && ccov) # bug 1438797 +[browser_dbg-babel-stepping.js] [browser_dbg-breaking.js] [browser_dbg-breaking-from-console.js] [browser_dbg-breakpoints.js] diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-babel.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-scopes.js similarity index 100% rename from devtools/client/debugger/new/test/mochitest/browser_dbg-babel.js rename to devtools/client/debugger/new/test/mochitest/browser_dbg-babel-scopes.js diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-stepping.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-stepping.js new file mode 100644 index 000000000000..2c29d45536d6 --- /dev/null +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-stepping.js @@ -0,0 +1,154 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests for stepping through Babel's compile output. + +async function breakpointSteps(dbg, fixture, { line, column }, steps) { + const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg; + + const filename = `fixtures/${fixture}/input.js`; + await waitForSources(dbg, filename); + + ok(true, "Original sources exist"); + const source = findSource(dbg, filename); + + await selectSource(dbg, source); + + // Test that breakpoint is not off by a line. + await addBreakpoint(dbg, source, line); + + is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); + ok( + getBreakpoint(getState(), { sourceId: source.id, line, column }), + "Breakpoint has correct line" + ); + + const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase()); + + const invokeResult = invokeInTab(fnName); + + let invokeFailed = await Promise.race([ + waitForPaused(dbg), + invokeResult.then(() => new Promise(() => {}), () => true) + ]); + + if (invokeFailed) { + return invokeResult; + } + + assertPausedLocation(dbg); + + await removeBreakpoint(dbg, source.id, line, column); + + is(getBreakpoints(getState()).size, 0, "Breakpoint reverted"); + + await runSteps(dbg, source, steps); + + await resume(dbg); + + // If the invoke errored later somehow, capture here so the error is + // reported nicely. + await invokeResult; + + ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`); +} + +async function runSteps(dbg, source, steps) { + const { selectors: { getVisibleSelectedFrame }, getState } = dbg; + + for (const [i, [type, position]] of steps.entries()) { + switch (type) { + case "stepOver": + await stepOver(dbg); + break; + case "stepIn": + await stepIn(dbg); + break; + default: + throw new Error("Unknown stepping type"); + } + + const { location } = getVisibleSelectedFrame(getState()); + + is(location.sourceId, source.id, `Step ${i} has correct sourceId`); + is(location.line, position.line, `Step ${i} has correct line`); + is(location.column, position.column, `Step ${i} has correct column`); + + assertPausedLocation(dbg); + } +} + +add_task(async function() { + requestLongerTimeout(4); + + const dbg = await initDebugger("doc-babel.html"); + + await breakpointSteps(dbg, "step-over-for-of", { line: 4, column: 2 }, [ + ["stepOver", { line: 6, column: 2 }], + ["stepOver", { line: 7, column: 4 }], + ["stepOver", { line: 6, column: 2 }], + ["stepOver", { line: 7, column: 4 }], + ["stepOver", { line: 6, column: 2 }], + ["stepOver", { line: 10, column: 2 }] + ]); + + // This codifies the current behavior, but stepping twice over the for + // header isn't ideal. + await breakpointSteps(dbg, "step-over-for-of-array", { line: 3, column: 2 }, [ + ["stepOver", { line: 5, column: 2 }], + ["stepOver", { line: 5, column: 7 }], + ["stepOver", { line: 6, column: 4 }], + ["stepOver", { line: 5, column: 2 }], + ["stepOver", { line: 5, column: 7 }], + ["stepOver", { line: 6, column: 4 }], + ["stepOver", { line: 5, column: 2 }], + ["stepOver", { line: 9, column: 2 }] + ]); + + // The closure means it isn't actually possible to step into the for body, + // and Babel doesn't map the _loop() call, so we step past it automatically. + await breakpointSteps( + dbg, + "step-over-for-of-closure", + { line: 6, column: 2 }, + [ + ["stepOver", { line: 8, column: 2 }], + ["stepOver", { line: 12, column: 2 }] + ] + ); + + // Same as the previous, not possible to step into the body. The less + // complicated array logic makes it possible to step into the header at least, + // but this does end up double-visiting the for head. + await breakpointSteps( + dbg, + "step-over-for-of-array-closure", + { line: 3, column: 2 }, + [ + ["stepOver", { line: 5, column: 2 }], + ["stepOver", { line: 5, column: 7 }], + ["stepOver", { line: 5, column: 2 }], + ["stepOver", { line: 5, column: 7 }], + ["stepOver", { line: 5, column: 2 }], + ["stepOver", { line: 9, column: 2 }] + ] + ); + + await breakpointSteps( + dbg, + "step-over-function-params", + { line: 6, column: 2 }, + [["stepOver", { line: 7, column: 2 }], ["stepIn", { line: 2, column: 2 }]] + ); + + await breakpointSteps( + dbg, + "step-over-regenerator-await", + { line: 2, column: 2 }, + [ + // Won't work until a fix to regenerator lands and we rebuild. + // https://github.com/facebook/regenerator/issues/342 + // ["stepOver", { line: 4, column: 2 }], + ] + ); +}); diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking-from-console.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking-from-console.js index 883a297c19b5..dd41c9c6957f 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking-from-console.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking-from-console.js @@ -26,7 +26,7 @@ add_task(async function() { const { selectors: { getSelectedSource }, getState } = dbg; // Make sure the thread is paused in the right source and location - await waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); + await waitForPaused(dbg); is(dbg.win.cm.getValue(), "debugger"); const source = getSelectedSource(getState()).toJS(); assertPausedLocation(dbg); diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js index 9899ffd47468..c879192c05d2 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js @@ -53,7 +53,6 @@ add_task(async function() { await reload(dbg); await waitForSource(dbg, "v1"); await syncBp; - await waitForSelectedSource(dbg, "v1"); is(getBreakpoints(dbg).length, 0, "No breakpoints"); }); From 767d4dafd25b65fb4c591a182926c6308c89505f Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Fri, 23 Feb 2018 08:00:00 +0200 Subject: [PATCH 22/31] Bug 1440663 - Add a preference to limit document opening data conversion recursion depth to nsDocumentOpenInfo, r=smaug --HG-- extra : histedit_source : 939bf4439875a7d88617d36cbf060e9d728c65fb --- modules/libpref/init/all.js | 5 +++++ uriloader/base/nsURILoader.cpp | 32 +++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 21edf6e72e78..5f3b06b8dbe4 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -6005,3 +6005,8 @@ pref("layers.omtp.paint-workers", 1); #endif pref("layers.omtp.release-capture-on-main-thread", false); pref("layers.omtp.dump-capture", false); + +// Limits the depth of recursive conversion of data when opening +// a content to view. This is mostly intended to prevent infinite +// loops with faulty converters involved. +pref("general.document_open_conversion_depth_limit", 20); diff --git a/uriloader/base/nsURILoader.cpp b/uriloader/base/nsURILoader.cpp index 90d56dee15c0..ff0d8079c099 100644 --- a/uriloader/base/nsURILoader.cpp +++ b/uriloader/base/nsURILoader.cpp @@ -49,6 +49,7 @@ #include "mozilla/Attributes.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/Preferences.h" +#include "mozilla/Unused.h" #include "nsContentUtils.h" mozilla::LazyLogModule nsURILoader::mLog("URILoader"); @@ -60,6 +61,17 @@ mozilla::LazyLogModule nsURILoader::mLog("URILoader"); #define NS_PREF_DISABLE_BACKGROUND_HANDLING \ "security.exthelperapp.disable_background_handling" +static uint32_t sConvertDataLimit = 20; + +static bool InitPreferences() +{ + nsresult rv = mozilla::Preferences::AddUintVarCache( + &sConvertDataLimit, + "general.document_open_conversion_depth_limit", + 20); + return NS_SUCCEEDED(rv); +} + /** * The nsDocumentOpenInfo contains the state required when a single * document is being opened in order to discover the content type... @@ -157,6 +169,11 @@ protected: * nsIURIContentListeners. */ RefPtr mURILoader; + + /** + * Limit of data conversion depth to prevent infinite conversion loops + */ + uint32_t mDataConversionDepthLimit; }; NS_IMPL_ADDREF(nsDocumentOpenInfo) @@ -179,7 +196,8 @@ nsDocumentOpenInfo::nsDocumentOpenInfo(nsIInterfaceRequestor* aWindowContext, nsURILoader* aURILoader) : m_originalContext(aWindowContext), mFlags(aFlags), - mURILoader(aURILoader) + mURILoader(aURILoader), + mDataConversionDepthLimit(sConvertDataLimit) { } @@ -625,6 +643,12 @@ nsDocumentOpenInfo::ConvertData(nsIRequest *request, PromiseFlatCString(aSrcContentType).get(), PromiseFlatCString(aOutContentType).get())); + if (mDataConversionDepthLimit == 0) { + LOG(("[0x%p] nsDocumentOpenInfo::ConvertData - reached the recursion limit!", this)); + // This will fall back to external helper app handling. + return NS_ERROR_ABORT; + } + NS_PRECONDITION(aSrcContentType != aOutContentType, "ConvertData called when the two types are the same!"); nsresult rv = NS_OK; @@ -648,6 +672,9 @@ nsDocumentOpenInfo::ConvertData(nsIRequest *request, LOG((" Downstream DocumentOpenInfo would be: 0x%p", nextLink.get())); + // Decrease the conversion recursion limit by one to prevent infinite loops. + nextLink->mDataConversionDepthLimit = mDataConversionDepthLimit - 1; + // Make sure nextLink starts with the contentListener that said it wanted the // results of this decode. nextLink->m_contentListener = aListener; @@ -885,6 +912,9 @@ nsresult nsURILoader::OpenChannel(nsIChannel* channel, } } + static bool once = InitPreferences(); + mozilla::Unused << once; + // we need to create a DocumentOpenInfo object which will go ahead and open // the url and discover the content type.... RefPtr loader = From e8e3e9a5e77a5ffdab450b2b9226d99570a78050 Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Thu, 22 Feb 2018 11:33:20 -0800 Subject: [PATCH 23/31] Bug 1440808 - Cleanup error handling in nsXULPrototypeDocument::Read. r=mccr8 This converts from the odd `tmp` for `rv` pattern and just returns immediately on failure instead. --HG-- extra : rebase_source : 1ad5882c1411e9e10f99201b6233ed87c71a20cc --- dom/xul/nsXULPrototypeDocument.cpp | 100 +++++++++++++---------------- xpcom/ds/nsISerializable.idl | 2 +- 2 files changed, 47 insertions(+), 55 deletions(-) diff --git a/dom/xul/nsXULPrototypeDocument.cpp b/dom/xul/nsXULPrototypeDocument.cpp index 55073fb45317..68d1148ed828 100644 --- a/dom/xul/nsXULPrototypeDocument.cpp +++ b/dom/xul/nsXULPrototypeDocument.cpp @@ -108,27 +108,25 @@ NS_NewXULPrototypeDocument(nsXULPrototypeDocument** aResult) NS_IMETHODIMP nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream) { - nsresult rv; - nsCOMPtr supports; - rv = aStream->ReadObject(true, getter_AddRefs(supports)); + nsresult rv = aStream->ReadObject(true, getter_AddRefs(supports)); + if (NS_FAILED(rv)) { + return rv; + } mURI = do_QueryInterface(supports); uint32_t count, i; nsCOMPtr styleOverlayURI; - nsresult tmp = aStream->Read32(&count); - if (NS_FAILED(tmp)) { - return tmp; - } + rv = aStream->Read32(&count); if (NS_FAILED(rv)) { return rv; } for (i = 0; i < count; ++i) { - tmp = aStream->ReadObject(true, getter_AddRefs(supports)); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = aStream->ReadObject(true, getter_AddRefs(supports)); + if (NS_FAILED(rv)) { + return rv; } styleOverlayURI = do_QueryInterface(supports); mStyleSheetReferences.AppendObject(styleOverlayURI); @@ -136,12 +134,11 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream) // nsIPrincipal mNodeInfoManager->mPrincipal - nsCOMPtr principal; - tmp = aStream->ReadObject(true, getter_AddRefs(supports)); - principal = do_QueryInterface(supports); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = aStream->ReadObject(true, getter_AddRefs(supports)); + if (NS_FAILED(rv)) { + return rv; } + nsCOMPtr principal = do_QueryInterface(supports); // Better safe than sorry.... mNodeInfoManager->SetDocumentPrincipal(principal); @@ -150,45 +147,45 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream) // mozilla::dom::NodeInfo table nsTArray> nodeInfos; - tmp = aStream->Read32(&count); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = aStream->Read32(&count); + if (NS_FAILED(rv)) { + return rv; } nsAutoString namespaceURI, prefixStr, localName; bool prefixIsNull; RefPtr prefix; for (i = 0; i < count; ++i) { - tmp = aStream->ReadString(namespaceURI); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = aStream->ReadString(namespaceURI); + if (NS_FAILED(rv)) { + return rv; } - tmp = aStream->ReadBoolean(&prefixIsNull); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = aStream->ReadBoolean(&prefixIsNull); + if (NS_FAILED(rv)) { + return rv; } if (prefixIsNull) { prefix = nullptr; } else { - tmp = aStream->ReadString(prefixStr); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = aStream->ReadString(prefixStr); + if (NS_FAILED(rv)) { + return rv; } prefix = NS_Atomize(prefixStr); } - tmp = aStream->ReadString(localName); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = aStream->ReadString(localName); + if (NS_FAILED(rv)) { + return rv; } RefPtr nodeInfo; // Using UINT16_MAX here as we don't know which nodeinfos will be // used for attributes and which for elements. And that doesn't really // matter. - tmp = mNodeInfoManager->GetNodeInfo(localName, prefix, namespaceURI, - UINT16_MAX, - getter_AddRefs(nodeInfo)); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = mNodeInfoManager->GetNodeInfo(localName, prefix, namespaceURI, + UINT16_MAX, + getter_AddRefs(nodeInfo)); + if (NS_FAILED(rv)) { + return rv; } nodeInfos.AppendElement(nodeInfo); } @@ -196,41 +193,36 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream) // Document contents uint32_t type; while (NS_SUCCEEDED(rv)) { - tmp = aStream->Read32(&type); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = aStream->Read32(&type); + if (NS_FAILED(rv)) { + return rv; break; } if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_PI) { RefPtr pi = new nsXULPrototypePI(); - tmp = pi->Deserialize(aStream, this, mURI, &nodeInfos); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = pi->Deserialize(aStream, this, mURI, &nodeInfos); + if (NS_FAILED(rv)) { + return rv; } - tmp = AddProcessingInstruction(pi); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = AddProcessingInstruction(pi); + if (NS_FAILED(rv)) { + return rv; } } else if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_Element) { - tmp = mRoot->Deserialize(aStream, this, mURI, &nodeInfos); - if (NS_FAILED(tmp)) { - rv = tmp; + rv = mRoot->Deserialize(aStream, this, mURI, &nodeInfos); + if (NS_FAILED(rv)) { + return rv; } break; } else { NS_NOTREACHED("Unexpected prototype node type"); - rv = NS_ERROR_FAILURE; - break; + return NS_ERROR_FAILURE; } } - tmp = NotifyLoadDone(); - if (NS_FAILED(tmp)) { - rv = tmp; - } - return rv; + return NotifyLoadDone(); } static nsresult diff --git a/xpcom/ds/nsISerializable.idl b/xpcom/ds/nsISerializable.idl index f525f3a8f3d1..1920fa1b16d4 100644 --- a/xpcom/ds/nsISerializable.idl +++ b/xpcom/ds/nsISerializable.idl @@ -17,7 +17,7 @@ interface nsISerializable : nsISupports * can't be set to default values must have been serialized by write, * and should be read from aInputStream in the same order by this method. */ - void read(in nsIObjectInputStream aInputStream); + [must_use] void read(in nsIObjectInputStream aInputStream); /** * Serialize the object implementing nsISerializable to aOutputStream, by From 77901ec1c9122ddf1616a949b9f284a56bed8e3e Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 13 Feb 2018 15:30:51 -0600 Subject: [PATCH 24/31] Bug 1432682 - Part 0: Factor out some test code into a new lib file, jit-test/lib/stepping.js. r=jimb. This also fixes a bug in that code: it skipped the first stopping point in the function (before the first instruction). --HG-- extra : rebase_source : 9682c42ba7ba09b1de475338c83479e1da30a6be --- js/src/jit-test/lib/stepping.js | 32 +++++++++++++++++ .../jit-test/tests/debug/Frame-onStep-19.js | 34 ++++--------------- 2 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 js/src/jit-test/lib/stepping.js diff --git a/js/src/jit-test/lib/stepping.js b/js/src/jit-test/lib/stepping.js new file mode 100644 index 000000000000..122fd9631936 --- /dev/null +++ b/js/src/jit-test/lib/stepping.js @@ -0,0 +1,32 @@ +// Test that stepping through a function stops at the expected lines. +// `script` is a string, some JS code that evaluates to a function. +// `expected` is the array of line numbers where stepping is expected to stop +// when we call the function. +function testStepping(script, expected) { + let g = newGlobal(); + let f = g.eval(script); + + let log = []; + function maybePause(frame) { + let previousLine = log[log.length - 1]; // note: may be undefined + let line = frame.script.getOffsetLocation(frame.offset).lineNumber; + if (line !== previousLine) + log.push(line); + } + + let dbg = new Debugger(g); + dbg.onEnterFrame = frame => { + // Log this pause (before the first instruction of the function). + maybePause(frame); + + // Log future pauses in the same stack frame. + frame.onStep = function() { maybePause(this); }; + + // Now disable this hook so that we step over function calls, not into them. + dbg.onEnterFrame = undefined; + }; + + f(); + + assertEq(log.join(","), expected.join(",")); +} diff --git a/js/src/jit-test/tests/debug/Frame-onStep-19.js b/js/src/jit-test/tests/debug/Frame-onStep-19.js index 3997b21182cd..4305fc130ae1 100644 --- a/js/src/jit-test/tests/debug/Frame-onStep-19.js +++ b/js/src/jit-test/tests/debug/Frame-onStep-19.js @@ -6,40 +6,17 @@ // But users don't actually want to see that happen when they're stepping. // It's super confusing. -function runTest(script, expected) { - let g = newGlobal(); - g.eval(script); +load(libdir + "stepping.js"); - let dbg = new Debugger(g); - let log = []; - dbg.onEnterFrame = frame => { - let previousLine = undefined; - frame.onStep = function() { - let line = this.script.getOffsetLocation(this.offset).lineNumber; - if (line != previousLine) { - log.push(line); - previousLine = line; - } - }; - - // Now disable this hook so that we step over function calls, not into them. - dbg.onEnterFrame = undefined; - }; - - g.f(); - - assertEq(log.join(","), expected.join(",")); -} - -runTest( +testStepping( `\ - var f = (function() { // line 1 + (function() { // line 1 let x = 1; // line 2 funcb("funcb"); // line 3 function funcb(msg) { // line 4 console.log(msg) } - }); // line 7 + }) // line 7 `, [2, 3, 7]); @@ -47,7 +24,7 @@ runTest( // stopping on line 5 wouldn't be so bad if we did it after line 3 and before // line 8; alas, the actual order of execution is 5, 2, 3, 8... which is too // confusing. -runTest( +testStepping( `\ function f() { // 1 var x = 0; // 2 @@ -59,5 +36,6 @@ runTest( class Car {} // 8 return x; // 9 } // 10 + f `, [2, 3, 8, 9, 10]); From 325c426c92f0940b51767ca22d6d3ab64841f7b9 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 26 Feb 2018 13:50:29 -0600 Subject: [PATCH 25/31] Bug 1432682 - Part 1: Remove the hack that causes the bad behavior. r=jimb. The hack caused bytecode for block declaration instantiation to be assigned the location of the first statement inside the block. Unfortunately it made the source view of the debugger client seem out of sync with the Scopes panel: when paused after hitting a breakpoint on that line or stepping there, the source panel showed our location as being inside the block, but the Scopes panel did not show a block scope. Two server tests required fixes (also r=jimb, in a separate patch in the same bug). test_stepping-08.js assumes that stepping into a function stops at the first statement in the function. This is usually true. However, now we are removing a hack, such that our actual behavior for this *particular* function is to stop at the opening curly brace. This causes the test to fail, without anything really being broken. The test is intended to test the interaction of stepping and breakpoints, so the fix that stays truest to the purpose of the test is to change the debuggee here to a function with no prologue instructions, so that we don't stop at the opening brace. test_blackboxing-01.js is a similar story. --HG-- extra : rebase_source : 7afc6cc039f313889ee08cdd93ce114691efa1e9 extra : histedit_source : dc274b7cefbb96574c8207a78db05d80238d291d --- .../server/tests/unit/test_blackboxing-01.js | 2 +- .../server/tests/unit/test_stepping-08.js | 4 ++-- js/src/frontend/BytecodeEmitter.cpp | 24 +++++-------------- .../jit-test/tests/debug/Frame-onStep-19.js | 4 ++-- 4 files changed, 11 insertions(+), 23 deletions(-) diff --git a/devtools/server/tests/unit/test_blackboxing-01.js b/devtools/server/tests/unit/test_blackboxing-01.js index 7d002f304e9e..00bc8bd077e8 100644 --- a/devtools/server/tests/unit/test_blackboxing-01.js +++ b/devtools/server/tests/unit/test_blackboxing-01.js @@ -96,7 +96,7 @@ function evalCode() { /* eslint-disable */ Components.utils.evalInSandbox( "" + function doStuff(k) { // line 1 - let arg = 15; // line 2 - Step in here + var arg = 15; // line 2 - Step in here k(arg); // line 3 }, // line 4 gDebuggee, diff --git a/devtools/server/tests/unit/test_stepping-08.js b/devtools/server/tests/unit/test_stepping-08.js index 6a82e890013e..a5a69a0327e0 100644 --- a/devtools/server/tests/unit/test_stepping-08.js +++ b/devtools/server/tests/unit/test_stepping-08.js @@ -60,8 +60,8 @@ function evaluateTestCode() { } // 4 // 5 function innerFunction() { // 6 - let x = 0; // 7 - let y = 72; // 8 + var x = 0; // 7 + var y = 72; // 8 return x+y; // 9 } // 10 outerFunction(); // 11 diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 59fb359e84a1..fe0969fae6da 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -895,7 +895,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind if (!ensureCache(bce)) return false; - // Marks all names as closed over if the the context requires it. This + // Marks all names as closed over if the context requires it. This // cannot be done in the Parser as we may not know if the context requires // all bindings to be closed over until after parsing is finished. For // example, legacy generators require all bindings to be closed over but @@ -6831,24 +6831,12 @@ BytecodeEmitter::emitLexicalScope(ParseNode* pn) if (pn->isEmptyScope()) return emitLexicalScopeBody(body); - // Update line number notes before emitting TDZ poison in - // EmitterScope::enterLexical to avoid spurious pausing on seemingly - // non-effectful lines in Debugger. - // - // For example, consider the following code. - // - // L1: { - // L2: let x = 42; - // L3: } - // - // If line number notes were not updated before the TDZ poison, the TDZ - // poison bytecode sequence of 'uninitialized; initlexical' will have line - // number L1, and the Debugger will pause there. + // We are about to emit some bytecode for what the spec calls "declaration + // instantiation". Assign these instructions to the opening `{` of the + // block. (Using the location of each declaration we're instantiating is + // too weird when stepping in the debugger.) if (!ParseNodeRequiresSpecialLineNumberNotes(body)) { - ParseNode* pnForPos = body; - if (body->isKind(ParseNodeKind::StatementList) && body->pn_head) - pnForPos = body->pn_head; - if (!updateLineNumberNotes(pnForPos->pn_pos.begin)) + if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false; } diff --git a/js/src/jit-test/tests/debug/Frame-onStep-19.js b/js/src/jit-test/tests/debug/Frame-onStep-19.js index 4305fc130ae1..019c026a8e49 100644 --- a/js/src/jit-test/tests/debug/Frame-onStep-19.js +++ b/js/src/jit-test/tests/debug/Frame-onStep-19.js @@ -18,7 +18,7 @@ testStepping( } }) // line 7 `, - [2, 3, 7]); + [1, 2, 3, 7]); // Stopping at the ClassDeclaration on line 8 is fine. For that matter, // stopping on line 5 wouldn't be so bad if we did it after line 3 and before @@ -38,4 +38,4 @@ testStepping( } // 10 f `, - [2, 3, 8, 9, 10]); + [1, 2, 3, 8, 9, 10]); From 63e95405548bf82983fec4b676f043123e772c31 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 20 Feb 2018 21:40:49 -0600 Subject: [PATCH 26/31] Bug 1440372 - StructuredClone comments. r=sfink. --HG-- extra : rebase_source : c712672413c3e001667d3fc30c88f2aeae891563 extra : histedit_source : 137a842d21598a72f6aa4027041ffc99f0b27e8b --- js/public/StructuredClone.h | 144 ++++++++++++++++++++++++++++++++-- js/src/vm/StructuredClone.cpp | 119 ++++++++++++++-------------- 2 files changed, 195 insertions(+), 68 deletions(-) diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index 5244f45a5fcf..f26d2c750f93 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -20,16 +20,143 @@ #include "js/Value.h" #include "js/Vector.h" +/* + * API for safe passing of structured data, HTML 2018 Feb 21 section 2.7. + * + * + * This is a serialization scheme for JS values, somewhat like JSON. It + * preserves some aspects of JS objects (strings, numbers, own data properties + * with string keys, array elements) but not others (methods, getters and + * setters, prototype chains). Unlike JSON, structured data: + * + * - can contain cyclic references. + * + * - handles Maps, Sets, and some other object types. + * + * - supports *transferring* objects of certain types from one realm to + * another, rather than cloning them. + * + * - is specified by a living standard, and continues to evolve. + * + * - is encoded in a nonstandard binary format, and is never exposed to Web + * content in its serialized form. It's used internally by the browser to + * send data from one thread/realm/domain to another, not across the + * network. + */ + struct JSStructuredCloneReader; struct JSStructuredCloneWriter; -// API for the HTML5 internal structured cloning algorithm. +/** + * The structured-clone serialization format version number. + * + * When serialized data is stored as bytes, e.g. in your Firefox profile, later + * versions of the engine may have to read it. When you upgrade Firefox, we + * don't crawl through your whole profile converting all saved data from the + * previous version of the serialization format to the latest version. So it is + * normal to have data in old formats stored in your profile. + * + * The JS engine can *write* data only in the current format version. + * + * It can *read* any data written in the current version, and data written for + * DifferentProcess scope in earlier versions. + * + * + * ## When to bump this version number + * + * When making a change so drastic that the JS engine needs to know whether + * it's reading old or new serialized data in order to handle both correctly, + * increment this version number. Make sure the engine can still read all + * old data written with previous versions. + * + * If StructuredClone.cpp doesn't contain code that distinguishes between + * version 8 and version 9, there should not be a version 9. + * + * Do not increment for changes that only affect SameProcess encoding. + * + * Increment only for changes that would otherwise break old serialized data. + * Do not increment for new data types. (Rationale: Modulo bugs, older versions + * of the JS engine can already correctly throw errors when they encounter new, + * unrecognized features. A version number bump does not actually help them.) + */ +#define JS_STRUCTURED_CLONE_VERSION 8 namespace JS { +/** + * Indicates the "scope of validity" of serialized data. + * + * Writing plain JS data produces an array of bytes that can be copied and + * read in another process or whatever. The serialized data is Plain Old Data. + * However, HTML also supports `Transferable` objects, which, when cloned, can + * be moved from the source object into the clone, like when you take a + * photograph of someone and it steals their soul. + * See . + * We support cloning and transferring objects of many types. + * + * For example, when we transfer an ArrayBuffer (within a process), we "detach" + * the ArrayBuffer, embed the raw buffer pointer in the serialized data, and + * later install it in a new ArrayBuffer in the destination realm. Ownership + * of that buffer memory is transferred from the original ArrayBuffer to the + * serialized data and then to the clone. + * + * This only makes sense within a single address space. When we transfer an + * ArrayBuffer to another process, the contents of the buffer must be copied + * into the serialized data. (The original ArrayBuffer is still detached, + * though, for consistency; in some cases the caller shouldn't know or care if + * the recipient is in the same process.) + * + * ArrayBuffers are actually a lucky case; some objects (like MessagePorts) + * can't reasonably be stored by value in serialized data -- it's pointers or + * nothing. + * + * So there is a tradeoff between scope of validity -- how far away the + * serialized data may be sent and still make sense -- and efficiency or + * features. The read and write algorithms therefore take an argument of this + * type, allowing the user to control those trade-offs. + */ enum class StructuredCloneScope : uint32_t { + /** + * The most restrictive scope, with greatest efficiency and features. + * + * When writing, this means we're writing for an audience in the same + * process and same thread. The caller promises that the serialized data + * will **not** be shipped off to a different thread/process or stored in a + * database. It's OK to produce serialized data that contains pointers. In + * Rust terms, the serialized data will be treated as `!Send`. + * + * When reading, this means: Accept transferred objects and buffers + * (pointers). The caller promises that the serialized data was written + * using this API (otherwise, the serialized data may contain bogus + * pointers, leading to undefined behavior). + */ SameProcessSameThread, + + /** + * When writing, this means: The caller promises that the serialized data + * will **not** be shipped off to a different process or stored in a + * database. However, it may be shipped to another thread. It's OK to + * produce serialized data that contains pointers to data that is safe to + * send across threads, such as array buffers. In Rust terms, the + * serialized data will be treated as `Send` but not `Copy`. + * + * When reading, this means the same thing as SameProcessSameThread; + * the distinction only matters when writing. + */ SameProcessDifferentThread, + + /** + * The broadest scope. + * + * When writing, this means we're writing for an audience in a different + * process. Produce serialized data that can be sent to other processes, + * bitwise copied, or even stored as bytes in a database and read by later + * versions of Firefox years from now. Transferable objects are limited to + * ArrayBuffers, whose contents are copied into the serialized data (rather + * than just writing a pointer). + * + * When reading, this means: Do not accept pointers. + */ DifferentProcess }; @@ -168,12 +295,6 @@ typedef bool (*TransferStructuredCloneOp)(JSContext* cx, typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership, void* content, uint64_t extraData, void* closure); -// The maximum supported structured-clone serialization format version. -// Increment this when anything at all changes in the serialization format. -// (Note that this does not need to be bumped for Transferable-only changes, -// since they are never saved to persistent storage.) -#define JS_STRUCTURED_CLONE_VERSION 8 - struct JSStructuredCloneCallbacks { ReadStructuredCloneOp read; WriteStructuredCloneOp write; @@ -257,7 +378,11 @@ public: using BufferList::BufferList; }; -/** Note: if the *data contains transferable objects, it can be read only once. */ +/** + * Implements StructuredDeserialize and StructuredDeserializeWithTransfer. + * + * Note: If `data` contains transferable objects, it can be read only once. + */ JS_PUBLIC_API(bool) JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version, JS::StructuredCloneScope scope, @@ -265,6 +390,9 @@ JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t vers const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); /** + * Implements StructuredSerialize, StructuredSerializeForStorage, and + * StructuredSerializeWithTransfer. + * * Note: If the scope is DifferentProcess then the cloneDataPolicy must deny * shared-memory objects, or an error will be signaled if a shared memory object * is seen. diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index c7ddb7801cf4..c7cfd1d34015 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -5,26 +5,25 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* - * This file implements the structured clone algorithm of - * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#safe-passing-of-structured-data + * This file implements the structured data algorithms of + * https://html.spec.whatwg.org/multipage/structured-data.html * - * The implementation differs slightly in that it uses an explicit stack, and - * the "memory" maps source objects to sequential integer indexes rather than - * directly pointing to destination objects. As a result, the order in which - * things are added to the memory must exactly match the order in which they - * are placed into 'allObjs', an analogous array of back-referenceable - * destination objects constructed while reading. + * The spec is in two parts: * - * For the most part, this is easy: simply add objects to the memory when first - * encountering them. But reading in a typed array requires an ArrayBuffer for - * construction, so objects cannot just be added to 'allObjs' in the order they - * are created. If they were, ArrayBuffers would come before typed arrays when - * in fact the typed array was added to 'memory' first. + * - StructuredSerialize examines a JS value and produces a graph of Records. + * - StructuredDeserialize walks the Records and produces a new JS value. * - * So during writing, we add objects to the memory when first encountering - * them. When reading a typed array, a placeholder is pushed onto allObjs until - * the ArrayBuffer has been read, then it is updated with the actual typed - * array object. + * The differences between our implementation and the spec are minor: + * + * - We call the two phases "write" and "read". + * - Our algorithms use an explicit work stack, rather than recursion. + * - Serialized data is a flat array of bytes, not a (possibly cyclic) graph + * of "Records". + * - As a consequence, we handle non-treelike object graphs differently. + * We serialize objects that appear in multiple places in the input as + * backreferences, using sequential integer indexes. + * See `JSStructuredCloneReader::allObjs`, our take on the "memory" map + * in the spec's StructuredDeserialize. */ #include "js/StructuredClone.h" @@ -71,7 +70,7 @@ using JS::CanonicalizeNaN; // sizing data structures. enum StructuredDataType : uint32_t { - /* Structured data types provided by the engine */ + // Structured data types provided by the engine SCTAG_FLOAT_MAX = 0xFFF00000, SCTAG_HEADER = 0xFFF10000, SCTAG_NULL = 0xFFFF0000, @@ -119,11 +118,9 @@ enum StructuredDataType : uint32_t { SCTAG_TYPED_ARRAY_V1_UINT8_CLAMPED = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint8Clamped, SCTAG_TYPED_ARRAY_V1_MAX = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::MaxTypedArrayViewType - 1, - /* - * Define a separate range of numbers for Transferable-only tags, since - * they are not used for persistent clone buffers and therefore do not - * require bumping JS_STRUCTURED_CLONE_VERSION. - */ + // Define a separate range of numbers for Transferable-only tags, since + // they are not used for persistent clone buffers and therefore do not + // require bumping JS_STRUCTURED_CLONE_VERSION. SCTAG_TRANSFER_MAP_HEADER = 0xFFFF0200, SCTAG_TRANSFER_MAP_PENDING_ENTRY, SCTAG_TRANSFER_MAP_ARRAY_BUFFER, @@ -380,7 +377,7 @@ class SCInput { BufferIterator point; }; -} /* namespace js */ +} // namespace js struct JSStructuredCloneReader { public: @@ -432,7 +429,17 @@ struct JSStructuredCloneReader { // Stack of objects with properties remaining to be read. AutoValueVector objs; - // Stack of all objects read during this deserialization + // Array of all objects read during this deserialization, for resolving + // backreferences. + // + // For backreferences to work correctly, objects must be added to this + // array in exactly the order expected by the version of the Writer that + // created the serialized data, even across years and format versions. This + // is usually no problem, since both algorithms do a single linear pass + // over the serialized data. There is one hitch; see readTypedArray. + // + // The values in this vector are objects, except it can temporarily have + // one `undefined` placeholder value (the readTypedArray hack). AutoValueVector allObjs; // The user defined callbacks that will be used for cloning. @@ -736,7 +743,7 @@ bool SCInput::read(uint64_t* p) { if (!point.canPeek()) { - *p = 0; /* initialize to shut GCC up */ + *p = 0; // initialize to shut GCC up return reportTruncated(); } *p = NativeEndian::swapFromLittleEndian(point.peek()); @@ -748,7 +755,7 @@ bool SCInput::readNativeEndian(uint64_t* p) { if (!point.canPeek()) { - *p = 0; /* initialize to shut GCC up */ + *p = 0; // initialize to shut GCC up return reportTruncated(); } *p = point.peek(); @@ -844,9 +851,7 @@ SCInput::readArray(T* p, size_t nelems) JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0); - /* - * Fail if nelems is so huge that computing the full size will overflow. - */ + // Fail if nelems is so huge that computing the full size will overflow. mozilla::CheckedInt size = mozilla::CheckedInt(nelems) * sizeof(T); if (!size.isValid()) return reportTruncated(); @@ -915,15 +920,13 @@ SCOutput::write(uint64_t u) bool SCOutput::writePair(uint32_t tag, uint32_t data) { - /* - * As it happens, the tag word appears after the data word in the output. - * This is because exponents occupy the last 2 bytes of doubles on the - * little-endian platforms we care most about. - * - * For example, TrueValue() is written using writePair(SCTAG_BOOLEAN, 1). - * PairToUInt64 produces the number 0xFFFF000200000001. - * That is written out as the bytes 01 00 00 00 02 00 FF FF. - */ + // As it happens, the tag word appears after the data word in the output. + // This is because exponents occupy the last 2 bytes of doubles on the + // little-endian platforms we care most about. + // + // For example, TrueValue() is written using writePair(SCTAG_BOOLEAN, 1). + // PairToUInt64 produces the number 0xFFFF000200000001. + // That is written out as the bytes 01 00 00 00 02 00 FF FF. return write(PairToUInt64(tag, data)); } @@ -1031,7 +1034,7 @@ SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClo DiscardTransferables(buf, cb, cbClosure); } -} /* namespace js */ +} // namespace js JSStructuredCloneData::~JSStructuredCloneData() { @@ -1152,7 +1155,7 @@ inline void JSStructuredCloneWriter::checkStack() { #ifdef DEBUG - /* To avoid making serialization O(n^2), limit stack-checking at 10. */ + // To avoid making serialization O(n^2), limit stack-checking at 10. const size_t MAX = 10; size_t limit = Min(counts.length(), MAX); @@ -1296,7 +1299,7 @@ JSStructuredCloneWriter::writeSharedWasmMemory(HandleObject obj) bool JSStructuredCloneWriter::startObject(HandleObject obj, bool* backref) { - /* Handle cycles in the object graph. */ + // Handle cycles in the object graph. CloneMemory::AddPtr p = memory.lookupForAdd(obj); if ((*backref = p.found())) return out.writePair(SCTAG_BACK_REFERENCE_OBJECT, p->value()); @@ -1317,10 +1320,8 @@ JSStructuredCloneWriter::startObject(HandleObject obj, bool* backref) bool JSStructuredCloneWriter::traverseObject(HandleObject obj) { - /* - * Get enumerable property ids and put them in reverse order so that they - * will come off the stack in forward order. - */ + // Get enumerable property ids and put them in reverse order so that they + // will come off the stack in forward order. AutoIdVector properties(context()); if (!GetPropertyKeys(context(), obj, JSITER_OWNONLY, &properties)) return false; @@ -1332,13 +1333,13 @@ JSStructuredCloneWriter::traverseObject(HandleObject obj) return false; } - /* Push obj and count to the stack. */ + // Push obj and count to the stack. if (!objs.append(ObjectValue(*obj)) || !counts.append(properties.length())) return false; checkStack(); - /* Write the header for obj. */ + // Write the header for obj. ESClass cls; if (!GetBuiltinClass(context(), obj, &cls)) return false; @@ -1365,13 +1366,13 @@ JSStructuredCloneWriter::traverseMap(HandleObject obj) return false; } - /* Push obj and count to the stack. */ + // Push obj and count to the stack. if (!objs.append(ObjectValue(*obj)) || !counts.append(newEntries.length())) return false; checkStack(); - /* Write the header for obj. */ + // Write the header for obj. return out.writePair(SCTAG_MAP_OBJECT, 0); } @@ -1395,13 +1396,13 @@ JSStructuredCloneWriter::traverseSet(HandleObject obj) return false; } - /* Push obj and count to the stack. */ + // Push obj and count to the stack. if (!objs.append(ObjectValue(*obj)) || !counts.append(keys.length())) return false; checkStack(); - /* Write the header for obj. */ + // Write the header for obj. return out.writePair(SCTAG_SET_OBJECT, 0); } @@ -1587,7 +1588,7 @@ JSStructuredCloneWriter::startWrite(HandleValue v) if (callbacks && callbacks->write) return callbacks->write(context(), this, obj, closure); - /* else fall through */ + // else fall through } return reportDataCloneError(JS_SCERR_UNSUPPORTED_TYPE); @@ -1786,11 +1787,9 @@ JSStructuredCloneWriter::write(HandleValue v) return false; MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id)); - /* - * If obj still has an own property named id, write it out. - * The cost of re-checking could be avoided by using - * NativeIterators. - */ + // If obj still has an own property named id, write it out. + // The cost of re-checking could be avoided by using + // NativeIterators. bool found; if (!HasOwnProperty(context(), obj, id, &found)) return false; @@ -1852,7 +1851,7 @@ class Chars { void forget() { p = nullptr; } }; -} /* anonymous namespace */ +} // anonymous namespace template JSString* @@ -1897,7 +1896,7 @@ JSStructuredCloneReader::readTypedArray(uint32_t arrayType, uint32_t nelems, Mut return false; } - // Push a placeholder onto the allObjs list to stand in for the typed array + // Push a placeholder onto the allObjs list to stand in for the typed array. uint32_t placeholderIndex = allObjs.length(); Value dummy = UndefinedValue(); if (!allObjs.append(dummy)) From 350a71e22a3e56ab6762d76079547af3f7caed25 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Fri, 15 Dec 2017 17:54:52 -0600 Subject: [PATCH 27/31] Bug 1426457 - In the js shell, support setting serialize(_).arraybuffer. r=sfink. --HG-- extra : rebase_source : f8c68c043db78456c061ef9ad32557b0f57b27b3 extra : amend_source : ddeb3b800e26bcbd8283b872fd7c5dd534d3cb08 extra : histedit_source : ce7bdb619d744dd4e268cd9e6b1fbfd1dcfe89c0 --- js/src/builtin/TestingFunctions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index a6b7b010fe27..e0cb7c5d1947 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2911,7 +2911,7 @@ const Class CloneBufferObject::class_ = { const JSPropertySpec CloneBufferObject::props_[] = { JS_PSGS("clonebuffer", getCloneBuffer, setCloneBuffer, 0), - JS_PSG("arraybuffer", getCloneBufferAsArrayBuffer, 0), + JS_PSGS("arraybuffer", getCloneBufferAsArrayBuffer, setCloneBuffer, 0), JS_PS_END }; From b64eef3eaf5a9dcc1a62a52732d4fa48416e4d9f Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 27 Feb 2018 13:26:40 +1300 Subject: [PATCH 28/31] Bug 1439807 - Extend displaylist_mutate to also test inactive layers. r=jmaher --- .../displaylist_inactive_mutate.html | 56 +++++++++++++++++++ .../layout/benchmarks/displaylist_mutate.html | 3 - .../tests/layout/displaylist_mutate.manifest | 1 + 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 testing/talos/talos/tests/layout/benchmarks/displaylist_inactive_mutate.html diff --git a/testing/talos/talos/tests/layout/benchmarks/displaylist_inactive_mutate.html b/testing/talos/talos/tests/layout/benchmarks/displaylist_inactive_mutate.html new file mode 100644 index 000000000000..dd74a2617dc3 --- /dev/null +++ b/testing/talos/talos/tests/layout/benchmarks/displaylist_inactive_mutate.html @@ -0,0 +1,56 @@ + + + + + + + + + diff --git a/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html b/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html index b1668e402db6..22120c4bd8a2 100644 --- a/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html +++ b/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html @@ -37,9 +37,6 @@ function runFrame() { if (window.tpRecordTime) { window.tpRecordTime(end - start, start); } - if (parent.reportResults) { - parent.reportResults(end - start, start); - } return; } diff --git a/testing/talos/talos/tests/layout/displaylist_mutate.manifest b/testing/talos/talos/tests/layout/displaylist_mutate.manifest index 0e09c83d3d40..277ab4f259e6 100644 --- a/testing/talos/talos/tests/layout/displaylist_mutate.manifest +++ b/testing/talos/talos/tests/layout/displaylist_mutate.manifest @@ -1 +1,2 @@ % http://localhost/tests/layout/benchmarks/displaylist_mutate.html +% http://localhost/tests/layout/benchmarks/displaylist_inactive_mutate.html From 0c7ce1c5b6c05fea4ea1e4e399b88364c2a13e6e Mon Sep 17 00:00:00 2001 From: sotaro Date: Tue, 27 Feb 2018 12:10:22 +0900 Subject: [PATCH 29/31] Bug 1441056 - Get D3D11 device from EGLDisplay in RenderCompositorANGLE::Initialize() r=nical --- .../RenderCompositorANGLE.cpp | 30 +++++++++++++++++-- .../RenderCompositorANGLE.h | 1 + 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.cpp b/gfx/webrender_bindings/RenderCompositorANGLE.cpp index e20d7cab7c6a..3226f181033a 100644 --- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp +++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp @@ -45,10 +45,37 @@ RenderCompositorANGLE::~RenderCompositorANGLE() MOZ_ASSERT(!mEGLSurface); } +ID3D11Device* +RenderCompositorANGLE::GetDeviceOfEGLDisplay() +{ + const auto& egl = &gl::sEGLLibrary; + + // Fetch the D3D11 device. + EGLDeviceEXT eglDevice = nullptr; + egl->fQueryDisplayAttribEXT(egl->Display(), LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice); + MOZ_ASSERT(eglDevice); + ID3D11Device* device = nullptr; + egl->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, (EGLAttrib*)&device); + if (!device) { + gfxCriticalNote << "Failed to get D3D11Device from EGLDisplay"; + return false; + } + return device; +} + bool RenderCompositorANGLE::Initialize() { - mDevice = gfx::DeviceManagerDx::Get()->GetCompositorDevice(); + const auto& egl = &gl::sEGLLibrary; + + nsCString discardFailureId; + if (!egl->EnsureInitialized(/* forceAccel */ true, &discardFailureId)) { + gfxCriticalNote << "Failed to load EGL library: " << discardFailureId.get(); + return false; + } + + mDevice = GetDeviceOfEGLDisplay(); + if (!mDevice) { gfxCriticalNote << "[D3D11] failed to get compositor device."; return false; @@ -142,7 +169,6 @@ RenderCompositorANGLE::Initialize() // Create GLContext with dummy EGLSurface, the EGLSurface is not used. // Instread we override it with EGLSurface of SwapChain's back buffer. - nsCString discardFailureId; mGL = gl::GLContextProviderEGL::CreateHeadless(flags, &discardFailureId); if (!mGL || !mGL->IsANGLE()) { gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(mGL.get()); diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.h b/gfx/webrender_bindings/RenderCompositorANGLE.h index 880a81ecb2bc..0d811fc03958 100644 --- a/gfx/webrender_bindings/RenderCompositorANGLE.h +++ b/gfx/webrender_bindings/RenderCompositorANGLE.h @@ -44,6 +44,7 @@ protected: void WaitForPreviousPresentQuery(); bool ResizeBufferIfNeeded(); void DestroyEGLSurface(); + ID3D11Device* GetDeviceOfEGLDisplay(); RefPtr mGL; EGLConfig mEGLConfig; From 1d9b1a259f51e651cba61805f40809ea991bc200 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Mon, 26 Feb 2018 22:31:37 -0500 Subject: [PATCH 30/31] Bug 1441225 - Update Codemirror to 5.35.0. r=bgrins --- devtools/client/sourceeditor/README | 2 +- .../addon/search/match-highlighter.js | 2 +- .../codemirror/addon/search/searchcursor.js | 18 ++-- .../codemirror/codemirror.bundle.js | 93 ++++++++++++------- .../sourceeditor/codemirror/keymap/sublime.js | 10 +- .../sourceeditor/codemirror/keymap/vim.js | 31 +++++-- .../sourceeditor/codemirror/lib/codemirror.js | 13 ++- .../codemirror/mode/clike/clike.js | 14 +-- .../codemirror/mode/javascript/javascript.js | 7 +- .../test/codemirror/mode/javascript/test.js | 9 ++ .../sourceeditor/test/codemirror/test.js | 4 +- .../sourceeditor/test/codemirror/vim_test.js | 17 ++-- 12 files changed, 146 insertions(+), 74 deletions(-) diff --git a/devtools/client/sourceeditor/README b/devtools/client/sourceeditor/README index a49eb315fa97..85fe6417c4ba 100644 --- a/devtools/client/sourceeditor/README +++ b/devtools/client/sourceeditor/README @@ -5,7 +5,7 @@ code, and optionally help with indentation. # Upgrade -Currently used version is 5.34.0. To upgrade: download a new version of +Currently used version is 5.35.0. To upgrade: download a new version of CodeMirror from the project's page [1] and replace all JavaScript and CSS files inside the codemirror directory [2]. diff --git a/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js b/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js index 73ba0e053709..35221711790e 100644 --- a/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js +++ b/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js @@ -90,7 +90,7 @@ var state = cm.state.matchHighlighter; cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) { - var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query; + var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[+*?(){|^$]/g, "\\$&") + "\\b") : query; state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false, {className: "CodeMirror-selection-highlight-scrollbar"}); } diff --git a/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js b/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js index 58bc47c2c3e6..e606c5e7cf59 100644 --- a/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js +++ b/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js @@ -19,8 +19,11 @@ + (regexp.multiline ? "m" : "") } - function ensureGlobal(regexp) { - return regexp.global ? regexp : new RegExp(regexp.source, regexpFlags(regexp) + "g") + function ensureFlags(regexp, flags) { + var current = regexpFlags(regexp), target = current + for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1) + target += flags.charAt(i) + return current == target ? regexp : new RegExp(regexp.source, target) } function maybeMultiline(regexp) { @@ -28,7 +31,7 @@ } function searchRegexpForward(doc, regexp, start) { - regexp = ensureGlobal(regexp) + regexp = ensureFlags(regexp, "g") for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) { regexp.lastIndex = ch var string = doc.getLine(line), match = regexp.exec(string) @@ -42,7 +45,7 @@ function searchRegexpForwardMultiline(doc, regexp, start) { if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start) - regexp = ensureGlobal(regexp) + regexp = ensureFlags(regexp, "gm") var string, chunk = 1 for (var line = start.line, last = doc.lastLine(); line <= last;) { // This grows the search buffer in exponentially-sized chunks @@ -51,6 +54,7 @@ // searching for something that has tons of matches), but at the // same time, the amount of retries is limited. for (var i = 0; i < chunk; i++) { + if (line > last) break var curLine = doc.getLine(line++) string = string == null ? curLine : string + "\n" + curLine } @@ -81,7 +85,7 @@ } function searchRegexpBackward(doc, regexp, start) { - regexp = ensureGlobal(regexp) + regexp = ensureFlags(regexp, "g") for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { var string = doc.getLine(line) if (ch > -1) string = string.slice(0, ch) @@ -94,7 +98,7 @@ } function searchRegexpBackwardMultiline(doc, regexp, start) { - regexp = ensureGlobal(regexp) + regexp = ensureFlags(regexp, "gm") var string, chunk = 1 for (var line = start.line, first = doc.firstLine(); line >= first;) { for (var i = 0; i < chunk; i++) { @@ -213,7 +217,7 @@ return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold) } } else { - query = ensureGlobal(query) + query = ensureFlags(query, "gm") if (!options || options.multiline !== false) this.matches = function(reverse, pos) { return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos) diff --git a/devtools/client/sourceeditor/codemirror/codemirror.bundle.js b/devtools/client/sourceeditor/codemirror/codemirror.bundle.js index 0f81ea6dd2ce..83229e726b75 100644 --- a/devtools/client/sourceeditor/codemirror/codemirror.bundle.js +++ b/devtools/client/sourceeditor/codemirror/codemirror.bundle.js @@ -5454,7 +5454,8 @@ var CodeMirror = // Revert a change stored in a document's history. function makeChangeFromHistory(doc, type, allowSelectionOnly) { - if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return } + var suppress = doc.cm && doc.cm.state.suppressEdits + if (suppress && !allowSelectionOnly) { return } var hist = doc.history, event, selAfter = doc.sel var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done @@ -5479,8 +5480,10 @@ var CodeMirror = return } selAfter = event - } - else { break } + } else if (suppress) { + source.push(event) + return + } else { break } } // Build up a reverse change object to add to the opposite history @@ -5956,7 +5959,7 @@ var CodeMirror = } return true }) - signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) + if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) } return widget } @@ -9892,7 +9895,7 @@ var CodeMirror = addLegacyProps(CodeMirror) - CodeMirror.version = "5.34.0" + CodeMirror.version = "5.35.0" return CodeMirror; @@ -9923,8 +9926,11 @@ var CodeMirror = + (regexp.multiline ? "m" : "") } - function ensureGlobal(regexp) { - return regexp.global ? regexp : new RegExp(regexp.source, regexpFlags(regexp) + "g") + function ensureFlags(regexp, flags) { + var current = regexpFlags(regexp), target = current + for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1) + target += flags.charAt(i) + return current == target ? regexp : new RegExp(regexp.source, target) } function maybeMultiline(regexp) { @@ -9932,7 +9938,7 @@ var CodeMirror = } function searchRegexpForward(doc, regexp, start) { - regexp = ensureGlobal(regexp) + regexp = ensureFlags(regexp, "g") for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) { regexp.lastIndex = ch var string = doc.getLine(line), match = regexp.exec(string) @@ -9946,7 +9952,7 @@ var CodeMirror = function searchRegexpForwardMultiline(doc, regexp, start) { if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start) - regexp = ensureGlobal(regexp) + regexp = ensureFlags(regexp, "gm") var string, chunk = 1 for (var line = start.line, last = doc.lastLine(); line <= last;) { // This grows the search buffer in exponentially-sized chunks @@ -9955,6 +9961,7 @@ var CodeMirror = // searching for something that has tons of matches), but at the // same time, the amount of retries is limited. for (var i = 0; i < chunk; i++) { + if (line > last) break var curLine = doc.getLine(line++) string = string == null ? curLine : string + "\n" + curLine } @@ -9985,7 +9992,7 @@ var CodeMirror = } function searchRegexpBackward(doc, regexp, start) { - regexp = ensureGlobal(regexp) + regexp = ensureFlags(regexp, "g") for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { var string = doc.getLine(line) if (ch > -1) string = string.slice(0, ch) @@ -9998,7 +10005,7 @@ var CodeMirror = } function searchRegexpBackwardMultiline(doc, regexp, start) { - regexp = ensureGlobal(regexp) + regexp = ensureFlags(regexp, "gm") var string, chunk = 1 for (var line = start.line, first = doc.firstLine(); line >= first;) { for (var i = 0; i < chunk; i++) { @@ -10117,7 +10124,7 @@ var CodeMirror = return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold) } } else { - query = ensureGlobal(query) + query = ensureFlags(query, "gm") if (!options || options.multiline !== false) this.matches = function(reverse, pos) { return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos) @@ -11438,6 +11445,7 @@ var CodeMirror = if (type == "{") return contCommasep(objprop, "}", null, maybeop); if (type == "quasi") return pass(quasi, maybeop); if (type == "new") return cont(maybeTarget(noComma)); + if (type == "import") return cont(expression); return cont(); } function maybeexpression(type) { @@ -11632,7 +11640,7 @@ var CodeMirror = } function afterType(type, value) { if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) - if (value == "|" || type == ".") return cont(typeexpr) + if (value == "|" || type == "." || value == "&") return cont(typeexpr) if (type == "[") return cont(expect("]"), afterType) if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) } } @@ -11675,7 +11683,8 @@ var CodeMirror = function maybeelse(type, value) { if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); } - function forspec(type) { + function forspec(type, value) { + if (value == "await") return cont(forspec); if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); } function forspec1(type) { @@ -11764,6 +11773,7 @@ var CodeMirror = } function afterImport(type) { if (type == "string") return cont(); + if (type == "(") return pass(expression); return pass(importSpec, maybeMoreImports, maybeFrom); } function importSpec(type, value) { @@ -14416,7 +14426,7 @@ var CodeMirror = blockKeywords: words("case do else for if switch while struct"), defKeywords: words("struct"), typeFirstDefinitions: true, - atoms: words("null true false"), + atoms: words("NULL true false"), hooks: {"#": cppHook, "*": pointerHook}, modeProps: {fold: ["brace", "include"]} }); @@ -14432,7 +14442,7 @@ var CodeMirror = blockKeywords: words("catch class do else finally for if struct switch try while"), defKeywords: words("class namespace struct enum union"), typeFirstDefinitions: true, - atoms: words("true false null"), + atoms: words("true false NULL"), dontIndentStatements: /^template$/, isIdentifierChar: /[\w\$_~\xa1-\uffff]/, hooks: { @@ -14639,22 +14649,24 @@ var CodeMirror = name: "clike", keywords: words( /*keywords*/ - "package as typealias class interface this super val " + - "var fun for is in This throw return " + + "package as typealias class interface this super val operator " + + "var fun for is in This throw return annotation " + "break continue object if else while do try when !in !is as? " + /*soft keywords*/ "file import where by get set abstract enum open inner override private public internal " + "protected catch finally out final vararg reified dynamic companion constructor init " + "sealed field property receiver param sparam lateinit data inline noinline tailrec " + - "external annotation crossinline const operator infix suspend actual expect" + "external annotation crossinline const operator infix suspend actual expect setparam" ), types: words( /* package java.lang */ "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + - "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" + "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " + + "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " + + "LazyThreadSafetyMode LongArray Nothing ShortArray Unit" ), intendSwitch: false, indentStatements: false, @@ -16448,7 +16460,7 @@ var CodeMirror = } function handleKeyNonInsertMode() { - if (handleMacroRecording() || handleEsc()) { return true; }; + if (handleMacroRecording() || handleEsc()) { return true; } var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key; if (/^[1-9]\d*$/.test(keys)) { return true; } @@ -17033,7 +17045,7 @@ var CodeMirror = } else { if (vim.visualMode) { showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>', - onKeyDown: onPromptKeyDown}); + onKeyDown: onPromptKeyDown, selectValueOnOpen: false}); } else { showPrompt(cm, { onClose: onPromptClose, prefix: ':', onKeyDown: onPromptKeyDown}); @@ -19290,7 +19302,15 @@ var CodeMirror = } } function splitBySlash(argString) { - var slashes = findUnescapedSlashes(argString) || []; + return splitBySeparator(argString, '/'); + } + + function findUnescapedSlashes(argString) { + return findUnescapedSeparators(argString, '/'); + } + + function splitBySeparator(argString, separator) { + var slashes = findUnescapedSeparators(argString, separator) || []; if (!slashes.length) return []; var tokens = []; // in case of strings like foo/bar @@ -19302,12 +19322,15 @@ var CodeMirror = return tokens; } - function findUnescapedSlashes(str) { + function findUnescapedSeparators(str, separator) { + if (!separator) + separator = '/'; + var escapeNextChar = false; var slashes = []; for (var i = 0; i < str.length; i++) { var c = str.charAt(i); - if (!escapeNextChar && c == '/') { + if (!escapeNextChar && c == separator) { slashes.push(i); } escapeNextChar = !escapeNextChar && (c == '\\'); @@ -20173,7 +20196,7 @@ var CodeMirror = 'any other getSearchCursor implementation.'); } var argString = params.argString; - var tokens = argString ? splitBySlash(argString) : []; + var tokens = argString ? splitBySeparator(argString, argString[0]) : []; var regexPart, replacePart = '', trailing, flagsPart, count; var confirm = false; // Whether to confirm each replace. var global = false; // True to replace all instances on a line, false to replace only 1. @@ -20217,7 +20240,7 @@ var CodeMirror = global = true; flagsPart.replace('g', ''); } - regexPart = regexPart + '/' + flagsPart; + regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart; } } if (regexPart) { @@ -20433,7 +20456,7 @@ var CodeMirror = } if (!confirm) { replaceAll(); - if (callback) { callback(); }; + if (callback) { callback(); } return; } showPrompt(cm, { @@ -20569,7 +20592,7 @@ var CodeMirror = exitInsertMode(cm); } } - }; + } macroModeState.isPlaying = false; } @@ -20773,7 +20796,7 @@ var CodeMirror = exitInsertMode(cm); } macroModeState.isPlaying = false; - }; + } function repeatInsertModeChanges(cm, changes, repeat) { function keyHandler(binding) { @@ -20988,8 +21011,14 @@ var CodeMirror = var ranges = cm.listSelections(), newRanges = []; for (var i = 0; i < ranges.length; i++) { var range = ranges[i]; - var newAnchor = cm.findPosV(range.anchor, dir, "line"); - var newHead = cm.findPosV(range.head, dir, "line"); + var newAnchor = cm.findPosV( + range.anchor, dir, "line", range.anchor.goalColumn); + var newHead = cm.findPosV( + range.head, dir, "line", range.head.goalColumn); + newAnchor.goalColumn = range.anchor.goalColumn != null ? + range.anchor.goalColumn : cm.cursorCoords(range.anchor, "div").left; + newHead.goalColumn = range.head.goalColumn != null ? + range.head.goalColumn : cm.cursorCoords(range.head, "div").left; var newRange = {anchor: newAnchor, head: newHead}; newRanges.push(range); newRanges.push(newRange); diff --git a/devtools/client/sourceeditor/codemirror/keymap/sublime.js b/devtools/client/sourceeditor/codemirror/keymap/sublime.js index 7a9aadd33097..aa9b65e3b16d 100644 --- a/devtools/client/sourceeditor/codemirror/keymap/sublime.js +++ b/devtools/client/sourceeditor/codemirror/keymap/sublime.js @@ -156,8 +156,14 @@ var ranges = cm.listSelections(), newRanges = []; for (var i = 0; i < ranges.length; i++) { var range = ranges[i]; - var newAnchor = cm.findPosV(range.anchor, dir, "line"); - var newHead = cm.findPosV(range.head, dir, "line"); + var newAnchor = cm.findPosV( + range.anchor, dir, "line", range.anchor.goalColumn); + var newHead = cm.findPosV( + range.head, dir, "line", range.head.goalColumn); + newAnchor.goalColumn = range.anchor.goalColumn != null ? + range.anchor.goalColumn : cm.cursorCoords(range.anchor, "div").left; + newHead.goalColumn = range.head.goalColumn != null ? + range.head.goalColumn : cm.cursorCoords(range.head, "div").left; var newRange = {anchor: newAnchor, head: newHead}; newRanges.push(range); newRanges.push(newRange); diff --git a/devtools/client/sourceeditor/codemirror/keymap/vim.js b/devtools/client/sourceeditor/codemirror/keymap/vim.js index b08226818372..529654a3b538 100644 --- a/devtools/client/sourceeditor/codemirror/keymap/vim.js +++ b/devtools/client/sourceeditor/codemirror/keymap/vim.js @@ -841,7 +841,7 @@ } function handleKeyNonInsertMode() { - if (handleMacroRecording() || handleEsc()) { return true; }; + if (handleMacroRecording() || handleEsc()) { return true; } var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key; if (/^[1-9]\d*$/.test(keys)) { return true; } @@ -1426,7 +1426,7 @@ } else { if (vim.visualMode) { showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>', - onKeyDown: onPromptKeyDown}); + onKeyDown: onPromptKeyDown, selectValueOnOpen: false}); } else { showPrompt(cm, { onClose: onPromptClose, prefix: ':', onKeyDown: onPromptKeyDown}); @@ -3683,7 +3683,15 @@ } } function splitBySlash(argString) { - var slashes = findUnescapedSlashes(argString) || []; + return splitBySeparator(argString, '/'); + } + + function findUnescapedSlashes(argString) { + return findUnescapedSeparators(argString, '/'); + } + + function splitBySeparator(argString, separator) { + var slashes = findUnescapedSeparators(argString, separator) || []; if (!slashes.length) return []; var tokens = []; // in case of strings like foo/bar @@ -3695,12 +3703,15 @@ return tokens; } - function findUnescapedSlashes(str) { + function findUnescapedSeparators(str, separator) { + if (!separator) + separator = '/'; + var escapeNextChar = false; var slashes = []; for (var i = 0; i < str.length; i++) { var c = str.charAt(i); - if (!escapeNextChar && c == '/') { + if (!escapeNextChar && c == separator) { slashes.push(i); } escapeNextChar = !escapeNextChar && (c == '\\'); @@ -4566,7 +4577,7 @@ 'any other getSearchCursor implementation.'); } var argString = params.argString; - var tokens = argString ? splitBySlash(argString) : []; + var tokens = argString ? splitBySeparator(argString, argString[0]) : []; var regexPart, replacePart = '', trailing, flagsPart, count; var confirm = false; // Whether to confirm each replace. var global = false; // True to replace all instances on a line, false to replace only 1. @@ -4610,7 +4621,7 @@ global = true; flagsPart.replace('g', ''); } - regexPart = regexPart + '/' + flagsPart; + regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart; } } if (regexPart) { @@ -4826,7 +4837,7 @@ } if (!confirm) { replaceAll(); - if (callback) { callback(); }; + if (callback) { callback(); } return; } showPrompt(cm, { @@ -4962,7 +4973,7 @@ exitInsertMode(cm); } } - }; + } macroModeState.isPlaying = false; } @@ -5166,7 +5177,7 @@ exitInsertMode(cm); } macroModeState.isPlaying = false; - }; + } function repeatInsertModeChanges(cm, changes, repeat) { function keyHandler(binding) { diff --git a/devtools/client/sourceeditor/codemirror/lib/codemirror.js b/devtools/client/sourceeditor/codemirror/lib/codemirror.js index f22567442124..e942fe63728b 100644 --- a/devtools/client/sourceeditor/codemirror/lib/codemirror.js +++ b/devtools/client/sourceeditor/codemirror/lib/codemirror.js @@ -5212,7 +5212,8 @@ function makeChangeInner(doc, change) { // Revert a change stored in a document's history. function makeChangeFromHistory(doc, type, allowSelectionOnly) { - if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return } + var suppress = doc.cm && doc.cm.state.suppressEdits + if (suppress && !allowSelectionOnly) { return } var hist = doc.history, event, selAfter = doc.sel var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done @@ -5237,8 +5238,10 @@ function makeChangeFromHistory(doc, type, allowSelectionOnly) { return } selAfter = event - } - else { break } + } else if (suppress) { + source.push(event) + return + } else { break } } // Build up a reverse change object to add to the opposite history @@ -5714,7 +5717,7 @@ function addLineWidget(doc, handle, node, options) { } return true }) - signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) + if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) } return widget } @@ -9650,7 +9653,7 @@ CodeMirror.fromTextArea = fromTextArea addLegacyProps(CodeMirror) -CodeMirror.version = "5.34.0" +CodeMirror.version = "5.35.0" return CodeMirror; diff --git a/devtools/client/sourceeditor/codemirror/mode/clike/clike.js b/devtools/client/sourceeditor/codemirror/mode/clike/clike.js index b89ddf0d59bf..da7a6bf5b669 100644 --- a/devtools/client/sourceeditor/codemirror/mode/clike/clike.js +++ b/devtools/client/sourceeditor/codemirror/mode/clike/clike.js @@ -374,7 +374,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { blockKeywords: words("case do else for if switch while struct"), defKeywords: words("struct"), typeFirstDefinitions: true, - atoms: words("null true false"), + atoms: words("NULL true false"), hooks: {"#": cppHook, "*": pointerHook}, modeProps: {fold: ["brace", "include"]} }); @@ -390,7 +390,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { blockKeywords: words("catch class do else finally for if struct switch try while"), defKeywords: words("class namespace struct enum union"), typeFirstDefinitions: true, - atoms: words("true false null"), + atoms: words("true false NULL"), dontIndentStatements: /^template$/, isIdentifierChar: /[\w\$_~\xa1-\uffff]/, hooks: { @@ -597,22 +597,24 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { name: "clike", keywords: words( /*keywords*/ - "package as typealias class interface this super val " + - "var fun for is in This throw return " + + "package as typealias class interface this super val operator " + + "var fun for is in This throw return annotation " + "break continue object if else while do try when !in !is as? " + /*soft keywords*/ "file import where by get set abstract enum open inner override private public internal " + "protected catch finally out final vararg reified dynamic companion constructor init " + "sealed field property receiver param sparam lateinit data inline noinline tailrec " + - "external annotation crossinline const operator infix suspend actual expect" + "external annotation crossinline const operator infix suspend actual expect setparam" ), types: words( /* package java.lang */ "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + - "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" + "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " + + "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " + + "LazyThreadSafetyMode LongArray Nothing ShortArray Unit" ), intendSwitch: false, indentStatements: false, diff --git a/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js b/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js index 9eb50ba974e8..52da9e23532a 100644 --- a/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js +++ b/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js @@ -400,6 +400,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "{") return contCommasep(objprop, "}", null, maybeop); if (type == "quasi") return pass(quasi, maybeop); if (type == "new") return cont(maybeTarget(noComma)); + if (type == "import") return cont(expression); return cont(); } function maybeexpression(type) { @@ -594,7 +595,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function afterType(type, value) { if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) - if (value == "|" || type == ".") return cont(typeexpr) + if (value == "|" || type == "." || value == "&") return cont(typeexpr) if (type == "[") return cont(expect("]"), afterType) if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) } } @@ -637,7 +638,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function maybeelse(type, value) { if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); } - function forspec(type) { + function forspec(type, value) { + if (value == "await") return cont(forspec); if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); } function forspec1(type) { @@ -726,6 +728,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function afterImport(type) { if (type == "string") return cont(); + if (type == "(") return pass(expression); return pass(importSpec, maybeMoreImports, maybeFrom); } function importSpec(type, value) { diff --git a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js index 14a5183cab41..f770bd77f6b1 100644 --- a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js +++ b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js @@ -63,6 +63,12 @@ MT("import_trailing_comma", "[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']") + MT("import_dynamic", + "[keyword import]([string 'baz']).[property then]") + + MT("import_dynamic", + "[keyword const] [def t] [operator =] [keyword import]([string 'baz']).[property then]") + MT("const", "[keyword function] [def f]() {", " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];", @@ -71,6 +77,9 @@ MT("for/of", "[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}"); + MT("for await", + "[keyword for] [keyword await]([keyword let] [def of] [keyword of] [variable something]) {}"); + MT("generator", "[keyword function*] [def repeat]([def n]) {", " [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])", diff --git a/devtools/client/sourceeditor/test/codemirror/test.js b/devtools/client/sourceeditor/test/codemirror/test.js index 87615d06300b..415dd9f0bc5d 100644 --- a/devtools/client/sourceeditor/test/codemirror/test.js +++ b/devtools/client/sourceeditor/test/codemirror/test.js @@ -2330,7 +2330,7 @@ testCM("lineSeparator", function(cm) { lineSeparator: "\n"}); var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/ -var getChar = function (noExtending) { var res; do {res = String.fromCharCode(Math.floor(Math.random()*0x8ac)); } while ([0x90].includes(res.charCodeAt(0)) || (noExtending && extendingChars.test(res))); return res } +var getChar = function (noExtending) { var res; do {res = String.fromCharCode(Math.floor(Math.random()*0x8ac)); } while ([0x90].indexOf(res.charCodeAt(0)) != -1 || (noExtending && extendingChars.test(res))); return res } var getString = function (n) { var res = getChar(true); while (--n > 0) res += getChar(); return res } function makeItWrapAfter(cm, pos) { @@ -2356,7 +2356,7 @@ function testMoveBidi(str) { var steps = str.length - countIf(str.split(""), function(ch) { return extendingChars.test(ch) }); var lineBreaks = {} lineBreaks[6 - countIf(str.substr(0, 5).split(""), function(ch) { return extendingChars.test(ch) })] = 'w'; - if (str.includes("\n")) { + if (str.indexOf("\n") != -1) { lineBreaks[steps - 2] = 'n'; } diff --git a/devtools/client/sourceeditor/test/codemirror/vim_test.js b/devtools/client/sourceeditor/test/codemirror/vim_test.js index e5bf1f208135..6433134c21d6 100644 --- a/devtools/client/sourceeditor/test/codemirror/vim_test.js +++ b/devtools/client/sourceeditor/test/codemirror/vim_test.js @@ -153,7 +153,7 @@ function testVim(name, run, opts, expectedFail) { // Record for insert mode. if (handled == "handled" && cm.state.vim.insertMode && arguments[i] != 'Esc') { var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges; - if (lastChange && (key.includes('Delete') || key.includes('Backspace'))) { + if (lastChange && (key.indexOf('Delete') != -1 || key.indexOf('Backspace') != -1)) { lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key)); } } @@ -255,7 +255,7 @@ function testJumplist(name, keys, endPos, startPos, dialog) { helpers.doKeys.apply(null, keys); helpers.assertCursorAt(endPos); }, {value: jumplistScene}); -}; +} testJumplist('jumplist_H', ['H', ''], [5,2], [5,2]); testJumplist('jumplist_M', ['M', ''], [2,2], [2,2]); testJumplist('jumplist_L', ['L', ''], [2,2], [2,2]); @@ -299,15 +299,15 @@ function testMotion(name, keys, endPos, startPos) { helpers.doKeys(keys); helpers.assertCursorAt(endPos); }); -}; +} function makeCursor(line, ch) { return new Pos(line, ch); -}; +} function offsetCursor(cur, offsetLine, offsetCh) { return new Pos(cur.line + offsetLine, cur.ch + offsetCh); -}; +} // Motion tests testMotion('|', '|', makeCursor(0, 0), makeCursor(0,4)); @@ -3648,6 +3648,11 @@ testVim('ex_substitute_same_line', function(cm, vim, helpers) { helpers.doEx('s/one/two/g'); eq('one one\n two two', cm.getValue()); }, { value: 'one one\n one one'}); +testVim('ex_substitute_alternate_separator', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('s#o/e#two#g'); + eq('o/e o/e\n two two', cm.getValue()); +}, { value: 'o/e o/e\n o/e o/e'}); testVim('ex_substitute_full_file', function(cm, vim, helpers) { cm.setCursor(1, 0); helpers.doEx('%s/one/two/g'); @@ -3904,7 +3909,7 @@ function testSubstituteConfirm(name, command, initialValue, expectedValue, keys, cm.openDialog = savedOpenDialog; } }, { value: initialValue }); -}; +} testSubstituteConfirm('ex_substitute_confirm_emptydoc', '%s/x/b/c', '', '', '', makeCursor(0, 0)); testSubstituteConfirm('ex_substitute_confirm_nomatch', From c24507a6c0a2fb3cbfbba8079241d712a125fce3 Mon Sep 17 00:00:00 2001 From: sotaro Date: Tue, 27 Feb 2018 13:06:03 +0900 Subject: [PATCH 31/31] Bug 1441056 - backout because of build failure on MinGW --- .../RenderCompositorANGLE.cpp | 30 ++----------------- .../RenderCompositorANGLE.h | 1 - 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.cpp b/gfx/webrender_bindings/RenderCompositorANGLE.cpp index 3226f181033a..e20d7cab7c6a 100644 --- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp +++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp @@ -45,37 +45,10 @@ RenderCompositorANGLE::~RenderCompositorANGLE() MOZ_ASSERT(!mEGLSurface); } -ID3D11Device* -RenderCompositorANGLE::GetDeviceOfEGLDisplay() -{ - const auto& egl = &gl::sEGLLibrary; - - // Fetch the D3D11 device. - EGLDeviceEXT eglDevice = nullptr; - egl->fQueryDisplayAttribEXT(egl->Display(), LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice); - MOZ_ASSERT(eglDevice); - ID3D11Device* device = nullptr; - egl->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, (EGLAttrib*)&device); - if (!device) { - gfxCriticalNote << "Failed to get D3D11Device from EGLDisplay"; - return false; - } - return device; -} - bool RenderCompositorANGLE::Initialize() { - const auto& egl = &gl::sEGLLibrary; - - nsCString discardFailureId; - if (!egl->EnsureInitialized(/* forceAccel */ true, &discardFailureId)) { - gfxCriticalNote << "Failed to load EGL library: " << discardFailureId.get(); - return false; - } - - mDevice = GetDeviceOfEGLDisplay(); - + mDevice = gfx::DeviceManagerDx::Get()->GetCompositorDevice(); if (!mDevice) { gfxCriticalNote << "[D3D11] failed to get compositor device."; return false; @@ -169,6 +142,7 @@ RenderCompositorANGLE::Initialize() // Create GLContext with dummy EGLSurface, the EGLSurface is not used. // Instread we override it with EGLSurface of SwapChain's back buffer. + nsCString discardFailureId; mGL = gl::GLContextProviderEGL::CreateHeadless(flags, &discardFailureId); if (!mGL || !mGL->IsANGLE()) { gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(mGL.get()); diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.h b/gfx/webrender_bindings/RenderCompositorANGLE.h index 0d811fc03958..880a81ecb2bc 100644 --- a/gfx/webrender_bindings/RenderCompositorANGLE.h +++ b/gfx/webrender_bindings/RenderCompositorANGLE.h @@ -44,7 +44,6 @@ protected: void WaitForPreviousPresentQuery(); bool ResizeBufferIfNeeded(); void DestroyEGLSurface(); - ID3D11Device* GetDeviceOfEGLDisplay(); RefPtr mGL; EGLConfig mEGLConfig;