зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
8f11c1f438
|
@ -0,0 +1,3 @@
|
|||
. "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
|
||||
|
||||
ac_add_options --enable-stylo=only
|
|
@ -0,0 +1,3 @@
|
|||
. "$topsrcdir/browser/config/mozconfigs/linux64/debug"
|
||||
|
||||
ac_add_options --enable-stylo=only
|
|
@ -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
|
||||
|
|
@ -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-XinY.mk>
|
||||
|
||||
|
||||
###########################################################################
|
||||
## 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-arglist.mk>
|
||||
|
||||
|
||||
###########################################################################
|
||||
# <CHECK: autotargets.mk>
|
||||
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) $@
|
||||
# </CHECK: autotargets.mk>
|
||||
|
||||
endif #} findstring MAKECMDGOAL
|
|
@ -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
|
|
@ -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
|
|
@ -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)))
|
||||
|
|
@ -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/.
|
||||
|
|
@ -16,7 +16,6 @@ DIST_INSTALL = False
|
|||
NoVisibilityFlags()
|
||||
|
||||
CONFIGURE_SUBST_FILES += [
|
||||
'makefiles/test/Makefile',
|
||||
'tests/src-simple/Makefile',
|
||||
]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <http://mozilla.org/MPL/2.0/>. */
|
||||
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 <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
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 <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
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 <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
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 <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
});
|
|
@ -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 <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
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 <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
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 <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
});
|
|
@ -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]
|
||||
|
|
|
@ -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 }],
|
||||
]
|
||||
);
|
||||
});
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
|
|
|
@ -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].
|
||||
|
||||
|
|
|
@ -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"});
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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])",
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
|
||||
|
|
|
@ -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', '<C-o>'], [5,2], [5,2]);
|
||||
testJumplist('jumplist_M', ['M', '<C-o>'], [2,2], [2,2]);
|
||||
testJumplist('jumplist_L', ['L', '<C-o>'], [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',
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -108,27 +108,25 @@ NS_NewXULPrototypeDocument(nsXULPrototypeDocument** aResult)
|
|||
NS_IMETHODIMP
|
||||
nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupports> 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<nsIURI> 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<nsIPrincipal> 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<nsIPrincipal> principal = do_QueryInterface(supports);
|
||||
// Better safe than sorry....
|
||||
mNodeInfoManager->SetDocumentPrincipal(principal);
|
||||
|
||||
|
@ -150,45 +147,45 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
|
|||
// mozilla::dom::NodeInfo table
|
||||
nsTArray<RefPtr<mozilla::dom::NodeInfo>> 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<nsAtom> 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<mozilla::dom::NodeInfo> 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<nsXULPrototypePI> 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
|
||||
|
|
|
@ -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.
|
||||
* <https://html.spec.whatwg.org/multipage/structured-data.html>
|
||||
*
|
||||
* 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 <https://developer.mozilla.org/en-US/docs/Web/API/Transferable>.
|
||||
* 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.
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(","));
|
||||
}
|
|
@ -6,48 +6,25 @@
|
|||
// 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]);
|
||||
[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
|
||||
// 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]);
|
||||
[1, 2, 3, 8, 9, 10]);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -14236,6 +14236,9 @@ class MWasmBoundsCheck
|
|||
{
|
||||
// Bounds check is effectful: it throws for OOB.
|
||||
setGuard();
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
setResultType(MIRType::Int32);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -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 <class L>
|
||||
inline void wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
|
||||
DEFINED_ON(arm, arm64, mips32, mips64, x86);
|
||||
|
|
|
@ -15,6 +15,8 @@ using namespace mozilla;
|
|||
typedef js::HashMap<uint32_t, MDefinition*, DefaultHasher<uint32_t>, 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;
|
||||
|
|
|
@ -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 <class L>
|
||||
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <class L>
|
||||
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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_t> size = mozilla::CheckedInt<size_t>(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 <typename CharT>
|
||||
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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -184,7 +184,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)
|
||||
|
@ -195,6 +196,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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -326,8 +326,9 @@ static ArenaAllocator<8192, 1> gPrefNameArena;
|
|||
class Pref
|
||||
{
|
||||
public:
|
||||
explicit Pref()
|
||||
: mType(static_cast<uint32_t>(PrefType::None))
|
||||
explicit Pref(const char* aName)
|
||||
: mName(ArenaStrdup(aName, gPrefNameArena))
|
||||
, mType(static_cast<uint32_t>(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<PrefType>(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<const PrefEntry*>(aEntry);
|
||||
auto prefName = static_cast<const char*>(aKey);
|
||||
|
||||
return entry->mPref->MatchEntry(prefName);
|
||||
}
|
||||
|
||||
static void InitEntry(PLDHashEntryHdr* aEntry, const void* aKey)
|
||||
{
|
||||
auto entry = static_cast<PrefEntry*>(aEntry);
|
||||
auto prefName = static_cast<const char*>(aKey);
|
||||
|
||||
entry->mPref = new Pref(prefName);
|
||||
}
|
||||
|
||||
static void ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
||||
{
|
||||
auto entry = static_cast<PrefEntry*>(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<StringArenaHashKey, Pref>;
|
||||
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<PrefEntry*>(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<PrefEntry*>(gHashTable->Search(aPrefName));
|
||||
}
|
||||
|
||||
static Pref*
|
||||
pref_HashTableLookup(const char* aPrefName)
|
||||
{
|
||||
PrefsTable::LookupResult entry = pref_HashTableLookupInner(aPrefName);
|
||||
return entry ? static_cast<Pref*>(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<PrefEntry*>(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<PrefEntry*>(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<PrefEntry*>(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<PrefEntry*>(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<nsCStringHashKey, TelemetryLoadData>();
|
||||
|
@ -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<const char*> prefNames;
|
||||
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
Pref* pref = iter.Data();
|
||||
Pref* pref = static_cast<PrefEntry*>(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<PrefEntry*>(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<dom::Pref>* 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<PrefEntry*>(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<dom::Pref>* 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);
|
||||
|
|
|
@ -6012,3 +6012,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);
|
||||
|
|
|
@ -12,6 +12,7 @@ transforms:
|
|||
|
||||
kind-dependencies:
|
||||
- release-generate-checksums
|
||||
- release-update-verify
|
||||
|
||||
job-defaults:
|
||||
worker-type:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
<http://marionette-client.readthedocs.io>, 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.
|
||||
|
|
|
@ -1,75 +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:
|
||||
|
||||
* clearElement
|
||||
* getText
|
||||
* isDisplayed
|
||||
* isEnabled
|
||||
* isSelected
|
||||
- `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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div {
|
||||
transform: translate(1px);
|
||||
width:10px;
|
||||
height:10px;
|
||||
background-color:green;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body id="body">
|
||||
</body>
|
||||
<script>
|
||||
|
||||
var start = null;
|
||||
var divCount = 1000;
|
||||
var maxIterations = 600;
|
||||
|
||||
for (var i = 0; i < divCount; i++) {
|
||||
var div = document.createElement("div");
|
||||
div.id = i;
|
||||
document.getElementById("body").appendChild(div);
|
||||
}
|
||||
|
||||
var iteration = 0;
|
||||
function runFrame() {
|
||||
if (document.getElementById(iteration).style.backgroundColor == "red") {
|
||||
document.getElementById(iteration).style.backgroundColor = "green";
|
||||
} else {
|
||||
document.getElementById(iteration).style.backgroundColor = "red";
|
||||
}
|
||||
iteration++;
|
||||
iteration = iteration % divCount;
|
||||
if (--maxIterations == 0) {
|
||||
var end = performance.now();
|
||||
if (window.tpRecordTime) {
|
||||
window.tpRecordTime(end - start, start);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(runFrame);
|
||||
}
|
||||
|
||||
addEventListener("load", function() {
|
||||
TalosContentProfiler.resume("displaylist_inactive_mutate.html loaded", true).then(() => {
|
||||
start = performance.now();
|
||||
window.requestAnimationFrame(runFrame);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<script type="text/javascript" src="chrome://talos-powers-content/content/TalosContentProfiler.js"></script>
|
||||
</html>
|
|
@ -37,9 +37,6 @@ function runFrame() {
|
|||
if (window.tpRecordTime) {
|
||||
window.tpRecordTime(end - start, start);
|
||||
}
|
||||
if (parent.reportResults) {
|
||||
parent.reportResults(end - start, start);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
% http://localhost/tests/layout/benchmarks/displaylist_mutate.html
|
||||
% http://localhost/tests/layout/benchmarks/displaylist_inactive_mutate.html
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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<nsURILoader> 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<nsDocumentOpenInfo> loader =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче