Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2019-07-22 20:08:59 +08:00
commit 5fda7c378f
282 changed files with 8990 additions and 3961 deletions

View file

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Clobber for ICU update
Clobber for SpiderMonkey Update

View file

@ -75,22 +75,22 @@ MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_A
.PHONY: repackage
tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME)
$(MKDIR) -p $(dist_dest)/Contents/MacOS
$(MKDIR) -p $(dist_dest)/$(LPROJ)
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/$(LPROJ)
sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/$(LPROJ)/InfoPlist.strings
rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(dist_dest)/Contents/Resources
rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(dist_dest)/Contents/MacOS
$(RM) $(dist_dest)/Contents/MacOS/$(MOZ_APP_NAME)
rsync -aL $(DIST)/bin/$(MOZ_APP_NAME) $(dist_dest)/Contents/MacOS
cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns
cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns
$(MKDIR) -p '$(dist_dest)/Contents/MacOS'
$(MKDIR) -p '$(dist_dest)/$(LPROJ)'
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents '$(dist_dest)' --exclude English.lproj
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ '$(dist_dest)/$(LPROJ)'
sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > '$(dist_dest)/Contents/Info.plist'
sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > '$(dist_dest)/$(LPROJ)/InfoPlist.strings'
rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ '$(dist_dest)/Contents/Resources'
rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ '$(dist_dest)/Contents/MacOS'
$(RM) '$(dist_dest)/Contents/MacOS/$(MOZ_APP_NAME)'
rsync -aL $(DIST)/bin/$(MOZ_APP_NAME) '$(dist_dest)/Contents/MacOS'
cp -RL $(DIST)/branding/firefox.icns '$(dist_dest)/Contents/Resources/firefox.icns'
cp -RL $(DIST)/branding/document.icns '$(dist_dest)/Contents/Resources/document.icns'
ifdef MOZ_UPDATER
$(MKDIR) -p $(dist_dest)/Contents/Library/LaunchServices
mv -f $(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater $(dist_dest)/Contents/Library/LaunchServices
ln -s ../../../../Library/LaunchServices/org.mozilla.updater $(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater
$(MKDIR) -p '$(dist_dest)/Contents/Library/LaunchServices'
mv -f '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater' '$(dist_dest)/Contents/Library/LaunchServices'
ln -s ../../../../Library/LaunchServices/org.mozilla.updater '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater'
endif
printf APPLMOZB > $(dist_dest)/Contents/PkgInfo
printf APPLMOZB > '$(dist_dest)/Contents/PkgInfo'
endif

View file

@ -102,19 +102,19 @@ include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
ifeq (bundle, $(MOZ_FS_LAYOUT))
BINPATH = $(_BINPATH)
DEFINES += -DAPPNAME=$(_APPNAME)
DEFINES += -DAPPNAME='$(_APPNAME)'
else
# Every other platform just winds up in dist/bin
BINPATH = bin
endif
DEFINES += -DBINPATH=$(BINPATH)
DEFINES += -DBINPATH='$(BINPATH)'
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
RESPATH = $(_APPNAME)/Contents/Resources
else
RESPATH = $(BINPATH)
endif
DEFINES += -DRESPATH=$(RESPATH)
DEFINES += -DRESPATH='$(RESPATH)'
LPROJ_ROOT = $(firstword $(subst -, ,$(AB_CD)))
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
@ -167,7 +167,7 @@ FINDPATH=bin
endif
package-compare::
cd $(DIST); find $(PKGCOMP_FIND_OPTS) $(FINDPATH) -type f | sort > bin-list.txt
cd $(DIST); find $(PKGCOMP_FIND_OPTS) '$(FINDPATH)' -type f | sort > bin-list.txt
$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $(MOZ_PKG_MANIFEST)) | grep '^$(BINPATH)' | sed -e 's/^\///' | sort > $(DIST)/pack-list.txt
-diff -u $(DIST)/pack-list.txt $(DIST)/bin-list.txt
rm -f $(DIST)/pack-list.txt $(DIST)/bin-list.txt

View file

@ -183,6 +183,7 @@
@RESPATH@/components/dom.xpt
@RESPATH@/components/dom_apps.xpt
@RESPATH@/components/dom_base.xpt
@RESPATH@/components/dom_bindings.xpt
@RESPATH@/components/dom_system.xpt
@RESPATH@/components/dom_canvas.xpt
@RESPATH@/components/dom_core.xpt

View file

@ -170,10 +170,10 @@ endif
ident:
@printf 'fx_revision '
@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \
$(STAGEDIST)/application.ini App SourceStamp
'$(STAGEDIST)'/application.ini App SourceStamp
@printf 'buildid '
@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \
$(STAGEDIST)/application.ini App BuildID
'$(STAGEDIST)'/application.ini App BuildID
merge-%:
ifdef LOCALE_MERGEDIR

View file

@ -80,26 +80,26 @@ MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_A
.PHONY: repackage
tools repackage:: $(PROGRAM)
$(MKDIR) -p $(dist_dest)/Contents/MacOS
$(MKDIR) -p $(dist_dest)/Contents/Resources/$(AB).lproj
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj
sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings
rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(dist_dest)/Contents/Resources
rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(dist_dest)/Contents/MacOS
$(RM) $(dist_dest)/Contents/MacOS/$(PROGRAM)
rsync -aL $(PROGRAM) $(dist_dest)/Contents/MacOS
cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns
cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns
printf APPLMOZB > $(dist_dest)/Contents/PkgInfo
$(MKDIR) -p '$(dist_dest)/Contents/MacOS'
$(MKDIR) -p '$(dist_dest)/Contents/Resources/$(AB).lproj'
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents '$(dist_dest)' --exclude English.lproj
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ '$(dist_dest)/Contents/Resources/$(AB).lproj'
sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > '$(dist_dest)/Contents/Info.plist'
sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > '$(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings'
rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ '$(dist_dest)/Contents/Resources'
rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ '$(dist_dest)/Contents/MacOS'
$(RM) '$(dist_dest)/Contents/MacOS/$(PROGRAM)'
rsync -aL $(PROGRAM) '$(dist_dest)/Contents/MacOS'
cp -RL $(DIST)/branding/firefox.icns '$(dist_dest)/Contents/Resources/firefox.icns'
cp -RL $(DIST)/branding/document.icns '$(dist_dest)/Contents/Resources/document.icns'
printf APPLMOZB > '$(dist_dest)/Contents/PkgInfo'
endif
ifdef LIBXUL_SDK #{
ifndef SKIP_COPY_XULRUNNER #{
libs::
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) #{
rsync -a --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(dist_dest)/Contents/Frameworks
rsync -a --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework '$(dist_dest)/Contents/Frameworks'
else
$(NSINSTALL) -D $(DIST)/bin/xulrunner
(cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -)

View file

@ -113,19 +113,19 @@ include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
ifeq (bundle, $(MOZ_FS_LAYOUT))
BINPATH = $(_BINPATH)
DEFINES += -DAPPNAME=$(_APPNAME)
DEFINES += -DAPPNAME='$(_APPNAME)'
else
# Every other platform just winds up in dist/bin
BINPATH = bin
endif
DEFINES += -DBINPATH=$(BINPATH)
DEFINES += -DBINPATH='$(BINPATH)'
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
RESPATH = $(_APPNAME)/Contents/Resources
else
RESPATH = $(BINPATH)
endif
DEFINES += -DRESPATH=$(RESPATH)
DEFINES += -DRESPATH='$(RESPATH)'
AB = $(firstword $(subst -, ,$(AB_CD)))
DEFINES += -DAB=$(AB)
@ -173,7 +173,7 @@ endif
package-compare:: $(MOZ_PKG_MANIFEST)
ifdef MOZ_PKG_MANIFEST_P
cd $(DIST); find $(PKGCOMP_FIND_OPTS) $(FINDPATH) -type f | sort > bin-list.txt
cd $(DIST); find $(PKGCOMP_FIND_OPTS) '$(FINDPATH)' -type f | sort > bin-list.txt
grep '^$(BINPATH)' $(MOZ_PKG_MANIFEST) | sed -e 's/^\///' | sort > $(DIST)/pack-list.txt
-diff -u $(DIST)/pack-list.txt $(DIST)/bin-list.txt
rm -f $(DIST)/pack-list.txt $(DIST)/bin-list.txt

View file

@ -198,10 +198,10 @@ endif
ident:
@printf "fx_revision "
@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \
$(STAGEDIST)/application.ini App SourceStamp
'$(STAGEDIST)'/application.ini App SourceStamp
@printf "buildid "
@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \
$(STAGEDIST)/application.ini App BuildID
'$(STAGEDIST)'/application.ini App BuildID
merge-%:
ifdef LOCALE_MERGEDIR

View file

@ -63,7 +63,7 @@ included_inclnames_to_ignore = set([
'devtools/Instruments.h', # we ignore devtools/ in general
'double-conversion.h', # strange MFBT case
'javascript-trace.h', # generated in $OBJDIR if HAVE_DTRACE is defined
'jsautokw.h', # generated in $OBJDIR
'frontend/ReservedWordsGenerated.h', # generated in $OBJDIR
'jscustomallocator.h', # provided by embedders; allowed to be missing
'js-config.h', # generated in $OBJDIR
'fdlibm.h', # fdlibm
@ -99,7 +99,7 @@ included_inclnames_to_ignore = set([
# ignore #includes of them when checking #include ordering.
oddly_ordered_inclnames = set([
'ctypes/typedefs.h', # Included multiple times in the body of ctypes/CTypes.h
'jsautokw.h', # Included in the body of frontend/TokenStream.h
'frontend/ReservedWordsGenerated.h', # Included in the body of frontend/TokenStream.h
'jswin.h', # Must be #included before <psapi.h>
'machine/endian.h', # Must be included after <sys/types.h> on BSD
'winbase.h', # Must precede other system headers(?)

View file

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
4.3.0
4.4.0

View file

@ -34,6 +34,7 @@ function EvaluationResult(props) {
id: messageId,
exceptionDocURL,
frame,
notes,
} = message;
let messageBody;
@ -57,6 +58,7 @@ function EvaluationResult(props) {
serviceContainer,
exceptionDocURL,
frame,
notes,
};
return Message(childProps);
}

View file

@ -44,6 +44,7 @@ function PageError(props) {
stacktrace,
frame,
exceptionDocURL,
notes,
} = message;
const childProps = {
@ -62,6 +63,7 @@ function PageError(props) {
stacktrace,
serviceContainer,
exceptionDocURL,
notes,
};
return Message(childProps);
}

View file

@ -47,6 +47,10 @@ const Message = createClass({
onViewSourceInDebugger: PropTypes.func.isRequired,
sourceMapService: PropTypes.any,
}),
notes: PropTypes.arrayOf(PropTypes.shape({
messageBody: PropTypes.string.isRequired,
frame: PropTypes.any,
})),
},
getDefaultProps: function () {
@ -90,6 +94,7 @@ const Message = createClass({
serviceContainer,
dispatch,
exceptionDocURL,
notes,
} = this.props;
topLevelClasses.push("message", source, type, level);
@ -127,6 +132,29 @@ const Message = createClass({
});
}
let notesNodes;
if (notes) {
notesNodes = notes.map(note => dom.span(
{ className: "message-flex-body error-note" },
dom.span({ className: "message-body devtools-monospace" },
"note: " + note.messageBody
),
dom.span({ className: "message-location devtools-monospace" },
note.frame ? FrameView({
frame: note.frame,
onClick: serviceContainer
? serviceContainer.onViewSourceInDebugger
: undefined,
showEmptyPathAsHost: true,
sourceMapService: serviceContainer
? serviceContainer.sourceMapService
: undefined
}) : null
)));
} else {
notesNodes = [];
}
const repeat = this.props.repeat ? MessageRepeat({repeat: this.props.repeat}) : null;
// Configure the location.
@ -167,7 +195,8 @@ const Message = createClass({
repeat,
location
),
attachment
attachment,
...notesNodes
)
);
}

View file

@ -126,6 +126,15 @@ function matchSearchFilters(message, filters) {
|| (message.parameters !== null
&& message.parameters.join("").toLocaleLowerCase()
.includes(text.toLocaleLowerCase()))
// Look for a match in notes.
|| (Array.isArray(message.notes) && message.notes.some(note =>
// Look for a match in location.
isTextInFrame(text, note.frame)
// Look for a match in messageBody.
|| (note.messageBody !== null
&& note.messageBody.toLocaleLowerCase()
.includes(text.toLocaleLowerCase()))
))
);
}

View file

@ -123,4 +123,118 @@ describe("PageError component:", () => {
wrapper = render(PageError({ message, serviceContainer}));
expect(wrapper.find(".indent").prop("style").width).toBe(`0`);
});
it("has empty error notes", () => {
const message = stubPreparedMessages.get("ReferenceError: asdf is not defined");
let wrapper = render(PageError({ message, serviceContainer }));
const notes = wrapper.find(".error-note");
expect(notes.length).toBe(0);
});
it("can show an error note", () => {
const origMessage = stubPreparedMessages.get("ReferenceError: asdf is not defined");
const message = origMessage.set("notes", [
{
"messageBody": "test note",
"frame": {
"source": "http://example.com/test.js",
"line": 2,
"column": 6
}
}
]);
let wrapper = render(PageError({ message, serviceContainer }));
const notes = wrapper.find(".error-note");
expect(notes.length).toBe(1);
const note = notes.eq(0);
expect(note.find(".message-body").text())
.toBe("note: test note");
// There should be the location.
const locationLink = note.find(`.message-location`);
expect(locationLink.length).toBe(1);
expect(locationLink.text()).toBe("test.js:2:6");
});
it("can show multiple error notes", () => {
const origMessage = stubPreparedMessages.get("ReferenceError: asdf is not defined");
const message = origMessage.set("notes", [
{
"messageBody": "test note 1",
"frame": {
"source": "http://example.com/test1.js",
"line": 2,
"column": 6
}
},
{
"messageBody": "test note 2",
"frame": {
"source": "http://example.com/test2.js",
"line": 10,
"column": 18
}
},
{
"messageBody": "test note 3",
"frame": {
"source": "http://example.com/test3.js",
"line": 9,
"column": 4
}
}
]);
let wrapper = render(PageError({ message, serviceContainer }));
const notes = wrapper.find(".error-note");
expect(notes.length).toBe(3);
const note1 = notes.eq(0);
expect(note1.find(".message-body").text())
.toBe("note: test note 1");
const locationLink1 = note1.find(`.message-location`);
expect(locationLink1.length).toBe(1);
expect(locationLink1.text()).toBe("test1.js:2:6");
const note2 = notes.eq(1);
expect(note2.find(".message-body").text())
.toBe("note: test note 2");
const locationLink2 = note2.find(`.message-location`);
expect(locationLink2.length).toBe(1);
expect(locationLink2.text()).toBe("test2.js:10:18");
const note3 = notes.eq(2);
expect(note3.find(".message-body").text())
.toBe("note: test note 3");
const locationLink3 = note3.find(`.message-location`);
expect(locationLink3.length).toBe(1);
expect(locationLink3.text()).toBe("test3.js:9:4");
});
it("displays error notes", () => {
const message = stubPreparedMessages.get("SyntaxError: redeclaration of let a");
let wrapper = render(PageError({ message, serviceContainer }));
const notes = wrapper.find(".error-note");
expect(notes.length).toBe(1);
const note = notes.eq(0);
expect(note.find(".message-body").text())
.toBe("note: Previously declared at line 2, column 6");
// There should be the location.
const locationLink = note.find(`.message-location`);
expect(locationLink.length).toBe(1);
expect(locationLink.text()).toBe("test-console-api.html:2:6");
});
});

View file

@ -140,6 +140,10 @@ pageError.set("Reference Error", `
foo()
`);
pageError.set("Redeclaration Error", `
let a, a;
`);
module.exports = {
consoleApi,
evaluationResult,

View file

@ -11,8 +11,6 @@ const { ConsoleMessage, NetworkEventMessage } = require("devtools/client/webcons
let stubPreparedMessages = new Map();
let stubPackets = new Map();
stubPreparedMessages.set("console.log('foobar', 'test')", new ConsoleMessage({
"id": "1",
"allowRepeating": true,
@ -34,7 +32,8 @@ stubPreparedMessages.set("console.log('foobar', 'test')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.log(undefined)", new ConsoleMessage({
@ -50,7 +49,7 @@ stubPreparedMessages.set("console.log(undefined)", new ConsoleMessage({
}
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"undefined\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(undefined)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"undefined\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(undefined)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(undefined)",
@ -59,7 +58,8 @@ stubPreparedMessages.set("console.log(undefined)", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.warn('danger, will robinson!')", new ConsoleMessage({
@ -73,7 +73,7 @@ stubPreparedMessages.set("console.warn('danger, will robinson!')", new ConsoleMe
"danger, will robinson!"
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"warn\",\"level\":\"warn\",\"messageText\":null,\"parameters\":[\"danger, will robinson!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.warn(%27danger%2C%20will%20robinson!%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"warn\",\"level\":\"warn\",\"messageText\":null,\"parameters\":[\"danger, will robinson!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.warn(%27danger%2C%20will%20robinson!%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.warn(%27danger%2C%20will%20robinson!%27)",
@ -82,7 +82,8 @@ stubPreparedMessages.set("console.warn('danger, will robinson!')", new ConsoleMe
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.log(NaN)", new ConsoleMessage({
@ -98,7 +99,7 @@ stubPreparedMessages.set("console.log(NaN)", new ConsoleMessage({
}
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"NaN\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(NaN)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"NaN\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(NaN)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(NaN)",
@ -107,7 +108,8 @@ stubPreparedMessages.set("console.log(NaN)", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.log(null)", new ConsoleMessage({
@ -123,7 +125,7 @@ stubPreparedMessages.set("console.log(null)", new ConsoleMessage({
}
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"null\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(null)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"null\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(null)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(null)",
@ -132,7 +134,8 @@ stubPreparedMessages.set("console.log(null)", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({
@ -146,7 +149,7 @@ stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({
"鼬"
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"鼬\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%E9%BC%AC%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"鼬\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%E9%BC%AC%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%E9%BC%AC%27)",
@ -155,7 +158,8 @@ stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.clear()", new ConsoleMessage({
@ -169,8 +173,7 @@ stubPreparedMessages.set("console.clear()", new ConsoleMessage({
"Console was cleared."
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"clear\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"Console was cleared.\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.clear()\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"stacktrace": null,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"clear\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"Console was cleared.\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.clear()\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.clear()",
"line": 1,
@ -178,7 +181,8 @@ stubPreparedMessages.set("console.clear()", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.count('bar')", new ConsoleMessage({
@ -190,7 +194,7 @@ stubPreparedMessages.set("console.count('bar')", new ConsoleMessage({
"messageText": "bar: 1",
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"debug\",\"messageText\":\"bar: 1\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.count(%27bar%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"debug\",\"messageText\":\"bar: 1\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.count(%27bar%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.count(%27bar%27)",
@ -199,7 +203,8 @@ stubPreparedMessages.set("console.count('bar')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new ConsoleMessage({
@ -234,7 +239,7 @@ stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new Conso
}
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"assert\",\"level\":\"error\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn8.child1/obj31\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"message\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"foobar\"}},\"ownPropertiesLength\":1,\"safeGetterValues\":{}}}],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":27,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.assert(false%2C%20%7Bmessage%3A%20%27foobar%27%7D)\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":1}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.assert(false%2C%20%7Bmessage%3A%20%27foobar%27%7D)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"assert\",\"level\":\"error\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn8.child1/obj31\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"message\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"foobar\"}},\"ownPropertiesLength\":1,\"safeGetterValues\":{}}}],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":27,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.assert(false%2C%20%7Bmessage%3A%20%27foobar%27%7D)\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":1}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.assert(false%2C%20%7Bmessage%3A%20%27foobar%27%7D)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": [
{
"columnNumber": 27,
@ -251,7 +256,8 @@ stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new Conso
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.log('hello \nfrom \rthe \"string world!')", new ConsoleMessage({
@ -265,7 +271,7 @@ stubPreparedMessages.set("console.log('hello \nfrom \rthe \"string world!')", ne
"hello \nfrom \rthe \"string world!"
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"hello \\nfrom \\rthe \\\"string world!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27hello%20%5Cnfrom%20%5Crthe%20%5C%22string%20world!%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"hello \\nfrom \\rthe \\\"string world!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27hello%20%5Cnfrom%20%5Crthe%20%5C%22string%20world!%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27hello%20%5Cnfrom%20%5Crthe%20%5C%22string%20world!%27)",
@ -274,7 +280,8 @@ stubPreparedMessages.set("console.log('hello \nfrom \rthe \"string world!')", ne
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMessage({
@ -288,7 +295,7 @@ stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMe
"úṇĩçödê țĕșť"
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"úṇĩçödê țĕșť\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%C3%BA%E1%B9%87%C4%A9%C3%A7%C3%B6d%C3%AA%20%C8%9B%C4%95%C8%99%C5%A5%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"úṇĩçödê țĕșť\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%C3%BA%E1%B9%87%C4%A9%C3%A7%C3%B6d%C3%AA%20%C8%9B%C4%95%C8%99%C5%A5%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%C3%BA%E1%B9%87%C4%A9%C3%A7%C3%B6d%C3%AA%20%C8%9B%C4%95%C8%99%C5%A5%27)",
@ -297,7 +304,8 @@ stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMe
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({
@ -315,7 +323,7 @@ stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 804,
"ownPropertyLength": 815,
"preview": {
"kind": "ObjectWithURL",
"url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html"
@ -323,7 +331,7 @@ stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({
}
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn11.child1/obj31\",\"class\":\"Window\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":804,\"preview\":{\"kind\":\"ObjectWithURL\",\"url\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\"}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.dirxml(window)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn11.child1/obj31\",\"class\":\"Window\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":804,\"preview\":{\"kind\":\"ObjectWithURL\",\"url\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\"}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.dirxml(window)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.dirxml(window)",
@ -332,7 +340,8 @@ stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.trace()", new ConsoleMessage({
@ -344,7 +353,7 @@ stubPreparedMessages.set("console.trace()", new ConsoleMessage({
"messageText": null,
"parameters": [],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"trace\",\"level\":\"log\",\"messageText\":null,\"parameters\":[],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"testStacktraceFiltering\",\"language\":2,\"lineNumber\":3},{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"foo\",\"language\":2,\"lineNumber\":6},{\"columnNumber\":1,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":9}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"line\":3,\"column\":3},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"trace\",\"level\":\"log\",\"messageText\":null,\"parameters\":[],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"testStacktraceFiltering\",\"language\":2,\"lineNumber\":3},{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"foo\",\"language\":2,\"lineNumber\":6},{\"columnNumber\":1,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":9}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"line\":3,\"column\":3},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": [
{
"columnNumber": 3,
@ -375,7 +384,8 @@ stubPreparedMessages.set("console.trace()", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.time('bar')", new ConsoleMessage({
@ -387,7 +397,7 @@ stubPreparedMessages.set("console.time('bar')", new ConsoleMessage({
"messageText": null,
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"nullMessage\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"nullMessage\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)",
@ -396,7 +406,8 @@ stubPreparedMessages.set("console.time('bar')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.timeEnd('bar')", new ConsoleMessage({
@ -408,7 +419,7 @@ stubPreparedMessages.set("console.timeEnd('bar')", new ConsoleMessage({
"messageText": "bar: 1.36ms",
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"timeEnd\",\"level\":\"log\",\"messageText\":\"bar: 1.36ms\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"timeEnd\",\"level\":\"log\",\"messageText\":\"bar: 1.36ms\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)",
@ -417,7 +428,8 @@ stubPreparedMessages.set("console.timeEnd('bar')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.table('bar')", new ConsoleMessage({
@ -431,7 +443,7 @@ stubPreparedMessages.set("console.table('bar')", new ConsoleMessage({
"bar"
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%27bar%27)",
@ -440,7 +452,8 @@ stubPreparedMessages.set("console.table('bar')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.table(['a', 'b', 'c'])", new ConsoleMessage({
@ -471,7 +484,7 @@ stubPreparedMessages.set("console.table(['a', 'b', 'c'])", new ConsoleMessage({
}
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"table\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn15.child1/obj31\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"a\",\"b\",\"c\"]}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%5B%27a%27%2C%20%27b%27%2C%20%27c%27%5D)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"table\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn15.child1/obj31\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"a\",\"b\",\"c\"]}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%5B%27a%27%2C%20%27b%27%2C%20%27c%27%5D)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%5B%27a%27%2C%20%27b%27%2C%20%27c%27%5D)",
@ -480,7 +493,8 @@ stubPreparedMessages.set("console.table(['a', 'b', 'c'])", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.group('bar')", new ConsoleMessage({
@ -492,7 +506,7 @@ stubPreparedMessages.set("console.group('bar')", new ConsoleMessage({
"messageText": "bar",
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":\"bar\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":\"bar\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)",
@ -501,7 +515,8 @@ stubPreparedMessages.set("console.group('bar')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.groupEnd('bar')", new ConsoleMessage({
@ -513,7 +528,7 @@ stubPreparedMessages.set("console.groupEnd('bar')", new ConsoleMessage({
"messageText": null,
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)",
@ -522,7 +537,8 @@ stubPreparedMessages.set("console.groupEnd('bar')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.groupCollapsed('foo')", new ConsoleMessage({
@ -534,7 +550,7 @@ stubPreparedMessages.set("console.groupCollapsed('foo')", new ConsoleMessage({
"messageText": "foo",
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroupCollapsed\",\"level\":\"log\",\"messageText\":\"foo\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroupCollapsed\",\"level\":\"log\",\"messageText\":\"foo\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)",
@ -543,7 +559,8 @@ stubPreparedMessages.set("console.groupCollapsed('foo')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.groupEnd('foo')", new ConsoleMessage({
@ -555,7 +572,7 @@ stubPreparedMessages.set("console.groupEnd('foo')", new ConsoleMessage({
"messageText": null,
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)",
@ -564,7 +581,8 @@ stubPreparedMessages.set("console.groupEnd('foo')", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.group()", new ConsoleMessage({
@ -576,7 +594,7 @@ stubPreparedMessages.set("console.group()", new ConsoleMessage({
"messageText": "<no group label>",
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":\"<no group label>\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":\"<no group label>\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()",
@ -585,7 +603,8 @@ stubPreparedMessages.set("console.group()", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.groupEnd()", new ConsoleMessage({
@ -597,7 +616,7 @@ stubPreparedMessages.set("console.groupEnd()", new ConsoleMessage({
"messageText": null,
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()",
@ -606,7 +625,8 @@ stubPreparedMessages.set("console.groupEnd()", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": null,
"userProvidedStyles": []
"userProvidedStyles": [],
"notes": null
}));
stubPreparedMessages.set("console.log(%cfoobar)", new ConsoleMessage({
@ -621,7 +641,7 @@ stubPreparedMessages.set("console.log(%cfoobar)", new ConsoleMessage({
"bar"
],
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%25cfoobar)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"]}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%25cfoobar)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"],\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%25cfoobar)",
@ -633,10 +653,10 @@ stubPreparedMessages.set("console.log(%cfoobar)", new ConsoleMessage({
"userProvidedStyles": [
"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px",
"color:red;background:url('http://example.com/test')"
]
],
"notes": null
}));
stubPackets.set("console.log('foobar', 'test')", {
"from": "server1.conn0.child1/consoleActor2",
"type": "consoleAPICall",
@ -1028,7 +1048,7 @@ stubPackets.set("console.dirxml(window)", {
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 804,
"ownPropertyLength": 815,
"preview": {
"kind": "ObjectWithURL",
"url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html"
@ -1475,8 +1495,7 @@ stubPackets.set("console.log(%cfoobar)", {
}
});
module.exports = {
stubPreparedMessages,
stubPackets,
}
};

View file

@ -11,8 +11,6 @@ const { ConsoleMessage, NetworkEventMessage } = require("devtools/client/webcons
let stubPreparedMessages = new Map();
let stubPackets = new Map();
stubPreparedMessages.set("new Date(0)", new ConsoleMessage({
"id": "1",
"allowRepeating": true,
@ -32,11 +30,12 @@ stubPreparedMessages.set("new Date(0)", new ConsoleMessage({
}
},
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"log\",\"parameters\":{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj30\",\"class\":\"Date\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"timestamp\":0}},\"repeatId\":null,\"stacktrace\":null,\"frame\":null,\"groupId\":null,\"userProvidedStyles\":null}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"log\",\"parameters\":{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj30\",\"class\":\"Date\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"timestamp\":0}},\"repeatId\":null,\"stacktrace\":null,\"frame\":null,\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null}",
"stacktrace": null,
"frame": null,
"groupId": null,
"userProvidedStyles": null
"userProvidedStyles": null,
"notes": null
}));
stubPreparedMessages.set("asdf()", new ConsoleMessage({
@ -50,7 +49,7 @@ stubPreparedMessages.set("asdf()", new ConsoleMessage({
"type": "undefined"
},
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null,\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "debugger eval code",
@ -59,7 +58,8 @@ stubPreparedMessages.set("asdf()", new ConsoleMessage({
},
"groupId": null,
"exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
"userProvidedStyles": null
"userProvidedStyles": null,
"notes": null
}));
stubPreparedMessages.set("1 + @", new ConsoleMessage({
@ -73,7 +73,7 @@ stubPreparedMessages.set("1 + @", new ConsoleMessage({
"type": "undefined"
},
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"userProvidedStyles\":null}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null}",
"stacktrace": null,
"frame": {
"source": "debugger eval code",
@ -81,10 +81,10 @@ stubPreparedMessages.set("1 + @", new ConsoleMessage({
"column": 4
},
"groupId": null,
"userProvidedStyles": null
"userProvidedStyles": null,
"notes": null
}));
stubPackets.set("new Date(0)", {
"from": "server1.conn0.child1/consoleActor2",
"input": "new Date(0)",
@ -103,7 +103,8 @@ stubPackets.set("new Date(0)", {
"timestamp": 1476573073424,
"exception": null,
"frame": null,
"helperResult": null
"helperResult": null,
"notes": null
});
stubPackets.set("asdf()", {
@ -138,7 +139,8 @@ stubPackets.set("asdf()", {
"line": 1,
"column": 1
},
"helperResult": null
"helperResult": null,
"notes": null
});
stubPackets.set("1 + @", {
@ -172,11 +174,11 @@ stubPackets.set("1 + @", {
"line": 1,
"column": 4
},
"helperResult": null
"helperResult": null,
"notes": null
});
module.exports = {
stubPreparedMessages,
stubPackets,
}
};

View file

@ -11,8 +11,6 @@ const { ConsoleMessage, NetworkEventMessage } = require("devtools/client/webcons
let stubPreparedMessages = new Map();
let stubPackets = new Map();
stubPreparedMessages.set("ReferenceError: asdf is not defined", new ConsoleMessage({
"id": "1",
"allowRepeating": true,
@ -22,7 +20,7 @@ stubPreparedMessages.set("ReferenceError: asdf is not defined", new ConsoleMessa
"messageText": "ReferenceError: asdf is not defined",
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"log\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":3,\"columnNumber\":5,\"functionName\":\"bar\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":6,\"columnNumber\":5,\"functionName\":\"foo\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":9,\"columnNumber\":3,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"line\":3,\"column\":5},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\"}",
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"log\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":3,\"columnNumber\":5,\"functionName\":\"bar\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":6,\"columnNumber\":5,\"functionName\":\"foo\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":9,\"columnNumber\":3,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"line\":3,\"column\":5},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null,\"notes\":null}",
"stacktrace": [
{
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error",
@ -49,9 +47,53 @@ stubPreparedMessages.set("ReferenceError: asdf is not defined", new ConsoleMessa
"column": 5
},
"groupId": null,
"exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default"
"exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
"userProvidedStyles": null,
"notes": null
}));
stubPreparedMessages.set("SyntaxError: redeclaration of let a", new ConsoleMessage({
"id": "1",
"allowRepeating": true,
"source": "javascript",
"type": "log",
"level": "error",
"messageText": "SyntaxError: redeclaration of let a",
"parameters": null,
"repeat": 1,
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"log\",\"level\":\"error\",\"messageText\":\"SyntaxError: redeclaration of let a\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"chrome://mochikit/content/tests/BrowserTestUtils/content-task.js line 52 > eval\",\"lineNumber\":6,\"columnNumber\":9,\"functionName\":null},{\"filename\":\"chrome://mochikit/content/tests/BrowserTestUtils/content-task.js\",\"lineNumber\":53,\"columnNumber\":20,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":9},\"groupId\":null,\"userProvidedStyles\":null,\"notes\":[{\"messageBody\":\"Previously declared at line 2, column 6\",\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":6}}]}",
"stacktrace": [
{
"filename": "chrome://mochikit/content/tests/BrowserTestUtils/content-task.js line 52 > eval",
"lineNumber": 6,
"columnNumber": 9,
"functionName": null
},
{
"filename": "chrome://mochikit/content/tests/BrowserTestUtils/content-task.js",
"lineNumber": 53,
"columnNumber": 20,
"functionName": null
}
],
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
"line": 2,
"column": 9
},
"groupId": null,
"userProvidedStyles": null,
"notes": [
{
"messageBody": "Previously declared at line 2, column 6",
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
"line": 2,
"column": 6
}
}
]
}));
stubPackets.set("ReferenceError: asdf is not defined", {
"from": "server1.conn0.child1/consoleActor2",
@ -91,12 +133,56 @@ stubPackets.set("ReferenceError: asdf is not defined", {
"columnNumber": 3,
"functionName": null
}
]
],
"notes": null
}
});
stubPackets.set("SyntaxError: redeclaration of let a", {
"from": "server1.conn0.child1/consoleActor2",
"type": "pageError",
"pageError": {
"errorMessage": "SyntaxError: redeclaration of let a",
"errorMessageName": "JSMSG_REDECLARED_VAR",
"sourceName": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
"lineText": " let a, a;\n",
"lineNumber": 2,
"columnNumber": 9,
"category": "content javascript",
"warning": false,
"error": false,
"exception": true,
"strict": false,
"info": false,
"private": false,
"stacktrace": [
{
"filename": "chrome://mochikit/content/tests/BrowserTestUtils/content-task.js line 52 > eval",
"lineNumber": 6,
"columnNumber": 9,
"functionName": null
},
{
"filename": "chrome://mochikit/content/tests/BrowserTestUtils/content-task.js",
"lineNumber": 53,
"columnNumber": 20,
"functionName": null
}
],
"notes": [
{
"messageBody": "Previously declared at line 2, column 6",
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
"line": 2,
"column": 6
}
}
]
}
});
module.exports = {
stubPreparedMessages,
stubPackets,
}
};

View file

@ -38,6 +38,7 @@ exports.ConsoleMessage = Immutable.Record({
groupId: null,
exceptionDocURL: null,
userProvidedStyles: null,
notes: null,
});
exports.NetworkEventMessage = Immutable.Record({

View file

@ -165,6 +165,7 @@ function transformPacket(packet) {
stacktrace: pageError.stacktrace ? pageError.stacktrace : null,
frame,
exceptionDocURL: pageError.exceptionDocURL,
notes: pageError.notes,
});
}
@ -185,7 +186,8 @@ function transformPacket(packet) {
exceptionMessage: messageText,
exceptionDocURL,
frame,
result: parameters
result: parameters,
notes,
} = packet;
const level = messageText ? MESSAGE_LEVEL.ERROR : MESSAGE_LEVEL.LOG;
@ -197,6 +199,7 @@ function transformPacket(packet) {
parameters,
exceptionDocURL,
frame,
notes,
});
}
}

View file

@ -888,7 +888,8 @@ WebConsoleActor.prototype =
let evalResult = evalInfo.result;
let helperResult = evalInfo.helperResult;
let result, errorDocURL, errorMessage, errorGrip = null, frame = null;
let result, errorDocURL, errorMessage, errorNotes = null, errorGrip = null,
frame = null;
if (evalResult) {
if ("return" in evalResult) {
result = evalResult.return;
@ -943,6 +944,23 @@ WebConsoleActor.prototype =
};
}
} catch (ex) {}
try {
let notes = error.errorNotes;
if (notes && notes.length) {
errorNotes = [];
for (let note of notes) {
errorNotes.push({
messageBody: this._createStringGrip(note.message),
frame: {
source: note.fileName,
line: note.lineNumber,
column: note.columnNumber,
}
});
}
}
} catch (ex) {}
}
}
@ -967,6 +985,7 @@ WebConsoleActor.prototype =
exceptionDocURL: errorDocURL,
frame,
helperResult: helperResult,
notes: errorNotes,
};
},
@ -1500,6 +1519,23 @@ WebConsoleActor.prototype =
lineText = lineText.substr(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH);
}
let notesArray = null;
let notes = aPageError.notes;
if (notes && notes.length) {
notesArray = [];
for (let i = 0, len = notes.length; i < len; i++) {
let note = notes.queryElementAt(i, Ci.nsIScriptErrorNote);
notesArray.push({
messageBody: this._createStringGrip(note.errorMessage),
frame: {
source: note.sourceName,
line: note.lineNumber,
column: note.columnNumber,
}
});
}
}
return {
errorMessage: this._createStringGrip(aPageError.errorMessage),
errorMessageName: aPageError.errorMessageName,
@ -1516,7 +1552,8 @@ WebConsoleActor.prototype =
strict: !!(aPageError.flags & aPageError.strictFlag),
info: !!(aPageError.flags & aPageError.infoFlag),
private: aPageError.isFromPrivateWindow,
stacktrace: stack
stacktrace: stack,
notes: notesArray,
};
},

View file

@ -112,6 +112,24 @@ function doPageErrors()
warning: true,
exception: false,
},
"let a, a;": {
errorMessage: /redeclaration of/,
errorMessageName: "JSMSG_REDECLARED_VAR",
sourceName: /test_page_errors/,
category: "chrome javascript",
timeStamp: /^\d+$/,
error: false,
warning: false,
exception: true,
notes: [
{
messageBody: /Previously declared at line/,
frame: {
source: /test_page_errors/,
}
}
]
},
};
let container = document.createElement("script");

View file

@ -1183,14 +1183,6 @@ GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
}
}
bool
UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
args.rval().set(args.thisv());
return true;
}
bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
{

View file

@ -2044,9 +2044,6 @@ GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
}
bool
UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp);
bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);

View file

@ -2390,11 +2390,10 @@ class MethodDefiner(PropertyDefiner):
# Synthesize our valueOf method
self.regular.append({
"name": 'valueOf',
"nativeName": "UnforgeableValueOf",
"selfHostedName": "Object_valueOf",
"methodInfo": False,
"length": 0,
"flags": "JSPROP_ENUMERATE", # readonly/permanent added
# automatically.
"flags": "0", # readonly/permanent added automatically.
"condition": MemberCondition()
})
@ -3456,19 +3455,15 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode,
"nsContentUtils::ThreadsafeIsCallerChrome()"))
if descriptor.interface.getExtendedAttribute("Unforgeable"):
# We do our undefined toJSON and toPrimitive here, not as a regular
# property because we don't have a concept of value props anywhere in
# IDL.
# We do our undefined toPrimitive here, not as a regular property
# because we don't have a concept of value props anywhere in IDL.
unforgeables.append(CGGeneric(fill(
"""
JS::RootedId toPrimitive(aCx,
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::toPrimitive)));
if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive,
JS::UndefinedHandleValue,
JSPROP_READONLY | JSPROP_PERMANENT) ||
!JS_DefineProperty(aCx, ${holderName}, "toJSON",
JS::UndefinedHandleValue,
JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
JSPROP_READONLY | JSPROP_PERMANENT)) {
$*{failureCode}
}
""",

View file

@ -6,6 +6,12 @@
TEST_DIRS += ['test']
XPIDL_SOURCES += [
'nsIScriptError.idl'
]
XPIDL_MODULE = 'dom_bindings'
EXPORTS.ipc += [
'ErrorIPCUtils.h',
]
@ -91,6 +97,8 @@ UNIFIED_SOURCES += [
'DOMJSProxyHandler.cpp',
'Exceptions.cpp',
'IterableIterator.cpp',
'nsScriptError.cpp',
'nsScriptErrorWithStack.cpp',
'SimpleGlobalObject.cpp',
'ToJSValue.cpp',
'WebIDLGlobalNameHash.cpp',

View file

@ -9,13 +9,25 @@
#include "nsISupports.idl"
#include "nsIArray.idl"
#include "nsIConsoleMessage.idl"
%{C++
#include "nsStringGlue.h" // for nsDependentCString
%}
[scriptable, uuid(361be358-76f0-47aa-b37b-6ad833599e8d)]
[scriptable, uuid(e8933fc9-c302-4e12-a55b-4f88611d9c6c)]
interface nsIScriptErrorNote : nsISupports
{
readonly attribute AString errorMessage;
readonly attribute AString sourceName;
readonly attribute uint32_t lineNumber;
readonly attribute uint32_t columnNumber;
AUTF8String toString();
};
[scriptable, uuid(63eb4d3e-7d99-4150-b4f3-11314f9d82a9)]
interface nsIScriptError : nsIConsoleMessage
{
/** pseudo-flag for default case */
@ -74,6 +86,7 @@ interface nsIScriptError : nsIConsoleMessage
*/
attribute AString errorMessageName;
readonly attribute nsIArray notes;
void init(in AString message,
in AString sourceName,

View file

@ -5,18 +5,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* nsIScriptError implementation. Defined here, lacking a JS-specific
* place to put XPCOM things.
* nsIScriptError implementation.
*/
#include "xpcprivate.h"
#include "nsScriptError.h"
#include "jsprf.h"
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
#include "nsGlobalWindow.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsILoadContext.h"
#include "nsIDocShell.h"
#include "nsIMutableArray.h"
#include "nsIScriptError.h"
#include "nsISensitiveInfoHiddenURI.h"
@ -46,6 +47,12 @@ nsScriptErrorBase::nsScriptErrorBase()
nsScriptErrorBase::~nsScriptErrorBase() {}
void
nsScriptErrorBase::AddNote(nsIScriptErrorNote* note)
{
mNotes.AppendObject(note);
}
void
nsScriptErrorBase::InitializeOnMainThread()
{
@ -189,6 +196,28 @@ nsScriptErrorBase::Init(const nsAString& message,
0);
}
static void
AssignSourceNameHelper(nsString& aSourceNameDest, const nsAString& aSourceNameSrc)
{
if (aSourceNameSrc.IsEmpty())
return;
aSourceNameDest.Assign(aSourceNameSrc);
nsCOMPtr<nsIURI> uri;
nsAutoCString pass;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aSourceNameSrc)) &&
NS_SUCCEEDED(uri->GetPassword(pass)) &&
!pass.IsEmpty())
{
nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(uri);
nsAutoCString loc;
if (safeUri && NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc)))
aSourceNameDest.Assign(NS_ConvertUTF8toUTF16(loc));
}
}
NS_IMETHODIMP
nsScriptErrorBase::InitWithWindowID(const nsAString& message,
const nsAString& sourceName,
@ -200,26 +229,7 @@ nsScriptErrorBase::InitWithWindowID(const nsAString& message,
uint64_t aInnerWindowID)
{
mMessage.Assign(message);
if (!sourceName.IsEmpty()) {
mSourceName.Assign(sourceName);
nsCOMPtr<nsIURI> uri;
nsAutoCString pass;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), sourceName)) &&
NS_SUCCEEDED(uri->GetPassword(pass)) &&
!pass.IsEmpty()) {
nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri =
do_QueryInterface(uri);
nsAutoCString loc;
if (safeUri &&
NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc))) {
mSourceName.Assign(NS_ConvertUTF8toUTF16(loc));
}
}
}
AssignSourceNameHelper(mSourceName, sourceName);
mLineNumber = lineNumber;
mSourceLine.Assign(sourceLine);
mColumnNumber = columnNumber;
@ -235,8 +245,11 @@ nsScriptErrorBase::InitWithWindowID(const nsAString& message,
return NS_OK;
}
NS_IMETHODIMP
nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult)
static nsresult
ToStringHelper(const char* aSeverity, const nsString& aMessage,
const nsString& aSourceName, const nsString* aSourceLine,
uint32_t aLineNumber, uint32_t aColumnNumber,
nsACString& /*UTF8*/ aResult)
{
static const char format0[] =
"[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]";
@ -245,43 +258,39 @@ nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult)
static const char format2[] =
"[%s: \"%s\"]";
static const char error[] = "JavaScript Error";
static const char warning[] = "JavaScript Warning";
const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning;
char* temp;
char* tempMessage = nullptr;
char* tempSourceName = nullptr;
char* tempSourceLine = nullptr;
if (!mMessage.IsEmpty())
tempMessage = ToNewUTF8String(mMessage);
if (!mSourceName.IsEmpty())
if (!aMessage.IsEmpty())
tempMessage = ToNewUTF8String(aMessage);
if (!aSourceName.IsEmpty())
// Use at most 512 characters from mSourceName.
tempSourceName = ToNewUTF8String(StringHead(mSourceName, 512));
if (!mSourceLine.IsEmpty())
tempSourceName = ToNewUTF8String(StringHead(aSourceName, 512));
if (aSourceLine && !aSourceLine->IsEmpty())
// Use at most 512 characters from mSourceLine.
tempSourceLine = ToNewUTF8String(StringHead(mSourceLine, 512));
tempSourceLine = ToNewUTF8String(StringHead(*aSourceLine, 512));
if (nullptr != tempSourceName && nullptr != tempSourceLine)
if (nullptr != tempSourceName && nullptr != tempSourceLine) {
temp = JS_smprintf(format0,
severity,
aSeverity,
tempMessage,
tempSourceName,
mLineNumber,
mColumnNumber,
aLineNumber,
aColumnNumber,
tempSourceLine);
else if (!mSourceName.IsEmpty())
} else if (!aSourceName.IsEmpty()) {
temp = JS_smprintf(format1,
severity,
aSeverity,
tempMessage,
tempSourceName,
mLineNumber);
else
aLineNumber);
} else {
temp = JS_smprintf(format2,
severity,
aSeverity,
tempMessage);
}
if (nullptr != tempMessage)
free(tempMessage);
@ -298,6 +307,18 @@ nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult)
return NS_OK;
}
NS_IMETHODIMP
nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult)
{
static const char error[] = "JavaScript Error";
static const char warning[] = "JavaScript Warning";
const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning;
return ToStringHelper(severity, mMessage, mSourceName, &mSourceLine,
mLineNumber, mColumnNumber, aResult);
}
NS_IMETHODIMP
nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID)
{
@ -342,4 +363,76 @@ nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow)
return NS_OK;
}
NS_IMETHODIMP
nsScriptErrorBase::GetNotes(nsIArray** aNotes)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMutableArray> array =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t len = mNotes.Length();
for (uint32_t i = 0; i < len; i++)
array->AppendElement(mNotes[i], false);
array.forget(aNotes);
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError)
nsScriptErrorNote::nsScriptErrorNote()
: mMessage(),
mSourceName(),
mLineNumber(0),
mColumnNumber(0)
{
}
nsScriptErrorNote::~nsScriptErrorNote() {}
void
nsScriptErrorNote::Init(const nsAString& message,
const nsAString& sourceName,
uint32_t lineNumber,
uint32_t columnNumber)
{
mMessage.Assign(message);
AssignSourceNameHelper(mSourceName, sourceName);
mLineNumber = lineNumber;
mColumnNumber = columnNumber;
}
// nsIScriptErrorNote methods
NS_IMETHODIMP
nsScriptErrorNote::GetErrorMessage(nsAString& aResult) {
aResult.Assign(mMessage);
return NS_OK;
}
NS_IMETHODIMP
nsScriptErrorNote::GetSourceName(nsAString& aResult) {
aResult.Assign(mSourceName);
return NS_OK;
}
NS_IMETHODIMP
nsScriptErrorNote::GetLineNumber(uint32_t* result) {
*result = mLineNumber;
return NS_OK;
}
NS_IMETHODIMP
nsScriptErrorNote::GetColumnNumber(uint32_t* result) {
*result = mColumnNumber;
return NS_OK;
}
NS_IMETHODIMP
nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult)
{
return ToStringHelper("JavaScript Note", mMessage, mSourceName, nullptr,
mLineNumber, mColumnNumber, aResult);
}
NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote)

View file

@ -0,0 +1,109 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_nsScriptError_h
#define mozilla_dom_nsScriptError_h
#include "mozilla/Atomics.h"
#include <stdint.h>
#include "jsapi.h"
#include "js/RootingAPI.h"
#include "nsIScriptError.h"
#include "nsString.h"
class nsScriptErrorNote final : public nsIScriptErrorNote {
public:
nsScriptErrorNote();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSISCRIPTERRORNOTE
void Init(const nsAString& message, const nsAString& sourceName,
uint32_t lineNumber, uint32_t columnNumber);
private:
virtual ~nsScriptErrorNote();
nsString mMessage;
nsString mSourceName;
nsString mSourceLine;
uint32_t mLineNumber;
uint32_t mColumnNumber;
};
// Definition of nsScriptError..
class nsScriptErrorBase : public nsIScriptError {
public:
nsScriptErrorBase();
NS_DECL_NSICONSOLEMESSAGE
NS_DECL_NSISCRIPTERROR
void AddNote(nsIScriptErrorNote* note);
protected:
virtual ~nsScriptErrorBase();
void
InitializeOnMainThread();
nsCOMArray<nsIScriptErrorNote> mNotes;
nsString mMessage;
nsString mMessageName;
nsString mSourceName;
uint32_t mLineNumber;
nsString mSourceLine;
uint32_t mColumnNumber;
uint32_t mFlags;
nsCString mCategory;
// mOuterWindowID is set on the main thread from InitializeOnMainThread().
uint64_t mOuterWindowID;
uint64_t mInnerWindowID;
int64_t mTimeStamp;
// mInitializedOnMainThread and mIsFromPrivateWindow are set on the main
// thread from InitializeOnMainThread().
mozilla::Atomic<bool> mInitializedOnMainThread;
bool mIsFromPrivateWindow;
};
class nsScriptError final : public nsScriptErrorBase {
public:
nsScriptError() {}
NS_DECL_THREADSAFE_ISUPPORTS
private:
virtual ~nsScriptError() {}
};
class nsScriptErrorWithStack : public nsScriptErrorBase {
public:
explicit nsScriptErrorWithStack(JS::HandleObject);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack)
NS_IMETHOD Init(const nsAString& message,
const nsAString& sourceName,
const nsAString& sourceLine,
uint32_t lineNumber,
uint32_t columnNumber,
uint32_t flags,
const char* category) override;
NS_IMETHOD GetStack(JS::MutableHandleValue) override;
NS_IMETHOD ToString(nsACString& aResult) override;
private:
virtual ~nsScriptErrorWithStack();
// Complete stackframe where the error happened.
// Must be SavedFrame object.
JS::Heap<JSObject*> mStack;
};
#endif /* mozilla_dom_nsScriptError_h */

View file

@ -10,12 +10,14 @@
* that can store a SavedFrame stack trace object.
*/
#include "xpcprivate.h"
#include "nsScriptError.h"
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsGlobalWindow.h"
#include "nsCycleCollectionParticipant.h"
using namespace mozilla::dom;
namespace {

View file

@ -29,7 +29,9 @@ WebGLExtensionDebugShaders::GetTranslatedShaderSource(const WebGLShader& shader,
{
retval.SetIsVoid(true);
if (mIsLost || !mContext) return;
if (mIsLost || !mContext) {
return;
}
if (!mContext->ValidateObject("getShaderTranslatedSource: shader", shader))
return;

View file

@ -40,8 +40,10 @@ void
WebGLExtensionDisjointTimerQuery::DeleteQueryEXT(WebGLQuery* query) const
{
const char funcName[] = "deleteQueryEXT";
if (mIsLost || !mContext)
return;
if (mIsLost || !mContext) {
return;
}
mContext->DeleteQuery(query, funcName);
}
@ -50,8 +52,10 @@ bool
WebGLExtensionDisjointTimerQuery::IsQueryEXT(const WebGLQuery* query) const
{
const char funcName[] = "isQueryEXT";
if (mIsLost || !mContext)
return false;
if (mIsLost || !mContext) {
return false;
}
return mContext->IsQuery(query, funcName);
}
@ -60,8 +64,10 @@ void
WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target, WebGLQuery& query) const
{
const char funcName[] = "beginQueryEXT";
if (mIsLost || !mContext)
return;
if (mIsLost || !mContext) {
return;
}
mContext->BeginQuery(target, query, funcName);
}
@ -70,8 +76,10 @@ void
WebGLExtensionDisjointTimerQuery::EndQueryEXT(GLenum target) const
{
const char funcName[] = "endQueryEXT";
if (mIsLost || !mContext)
return;
if (mIsLost || !mContext) {
return;
}
mContext->EndQuery(target, funcName);
}
@ -80,8 +88,10 @@ void
WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLQuery& query, GLenum target) const
{
const char funcName[] = "queryCounterEXT";
if (mIsLost || !mContext)
return;
if (mIsLost || !mContext) {
return;
}
if (!mContext->ValidateObject(funcName, query))
return;
@ -95,8 +105,10 @@ WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, GLen
{
const char funcName[] = "getQueryEXT";
retval.setNull();
if (mIsLost || !mContext)
return;
if (mIsLost || !mContext) {
return;
}
mContext->GetQuery(cx, target, pname, retval, funcName);
}
@ -108,8 +120,10 @@ WebGLExtensionDisjointTimerQuery::GetQueryObjectEXT(JSContext* cx,
{
const char funcName[] = "getQueryObjectEXT";
retval.setNull();
if (mIsLost || !mContext)
return;
if (mIsLost || !mContext) {
return;
}
mContext->GetQueryParameter(cx, query, pname, retval, funcName);
}

View file

@ -31,8 +31,8 @@ WebGLExtensionInstancedArrays::DrawArraysInstancedANGLE(GLenum mode,
if (mContext) {
mContext->ErrorInvalidOperation("%s: Extension is lost.",
"drawArraysInstancedANGLE");
return;
}
return;
}
mContext->DrawArraysInstanced(mode, first, count, primcount);
@ -49,8 +49,8 @@ WebGLExtensionInstancedArrays::DrawElementsInstancedANGLE(GLenum mode,
if (mContext) {
mContext->ErrorInvalidOperation("%s: Extension is lost.",
"drawElementsInstancedANGLE");
return;
}
return;
}
mContext->DrawElementsInstanced(mode, count, type, offset, primcount);
@ -64,8 +64,8 @@ WebGLExtensionInstancedArrays::VertexAttribDivisorANGLE(GLuint index,
if (mContext) {
mContext->ErrorInvalidOperation("%s: Extension is lost.",
"vertexAttribDivisorANGLE");
return;
}
return;
}
mContext->VertexAttribDivisor(index, divisor);

View file

@ -8,7 +8,6 @@
#include "mozilla/WeakPtr.h"
#include "nsCycleCollectionNoteChild.h"
#include "WebGLTypes.h"
namespace mozilla {

View file

@ -1381,7 +1381,7 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh
return NS_ERROR_FAILURE;
}
// Don't allow cross-origin 307 POST redirects.
// Don't allow cross-origin 307/308 POST redirects.
nsCOMPtr<nsIHttpChannel> oldHttpChannel(do_QueryInterface(oldChannel));
if (oldHttpChannel) {
uint32_t responseStatus;
@ -1389,7 +1389,7 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh
if (NS_FAILED(rv)) {
return rv;
}
if (responseStatus == 307) {
if (responseStatus == 307 || responseStatus == 308) {
nsAutoCString method;
rv = oldHttpChannel->GetRequestMethod(method);
if (NS_FAILED(rv)) {

View file

@ -988,7 +988,7 @@ Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj)
}
if (existing) {
js::Wrapper::Renew(cx, existing, obj, wrapper);
js::Wrapper::Renew(existing, obj, wrapper);
}
return js::Wrapper::New(cx, obj, wrapper);
}

View file

@ -87,6 +87,7 @@
#include "nsProxyRelease.h"
#include "nsQueryObject.h"
#include "nsSandboxFlags.h"
#include "nsScriptError.h"
#include "nsUTF8Utils.h"
#include "prthread.h"
#include "xpcpublic.h"
@ -281,27 +282,34 @@ struct WindowAction
};
void
LogErrorToConsole(const nsAString& aMessage,
const nsAString& aFilename,
const nsAString& aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
uint32_t aFlags,
uint64_t aInnerWindowId)
LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId)
{
AssertIsOnMainThread();
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
RefPtr<nsScriptErrorBase> scriptError = new nsScriptError();
NS_WARNING_ASSERTION(scriptError, "Failed to create script error!");
if (scriptError) {
if (NS_FAILED(scriptError->InitWithWindowID(aMessage, aFilename, aLine,
aLineNumber, aColumnNumber,
aFlags, "Web Worker",
nsAutoCString category("Web Worker");
if (NS_FAILED(scriptError->InitWithWindowID(aReport.mMessage,
aReport.mFilename,
aReport.mLine,
aReport.mLineNumber,
aReport.mColumnNumber,
aReport.mFlags,
category,
aInnerWindowId))) {
NS_WARNING("Failed to init script error!");
scriptError = nullptr;
for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) {
const WorkerErrorNote& note = aReport.mNotes.ElementAt(i);
nsScriptErrorNote* noteObject = new nsScriptErrorNote();
noteObject->Init(note.mMessage, note.mFilename,
note.mLineNumber, note.mColumnNumber);
scriptError->AddNote(noteObject);
}
}
}
@ -316,23 +324,23 @@ LogErrorToConsole(const nsAString& aMessage,
}
NS_WARNING("LogMessage failed!");
} else if (NS_SUCCEEDED(consoleService->LogStringMessage(
aMessage.BeginReading()))) {
aReport.mMessage.BeginReading()))) {
return;
}
NS_WARNING("LogStringMessage failed!");
}
NS_ConvertUTF16toUTF8 msg(aMessage);
NS_ConvertUTF16toUTF8 filename(aFilename);
NS_ConvertUTF16toUTF8 msg(aReport.mMessage);
NS_ConvertUTF16toUTF8 filename(aReport.mFilename);
static const char kErrorString[] = "JS error in Web Worker: %s [%s:%u]";
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", kErrorString, msg.get(),
filename.get(), aLineNumber);
filename.get(), aReport.mLineNumber);
#endif
fprintf(stderr, kErrorString, msg.get(), filename.get(), aLineNumber);
fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.mLineNumber);
fflush(stderr);
}
@ -536,10 +544,7 @@ private:
}
if (aWorkerPrivate->IsSharedWorker()) {
aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, EmptyString(),
EmptyString(),
EmptyString(), 0, 0,
JSREPORT_ERROR,
aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, nullptr,
/* isErrorEvent */ false);
return true;
}
@ -1060,15 +1065,7 @@ private:
class ReportErrorRunnable final : public WorkerRunnable
{
nsString mMessage;
nsString mFilename;
nsString mLine;
uint32_t mLineNumber;
uint32_t mColumnNumber;
uint32_t mFlags;
uint32_t mErrorNumber;
JSExnType mExnType;
bool mMutedError;
WorkerErrorReport mReport;
public:
// aWorkerPrivate is the worker thread we're on (or the main thread, if null)
@ -1077,11 +1074,7 @@ public:
static void
ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aFireAtScope, WorkerPrivate* aTarget,
const nsString& aMessage, const nsString& aFilename,
const nsString& aLine, uint32_t aLineNumber,
uint32_t aColumnNumber, uint32_t aFlags,
uint32_t aErrorNumber, JSExnType aExnType,
bool aMutedError, uint64_t aInnerWindowId,
const WorkerErrorReport& aReport, uint64_t aInnerWindowId,
JS::Handle<JS::Value> aException = JS::NullHandleValue)
{
if (aWorkerPrivate) {
@ -1092,16 +1085,16 @@ public:
// We should not fire error events for warnings but instead make sure that
// they show up in the error console.
if (!JSREPORT_IS_WARNING(aFlags)) {
if (!JSREPORT_IS_WARNING(aReport.mFlags)) {
// First fire an ErrorEvent at the worker.
RootedDictionary<ErrorEventInit> init(aCx);
if (aMutedError) {
if (aReport.mMutedError) {
init.mMessage.AssignLiteral("Script error.");
} else {
init.mMessage = aMessage;
init.mFilename = aFilename;
init.mLineno = aLineNumber;
init.mMessage = aReport.mMessage;
init.mFilename = aReport.mFilename;
init.mLineno = aReport.mLineNumber;
init.mError = aException;
}
@ -1128,7 +1121,8 @@ public:
// into an error event on our parent worker!
// https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks making this
// better.
if (aFireAtScope && (aTarget || aErrorNumber != JSMSG_OVER_RECURSED)) {
if (aFireAtScope &&
(aTarget || aReport.mErrorNumber != JSMSG_OVER_RECURSED)) {
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
NS_ASSERTION(global, "This should never be null!");
@ -1145,8 +1139,8 @@ public:
MOZ_ASSERT_IF(globalScope, globalScope->GetWrapperPreserveColor() == global);
if (globalScope || IsDebuggerSandbox(global)) {
aWorkerPrivate->ReportErrorToDebugger(aFilename, aLineNumber,
aMessage);
aWorkerPrivate->ReportErrorToDebugger(aReport.mFilename, aReport.mLineNumber,
aReport.mMessage);
return;
}
@ -1193,28 +1187,20 @@ public:
// Now fire a runnable to do the same on the parent's thread if we can.
if (aWorkerPrivate) {
RefPtr<ReportErrorRunnable> runnable =
new ReportErrorRunnable(aWorkerPrivate, aMessage, aFilename, aLine,
aLineNumber, aColumnNumber, aFlags,
aErrorNumber, aExnType, aMutedError);
new ReportErrorRunnable(aWorkerPrivate, aReport);
runnable->Dispatch();
return;
}
// Otherwise log an error to the error console.
LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber,
aFlags, aInnerWindowId);
LogErrorToConsole(aReport, aInnerWindowId);
}
private:
ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, const nsString& aMessage,
const nsString& aFilename, const nsString& aLine,
uint32_t aLineNumber, uint32_t aColumnNumber,
uint32_t aFlags, uint32_t aErrorNumber,
JSExnType aExnType, bool aMutedError)
ReportErrorRunnable(WorkerPrivate* aWorkerPrivate,
const WorkerErrorReport& aReport)
: WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
mMessage(aMessage), mFilename(aFilename), mLine(aLine),
mLineNumber(aLineNumber), mColumnNumber(aColumnNumber), mFlags(aFlags),
mErrorNumber(aErrorNumber), mExnType(aExnType), mMutedError(aMutedError)
mReport(aReport)
{ }
virtual void
@ -1251,9 +1237,7 @@ private:
}
if (aWorkerPrivate->IsSharedWorker()) {
aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename,
mLine, mLineNumber,
mColumnNumber, mFlags,
aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, &mReport,
/* isErrorEvent */ true);
return true;
}
@ -1267,9 +1251,10 @@ private:
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
aWorkerPrivate->WorkerName(),
aWorkerPrivate->ScriptURL(),
mMessage,
mFilename, mLine, mLineNumber,
mColumnNumber, mFlags, mExnType);
mReport.mMessage,
mReport.mFilename, mReport.mLine, mReport.mLineNumber,
mReport.mColumnNumber, mReport.mFlags,
mReport.mExnType);
}
return true;
}
@ -1289,9 +1274,8 @@ private:
return true;
}
ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mMessage,
mFilename, mLine, mLineNumber, mColumnNumber, mFlags,
mErrorNumber, mExnType, mMutedError, innerWindowId);
ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mReport,
innerWindowId);
return true;
}
};
@ -3314,21 +3298,16 @@ template <class Derived>
void
WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
JSContext* aCx,
const nsAString& aMessage,
const nsAString& aFilename,
const nsAString& aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
uint32_t aFlags,
const WorkerErrorReport* aReport,
bool aIsErrorEvent)
{
AssertIsOnMainThread();
if (JSREPORT_IS_WARNING(aFlags)) {
if (aIsErrorEvent && JSREPORT_IS_WARNING(aReport->mFlags)) {
// Don't fire any events anywhere. Just log to console.
// XXXbz should we log to all the consoles of all the relevant windows?
LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber,
aFlags, 0);
MOZ_ASSERT(aReport);
LogErrorToConsole(*aReport, 0);
return;
}
@ -3357,10 +3336,10 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
RootedDictionary<ErrorEventInit> errorInit(aCx);
errorInit.mBubbles = false;
errorInit.mCancelable = true;
errorInit.mMessage = aMessage;
errorInit.mFilename = aFilename;
errorInit.mLineno = aLineNumber;
errorInit.mColno = aColumnNumber;
errorInit.mMessage = aReport->mMessage;
errorInit.mFilename = aReport->mFilename;
errorInit.mLineno = aReport->mLineNumber;
errorInit.mColno = aReport->mColumnNumber;
event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
errorInit);
@ -3426,9 +3405,9 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
MOZ_ASSERT(NS_IsMainThread());
RootedDictionary<ErrorEventInit> init(aCx);
init.mLineno = aLineNumber;
init.mFilename = aFilename;
init.mMessage = aMessage;
init.mLineno = aReport->mLineNumber;
init.mFilename = aReport->mFilename;
init.mMessage = aReport->mMessage;
init.mCancelable = true;
init.mBubbles = true;
@ -3446,8 +3425,8 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
// Finally log a warning in the console if no window tried to prevent it.
if (shouldLogErrorToConsole) {
LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber,
aFlags, 0);
MOZ_ASSERT(aReport);
LogErrorToConsole(*aReport, 0);
}
}
@ -4120,7 +4099,10 @@ WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
listeners[index]->OnError(aFilename, aLineno, aMessage);
}
LogErrorToConsole(aMessage, aFilename, nsString(), aLineno, 0, 0, 0);
WorkerErrorReport report;
report.mMessage = aMessage;
report.mFilename = aFilename;
LogErrorToConsole(report, 0);
}
WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
@ -5925,6 +5907,47 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
return false;
}
void
WorkerErrorBase::AssignErrorBase(JSErrorBase* aReport)
{
mFilename = NS_ConvertUTF8toUTF16(aReport->filename);
mLineNumber = aReport->lineno;
mColumnNumber = aReport->column;
mErrorNumber = aReport->errorNumber;
}
void
WorkerErrorNote::AssignErrorNote(JSErrorNotes::Note* aNote)
{
WorkerErrorBase::AssignErrorBase(aNote);
xpc::ErrorNote::ErrorNoteToMessageString(aNote, mMessage);
}
void
WorkerErrorReport::AssignErrorReport(JSErrorReport* aReport)
{
WorkerErrorBase::AssignErrorBase(aReport);
xpc::ErrorReport::ErrorReportToMessageString(aReport, mMessage);
mLine.Assign(aReport->linebuf(), aReport->linebufLength());
mFlags = aReport->flags;
MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT);
mExnType = JSExnType(aReport->exnType);
mMutedError = aReport->isMuted;
if (aReport->notes) {
if (!mNotes.SetLength(aReport->notes->length(), fallible)) {
return;
}
size_t i = 0;
for (auto&& note : *aReport->notes) {
mNotes.ElementAt(i).AssignErrorNote(note.get());
i++;
}
}
}
void
WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
JSErrorReport* aReport)
@ -5947,32 +5970,17 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
}
JS_ClearPendingException(aCx);
nsString message, filename, line;
uint32_t lineNumber, columnNumber, flags, errorNumber;
JSExnType exnType = JSEXN_ERR;
bool mutedError = aReport && aReport->isMuted;
WorkerErrorReport report;
if (aReport) {
// We want the same behavior here as xpc::ErrorReport::init here.
xpc::ErrorReport::ErrorReportToMessageString(aReport, message);
filename = NS_ConvertUTF8toUTF16(aReport->filename);
line.Assign(aReport->linebuf(), aReport->linebufLength());
lineNumber = aReport->lineno;
columnNumber = aReport->tokenOffset();
flags = aReport->flags;
errorNumber = aReport->errorNumber;
MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT);
exnType = JSExnType(aReport->exnType);
report.AssignErrorReport(aReport);
}
else {
lineNumber = columnNumber = errorNumber = 0;
flags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
report.mFlags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
}
if (message.IsEmpty() && aToStringResult) {
if (report.mMessage.IsEmpty() && aToStringResult) {
nsDependentCString toStringResult(aToStringResult.c_str());
if (!AppendUTF8toUTF16(toStringResult, message, mozilla::fallible)) {
if (!AppendUTF8toUTF16(toStringResult, report.mMessage, mozilla::fallible)) {
// Try again, with only a 1 KB string. Do this infallibly this time.
// If the user doesn't have 1 KB to spare we're done anyways.
uint32_t index = std::min(uint32_t(1024), toStringResult.Length());
@ -5982,7 +5990,7 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
nsDependentCString truncatedToStringResult(aToStringResult.c_str(),
index);
AppendUTF8toUTF16(truncatedToStringResult, message);
AppendUTF8toUTF16(truncatedToStringResult, report.mMessage);
}
}
@ -5991,13 +5999,11 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
// Don't want to run the scope's error handler if this is a recursive error or
// if we ran out of memory.
bool fireAtScope = mErrorHandlerRecursionCount == 1 &&
errorNumber != JSMSG_OUT_OF_MEMORY &&
report.mErrorNumber != JSMSG_OUT_OF_MEMORY &&
JS::CurrentGlobalOrNull(aCx);
ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message,
filename, line, lineNumber,
columnNumber, flags, errorNumber, exnType,
mutedError, 0, exn);
ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, report, 0,
exn);
mErrorHandlerRecursionCount--;
}

View file

@ -140,6 +140,45 @@ public:
}
};
class WorkerErrorBase {
public:
nsString mMessage;
nsString mFilename;
uint32_t mLineNumber;
uint32_t mColumnNumber;
uint32_t mErrorNumber;
WorkerErrorBase()
: mLineNumber(0),
mColumnNumber(0),
mErrorNumber(0)
{ }
void AssignErrorBase(JSErrorBase* aReport);
};
class WorkerErrorNote : public WorkerErrorBase {
public:
void AssignErrorNote(JSErrorNotes::Note* aNote);
};
class WorkerErrorReport : public WorkerErrorBase {
public:
nsString mLine;
uint32_t mFlags;
JSExnType mExnType;
bool mMutedError;
nsTArray<WorkerErrorNote> mNotes;
WorkerErrorReport()
: mFlags(0),
mExnType(JSEXN_ERR),
mMutedError(false)
{ }
void AssignErrorReport(JSErrorReport* aReport);
};
template <class Derived>
class WorkerPrivateParent : public DOMEventTargetHelper
{
@ -401,12 +440,7 @@ public:
void
BroadcastErrorToSharedWorkers(JSContext* aCx,
const nsAString& aMessage,
const nsAString& aFilename,
const nsAString& aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
uint32_t aFlags,
const WorkerErrorReport* aReport,
bool aIsErrorEvent);
void

View file

@ -94,6 +94,7 @@ LOCAL_INCLUDES += [
'../base',
'../system',
'/dom/base',
'/dom/bindings',
'/xpcom/build',
'/xpcom/threads',
]

View file

@ -23,7 +23,7 @@
const errorFilename = href.substring(0, href.lastIndexOf("/") + 1) +
filename;
const errorLine = 91;
const errorColumn = 0;
const errorColumn = 11;
var worker = new SharedWorker(filename);

View file

@ -9,6 +9,7 @@
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsJSUtils.h"
#include "nsIScriptError.h"
#include "jsfriendapi.h"
#include "jswrapper.h"
#include "js/Proxy.h"

View file

@ -128,7 +128,10 @@ class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval
protected:
Value* argv_;
unsigned argc_;
bool constructing_;
bool constructing_:1;
// True if the caller does not use the return value.
bool ignoresReturnValue_:1;
public:
// CALLEE ACCESS
@ -164,6 +167,10 @@ class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval
return true;
}
bool ignoresReturnValue() const {
return ignoresReturnValue_;
}
MutableHandleValue newTarget() const {
MOZ_ASSERT(constructing_);
return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]);
@ -280,14 +287,17 @@ class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsed
{
private:
friend CallArgs CallArgsFromVp(unsigned argc, Value* vp);
friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing);
friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing,
bool ignoresReturnValue);
static CallArgs create(unsigned argc, Value* argv, bool constructing) {
static CallArgs create(unsigned argc, Value* argv, bool constructing,
bool ignoresReturnValue = false) {
CallArgs args;
args.clearUsedRval();
args.argv_ = argv;
args.argc_ = argc;
args.constructing_ = constructing;
args.ignoresReturnValue_ = ignoresReturnValue;
#ifdef DEBUG
for (unsigned i = 0; i < argc; ++i)
MOZ_ASSERT_IF(argv[i].isGCThing(), !GCThingIsMarkedGray(GCCellPtr(argv[i])));
@ -314,9 +324,11 @@ CallArgsFromVp(unsigned argc, Value* vp)
// eventually move it to an internal header. Embedders should use
// JS::CallArgsFromVp!
MOZ_ALWAYS_INLINE CallArgs
CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false)
CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false,
bool ignoresReturnValue = false)
{
return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing);
return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing,
ignoresReturnValue);
}
} // namespace JS

View file

@ -1117,7 +1117,7 @@ JSObject*
AtomicsObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
{
// Create Atomics Object.
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!objProto)
return nullptr;
RootedObject Atomics(cx, NewObjectWithGivenProto(cx, &AtomicsObject::class_, objProto,

View file

@ -270,7 +270,7 @@ Collator(JSContext* cx, const CallArgs& args, bool construct)
// See https://github.com/tc39/ecma402/issues/57
if (!construct) {
// ES Intl 1st ed., 10.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global());
if (!intl)
return false;
RootedValue self(cx, args.thisv());
@ -298,7 +298,7 @@ Collator(JSContext* cx, const CallArgs& args, bool construct)
return false;
if (!proto) {
proto = cx->global()->getOrCreateCollatorPrototype(cx);
proto = GlobalObject::getOrCreateCollatorPrototype(cx, cx->global());
if (!proto)
return false;
}
@ -358,11 +358,12 @@ collator_finalize(FreeOp* fop, JSObject* obj)
static JSObject*
CreateCollatorPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global)
{
RootedFunction ctor(cx, global->createConstructor(cx, &Collator, cx->names().Collator, 0));
RootedFunction ctor(cx, GlobalObject::createConstructor(cx, &Collator, cx->names().Collator,
0));
if (!ctor)
return nullptr;
RootedNativeObject proto(cx, global->createBlankPrototype(cx, &CollatorClass));
RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &CollatorClass));
if (!proto)
return nullptr;
proto->setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr));
@ -772,7 +773,7 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
// See https://github.com/tc39/ecma402/issues/57
if (!construct) {
// ES Intl 1st ed., 11.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global());
if (!intl)
return false;
RootedValue self(cx, args.thisv());
@ -800,7 +801,7 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
return false;
if (!proto) {
proto = cx->global()->getOrCreateNumberFormatPrototype(cx);
proto = GlobalObject::getOrCreateNumberFormatPrototype(cx, cx->global());
if (!proto)
return false;
}
@ -862,11 +863,12 @@ static JSObject*
CreateNumberFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global)
{
RootedFunction ctor(cx);
ctor = global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0);
ctor = GlobalObject::createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0);
if (!ctor)
return nullptr;
RootedNativeObject proto(cx, global->createBlankPrototype(cx, &NumberFormatClass));
RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global,
&NumberFormatClass));
if (!proto)
return nullptr;
proto->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
@ -1250,7 +1252,7 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
// See https://github.com/tc39/ecma402/issues/57
if (!construct) {
// ES Intl 1st ed., 12.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global());
if (!intl)
return false;
RootedValue self(cx, args.thisv());
@ -1278,7 +1280,7 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
return false;
if (!proto) {
proto = cx->global()->getOrCreateDateTimeFormatPrototype(cx);
proto = GlobalObject::getOrCreateDateTimeFormatPrototype(cx, cx->global());
if (!proto)
return false;
}
@ -1340,11 +1342,12 @@ static JSObject*
CreateDateTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global)
{
RootedFunction ctor(cx);
ctor = global->createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0);
ctor = GlobalObject::createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0);
if (!ctor)
return nullptr;
RootedNativeObject proto(cx, global->createBlankPrototype(cx, &DateTimeFormatClass));
RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global,
&DateTimeFormatClass));
if (!proto)
return nullptr;
proto->setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr));
@ -2731,10 +2734,10 @@ static const JSFunctionSpec intl_static_methods[] = {
* Initializes the Intl Object and its standard built-in properties.
* Spec: ECMAScript Internationalization API Specification, 8.0, 8.1
*/
bool
/* static */ bool
GlobalObject::initIntlObject(JSContext* cx, Handle<GlobalObject*> global)
{
RootedObject proto(cx, global->getOrCreateObjectPrototype(cx));
RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!proto)
return false;

View file

@ -164,7 +164,7 @@ MapIteratorObject::kind() const
return MapObject::IteratorKind(i);
}
bool
/* static */ bool
GlobalObject::initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
{
Rooted<JSObject*> base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));
@ -924,7 +924,7 @@ SetIteratorObject::kind() const
return SetObject::IteratorKind(i);
}
bool
/* static */ bool
GlobalObject::initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
{
Rooted<JSObject*> base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));

View file

@ -103,7 +103,7 @@ GlobalObject::initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global)
JS_PS_END
};
RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx));
RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
if (!proto)
return false;
@ -169,7 +169,7 @@ GlobalObject::initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global)
JS_PS_END
};
RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx));
RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
if (!proto)
return false;
@ -788,7 +788,7 @@ AssertModuleScopesMatch(ModuleObject* module)
}
void
ModuleObject::fixEnvironmentsAfterCompartmentMerge(JSContext* cx)
ModuleObject::fixEnvironmentsAfterCompartmentMerge()
{
AssertModuleScopesMatch(this);
initialEnvironment().fixEnclosingEnvironmentAfterCompartmentMerge(script()->global());
@ -1020,7 +1020,7 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global)
JS_FS_END
};
RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx));
RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
if (!proto)
return false;

View file

@ -244,7 +244,7 @@ class ModuleObject : public NativeObject
#ifdef DEBUG
static bool IsFrozen(JSContext* cx, HandleModuleObject self);
#endif
void fixEnvironmentsAfterCompartmentMerge(JSContext* cx);
void fixEnvironmentsAfterCompartmentMerge();
JSScript* script() const;
Scope* enclosingScope() const;

View file

@ -525,18 +525,6 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
return true;
}
bool
js::obj_valueOf(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
static bool
obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
{
@ -1301,7 +1289,7 @@ static const JSFunctionSpec object_methods[] = {
#endif
JS_FN(js_toString_str, obj_toString, 0,0),
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0),
JS_FN(js_valueOf_str, obj_valueOf, 0,0),
JS_SELF_HOSTED_FN(js_valueOf_str, "Object_valueOf", 0,0),
#if JS_HAS_OBJ_WATCHPOINT
JS_FN(js_watch_str, obj_watch, 2,0),
JS_FN(js_unwatch_str, obj_unwatch, 1,0),
@ -1420,8 +1408,8 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro
* only set the [[Prototype]] if it hasn't already been set.
*/
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
if (global->shouldSplicePrototype(cx)) {
if (!global->splicePrototype(cx, global->getClass(), tagged))
if (global->shouldSplicePrototype()) {
if (!JSObject::splicePrototype(cx, global, global->getClass(), tagged))
return false;
}
return true;

View file

@ -25,9 +25,6 @@ obj_construct(JSContext* cx, unsigned argc, JS::Value* vp);
MOZ_MUST_USE bool
obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool
obj_valueOf(JSContext* cx, unsigned argc, JS::Value* vp);
PlainObject*
ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind = GenericObject,
HandleObjectGroup group = nullptr);

View file

@ -87,6 +87,12 @@ function Object_toLocaleString() {
return callContentFunction(O.toString, O);
}
// ES 2017 draft bb96899bb0d9ef9be08164a26efae2ee5f25e875 19.1.3.7
function Object_valueOf() {
// Step 1.
return ToObject(this);
}
// ES7 draft (2016 March 8) B.2.2.3
function ObjectDefineSetter(name, setter) {
// Step 1.

View file

@ -603,7 +603,7 @@ ResolvePromise(JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueO
// Now that everything else is done, do the things the debugger needs.
// Step 7 of RejectPromise implemented in onSettled.
promise->onSettled(cx);
PromiseObject::onSettled(cx, promise);
// Step 7 of FulfillPromise.
// Step 8 of RejectPromise.
@ -1947,26 +1947,23 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
}
// ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5.
static MOZ_MUST_USE bool
CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, ResolutionMode mode)
static MOZ_MUST_USE JSObject*
CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal,
ResolutionMode mode)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue x(cx, args.get(0));
// Steps 1-2.
if (!args.thisv().isObject()) {
if (!thisVal.isObject()) {
const char* msg = mode == ResolveMode
? "Receiver of Promise.resolve call"
: "Receiver of Promise.reject call";
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg);
return false;
return nullptr;
}
RootedValue cVal(cx, args.thisv());
RootedObject C(cx, &cVal.toObject());
RootedObject C(cx, &thisVal.toObject());
// Step 3 of Resolve.
if (mode == ResolveMode && x.isObject()) {
RootedObject xObj(cx, &x.toObject());
if (mode == ResolveMode && argVal.isObject()) {
RootedObject xObj(cx, &argVal.toObject());
bool isPromise = false;
if (xObj->is<PromiseObject>()) {
isPromise = true;
@ -1985,11 +1982,9 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
if (isPromise) {
RootedValue ctorVal(cx);
if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal))
return false;
if (ctorVal == cVal) {
args.rval().set(x);
return true;
}
return nullptr;
if (ctorVal == thisVal)
return xObj;
}
}
@ -1998,15 +1993,17 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
RootedObject resolveFun(cx);
RootedObject rejectFun(cx);
if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true))
return false;
return nullptr;
// Step 5 of Resolve, 4 of Reject.
if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, x, mode, promise))
return false;
if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode,
promise))
{
return nullptr;
}
// Step 6 of Resolve, 4 of Reject.
args.rval().setObject(*promise);
return true;
return promise;
}
/**
@ -2015,7 +2012,14 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
bool
js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
{
return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode);
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue thisVal(cx, args.thisv());
RootedValue argVal(cx, args.get(0));
JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode);
if (!result)
return false;
args.rval().setObject(*result);
return true;
}
/**
@ -2024,19 +2028,11 @@ js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
/* static */ JSObject*
PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
{
// Steps 1-2 (omitted).
// Roughly step 3.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
if (!promise)
RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
if (!promiseCtor)
return nullptr;
// Roughly step 4.
if (!ResolvePromise(cx, promise, value, JS::PromiseState::Rejected))
return nullptr;
// Step 5.
return promise;
RootedValue cVal(cx, ObjectValue(*promiseCtor));
return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode);
}
/**
@ -2045,7 +2041,14 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
bool
js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
{
return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode);
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue thisVal(cx, args.thisv());
RootedValue argVal(cx, args.get(0));
JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode);
if (!result)
return false;
args.rval().setObject(*result);
return true;
}
/**
@ -2054,30 +2057,11 @@ js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
/* static */ JSObject*
PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
{
// Steps 1-2 (omitted).
// Step 3.
if (value.isObject()) {
JSObject* obj = &value.toObject();
if (IsWrapper(obj))
obj = CheckedUnwrap(obj);
// Instead of getting the `constructor` property, do an unforgeable
// check.
if (obj && obj->is<PromiseObject>())
return obj;
}
// Step 4.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
if (!promise)
RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
if (!promiseCtor)
return nullptr;
// Steps 5.
if (!ResolvePromiseInternal(cx, promise, value))
return nullptr;
// Step 6.
return promise;
RootedValue cVal(cx, ObjectValue(*promiseCtor));
return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
}
// ES2016, 25.4.4.6, implemented in Promise.js.
@ -2647,14 +2631,14 @@ PromiseObject::dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> v
return true;
}
bool
PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue)
/* static */ bool
PromiseObject::resolve(JSContext* cx, Handle<PromiseObject*> promise, HandleValue resolutionValue)
{
MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC));
if (state() != JS::PromiseState::Pending)
MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC));
if (promise->state() != JS::PromiseState::Pending)
return true;
RootedObject resolveFun(cx, GetResolveFunctionFromPromise(this));
RootedObject resolveFun(cx, GetResolveFunctionFromPromise(promise));
RootedValue funVal(cx, ObjectValue(*resolveFun));
// For xray'd Promises, the resolve fun may have been created in another
@ -2670,14 +2654,14 @@ PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue)
return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
}
bool
PromiseObject::reject(JSContext* cx, HandleValue rejectionValue)
/* static */ bool
PromiseObject::reject(JSContext* cx, Handle<PromiseObject*> promise, HandleValue rejectionValue)
{
MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC));
if (state() != JS::PromiseState::Pending)
MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC));
if (promise->state() != JS::PromiseState::Pending)
return true;
RootedValue funVal(cx, this->getFixedSlot(PromiseSlot_RejectFunction));
RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction));
MOZ_ASSERT(IsCallable(funVal));
FixedInvokeArgs<1> args(cx);
@ -2687,10 +2671,9 @@ PromiseObject::reject(JSContext* cx, HandleValue rejectionValue)
return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
}
void
PromiseObject::onSettled(JSContext* cx)
/* static */ void
PromiseObject::onSettled(JSContext* cx, Handle<PromiseObject*> promise)
{
Rooted<PromiseObject*> promise(cx, this);
RootedObject stack(cx);
if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) {
@ -2750,7 +2733,7 @@ PromiseTask::executeAndFinish(JSContext* cx)
static JSObject*
CreatePromisePrototype(JSContext* cx, JSProtoKey key)
{
return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_);
return GlobalObject::createBlankPrototype(cx, cx->global(), &PromiseObject::protoClass_);
}
static const JSFunctionSpec promise_methods[] = {

View file

@ -66,10 +66,12 @@ class PromiseObject : public NativeObject
return getFixedSlot(PromiseSlot_ReactionsOrResult);
}
MOZ_MUST_USE bool resolve(JSContext* cx, HandleValue resolutionValue);
MOZ_MUST_USE bool reject(JSContext* cx, HandleValue rejectionValue);
static MOZ_MUST_USE bool resolve(JSContext* cx, Handle<PromiseObject*> promise,
HandleValue resolutionValue);
static MOZ_MUST_USE bool reject(JSContext* cx, Handle<PromiseObject*> promise,
HandleValue rejectionValue);
void onSettled(JSContext* cx);
static void onSettled(JSContext* cx, Handle<PromiseObject*> promise);
double allocationTime() { return getFixedSlot(PromiseSlot_AllocationTime).toNumber(); }
double resolutionTime() { return getFixedSlot(PromiseSlot_ResolutionTime).toNumber(); }

View file

@ -268,7 +268,8 @@ static const JSFunctionSpec methods[] = {
JSObject*
js::InitReflect(JSContext* cx, HandleObject obj)
{
RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
Handle<GlobalObject*> global = obj.as<GlobalObject>();
RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!proto)
return nullptr;

View file

@ -3044,7 +3044,12 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
RootedValue expr(cx);
expr.setString(next->pn_atom);
if (next->isKind(PNK_RAW_UNDEFINED)) {
expr.setUndefined();
} else {
MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING));
expr.setString(next->pn_atom);
}
cooked.infallibleAppend(expr);
}
@ -3136,6 +3141,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
return literal(pn, dst);
case PNK_YIELD_STAR:
@ -3216,6 +3222,8 @@ ASTSerializer::property(ParseNode* pn, MutableHandleValue dst)
return expression(pn->pn_kid, &val) &&
builder.prototypeMutation(val, &pn->pn_pos, dst);
}
if (pn->isKind(PNK_SPREAD))
return expression(pn, dst);
PropKind kind;
switch (pn->getOp()) {
@ -3276,6 +3284,10 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst)
val.setNull();
break;
case PNK_RAW_UNDEFINED:
val.setUndefined();
break;
case PNK_TRUE:
val.setBoolean(true);
break;
@ -3332,6 +3344,16 @@ ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst)
return false;
for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) {
if (propdef->isKind(PNK_SPREAD)) {
RootedValue target(cx);
RootedValue spread(cx);
if (!pattern(propdef->pn_kid, &target))
return false;
if(!builder.spreadExpression(target, &propdef->pn_pos, &spread))
return false;
elts.infallibleAppend(spread);
continue;
}
LOCAL_ASSERT(propdef->isKind(PNK_MUTATEPROTO) != propdef->isOp(JSOP_INITPROP));
RootedValue key(cx);
@ -3407,12 +3429,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
: GeneratorStyle::None;
bool isAsync = pn->pn_funbox->isAsync();
bool isExpression =
#if JS_HAS_EXPR_CLOSURES
func->isExprBody();
#else
false;
#endif
bool isExpression = pn->pn_funbox->isExprBody();
RootedValue id(cx);
RootedAtom funcAtom(cx, func->explicitName());

View file

@ -140,12 +140,12 @@ ExecuteRegExpImpl(JSContext* cx, RegExpStatics* res, RegExpShared& re, HandleLin
/* Legacy ExecuteRegExp behavior is baked into the JSAPI. */
bool
js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj,
js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle<RegExpObject*> reobj,
HandleLinearString input, size_t* lastIndex, bool test,
MutableHandleValue rval)
{
RegExpGuard shared(cx);
if (!reobj.getShared(cx, &shared))
if (!RegExpObject::getShared(cx, reobj, &shared))
return false;
ScopedMatchPairs matches(&cx->tempLifoAlloc());
@ -801,7 +801,7 @@ const JSFunctionSpec js::regexp_methods[] = {
name(JSContext* cx, unsigned argc, Value* vp) \
{ \
CallArgs args = CallArgsFromVp(argc, vp); \
RegExpStatics* res = cx->global()->getRegExpStatics(cx); \
RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); \
if (!res) \
return false; \
code; \
@ -827,7 +827,7 @@ DEFINE_STATIC_GETTER(static_paren9_getter, STATIC_PAREN_GETTER_CODE(9))
static bool \
name(JSContext* cx, unsigned argc, Value* vp) \
{ \
RegExpStatics* res = cx->global()->getRegExpStatics(cx); \
RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); \
if (!res) \
return false; \
code; \
@ -838,7 +838,7 @@ static bool
static_input_setter(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RegExpStatics* res = cx->global()->getRegExpStatics(cx);
RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global());
if (!res)
return false;
@ -918,12 +918,12 @@ ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string,
Rooted<RegExpObject*> reobj(cx, &regexp->as<RegExpObject>());
RegExpGuard re(cx);
if (!reobj->getShared(cx, &re))
if (!RegExpObject::getShared(cx, reobj, &re))
return RegExpRunStatus_Error;
RegExpStatics* res;
if (staticsUpdate == UpdateRegExpStatics) {
res = cx->global()->getRegExpStatics(cx);
res = GlobalObject::getRegExpStatics(cx, cx->global());
if (!res)
return RegExpRunStatus_Error;
} else {
@ -1725,7 +1725,7 @@ js::intrinsic_GetElemBaseForLambda(JSContext* cx, unsigned argc, Value* vp)
if (!fun->isInterpreted() || fun->isClassConstructor())
return true;
JSScript* script = fun->getOrCreateScript(cx);
JSScript* script = JSFunction::getOrCreateScript(cx, fun);
if (!script)
return false;
@ -1800,7 +1800,7 @@ js::intrinsic_GetStringDataProperty(JSContext* cx, unsigned argc, Value* vp)
return false;
RootedValue v(cx);
if (HasDataProperty(cx, nobj, AtomToId(atom), v.address()) && v.isString())
if (GetPropertyPure(cx, nobj, AtomToId(atom), v.address()) && v.isString())
args.rval().set(v);
else
args.rval().setUndefined();

View file

@ -31,7 +31,7 @@ enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics };
* |chars| and |length|.
*/
MOZ_MUST_USE bool
ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj,
ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle<RegExpObject*> reobj,
HandleLinearString input, size_t* lastIndex, bool test,
MutableHandleValue rval);

View file

@ -475,7 +475,7 @@ const Class SimdObject::class_ = {
&SimdObjectClassOps
};
bool
/* static */ bool
GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global)
{
// SIMD relies on the TypedObject module being initialized.
@ -483,11 +483,11 @@ GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global)
// to be able to call GetTypedObjectModule(). It is NOT necessary
// to install the TypedObjectModule global, but at the moment
// those two things are not separable.
if (!global->getOrCreateTypedObjectModule(cx))
if (!GlobalObject::getOrCreateTypedObjectModule(cx, global))
return false;
RootedObject globalSimdObject(cx);
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!objProto)
return false;
@ -510,7 +510,7 @@ static bool
CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr,
SimdType simdType, const JSFunctionSpec* methods)
{
RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global));
if (!funcProto)
return false;
@ -531,7 +531,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s
return false;
// Create prototype property, which inherits from Object.prototype.
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!objProto)
return false;
Rooted<TypedProto*> proto(cx);
@ -551,7 +551,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s
}
// Bind type descriptor to the global SIMD object
RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global));
MOZ_ASSERT(globalSimdObject);
RootedValue typeValue(cx, ObjectValue(*typeDescr));
@ -568,7 +568,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s
return !!typeDescr;
}
bool
/* static */ bool
GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType)
{
#define CREATE_(Type) \
@ -584,13 +584,13 @@ GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType
#undef CREATE_
}
SimdTypeDescr*
/* static */ SimdTypeDescr*
GlobalObject::getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global,
SimdType simdType)
{
MOZ_ASSERT(unsigned(simdType) < unsigned(SimdType::Count), "Invalid SIMD type");
RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global));
if (!globalSimdObject)
return nullptr;
@ -628,8 +628,8 @@ SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool*
JSObject*
js::InitSimdClass(JSContext* cx, HandleObject obj)
{
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
return global->getOrCreateSimdGlobalObject(cx);
Handle<GlobalObject*> global = obj.as<GlobalObject>();
return GlobalObject::getOrCreateSimdGlobalObject(cx, global);
}
template<typename V>

View file

@ -53,17 +53,17 @@ const JSFunctionSpec SymbolObject::staticMethods[] = {
JSObject*
SymbolObject::initClass(JSContext* cx, HandleObject obj)
{
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
Handle<GlobalObject*> global = obj.as<GlobalObject>();
// This uses &JSObject::class_ because: "The Symbol prototype object is an
// ordinary object. It is not a Symbol instance and does not have a
// [[SymbolData]] internal slot." (ES6 rev 24, 19.4.3)
RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx));
RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
if (!proto)
return nullptr;
RootedFunction ctor(cx, global->createConstructor(cx, construct,
ClassName(JSProto_Symbol, cx), 0));
RootedFunction ctor(cx, GlobalObject::createConstructor(cx, construct,
ClassName(JSProto_Symbol, cx), 0));
if (!ctor)
return nullptr;

View file

@ -3218,13 +3218,13 @@ ByteSizeOfScript(JSContext*cx, unsigned argc, Value* vp)
return false;
}
JSFunction* fun = &args[0].toObject().as<JSFunction>();
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
if (fun->isNative()) {
JS_ReportErrorASCII(cx, "Argument must be a scripted function");
return false;
}
RootedScript script(cx, fun->getOrCreateScript(cx));
RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
if (!script)
return false;
@ -3319,7 +3319,8 @@ GetConstructorName(JSContext* cx, unsigned argc, Value* vp)
}
RootedAtom name(cx);
if (!args[0].toObject().constructorDisplayAtom(cx, &name))
RootedObject obj(cx, &args[0].toObject());
if (!JSObject::constructorDisplayAtom(cx, obj, &name))
return false;
if (name) {
@ -4023,7 +4024,7 @@ DisRegExp(JSContext* cx, unsigned argc, Value* vp)
return false;
}
if (!reobj->dumpBytecode(cx, match_only, input))
if (!RegExpObject::dumpBytecode(cx, reobj, match_only, input))
return false;
args.rval().setUndefined();
@ -4042,6 +4043,32 @@ IsConstructor(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
GetErrorNotes(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.requireAtLeast(cx, "getErrorNotes", 1))
return false;
if (!args[0].isObject() || !args[0].toObject().is<ErrorObject>()) {
args.rval().setNull();
return true;
}
JSErrorReport* report = args[0].toObject().as<ErrorObject>().getErrorReport();
if (!report) {
args.rval().setNull();
return true;
}
RootedObject notesArray(cx, CreateErrorNotesArray(cx, report));
if (!notesArray)
return false;
args.rval().setObject(*notesArray);
return true;
}
static const JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0,
"gc([obj] | 'zone' [, 'shrinking'])",
@ -4576,6 +4603,10 @@ static const JSFunctionSpecWithHelp FuzzingUnsafeTestingFunctions[] = {
" Dumps RegExp bytecode."),
#endif
JS_FN_HELP("getErrorNotes", GetErrorNotes, 1, 0,
"getErrorNotes(error)",
" Returns an array of error notes."),
JS_FS_HELP_END
};

View file

@ -1124,11 +1124,11 @@ DefineSimpleTypeDescr(JSContext* cx,
typename T::Type type,
HandlePropertyName className)
{
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!objProto)
return false;
RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global));
if (!funcProto)
return false;
@ -1185,7 +1185,7 @@ DefineMetaTypeDescr(JSContext* cx,
if (!className)
return nullptr;
RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global));
if (!funcProto)
return nullptr;
@ -1197,7 +1197,7 @@ DefineMetaTypeDescr(JSContext* cx,
// Create ctor.prototype.prototype, which inherits from Object.__proto__
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!objProto)
return nullptr;
RootedObject protoProto(cx);
@ -1216,7 +1216,7 @@ DefineMetaTypeDescr(JSContext* cx,
const int constructorLength = 2;
RootedFunction ctor(cx);
ctor = global->createConstructor(cx, T::construct, className, constructorLength);
ctor = GlobalObject::createConstructor(cx, T::construct, className, constructorLength);
if (!ctor ||
!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndFunctions(cx, proto,
@ -1240,10 +1240,10 @@ DefineMetaTypeDescr(JSContext* cx,
* initializer for the `TypedObject` class populate the
* `TypedObject` global (which is referred to as "module" herein).
*/
bool
/* static */ bool
GlobalObject::initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global)
{
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!objProto)
return false;
@ -1317,9 +1317,8 @@ GlobalObject::initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global)
JSObject*
js::InitTypedObjectModuleObject(JSContext* cx, HandleObject obj)
{
MOZ_ASSERT(obj->is<GlobalObject>());
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
return global->getOrCreateTypedObjectModule(cx);
Handle<GlobalObject*> global = obj.as<GlobalObject>();
return GlobalObject::getOrCreateTypedObjectModule(cx, global);
}
/******************************************************************************

View file

@ -229,6 +229,69 @@ function GetInternalError(msg) {
// To be used when a function is required but calling it shouldn't do anything.
function NullFunction() {}
// Object Rest/Spread Properties proposal
// Abstract operation: CopyDataProperties (target, source, excluded)
function CopyDataProperties(target, source, excluded) {
// Step 1.
assert(IsObject(target), "target is an object");
// Step 2.
assert(IsObject(excluded), "excluded is an object");
// Steps 3, 6.
if (source === undefined || source === null)
return;
// Step 4.a.
source = ToObject(source);
// Step 4.b.
var keys = OwnPropertyKeys(source, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
// Step 5.
for (var index = 0; index < keys.length; index++) {
var key = keys[index];
// We abbreviate this by calling propertyIsEnumerable which is faster
// and returns false for not defined properties.
if (!callFunction(std_Object_hasOwnProperty, excluded, key) && callFunction(std_Object_propertyIsEnumerable, source, key))
_DefineDataProperty(target, key, source[key]);
}
// Step 6 (Return).
}
// Object Rest/Spread Properties proposal
// Abstract operation: CopyDataProperties (target, source, excluded)
function CopyDataPropertiesUnfiltered(target, source) {
// Step 1.
assert(IsObject(target), "target is an object");
// Step 2 (Not applicable).
// Steps 3, 6.
if (source === undefined || source === null)
return;
// Step 4.a.
source = ToObject(source);
// Step 4.b.
var keys = OwnPropertyKeys(source, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
// Step 5.
for (var index = 0; index < keys.length; index++) {
var key = keys[index];
// We abbreviate this by calling propertyIsEnumerable which is faster
// and returns false for not defined properties.
if (callFunction(std_Object_propertyIsEnumerable, source, key))
_DefineDataProperty(target, key, source[key]);
}
// Step 6 (Return).
}
/*************************************** Testing functions ***************************************/
function outer() {
return function inner() {

View file

@ -350,14 +350,14 @@ InitWeakMapClass(JSContext* cx, HandleObject obj, bool defineMembers)
{
MOZ_ASSERT(obj->isNative());
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
Handle<GlobalObject*> global = obj.as<GlobalObject>();
RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!proto)
return nullptr;
RootedFunction ctor(cx, global->createConstructor(cx, WeakMap_construct,
cx->names().WeakMap, 0));
RootedFunction ctor(cx, GlobalObject::createConstructor(cx, WeakMap_construct,
cx->names().WeakMap, 0));
if (!ctor)
return nullptr;

View file

@ -41,14 +41,15 @@ const JSFunctionSpec WeakSetObject::methods[] = {
};
JSObject*
WeakSetObject::initClass(JSContext* cx, JSObject* obj)
WeakSetObject::initClass(JSContext* cx, HandleObject obj)
{
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
Handle<GlobalObject*> global = obj.as<GlobalObject>();
RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!proto)
return nullptr;
Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(JSProto_WeakSet, cx), 0));
Rooted<JSFunction*> ctor(cx, GlobalObject::createConstructor(cx, construct,
ClassName(JSProto_WeakSet, cx), 0));
if (!ctor ||
!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||

View file

@ -16,7 +16,7 @@ class WeakSetObject : public NativeObject
public:
static const unsigned RESERVED_SLOTS = 1;
static JSObject* initClass(JSContext* cx, JSObject* obj);
static JSObject* initClass(JSContext* cx, HandleObject obj);
static const Class class_;
private:

View file

@ -77,7 +77,13 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool canLazilyParse();
bool createParser();
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
bool createScript(uint32_t preludeStart = 0);
// If toString{Start,End} are not explicitly passed, assume the script's
// offsets in the source used to parse it are the same as what should be
// used to compute its Function.prototype.toString() value.
bool createScript();
bool createScript(uint32_t toStringStart, uint32_t toStringEnd);
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives);
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
@ -242,11 +248,17 @@ BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = No
}
bool
BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */)
BytecodeCompiler::createScript()
{
return createScript(0, sourceBuffer.length());
}
bool
BytecodeCompiler::createScript(uint32_t toStringStart, uint32_t toStringEnd)
{
script = JSScript::Create(cx, options,
sourceObject, /* sourceStart = */ 0, sourceBuffer.length(),
preludeStart);
toStringStart, toStringEnd);
return script != nullptr;
}
@ -287,7 +299,8 @@ BytecodeCompiler::deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObj
RootedObject env(cx, environment);
while (env->is<EnvironmentObject>() || env->is<DebugEnvironmentProxy>()) {
if (env->is<CallObject>()) {
RootedScript script(cx, env->as<CallObject>().callee().getOrCreateScript(cx));
RootedFunction fun(cx, &env->as<CallObject>().callee());
RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
if (!script)
return false;
if (script->argumentsHasVarBinding()) {
@ -457,7 +470,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
if (fn->pn_funbox->function()->isInterpreted()) {
MOZ_ASSERT(fun == fn->pn_funbox->function());
if (!createScript(fn->pn_funbox->preludeStart))
if (!createScript(fn->pn_funbox->toStringStart, fn->pn_funbox->toStringEnd))
return false;
Maybe<BytecodeEmitter> emitter;
@ -652,7 +665,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
lazy->begin(), lazy->end(),
lazy->preludeStart()));
lazy->toStringStart(), lazy->toStringEnd()));
if (!script)
return false;

View file

@ -3069,6 +3069,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
case PNK_ELISION:
case PNK_GENERATOR:
case PNK_NUMBER:
@ -3538,9 +3539,10 @@ BytecodeEmitter::needsImplicitThis()
bool
BytecodeEmitter::maybeSetDisplayURL()
{
if (tokenStream()->hasDisplayURL()) {
if (!parser->ss->setDisplayURL(cx, tokenStream()->displayURL()))
if (tokenStream().hasDisplayURL()) {
if (!parser->ss->setDisplayURL(cx, tokenStream().displayURL())) {
return false;
}
}
return true;
}
@ -3548,10 +3550,11 @@ BytecodeEmitter::maybeSetDisplayURL()
bool
BytecodeEmitter::maybeSetSourceMap()
{
if (tokenStream()->hasSourceMapURL()) {
if (tokenStream().hasSourceMapURL()) {
MOZ_ASSERT(!parser->ss->hasSourceMapURL());
if (!parser->ss->setSourceMapURL(cx, tokenStream()->sourceMapURL()))
if (!parser->ss->setSourceMapURL(cx, tokenStream().sourceMapURL())) {
return false;
}
}
/*
@ -3590,21 +3593,21 @@ BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext* cx)
}
}
inline TokenStream*
inline TokenStream&
BytecodeEmitter::tokenStream()
{
return &parser->tokenStream;
return parser->tokenStream;
}
bool
BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
{
TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos;
TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
va_list args;
va_start(args, errorNumber);
bool result = tokenStream()->reportCompileErrorNumberVA(pos.begin, JSREPORT_ERROR,
errorNumber, args);
bool result = tokenStream().reportCompileErrorNumberVA(nullptr, pos.begin, JSREPORT_ERROR,
errorNumber, args);
va_end(args);
return result;
}
@ -3612,11 +3615,12 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
bool
BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
{
TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos;
TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
va_list args;
va_start(args, errorNumber);
bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args);
bool result = tokenStream().reportExtraWarningErrorNumberVA(nullptr, pos.begin,
errorNumber, args);
va_end(args);
return result;
}
@ -3624,12 +3628,12 @@ BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
bool
BytecodeEmitter::reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...)
{
TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos;
TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
va_list args;
va_start(args, errorNumber);
bool result = tokenStream()->reportStrictModeErrorNumberVA(pos.begin, sc->strict(),
errorNumber, args);
bool result = tokenStream().reportStrictModeErrorNumberVA(nullptr, pos.begin, sc->strict(),
errorNumber, args);
va_end(args);
return result;
}
@ -4599,7 +4603,7 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
// If the expression is a literal, suppress line number emission so
// that debugging works more naturally.
if (caseValue) {
if (!emitTree(caseValue,
if (!emitTree(caseValue, ValueUsage::WantValue,
caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
{
return false;
@ -5810,36 +5814,78 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla
if (!emitRequireObjectCoercible()) // ... RHS
return false;
bool needsRestPropertyExcludedSet = pattern->pn_count > 1 &&
pattern->last()->isKind(PNK_SPREAD);
if (needsRestPropertyExcludedSet) {
if (!emitDestructuringObjRestExclusionSet(pattern)) // ... RHS SET
return false;
if (!emit1(JSOP_SWAP)) // ... SET RHS
return false;
}
for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
ParseNode* subpattern;
if (member->isKind(PNK_MUTATEPROTO))
if (member->isKind(PNK_MUTATEPROTO) || member->isKind(PNK_SPREAD))
subpattern = member->pn_kid;
else
subpattern = member->pn_right;
ParseNode* lhs = subpattern;
MOZ_ASSERT_IF(member->isKind(PNK_SPREAD), !lhs->isKind(PNK_ASSIGN));
if (lhs->isKind(PNK_ASSIGN))
lhs = lhs->pn_left;
size_t emitted;
if (!emitDestructuringLHSRef(lhs, &emitted)) // ... RHS *LREF
if (!emitDestructuringLHSRef(lhs, &emitted)) // ... *SET RHS *LREF
return false;
// Duplicate the value being destructured to use as a reference base.
if (emitted) {
if (!emitDupAt(emitted)) // ... RHS *LREF RHS
if (!emitDupAt(emitted)) // ... *SET RHS *LREF RHS
return false;
} else {
if (!emit1(JSOP_DUP)) // ... RHS RHS
if (!emit1(JSOP_DUP)) // ... *SET RHS RHS
return false;
}
if (member->isKind(PNK_SPREAD)) {
if (!updateSourceCoordNotes(member->pn_pos.begin))
return false;
if (!emitNewInit(JSProto_Object)) // ... *SET RHS *LREF RHS TARGET
return false;
if (!emit1(JSOP_DUP)) // ... *SET RHS *LREF RHS TARGET TARGET
return false;
if (!emit2(JSOP_PICK, 2)) // ... *SET RHS *LREF TARGET TARGET RHS
return false;
if (needsRestPropertyExcludedSet) {
if (!emit2(JSOP_PICK, emitted + 4)) // ... RHS *LREF TARGET TARGET RHS SET
return false;
}
CopyOption option = needsRestPropertyExcludedSet
? CopyOption::Filtered
: CopyOption::Unfiltered;
if (!emitCopyDataProperties(option)) // ... RHS *LREF TARGET
return false;
// Destructure TARGET per this member's lhs.
if (!emitSetOrInitializeDestructuring(lhs, flav)) // ... RHS
return false;
MOZ_ASSERT(member == pattern->last(), "Rest property is always last");
break;
}
// Now push the property name currently being matched, which is the
// current property name "label" on the left of a colon in the object
// initialiser.
bool needsGetElem = true;
if (member->isKind(PNK_MUTATEPROTO)) {
if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... RHS *LREF PROP
if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... *SET RHS *LREF PROP
return false;
needsGetElem = false;
} else {
@ -5847,40 +5893,131 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla
ParseNode* key = member->pn_left;
if (key->isKind(PNK_NUMBER)) {
if (!emitNumberOp(key->pn_dval)) // ... RHS *LREF RHS KEY
if (!emitNumberOp(key->pn_dval)) // ... *SET RHS *LREF RHS KEY
return false;
} else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) {
PropertyName* name = key->pn_atom->asPropertyName();
// The parser already checked for atoms representing indexes and
// used PNK_NUMBER instead, but also watch for ids which TI treats
// as indexes for simplification of downstream analysis.
jsid id = NameToId(name);
if (id != IdToTypeId(id)) {
if (!emitTree(key)) // ... RHS *LREF RHS KEY
return false;
} else {
if (!emitAtomOp(name, JSOP_GETPROP)) // ... RHS *LREF PROP
return false;
needsGetElem = false;
}
} else {
if (!emitComputedPropertyName(key)) // ... RHS *LREF RHS KEY
if (!emitAtomOp(key->pn_atom, JSOP_GETPROP)) // ... *SET RHS *LREF PROP
return false;
needsGetElem = false;
} else {
if (!emitComputedPropertyName(key)) // ... *SET RHS *LREF RHS KEY
return false;
// Add the computed property key to the exclusion set.
if (needsRestPropertyExcludedSet) {
if (!emitDupAt(emitted + 3)) // ... SET RHS *LREF RHS KEY SET
return false;
if (!emitDupAt(1)) // ... SET RHS *LREF RHS KEY SET KEY
return false;
if (!emit1(JSOP_UNDEFINED)) // ... SET RHS *LREF RHS KEY SET KEY UNDEFINED
return false;
if (!emit1(JSOP_INITELEM)) // ... SET RHS *LREF RHS KEY SET
return false;
if (!emit1(JSOP_POP)) // ... SET RHS *LREF RHS KEY
return false;
}
}
}
// Get the property value if not done already.
if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... RHS *LREF PROP
if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... *SET RHS *LREF PROP
return false;
if (subpattern->isKind(PNK_ASSIGN)) {
if (!emitDefault(subpattern->pn_right, lhs)) // ... RHS *LREF VALUE
if (!emitDefault(subpattern->pn_right, lhs)) // ... *SET RHS *LREF VALUE
return false;
}
// Destructure PROP per this member's lhs.
if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... RHS
if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... *SET RHS
return false;
}
return true;
}
bool
BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern)
{
MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
MOZ_ASSERT(pattern->isArity(PN_LIST));
MOZ_ASSERT(pattern->last()->isKind(PNK_SPREAD));
ptrdiff_t offset = this->offset();
if (!emitNewInit(JSProto_Object))
return false;
// Try to construct the shape of the object as we go, so we can emit a
// JSOP_NEWOBJECT with the final shape instead.
// In the case of computed property names and indices, we cannot fix the
// shape at bytecode compile time. When the shape cannot be determined,
// |obj| is nulled out.
// No need to do any guessing for the object kind, since we know the upper
// bound of how many properties we plan to have.
gc::AllocKind kind = gc::GetGCObjectKind(pattern->pn_count - 1);
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
if (!obj)
return false;
RootedAtom pnatom(cx);
for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
if (member->isKind(PNK_SPREAD))
break;
bool isIndex = false;
if (member->isKind(PNK_MUTATEPROTO)) {
pnatom.set(cx->names().proto);
} else {
ParseNode* key = member->pn_left;
if (key->isKind(PNK_NUMBER)) {
if (!emitNumberOp(key->pn_dval))
return false;
isIndex = true;
} else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) {
pnatom.set(key->pn_atom);
} else {
// Otherwise this is a computed property name which needs to
// be added dynamically.
obj.set(nullptr);
continue;
}
}
// Initialize elements with |undefined|.
if (!emit1(JSOP_UNDEFINED))
return false;
if (isIndex) {
obj.set(nullptr);
if (!emit1(JSOP_INITELEM))
return false;
} else {
uint32_t index;
if (!makeAtomIndex(pnatom, &index))
return false;
if (obj) {
MOZ_ASSERT(!obj->inDictionaryMode());
Rooted<jsid> id(cx, AtomToId(pnatom));
if (!NativeDefineProperty(cx, obj, id, UndefinedHandleValue, nullptr, nullptr,
JSPROP_ENUMERATE))
{
return false;
}
if (obj->inDictionaryMode())
obj.set(nullptr);
}
if (!emitIndex32(JSOP_INITPROP, index))
return false;
}
}
if (obj) {
// The object survived and has a predictable shape: update the
// original bytecode.
if (!replaceNewInitWithNewObject(obj, offset))
return false;
}
@ -6242,6 +6379,9 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje
case PNK_NULL:
vp.setNull();
return true;
case PNK_RAW_UNDEFINED:
vp.setUndefined();
return true;
case PNK_CALLSITEOBJ:
case PNK_ARRAY: {
unsigned count;
@ -6645,7 +6785,7 @@ BytecodeEmitter::emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLi
}
// Line notes were updated by emitLexicalScope.
return emitTree(body, emitLineNote);
return emitTree(body, ValueUsage::WantValue, emitLineNote);
}
// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
@ -6747,9 +6887,9 @@ BytecodeEmitter::emitRequireObjectCoercible()
return false;
if (!emit2(JSOP_PICK, 2)) // VAL REQUIREOBJECTCOERCIBLE UNDEFINED VAL
return false;
if (!emitCall(JSOP_CALL, 1)) // VAL IGNORED
if (!emitCall(JSOP_CALL_IGNORES_RV, 1))// VAL IGNORED
return false;
checkTypeSet(JSOP_CALL);
checkTypeSet(JSOP_CALL_IGNORES_RV);
if (!emit1(JSOP_POP)) // VAL
return false;
@ -6758,6 +6898,53 @@ BytecodeEmitter::emitRequireObjectCoercible()
return true;
}
bool
BytecodeEmitter::emitCopyDataProperties(CopyOption option)
{
DebugOnly<int32_t> depth = this->stackDepth;
uint32_t argc;
if (option == CopyOption::Filtered) {
MOZ_ASSERT(depth > 2); // TARGET SOURCE SET
argc = 3;
if (!emitAtomOp(cx->names().CopyDataProperties,
JSOP_GETINTRINSIC)) // TARGET SOURCE SET COPYDATAPROPERTIES
{
return false;
}
} else {
MOZ_ASSERT(depth > 1); // TARGET SOURCE
argc = 2;
if (!emitAtomOp(cx->names().CopyDataPropertiesUnfiltered,
JSOP_GETINTRINSIC)) // TARGET SOURCE COPYDATAPROPERTIES
{
return false;
}
}
if (!emit1(JSOP_UNDEFINED)) // TARGET SOURCE *SET COPYDATAPROPERTIES UNDEFINED
return false;
if (!emit2(JSOP_PICK, argc + 1)) // SOURCE *SET COPYDATAPROPERTIES UNDEFINED TARGET
return false;
if (!emit2(JSOP_PICK, argc + 1)) // *SET COPYDATAPROPERTIES UNDEFINED TARGET SOURCE
return false;
if (option == CopyOption::Filtered) {
if (!emit2(JSOP_PICK, argc + 1)) // COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
return false;
}
if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) // IGNORED
return false;
checkTypeSet(JSOP_CALL_IGNORES_RV);
if (!emit1(JSOP_POP)) // -
return false;
MOZ_ASSERT(depth - int(argc) == this->stackDepth);
return true;
}
bool
BytecodeEmitter::emitIterator()
{
@ -7269,12 +7456,14 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
// scope, but we still need to emit code for the initializers.)
if (!updateSourceCoordNotes(init->pn_pos.begin))
return false;
if (!emitTree(init))
return false;
if (!init->isForLoopDeclaration()) {
if (init->isForLoopDeclaration()) {
if (!emitTree(init))
return false;
} else {
// 'init' is an expression, not a declaration. emitTree left its
// value on the stack.
if (!emitTree(init, ValueUsage::IgnoreValue))
return false;
if (!emit1(JSOP_POP))
return false;
}
@ -7356,7 +7545,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
if (!updateSourceCoordNotes(update->pn_pos.begin))
return false;
if (!emitTree(update))
if (!emitTree(update, ValueUsage::IgnoreValue))
return false;
if (!emit1(JSOP_POP))
return false;
@ -7839,7 +8028,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
Rooted<JSObject*> sourceObject(cx, script->sourceObject());
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
funbox->bufStart, funbox->bufEnd,
funbox->preludeStart));
funbox->toStringStart,
funbox->toStringEnd));
if (!script)
return false;
@ -8682,8 +8872,9 @@ BytecodeEmitter::emitStatement(ParseNode* pn)
if (useful) {
JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
ValueUsage valueUsage = wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
MOZ_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
if (!emitTree(pn2))
if (!emitTree(pn2, valueUsage))
return false;
if (!emit1(op))
return false;
@ -9033,7 +9224,7 @@ BytecodeEmitter::emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitte
}
bool
BytecodeEmitter::emitCallOrNew(ParseNode* pn)
BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
{
bool callop = pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE);
/*
@ -9212,13 +9403,20 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
}
if (!spread) {
if (!emitCall(pn->getOp(), argc, pn))
return false;
if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
return false;
checkTypeSet(JSOP_CALL_IGNORES_RV);
} else {
if (!emitCall(pn->getOp(), argc, pn))
return false;
checkTypeSet(pn->getOp());
}
} else {
if (!emit1(pn->getOp()))
return false;
checkTypeSet(pn->getOp());
}
checkTypeSet(pn->getOp());
if (pn->isOp(JSOP_EVAL) ||
pn->isOp(JSOP_STRICTEVAL) ||
pn->isOp(JSOP_SPREADEVAL) ||
@ -9316,12 +9514,13 @@ BytecodeEmitter::emitLogical(ParseNode* pn)
}
bool
BytecodeEmitter::emitSequenceExpr(ParseNode* pn)
BytecodeEmitter::emitSequenceExpr(ParseNode* pn,
ValueUsage valueUsage /* = ValueUsage::WantValue */)
{
for (ParseNode* child = pn->pn_head; ; child = child->pn_next) {
if (!updateSourceCoordNotes(child->pn_pos.begin))
return false;
if (!emitTree(child))
if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage))
return false;
if (!child->pn_next)
break;
@ -9384,7 +9583,8 @@ BytecodeEmitter::emitLabeledStatement(const LabeledStatement* pn)
}
bool
BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional)
BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional,
ValueUsage valueUsage /* = ValueUsage::WantValue */)
{
/* Emit the condition, then branch if false to the else part. */
if (!emitTree(&conditional.condition()))
@ -9394,13 +9594,13 @@ BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional)
if (!ifThenElse.emitCond())
return false;
if (!emitTreeInBranch(&conditional.thenExpression()))
if (!emitTreeInBranch(&conditional.thenExpression(), valueUsage))
return false;
if (!ifThenElse.emitElse())
return false;
if (!emitTreeInBranch(&conditional.elseExpression()))
if (!emitTreeInBranch(&conditional.elseExpression(), valueUsage))
return false;
if (!ifThenElse.emitEnd())
@ -9429,6 +9629,22 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
continue;
}
if (propdef->isKind(PNK_SPREAD)) {
MOZ_ASSERT(type == ObjectLiteral);
if (!emit1(JSOP_DUP))
return false;
if (!emitTree(propdef->pn_kid))
return false;
if (!emitCopyDataProperties(CopyOption::Unfiltered))
return false;
objp.set(nullptr);
continue;
}
bool extraPop = false;
if (type == ClassBody && propdef->as<ClassMethod>().isStatic()) {
extraPop = true;
@ -9452,16 +9668,6 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
{
continue;
}
// The parser already checked for atoms representing indexes and
// used PNK_NUMBER instead, but also watch for ids which TI treats
// as indexes for simpliciation of downstream analysis.
jsid id = NameToId(key->pn_atom->asPropertyName());
if (id != IdToTypeId(id)) {
if (!emitTree(key))
return false;
isIndex = true;
}
} else {
if (!emitComputedPropertyName(key))
return false;
@ -9542,8 +9748,7 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
MOZ_ASSERT(!IsHiddenInitOp(op));
MOZ_ASSERT(!objp->inDictionaryMode());
Rooted<jsid> id(cx, AtomToId(key->pn_atom));
RootedValue undefinedValue(cx, UndefinedValue());
if (!NativeDefineProperty(cx, objp, id, undefinedValue, nullptr, nullptr,
if (!NativeDefineProperty(cx, objp, id, UndefinedHandleValue, nullptr, nullptr,
JSPROP_ENUMERATE))
{
return false;
@ -9586,15 +9791,16 @@ BytecodeEmitter::emitObject(ParseNode* pn)
if (!emitNewInit(JSProto_Object))
return false;
/*
* Try to construct the shape of the object as we go, so we can emit a
* JSOP_NEWOBJECT with the final shape instead.
*/
RootedPlainObject obj(cx);
// No need to do any guessing for the object kind, since we know exactly
// how many properties we plan to have.
// Try to construct the shape of the object as we go, so we can emit a
// JSOP_NEWOBJECT with the final shape instead.
// In the case of computed property names and indices, we cannot fix the
// shape at bytecode compile time. When the shape cannot be determined,
// |obj| is nulled out.
// No need to do any guessing for the object kind, since we know the upper
// bound of how many properties we plan to have.
gc::AllocKind kind = gc::GetGCObjectKind(pn->pn_count);
obj = NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject);
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
if (!obj)
return false;
@ -9602,29 +9808,38 @@ BytecodeEmitter::emitObject(ParseNode* pn)
return false;
if (obj) {
/*
* The object survived and has a predictable shape: update the original
* bytecode.
*/
ObjectBox* objbox = parser->newObjectBox(obj);
if (!objbox)
// The object survived and has a predictable shape: update the original
// bytecode.
if (!replaceNewInitWithNewObject(obj, offset))
return false;
static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
"newinit and newobject must have equal length to edit in-place");
uint32_t index = objectList.add(objbox);
jsbytecode* code = this->code(offset);
code[0] = JSOP_NEWOBJECT;
code[1] = jsbytecode(index >> 24);
code[2] = jsbytecode(index >> 16);
code[3] = jsbytecode(index >> 8);
code[4] = jsbytecode(index);
}
return true;
}
bool
BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset)
{
ObjectBox* objbox = parser->newObjectBox(obj);
if (!objbox)
return false;
static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
"newinit and newobject must have equal length to edit in-place");
uint32_t index = objectList.add(objbox);
jsbytecode* code = this->code(offset);
MOZ_ASSERT(code[0] == JSOP_NEWINIT);
code[0] = JSOP_NEWOBJECT;
code[1] = jsbytecode(index >> 24);
code[2] = jsbytecode(index >> 16);
code[3] = jsbytecode(index >> 8);
code[4] = jsbytecode(index);
return true;
}
bool
BytecodeEmitter::emitArrayComp(ParseNode* pn)
{
@ -10220,6 +10435,13 @@ BytecodeEmitter::emitClass(ParseNode* pn)
return false;
}
} else {
// In the case of default class constructors, emit the start and end
// offsets in the source buffer as source notes so that when we
// actually make the constructor during execution, we can give it the
// correct toString output.
if (!newSrcNote3(SRC_CLASS_SPAN, ptrdiff_t(pn->pn_pos.begin), ptrdiff_t(pn->pn_pos.end)))
return false;
JSAtom *name = names ? names->innerBinding()->pn_atom : cx->names().empty;
if (heritageExpression) {
if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR))
@ -10274,7 +10496,8 @@ BytecodeEmitter::emitClass(ParseNode* pn)
}
bool
BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */)
{
JS_CHECK_RECURSION(cx, return false);
@ -10396,7 +10619,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
break;
case PNK_COMMA:
if (!emitSequenceExpr(pn))
if (!emitSequenceExpr(pn, valueUsage))
return false;
break;
@ -10418,7 +10641,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
break;
case PNK_CONDITIONAL:
if (!emitConditionalExpression(pn->as<ConditionalExpression>()))
if (!emitConditionalExpression(pn->as<ConditionalExpression>(), valueUsage))
return false;
break;
@ -10531,7 +10754,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
case PNK_CALL:
case PNK_GENEXP:
case PNK_SUPERCALL:
if (!emitCallOrNew(pn))
if (!emitCallOrNew(pn, valueUsage))
return false;
break;
@ -10637,6 +10860,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
if (!emit1(pn->getOp()))
return false;
break;
@ -10688,12 +10912,13 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
}
bool
BytecodeEmitter::emitTreeInBranch(ParseNode* pn)
BytecodeEmitter::emitTreeInBranch(ParseNode* pn,
ValueUsage valueUsage /* = ValueUsage::WantValue */)
{
// Code that may be conditionally executed always need their own TDZ
// cache.
TDZCheckCache tdzCache(this);
return emitTree(pn);
return emitTree(pn, valueUsage);
}
static bool

View file

@ -171,6 +171,11 @@ struct JumpList {
void patchAll(jsbytecode* code, JumpTarget target);
};
enum class ValueUsage {
WantValue,
IgnoreValue
};
struct MOZ_STACK_CLASS BytecodeEmitter
{
class TDZCheckCache;
@ -356,7 +361,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool maybeSetSourceMap();
void tellDebuggerAboutCompiledScript(ExclusiveContext* cx);
inline TokenStream* tokenStream();
inline TokenStream& tokenStream();
BytecodeVector& code() const { return current->code; }
jsbytecode* code(ptrdiff_t offset) const { return current->code.begin() + offset; }
@ -434,10 +439,12 @@ struct MOZ_STACK_CLASS BytecodeEmitter
};
// Emit code for the tree rooted at pn.
MOZ_MUST_USE bool emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
MOZ_MUST_USE bool emitTree(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue,
EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
// Emit code for the tree rooted at pn with its own TDZ cache.
MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn);
MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn,
ValueUsage valueUsage = ValueUsage::WantValue);
// Emit global, eval, or module code for tree rooted at body. Always
// encompasses the entire source.
@ -533,6 +540,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitFunction(ParseNode* pn, bool needsProto = false);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ParseNode* pn);
MOZ_MUST_USE bool replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset);
MOZ_MUST_USE bool emitHoistedFunctionsInList(ParseNode* pn);
MOZ_MUST_USE bool emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
@ -660,6 +669,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// []/{} expression).
MOZ_MUST_USE bool emitSetOrInitializeDestructuring(ParseNode* target, DestructuringFlavor flav);
// emitDestructuringObjRestExclusionSet emits the property exclusion set
// for the rest-property in an object pattern.
MOZ_MUST_USE bool emitDestructuringObjRestExclusionSet(ParseNode* pattern);
// emitDestructuringOps assumes the to-be-destructured value has been
// pushed on the stack and emits code to destructure each part of a [] or
// {} lhs expression.
@ -677,6 +690,15 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// object, with no overall effect on the stack.
MOZ_MUST_USE bool emitRequireObjectCoercible();
enum class CopyOption {
Filtered, Unfiltered
};
// Calls either the |CopyDataProperties| or the
// |CopyDataPropertiesUnfiltered| intrinsic function, consumes three (or
// two in the latter case) elements from the stack.
MOZ_MUST_USE bool emitCopyDataProperties(CopyOption option);
// emitIterator expects the iterable to already be on the stack.
// It will replace that stack value with the corresponding iterator
MOZ_MUST_USE bool emitIterator();
@ -724,16 +746,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn);
MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn);
MOZ_MUST_USE bool emitLogical(ParseNode* pn);
MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn);
MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn,
ValueUsage valueUsage = ValueUsage::WantValue);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn);
MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional);
MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional,
ValueUsage valueUsage = ValueUsage::WantValue);
MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result);
MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted);
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn);
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);
MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn);

View file

@ -378,6 +378,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
case PNK_THIS:
case PNK_ELISION:
case PNK_NUMBER:
@ -468,6 +469,7 @@ IsEffectless(ParseNode* node)
node->isKind(PNK_TEMPLATE_STRING) ||
node->isKind(PNK_NUMBER) ||
node->isKind(PNK_NULL) ||
node->isKind(PNK_RAW_UNDEFINED) ||
node->isKind(PNK_FUNCTION) ||
node->isKind(PNK_GENEXP);
}
@ -492,6 +494,7 @@ Boolish(ParseNode* pn)
case PNK_FALSE:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
return Falsy;
case PNK_VOID: {
@ -1342,15 +1345,8 @@ FoldElement(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>&
if (!name)
return true;
// Also don't optimize if the name doesn't map directly to its id for TI's
// purposes.
if (NameToId(name) != IdToTypeId(NameToId(name)))
return true;
// Optimization 3: We have expr["foo"] where foo is not an index. Convert
// to a property access (like expr.foo) that optimizes better downstream.
// Don't bother with this for names that TI considers to be indexes, to
// simplify downstream analysis.
ParseNode* dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end);
if (!dottedAccess)
return false;
@ -1643,6 +1639,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
case PNK_ELISION:
case PNK_NUMBER:
case PNK_DEBUGGER:

View file

@ -10,6 +10,8 @@
#include "mozilla/Attributes.h"
#include "mozilla/PodOperations.h"
#include <string.h>
#include "frontend/ParseNode.h"
#include "frontend/SharedContext.h"
@ -181,6 +183,10 @@ class FullParseHandler
return new_<NullLiteral>(pos);
}
ParseNode* newRawUndefinedLiteral(const TokenPos& pos) {
return new_<RawUndefinedLiteral>(pos);
}
// The Boxer object here is any object that can allocate ObjectBoxes.
// Specifically, a Boxer has a .newObjectBox(T) method that accepts a
// Rooted<RegExpObject*> argument and returns an ObjectBox*.
@ -296,10 +302,9 @@ class FullParseHandler
}
MOZ_MUST_USE bool addSpreadElement(ParseNode* literal, uint32_t begin, ParseNode* inner) {
TokenPos pos(begin, inner->pn_pos.end);
ParseNode* spread = new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, inner);
ParseNode* spread = newSpread(begin, inner);
if (!spread)
return null();
return false;
literal->append(spread);
literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST;
return true;
@ -327,8 +332,10 @@ class FullParseHandler
return literal;
}
ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock) {
return new_<ClassNode>(name, heritage, methodBlock);
ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
const TokenPos& pos)
{
return new_<ClassNode>(name, heritage, methodBlock, pos);
}
ParseNode* newClassMethodList(uint32_t begin) {
return new_<ListNode>(PNK_CLASSMETHODLIST, TokenPos(begin, begin + 1));
@ -388,6 +395,18 @@ class FullParseHandler
return true;
}
MOZ_MUST_USE bool addSpreadProperty(ParseNode* literal, uint32_t begin, ParseNode* inner) {
MOZ_ASSERT(literal->isKind(PNK_OBJECT));
MOZ_ASSERT(literal->isArity(PN_LIST));
setListFlag(literal, PNX_NONCONST);
ParseNode* spread = newSpread(begin, inner);
if (!spread)
return false;
literal->append(spread);
return true;
}
MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn,
JSOp op)
{
@ -870,29 +889,29 @@ class FullParseHandler
return node->isKind(PNK_NAME);
}
bool nameIsEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) {
MOZ_ASSERT(isNameAnyParentheses(node),
"must only call this function on known names");
bool isArgumentsAnyParentheses(ParseNode* node, ExclusiveContext* cx) {
return node->isKind(PNK_NAME) && node->pn_atom == cx->names().arguments;
}
return node->pn_atom == cx->names().eval;
bool isEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) {
return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval;
}
const char* nameIsArgumentsEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) {
MOZ_ASSERT(isNameAnyParentheses(node),
"must only call this function on known names");
if (nameIsEvalAnyParentheses(node, cx))
if (isEvalAnyParentheses(node, cx))
return js_eval_str;
if (node->pn_atom == cx->names().arguments)
if (isArgumentsAnyParentheses(node, cx))
return js_arguments_str;
return nullptr;
}
bool nameIsUnparenthesizedAsync(ParseNode* node, ExclusiveContext* cx) {
MOZ_ASSERT(isNameAnyParentheses(node),
"must only call this function on known names");
return node->pn_atom == cx->names().async;
bool isAsyncKeyword(ParseNode* node, ExclusiveContext* cx) {
return node->isKind(PNK_NAME) &&
node->pn_pos.begin + strlen("async") == node->pn_pos.end &&
node->pn_atom == cx->names().async;
}
bool isCall(ParseNode* pn) {

View file

@ -0,0 +1,213 @@
# 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/.
import re
import sys
def read_reserved_word_list(filename):
macro_pat = re.compile(r"^\s*macro\(([^,]+), *[^,]+, *[^\)]+\)\s*\\?$")
reserved_word_list = []
index = 0
with open(filename, 'r') as f:
for line in f:
m = macro_pat.search(line)
if m:
reserved_word_list.append((index, m.group(1)))
index += 1
assert(len(reserved_word_list) != 0)
return reserved_word_list
def line(opt, s):
opt['output'].write('{}{}\n'.format(' ' * opt['indent_level'], s))
def indent(opt):
opt['indent_level'] += 1
def dedent(opt):
opt['indent_level'] -= 1
def span_and_count_at(reserved_word_list, column):
assert(len(reserved_word_list) != 0);
chars_dict = {}
for index, word in reserved_word_list:
chars_dict[ord(word[column])] = True
chars = sorted(chars_dict.keys())
return chars[-1] - chars[0] + 1, len(chars)
def optimal_switch_column(opt, reserved_word_list, columns, unprocessed_columns):
assert(len(reserved_word_list) != 0);
assert(unprocessed_columns != 0);
min_count = 0
min_span = 0
min_count_index = 0
min_span_index = 0
for index in range(0, unprocessed_columns):
span, count = span_and_count_at(reserved_word_list, columns[index])
assert(span != 0)
if span == 1:
assert(count == 1)
return 1, True
assert(count != 1)
if index == 0 or min_span > span:
min_span = span
min_span_index = index
if index == 0 or min_count > count:
min_count = count
min_count_index = index
if min_count <= opt['use_if_threshold']:
return min_count_index, True
return min_span_index, False
def split_list_per_column(reserved_word_list, column):
assert(len(reserved_word_list) != 0);
column_dict = {}
for item in reserved_word_list:
index, word = item
per_column = column_dict.setdefault(word[column], [])
per_column.append(item)
return sorted(column_dict.items(), key=lambda (char, word): ord(char))
def generate_letter_switch(opt, unprocessed_columns, reserved_word_list,
columns=None):
assert(len(reserved_word_list) != 0);
if not columns:
columns = range(0, unprocessed_columns)
if len(reserved_word_list) == 1:
index, word = reserved_word_list[0]
if unprocessed_columns == 0:
line(opt, 'JSRW_GOT_MATCH({}) /* {} */'.format(index, word))
return
if unprocessed_columns > opt['char_tail_test_threshold']:
line(opt, 'JSRW_TEST_GUESS({}) /* {} */'.format(index, word))
return
conds = []
for column in columns[0:unprocessed_columns]:
quoted = repr(word[column])
conds.append('JSRW_AT({})=={}'.format(column, quoted))
line(opt, 'if ({}) {{'.format(' && '.join(conds)))
indent(opt)
line(opt, 'JSRW_GOT_MATCH({}) /* {} */'.format(index, word))
dedent(opt)
line(opt, '}')
line(opt, 'JSRW_NO_MATCH()')
return
assert(unprocessed_columns != 0);
optimal_column_index, use_if = optimal_switch_column(opt, reserved_word_list,
columns,
unprocessed_columns)
optimal_column = columns[optimal_column_index]
# Make a copy to avoid breaking passed list.
columns = columns[:]
columns[optimal_column_index] = columns[unprocessed_columns - 1]
list_per_column = split_list_per_column(reserved_word_list, optimal_column)
if not use_if:
line(opt, 'switch (JSRW_AT({})) {{'.format(optimal_column))
for char, reserved_word_list_per_column in list_per_column:
quoted = repr(char)
if use_if:
line(opt, 'if (JSRW_AT({}) == {}) {{'.format(optimal_column,
quoted))
else:
line(opt, ' case {}:'.format(quoted))
indent(opt)
generate_letter_switch(opt, unprocessed_columns - 1,
reserved_word_list_per_column, columns)
dedent(opt)
if use_if:
line(opt, '}')
if not use_if:
line(opt, '}')
line(opt, 'JSRW_NO_MATCH()')
def split_list_per_length(reserved_word_list):
assert(len(reserved_word_list) != 0);
length_dict = {}
for item in reserved_word_list:
index, word = item
per_length = length_dict.setdefault(len(word), [])
per_length.append(item)
return sorted(length_dict.items(), key=lambda (length, word): length)
def generate_switch(opt, reserved_word_list):
assert(len(reserved_word_list) != 0);
line(opt, '/*')
line(opt, ' * Generating switch for the list of {} entries:'.format(len(reserved_word_list)))
for index, word in reserved_word_list:
line(opt, ' * {}'.format(word))
line(opt, ' */')
list_per_length = split_list_per_length(reserved_word_list)
use_if = False
if len(list_per_length) < opt['use_if_threshold']:
use_if = True
if not use_if:
line(opt, 'switch (JSRW_LENGTH()) {')
for length, reserved_word_list_per_length in list_per_length:
if use_if:
line(opt, 'if (JSRW_LENGTH() == {}) {{'.format(length))
else:
line(opt, ' case {}:'.format(length))
indent(opt)
generate_letter_switch(opt, length, reserved_word_list_per_length)
dedent(opt)
if use_if:
line(opt, '}')
if not use_if:
line(opt, '}')
line(opt, 'JSRW_NO_MATCH()')
def main(output, reserved_words_h):
reserved_word_list = read_reserved_word_list(reserved_words_h)
opt = {
'indent_level': 1,
'use_if_threshold': 3,
'char_tail_test_threshold': 4,
'output': output
}
generate_switch(opt, reserved_word_list)
if __name__ == '__main__':
main(sys.stdout, *sys.argv[1:])

View file

@ -78,6 +78,7 @@ enum class DeclarationKind : uint8_t
Const,
Import,
BodyLevelFunction,
ModuleBodyLevelFunction,
LexicalFunction,
VarForAnnexBLexicalFunction,
SimpleCatchParameter,
@ -95,6 +96,7 @@ DeclarationKindToBindingKind(DeclarationKind kind)
case DeclarationKind::Var:
case DeclarationKind::BodyLevelFunction:
case DeclarationKind::ModuleBodyLevelFunction:
case DeclarationKind::VarForAnnexBLexicalFunction:
case DeclarationKind::ForOfVar:
return BindingKind::Var;
@ -124,6 +126,7 @@ DeclarationKindIsLexical(DeclarationKind kind)
// Used in Parser to track declared names.
class DeclaredNameInfo
{
uint32_t pos_;
DeclarationKind kind_;
// If the declared name is a binding, whether the binding is closed
@ -132,8 +135,9 @@ class DeclaredNameInfo
bool closedOver_;
public:
explicit DeclaredNameInfo(DeclarationKind kind)
: kind_(kind),
explicit DeclaredNameInfo(DeclarationKind kind, uint32_t pos)
: pos_(pos),
kind_(kind),
closedOver_(false)
{ }
@ -144,6 +148,12 @@ class DeclaredNameInfo
return kind_;
}
static const uint32_t npos = uint32_t(-1);
uint32_t pos() const {
return pos_;
}
void alterKind(DeclarationKind kind) {
kind_ = kind;
}

View file

@ -316,7 +316,8 @@ class NameResolver
return false;
// Next is the callsite object node. This node only contains
// internal strings and an array -- no user-controlled expressions.
// internal strings or undefined and an array -- no user-controlled
// expressions.
element = element->pn_next;
#ifdef DEBUG
{
@ -326,7 +327,7 @@ class NameResolver
for (ParseNode* kid = array->pn_head; kid; kid = kid->pn_next)
MOZ_ASSERT(kid->isKind(PNK_TEMPLATE_STRING));
for (ParseNode* next = array->pn_next; next; next = next->pn_next)
MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING));
MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING) || next->isKind(PNK_RAW_UNDEFINED));
}
#endif
@ -382,6 +383,7 @@ class NameResolver
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
case PNK_ELISION:
case PNK_GENERATOR:
case PNK_NUMBER:

View file

@ -190,6 +190,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
case PNK_ELISION:
case PNK_GENERATOR:
case PNK_NUMBER:
@ -685,6 +686,7 @@ NullaryNode::dump()
case PNK_TRUE: fprintf(stderr, "#true"); break;
case PNK_FALSE: fprintf(stderr, "#false"); break;
case PNK_NULL: fprintf(stderr, "#null"); break;
case PNK_RAW_UNDEFINED: fprintf(stderr, "#undefined"); break;
case PNK_NUMBER: {
ToCStringBuf cbuf;

View file

@ -54,6 +54,7 @@ class ObjectBox;
F(TRUE) \
F(FALSE) \
F(NULL) \
F(RAW_UNDEFINED) \
F(THIS) \
F(FUNCTION) \
F(MODULE) \
@ -406,7 +407,8 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_NUMBER dval pn_dval: double value of numeric literal
* PNK_TRUE, nullary pn_op: JSOp bytecode
* PNK_FALSE,
* PNK_NULL
* PNK_NULL,
* PNK_RAW_UNDEFINED
*
* PNK_THIS, unary pn_kid: '.this' Name if function `this`, else nullptr
* PNK_SUPERBASE unary pn_kid: '.this' Name
@ -686,7 +688,8 @@ class ParseNode
isKind(PNK_STRING) ||
isKind(PNK_TRUE) ||
isKind(PNK_FALSE) ||
isKind(PNK_NULL);
isKind(PNK_NULL) ||
isKind(PNK_RAW_UNDEFINED);
}
/* Return true if this node appears in a Directive Prologue. */
@ -1141,6 +1144,16 @@ class NullLiteral : public ParseNode
explicit NullLiteral(const TokenPos& pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { }
};
// This is only used internally, currently just for tagged templates.
// It represents the value 'undefined' (aka `void 0`), like NullLiteral
// represents the value 'null'.
class RawUndefinedLiteral : public ParseNode
{
public:
explicit RawUndefinedLiteral(const TokenPos& pos)
: ParseNode(PNK_RAW_UNDEFINED, JSOP_UNDEFINED, PN_NULLARY, pos) { }
};
class BooleanLiteral : public ParseNode
{
public:
@ -1296,8 +1309,9 @@ struct ClassNames : public BinaryNode {
};
struct ClassNode : public TernaryNode {
ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock)
: TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock)
ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock,
const TokenPos& pos)
: TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock, pos)
{
MOZ_ASSERT_IF(names, names->is<ClassNames>());
MOZ_ASSERT(methodsOrBlock->is<LexicalScopeNode>() ||
@ -1361,6 +1375,7 @@ ParseNode::isConstant()
case PNK_STRING:
case PNK_TEMPLATE_STRING:
case PNK_NULL:
case PNK_RAW_UNDEFINED:
case PNK_FALSE:
case PNK_TRUE:
return true;

File diff suppressed because it is too large Load diff

View file

@ -85,6 +85,16 @@ class ParseContext : public Nestable<ParseContext>
}
};
struct ClassStatement : public Statement
{
FunctionBox* constructorBox;
explicit ClassStatement(ParseContext* pc)
: Statement(pc, StatementKind::Class),
constructorBox(nullptr)
{ }
};
// The intra-function scope stack.
//
// Tracks declared and used names within a scope.
@ -146,9 +156,9 @@ class ParseContext : public Nestable<ParseContext>
}
MOZ_MUST_USE bool addDeclaredName(ParseContext* pc, AddDeclaredNamePtr& p, JSAtom* name,
DeclarationKind kind)
DeclarationKind kind, uint32_t pos)
{
return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind)));
return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind, pos)));
}
// Remove all VarForAnnexBLexicalFunction declarations of a certain
@ -330,17 +340,6 @@ class ParseContext : public Nestable<ParseContext>
// pointer may be nullptr.
Directives* newDirectives;
// Set when parsing a declaration-like destructuring pattern. This flag
// causes PrimaryExpr to create PN_NAME parse nodes for variable references
// which are not hooked into any definition's use chain, added to any tree
// context's AtomList, etc. etc. checkDestructuring will do that work
// later.
//
// The comments atop checkDestructuring explain the distinction between
// assignment-like and declaration-like destructuring patterns, and why
// they need to be treated differently.
mozilla::Maybe<DeclarationKind> inDestructuringDecl;
// Set when parsing a function and it has 'return <expr>;'
bool funHasReturnExpr;
@ -432,6 +431,11 @@ class ParseContext : public Nestable<ParseContext>
return Statement::findNearest<T>(innermostStatement_, predicate);
}
template <typename T>
T* findInnermostStatement() {
return Statement::findNearest<T>(innermostStatement_);
}
AtomVector& positionalFormalParameterNames() {
return *positionalFormalParameterNames_;
}
@ -532,6 +536,13 @@ ParseContext::Statement::is<ParseContext::LabelStatement>() const
return kind_ == StatementKind::Label;
}
template <>
inline bool
ParseContext::Statement::is<ParseContext::ClassStatement>() const
{
return kind_ == StatementKind::Class;
}
template <typename T>
inline T&
ParseContext::Statement::as()
@ -735,7 +746,155 @@ class UsedNameTracker
};
template <typename ParseHandler>
class Parser final : private JS::AutoGCRooter, public StrictModeGetter
class AutoAwaitIsKeyword;
class ParserBase : public StrictModeGetter
{
private:
ParserBase* thisForCtor() { return this; }
public:
ExclusiveContext* const context;
LifoAlloc& alloc;
TokenStream tokenStream;
LifoAlloc::Mark tempPoolMark;
/* list of parsed objects for GC tracing */
ObjectBox* traceListHead;
/* innermost parse context (stack-allocated) */
ParseContext* pc;
// For tracking used names in this parsing session.
UsedNameTracker& usedNames;
/* Compression token for aborting. */
SourceCompressionTask* sct;
ScriptSource* ss;
/* Root atoms and objects allocated for the parsed tree. */
AutoKeepAtoms keepAtoms;
/* Perform constant-folding; must be true when interfacing with the emitter. */
const bool foldConstants:1;
protected:
#if DEBUG
/* Our fallible 'checkOptions' member function has been called. */
bool checkOptionsCalled:1;
#endif
/*
* Not all language constructs can be handled during syntax parsing. If it
* is not known whether the parse succeeds or fails, this bit is set and
* the parse will return false.
*/
bool abortedSyntaxParse:1;
/* Unexpected end of input, i.e. TOK_EOF not at top-level. */
bool isUnexpectedEOF_:1;
bool awaitIsKeyword_:1;
public:
bool awaitIsKeyword() const {
return awaitIsKeyword_;
}
ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, bool foldConstants,
UsedNameTracker& usedNames, Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction);
~ParserBase();
const char* getFilename() const { return tokenStream.getFilename(); }
JSVersion versionNumber() const { return tokenStream.versionNumber(); }
TokenPos pos() const { return tokenStream.currentToken().pos; }
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence
// inside a star generator.
bool yieldExpressionsSupported() {
return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
}
virtual bool strictMode() { return pc->sc()->strict(); }
bool setLocalStrictMode(bool strict) {
MOZ_ASSERT(tokenStream.debugHasNoLookahead());
return pc->sc()->setLocalStrictMode(strict);
}
const ReadOnlyCompileOptions& options() const {
return tokenStream.options();
}
bool hadAbortedSyntaxParse() {
return abortedSyntaxParse;
}
void clearAbortedSyntaxParse() {
abortedSyntaxParse = false;
}
bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
/* Report the given error at the current offset. */
void error(unsigned errorNumber, ...);
void errorWithNotes(UniquePtr<JSErrorNotes> notes, unsigned errorNumber, ...);
/* Report the given error at the given offset. */
void errorAt(uint32_t offset, unsigned errorNumber, ...);
void errorWithNotesAt(UniquePtr<JSErrorNotes> notes, uint32_t offset,
unsigned errorNumber, ...);
/*
* Handle a strict mode error at the current offset. Report an error if in
* strict mode code, or warn if not, using the given error number and
* arguments.
*/
MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...);
/*
* Handle a strict mode error at the given offset. Report an error if in
* strict mode code, or warn if not, using the given error number and
* arguments.
*/
MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...);
/* Report the given warning at the current offset. */
MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
/* Report the given warning at the given offset. */
MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...);
/*
* If extra warnings are enabled, report the given warning at the current
* offset.
*/
MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
/*
* If extra warnings are enabled, report the given warning at the given
* offset.
*/
MOZ_MUST_USE bool extraWarningAt(uint32_t offset, unsigned errorNumber, ...);
bool isValidStrictBinding(PropertyName* name);
bool warnOnceAboutExprClosure();
bool warnOnceAboutForEach();
protected:
enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
enum ForInitLocation { InForInit, NotInForInit };
};
template <typename ParseHandler>
class Parser final : public ParserBase, private JS::AutoGCRooter
{
private:
using Node = typename ParseHandler::Node;
@ -788,7 +947,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
class MOZ_STACK_CLASS PossibleError
{
private:
enum class ErrorKind { Expression, Destructuring };
enum class ErrorKind { Expression, Destructuring, DestructuringWarning };
enum class ErrorState { None, Pending };
@ -803,11 +962,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
Parser<ParseHandler>& parser_;
Error exprError_;
Error destructuringError_;
Error destructuringWarning_;
// Returns the error report.
Error& error(ErrorKind kind);
// Return true if an error is pending without reporting
// Return true if an error is pending without reporting.
bool hasError(ErrorKind kind);
// Resolve any pending error.
@ -819,7 +979,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// If there is a pending error, report it and return false, otherwise
// return true.
bool checkForError(ErrorKind kind);
MOZ_MUST_USE bool checkForError(ErrorKind kind);
// If there is a pending warning, report it and return either false or
// true depending on the werror option, otherwise return true.
MOZ_MUST_USE bool checkForWarning(ErrorKind kind);
// Transfer an existing error to another instance.
void transferErrorTo(ErrorKind kind, PossibleError* other);
@ -827,23 +991,33 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
public:
explicit PossibleError(Parser<ParseHandler>& parser);
// Return true if a pending destructuring error is present.
bool hasPendingDestructuringError();
// Set a pending destructuring error. Only a single error may be set
// per instance, i.e. subsequent calls to this method are ignored and
// won't overwrite the existing pending error.
void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber);
// Set a pending destructuring warning. Only a single warning may be
// set per instance, i.e. subsequent calls to this method are ignored
// and won't overwrite the existing pending warning.
void setPendingDestructuringWarningAt(const TokenPos& pos, unsigned errorNumber);
// Set a pending expression error. Only a single error may be set per
// instance, i.e. subsequent calls to this method are ignored and won't
// overwrite the existing pending error.
void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber);
// If there is a pending destructuring error, report it and return
// false, otherwise return true. Clears any pending expression error.
bool checkForDestructuringError();
// If there is a pending destructuring error or warning, report it and
// return false, otherwise return true. Clears any pending expression
// error.
MOZ_MUST_USE bool checkForDestructuringErrorOrWarning();
// If there is a pending expression error, report it and return false,
// otherwise return true. Clears any pending destructuring error.
bool checkForExpressionError();
// otherwise return true. Clears any pending destructuring error or
// warning.
MOZ_MUST_USE bool checkForExpressionError();
// Pass pending errors between possible error instances. This is useful
// for extending the lifetime of a pending error beyond the scope of
@ -852,50 +1026,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
void transferErrorsTo(PossibleError* other);
};
public:
ExclusiveContext* const context;
LifoAlloc& alloc;
TokenStream tokenStream;
LifoAlloc::Mark tempPoolMark;
/* list of parsed objects for GC tracing */
ObjectBox* traceListHead;
/* innermost parse context (stack-allocated) */
ParseContext* pc;
// For tracking used names in this parsing session.
UsedNameTracker& usedNames;
/* Compression token for aborting. */
SourceCompressionTask* sct;
ScriptSource* ss;
/* Root atoms and objects allocated for the parsed tree. */
AutoKeepAtoms keepAtoms;
/* Perform constant-folding; must be true when interfacing with the emitter. */
const bool foldConstants:1;
private:
#if DEBUG
/* Our fallible 'checkOptions' member function has been called. */
bool checkOptionsCalled:1;
#endif
/*
* Not all language constructs can be handled during syntax parsing. If it
* is not known whether the parse succeeds or fails, this bit is set and
* the parse will return false.
*/
bool abortedSyntaxParse:1;
/* Unexpected end of input, i.e. TOK_EOF not at top-level. */
bool isUnexpectedEOF_:1;
public:
/* State specific to the kind of parse being performed. */
ParseHandler handler;
@ -904,45 +1034,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
void freeTree(Node node) { handler.freeTree(node); }
public:
bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
/* Report the given error at the current offset. */
void error(unsigned errorNumber, ...);
/* Report the given error at the given offset. */
void errorAt(uint32_t offset, unsigned errorNumber, ...);
/*
* Handle a strict mode error at the current offset. Report an error if in
* strict mode code, or warn if not, using the given error number and
* arguments.
*/
MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...);
/*
* Handle a strict mode error at the given offset. Report an error if in
* strict mode code, or warn if not, using the given error number and
* arguments.
*/
MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...);
/* Report the given warning at the current offset. */
MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
/* Report the given warning at the given offset. */
MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...);
/*
* If extra warnings are enabled, report the given warning at the current
* offset.
*/
MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames,
Parser<SyntaxParseHandler>* syntaxParser, LazyScript* lazyOuterFunction);
~Parser();
friend class AutoAwaitIsKeyword<ParseHandler>;
void setAwaitIsKeyword(bool isKeyword);
bool checkOptions();
// A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
@ -967,9 +1066,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
friend void js::frontend::MarkParser(JSTracer* trc, JS::AutoGCRooter* parser);
const char* getFilename() const { return tokenStream.getFilename(); }
JSVersion versionNumber() const { return tokenStream.versionNumber(); }
/*
* Parse a top-level JS script.
*/
@ -980,7 +1076,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
* cx->tempLifoAlloc.
*/
ObjectBox* newObjectBox(JSObject* obj);
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
Directives directives,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB);
@ -995,24 +1091,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
void trace(JSTracer* trc);
bool hadAbortedSyntaxParse() {
return abortedSyntaxParse;
}
void clearAbortedSyntaxParse() {
abortedSyntaxParse = false;
}
bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
bool checkUnescapedName();
private:
Parser* thisForCtor() { return this; }
JSAtom* stopStringCompression();
Node stringLiteral();
Node noSubstitutionTemplate();
Node noSubstitutionTaggedTemplate();
Node noSubstitutionUntaggedTemplate();
Node templateLiteral(YieldHandling yieldHandling);
bool taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt);
bool appendToCallSiteObj(Node callSiteObj);
@ -1061,7 +1147,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse an inner function given an enclosing ParseContext and a
// FunctionBox for the inner function.
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart,
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t toStringStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
Directives inheritedDirectives, Directives* newDirectives);
@ -1070,35 +1156,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// ParseContext is already on the stack.
bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
Node pn, FunctionSyntaxKind kind,
mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence
// inside a star generator.
bool yieldExpressionsSupported() {
return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
}
mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing(),
bool isStandaloneFunction = false);
// Match the current token against the BindingIdentifier production with
// the given Yield parameter. If there is no match, report a syntax
// error.
PropertyName* bindingIdentifier(YieldHandling yieldHandling);
virtual bool strictMode() { return pc->sc()->strict(); }
bool setLocalStrictMode(bool strict) {
MOZ_ASSERT(tokenStream.debugHasNoLookahead());
return pc->sc()->setLocalStrictMode(strict);
}
const ReadOnlyCompileOptions& options() const {
return tokenStream.options();
}
private:
enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
enum ForInitLocation { InForInit, NotInForInit };
private:
/*
* JS parsers, from lowest to highest precedence.
@ -1116,10 +1181,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
* Some parsers have two versions: an always-inlined version (with an 'i'
* suffix) and a never-inlined version (with an 'n' suffix).
*/
Node functionStmt(uint32_t preludeStart,
Node functionStmt(uint32_t toStringStart,
YieldHandling yieldHandling, DefaultHandling defaultHandling,
FunctionAsyncKind asyncKind = SyncFunction);
Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked,
Node functionExpr(uint32_t toStringStart, InvokedPrediction invoked = PredictUninvoked,
FunctionAsyncKind asyncKind = SyncFunction);
Node statementList(YieldHandling yieldHandling);
@ -1160,9 +1225,27 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// continues a LexicalDeclaration.
bool nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling);
Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst);
Node lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind);
Node importDeclaration();
bool processExport(Node node);
bool processExportFrom(Node node);
Node exportFrom(uint32_t begin, Node specList);
Node exportBatch(uint32_t begin);
bool checkLocalExportNames(Node node);
Node exportClause(uint32_t begin);
Node exportFunctionDeclaration(uint32_t begin);
Node exportVariableStatement(uint32_t begin);
Node exportClassDeclaration(uint32_t begin);
Node exportLexicalDeclaration(uint32_t begin, DeclarationKind kind);
Node exportDefaultFunctionDeclaration(uint32_t begin,
FunctionAsyncKind asyncKind = SyncFunction);
Node exportDefaultClassDeclaration(uint32_t begin);
Node exportDefaultAssignExpr(uint32_t begin);
Node exportDefault(uint32_t begin);
Node exportDeclaration();
Node expressionStatement(YieldHandling yieldHandling,
InvokedPrediction invoked = PredictUninvoked);
@ -1250,7 +1333,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool tryNewTarget(Node& newTarget);
bool checkAndMarkSuperScope();
Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName);
Node methodDefinition(uint32_t toStringStart, PropertyType propType, HandleAtom funName);
/*
* Additional JS parsers.
@ -1258,7 +1341,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
Node funcpn);
Node functionDefinition(uint32_t preludeStart, Node pn,
Node functionDefinition(uint32_t toStringStart, Node pn,
InHandling inHandling, YieldHandling yieldHandling, HandleAtom name,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
@ -1294,21 +1377,34 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool checkExportedName(JSAtom* exportName);
bool checkExportedNamesForDeclaration(Node node);
bool checkExportedNameForClause(Node node);
bool checkExportedNameForFunction(Node node);
bool checkExportedNameForClass(Node node);
enum ClassContext { ClassStatement, ClassExpression };
Node classDefinition(YieldHandling yieldHandling, ClassContext classContext,
DefaultHandling defaultHandling);
PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling,
bool yieldTokenizedAsName);
bool checkLabelOrIdentifierReference(HandlePropertyName ident,
uint32_t offset,
YieldHandling yieldHandling);
PropertyName* labelIdentifier(YieldHandling yieldHandling) {
return labelOrIdentifierReference(yieldHandling, false);
bool checkLocalExportName(HandlePropertyName ident, uint32_t offset) {
return checkLabelOrIdentifierReference(ident, offset, YieldIsName);
}
PropertyName* identifierReference(YieldHandling yieldHandling,
bool yieldTokenizedAsName = false)
{
return labelOrIdentifierReference(yieldHandling, yieldTokenizedAsName);
bool checkBindingIdentifier(HandlePropertyName ident,
uint32_t offset,
YieldHandling yieldHandling);
PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling);
PropertyName* labelIdentifier(YieldHandling yieldHandling) {
return labelOrIdentifierReference(yieldHandling);
}
PropertyName* identifierReference(YieldHandling yieldHandling) {
return labelOrIdentifierReference(yieldHandling);
}
PropertyName* importedBinding() {
@ -1337,23 +1433,27 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
Node newDotGeneratorName();
bool declareDotGeneratorName();
bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind,
bool skipLazyInnerFunction(Node pn, uint32_t toStringStart, FunctionSyntaxKind kind,
bool tryAnnexB);
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart,
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t toStringStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives);
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart,
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t toStringStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives);
bool finishFunctionScopes();
bool finishFunction();
bool finishFunctionScopes(bool isStandaloneFunction);
bool finishFunction(bool isStandaloneFunction = false);
bool leaveInnerFunction(ParseContext* outerpc);
bool matchOrInsertSemicolonHelper(TokenStream::Modifier modifier);
bool matchOrInsertSemicolonAfterExpression();
bool matchOrInsertSemicolonAfterNonExpression();
public:
enum FunctionCallBehavior {
PermitAssignmentToFunctionCalls,
@ -1366,21 +1466,22 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
private:
bool checkIncDecOperand(Node operand, uint32_t operandOffset);
bool checkStrictAssignment(Node lhs);
bool checkStrictBinding(PropertyName* name, TokenPos pos);
bool hasValidSimpleStrictParameterNames();
bool isValidStrictBinding(PropertyName* name);
void reportMissingClosing(unsigned errorNumber, unsigned noteNumber, uint32_t openedPos);
void reportRedeclaration(HandlePropertyName name, DeclarationKind kind, TokenPos pos);
bool notePositionalFormalParameter(Node fn, HandlePropertyName name,
void reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, TokenPos pos,
uint32_t prevPos);
bool notePositionalFormalParameter(Node fn, HandlePropertyName name, uint32_t beginPos,
bool disallowDuplicateParams, bool* duplicatedParam);
bool noteDestructuredPositionalFormalParameter(Node fn, Node destruct);
mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name,
DeclarationKind kind);
bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
mozilla::Maybe<DeclarationKind>* redeclaredKind);
bool tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, bool* tryAnnexB);
bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos,
mozilla::Maybe<DeclarationKind>* redeclaredKind, uint32_t* prevPos);
bool tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, uint32_t beginPos,
bool* tryAnnexB);
bool checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
DeclarationKind kind, TokenPos pos);
bool noteDeclaredName(HandlePropertyName name, DeclarationKind kind, TokenPos pos);
@ -1399,25 +1500,27 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
mozilla::Maybe<LexicalScope::Data*> newLexicalScopeData(ParseContext::Scope& scope);
Node finishLexicalScope(ParseContext::Scope& scope, Node body);
Node propertyName(YieldHandling yieldHandling, Node propList,
Node propertyName(YieldHandling yieldHandling,
const mozilla::Maybe<DeclarationKind>& maybeDecl, Node propList,
PropertyType* propType, MutableHandleAtom propAtom);
Node computedPropertyName(YieldHandling yieldHandling, Node literal);
Node computedPropertyName(YieldHandling yieldHandling,
const mozilla::Maybe<DeclarationKind>& maybeDecl, Node literal);
Node arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError);
Node newRegExp();
Node objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError);
// Top-level entrypoint into destructuring pattern checking/name-analyzing.
bool checkDestructuringPattern(Node pattern, mozilla::Maybe<DeclarationKind> maybeDecl,
PossibleError* possibleError = nullptr);
Node bindingInitializer(Node lhs, DeclarationKind kind, YieldHandling yieldHandling);
Node bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling);
Node bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling,
TokenKind tt);
Node objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling);
Node arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling);
// Recursive methods for checking/name-analyzing subcomponents of a
// destructuring pattern. The array/object methods *must* be passed arrays
// or objects. The name method may be passed anything but will report an
// error if not passed a name.
bool checkDestructuringArray(Node arrayPattern, mozilla::Maybe<DeclarationKind> maybeDecl);
bool checkDestructuringObject(Node objectPattern, mozilla::Maybe<DeclarationKind> maybeDecl);
bool checkDestructuringName(Node expr, mozilla::Maybe<DeclarationKind> maybeDecl);
void checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
PossibleError* possibleError);
void checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
PossibleError* possibleError);
Node newNumber(const Token& tok) {
return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
@ -1427,12 +1530,26 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom);
TokenPos pos() const { return tokenStream.currentToken().pos; }
bool asmJS(Node list);
};
bool warnOnceAboutExprClosure();
bool warnOnceAboutForEach();
template <typename ParseHandler>
class MOZ_STACK_CLASS AutoAwaitIsKeyword
{
private:
Parser<ParseHandler>* parser_;
bool oldAwaitIsKeyword_;
public:
AutoAwaitIsKeyword(Parser<ParseHandler>* parser, bool awaitIsKeyword) {
parser_ = parser;
oldAwaitIsKeyword_ = parser_->awaitIsKeyword_;
parser_->setAwaitIsKeyword(awaitIsKeyword);
}
~AutoAwaitIsKeyword() {
parser_->setAwaitIsKeyword(oldAwaitIsKeyword_);
}
};
} /* namespace frontend */

View file

@ -4,15 +4,16 @@
* 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/. */
/* A higher-order macro for enumerating keyword tokens. */
/* A higher-order macro for enumerating reserved word tokens. */
#ifndef vm_Keywords_h
#define vm_Keywords_h
#ifndef vm_ReservedWords_h
#define vm_ReservedWords_h
#define FOR_EACH_JAVASCRIPT_KEYWORD(macro) \
#define FOR_EACH_JAVASCRIPT_RESERVED_WORD(macro) \
macro(false, false_, TOK_FALSE) \
macro(true, true_, TOK_TRUE) \
macro(null, null, TOK_NULL) \
\
/* Keywords. */ \
macro(break, break_, TOK_BREAK) \
macro(case, case_, TOK_CASE) \
@ -36,31 +37,45 @@
macro(this, this_, TOK_THIS) \
macro(throw, throw_, TOK_THROW) \
macro(try, try_, TOK_TRY) \
macro(typeof, typeof, TOK_TYPEOF) \
macro(typeof, typeof_, TOK_TYPEOF) \
macro(var, var, TOK_VAR) \
macro(void, void_, TOK_VOID) \
macro(while, while_, TOK_WHILE) \
macro(with, with, TOK_WITH) \
macro(import, import, TOK_IMPORT) \
macro(export, export, TOK_EXPORT) \
macro(export, export_, TOK_EXPORT) \
macro(class, class_, TOK_CLASS) \
macro(extends, extends, TOK_EXTENDS) \
macro(super, super, TOK_SUPER) \
/* Reserved keywords. */ \
macro(enum, enum_, TOK_RESERVED) \
/* Future reserved keywords, but only in strict mode. */ \
macro(implements, implements, TOK_STRICT_RESERVED) \
macro(interface, interface, TOK_STRICT_RESERVED) \
macro(package, package, TOK_STRICT_RESERVED) \
macro(private, private_, TOK_STRICT_RESERVED) \
macro(protected, protected_, TOK_STRICT_RESERVED) \
macro(public, public_, TOK_STRICT_RESERVED) \
\
/* Future reserved words. */ \
macro(enum, enum_, TOK_ENUM) \
\
/* Future reserved words, but only in strict mode. */ \
macro(implements, implements, TOK_IMPLEMENTS) \
macro(interface, interface, TOK_INTERFACE) \
macro(package, package, TOK_PACKAGE) \
macro(private, private_, TOK_PRIVATE) \
macro(protected, protected_, TOK_PROTECTED) \
macro(public, public_, TOK_PUBLIC) \
\
/* Contextual keywords. */ \
macro(as, as, TOK_AS) \
macro(async, async, TOK_ASYNC) \
macro(await, await, TOK_AWAIT) \
macro(each, each, TOK_EACH) \
macro(from, from, TOK_FROM) \
macro(get, get, TOK_GET) \
macro(let, let, TOK_LET) \
macro(of, of, TOK_OF) \
macro(set, set, TOK_SET) \
macro(static, static_, TOK_STATIC) \
macro(target, target, TOK_TARGET) \
/* \
* Yield is a token inside function*. Outside of a function*, it is a \
* future reserved keyword in strict mode, but a keyword in JS1.7 even \
* future reserved word in strict mode, but a keyword in JS1.7 even \
* when strict. Punt logic to parser. \
*/ \
macro(yield, yield, TOK_YIELD)
#endif /* vm_Keywords_h */
#endif /* vm_ReservedWords_h */

View file

@ -38,6 +38,7 @@ enum class StatementKind : uint8_t
ForOfLoop,
DoLoop,
WhileLoop,
Class,
// Used only by BytecodeEmitter.
Spread
@ -450,7 +451,8 @@ class FunctionBox : public ObjectBox, public SharedContext
uint32_t bufEnd;
uint32_t startLine;
uint32_t startColumn;
uint32_t preludeStart;
uint32_t toStringStart;
uint32_t toStringEnd;
uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
@ -473,11 +475,14 @@ class FunctionBox : public ObjectBox, public SharedContext
bool usesThis:1; /* contains 'this' */
bool usesReturn:1; /* contains a 'return' statement */
bool hasRest_:1; /* has rest parameter */
bool isExprBody_:1; /* arrow function with expression
* body or expression closure:
* function(x) x*x */
FunctionContextFlags funCxFlags;
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
uint32_t preludeStart, Directives directives, bool extraWarnings,
uint32_t toStringStart, Directives directives, bool extraWarnings,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
@ -546,6 +551,11 @@ class FunctionBox : public ObjectBox, public SharedContext
hasRest_ = true;
}
bool isExprBody() const { return isExprBody_; }
void setIsExprBody() {
isExprBody_ = true;
}
void setGeneratorKind(GeneratorKind kind) {
// A generator kind can be set at initialization, or when "yield" is
// first seen. In both cases the transition can only happen from
@ -595,6 +605,14 @@ class FunctionBox : public ObjectBox, public SharedContext
tokenStream.srcCoords.lineNumAndColumnIndex(bufStart, &startLine, &startColumn);
}
void setEnd(uint32_t end) {
// For all functions except class constructors, the buffer and
// toString ending positions are the same. Class constructors override
// the toString ending position with the end of the class definition.
bufEnd = end;
toStringEnd = end;
}
void trace(JSTracer* trc) override;
};

View file

@ -56,13 +56,14 @@ namespace js {
M(SRC_NEXTCASE, "nextcase", 1) /* Distance forward from one CASE in a CONDSWITCH to \
the next. */ \
M(SRC_ASSIGNOP, "assignop", 0) /* += or another assign-op follows. */ \
M(SRC_CLASS_SPAN, "class", 2) /* The starting and ending offsets for the class, used \
for toString correctness for default ctors. */ \
M(SRC_TRY, "try", 1) /* JSOP_TRY, offset points to goto at the end of the \
try block. */ \
/* All notes above here are "gettable". See SN_IS_GETTABLE below. */ \
M(SRC_COLSPAN, "colspan", 1) /* Number of columns this opcode spans. */ \
M(SRC_NEWLINE, "newline", 0) /* Bytecode follows a source newline. */ \
M(SRC_SETLINE, "setline", 1) /* A file-absolute source line number note. */ \
M(SRC_UNUSED20, "unused20", 0) /* Unused. */ \
M(SRC_UNUSED21, "unused21", 0) /* Unused. */ \
M(SRC_UNUSED22, "unused22", 0) /* Unused. */ \
M(SRC_UNUSED23, "unused23", 0) /* Unused. */ \

View file

@ -9,6 +9,8 @@
#include "mozilla/Attributes.h"
#include <string.h>
#include "frontend/ParseNode.h"
#include "frontend/TokenStream.h"
@ -94,10 +96,13 @@ class SyntaxParseHandler
// Nodes representing unparenthesized names.
NodeUnparenthesizedArgumentsName,
NodeUnparenthesizedAsyncName,
NodeUnparenthesizedEvalName,
NodeUnparenthesizedName,
// Node representing the "async" name, which may actually be a
// contextual keyword.
NodePotentialAsyncKeyword,
// Valuable for recognizing potential destructuring patterns.
NodeUnparenthesizedArray,
NodeUnparenthesizedObject,
@ -183,8 +188,8 @@ class SyntaxParseHandler
lastAtom = name;
if (name == cx->names().arguments)
return NodeUnparenthesizedArgumentsName;
if (name == cx->names().async)
return NodeUnparenthesizedAsyncName;
if (pos.begin + strlen("async") == pos.end && name == cx->names().async)
return NodePotentialAsyncKeyword;
if (name == cx->names().eval)
return NodeUnparenthesizedEvalName;
return NodeUnparenthesizedName;
@ -219,6 +224,7 @@ class SyntaxParseHandler
Node newThisLiteral(const TokenPos& pos, Node thisName) { return NodeGeneric; }
Node newNullLiteral(const TokenPos& pos) { return NodeGeneric; }
Node newRawUndefinedLiteral(const TokenPos& pos) { return NodeGeneric; }
template <class Boxer>
Node newRegExp(RegExpObject* reobj, const TokenPos& pos, Boxer& boxer) { return NodeGeneric; }
@ -235,6 +241,10 @@ class SyntaxParseHandler
return NodeUnparenthesizedUnary;
}
Node newNullary(ParseNodeKind kind, JSOp op, const TokenPos& pos) {
return NodeGeneric;
}
Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) {
return NodeUnparenthesizedUnary;
}
@ -279,7 +289,7 @@ class SyntaxParseHandler
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
Node newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; }
Node newClass(Node name, Node heritage, Node methodBlock) { return NodeGeneric; }
Node newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; }
Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
@ -288,6 +298,7 @@ class SyntaxParseHandler
MOZ_MUST_USE bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
MOZ_MUST_USE bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; }
MOZ_MUST_USE bool addShorthand(Node literal, Node name, Node expr) { return true; }
MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; }
MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
@ -302,6 +313,16 @@ class SyntaxParseHandler
MOZ_MUST_USE bool prependInitialYield(Node stmtList, Node gen) { return true; }
Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; }
Node newExportDeclaration(Node kid, const TokenPos& pos) {
return NodeGeneric;
}
Node newExportFromDeclaration(uint32_t begin, Node exportSpecSet, Node moduleSpec) {
return NodeGeneric;
}
Node newExportDefaultDeclaration(Node kid, Node maybeBinding, const TokenPos& pos) {
return NodeGeneric;
}
Node newSetThis(Node thisName, Node value) { return value; }
Node newExprStatement(Node expr, uint32_t end) {
@ -497,7 +518,7 @@ class SyntaxParseHandler
return NodeParenthesizedArgumentsName;
if (node == NodeUnparenthesizedEvalName)
return NodeParenthesizedEvalName;
if (node == NodeUnparenthesizedName || node == NodeUnparenthesizedAsyncName)
if (node == NodeUnparenthesizedName || node == NodePotentialAsyncKeyword)
return NodeParenthesizedName;
if (node == NodeUnparenthesizedArray)
@ -528,9 +549,9 @@ class SyntaxParseHandler
bool isUnparenthesizedName(Node node) {
return node == NodeUnparenthesizedArgumentsName ||
node == NodeUnparenthesizedAsyncName ||
node == NodeUnparenthesizedEvalName ||
node == NodeUnparenthesizedName;
node == NodeUnparenthesizedName ||
node == NodePotentialAsyncKeyword;
}
bool isNameAnyParentheses(Node node) {
@ -541,9 +562,11 @@ class SyntaxParseHandler
node == NodeParenthesizedName;
}
bool nameIsEvalAnyParentheses(Node node, ExclusiveContext* cx) {
MOZ_ASSERT(isNameAnyParentheses(node),
"must only call this function on known names");
bool isArgumentsAnyParentheses(Node node, ExclusiveContext* cx) {
return node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName;
}
bool isEvalAnyParentheses(Node node, ExclusiveContext* cx) {
return node == NodeUnparenthesizedEvalName || node == NodeParenthesizedEvalName;
}
@ -551,17 +574,15 @@ class SyntaxParseHandler
MOZ_ASSERT(isNameAnyParentheses(node),
"must only call this method on known names");
if (nameIsEvalAnyParentheses(node, cx))
if (isEvalAnyParentheses(node, cx))
return js_eval_str;
if (node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName)
if (isArgumentsAnyParentheses(node, cx))
return js_arguments_str;
return nullptr;
}
bool nameIsUnparenthesizedAsync(Node node, ExclusiveContext* cx) {
MOZ_ASSERT(isNameAnyParentheses(node),
"must only call this function on known names");
return node == NodeUnparenthesizedAsyncName;
bool isAsyncKeyword(Node node, ExclusiveContext* cx) {
return node == NodePotentialAsyncKeyword;
}
PropertyName* maybeDottedProperty(Node node) {

View file

@ -81,9 +81,12 @@
\
macro(REGEXP, "regular expression literal") \
macro(TRUE, "boolean literal 'true'") \
range(RESERVED_WORD_LITERAL_FIRST, TRUE) \
macro(FALSE, "boolean literal 'false'") \
macro(NULL, "null literal") \
range(RESERVED_WORD_LITERAL_LAST, NULL) \
macro(THIS, "keyword 'this'") \
range(KEYWORD_FIRST, THIS) \
macro(FUNCTION, "keyword 'function'") \
macro(IF, "keyword 'if'") \
macro(ELSE, "keyword 'else'") \
@ -106,16 +109,43 @@
macro(FINALLY, "keyword 'finally'") \
macro(THROW, "keyword 'throw'") \
macro(DEBUGGER, "keyword 'debugger'") \
macro(YIELD, "keyword 'yield'") \
macro(AWAIT, "keyword 'await'") \
macro(EXPORT, "keyword 'export'") \
macro(IMPORT, "keyword 'import'") \
macro(CLASS, "keyword 'class'") \
macro(EXTENDS, "keyword 'extends'") \
macro(SUPER, "keyword 'super'") \
macro(RESERVED, "reserved keyword") \
/* reserved keywords in strict mode */ \
macro(STRICT_RESERVED, "reserved keyword") \
range(KEYWORD_LAST, SUPER) \
\
/* contextual keywords */ \
macro(AS, "'as'") \
range(CONTEXTUAL_KEYWORD_FIRST, AS) \
macro(ASYNC, "'async'") \
macro(AWAIT, "'await'") \
macro(EACH, "'each'") \
macro(FROM, "'from'") \
macro(GET, "'get'") \
macro(LET, "'let'") \
macro(OF, "'of'") \
macro(SET, "'set'") \
macro(STATIC, "'static'") \
macro(TARGET, "'target'") \
macro(YIELD, "'yield'") \
range(CONTEXTUAL_KEYWORD_LAST, YIELD) \
\
/* future reserved words */ \
macro(ENUM, "reserved word 'enum'") \
range(FUTURE_RESERVED_KEYWORD_FIRST, ENUM) \
range(FUTURE_RESERVED_KEYWORD_LAST, ENUM) \
\
/* reserved words in strict mode */ \
macro(IMPLEMENTS, "reserved word 'implements'") \
range(STRICT_RESERVED_KEYWORD_FIRST, IMPLEMENTS) \
macro(INTERFACE, "reserved word 'interface'") \
macro(PACKAGE, "reserved word 'package'") \
macro(PRIVATE, "reserved word 'private'") \
macro(PROTECTED, "reserved word 'protected'") \
macro(PUBLIC, "reserved word 'public'") \
range(STRICT_RESERVED_KEYWORD_LAST, PUBLIC) \
\
/* \
* The following token types occupy contiguous ranges to enable easy \
@ -149,7 +179,9 @@
range(RELOP_LAST, GE) \
\
macro(INSTANCEOF, "keyword 'instanceof'") \
range(KEYWORD_BINOP_FIRST, INSTANCEOF) \
macro(IN, "keyword 'in'") \
range(KEYWORD_BINOP_LAST, IN) \
\
/* Shift ops, per TokenKindIsShift. */ \
macro(LSH, "'<<'") \
@ -168,7 +200,9 @@
\
/* Unary operation tokens. */ \
macro(TYPEOF, "keyword 'typeof'") \
range(KEYWORD_UNOP_FIRST, TYPEOF) \
macro(VOID, "keyword 'void'") \
range(KEYWORD_UNOP_LAST, VOID) \
macro(NOT, "'!'") \
macro(BITNOT, "'~'") \
\
@ -239,6 +273,61 @@ TokenKindIsAssignment(TokenKind tt)
return TOK_ASSIGNMENT_START <= tt && tt <= TOK_ASSIGNMENT_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsKeyword(TokenKind tt)
{
return (TOK_KEYWORD_FIRST <= tt && tt <= TOK_KEYWORD_LAST) ||
(TOK_KEYWORD_BINOP_FIRST <= tt && tt <= TOK_KEYWORD_BINOP_LAST) ||
(TOK_KEYWORD_UNOP_FIRST <= tt && tt <= TOK_KEYWORD_UNOP_LAST);
}
inline MOZ_MUST_USE bool
TokenKindIsContextualKeyword(TokenKind tt)
{
return TOK_CONTEXTUAL_KEYWORD_FIRST <= tt && tt <= TOK_CONTEXTUAL_KEYWORD_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsFutureReservedWord(TokenKind tt)
{
return TOK_FUTURE_RESERVED_KEYWORD_FIRST <= tt && tt <= TOK_FUTURE_RESERVED_KEYWORD_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsStrictReservedWord(TokenKind tt)
{
return TOK_STRICT_RESERVED_KEYWORD_FIRST <= tt && tt <= TOK_STRICT_RESERVED_KEYWORD_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsReservedWordLiteral(TokenKind tt)
{
return TOK_RESERVED_WORD_LITERAL_FIRST <= tt && tt <= TOK_RESERVED_WORD_LITERAL_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsReservedWord(TokenKind tt)
{
return TokenKindIsKeyword(tt) ||
TokenKindIsFutureReservedWord(tt) ||
TokenKindIsReservedWordLiteral(tt);
}
inline MOZ_MUST_USE bool
TokenKindIsPossibleIdentifier(TokenKind tt)
{
return tt == TOK_NAME ||
TokenKindIsContextualKeyword(tt) ||
TokenKindIsStrictReservedWord(tt);
}
inline MOZ_MUST_USE bool
TokenKindIsPossibleIdentifierName(TokenKind tt)
{
return TokenKindIsPossibleIdentifier(tt) ||
TokenKindIsReservedWord(tt);
}
} // namespace frontend
} // namespace js

View file

@ -8,6 +8,7 @@
#include "frontend/TokenStream.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/IntegerTypeTraits.h"
#include "mozilla/PodOperations.h"
@ -23,80 +24,81 @@
#include "jsnum.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/ReservedWords.h"
#include "js/CharacterEncoding.h"
#include "js/UniquePtr.h"
#include "vm/HelperThreads.h"
#include "vm/Keywords.h"
#include "vm/StringBuffer.h"
#include "vm/Unicode.h"
using namespace js;
using namespace js::frontend;
using mozilla::ArrayLength;
using mozilla::Maybe;
using mozilla::PodAssign;
using mozilla::PodCopy;
using mozilla::PodZero;
struct KeywordInfo {
const char* chars; // C string with keyword text
struct ReservedWordInfo {
const char* chars; // C string with reserved word text
TokenKind tokentype;
};
static const KeywordInfo keywords[] = {
#define KEYWORD_INFO(keyword, name, type) \
{js_##keyword##_str, type},
FOR_EACH_JAVASCRIPT_KEYWORD(KEYWORD_INFO)
#undef KEYWORD_INFO
static const ReservedWordInfo reservedWords[] = {
#define RESERVED_WORD_INFO(word, name, type) \
{js_##word##_str, type},
FOR_EACH_JAVASCRIPT_RESERVED_WORD(RESERVED_WORD_INFO)
#undef RESERVED_WORD_INFO
};
// Returns a KeywordInfo for the specified characters, or nullptr if the string
// is not a keyword.
// Returns a ReservedWordInfo for the specified characters, or nullptr if the
// string is not a reserved word.
template <typename CharT>
static const KeywordInfo*
FindKeyword(const CharT* s, size_t length)
static const ReservedWordInfo*
FindReservedWord(const CharT* s, size_t length)
{
MOZ_ASSERT(length != 0);
size_t i;
const KeywordInfo* kw;
const ReservedWordInfo* rw;
const char* chars;
#define JSKW_LENGTH() length
#define JSKW_AT(column) s[column]
#define JSKW_GOT_MATCH(index) i = (index); goto got_match;
#define JSKW_TEST_GUESS(index) i = (index); goto test_guess;
#define JSKW_NO_MATCH() goto no_match;
#include "jsautokw.h"
#undef JSKW_NO_MATCH
#undef JSKW_TEST_GUESS
#undef JSKW_GOT_MATCH
#undef JSKW_AT
#undef JSKW_LENGTH
#define JSRW_LENGTH() length
#define JSRW_AT(column) s[column]
#define JSRW_GOT_MATCH(index) i = (index); goto got_match;
#define JSRW_TEST_GUESS(index) i = (index); goto test_guess;
#define JSRW_NO_MATCH() goto no_match;
#include "frontend/ReservedWordsGenerated.h"
#undef JSRW_NO_MATCH
#undef JSRW_TEST_GUESS
#undef JSRW_GOT_MATCH
#undef JSRW_AT
#undef JSRW_LENGTH
got_match:
return &keywords[i];
return &reservedWords[i];
test_guess:
kw = &keywords[i];
chars = kw->chars;
rw = &reservedWords[i];
chars = rw->chars;
do {
if (*s++ != (unsigned char)(*chars++))
goto no_match;
} while (--length != 0);
return kw;
return rw;
no_match:
return nullptr;
}
static const KeywordInfo*
FindKeyword(JSLinearString* str)
static const ReservedWordInfo*
FindReservedWord(JSLinearString* str)
{
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? FindKeyword(str->latin1Chars(nogc), str->length())
: FindKeyword(str->twoByteChars(nogc), str->length());
? FindReservedWord(str->latin1Chars(nogc), str->length())
: FindReservedWord(str->twoByteChars(nogc), str->length());
}
template <typename CharT>
@ -186,7 +188,68 @@ frontend::IsIdentifier(const char16_t* chars, size_t length)
bool
frontend::IsKeyword(JSLinearString* str)
{
return FindKeyword(str) != nullptr;
if (const ReservedWordInfo* rw = FindReservedWord(str))
return TokenKindIsKeyword(rw->tokentype);
return false;
}
bool
frontend::IsFutureReservedWord(JSLinearString* str)
{
if (const ReservedWordInfo* rw = FindReservedWord(str))
return TokenKindIsFutureReservedWord(rw->tokentype);
return false;
}
bool
frontend::IsStrictReservedWord(JSLinearString* str)
{
if (const ReservedWordInfo* rw = FindReservedWord(str))
return TokenKindIsStrictReservedWord(rw->tokentype);
return false;
}
bool
frontend::IsReservedWordLiteral(JSLinearString* str)
{
if (const ReservedWordInfo* rw = FindReservedWord(str))
return TokenKindIsReservedWordLiteral(rw->tokentype);
return false;
}
const char*
frontend::ReservedWordToCharZ(PropertyName* str)
{
const ReservedWordInfo* rw = FindReservedWord(str);
if (rw == nullptr)
return nullptr;
switch (rw->tokentype) {
#define EMIT_CASE(word, name, type) case type: return js_##word##_str;
FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE)
#undef EMIT_CASE
default:
MOZ_ASSERT_UNREACHABLE("Not a reserved word PropertyName.");
}
return nullptr;
}
PropertyName*
TokenStream::reservedWordToPropertyName(TokenKind tt) const
{
MOZ_ASSERT(tt != TOK_NAME);
switch (tt) {
#define EMIT_CASE(word, name, type) case type: return cx->names().name;
FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE)
#undef EMIT_CASE
default:
MOZ_ASSERT_UNREACHABLE("Not a reserved word TokenKind.");
}
return nullptr;
}
TokenStream::SourceCoords::SourceCoords(ExclusiveContext* cx, uint32_t ln)
@ -223,8 +286,13 @@ TokenStream::SourceCoords::add(uint32_t lineNum, uint32_t lineStartOffset)
// only if lineStartOffsets_.append succeeds, to keep sentinel.
// Otherwise return false to tell TokenStream about OOM.
uint32_t maxPtr = MAX_PTR;
if (!lineStartOffsets_.append(maxPtr))
if (!lineStartOffsets_.append(maxPtr)) {
static_assert(mozilla::IsSame<decltype(lineStartOffsets_.allocPolicy()),
TempAllocPolicy&>::value,
"this function's caller depends on it reporting an "
"error on failure, as TempAllocPolicy ensures");
return false;
}
lineStartOffsets_[lineIndex] = lineStartOffset;
} else {
@ -554,8 +622,9 @@ TokenStream::advance(size_t position)
MOZ_MAKE_MEM_UNDEFINED(&cur->type, sizeof(cur->type));
lookahead = 0;
if (flags.hitOOM)
return reportError(JSMSG_OUT_OF_MEMORY);
if (flags.hitOOM) {
return false;
}
return true;
}
@ -599,8 +668,8 @@ TokenStream::seek(const Position& pos, const TokenStream& other)
}
bool
TokenStream::reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber,
va_list args)
TokenStream::reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
bool strictMode, unsigned errorNumber, va_list args)
{
// In strict mode code, this is an error, not merely a warning.
unsigned flags;
@ -611,7 +680,7 @@ TokenStream::reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, uns
else
return true;
return reportCompileErrorNumberVA(offset, flags, errorNumber, args);
return reportCompileErrorNumberVA(Move(notes), offset, flags, errorNumber, args);
}
void
@ -637,8 +706,8 @@ CompileError::throwError(JSContext* cx)
}
bool
TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigned errorNumber,
va_list args)
TokenStream::reportCompileErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
unsigned flags, unsigned errorNumber, va_list args)
{
bool warning = JSREPORT_IS_WARNING(flags);
@ -655,6 +724,7 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
return false;
CompileError& err = *tempErrPtr;
err.notes = Move(notes);
err.flags = flags;
err.errorNumber = errorNumber;
err.filename = filename;
@ -746,7 +816,7 @@ TokenStream::reportStrictModeError(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool result = reportStrictModeErrorNumberVA(currentToken().pos.begin, strictMode(),
bool result = reportStrictModeErrorNumberVA(nullptr, currentToken().pos.begin, strictMode(),
errorNumber, args);
va_end(args);
return result;
@ -757,8 +827,8 @@ TokenStream::reportError(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool result = reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_ERROR, errorNumber,
args);
bool result = reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_ERROR,
errorNumber, args);
va_end(args);
return result;
}
@ -768,30 +838,32 @@ TokenStream::reportErrorNoOffset(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool result = reportCompileErrorNumberVA(NoOffset, JSREPORT_ERROR, errorNumber,
args);
va_end(args);
return result;
}
bool
TokenStream::reportWarning(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool result = reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_WARNING,
bool result = reportCompileErrorNumberVA(nullptr, NoOffset, JSREPORT_ERROR,
errorNumber, args);
va_end(args);
return result;
}
bool
TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args)
TokenStream::warning(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool result = reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_WARNING,
errorNumber, args);
va_end(args);
return result;
}
bool
TokenStream::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
unsigned errorNumber, va_list args)
{
if (!options().extraWarningsOption)
return true;
return reportCompileErrorNumberVA(offset, JSREPORT_STRICT|JSREPORT_WARNING, errorNumber, args);
return reportCompileErrorNumberVA(Move(notes), offset, JSREPORT_STRICT|JSREPORT_WARNING,
errorNumber, args);
}
void
@ -802,7 +874,34 @@ TokenStream::reportAsmJSError(uint32_t offset, unsigned errorNumber, ...)
unsigned flags = options().throwOnAsmJSValidationFailureOption
? JSREPORT_ERROR
: JSREPORT_WARNING;
reportCompileErrorNumberVA(offset, flags, errorNumber, args);
reportCompileErrorNumberVA(nullptr, offset, flags, errorNumber, args);
va_end(args);
}
void
TokenStream::error(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
#ifdef DEBUG
bool result =
#endif
reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_ERROR,
errorNumber, args);
MOZ_ASSERT(!result, "reporting an error returned true?");
va_end(args);
}
void
TokenStream::errorAt(uint32_t offset, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
#ifdef DEBUG
bool result =
#endif
reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, errorNumber, args);
MOZ_ASSERT(!result, "reporting an error returned true?");
va_end(args);
}
@ -934,34 +1033,49 @@ TokenStream::getDirectives(bool isMultiline, bool shouldWarnDeprecated)
bool
TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated,
const char* directive, int directiveLength,
const char* directive, uint8_t directiveLength,
const char* errorMsgPragma,
UniqueTwoByteChars* destination)
{
MOZ_ASSERT(directiveLength <= 18);
char16_t peeked[18];
int32_t c;
if (peekChars(directiveLength, peeked) && CharsMatch(peeked, directive)) {
if (shouldWarnDeprecated &&
!reportWarning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma))
return false;
if (shouldWarnDeprecated) {
if (!warning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma))
return false;
}
skipChars(directiveLength);
tokenbuf.clear();
while ((c = peekChar()) && c != EOF && !unicode::IsSpaceOrBOM2(c)) {
getChar();
do {
int32_t c;
if (!peekChar(&c))
return false;
if (c == EOF || unicode::IsSpaceOrBOM2(c))
break;
consumeKnownChar(c);
// Debugging directives can occur in both single- and multi-line
// comments. If we're currently inside a multi-line comment, we also
// need to recognize multi-line comment terminators.
if (isMultiline && c == '*' && peekChar() == '/') {
ungetChar('*');
break;
if (isMultiline && c == '*') {
int32_t c2;
if (!peekChar(&c2))
return false;
if (c2 == '/') {
ungetChar('*');
break;
}
}
if (!tokenbuf.append(c))
return false;
}
} while (true);
if (tokenbuf.empty()) {
// The directive's URL was missing, but this is not quite an
@ -993,7 +1107,10 @@ TokenStream::getDisplayURL(bool isMultiline, bool shouldWarnDeprecated)
// developer would like to refer to the source as from the source's actual
// URL.
return getDirective(isMultiline, shouldWarnDeprecated, " sourceURL=", 11,
static const char sourceURLDirective[] = " sourceURL=";
constexpr uint8_t sourceURLDirectiveLength = ArrayLength(sourceURLDirective) - 1;
return getDirective(isMultiline, shouldWarnDeprecated,
sourceURLDirective, sourceURLDirectiveLength,
"sourceURL", &displayURL_);
}
@ -1003,7 +1120,10 @@ TokenStream::getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated)
// Match comments of the form "//# sourceMappingURL=<url>" or
// "/\* //# sourceMappingURL=<url> *\/"
return getDirective(isMultiline, shouldWarnDeprecated, " sourceMappingURL=", 18,
static const char sourceMappingURLDirective[] = " sourceMappingURL=";
constexpr uint8_t sourceMappingURLDirectiveLength = ArrayLength(sourceMappingURLDirective) - 1;
return getDirective(isMultiline, shouldWarnDeprecated,
sourceMappingURLDirective, sourceMappingURLDirectiveLength,
"sourceMappingURL", &sourceMapURL_);
}
@ -1110,36 +1230,6 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart)
return true;
}
bool
TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp)
{
if (!awaitIsKeyword && kw->tokentype == TOK_AWAIT) {
if (ttp)
*ttp = TOK_NAME;
return true;
}
if (kw->tokentype == TOK_RESERVED)
return reportError(JSMSG_RESERVED_ID, kw->chars);
if (kw->tokentype == TOK_STRICT_RESERVED)
return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars);
// Working keyword.
*ttp = kw->tokentype;
return true;
}
bool
TokenStream::checkForKeyword(JSAtom* atom, TokenKind* ttp)
{
const KeywordInfo* kw = FindKeyword(atom);
if (!kw)
return true;
return checkForKeyword(kw, ttp);
}
enum FirstCharKind {
// A char16_t has the 'OneChar' kind if it, by itself, constitutes a valid
// token that cannot also be a prefix of a longer token. E.g. ';' has the
@ -1363,36 +1453,18 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
length = userbuf.addressOfNextRawChar() - identStart;
}
// Represent keywords as keyword tokens unless told otherwise.
if (modifier != KeywordIsName) {
if (const KeywordInfo* kw = FindKeyword(chars, length)) {
// That said, keywords can't contain escapes. (Contexts where
// keywords are treated as names, that also sometimes treat
// keywords as keywords, must manually check this requirement.)
// There are two exceptions
// 1) StrictReservedWords: These keywords need to be treated as
// names in non-strict mode.
// 2) yield is also treated as a name if it contains an escape
// sequence. The parser must handle this case separately.
if (hadUnicodeEscape && !(
(kw->tokentype == TOK_STRICT_RESERVED && !strictMode()) ||
kw->tokentype == TOK_YIELD))
{
reportError(JSMSG_ESCAPED_KEYWORD);
goto error;
}
tp->type = TOK_NAME;
if (!checkForKeyword(kw, &tp->type))
goto error;
if (tp->type != TOK_NAME && !hadUnicodeEscape)
goto out;
// Represent reserved words as reserved word tokens.
if (!hadUnicodeEscape) {
if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
tp->type = rw->tokentype;
goto out;
}
}
JSAtom* atom = AtomizeChars(cx, chars, length);
if (!atom)
if (!atom) {
goto error;
}
tp->type = TOK_NAME;
tp->setName(atom->asPropertyName());
goto out;
@ -1538,10 +1610,11 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
// grammar. We might not always be so permissive, so we warn
// about it.
if (c >= '8') {
if (!reportWarning(JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) {
if (!warning(JSMSG_BAD_OCTAL, c == '8' ? "08" : "09"))
goto error;
}
goto decimal; // use the decimal scanner for the rest of the number
// Use the decimal scanner for the rest of the number.
goto decimal;
}
c = getCharIgnoreEOL();
}
@ -1690,7 +1763,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
case '/':
// Look for a single-line comment.
if (matchChar('/')) {
c = peekChar();
if (!peekChar(&c))
goto error;
if (c == '@' || c == '#') {
bool shouldWarn = getChar() == '@';
if (!getDirectives(false, shouldWarn))
@ -1757,7 +1831,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
RegExpFlag reflags = NoFlags;
unsigned length = tokenbuf.length() + 1;
while (true) {
c = peekChar();
if (!peekChar(&c))
goto error;
if (c == 'g' && !(reflags & GlobalFlag))
reflags = RegExpFlag(reflags | GlobalFlag);
else if (c == 'i' && !(reflags & IgnoreCaseFlag))
@ -1774,7 +1849,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
length++;
}
c = peekChar();
if (!peekChar(&c))
goto error;
if (JS7_ISLET(c)) {
char buf[2] = { '\0', '\0' };
tp->pos.begin += length + 1;
@ -1797,8 +1873,13 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
case '-':
if (matchChar('-')) {
if (peekChar() == '>' && !flags.isDirtyLine)
int32_t c2;
if (!peekChar(&c2))
goto error;
if (c2 == '>' && !flags.isDirtyLine)
goto skipline;
tp->type = TOK_DEC;
} else {
tp->type = matchChar('=') ? TOK_SUBASSIGN : TOK_SUB;
@ -1814,8 +1895,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
MOZ_CRASH("should have jumped to |out| or |error|");
out:
if (flags.hitOOM)
return reportError(JSMSG_OUT_OF_MEMORY);
if (flags.hitOOM) {
return false;
}
flags.isDirtyLine = true;
tp->pos.end = userbuf.offset();
@ -1831,8 +1913,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
return true;
error:
if (flags.hitOOM)
return reportError(JSMSG_OUT_OF_MEMORY);
if (flags.hitOOM) {
return false;
}
flags.isDirtyLine = true;
tp->pos.end = userbuf.offset();
@ -1849,37 +1932,6 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
return false;
}
bool
TokenStream::getBracedUnicode(uint32_t* cp)
{
consumeKnownChar('{');
bool first = true;
int32_t c;
uint32_t code = 0;
while (true) {
c = getCharIgnoreEOL();
if (c == EOF)
return false;
if (c == '}') {
if (first)
return false;
break;
}
if (!JS7_ISHEX(c))
return false;
code = (code << 4) | JS7_UNHEX(c);
if (code > unicode::NonBMPMax)
return false;
first = false;
}
*cp = code;
return true;
}
bool
TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
{
@ -1897,11 +1949,15 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
while ((c = getCharIgnoreEOL()) != untilChar) {
if (c == EOF) {
ungetCharIgnoreEOL(c);
reportError(JSMSG_UNTERMINATED_STRING);
error(JSMSG_UNTERMINATED_STRING);
return false;
}
if (c == '\\') {
// When parsing templates, we don't immediately report errors for
// invalid escapes; these are handled by the parser.
// In those cases we don't append to tokenbuf, since it won't be
// read.
switch (c = getChar()) {
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
@ -1917,12 +1973,73 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
// Unicode character specification.
case 'u': {
if (peekChar() == '{') {
uint32_t code;
if (!getBracedUnicode(&code)) {
reportError(JSMSG_MALFORMED_ESCAPE, "Unicode");
return false;
}
uint32_t code = 0;
int32_t c2;
if (!peekChar(&c2))
return false;
uint32_t start = userbuf.offset() - 2;
if (c2 == '{') {
consumeKnownChar('{');
bool first = true;
bool valid = true;
do {
int32_t c = getCharIgnoreEOL();
if (c == EOF) {
if (parsingTemplate) {
setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
valid = false;
break;
}
reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
return false;
}
if (c == '}') {
if (first) {
if (parsingTemplate) {
setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
valid = false;
break;
}
reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
return false;
}
break;
}
if (!JS7_ISHEX(c)) {
if (parsingTemplate) {
// We put the character back so that we read
// it on the next pass, which matters if it
// was '`' or '\'.
ungetCharIgnoreEOL(c);
setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
valid = false;
break;
}
reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
return false;
}
code = (code << 4) | JS7_UNHEX(c);
if (code > unicode::NonBMPMax) {
if (parsingTemplate) {
setInvalidTemplateEscape(start + 3, InvalidEscapeType::UnicodeOverflow);
valid = false;
break;
}
reportInvalidEscapeError(start + 3, InvalidEscapeType::UnicodeOverflow);
return false;
}
first = false;
} while (true);
if (!valid)
continue;
MOZ_ASSERT(code <= unicode::NonBMPMax);
if (code < unicode::NonBMPMin) {
@ -1945,7 +2062,11 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
c = (c << 4) + JS7_UNHEX(cp[3]);
skipChars(4);
} else {
reportError(JSMSG_MALFORMED_ESCAPE, "Unicode");
if (parsingTemplate) {
setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
continue;
}
reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
return false;
}
break;
@ -1958,7 +2079,12 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
skipChars(2);
} else {
reportError(JSMSG_MALFORMED_ESCAPE, "hexadecimal");
uint32_t start = userbuf.offset() - 2;
if (parsingTemplate) {
setInvalidTemplateEscape(start, InvalidEscapeType::Hexadecimal);
continue;
}
reportInvalidEscapeError(start, InvalidEscapeType::Hexadecimal);
return false;
}
break;
@ -1969,13 +2095,14 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
if (JS7_ISOCT(c)) {
int32_t val = JS7_UNOCT(c);
c = peekChar();
if (!peekChar(&c))
return false;
// Strict mode code allows only \0, then a non-digit.
if (val != 0 || JS7_ISDEC(c)) {
if (parsingTemplate) {
reportError(JSMSG_DEPRECATED_OCTAL);
return false;
setInvalidTemplateEscape(userbuf.offset() - 2, InvalidEscapeType::Octal);
continue;
}
if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL))
return false;
@ -1985,7 +2112,8 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
if (JS7_ISOCT(c)) {
val = 8 * val + JS7_UNOCT(c);
getChar();
c = peekChar();
if (!peekChar(&c))
return false;
if (JS7_ISOCT(c)) {
int32_t save = val;
val = 8 * val + JS7_UNOCT(c);
@ -2003,7 +2131,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
} else if (TokenBuf::isRawEOLChar(c)) {
if (!parsingTemplate) {
ungetCharIgnoreEOL(c);
reportError(JSMSG_UNTERMINATED_STRING);
error(JSMSG_UNTERMINATED_STRING);
return false;
}
if (c == '\r') {

View file

@ -26,14 +26,13 @@
#include "js/UniquePtr.h"
#include "js/Vector.h"
#include "vm/RegExpObject.h"
#include "vm/String.h"
struct KeywordInfo;
namespace js {
namespace frontend {
class AutoAwaitIsKeyword;
struct TokenPos {
uint32_t begin; // Offset of the token's first char.
uint32_t end; // Offset of 1 past the token's last char.
@ -80,6 +79,20 @@ struct TokenPos {
enum DecimalPoint { NoDecimal = false, HasDecimal = true };
enum class InvalidEscapeType {
// No invalid character escapes.
None,
// A malformed \x escape.
Hexadecimal,
// A malformed \u escape.
Unicode,
// An otherwise well-formed \u escape which represents a
// codepoint > 10FFFF.
UnicodeOverflow,
// An octal escape in a template token.
Octal
};
class TokenStream;
struct Token
@ -106,9 +119,6 @@ struct Token
// TOK_DIV.
Operand,
// Treat keywords as names by returning TOK_NAME.
KeywordIsName,
// Treat subsequent characters as the tail of a template literal, after
// a template substitution, beginning with a "}", continuing with zero
// or more template literal characters, and ending with either "${" or
@ -150,10 +160,6 @@ struct Token
// If a semicolon is inserted automatically, the next token is already
// gotten with None, but we expect Operand.
OperandIsNone,
// If name of method definition is `get` or `set`, the next token is
// already gotten with KeywordIsName, but we expect None.
NoneIsKeywordIsName,
};
friend class TokenStream;
@ -210,11 +216,6 @@ struct Token
return u.name->JSAtom::asPropertyName(); // poor-man's type verification
}
bool nameContainsEscape() const {
PropertyName* n = name();
return pos.begin + n->length() != pos.end;
}
JSAtom* atom() const {
MOZ_ASSERT(type == TOK_STRING ||
type == TOK_TEMPLATE_HEAD ||
@ -240,10 +241,22 @@ struct Token
};
class CompileError : public JSErrorReport {
public:
public:
void throwError(JSContext* cx);
};
extern const char*
ReservedWordToCharZ(PropertyName* str);
extern MOZ_MUST_USE bool
IsFutureReservedWord(JSLinearString* str);
extern MOZ_MUST_USE bool
IsReservedWordLiteral(JSLinearString* str);
extern MOZ_MUST_USE bool
IsStrictReservedWord(JSLinearString* str);
// Ideally, tokenizing would be entirely independent of context. But the
// strict mode flag, which is in SharedContext, affects tokenizing, and
// TokenStream needs to see it.
@ -330,25 +343,26 @@ class MOZ_STACK_CLASS TokenStream
JSVersion versionNumber() const { return VersionNumber(options().version); }
JSVersion versionWithFlags() const { return options().version; }
private:
PropertyName* reservedWordToPropertyName(TokenKind tt) const;
public:
PropertyName* currentName() const {
if (isCurrentTokenType(TOK_YIELD))
return cx->names().yield;
MOZ_ASSERT(isCurrentTokenType(TOK_NAME));
return currentToken().name();
if (isCurrentTokenType(TOK_NAME)) {
return currentToken().name();
}
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(currentToken().type));
return reservedWordToPropertyName(currentToken().type);
}
PropertyName* nextName() const {
if (nextToken().type == TOK_YIELD)
return cx->names().yield;
MOZ_ASSERT(nextToken().type == TOK_NAME);
return nextToken().name();
}
if (nextToken().type != TOK_NAME) {
return nextToken().name();
}
bool nextNameContainsEscape() const {
if (nextToken().type == TOK_YIELD)
return false;
MOZ_ASSERT(nextToken().type == TOK_NAME);
return nextToken().nameContainsEscape();
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(nextToken().type));
return reservedWordToPropertyName(nextToken().type);
}
bool isCurrentTokenAssignment() const {
@ -361,21 +375,47 @@ class MOZ_STACK_CLASS TokenStream
bool hadError() const { return flags.hadError; }
void clearSawOctalEscape() { flags.sawOctalEscape = false; }
bool hasInvalidTemplateEscape() const {
return invalidTemplateEscapeType != InvalidEscapeType::None;
}
void clearInvalidTemplateEscape() {
invalidTemplateEscapeType = InvalidEscapeType::None;
}
// If there is an invalid escape in a template, report it and return false,
// otherwise return true.
bool checkForInvalidTemplateEscapeError() {
if (invalidTemplateEscapeType == InvalidEscapeType::None)
return true;
reportInvalidEscapeError(invalidTemplateEscapeOffset, invalidTemplateEscapeType);
return false;
}
// TokenStream-specific error reporters.
bool reportError(unsigned errorNumber, ...);
bool reportErrorNoOffset(unsigned errorNumber, ...);
bool reportWarning(unsigned errorNumber, ...);
// Report the given error at the current offset.
void error(unsigned errorNumber, ...);
// Report the given error at the given offset.
void errorAt(uint32_t offset, unsigned errorNumber, ...);
// Warn at the current offset.
MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
static const uint32_t NoOffset = UINT32_MAX;
// General-purpose error reporters. You should avoid calling these
// directly, and instead use the more succinct alternatives (e.g.
// reportError()) in TokenStream, Parser, and BytecodeEmitter.
bool reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigned errorNumber,
va_list args);
bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber,
va_list args);
bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args);
// directly, and instead use the more succinct alternatives (error(),
// warning(), &c.) in TokenStream, Parser, and BytecodeEmitter.
bool reportCompileErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, unsigned flags,
unsigned errorNumber, va_list args);
bool reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
bool strictMode, unsigned errorNumber, va_list args);
bool reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
unsigned errorNumber, va_list args);
// asm.js reporter
void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...);
@ -414,6 +454,33 @@ class MOZ_STACK_CLASS TokenStream
bool reportStrictModeError(unsigned errorNumber, ...);
bool strictMode() const { return strictModeGetter && strictModeGetter->strictMode(); }
void setInvalidTemplateEscape(uint32_t offset, InvalidEscapeType type) {
MOZ_ASSERT(type != InvalidEscapeType::None);
if (invalidTemplateEscapeType != InvalidEscapeType::None)
return;
invalidTemplateEscapeOffset = offset;
invalidTemplateEscapeType = type;
}
void reportInvalidEscapeError(uint32_t offset, InvalidEscapeType type) {
switch (type) {
case InvalidEscapeType::None:
MOZ_ASSERT_UNREACHABLE("unexpected InvalidEscapeType");
return;
case InvalidEscapeType::Hexadecimal:
errorAt(offset, JSMSG_MALFORMED_ESCAPE, "hexadecimal");
return;
case InvalidEscapeType::Unicode:
errorAt(offset, JSMSG_MALFORMED_ESCAPE, "Unicode");
return;
case InvalidEscapeType::UnicodeOverflow:
errorAt(offset, JSMSG_UNICODE_OVERFLOW, "escape sequence");
return;
case InvalidEscapeType::Octal:
errorAt(offset, JSMSG_DEPRECATED_OCTAL);
return;
}
}
static JSAtom* atomize(ExclusiveContext* cx, CharBuffer& cb);
MOZ_MUST_USE bool putIdentInTokenbuf(const char16_t* identStart);
@ -431,21 +498,19 @@ class MOZ_STACK_CLASS TokenStream
{}
};
bool awaitIsKeyword = false;
friend class AutoAwaitIsKeyword;
uint32_t invalidTemplateEscapeOffset = 0;
InvalidEscapeType invalidTemplateEscapeType = InvalidEscapeType::None;
public:
typedef Token::Modifier Modifier;
static constexpr Modifier None = Token::None;
static constexpr Modifier Operand = Token::Operand;
static constexpr Modifier KeywordIsName = Token::KeywordIsName;
static constexpr Modifier TemplateTail = Token::TemplateTail;
typedef Token::ModifierException ModifierException;
static constexpr ModifierException NoException = Token::NoException;
static constexpr ModifierException NoneIsOperand = Token::NoneIsOperand;
static constexpr ModifierException OperandIsNone = Token::OperandIsNone;
static constexpr ModifierException NoneIsKeywordIsName = Token::NoneIsKeywordIsName;
void addModifierException(ModifierException modifierException) {
#ifdef DEBUG
@ -474,10 +539,6 @@ class MOZ_STACK_CLASS TokenStream
MOZ_ASSERT(next.type != TOK_DIV && next.type != TOK_REGEXP,
"next token requires contextual specifier to be parsed unambiguously");
break;
case NoneIsKeywordIsName:
MOZ_ASSERT(next.modifier == KeywordIsName);
MOZ_ASSERT(next.type != TOK_NAME);
break;
default:
MOZ_CRASH("unexpected modifier exception");
}
@ -504,18 +565,17 @@ class MOZ_STACK_CLASS TokenStream
return;
}
if (lookaheadToken.modifierException == NoneIsKeywordIsName) {
// getToken() permissibly following getToken(KeywordIsName).
if (modifier == None && lookaheadToken.modifier == KeywordIsName)
return;
}
MOZ_ASSERT_UNREACHABLE("this token was previously looked up with a "
"different modifier, potentially making "
"tokenization non-deterministic");
#endif
}
const Token& nextToken() const {
MOZ_ASSERT(hasLookahead());
return tokens[(cursor + 1) & ntokensMask];
}
// Advance to the next token. If the token stream encountered an error,
// return false. Otherwise return true and store the token kind in |*ttp|.
MOZ_MUST_USE bool getToken(TokenKind* ttp, Modifier modifier = None) {
@ -644,36 +704,6 @@ class MOZ_STACK_CLASS TokenStream
MOZ_ALWAYS_TRUE(matched);
}
// Like matchToken(..., TOK_NAME) but further matching the name token only
// if it has the given characters, without containing escape sequences.
// If the name token has the given characters yet *does* contain an escape,
// a syntax error will be reported.
//
// This latter behavior makes this method unsuitable for use in any context
// where ASI might occur. In such places, an escaped "contextual keyword"
// on a new line is the start of an ExpressionStatement, not a continuation
// of a StatementListItem (or ImportDeclaration or ExportDeclaration, in
// modules).
MOZ_MUST_USE bool matchContextualKeyword(bool* matchedp, Handle<PropertyName*> keyword,
Modifier modifier = None)
{
TokenKind token;
if (!getToken(&token, modifier))
return false;
if (token == TOK_NAME && currentToken().name() == keyword) {
if (currentToken().nameContainsEscape()) {
reportError(JSMSG_ESCAPED_KEYWORD);
return false;
}
*matchedp = true;
} else {
*matchedp = false;
ungetToken();
}
return true;
}
MOZ_MUST_USE bool nextTokenEndsExpr(bool* endsExpr) {
TokenKind tt;
if (!peekToken(&tt))
@ -739,19 +769,6 @@ class MOZ_STACK_CLASS TokenStream
return sourceMapURL_.get();
}
// If |atom| is not a keyword in this version, return true with *ttp
// unchanged.
//
// If it is a reserved word in this version and strictness mode, and thus
// can't be present in correct code, report a SyntaxError and return false.
//
// If it is a keyword, like "if", return true with the keyword's TokenKind
// in *ttp.
MOZ_MUST_USE bool checkForKeyword(JSAtom* atom, TokenKind* ttp);
// Same semantics as above, but for the provided keyword.
MOZ_MUST_USE bool checkForKeyword(const KeywordInfo* kw, TokenKind* ttp);
// This class maps a userbuf offset (which is 0-indexed) to a line number
// (which is 1-indexed) and a column index (which is 0-indexed).
class SourceCoords
@ -947,7 +964,6 @@ class MOZ_STACK_CLASS TokenStream
MOZ_MUST_USE bool getTokenInternal(TokenKind* ttp, Modifier modifier);
MOZ_MUST_USE bool getBracedUnicode(uint32_t* code);
MOZ_MUST_USE bool getStringOrTemplateToken(int untilChar, Token** tp);
int32_t getChar();
@ -964,7 +980,7 @@ class MOZ_STACK_CLASS TokenStream
MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated);
MOZ_MUST_USE bool getDirective(bool isMultiline, bool shouldWarnDeprecated,
const char* directive, int directiveLength,
const char* directive, uint8_t directiveLength,
const char* errorMsgPragma,
UniquePtr<char16_t[], JS::FreePolicy>* destination);
MOZ_MUST_USE bool getDisplayURL(bool isMultiline, bool shouldWarnDeprecated);
@ -982,29 +998,30 @@ class MOZ_STACK_CLASS TokenStream
MOZ_ASSERT(c == expect);
}
int32_t peekChar() {
int32_t c = getChar();
ungetChar(c);
return c;
MOZ_MUST_USE bool peekChar(int32_t* c) {
*c = getChar();
ungetChar(*c);
return true;
}
void skipChars(int n) {
while (--n >= 0)
getChar();
void skipChars(uint8_t n) {
while (n-- > 0) {
MOZ_ASSERT(userbuf.hasRawChars());
mozilla::DebugOnly<int32_t> c = getCharIgnoreEOL();
MOZ_ASSERT(c != '\n');
}
}
void skipCharsIgnoreEOL(int n) {
while (--n >= 0)
void skipCharsIgnoreEOL(uint8_t n) {
while (n-- > 0) {
MOZ_ASSERT(userbuf.hasRawChars());
getCharIgnoreEOL();
}
}
void updateLineInfoForEOL();
void updateFlagsForEOL();
const Token& nextToken() const {
MOZ_ASSERT(hasLookahead());
return tokens[(cursor + 1) & ntokensMask];
}
bool hasLookahead() const { return lookahead > 0; }
@ -1029,25 +1046,6 @@ class MOZ_STACK_CLASS TokenStream
StrictModeGetter* strictModeGetter; // used to test for strict mode
};
class MOZ_STACK_CLASS AutoAwaitIsKeyword
{
private:
TokenStream* ts_;
bool oldAwaitIsKeyword_;
public:
AutoAwaitIsKeyword(TokenStream* ts, bool awaitIsKeyword) {
ts_ = ts;
oldAwaitIsKeyword_ = ts_->awaitIsKeyword;
ts_->awaitIsKeyword = awaitIsKeyword;
}
~AutoAwaitIsKeyword() {
ts_->awaitIsKeyword = oldAwaitIsKeyword_;
ts_ = nullptr;
}
};
extern const char*
TokenKindToDesc(TokenKind tt);

View file

@ -243,10 +243,10 @@ RegExpParser<CharT>::RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc,
template <typename CharT>
RegExpTree*
RegExpParser<CharT>::ReportError(unsigned errorNumber)
RegExpParser<CharT>::ReportError(unsigned errorNumber, const char* param /* = nullptr */)
{
gc::AutoSuppressGC suppressGC(ts.context());
ts.reportError(errorNumber);
ts.reportError(errorNumber, param);
return nullptr;
}
@ -350,7 +350,7 @@ RegExpParser<CharT>::ParseBracedHexEscape(widechar* value)
}
code = (code << 4) | d;
if (code > unicode::NonBMPMax) {
ReportError(JSMSG_UNICODE_OVERFLOW);
ReportError(JSMSG_UNICODE_OVERFLOW, "regular expression");
return false;
}
Advance();

View file

@ -211,7 +211,7 @@ class RegExpParser
bool ParseBackReferenceIndex(int* index_out);
bool ParseClassAtom(char16_t* char_class, widechar *value);
RegExpTree* ReportError(unsigned errorNumber);
RegExpTree* ReportError(unsigned errorNumber, const char* param = nullptr);
void Advance();
void Advance(int dist) {
next_pos_ += dist - 1;

View file

@ -0,0 +1,2 @@
export default async // ASI occurs here due to the [no LineTerminator here] restriction on default-exporting an async function
function async() { return 17; }

View file

@ -0,0 +1,26 @@
var counter = 0;
function f(stdlib, foreign)
{
"use asm";
var a = +foreign.a;
var b = +foreign.b;
function g() {}
return g;
}
var foreign =
{
a: function() {},
b: /value that doesn't coerce purely/,
};
foreign.a[Symbol.toPrimitive] =
function()
{
counter++;
return 0;
};
f(null, foreign);
assertEq(counter, 1);

View file

@ -0,0 +1,14 @@
if (!('oomTest' in this))
quit();
function f(s) {
s + "x";
s.indexOf("y") === 0;
oomTest(new Function(s));
}
var s = `
class TestClass { constructor() {} }
for (var fun of hasPrototype) {}
`;
if (s.length)
f(s);

View file

@ -8,7 +8,7 @@ function addDebug(g, id) {\
var debuggerGlobal = newGlobal();\
debuggerGlobal.debuggee = g;\
debuggerGlobal.id = id;\
debuggerGlobal.print = function (s) { (g) += s; };\
debuggerGlobal.print = function (s) { print(s); };\
debuggerGlobal.eval('var dbg = new Debugger(debuggee);dbg.onDebuggerStatement = function () { print(id); debugger; };');\
return debuggerGlobal;\
}\

View file

@ -0,0 +1,21 @@
load(libdir + "asserts.js");
let string = Object.defineProperty(new String("123"), "valueOf", {
get: function() { throw "get-valueOf"; }
});
assertThrowsValue(() => "" + string, "get-valueOf");
string = Object.defineProperty(new String("123"), "toString", {
get: function() { throw "get-toString"; }
});
assertThrowsValue(() => string.toLowerCase(), "get-toString");
string = Object.defineProperty(new String("123"), Symbol.toPrimitive, {
get: function() { throw "get-toPrimitive"; }
});
assertThrowsValue(() => string.toLowerCase(), "get-toPrimitive");
let number = Object.defineProperty(new Number(123), "valueOf", {
get: function() { throw "get-valueOf"; }
});
assertThrowsValue(() => +number, "get-valueOf");

View file

@ -8,9 +8,11 @@ assertEq(typeof f1(true), "function");
assertEq(f1(false), 3);
function f2(b, w) {
// Annex B doesn't apply to functions in blocks with the same name as a
// parameter.
if (b)
function w() {}
return w;
}
assertEq(typeof f2(true, 3), "function");
assertEq(typeof f2(true, 3), "number");
assertEq(f2(false, 3), 3);

View file

@ -0,0 +1,8 @@
// Test that constructors that abort due to asm.js do not assert due to the
// parser keeping track of the FunctionBox corresponding to the constructor.
class a {
constructor() {
"use asm";
}
}

View file

@ -0,0 +1,4 @@
setDiscardSource(true)
evaluate(`
unescape(class get { static staticMethod() {} });
`);

View file

@ -0,0 +1,26 @@
// Tests that wasm module scripts have special URLs.
if (!wasmIsSupported())
quit();
var g = newGlobal();
g.eval(`
function initWasm(s) { return new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(s))); }
o = initWasm('(module (func) (export "" 0))');
o2 = initWasm('(module (func) (func) (export "" 1))');
`);
function isWasm(script) { return script.format === "wasm"; }
function isValidWasmURL(url) {
// The URLs will have the following format:
// wasm: [<uri-econded-filename-of-host> ":"] <64-bit-hash>
return /^wasm:(?:[^:]*:)*?[0-9a-f]{16}$/.test(url);
}
var dbg = new Debugger(g);
var foundScripts = dbg.findScripts().filter(isWasm);
assertEq(foundScripts.length, 2);
assertEq(isValidWasmURL(foundScripts[0].source.url), true);
assertEq(isValidWasmURL(foundScripts[1].source.url), true);
assertEq(foundScripts[0].source.url != foundScripts[1].source.url, true);

View file

@ -403,12 +403,52 @@ assertThrowsInstanceOf(function() {
parseAsModule("export {,} from 'a'");
}, SyntaxError);
program([
exportDeclaration(
null,
[
exportSpecifier(
ident("true"),
ident("true")
),
],
lit("b"),
false
)
]).assert(parseAsModule("export { true } from 'b'"));
program([
exportDeclaration(
null,
[
exportSpecifier(
ident("true"),
ident("name")
),
],
lit("b"),
false
)
]).assert(parseAsModule("export { true as name } from 'b'"));
assertThrowsInstanceOf(function() {
parseAsModule("export { true as a } from 'b'");
parseAsModule("export { true }");
}, SyntaxError);
assertThrowsInstanceOf(function() {
parseAsModule("export { true as name }");
}, SyntaxError);
assertThrowsInstanceOf(function() {
parseAsModule("export { static }");
}, SyntaxError);
assertThrowsInstanceOf(function() {
parseAsModule("export { static as name }");
}, SyntaxError);
assertThrowsInstanceOf(function () {
parseAsModule("export { a } from 'b' f();");
parseAsModule("export { name } from 'b' f();");
}, SyntaxError);
assertThrowsInstanceOf(function () {

View file

@ -0,0 +1,94 @@
load(libdir + "asserts.js");
var functionDeclarations = [
"function f(){}",
"function* f(){}",
"async function f(){}",
];
var varDeclarations = [
"var f",
"{ var f; }",
"for (var f in null);",
"for (var f of null);",
"for (var f; ;);",
];
var lexicalDeclarations = [
"let f;",
"const f = 0;",
"class f {};",
];
var imports = [
"import f from '';",
"import f, {} from '';",
"import d, {f} from '';",
"import d, {f as f} from '';",
"import d, {foo as f} from '';",
"import f, * as d from '';",
"import d, * as f from '';",
"import {f} from '';",
"import {f as f} from '';",
"import {foo as f} from '';",
"import* as f from '';",
];
var exports = [
"export var f;",
...functionDeclarations.map(fn => `export ${fn};`),
...lexicalDeclarations.map(ld => `export ${ld};`),
...functionDeclarations.map(fn => `export default ${fn};`),
"export default class f {};",
];
var redeclarations = [
...functionDeclarations,
...varDeclarations,
...lexicalDeclarations,
...imports,
...exports,
];
var noredeclarations = [
...functionDeclarations.map(fn => `{ ${fn} }`),
...lexicalDeclarations.map(ld => `{ ${ld} }`),
...["let", "const"].map(ld => `for (${ld} f in null);`),
...["let", "const"].map(ld => `for (${ld} f of null);`),
...["let", "const"].map(ld => `for (${ld} f = 0; ;);`),
"export {f};",
"export {f as f};",
"export {foo as f}; var foo;",
"export {f} from '';",
"export {f as f} from '';",
"export {foo as f} from '';",
];
for (var decl of functionDeclarations) {
for (var redecl of redeclarations) {
assertThrowsInstanceOf(() => {
parseModule(`
${decl}
${redecl}
`);
}, SyntaxError);
assertThrowsInstanceOf(() => {
parseModule(`
${redecl}
${decl}
`);
}, SyntaxError);
}
for (var redecl of noredeclarations) {
parseModule(`
${decl}
${redecl}
`);
parseModule(`
${redecl}
${decl}
`);
}
}

View file

@ -39,7 +39,7 @@ testThrow(`
testThrow(`
({...a)=>
`, 2);
`, 6);
testThrow(`
function f([... ...a)=>
@ -47,7 +47,7 @@ function f([... ...a)=>
testThrow(`
function f({...a)=>
`, 12);
`, 16);
// arrow
@ -67,7 +67,7 @@ var [... ...a)=>
testThrow(`
var {...a)=>
`, 5);
`, 9);
// initializer

View file

@ -0,0 +1,90 @@
function test(source, [lineNumber, columnNumber], openType = "{", closeType = "}") {
let caught = false;
try {
Reflect.parse(source, { source: "foo.js" });
} catch (e) {
assertEq(e.message.includes("missing " + closeType + " "), true);
let notes = getErrorNotes(e);
assertEq(notes.length, 1);
let note = notes[0];
assertEq(note.message, openType + " opened at line " + lineNumber + ", column " + columnNumber);
assertEq(note.fileName, "foo.js");
assertEq(note.lineNumber, lineNumber);
assertEq(note.columnNumber, columnNumber);
caught = true;
}
assertEq(caught, true);
}
// Function
test(`
function test1() {
}
function test2() {
if (true) {
//}
}
function test3() {
}
`, [4, 17]);
// Block statement.
test(`
{
if (true) {
}
`, [2, 0]);
test(`
if (true) {
if (true) {
}
`, [2, 10]);
test(`
for (;;) {
if (true) {
}
`, [2, 9]);
test(`
while (true) {
if (true) {
}
`, [2, 13]);
test(`
do {
do {
} while(true);
`, [2, 3]);
// try-catch-finally.
test(`
try {
if (true) {
}
`, [2, 4]);
test(`
try {
} catch (e) {
if (true) {
}
`, [3, 12]);
test(`
try {
} finally {
if (true) {
}
`, [3, 10]);
// Object literal.
test(`
var x = {
foo: {
};
`, [2, 8]);
// Array literal.
test(`
var x = [
[
];
`, [2, 8], "[", "]");

View file

@ -0,0 +1,230 @@
// Error message for redeclaration should show the position where the variable
// was declared.
const npos = -1;
function test_one(fun, filename, name,
[prevLineNumber, prevColumnNumber],
[lineNumber, columnNumber]) {
let caught = false;
try {
fun();
} catch (e) {
assertEq(e.message.includes("redeclaration"), true);
assertEq(e.lineNumber, lineNumber);
assertEq(e.columnNumber, columnNumber);
let notes = getErrorNotes(e);
if (prevLineNumber == npos) {
assertEq(notes.length, 0);
} else {
assertEq(notes.length, 1);
let note = notes[0];
assertEq(note.message,
`Previously declared at line ${prevLineNumber}, column ${prevColumnNumber}`);
assertEq(note.lineNumber, prevLineNumber);
assertEq(note.columnNumber, prevColumnNumber);
if (filename)
assertEq(note.fileName, filename);
}
caught = true;
}
assertEq(caught, true);
}
function test_parse(source, ...args) {
test_one(() => {
Reflect.parse(source, { source: "foo.js" });
}, "foo.js", ...args);
}
function test_eval(source, ...args) {
test_one(() => {
eval(source);
}, undefined, ...args);
}
function test(...args) {
test_parse(...args);
test_eval(...args);
}
// let
test(`
let a, a;
`, "a", [2, 4], [2, 7]);
test(`
let a;
let a;
`, "a", [2, 4], [3, 4]);
test(`
let a;
const a = 1;
`, "a", [2, 4], [3, 6]);
test(`
let a;
var a;
`, "a", [2, 4], [3, 4]);
test(`
let a;
function a() {
}
`, "a", [2, 4], [3, 9]);
test(`
{
let a;
function a() {
}
}
`, "a", [3, 6], [4, 11]);
// const
test(`
const a = 1, a = 2;
`, "a", [2, 6], [2, 13]);
test(`
const a = 1;
const a = 2;
`, "a", [2, 6], [3, 6]);
test(`
const a = 1;
let a;
`, "a", [2, 6], [3, 4]);
test(`
const a = 1;
var a;
`, "a", [2, 6], [3, 4]);
test(`
const a = 1;
function a() {
}
`, "a", [2, 6], [3, 9]);
test(`
{
const a = 1;
function a() {
}
}
`, "a", [3, 8], [4, 11]);
// var
test(`
var a;
let a;
`, "a", [2, 4], [3, 4]);
test(`
var a;
const a = 1;
`, "a", [2, 4], [3, 6]);
// function
test(`
function a() {};
let a;
`, "a", [2, 9], [3, 4]);
test(`
function a() {};
const a = 1;
`, "a", [2, 9], [3, 6]);
// Annex B lexical function
test(`
{
function a() {};
let a;
}
`, "a", [3, 11], [4, 6]);
test(`
{
function a() {};
const a = 1;
}
`, "a", [3, 11], [4, 8]);
// catch parameter
test(`
try {
} catch (a) {
let a;
}
`, "a", [3, 9], [4, 6]);
test(`
try {
} catch (a) {
const a = 1;
}
`, "a", [3, 9], [4, 8]);
test(`
try {
} catch (a) {
function a() {
}
}
`, "a", [3, 9], [4, 11]);
// parameter
test(`
function f(a) {
let a;
}
`, "a", [2, 11], [3, 6]);
test(`
function f(a) {
const a = 1;
}
`, "a", [2, 11], [3, 8]);
test(`
function f([a]) {
let a;
}
`, "a", [2, 12], [3, 6]);
test(`
function f({a}) {
let a;
}
`, "a", [2, 12], [3, 6]);
test(`
function f(...a) {
let a;
}
`, "a", [2, 14], [3, 6]);
test(`
function f(a=1) {
let a;
}
`, "a", [2, 11], [3, 6]);
// eval
// We don't have position information at runtime.
// No note should be shown.
test_eval(`
let a;
eval("var a");
`, "a", [npos, npos], [1, 4]);

Some files were not shown because too many files have changed in this diff Show more