Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2016-10-31 16:58:01 +01:00
Родитель 44c54db977 a581a8b8cf
Коммит d54be5b042
124 изменённых файлов: 15497 добавлений и 13521 удалений

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<blocklist lastupdate="1477831926672" xmlns="http://www.mozilla.org/2006/addons-blocklist">
<blocklist lastupdate="1477919228776" xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem blockID="i988" id="{b12785f5-d8d0-4530-a3ea-5c4263b85bef}">
<prefs/>
@ -145,10 +145,6 @@
<prefs/>
<versionRange minVersion="0" maxVersion="0.0.4" severity="1"/>
</emItem>
<emItem blockID="i473" id="{81b13b5d-fba1-49fd-9a6b-189483ac548a}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i914" id="{0153E448-190B-4987-BDE1-F256CADA672F}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3">
@ -157,6 +153,10 @@
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i473" id="{81b13b5d-fba1-49fd-9a6b-189483ac548a}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i496" id="{ACAA314B-EEBA-48e4-AD47-84E31C44796C}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -181,11 +181,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i716" id="{cc6cc772-f121-49e0-b1f0-c26583cb0c5e}">
<emItem blockID="i501" id="xivars@aol.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i501" id="xivars@aol.com">
<emItem blockID="i716" id="{cc6cc772-f121-49e0-b1f0-c26583cb0c5e}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
@ -307,14 +307,14 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i1016" id="jid1-uabu5A9hduqzCw@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i694" id="59D317DB041748fdB89B47E6F96058F3@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i1016" id="jid1-uabu5A9hduqzCw@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i12" id="masterfiler@gmail.com">
<prefs/>
<versionRange severity="3"/>
@ -416,14 +416,14 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i479" id="mbrsepone@facebook.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i744" id="{84a93d51-b7a9-431e-8ff8-d60e5d7f5df1}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i479" id="mbrsepone@facebook.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i736" id="{c5e48979-bd7f-4cf7-9b73-2482a67a4f37}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -456,6 +456,10 @@
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i650" id="jid1-qj0w91o64N7Eeg@jetpack">
<prefs/>
<versionRange minVersion="39.5.1" maxVersion="47.0.4" severity="3"/>
</emItem>
<emItem blockID="i544" id="/^(93abedcf-8e3a-4d02-b761-d1441e437c09@243f129d-aee2-42c2-bcd1-48858e1c22fd\.com|9acfc440-ac2d-417a-a64c-f6f14653b712@09f9a966-9258-4b12-af32-da29bdcc28c5\.com|58ad0086-1cfb-48bb-8ad2-33a8905572bc@5715d2be-69b9-4930-8f7e-64bdeb961cfd\.com)$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -464,14 +468,6 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i650" id="jid1-qj0w91o64N7Eeg@jetpack">
<prefs/>
<versionRange minVersion="39.5.1" maxVersion="47.0.4" severity="3"/>
</emItem>
<emItem blockID="i640" id="jid0-l9BxpNUhx1UUgRfKigWzSfrZqAc@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i628" id="ffxtlbr@iminent.com">
<prefs>
<pref>browser.startup.homepage</pref>
@ -479,6 +475,10 @@
</prefs>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i640" id="jid0-l9BxpNUhx1UUgRfKigWzSfrZqAc@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i1228" id="unblocker30__web@unblocker.yt">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -529,6 +529,10 @@
<prefs/>
<versionRange minVersion="2.4.6.4" maxVersion="2.4.6.4" severity="1"/>
</emItem>
<emItem blockID="i586" id="jid1-0xtMKhXFEs4jIg@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i358" id="lfind@nijadsoft.net">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -545,10 +549,6 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i586" id="jid1-0xtMKhXFEs4jIg@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i786" id="{63eb5ed4-e1b3-47ec-a253-f8462f205350}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -678,17 +678,17 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i658" id="low_quality_flash@pie2k.com">
<emItem blockID="i742" id="{f894a29a-f065-40c3-bb19-da6057778493}">
<prefs/>
<versionRange minVersion="46.2" maxVersion="47.1" severity="3"/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i792" id="{8f894ed3-0bf2-498e-a103-27ef6e88899f}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i742" id="{f894a29a-f065-40c3-bb19-da6057778493}">
<emItem blockID="i658" id="low_quality_flash@pie2k.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
<versionRange minVersion="46.2" maxVersion="47.1" severity="3"/>
</emItem>
<emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
<prefs/>
@ -714,11 +714,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i1278" id="dodatek@firefox.pl">
<emItem blockID="i256" id="/^[0-9a-f]+@[0-9a-f]+\.info/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i256" id="/^[0-9a-f]+@[0-9a-f]+\.info/">
<emItem blockID="i1278" id="dodatek@firefox.pl">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
@ -750,14 +750,14 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i392" id="{EEE6C361-6118-11DC-9C72-001320C79847}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i724" id="{1cdbda58-45f8-4d91-b566-8edce18f8d0a}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i392" id="{EEE6C361-6118-11DC-9C72-001320C79847}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i429" id="{B40794A0-7477-4335-95C5-8CB9BBC5C4A5}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -818,14 +818,14 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i966" id="{5C655500-E712-41e7-9349-CE462F844B19}">
<prefs/>
<versionRange minVersion="0" maxVersion="1.0.1-signed" severity="1"/>
</emItem>
<emItem blockID="i90" id="videoplugin@player.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i966" id="{5C655500-E712-41e7-9349-CE462F844B19}">
<prefs/>
<versionRange minVersion="0" maxVersion="1.0.1-signed" severity="1"/>
</emItem>
<emItem blockID="i1012" id="wxtui502n2xce9j@no14">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -859,6 +859,14 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i75" id="firebug@software.joehewitt.com" os="Darwin,Linux">
<prefs/>
<versionRange minVersion="1.9.0" maxVersion="1.9.0" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="9.*" minVersion="9.0a1"/>
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i718" id="G4Ce4@w.net">
<prefs>
<pref>browser.startup.homepage</pref>
@ -872,14 +880,6 @@
<emItem blockID="i21" id="support@update-firefox.com">
<prefs/>
</emItem>
<emItem blockID="i75" id="firebug@software.joehewitt.com" os="Darwin,Linux">
<prefs/>
<versionRange minVersion="1.9.0" maxVersion="1.9.0" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="9.*" minVersion="9.0a1"/>
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i491" id="{515b2424-5911-40bd-8a2c-bdb20286d8f5}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -888,14 +888,14 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i1264" id="suchpony@suchpony.de">
<prefs/>
<versionRange minVersion="0" maxVersion="1.6.7" severity="3"/>
</emItem>
<emItem blockID="i532" id="249911bc-d1bd-4d66-8c17-df533609e6d8@c76f3de9-939e-4922-b73c-5d7a3139375d.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i1264" id="suchpony@suchpony.de">
<prefs/>
<versionRange minVersion="0" maxVersion="1.6.7" severity="3"/>
</emItem>
<emItem blockID="i476" id="mbroctone@facebook.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -916,6 +916,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i1223" id="tmbepff@trendmicro.com">
<prefs/>
<versionRange minVersion="9.2" maxVersion="9.2.0.1023" severity="1"/>
<versionRange minVersion="0" maxVersion="9.1.0.1035" severity="1"/>
</emItem>
<emItem blockID="i478" id="{7e8a1050-cf67-4575-92df-dcc60e7d952d}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -924,11 +929,6 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i1223" id="tmbepff@trendmicro.com">
<prefs/>
<versionRange minVersion="9.2" maxVersion="9.2.0.1023" severity="1"/>
<versionRange minVersion="0" maxVersion="9.1.0.1035" severity="1"/>
</emItem>
<emItem blockID="i440" id="{2d069a16-fca1-4e81-81ea-5d5086dcbd0c}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -956,11 +956,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i868" id="{6e7f6f9f-8ce6-4611-add2-05f0f7049ee6}">
<emItem blockID="i624" id="/^({b95faac1-a3d7-4d69-8943-ddd5a487d966}|{ecce0073-a837-45a2-95b9-600420505f7e}|{2713b394-286f-4d7c-89ea-4174eeab9f5a}|{da7a20cf-bef4-4342-ad78-0240fdf87055})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i624" id="/^({b95faac1-a3d7-4d69-8943-ddd5a487d966}|{ecce0073-a837-45a2-95b9-600420505f7e}|{2713b394-286f-4d7c-89ea-4174eeab9f5a}|{da7a20cf-bef4-4342-ad78-0240fdf87055})$/">
<emItem blockID="i868" id="{6e7f6f9f-8ce6-4611-add2-05f0f7049ee6}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
@ -1006,14 +1006,14 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i652" id="garg_sms@yahoo.in">
<prefs/>
<versionRange minVersion="67.9" maxVersion="67.9" severity="3"/>
</emItem>
<emItem blockID="i712" id="{a2bfe612-4cf5-48ea-907c-f3fb25bc9d6b}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i652" id="garg_sms@yahoo.in">
<prefs/>
<versionRange minVersion="67.9" maxVersion="67.9" severity="3"/>
</emItem>
<emItem blockID="i47" id="youtube@youtube2.com">
<prefs/>
</emItem>
@ -1037,11 +1037,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i451" id="{e44a1809-4d10-4ab8-b343-3326b64c7cdd}">
<emItem blockID="i402" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i402" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
<emItem blockID="i451" id="{e44a1809-4d10-4ab8-b343-3326b64c7cdd}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
@ -1069,6 +1069,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i226" id="{462be121-2b54-4218-bf00-b9bf8135b23f}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i13" id="{E8E88AB0-7182-11DF-904E-6045E0D72085}">
<prefs/>
</emItem>
@ -1076,10 +1080,6 @@
<prefs/>
<versionRange minVersion="0" maxVersion="1.0.8" severity="1"/>
</emItem>
<emItem blockID="i226" id="{462be121-2b54-4218-bf00-b9bf8135b23f}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i258" id="helperbar@helperbar.com">
<prefs/>
<versionRange minVersion="0" maxVersion="1.0" severity="1"/>
@ -1095,18 +1095,22 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i500" id="{2aab351c-ad56-444c-b935-38bffe18ad26}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i97" id="support3_en@adobe122.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i500" id="{2aab351c-ad56-444c-b935-38bffe18ad26}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i439" id="{d2cf9842-af95-48cd-b873-bfbb48cd7f5e}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i576" id="newmoz@facebook.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
<prefs/>
<versionRange minVersion="0.1" maxVersion="*">
@ -1115,10 +1119,6 @@
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i576" id="newmoz@facebook.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i776" id="g@uzcERQ6ko.net">
<prefs>
<pref>browser.startup.homepage</pref>
@ -1301,14 +1301,14 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i536" id="{25D77636-38B1-1260-887C-2D4AFA92D6A4}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i336" id="CortonExt@ext.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i536" id="{25D77636-38B1-1260-887C-2D4AFA92D6A4}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i374" id="update@firefox.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -1368,10 +1368,6 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i970" id="hha8771ui3-Fo9j9h7aH98jsdfa8sda@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i338" id="{1FD91A9C-410C-4090-BBCC-55D3450EF433}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -1384,6 +1380,10 @@
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i970" id="hha8771ui3-Fo9j9h7aH98jsdfa8sda@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i344" id="lrcsTube@hansanddeta.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -1392,11 +1392,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i483" id="brasilescapefive@facebook.com">
<emItem blockID="i469" id="OKitSpace@OKitSpace.es">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i469" id="OKitSpace@OKitSpace.es">
<emItem blockID="i483" id="brasilescapefive@facebook.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
@ -1450,14 +1450,14 @@
<prefs/>
<versionRange minVersion=" " maxVersion="1.0.0.5"/>
</emItem>
<emItem blockID="i449" id="gystqfr@ylgga.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i378" id="{a7aae4f0-bc2e-a0dd-fb8d-68ce32c9261f}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i449" id="gystqfr@ylgga.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i545" id="superlrcs@svenyor.net">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -1548,11 +1548,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i570" id="jid1-vW9nopuIAJiRHw@jetpack">
<emItem blockID="i678" id="{C4A4F5A0-4B89-4392-AFAC-D58010E349AF}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i678" id="{C4A4F5A0-4B89-4392-AFAC-D58010E349AF}">
<emItem blockID="i570" id="jid1-vW9nopuIAJiRHw@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
@ -1592,14 +1592,14 @@
<prefs/>
<versionRange minVersion=" " severity="1"/>
</emItem>
<emItem blockID="i854" id="/^(7tG@zEb\.net|ru@gfK0J\.edu)$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i73" id="a1g0a9g219d@a1.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i854" id="/^(7tG@zEb\.net|ru@gfK0J\.edu)$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i662" id="imbaty@taringamp3.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -1663,11 +1663,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i103" id="kdrgun@gmail.com">
<emItem blockID="i62" id="jid0-EcdqvFOgWLKHNJPuqAnawlykCGZ@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i62" id="jid0-EcdqvFOgWLKHNJPuqAnawlykCGZ@jetpack">
<emItem blockID="i103" id="kdrgun@gmail.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
@ -1675,11 +1675,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i519" id="703db0db-5fe9-44b6-9f53-c6a91a0ad5bd@7314bc82-969e-4d2a-921b-e5edd0b02cf1.com">
<emItem blockID="i484" id="plugin@getwebcake.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i484" id="plugin@getwebcake.com">
<emItem blockID="i519" id="703db0db-5fe9-44b6-9f53-c6a91a0ad5bd@7314bc82-969e-4d2a-921b-e5edd0b02cf1.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
@ -1687,11 +1687,11 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i495" id="kallow@facebook.com">
<emItem blockID="i836" id="hansin@topvest.id">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i836" id="hansin@topvest.id">
<emItem blockID="i495" id="kallow@facebook.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
@ -1801,6 +1801,10 @@
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i782" id="safebrowse@safebrowse.co">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i806" id="{d9284e50-81fc-11da-a72b-0800200c9a66}">
<prefs/>
<versionRange minVersion="0" maxVersion="7.7.34" severity="1">
@ -1809,10 +1813,6 @@
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i782" id="safebrowse@safebrowse.co">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i382" id="{6926c7f7-6006-42d1-b046-eba1b3010315}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -1901,10 +1901,6 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i66" id="youtubeer@youtuber.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
<prefs/>
<versionRange minVersion="1.2" maxVersion="1.2">
@ -1913,6 +1909,10 @@
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i66" id="youtubeer@youtuber.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
<emItem blockID="i517" id="/^({16e193c8-1706-40bf-b6f3-91403a9a22be}|{284fed43-2e13-4afe-8aeb-50827d510e20}|{5e3cc5d8-ed11-4bed-bc47-35b4c4bc1033}|{7429e64a-1fd4-4112-a186-2b5630816b91}|{8c9980d7-0f09-4459-9197-99b3e559660c}|{8f1d9545-0bb9-4583-bb3c-5e1ac1e2920c})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>

95
browser/extensions/e10srollout/bootstrap.js поставляемый
Просмотреть файл

@ -9,9 +9,6 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/UpdateUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/TelemetryArchive.jsm");
Cu.import("resource://gre/modules/TelemetryController.jsm");
// The amount of people to be part of e10s
const TEST_THRESHOLD = {
@ -21,7 +18,7 @@ const TEST_THRESHOLD = {
const ADDON_ROLLOUT_POLICY = {
"beta" : "50allmpc", // Any WebExtension or addon with mpc = true
"release" : "49a", // 10 tested add-ons + any WebExtension
"release" : "50allmpc", // Any WebExtension or addon with mpc = true
};
const PREF_COHORT_SAMPLE = "e10s.rollout.cohortSample";
@ -33,9 +30,6 @@ const PREF_TOGGLE_E10S = "browser.tabs.remote.autostart.2";
const PREF_E10S_ADDON_POLICY = "extensions.e10s.rollout.policy";
const PREF_E10S_ADDON_BLOCKLIST = "extensions.e10s.rollout.blocklist";
const PREF_E10S_HAS_NONEXEMPT_ADDON = "extensions.e10s.rollout.hasAddon";
const PREF_DISABLED_FOR_SPINNERS = "e10s.rollout.disabledByLongSpinners";
const LONG_SPINNER_HISTOGRAM = "FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS";
function startup() {
// In theory we only need to run this once (on install()), but
@ -47,8 +41,6 @@ function startup() {
// to take effect, so we keep the data based on how it was when
// the session started.
defineCohort();
setUpSpinnerCheck();
}
function install() {
@ -178,10 +170,6 @@ function optedOut() {
* string must be returned.
*/
function getTemporaryDisqualification() {
if (Preferences.isSet(PREF_DISABLED_FOR_SPINNERS)) {
return "longspinner";
}
let applicationLanguage =
Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry)
@ -194,84 +182,3 @@ function getTemporaryDisqualification() {
return "";
}
let performLongSpinnerCheck = Task.async(function*() {
if (!Services.appinfo.browserTabsRemoteAutostart) {
return;
}
const DAYS_OLD = 3;
let thresholdDate = new Date(Date.now() - (1000 * 60 * 60 * 24 * DAYS_OLD));
let allPingsInfo = yield TelemetryArchive.promiseArchivedPingList();
let recentPingsInfo = allPingsInfo.filter(ping => {
let pingDate = new Date(ping.timestampCreated);
return pingDate > thresholdDate;
});
let pingList = [];
for (let pingInfo of recentPingsInfo) {
pingList.push(yield TelemetryArchive.promiseArchivedPingById(pingInfo.id));
}
pingList.push(TelemetryController.getCurrentPingData(/* subsession = */ true));
let totalSessionTime = 0;
let totalSpinnerTime = 0;
for (let ping of pingList) {
try {
if (ping.type != "main") {
continue;
}
if (!ping.environment.settings.e10sEnabled) {
continue;
}
totalSessionTime = ping.payload.info.subsessionLength;
if (!(LONG_SPINNER_HISTOGRAM in ping.payload.histograms)) {
// The Histogram might not be defined in this ping if no data was recorded for it.
// In this case, we still add the session length because that was a valid session
// without a long spinner.
continue;
}
let histogram = ping.payload.histograms[LONG_SPINNER_HISTOGRAM];
for (let spinnerTime of Object.keys(histogram.values)) {
// Only consider spinners that took more than 2 seconds.
// Note: the first bucket size that fits this criteria is
// 2297ms. And the largest bucket is 64000ms, meaning that
// any pause larger than that is only counted as a 64s pause.
// For reference, the bucket sizes are:
// 0, 1000, 2297, 5277, 12124, 27856, 64000
if (spinnerTime >= 2000) {
totalSpinnerTime += spinnerTime * histogram.values[spinnerTime];
}
}
} catch (e) { /* just in case there's a malformed ping, ignore it silently */ }
}
totalSpinnerTime /= 1000; // session time is in seconds, but spinner time in ms
const ACCEPTABLE_THRESHOLD = 20 / 3600; // 20 seconds per hour, per bug 1301131
if ((totalSpinnerTime / totalSessionTime) > ACCEPTABLE_THRESHOLD) {
Preferences.set(PREF_DISABLED_FOR_SPINNERS, true);
} else {
Preferences.reset(PREF_DISABLED_FOR_SPINNERS);
}
});
function setUpSpinnerCheck() {
let {setTimeout, setInterval} = Cu.import("resource://gre/modules/Timer.jsm");
// Perform an initial check after 5min (which should give good clearance from
// the startup process), and then a subsequent check every hour.
setTimeout(performLongSpinnerCheck, 1000 * 60 * 5);
setInterval(performLongSpinnerCheck, 1000 * 60 * 60);
}

Просмотреть файл

@ -10,7 +10,7 @@
<Description about="urn:mozilla:install-manifest">
<em:id>e10srollout@mozilla.org</em:id>
<em:version>1.4</em:version>
<em:version>1.5</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

21
devtools/client/shared/vendor/RESELECT_LICENSE поставляемый Normal file
Просмотреть файл

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-2016 Reselect Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
devtools/client/shared/vendor/RESELECT_UPGRADING поставляемый Normal file
Просмотреть файл

@ -0,0 +1,7 @@
Follow these steps when adding/upgrading the reselect.js module:
1. git clone https://github.com/reactjs/reselect - clone the repo
2. npm install - compile the sources to a compiled JS module file
3. cp dist/reselect.js $DEST_DIR - copy the compiled file to Firefox source tree
The package version used it currently 2.5.4 (last update in bug 1310573)

1
devtools/client/shared/vendor/moz.build поставляемый
Просмотреть файл

@ -20,6 +20,7 @@ modules += [
'react-redux.js',
'react.js',
'redux.js',
'reselect.js',
'seamless-immutable.js',
]

136
devtools/client/shared/vendor/reselect.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,136 @@
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define('Reselect', ['exports'], factory);
} else if (typeof exports !== "undefined") {
factory(exports);
} else {
var mod = {
exports: {}
};
factory(mod.exports);
global.Reselect = mod.exports;
}
})(this, function (exports) {
'use strict';
exports.__esModule = true;
exports.defaultMemoize = defaultMemoize;
exports.createSelectorCreator = createSelectorCreator;
exports.createStructuredSelector = createStructuredSelector;
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
arr2[i] = arr[i];
}
return arr2;
} else {
return Array.from(arr);
}
}
function defaultEqualityCheck(a, b) {
return a === b;
}
function defaultMemoize(func) {
var equalityCheck = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultEqualityCheck;
var lastArgs = null;
var lastResult = null;
var isEqualToLastArg = function isEqualToLastArg(value, index) {
return equalityCheck(value, lastArgs[index]);
};
return function () {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
if (lastArgs === null || lastArgs.length !== args.length || !args.every(isEqualToLastArg)) {
lastResult = func.apply(undefined, args);
}
lastArgs = args;
return lastResult;
};
}
function getDependencies(funcs) {
var dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs;
if (!dependencies.every(function (dep) {
return typeof dep === 'function';
})) {
var dependencyTypes = dependencies.map(function (dep) {
return typeof dep;
}).join(', ');
throw new Error('Selector creators expect all input-selectors to be functions, ' + ('instead received the following types: [' + dependencyTypes + ']'));
}
return dependencies;
}
function createSelectorCreator(memoize) {
for (var _len2 = arguments.length, memoizeOptions = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
memoizeOptions[_key2 - 1] = arguments[_key2];
}
return function () {
for (var _len3 = arguments.length, funcs = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
funcs[_key3] = arguments[_key3];
}
var recomputations = 0;
var resultFunc = funcs.pop();
var dependencies = getDependencies(funcs);
var memoizedResultFunc = memoize.apply(undefined, [function () {
recomputations++;
return resultFunc.apply(undefined, arguments);
}].concat(memoizeOptions));
var selector = function selector(state, props) {
for (var _len4 = arguments.length, args = Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) {
args[_key4 - 2] = arguments[_key4];
}
var params = dependencies.map(function (dependency) {
return dependency.apply(undefined, [state, props].concat(args));
});
return memoizedResultFunc.apply(undefined, _toConsumableArray(params));
};
selector.resultFunc = resultFunc;
selector.recomputations = function () {
return recomputations;
};
selector.resetRecomputations = function () {
return recomputations = 0;
};
return selector;
};
}
var createSelector = exports.createSelector = createSelectorCreator(defaultMemoize);
function createStructuredSelector(selectors) {
var selectorCreator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : createSelector;
if (typeof selectors !== 'object') {
throw new Error('createStructuredSelector expects first argument to be an object ' + ('where each property is a selector, instead received a ' + typeof selectors));
}
var objectKeys = Object.keys(selectors);
return selectorCreator(objectKeys.map(function (key) {
return selectors[key];
}), function () {
for (var _len5 = arguments.length, values = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
values[_key5] = arguments[_key5];
}
return values.reduce(function (composition, value, index) {
composition[objectKeys[index]] = value;
return composition;
}, {});
});
}
});

Просмотреть файл

@ -347,10 +347,11 @@ HTMLAnchorElement::ToString(nsAString& aSource)
return GetHref(aSource);
}
NS_IMETHODIMP
NS_IMETHODIMP
HTMLAnchorElement::GetPing(nsAString& aValue)
{
return GetURIListAttr(nsGkAtoms::ping, aValue);
GetAttr(kNameSpaceID_None, nsGkAtoms::ping, aValue);
return NS_OK;
}
NS_IMETHODIMP

Просмотреть файл

@ -221,10 +221,11 @@ HTMLAreaElement::ToString(nsAString& aSource)
return GetHref(aSource);
}
NS_IMETHODIMP
NS_IMETHODIMP
HTMLAreaElement::GetPing(nsAString& aValue)
{
return GetURIListAttr(nsGkAtoms::ping, aValue);
GetAttr(kNameSpaceID_None, nsGkAtoms::ping, aValue);
return NS_OK;
}
NS_IMETHODIMP

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/MathAlgorithms.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/MediaEncryptedEvent.h"
#include "mozilla/EMEUtils.h"
#include "base/basictypes.h"
#include "nsIDOMHTMLMediaElement.h"
@ -5249,16 +5250,23 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
ReportTelemetry();
ReportEMETelemetry();
// For EME content, force destruction of the CDM client (and CDM
// For EME content, we may force destruction of the CDM client (and CDM
// instance if this is the last client for that CDM instance) and
// the CDM's decoder. This ensures the CDM gets reliable and prompt
// shutdown notifications, as it may have book-keeping it needs
// to do on shutdown.
if (mMediaKeys) {
mMediaKeys->Shutdown();
mMediaKeys = nullptr;
if (mDecoder) {
ShutdownDecoder();
nsAutoString keySystem;
mMediaKeys->GetKeySystem(keySystem);
// If we're using Primetime we need to shutdown the key system and
// decoder to preserve secure stop like behavior, other CDMs don't
// implement this so we don't need to worry with them.
if (IsPrimetimeKeySystem(keySystem)) {
mMediaKeys->Shutdown();
mMediaKeys = nullptr;
if (mDecoder) {
ShutdownDecoder();
}
}
}
if (mDecoder) {
@ -5267,7 +5275,6 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
}
mEventDeliveryPaused = aSuspendEvents;
} else {
MOZ_ASSERT(!mMediaKeys);
if (mDecoder) {
mDecoder->Resume();
if (!mPaused && !mDecoder->IsEnded()) {

Просмотреть файл

@ -1679,68 +1679,6 @@ nsGenericHTMLElement::IsScrollGrabAllowed(JSContext*, JSObject*)
return nsContentUtils::IsSystemPrincipal(prin);
}
nsresult
nsGenericHTMLElement::GetURIListAttr(nsIAtom* aAttr, nsAString& aResult)
{
aResult.Truncate();
nsAutoString value;
if (!GetAttr(kNameSpaceID_None, aAttr, value))
return NS_OK;
nsIDocument* doc = OwnerDoc();
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
nsString::const_iterator end;
value.EndReading(end);
nsAString::const_iterator iter;
value.BeginReading(iter);
while (iter != end) {
while (*iter == ' ' && iter != end) {
++iter;
}
if (iter == end) {
break;
}
nsAString::const_iterator start = iter;
while (iter != end && *iter != ' ') {
++iter;
}
if (!aResult.IsEmpty()) {
aResult.Append(NS_LITERAL_STRING(" "));
}
const nsSubstring& uriPart = Substring(start, iter);
nsCOMPtr<nsIURI> attrURI;
nsresult rv =
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(attrURI),
uriPart, doc, baseURI);
if (NS_FAILED(rv)) {
aResult.Append(uriPart);
continue;
}
MOZ_ASSERT(attrURI);
nsAutoCString spec;
rv = attrURI->GetSpec(spec);
if (NS_WARN_IF(NS_FAILED(rv))) {
aResult.Append(uriPart);
continue;
}
AppendUTF8toUTF16(spec, aResult);
}
return NS_OK;
}
HTMLMenuElement*
nsGenericHTMLElement::GetContextMenu() const
{

Просмотреть файл

@ -1062,20 +1062,6 @@ protected:
SetHTMLAttr(aAttr, value, aRv);
}
/**
* This method works like GetURIAttr, except that it supports multiple
* URIs separated by whitespace (one or more U+0020 SPACE characters).
*
* Gets the absolute URI values of an attribute, by resolving any relative
* URIs in the attribute against the baseuri of the element. If a substring
* isn't a relative URI, the substring is returned as is. Only works for
* attributes in null namespace.
*
* @param aAttr name of attribute.
* @param aResult result value [out]
*/
nsresult GetURIListAttr(nsIAtom* aAttr, nsAString& aResult);
/**
* Locates the nsIEditor associated with this node. In general this is
* equivalent to GetEditorInternal(), but for designmode or contenteditable,

Просмотреть файл

@ -5244,7 +5244,7 @@ bool
ContentParent::RecvAccumulateChildHistogram(
InfallibleTArray<Accumulation>&& aAccumulations)
{
Telemetry::AccumulateChild(aAccumulations);
Telemetry::AccumulateChild(GeckoProcessType_Content, aAccumulations);
return true;
}
@ -5252,6 +5252,6 @@ bool
ContentParent::RecvAccumulateChildKeyedHistogram(
InfallibleTArray<KeyedAccumulation>&& aAccumulations)
{
Telemetry::AccumulateChildKeyed(aAccumulations);
Telemetry::AccumulateChildKeyed(GeckoProcessType_Content, aAccumulations);
return true;
}

Просмотреть файл

@ -137,6 +137,20 @@ GPUChild::RecvNotifyUiObservers(const nsCString& aTopic)
return true;
}
bool
GPUChild::RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations)
{
Telemetry::AccumulateChild(GeckoProcessType_GPU, aAccumulations);
return true;
}
bool
GPUChild::RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations)
{
Telemetry::AccumulateChildKeyed(GeckoProcessType_GPU, aAccumulations);
return true;
}
void
GPUChild::ActorDestroy(ActorDestroyReason aWhy)
{

Просмотреть файл

@ -38,6 +38,8 @@ public:
bool RecvInitComplete(const GPUDeviceData& aData) override;
bool RecvReportCheckerboard(const uint32_t& aSeverity, const nsCString& aLog) override;
bool RecvInitCrashReporter(Shmem&& shmem) override;
bool RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations) override;
bool RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
bool RecvGraphicsError(const nsCString& aError) override;
bool RecvNotifyUiObservers(const nsCString& aTopic) override;

Просмотреть файл

@ -97,9 +97,11 @@ GPUParent::Init(base::ProcessId aParentPid,
DeviceManagerDx::Init();
DeviceManagerD3D9::Init();
#endif
if (NS_FAILED(NS_InitMinimalXPCOM())) {
return false;
}
CompositorThreadHolder::Start();
APZThreadUtils::SetControllerThread(CompositorThreadHolder::Loop());
APZCTreeManager::InitializeGlobalState();

Просмотреть файл

@ -137,6 +137,11 @@ public:
return mGPUChild;
}
// Returns whether or not a GPU process was ever launched.
bool AttemptedGPUProcess() const {
return mNumProcessAttempts > 0;
}
private:
// Called from our xpcom-shutdown observer.
void OnXPCOMShutdown();

Просмотреть файл

@ -14,6 +14,8 @@ using base::ProcessId from "base/process.h";
using mozilla::TimeDuration from "mozilla/TimeStamp.h";
using mozilla::CSSToLayoutDeviceScale from "Units.h";
using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h";
using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h";
namespace mozilla {
namespace gfx {
@ -88,6 +90,10 @@ child:
// Have a message be broadcasted to the UI process by the UI process
// observer service.
async NotifyUiObservers(nsCString aTopic);
// Messages for reporting telemetry to the UI process.
async AccumulateChildHistogram(Accumulation[] accumulations);
async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations);
};
} // namespace gfx

Просмотреть файл

@ -1737,10 +1737,6 @@ ChildImpl::CloseForCurrentThread()
threadLocalInfo->mClosed = true;
#endif
if (threadLocalInfo->mActor) {
threadLocalInfo->mActor->FlushPendingInterruptQueue();
}
// Clearing the thread local will synchronously close the actor.
DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
MOZ_ASSERT(status == PR_SUCCESS);

Просмотреть файл

@ -489,10 +489,7 @@ MessageChannel::MessageChannel(MessageListener *aListener)
mTransactionStack(nullptr),
mTimedOutMessageSeqno(0),
mTimedOutMessageNestedLevel(0),
#if defined(MOZ_CRASHREPORTER) && defined(OS_WIN)
mPending(AnnotateAllocator<Message>(*this)),
#endif
mRemoteStackDepthGuess(false),
mRemoteStackDepthGuess(0),
mSawInterruptOutMsg(false),
mIsWaitingForIncoming(false),
mAbortOnError(false),
@ -508,12 +505,8 @@ MessageChannel::MessageChannel(MessageListener *aListener)
mIsSyncWaitingOnNonMainThread = false;
#endif
RefPtr<CancelableRunnable> runnable =
NewNonOwningCancelableRunnableMethod(this, &MessageChannel::OnMaybeDequeueOne);
mDequeueOneTask = new RefCountedTask(runnable.forget());
runnable = NewNonOwningCancelableRunnableMethod(this, &MessageChannel::DispatchOnChannelConnected);
mOnChannelConnectedTask = new RefCountedTask(runnable.forget());
mOnChannelConnectedTask =
NewNonOwningCancelableRunnableMethod(this, &MessageChannel::DispatchOnChannelConnected);
#ifdef OS_WIN
mEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
@ -635,8 +628,6 @@ MessageChannel::Clear()
gParentProcessBlocker = nullptr;
}
mDequeueOneTask->Cancel();
mWorkerLoop = nullptr;
delete mLink;
mLink = nullptr;
@ -649,7 +640,11 @@ MessageChannel::Clear()
}
// Free up any memory used by pending messages.
for (RefPtr<MessageTask> task : mPending) {
task->Clear();
}
mPending.clear();
mOutOfTurnReplies.clear();
while (!mDeferred.empty()) {
mDeferred.pop();
@ -879,19 +874,6 @@ MessageChannel::ShouldDeferMessage(const Message& aMsg)
return mSide == ParentSide && aMsg.transaction_id() != CurrentNestedInsideSyncTransaction();
}
// Predicate that is true for messages that should be consolidated if 'compress' is set.
class MatchingKinds {
typedef IPC::Message Message;
Message::msgid_t mType;
int32_t mRoutingId;
public:
MatchingKinds(Message::msgid_t aType, int32_t aRoutingId) :
mType(aType), mRoutingId(aRoutingId) {}
bool operator()(const Message &msg) {
return msg.type() == mType && msg.routing_id() == mRoutingId;
}
};
void
MessageChannel::OnMessageReceivedFromLink(Message&& aMsg)
{
@ -925,31 +907,34 @@ MessageChannel::OnMessageReceivedFromLink(Message&& aMsg)
MOZ_RELEASE_ASSERT(aMsg.compress_type() == IPC::Message::COMPRESSION_NONE ||
aMsg.nested_level() == IPC::Message::NOT_NESTED);
bool compress = false;
bool reuseTask = false;
if (aMsg.compress_type() == IPC::Message::COMPRESSION_ENABLED) {
compress = (!mPending.empty() &&
mPending.back().type() == aMsg.type() &&
mPending.back().routing_id() == aMsg.routing_id());
bool compress = (!mPending.isEmpty() &&
mPending.getLast()->Msg().type() == aMsg.type() &&
mPending.getLast()->Msg().routing_id() == aMsg.routing_id());
if (compress) {
// This message type has compression enabled, and the back of the
// queue was the same message type and routed to the same destination.
// Replace it with the newer message.
MOZ_RELEASE_ASSERT(mPending.back().compress_type() ==
IPC::Message::COMPRESSION_ENABLED);
mPending.pop_back();
MOZ_RELEASE_ASSERT(mPending.getLast()->Msg().compress_type() ==
IPC::Message::COMPRESSION_ENABLED);
mPending.getLast()->Msg() = Move(aMsg);
reuseTask = true;
}
} else if (aMsg.compress_type() == IPC::Message::COMPRESSION_ALL) {
// Check the message queue for another message with this type/destination.
auto it = std::find_if(mPending.rbegin(), mPending.rend(),
MatchingKinds(aMsg.type(), aMsg.routing_id()));
if (it != mPending.rend()) {
// This message type has compression enabled, and the queue holds
// a message with the same message type and routed to the same destination.
// Erase it. Note that, since we always compress these redundancies, There Can
// Be Only One.
compress = true;
MOZ_RELEASE_ASSERT((*it).compress_type() == IPC::Message::COMPRESSION_ALL);
mPending.erase((++it).base());
} else if (aMsg.compress_type() == IPC::Message::COMPRESSION_ALL && !mPending.isEmpty()) {
for (RefPtr<MessageTask> p = mPending.getLast(); p; p = p->getPrevious()) {
if (p->Msg().type() == aMsg.type() &&
p->Msg().routing_id() == aMsg.routing_id())
{
// This message type has compression enabled, and the queue
// holds a message with the same message type and routed to the
// same destination. Erase it. Note that, since we always
// compress these redundancies, There Can Be Only One.
MOZ_RELEASE_ASSERT(p->Msg().compress_type() == IPC::Message::COMPRESSION_ALL);
p->remove();
break;
}
}
}
@ -959,7 +944,7 @@ MessageChannel::OnMessageReceivedFromLink(Message&& aMsg)
wakeUpSyncSend ||
AwaitingIncomingMessage();
// Although we usually don't need to post an OnMaybeDequeueOne task if
// Although we usually don't need to post a message task if
// shouldWakeUp is true, it's easier to post anyway than to have to
// guarantee that every Send call processes everything it's supposed to
// before returning.
@ -968,6 +953,10 @@ MessageChannel::OnMessageReceivedFromLink(Message&& aMsg)
IPC_LOG("Receive on link thread; seqno=%d, xid=%d, shouldWakeUp=%d",
aMsg.seqno(), aMsg.transaction_id(), shouldWakeUp);
if (reuseTask) {
return;
}
// There are three cases we're concerned about, relating to the state of the
// main thread:
//
@ -990,29 +979,26 @@ MessageChannel::OnMessageReceivedFromLink(Message&& aMsg)
// blocked. This is okay, since we always check for pending events before
// blocking again.
mPending.push_back(Move(aMsg));
RefPtr<MessageTask> task = new MessageTask(this, Move(aMsg));
mPending.insertBack(task);
if (shouldWakeUp) {
NotifyWorkerThread();
}
if (shouldPostTask) {
if (!compress) {
// If we compressed away the previous message, we'll re-use
// its pending task.
RefPtr<DequeueTask> task = new DequeueTask(mDequeueOneTask);
mWorkerLoop->PostTask(task.forget());
}
task->Post();
}
}
void
MessageChannel::PeekMessages(mozilla::function<bool(const Message& aMsg)> aInvoke)
{
// FIXME: We shouldn't be holding the lock for aInvoke!
MonitorAutoLock lock(*mMonitor);
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); it++) {
Message &msg = *it;
for (RefPtr<MessageTask> it : mPending) {
const Message &msg = it->Msg();
if (!aInvoke(msg)) {
break;
}
@ -1022,6 +1008,8 @@ MessageChannel::PeekMessages(mozilla::function<bool(const Message& aMsg)> aInvok
void
MessageChannel::ProcessPendingRequests(AutoEnterTransaction& aTransaction)
{
mMonitor->AssertCurrentThreadOwns();
IPC_LOG("ProcessPendingRequests for seqno=%d, xid=%d",
aTransaction.SequenceNumber(), aTransaction.TransactionID());
@ -1038,8 +1026,8 @@ MessageChannel::ProcessPendingRequests(AutoEnterTransaction& aTransaction)
mozilla::Vector<Message> toProcess;
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
Message &msg = *it;
for (RefPtr<MessageTask> p = mPending.getFirst(); p; ) {
Message &msg = p->Msg();
MOZ_RELEASE_ASSERT(!aTransaction.IsCanceled(),
"Calling ShouldDeferMessage when cancelled");
@ -1053,10 +1041,11 @@ MessageChannel::ProcessPendingRequests(AutoEnterTransaction& aTransaction)
if (!defer) {
if (!toProcess.append(Move(msg)))
MOZ_CRASH();
it = mPending.erase(it);
p = p->removeAndGetNext();
continue;
}
it++;
p = p->getNext();
}
if (toProcess.empty()) {
@ -1358,9 +1347,9 @@ MessageChannel::Call(Message* aMsg, Message* aReply)
{
recvd = Move(it->second);
mOutOfTurnReplies.erase(it);
} else if (!mPending.empty()) {
recvd = Move(mPending.front());
mPending.pop_front();
} else if (!mPending.isEmpty()) {
RefPtr<MessageTask> task = mPending.popFirst();
recvd = Move(task->Msg());
} else {
// because of subtleties with nested event loops, it's possible
// that we got here and nothing happened. or, we might have a
@ -1449,18 +1438,19 @@ MessageChannel::WaitForIncomingMessage()
NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
#endif
{ // Scope for lock
MonitorAutoLock lock(*mMonitor);
AutoEnterWaitForIncoming waitingForIncoming(*this);
if (mChannelState != ChannelConnected) {
return false;
}
if (!HasPendingEvents()) {
return WaitForInterruptNotify();
}
MonitorAutoLock lock(*mMonitor);
AutoEnterWaitForIncoming waitingForIncoming(*this);
if (mChannelState != ChannelConnected) {
return false;
}
if (!HasPendingEvents()) {
return WaitForInterruptNotify();
}
return OnMaybeDequeueOne();
MOZ_RELEASE_ASSERT(!mPending.isEmpty());
RefPtr<MessageTask> task = mPending.getFirst();
RunMessage(*task);
return true;
}
bool
@ -1468,7 +1458,7 @@ MessageChannel::HasPendingEvents()
{
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
return Connected() && !mPending.empty();
return Connected() && !mPending.isEmpty();
}
bool
@ -1479,7 +1469,7 @@ MessageChannel::InterruptEventOccurred()
IPC_ASSERT(InterruptStackDepth() > 0, "not in wait loop");
return (!Connected() ||
!mPending.empty() ||
!mPending.isEmpty() ||
(!mOutOfTurnReplies.empty() &&
mOutOfTurnReplies.find(mInterruptStack.top().seqno()) !=
mOutOfTurnReplies.end()));
@ -1503,19 +1493,12 @@ MessageChannel::ProcessPendingRequest(Message &&aUrgent)
}
bool
MessageChannel::DequeueOne(Message *recvd)
MessageChannel::ShouldRunMessage(const Message& aMsg)
{
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
if (!Connected()) {
ReportConnectionError("OnMaybeDequeueOne");
return false;
if (!mTimedOutMessageSeqno) {
return true;
}
if (!mDeferred.empty())
MaybeUndeferIncall();
// If we've timed out a message and we're awaiting the reply to the timed
// out message, we have to be careful what messages we process. Here's what
// can go wrong:
@ -1532,56 +1515,131 @@ MessageChannel::DequeueOne(Message *recvd)
// message unless the child would need the response to that message in order
// to process M. Those messages are the ones that have a higher nested level
// than M or that are part of the same transaction as M.
if (mTimedOutMessageSeqno) {
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); it++) {
Message &msg = *it;
if (msg.nested_level() > mTimedOutMessageNestedLevel ||
(msg.nested_level() == mTimedOutMessageNestedLevel
&& msg.transaction_id() == mTimedOutMessageSeqno))
{
*recvd = Move(msg);
mPending.erase(it);
return true;
}
}
if (aMsg.nested_level() < mTimedOutMessageNestedLevel ||
(aMsg.nested_level() == mTimedOutMessageNestedLevel
&& aMsg.transaction_id() != mTimedOutMessageSeqno))
{
return false;
}
if (mPending.empty())
return false;
*recvd = Move(mPending.front());
mPending.pop_front();
return true;
}
bool
MessageChannel::OnMaybeDequeueOne()
{
AssertWorkerThread();
mMonitor->AssertNotCurrentThreadOwns();
Message recvd;
MonitorAutoLock lock(*mMonitor);
if (!DequeueOne(&recvd))
return false;
if (IsOnCxxStack() && recvd.is_interrupt() && recvd.is_reply()) {
// We probably just received a reply in a nested loop for an
// Interrupt call sent before entering that loop.
mOutOfTurnReplies[recvd.seqno()] = Move(recvd);
return false;
}
DispatchMessage(Move(recvd));
return true;
}
void
MessageChannel::RunMessage(MessageTask& aTask)
{
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
Message& msg = aTask.Msg();
if (!Connected()) {
ReportConnectionError("RunMessage");
return;
}
// Check that we're going to run the first message that's valid to run.
#ifdef DEBUG
for (RefPtr<MessageTask> task : mPending) {
if (task == &aTask) {
break;
}
MOZ_ASSERT(!ShouldRunMessage(task->Msg()));
}
#endif
if (!mDeferred.empty()) {
MaybeUndeferIncall();
}
if (!ShouldRunMessage(msg)) {
return;
}
MOZ_RELEASE_ASSERT(aTask.isInList());
aTask.remove();
if (IsOnCxxStack() && msg.is_interrupt() && msg.is_reply()) {
// We probably just received a reply in a nested loop for an
// Interrupt call sent before entering that loop.
mOutOfTurnReplies[msg.seqno()] = Move(msg);
return;
}
DispatchMessage(Move(msg));
}
nsresult
MessageChannel::MessageTask::Run()
{
if (!mChannel) {
return NS_OK;
}
mChannel->AssertWorkerThread();
mChannel->mMonitor->AssertNotCurrentThreadOwns();
MonitorAutoLock lock(*mChannel->mMonitor);
// In case we choose not to run this message, we may need to be able to Post
// it again.
mScheduled = false;
if (!isInList()) {
return NS_OK;
}
mChannel->RunMessage(*this);
return NS_OK;
}
// Warning: This method removes the receiver from whatever list it might be in.
nsresult
MessageChannel::MessageTask::Cancel()
{
if (!mChannel) {
return NS_OK;
}
mChannel->AssertWorkerThread();
mChannel->mMonitor->AssertNotCurrentThreadOwns();
MonitorAutoLock lock(*mChannel->mMonitor);
if (!isInList()) {
return NS_OK;
}
remove();
return NS_OK;
}
void
MessageChannel::MessageTask::Post()
{
MOZ_RELEASE_ASSERT(!mScheduled);
MOZ_RELEASE_ASSERT(isInList());
mScheduled = true;
RefPtr<MessageTask> self = this;
mChannel->mWorkerLoop->PostTask(self.forget());
}
void
MessageChannel::MessageTask::Clear()
{
mChannel->AssertWorkerThread();
mChannel = nullptr;
}
void
MessageChannel::DispatchMessage(Message &&aMsg)
{
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
Maybe<AutoNoJSAPI> nojsapi;
if (ScriptSettingsInitialized() && NS_IsMainThread())
nojsapi.emplace();
@ -1780,29 +1838,9 @@ MessageChannel::MaybeUndeferIncall()
--mRemoteStackDepthGuess;
MOZ_RELEASE_ASSERT(call.nested_level() == IPC::Message::NOT_NESTED);
mPending.push_back(Move(call));
}
void
MessageChannel::FlushPendingInterruptQueue()
{
AssertWorkerThread();
mMonitor->AssertNotCurrentThreadOwns();
{
MonitorAutoLock lock(*mMonitor);
if (mDeferred.empty()) {
if (mPending.empty())
return;
const Message& last = mPending.back();
if (!last.is_interrupt() || last.is_reply())
return;
}
}
while (OnMaybeDequeueOne());
RefPtr<MessageTask> task = new MessageTask(this, Move(call));
mPending.insertBack(task);
task->Post();
}
void
@ -1825,18 +1863,10 @@ MessageChannel::EnqueuePendingMessages()
MaybeUndeferIncall();
for (size_t i = 0; i < mDeferred.size(); ++i) {
RefPtr<DequeueTask> task = new DequeueTask(mDequeueOneTask);
mWorkerLoop->PostTask(task.forget());
}
// XXX performance tuning knob: could process all or k pending
// messages here, rather than enqueuing for later processing
for (size_t i = 0; i < mPending.size(); ++i) {
RefPtr<DequeueTask> task = new DequeueTask(mDequeueOneTask);
mWorkerLoop->PostTask(task.forget());
}
RepostAllMessages();
}
static inline bool
@ -1943,7 +1973,7 @@ MessageChannel::OnChannelConnected(int32_t peer_id)
MOZ_RELEASE_ASSERT(!mPeerPidSet);
mPeerPidSet = true;
mPeerPid = peer_id;
RefPtr<DequeueTask> task = new DequeueTask(mOnChannelConnectedTask);
RefPtr<CancelableRunnable> task = mOnChannelConnectedTask;
mWorkerLoop->PostTask(task.forget());
}
@ -2291,16 +2321,14 @@ MessageChannel::DebugAbort(const char* file, int line, const char* cond,
mDeferred.size());
printf_stderr(" out-of-turn Interrupt replies stack size: %" PRIuSIZE "\n",
mOutOfTurnReplies.size());
printf_stderr(" Pending queue size: %" PRIuSIZE ", front to back:\n",
mPending.size());
MessageQueue pending = Move(mPending);
while (!pending.empty()) {
while (!pending.isEmpty()) {
printf_stderr(" [ %s%s ]\n",
pending.front().is_interrupt() ? "intr" :
(pending.front().is_sync() ? "sync" : "async"),
pending.front().is_reply() ? "reply" : "");
pending.pop_front();
pending.getFirst()->Msg().is_interrupt() ? "intr" :
(pending.getFirst()->Msg().is_sync() ? "sync" : "async"),
pending.getFirst()->Msg().is_reply() ? "reply" : "");
pending.popFirst();
}
NS_RUNTIMEABORT(why);
@ -2348,13 +2376,33 @@ MessageChannel::EndTimeout()
mTimedOutMessageSeqno = 0;
mTimedOutMessageNestedLevel = 0;
for (size_t i = 0; i < mPending.size(); i++) {
// There may be messages in the queue that we expected to process from
// OnMaybeDequeueOne. But during the timeout, that function will skip
// some messages. Now they're ready to be processed, so we enqueue more
// tasks.
RefPtr<DequeueTask> task = new DequeueTask(mDequeueOneTask);
mWorkerLoop->PostTask(task.forget());
RepostAllMessages();
}
void
MessageChannel::RepostAllMessages()
{
bool needRepost = false;
for (RefPtr<MessageTask> task : mPending) {
if (!task->IsScheduled()) {
needRepost = true;
}
}
if (!needRepost) {
// If everything is already scheduled to run, do nothing.
return;
}
// In some cases we may have deferred dispatch of some messages in the
// queue. Now we want to run them again. However, we can't just re-post
// those messages since the messages after them in mPending would then be
// before them in the event queue. So instead we cancel everything and
// re-post all messages in the correct order.
MessageQueue queue = Move(mPending);
while (RefPtr<MessageTask> task = queue.popFirst()) {
RefPtr<MessageTask> newTask = new MessageTask(this, Move(task->Msg()));
mPending.insertBack(newTask);
newTask->Post();
}
}
@ -2397,8 +2445,8 @@ MessageChannel::CancelTransaction(int transaction)
}
bool foundSync = false;
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
Message &msg = *it;
for (RefPtr<MessageTask> p = mPending.getFirst(); p; ) {
Message &msg = p->Msg();
// If there was a race between the parent and the child, then we may
// have a queued sync message. We want to drop this message from the
@ -2409,11 +2457,11 @@ MessageChannel::CancelTransaction(int transaction)
MOZ_RELEASE_ASSERT(msg.transaction_id() != transaction);
IPC_LOG("Removing msg from queue seqno=%d xid=%d", msg.seqno(), msg.transaction_id());
foundSync = true;
it = mPending.erase(it);
p = p->removeAndGetNext();
continue;
}
it++;
p = p->getNext();
}
}

Просмотреть файл

@ -183,8 +183,6 @@ class MessageChannel : HasResultCodes
*/
int32_t GetTopmostMessageRoutingId() const;
void FlushPendingInterruptQueue();
// Unsound_IsClosed and Unsound_NumQueuedMessages are safe to call from any
// thread, but they make no guarantees about whether you'll get an
// up-to-date value; the values are written on one thread and read without
@ -276,10 +274,6 @@ class MessageChannel : HasResultCodes
void MaybeUndeferIncall();
void EnqueuePendingMessages();
// Executed on the worker thread. Dequeues one pending message.
bool OnMaybeDequeueOne();
bool DequeueOne(Message *recvd);
// Dispatches an incoming message to its appropriate handler.
void DispatchMessage(Message &&aMsg);
@ -311,6 +305,8 @@ class MessageChannel : HasResultCodes
void EndTimeout();
void CancelTransaction(int transaction);
void RepostAllMessages();
// The "remote view of stack depth" can be different than the
// actual stack depth when there are out-of-turn replies. When we
// receive one, our actual Interrupt stack depth doesn't decrease, but
@ -456,119 +452,41 @@ class MessageChannel : HasResultCodes
}
private:
#if defined(MOZ_CRASHREPORTER) && defined(OS_WIN)
// TODO: Remove the condition OS_WIN above once we move to GCC 5 or higher,
// the code will be able to get compiled as std::deque will meet C++11
// allocator requirements.
template<class T>
struct AnnotateAllocator
class MessageTask :
public CancelableRunnable,
public LinkedListElement<RefPtr<MessageTask>>
{
typedef T value_type;
AnnotateAllocator(MessageChannel& channel) : mChannel(channel) {}
template<class U> AnnotateAllocator(const AnnotateAllocator<U>& other) :
mChannel(other.mChannel) {}
template<class U> bool operator==(const AnnotateAllocator<U>&) { return true; }
template<class U> bool operator!=(const AnnotateAllocator<U>&) { return false; }
T* allocate(size_t n) {
void* p = ::operator new(n * sizeof(T), std::nothrow);
if (!p && n) {
// Sort the pending messages by its type, note the sorting algorithm
// has to be in-place to avoid memory allocation.
MessageQueue& q = mChannel.mPending;
std::sort(q.begin(), q.end(), [](const Message& a, const Message& b) {
return a.type() < b.type();
});
public:
explicit MessageTask(MessageChannel* aChannel, Message&& aMessage)
: mChannel(aChannel), mMessage(Move(aMessage)), mScheduled(false)
{}
// Iterate over the sorted queue to find the message that has the
// highest number of count.
const char* topName = nullptr;
const char* curName = nullptr;
msgid_t topType = 0, curType = 0;
uint32_t topCount = 0, curCount = 0;
for (MessageQueue::iterator it = q.begin(); it != q.end(); ++it) {
Message &msg = *it;
if (msg.type() == curType) {
++curCount;
} else {
if (curCount > topCount) {
topName = curName;
topType = curType;
topCount = curCount;
}
curName = StringFromIPCMessageType(msg.type());
curType = msg.type();
curCount = 1;
}
}
// In case the last type is the top one.
if (curCount > topCount) {
topName = curName;
topType = curType;
topCount = curCount;
}
NS_IMETHOD Run() override;
nsresult Cancel() override;
void Post();
void Clear();
CrashReporter::AnnotatePendingIPC(q.size(), topCount, topName, topType);
bool IsScheduled() const { return mScheduled; }
mozalloc_handle_oom(n * sizeof(T));
}
return static_cast<T*>(p);
}
void deallocate(T* p, size_t n) {
::operator delete(p);
}
MessageChannel& mChannel;
Message& Msg() { return mMessage; }
const Message& Msg() const { return mMessage; }
private:
MessageTask() = delete;
MessageTask(const MessageTask&) = delete;
MessageChannel* mChannel;
Message mMessage;
bool mScheduled : 1;
};
typedef std::deque<Message, AnnotateAllocator<Message>> MessageQueue;
#else
typedef std::deque<Message> MessageQueue;
#endif
bool ShouldRunMessage(const Message& aMsg);
void RunMessage(MessageTask& aTask);
typedef LinkedList<RefPtr<MessageTask>> MessageQueue;
typedef std::map<size_t, Message> MessageMap;
typedef IPC::Message::msgid_t msgid_t;
// XXXkhuey this can almost certainly die.
// All dequeuing tasks require a single point of cancellation,
// which is handled via a reference-counted task.
class RefCountedTask
{
public:
explicit RefCountedTask(already_AddRefed<CancelableRunnable> aTask)
: mTask(aTask)
{ }
private:
~RefCountedTask() { }
public:
void Run() { mTask->Run(); }
void Cancel() { mTask->Cancel(); }
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedTask)
private:
RefPtr<CancelableRunnable> mTask;
};
// Wrap an existing task which can be cancelled at any time
// without the wrapper's knowledge.
class DequeueTask : public CancelableRunnable
{
public:
explicit DequeueTask(RefCountedTask* aTask)
: mTask(aTask)
{ }
NS_IMETHOD Run() override {
if (mTask) {
mTask->Run();
}
return NS_OK;
}
nsresult Cancel() override {
mTask = nullptr;
return NS_OK;
}
private:
RefPtr<RefCountedTask> mTask;
};
private:
// Based on presumption the listener owns and overlives the channel,
// this is never nullified.
@ -584,9 +502,6 @@ class MessageChannel : HasResultCodes
// during channel shutdown.
int mWorkerLoopID;
// A task encapsulating dequeuing one pending message.
RefPtr<RefCountedTask> mDequeueOneTask;
// Timeout periods are broken up in two to prevent system suspension from
// triggering an abort. This method (called by WaitForEvent with a 'did
// timeout' flag) decides if we should wait again for half of mTimeoutMs
@ -673,9 +588,7 @@ class MessageChannel : HasResultCodes
int32_t mTimedOutMessageSeqno;
int mTimedOutMessageNestedLevel;
// Queue of all incoming messages, except for replies to sync and urgent
// messages, which are delivered directly to mRecvd, and any pending urgent
// incall, which is stored in mPendingUrgentRequest.
// Queue of all incoming messages.
//
// If both this side and the other side are functioning correctly, the queue
// can only be in certain configurations. Let
@ -687,7 +600,7 @@ class MessageChannel : HasResultCodes
//
// The queue can only match this configuration
//
// A<* (S< | C< | R< (?{mStack.size() == 1} A<* (S< | C<)))
// A<* (S< | C< | R< (?{mInterruptStack.size() == 1} A<* (S< | C<)))
//
// The other side can send as many async messages |A<*| as it wants before
// sending us a blocking message.
@ -702,7 +615,7 @@ class MessageChannel : HasResultCodes
// |mRemoteStackDepth|, and races don't matter to the queue.)
//
// Final case, the other side replied to our most recent out-call |R<|.
// If that was the *only* out-call on our stack, |?{mStack.size() == 1}|,
// If that was the *only* out-call on our stack, |?{mInterruptStack.size() == 1}|,
// then other side "finished with us," and went back to its own business.
// That business might have included sending any number of async message
// |A<*| until sending a blocking message |(S< | C<)|. If we had more than
@ -727,7 +640,7 @@ class MessageChannel : HasResultCodes
//
// Then when processing an in-call |c|, it must be true that
//
// mStack.size() == c.remoteDepth
// mInterruptStack.size() == c.remoteDepth
//
// I.e., my depth is actually the same as what the other side thought it
// was when it sent in-call |c|. If this fails to hold, we have detected
@ -788,7 +701,7 @@ class MessageChannel : HasResultCodes
// Task and state used to asynchronously notify channel has been connected
// safely. This is necessary to be able to cancel notification if we are
// closed at the same time.
RefPtr<RefCountedTask> mOnChannelConnectedTask;
RefPtr<CancelableRunnable> mOnChannelConnectedTask;
bool mPeerPidSet;
int32_t mPeerPid;
};

Просмотреть файл

@ -3334,14 +3334,9 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
onstack.addstmt(StmtReturn(ExprCall(
ExprSelect(p.channelVar(), '.', p.onCxxStackVar().name))))
# void ProcessIncomingRacingInterruptCall
processincoming = MethodDefn(
MethodDecl('FlushPendingInterruptQueue', ret=Type.VOID))
processincoming.addstmt(StmtExpr(ExprCall(ExprSelect(_actorChannel(ExprVar.THIS), '.', 'FlushPendingInterruptQueue'))))
self.cls.addstmts([ onentered, onexited,
onenteredcall, onexitedcall,
onstack, processincoming, Whitespace.NL ])
onstack, Whitespace.NL ])
# OnChannelClose()
onclose = MethodDefn(MethodDecl('OnChannelClose'))

Просмотреть файл

@ -785,7 +785,7 @@ struct JSClass {
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT \
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 37)
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \

Просмотреть файл

@ -7068,7 +7068,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
ParseContext* outerpc = m.parser().pc;
Directives directives(outerpc);
FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, directives, NotGenerator,
/* tryAnnexB = */ false);
SyncFunction, /* tryAnnexB = */ false);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(outerpc, frontend::Statement);

Просмотреть файл

@ -0,0 +1,47 @@
/* 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/. */
// Called when creating async function.
// See the comment for js::CreateAsyncFunction what unwrapped, wrapped and the
// return value are.
function AsyncFunction_wrap(unwrapped) {
var wrapper = function() {
// The try block is required to handle throws in default arguments properly.
try {
return AsyncFunction_start(callFunction(std_Function_apply, unwrapped, this, arguments));
} catch (e) {
var promiseCtor = GetBuiltinConstructor('Promise');
return callFunction(Promise_static_reject, promiseCtor, e);
}
};
return CreateAsyncFunction(wrapper, unwrapped);
}
function AsyncFunction_start(generator) {
return AsyncFunction_resume(generator, undefined, generator.next);
}
function AsyncFunction_resume(gen, v, method) {
var promiseCtor = GetBuiltinConstructor('Promise');
let result;
try {
// get back into async function, run to next await point
result = callFunction(method, gen, v);
} catch (exc) {
// The async function itself failed.
return callFunction(Promise_static_reject, promiseCtor, exc);
}
if (result.done)
return callFunction(Promise_static_resolve, promiseCtor, result.value);
// If we get here, `await` occurred. `gen` is paused at a yield point.
return callFunction(Promise_then,
callFunction(Promise_static_resolve, promiseCtor, result.value),
function(val) {
return AsyncFunction_resume(gen, val, gen.next);
}, function (err) {
return AsyncFunction_resume(gen, err, gen.throw);
});
}

Просмотреть файл

@ -966,6 +966,7 @@ js::FutexRuntime::wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
// See explanation below.
if (state_ == WaitingInterrupted) {
UnlockGuard<Mutex> unlock(locked);
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_WAIT_NOT_ALLOWED);
return false;
}

Просмотреть файл

@ -704,7 +704,7 @@ ObjectDefineProperties(JSContext* cx, HandleObject obj, HandleValue properties)
// Step 5.b.
if (desc.object() && desc.enumerable()) {
if (!GetProperty(cx, props, props, nextKey, &descObj) ||
!ToPropertyDescriptor(cx, descObj, false, &desc) ||
!ToPropertyDescriptor(cx, descObj, true, &desc) ||
!descriptors.append(desc) ||
!descriptorKeys.append(nextKey))
{

Просмотреть файл

@ -1919,8 +1919,8 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
/**
* ES2016, 25.4.4.4, Promise.reject.
*/
static bool
Promise_reject(JSContext* cx, unsigned argc, Value* vp)
bool
js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
{
return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode);
}
@ -1949,8 +1949,8 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
/**
* ES2016, 25.4.4.5, Promise.resolve.
*/
static bool
Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
bool
js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
{
return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode);
}
@ -2051,8 +2051,8 @@ js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleVal
}
// ES2016, 25.4.5.3.
static bool
Promise_then(JSContext* cx, unsigned argc, Value* vp)
bool
js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);

Просмотреть файл

@ -153,6 +153,13 @@ class PromiseTask : public JS::AsyncTask
virtual void execute() = 0;
};
bool
Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp);
bool
Promise_reject(JSContext* cx, unsigned argc, Value* vp);
bool
Promise_then(JSContext* cx, unsigned argc, Value* vp);
} // namespace js
#endif /* builtin_Promise_h */

Просмотреть файл

@ -93,6 +93,7 @@ enum UnaryOperator {
UNOP_BITNOT,
UNOP_TYPEOF,
UNOP_VOID,
UNOP_AWAIT,
UNOP_LIMIT
};
@ -162,7 +163,8 @@ static const char* const unopNames[] = {
"!", /* UNOP_NOT */
"~", /* UNOP_BITNOT */
"typeof", /* UNOP_TYPEOF */
"void" /* UNOP_VOID */
"void", /* UNOP_VOID */
"await" /* UNOP_AWAIT */
};
static const char* const nodeTypeNames[] = {
@ -466,7 +468,7 @@ class NodeBuilder
MOZ_MUST_USE bool function(ASTType type, TokenPos* pos,
HandleValue id, NodeVector& args, NodeVector& defaults,
HandleValue body, HandleValue rest, GeneratorStyle generatorStyle,
bool isExpression, MutableHandleValue dst);
bool isAsync, bool isExpression, MutableHandleValue dst);
MOZ_MUST_USE bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
MutableHandleValue dst);
@ -1590,7 +1592,7 @@ bool
NodeBuilder::function(ASTType type, TokenPos* pos,
HandleValue id, NodeVector& args, NodeVector& defaults,
HandleValue body, HandleValue rest,
GeneratorStyle generatorStyle, bool isExpression,
GeneratorStyle generatorStyle, bool isAsync, bool isExpression,
MutableHandleValue dst)
{
RootedValue array(cx), defarray(cx);
@ -1601,6 +1603,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
bool isGenerator = generatorStyle != GeneratorStyle::None;
RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
RootedValue isAsyncVal(cx, BooleanValue(isAsync));
RootedValue isExpressionVal(cx, BooleanValue(isExpression));
RootedValue cb(cx, callbacks[type]);
@ -1624,6 +1627,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
"body", body,
"rest", rest,
"generator", isGeneratorVal,
"async", isAsyncVal,
"style", styleVal,
"expression", isExpressionVal,
dst);
@ -1636,6 +1640,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
"body", body,
"rest", rest,
"generator", isGeneratorVal,
"async", isAsyncVal,
"expression", isExpressionVal,
dst);
}
@ -1804,6 +1809,7 @@ class ASTSerializer
bool function(ParseNode* pn, ASTType type, MutableHandleValue dst);
bool functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& defaults,
bool isAsync, bool isExpression,
MutableHandleValue body, MutableHandleValue rest);
bool functionBody(ParseNode* pn, TokenPos* pos, MutableHandleValue dst);
@ -1880,6 +1886,9 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op)
if (IsTypeofKind(kind))
return UNOP_TYPEOF;
if (kind == PNK_AWAIT)
return UNOP_AWAIT;
switch (op) {
case JSOP_NEG:
return UNOP_NEG;
@ -2907,7 +2916,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
return leftAssociate(pn, dst);
case PNK_POW:
return rightAssociate(pn, dst);
return rightAssociate(pn, dst);
case PNK_DELETENAME:
case PNK_DELETEPROP:
@ -2919,6 +2928,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_NOT:
case PNK_BITNOT:
case PNK_POS:
case PNK_AWAIT:
case PNK_NEG: {
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
@ -3396,6 +3406,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
: GeneratorStyle::ES6)
: GeneratorStyle::None;
bool isAsync = pn->pn_funbox->isAsync();
bool isExpression =
#if JS_HAS_EXPR_CLOSURES
func->isExprBody();
@ -3416,13 +3427,14 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
rest.setUndefined();
else
rest.setNull();
return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) &&
builder.function(type, &pn->pn_pos, id, args, defaults, body,
rest, generatorStyle, isExpression, dst);
return functionArgsAndBody(pn->pn_body, args, defaults, isAsync, isExpression, &body, &rest) &&
builder.function(type, &pn->pn_pos, id, args, defaults, body,
rest, generatorStyle, isAsync, isExpression, dst);
}
bool
ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& defaults,
bool isAsync, bool isExpression,
MutableHandleValue body, MutableHandleValue rest)
{
ParseNode* pnargs;
@ -3456,6 +3468,14 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
pnstart = pnstart->pn_next;
}
// Async arrow with expression body is converted into STATEMENTLIST
// to insert initial yield.
if (isAsync && isExpression) {
MOZ_ASSERT(pnstart->getKind() == PNK_RETURN);
return functionArgs(pn, pnargs, args, defaults, rest) &&
expression(pnstart->pn_kid, body);
}
return functionArgs(pn, pnargs, args, defaults, rest) &&
functionBody(pnstart, &pnbody->pn_pos, body);
}

Просмотреть файл

@ -93,6 +93,9 @@
#define REGEXP_STICKY_FLAG 0x08
#define REGEXP_UNICODE_FLAG 0x10
#define ASYNC_WRAPPED_SLOT 1
#define ASYNC_UNWRAPPED_SLOT 1
#define MODULE_OBJECT_ENVIRONMENT_SLOT 2
#define MODULE_STATE_FAILED 0

Просмотреть файл

@ -63,7 +63,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
ModuleObject* compileModule();
bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
GeneratorKind generatorKind);
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
ScriptSourceObject* sourceObjectPtr() const;
@ -435,7 +435,8 @@ BytecodeCompiler::compileModule()
bool
BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind)
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(fun);
MOZ_ASSERT(fun->isTenured());
@ -453,7 +454,7 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
ParseNode* fn;
do {
Directives newDirectives = directives;
fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind,
fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind,
directives, &newDirectives);
if (!fn && !handleParseFailure(newDirectives))
return false;
@ -646,7 +647,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
MOZ_ASSERT(!lazy->isLegacyGenerator());
ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind());
ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(),
lazy->asyncKind());
if (!pn)
return false;
@ -679,7 +681,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
static bool
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
HandleScope enclosingScope, GeneratorKind generatorKind)
HandleScope enclosingScope, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(!options.isRunOnce);
@ -689,7 +692,7 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyComp
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
TraceLogger_ParserCompileFunction);
compiler.setSourceArgumentsNotIncluded();
return compiler.compileFunctionBody(fun, formals, generatorKind);
return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
}
bool
@ -698,7 +701,8 @@ frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
HandleScope enclosingScope)
{
return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator);
return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator,
SyncFunction);
}
bool
@ -708,10 +712,9 @@ frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
NotGenerator);
NotGenerator, SyncFunction);
}
bool
frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
@ -720,5 +723,16 @@ frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
StarGenerator);
StarGenerator, SyncFunction);
}
bool
frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals,
JS::SourceBufferHolder& srcBuf)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
StarGenerator, AsyncFunction);
}

Просмотреть файл

@ -68,6 +68,11 @@ CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
MOZ_MUST_USE bool
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
ScriptSourceObject*
CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);

Просмотреть файл

@ -2465,6 +2465,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_YIELD_STAR:
case PNK_YIELD:
case PNK_AWAIT:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
@ -6928,6 +6929,11 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
if (!pn->functionIsHoisted()) {
/* JSOP_LAMBDA_ARROW is always preceded by a new.target */
MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
if (funbox->isAsync()) {
MOZ_ASSERT(!needsProto);
return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow());
}
if (fun->isArrow()) {
if (sc->allowNewTarget()) {
if (!emit1(JSOP_NEWTARGET))
@ -6942,6 +6948,13 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
MOZ_ASSERT(pn->getOp() == JSOP_FUNWITHPROTO || pn->getOp() == JSOP_LAMBDA);
pn->setOp(JSOP_FUNWITHPROTO);
}
if (pn->getOp() == JSOP_DEFFUN) {
if (!emitIndex32(JSOP_LAMBDA, index))
return false;
return emit1(JSOP_DEFFUN);
}
return emitIndex32(pn->getOp(), index);
}
@ -6972,7 +6985,14 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
MOZ_ASSERT(sc->isGlobalContext() || sc->isEvalContext());
MOZ_ASSERT(pn->getOp() == JSOP_NOP);
switchToPrologue();
if (!emitIndex32(JSOP_DEFFUN, index))
if (funbox->isAsync()) {
if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow()))
return false;
} else {
if (!emitIndex32(JSOP_LAMBDA, index))
return false;
}
if (!emit1(JSOP_DEFFUN))
return false;
if (!updateSourceCoordNotes(pn->pn_pos.begin))
return false;
@ -6982,7 +7002,12 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
// For functions nested within functions and blocks, make a lambda and
// initialize the binding name of the function in the current scope.
auto emitLambda = [index](BytecodeEmitter* bce, const NameLocation&, bool) {
bool isAsync = funbox->isAsync();
auto emitLambda = [index, isAsync](BytecodeEmitter* bce, const NameLocation&, bool) {
if (isAsync) {
return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
/* isArrow = */ false);
}
return bce->emitIndexOp(JSOP_LAMBDA, index);
};
@ -6995,6 +7020,74 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
return true;
}
bool
BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
if (isArrow) {
if (sc->allowNewTarget()) {
if (!emit1(JSOP_NEWTARGET))
return false;
} else {
if (!emit1(JSOP_NULL))
return false;
}
if (!emitIndex32(JSOP_LAMBDA_ARROW, index))
return false;
} else {
if (!emitIndex32(JSOP_LAMBDA, index))
return false;
}
return true;
}
bool
BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow) {
// needsHomeObject can be true for propertyList for extended class.
// In that case push both unwrapped and wrapped function, in order to
// initialize home object of unwrapped function, and set wrapped function
// as a property.
//
// lambda // unwrapped
// getintrinsic // unwrapped AsyncFunction_wrap
// undefined // unwrapped AsyncFunction_wrap undefined
// dupat 2 // unwrapped AsyncFunction_wrap undefined unwrapped
// call 1 // unwrapped wrapped
//
// Emitted code is surrounded by the following code.
//
// // classObj classCtor classProto
// (emitted code) // classObj classCtor classProto unwrapped wrapped
// swap // classObj classCtor classProto wrapped unwrapped
// inithomeobject 1 // classObj classCtor classProto wrapped unwrapped
// // initialize the home object of unwrapped
// // with classProto here
// pop // classObj classCtor classProto wrapped
// inithiddenprop // classObj classCtor classProto wrapped
// // initialize the property of the classProto
// // with wrapped function here
// pop // classObj classCtor classProto
//
// needsHomeObject is false for other cases, push wrapped function only.
if (needsHomeObject) {
if (!emitAsyncWrapperLambda(index, isArrow))
return false;
}
if (!emitAtomOp(cx->names().AsyncFunction_wrap, JSOP_GETINTRINSIC))
return false;
if (!emit1(JSOP_UNDEFINED))
return false;
if (needsHomeObject) {
if (!emitDupAt(2))
return false;
} else {
if (!emitAsyncWrapperLambda(index, isArrow))
return false;
}
if (!emitCall(JSOP_CALL, 1))
return false;
return true;
}
bool
BytecodeEmitter::emitDo(ParseNode* pn)
{
@ -8376,8 +8469,17 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
propdef->pn_right->pn_funbox->needsHomeObject())
{
MOZ_ASSERT(propdef->pn_right->pn_funbox->function()->allowSuperProperty());
if (!emit2(JSOP_INITHOMEOBJECT, isIndex))
bool isAsync = propdef->pn_right->pn_funbox->isAsync();
if (isAsync) {
if (!emit1(JSOP_SWAP))
return false;
}
if (!emit2(JSOP_INITHOMEOBJECT, isIndex + isAsync))
return false;
if (isAsync) {
if (!emit1(JSOP_POP))
return false;
}
}
// Class methods are not enumerable.
@ -9243,6 +9345,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
break;
case PNK_YIELD:
case PNK_AWAIT:
if (!emitYield(pn))
return false;
break;

Просмотреть файл

@ -603,6 +603,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn);
MOZ_MUST_USE bool emitAsyncWrapperLambda(unsigned index, bool isArrow);
MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow);
MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);
// Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM

Просмотреть файл

@ -311,6 +311,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_CONDITIONAL:
case PNK_TYPEOFNAME:
case PNK_TYPEOFEXPR:
case PNK_AWAIT:
case PNK_VOID:
case PNK_NOT:
case PNK_BITNOT:
@ -1783,6 +1784,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
case PNK_YIELD:
case PNK_AWAIT:
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
(pn->pn_right->isKind(PNK_ASSIGN) &&

Просмотреть файл

@ -432,6 +432,11 @@ class FullParseHandler
return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);
}
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
return new_<BinaryNode>(PNK_AWAIT, JSOP_YIELD, pos, value, gen);
}
// Statements
ParseNode* newStatementList(const TokenPos& pos) {

Просмотреть файл

@ -507,6 +507,7 @@ class NameResolver
break;
case PNK_YIELD:
case PNK_AWAIT:
MOZ_ASSERT(cur->isArity(PN_BINARY));
if (cur->pn_left) {
if (!resolve(cur->pn_left, prefix))

Просмотреть файл

@ -290,7 +290,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
// variable, or an assignment of a PNK_GENERATOR node to the '.generator'
// local, for a synthesized, prepended initial yield. Yum!
case PNK_YIELD_STAR:
case PNK_YIELD: {
case PNK_YIELD:
case PNK_AWAIT: {
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->pn_right);
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||

Просмотреть файл

@ -120,6 +120,7 @@ class ObjectBox;
F(VOID) \
F(NOT) \
F(BITNOT) \
F(AWAIT) \
\
/* \
* Binary operators. \
@ -350,7 +351,8 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_NEG
* PNK_VOID, unary pn_kid: UNARY expr
* PNK_NOT,
* PNK_BITNOT
* PNK_BITNOT,
* PNK_AWAIT
* PNK_TYPEOFNAME, unary pn_kid: UNARY expr
* PNK_TYPEOFEXPR
* PNK_PREINCREMENT, unary pn_kid: MEMBER expr

Просмотреть файл

@ -436,7 +436,7 @@ UsedNameTracker::rewind(RewindToken token)
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
JSFunction* fun, Directives directives, bool extraWarnings,
GeneratorKind generatorKind)
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
: ObjectBox(fun, traceListHead),
SharedContext(cx, Kind::ObjectBox, directives, extraWarnings),
enclosingScope_(nullptr),
@ -450,6 +450,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
startColumn(0),
length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
asyncKindBits_(AsyncKindAsBits(asyncKind)),
isGenexpLambda(false),
hasDestructuringArgs(false),
hasParameterExprs(false),
@ -734,7 +735,8 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
template <typename ParseHandler>
FunctionBox*
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives,
GeneratorKind generatorKind, bool tryAnnexB)
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB)
{
MOZ_ASSERT(fun);
MOZ_ASSERT_IF(tryAnnexB, !pc->sc()->strict());
@ -748,7 +750,7 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheri
*/
FunctionBox* funbox =
alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, inheritedDirectives,
options().extraWarningsOption, generatorKind);
options().extraWarningsOption, generatorKind, asyncKind);
if (!funbox) {
ReportOutOfMemory(context);
return nullptr;
@ -855,7 +857,7 @@ Parser<ParseHandler>::isValidStrictBinding(PropertyName* name)
name != context->names().arguments &&
name != context->names().let &&
name != context->names().static_ &&
!IsKeyword(name);
!(IsKeyword(name) && name != context->names().await);
}
/*
@ -1967,6 +1969,7 @@ Parser<FullParseHandler>::moduleBody(ModuleSharedContext* modulesc)
if (!mn)
return null();
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, true);
ParseNode* pn = statementList(YieldIsKeyword);
if (!pn)
return null();
@ -2195,6 +2198,7 @@ Parser<SyntaxParseHandler>::finishFunction()
if (pc->sc()->strict())
lazy->setStrict();
lazy->setGeneratorKind(funbox->generatorKind());
lazy->setAsyncKind(funbox->asyncKind());
if (funbox->isLikelyConstructorWrapper())
lazy->setLikelyConstructorWrapper();
if (funbox->isDerivedClassConstructor())
@ -2214,12 +2218,23 @@ Parser<SyntaxParseHandler>::finishFunction()
return true;
}
static YieldHandling
GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
{
if (asyncKind == AsyncFunction)
return YieldIsName;
if (generatorKind == NotGenerator)
return YieldIsName;
return YieldIsKeyword;
}
template <>
ParseNode*
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
HandleScope enclosingScope,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Directives inheritedDirectives,
Directives* newDirectives)
{
@ -2235,7 +2250,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
fn->pn_body = argsbody;
FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind,
/* tryAnnexB = */ false);
asyncKind, /* tryAnnexB = */ false);
if (!funbox)
return null();
funbox->initStandaloneFunction(enclosingScope);
@ -2258,7 +2273,8 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
}
funbox->hasDuplicateParameters = duplicatedParam;
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
if (!pn)
return null();
@ -2394,6 +2410,16 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
} else {
MOZ_ASSERT(type == ExpressionBody);
// Async functions are implemented as star generators, and star
// generators are assumed to be statement lists, to prepend initial
// `yield`.
Node stmtList = null();
if (pc->isAsync()) {
stmtList = handler.newStatementList(pos());
if (!stmtList)
return null();
}
Node kid = assignExpr(inHandling, yieldHandling, TripledotProhibited);
if (!kid)
return null();
@ -2401,6 +2427,11 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
pn = handler.newReturnStatement(kid, handler.getPosition(kid));
if (!pn)
return null();
if (pc->isAsync()) {
handler.addStatementToList(stmtList, pn);
pn = stmtList;
}
}
switch (pc->generatorKind()) {
@ -2421,13 +2452,13 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
break;
case StarGenerator:
MOZ_ASSERT(kind != Arrow);
MOZ_ASSERT(type == StatementListBody);
MOZ_ASSERT_IF(!pc->isAsync(), kind != Arrow);
MOZ_ASSERT_IF(!pc->isAsync(), type == StatementListBody);
break;
}
if (pc->isGenerator()) {
MOZ_ASSERT(type == StatementListBody);
MOZ_ASSERT_IF(!pc->isAsync(), type == StatementListBody);
if (!declareDotGeneratorName())
return null();
Node generator = newDotGeneratorName();
@ -2453,7 +2484,8 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
template <typename ParseHandler>
JSFunction*
Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
GeneratorKind generatorKind, HandleObject proto)
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
HandleObject proto)
{
MOZ_ASSERT_IF(kind == Statement, atom != nullptr);
@ -2509,6 +2541,10 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
: JSFunction::INTERPRETED_GENERATOR);
}
// We store the async wrapper in a slot for later access.
if (asyncKind == AsyncFunction)
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto,
allocKind, TenuredObject);
if (!fun)
@ -2618,19 +2654,47 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
FunctionBox* funbox = pc->functionBox();
bool parenFreeArrow = false;
TokenStream::Modifier modifier = TokenStream::None;
// Modifier for the following tokens.
// TokenStream::None for the following cases:
// async a => 1
// ^
//
// (a) => 1
// ^
//
// async (a) => 1
// ^
//
// function f(a) {}
// ^
//
// TokenStream::Operand for the following case:
// a => 1
// ^
TokenStream::Modifier firstTokenModifier = TokenStream::None;
// Modifier for the the first token in each argument.
// can be changed to TokenStream::None for the following case:
// async a => 1
// ^
TokenStream::Modifier argModifier = TokenStream::Operand;
if (kind == Arrow) {
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
// In async function, the first token after `async` is already gotten
// with TokenStream::None.
// In sync function, the first token is already gotten with
// TokenStream::Operand.
firstTokenModifier = funbox->isAsync() ? TokenStream::None : TokenStream::Operand;
if (!tokenStream.peekToken(&tt, firstTokenModifier))
return false;
if (tt == TOK_NAME || tt == TOK_YIELD)
if (tt == TOK_NAME || tt == TOK_YIELD) {
parenFreeArrow = true;
else
modifier = TokenStream::Operand;
argModifier = firstTokenModifier;
}
}
if (!parenFreeArrow) {
TokenKind tt;
if (!tokenStream.getToken(&tt, modifier))
if (!tokenStream.getToken(&tt, firstTokenModifier))
return false;
if (tt != TOK_LP) {
report(ParseError, false, null(),
@ -2677,8 +2741,9 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
}
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
if (!tokenStream.getToken(&tt, argModifier))
return false;
argModifier = TokenStream::Operand;
MOZ_ASSERT_IF(parenFreeArrow, tt == TOK_NAME || tt == TOK_YIELD);
if (tt == TOK_TRIPLEDOT) {
@ -2719,10 +2784,9 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
funbox->hasDestructuringArgs = true;
Node destruct = destructuringDeclarationWithoutYield(
Node destruct = destructuringDeclarationWithoutYieldOrAwait(
DeclarationKind::FormalParameter,
yieldHandling, tt,
JSMSG_YIELD_IN_DEFAULT);
yieldHandling, tt);
if (!destruct)
return false;
@ -2737,6 +2801,15 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
if (parenFreeArrow)
funbox->setStart(tokenStream);
if (funbox->isAsync() && tokenStream.currentName() == context->names().await) {
// `await` is already gotten as TOK_NAME for the following
// case:
//
// async await => 1
report(ParseError, false, null(), JSMSG_RESERVED_ID, "await");
return false;
}
RootedPropertyName name(context, bindingIdentifier(yieldHandling));
if (!name)
return false;
@ -2791,7 +2864,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
}
funbox->hasParameterExprs = true;
Node def_expr = assignExprWithoutYield(yieldHandling, JSMSG_YIELD_IN_DEFAULT);
Node def_expr = assignExprWithoutYieldOrAwait(yieldHandling);
if (!def_expr)
return false;
if (!handler.setLastFunctionFormalParameterDefault(funcpn, def_expr))
@ -2921,7 +2994,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
RootedFunction fun(context, handler.nextLazyInnerFunction());
MOZ_ASSERT(!fun->isLegacyGenerator());
FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false),
fun->generatorKind(), tryAnnexB);
fun->generatorKind(), fun->asyncKind(), tryAnnexB);
if (!funbox)
return false;
@ -3029,9 +3102,11 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yieldHandling,
HandleAtom funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, InvokedPrediction invoked)
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
InvokedPrediction invoked)
{
MOZ_ASSERT_IF(kind == Statement, funName);
MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator);
Node pn = handler.newFunctionDefinition();
if (!pn)
@ -3064,7 +3139,7 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
if (!proto)
return null();
}
RootedFunction fun(context, newFunction(funName, kind, generatorKind, proto));
RootedFunction fun(context, newFunction(funName, kind, generatorKind, asyncKind, proto));
if (!fun)
return null();
@ -3083,7 +3158,7 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
// "use foo" directives.
while (true) {
if (trySyntaxParseInnerFunction(pn, fun, inHandling, yieldHandling, kind, generatorKind,
tryAnnexB, directives, &newDirectives))
asyncKind, tryAnnexB, directives, &newDirectives))
{
break;
}
@ -3114,6 +3189,7 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
bool tryAnnexB,
Directives inheritedDirectives,
Directives* newDirectives)
@ -3143,7 +3219,7 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
// still expects a FunctionBox to be attached to it during BCE, and
// the syntax parser cannot attach one to it.
FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
tryAnnexB);
asyncKind, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(pc, kind);
@ -3175,8 +3251,8 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
} while (false);
// We failed to do a syntax parse above, so do the full parse.
return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, tryAnnexB,
inheritedDirectives, newDirectives);
return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind,
tryAnnexB, inheritedDirectives, newDirectives);
}
template <>
@ -3186,13 +3262,14 @@ Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
bool tryAnnexB,
Directives inheritedDirectives,
Directives* newDirectives)
{
// This is already a syntax parser, so just parse the inner function.
return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, tryAnnexB,
inheritedDirectives, newDirectives);
return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind,
tryAnnexB, inheritedDirectives, newDirectives);
}
template <typename ParseHandler>
@ -3222,16 +3299,18 @@ template <typename ParseHandler>
bool
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
bool tryAnnexB, Directives inheritedDirectives,
Directives* newDirectives)
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives)
{
// Note that it is possible for outerpc != this->pc, as we may be
// attempting to syntax parse an inner function from an outer full
// parser. In that case, outerpc is a ParseContext from the full parser
// instead of the current top of the stack of the syntax parser.
FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, tryAnnexB);
FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
asyncKind, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(outerpc, kind);
@ -3262,7 +3341,8 @@ Parser<ParseHandler>::appendToCallSiteObj(Node callSiteObj)
template <>
ParseNode*
Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict,
GeneratorKind generatorKind)
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(checkOptionsCalled);
@ -3271,7 +3351,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
return null();
Directives directives(strict);
FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind,
FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind,
/* tryAnnexB = */ false);
if (!funbox)
return null();
@ -3284,15 +3364,15 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
// Our tokenStream has no current token, so pn's position is garbage.
// Substitute the position of the first token in our source. If the function
// is an arrow, use TokenStream::Operand to keep verifyConsistentModifier
// from complaining (we will use TokenStream::Operand in functionArguments).
if (!tokenStream.peekTokenPos(&pn->pn_pos,
fun->isArrow() ? TokenStream::Operand : TokenStream::None))
{
// is a not-async arrow, use TokenStream::Operand to keep
// verifyConsistentModifier from complaining (we will use
// TokenStream::Operand in functionArguments).
TokenStream::Modifier modifier = (fun->isArrow() && asyncKind == SyncFunction)
? TokenStream::Operand : TokenStream::None;
if (!tokenStream.peekTokenPos(&pn->pn_pos, modifier))
return null();
}
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
FunctionSyntaxKind syntaxKind = Statement;
if (fun->isClassConstructor())
syntaxKind = ClassConstructor;
@ -3329,6 +3409,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
FunctionBox* funbox = pc->functionBox();
RootedFunction fun(context, funbox->function());
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, funbox->isAsync());
if (!functionArguments(yieldHandling, kind, pn))
return false;
@ -3357,7 +3438,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return false;
if (tt != TOK_LC) {
if (funbox->isStarGenerator() || kind == Method ||
if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method ||
kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
IsConstructorKind(kind)) {
report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
@ -3387,9 +3468,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
// |yield| in the parameters is either a name or keyword, depending on
// whether the arrow function is enclosed in a generator function or not.
// Whereas the |yield| in the function body is always parsed as a name.
YieldHandling bodyYieldHandling = pc->isGenerator() ? YieldIsKeyword : YieldIsName;
MOZ_ASSERT_IF(yieldHandling != bodyYieldHandling, kind == Arrow);
YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind(), pc->asyncKind());
Node body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
if (!body)
return false;
@ -3435,7 +3514,8 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling)
Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
@ -3455,12 +3535,16 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
}
RootedPropertyName name(context);
GeneratorKind generatorKind = NotGenerator;
GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
if (tt == TOK_MUL) {
if (asyncKind != SyncFunction) {
report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
return null();
}
generatorKind = StarGenerator;
if (!tokenStream.getToken(&tt))
return null();
@ -3479,9 +3563,9 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
return null();
}
YieldHandling newYieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
Node fun = functionDefinition(InAllowed, newYieldHandling, name, Statement, generatorKind,
PredictUninvoked);
asyncKind, PredictUninvoked);
if (!fun)
return null();
@ -3498,22 +3582,27 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
GeneratorKind generatorKind = NotGenerator;
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
if (tt == TOK_MUL) {
if (asyncKind != SyncFunction) {
report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
return null();
}
generatorKind = StarGenerator;
if (!tokenStream.getToken(&tt))
return null();
}
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
RootedPropertyName name(context);
if (tt == TOK_NAME || tt == TOK_YIELD) {
@ -3524,7 +3613,8 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
tokenStream.ungetToken();
}
return functionDefinition(InAllowed, yieldHandling, name, Expression, generatorKind, invoked);
return functionDefinition(InAllowed, yieldHandling, name, Expression, generatorKind,
asyncKind, invoked);
}
/*
@ -4138,16 +4228,22 @@ Parser<ParseHandler>::destructuringDeclaration(DeclarationKind kind, YieldHandli
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::destructuringDeclarationWithoutYield(DeclarationKind kind,
YieldHandling yieldHandling,
TokenKind tt, unsigned msg)
Parser<ParseHandler>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind,
YieldHandling yieldHandling,
TokenKind tt)
{
uint32_t startYieldOffset = pc->lastYieldOffset;
uint32_t startAwaitOffset = pc->lastAwaitOffset;
Node res = destructuringDeclaration(kind, yieldHandling, tt);
if (res && pc->lastYieldOffset != startYieldOffset) {
reportWithOffset(ParseError, false, pc->lastYieldOffset,
msg, js_yield_str);
return null();
if (res) {
if (pc->lastYieldOffset != startYieldOffset) {
reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
return null();
}
if (pc->lastAwaitOffset != startAwaitOffset) {
reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
return null();
}
}
return res;
}
@ -5009,6 +5105,20 @@ Parser<FullParseHandler>::exportDeclaration()
return null();
break;
default: {
if (tt == TOK_NAME && tokenStream.currentName() == context->names().async) {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_FUNCTION) {
tokenStream.consumeKnownToken(nextSameLine);
kid = functionStmt(YieldIsName, AllowDefaultName, AsyncFunction);
if (!kid)
return null();
break;
}
}
tokenStream.ungetToken();
RootedPropertyName name(context, context->names().starDefaultStar);
nameNode = newName(name);
@ -5844,6 +5954,16 @@ Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::
return handler.newYieldExpression(begin, expr, generator);
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::newAwaitExpression(uint32_t begin, typename ParseHandler::Node expr)
{
Node generator = newDotGeneratorName();
if (!generator)
return null();
return handler.newAwaitExpression(begin, expr, generator);
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::yieldExpression(InHandling inHandling)
@ -6356,6 +6476,7 @@ JSOpFromPropertyType(PropertyType propType)
case PropertyType::Normal:
case PropertyType::Method:
case PropertyType::GeneratorMethod:
case PropertyType::AsyncMethod:
case PropertyType::Constructor:
case PropertyType::DerivedConstructor:
return JSOP_INITPROP;
@ -6377,8 +6498,8 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType)
case PropertyType::SetterNoExpressionClosure:
return SetterNoExpressionClosure;
case PropertyType::Method:
return Method;
case PropertyType::GeneratorMethod:
case PropertyType::AsyncMethod:
return Method;
case PropertyType::Constructor:
return ClassConstructor;
@ -6392,7 +6513,19 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType)
static GeneratorKind
GeneratorKindFromPropertyType(PropertyType propType)
{
return propType == PropertyType::GeneratorMethod ? StarGenerator : NotGenerator;
if (propType == PropertyType::GeneratorMethod)
return StarGenerator;
if (propType == PropertyType::AsyncMethod)
return StarGenerator;
return NotGenerator;
}
static FunctionAsyncKind
AsyncKindFromPropertyType(PropertyType propType)
{
if (propType == PropertyType::AsyncMethod)
return AsyncFunction;
return SyncFunction;
}
template <typename ParseHandler>
@ -6506,6 +6639,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
propType != PropertyType::Method && propType != PropertyType::GeneratorMethod &&
propType != PropertyType::AsyncMethod &&
propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor)
{
report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
@ -6938,6 +7072,16 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
return lexicalDeclaration(yieldHandling, /* isConst = */ false);
}
if (tokenStream.currentName() == context->names().async) {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_FUNCTION) {
tokenStream.consumeKnownToken(TOK_FUNCTION);
return functionStmt(yieldHandling, NameRequired, AsyncFunction);
}
}
if (next == TOK_COLON)
return labeledStatement(yieldHandling);
@ -7428,6 +7572,16 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (tt == TOK_YIELD && yieldExpressionsSupported())
return yieldExpression(inHandling);
bool maybeAsyncArrow = false;
if (tt == TOK_NAME && tokenStream.currentName() == context->names().async) {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_NAME || nextSameLine == TOK_YIELD)
maybeAsyncArrow = true;
}
tokenStream.ungetToken();
// Save the tokenizer state in case we find an arrow function and have to
@ -7436,9 +7590,35 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
tokenStream.tell(&start);
PossibleError possibleErrorInner(*this);
Node lhs = condExpr1(inHandling, yieldHandling, tripledotHandling, &possibleErrorInner, invoked);
if (!lhs)
return null();
Node lhs;
if (maybeAsyncArrow) {
tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand);
MOZ_ASSERT(tokenStream.currentName() == context->names().async);
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
MOZ_ASSERT(tt == TOK_NAME || tt == TOK_YIELD);
// Check yield validity here.
RootedPropertyName name(context, bindingIdentifier(yieldHandling));
if (!name)
return null();
if (!tokenStream.getToken(&tt))
return null();
if (tt != TOK_ARROW) {
report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
"'=>' after argument list", TokenKindToDesc(tt));
return null();
}
} else {
lhs = condExpr1(inHandling, yieldHandling, tripledotHandling, &possibleErrorInner, invoked);
if (!lhs) {
return null();
}
}
ParseNodeKind kind;
JSOp op;
@ -7480,12 +7660,33 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
tokenStream.seek(start);
TokenKind ignored;
if (!tokenStream.peekToken(&ignored, TokenStream::Operand))
if (!tokenStream.peekToken(&next, TokenStream::Operand))
return null();
GeneratorKind generatorKind = NotGenerator;
FunctionAsyncKind asyncKind = SyncFunction;
if (next == TOK_NAME) {
tokenStream.consumeKnownToken(next, TokenStream::Operand);
if (tokenStream.currentName() == context->names().async) {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_ARROW) {
tokenStream.ungetToken();
} else {
generatorKind = StarGenerator;
asyncKind = AsyncFunction;
}
} else {
tokenStream.ungetToken();
}
}
Node arrowFunc = functionDefinition(inHandling, yieldHandling, nullptr,
Arrow, NotGenerator);
Arrow, generatorKind, asyncKind);
if (!arrowFunc)
return null();
@ -7514,6 +7715,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
// has block body. An arrow function not ending in such, ends in
// another AssignmentExpression that we can inductively assume was
// peeked consistently.
TokenKind ignored;
if (!tokenStream.peekToken(&ignored, TokenStream::Operand))
return null();
tokenStream.addModifierException(TokenStream::NoneIsOperand);
@ -7754,6 +7956,21 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
return handler.newDelete(begin, expr);
}
case TOK_AWAIT: {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine, TokenStream::Operand))
return null();
if (nextSameLine != TOK_EOL) {
Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
if (!kid)
return null();
pc->lastAwaitOffset = begin;
return newAwaitExpression(begin, kid);
}
report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_AWAIT);
return null();
}
default: {
Node pn = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
possibleError, invoked);
@ -7811,13 +8028,13 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
return null();
RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression,
StarGenerator, proto));
StarGenerator, SyncFunction, proto));
if (!fun)
return null();
// Create box for fun->object early to root it.
Directives directives(/* strict = */ outerpc->sc()->strict());
FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator,
FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction,
/* tryAnnexB = */ false);
if (!genFunbox)
return null();
@ -8083,14 +8300,20 @@ Parser<ParseHandler>::generatorComprehension(uint32_t begin)
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::assignExprWithoutYield(YieldHandling yieldHandling, unsigned msg)
Parser<ParseHandler>::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling)
{
uint32_t startYieldOffset = pc->lastYieldOffset;
uint32_t startAwaitOffset = pc->lastAwaitOffset;
Node res = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (res && pc->lastYieldOffset != startYieldOffset) {
reportWithOffset(ParseError, false, pc->lastYieldOffset,
msg, js_yield_str);
return null();
if (res) {
if (pc->lastYieldOffset != startYieldOffset) {
reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
return null();
}
if (pc->lastAwaitOffset != startAwaitOffset) {
reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
return null();
}
}
return res;
}
@ -8664,12 +8887,31 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC");
bool isGenerator = false;
bool isAsync = false;
if (ltok == TOK_MUL) {
isGenerator = true;
if (!tokenStream.getToken(&ltok, TokenStream::KeywordIsName))
return null();
}
if (ltok == TOK_NAME && tokenStream.currentName() == context->names().async) {
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
return null();
if (tt != TOK_LP && tt != TOK_COLON && tt != TOK_RC && tt != TOK_ASSIGN) {
isAsync = true;
ltok = tt;
} else {
tokenStream.ungetToken();
tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName);
}
}
if (isAsync && isGenerator) {
report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
return null();
}
propAtom.set(nullptr);
Node propName;
switch (ltok) {
@ -8691,7 +8933,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
case TOK_NAME: {
propAtom.set(tokenStream.currentName());
// Do not look for accessor syntax on generators
if (isGenerator ||
if (isGenerator || isAsync ||
!(propAtom.get() == context->names().get ||
propAtom.get() == context->names().set))
{
@ -8810,7 +9052,12 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
if (tt == TOK_LP) {
tokenStream.ungetToken();
*propType = isGenerator ? PropertyType::GeneratorMethod : PropertyType::Method;
if (isGenerator)
*propType = PropertyType::GeneratorMethod;
else if (isAsync)
*propType = PropertyType::AsyncMethod;
else
*propType = PropertyType::Method;
return propName;
}
@ -9042,8 +9289,9 @@ Parser<ParseHandler>::methodDefinition(PropertyType propType, HandleAtom funName
{
FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType);
GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType);
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind);
FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType);
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
}
template <typename ParseHandler>
@ -9166,6 +9414,17 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
case TOK_YIELD:
case TOK_NAME: {
if (tokenStream.currentName() == context->names().async) {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_FUNCTION) {
tokenStream.consumeKnownToken(TOK_FUNCTION);
return functionExpr(PredictUninvoked, AsyncFunction);
}
}
Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
if (!name)
return null();

Просмотреть файл

@ -315,6 +315,11 @@ class ParseContext : public Nestable<ParseContext>
static const uint32_t NoYieldOffset = UINT32_MAX;
uint32_t lastYieldOffset;
// lastAwaitOffset stores the offset of the last await that was parsed.
// NoAwaitOffset is its initial value.
static const uint32_t NoAwaitOffset = UINT32_MAX;
uint32_t lastAwaitOffset;
// All inner functions in this context. Only used when syntax parsing.
Rooted<GCVector<JSFunction*, 8>> innerFunctionsForLazy;
@ -358,6 +363,7 @@ class ParseContext : public Nestable<ParseContext>
isStandaloneFunctionBody_(false),
superScopeNeedsHomeObject_(false),
lastYieldOffset(NoYieldOffset),
lastAwaitOffset(NoAwaitOffset),
innerFunctionsForLazy(prs->context, GCVector<JSFunction*, 8>(prs->context)),
newDirectives(newDirectives),
funHasReturnExpr(false),
@ -498,6 +504,14 @@ class ParseContext : public Nestable<ParseContext>
return generatorKind() == StarGenerator;
}
bool isAsync() const {
return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
}
FunctionAsyncKind asyncKind() const {
return isAsync() ? AsyncFunction : SyncFunction;
}
bool isArrowFunction() const {
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isArrow();
}
@ -553,6 +567,7 @@ enum class PropertyType {
SetterNoExpressionClosure,
Method,
GeneratorMethod,
AsyncMethod,
Constructor,
DerivedConstructor
};
@ -940,13 +955,15 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
*/
ObjectBox* newObjectBox(JSObject* obj);
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, Directives directives,
GeneratorKind generatorKind, bool tryAnnexB);
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB);
/*
* Create a new function object given a name (which is optional if this is
* a function expression).
*/
JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind,
JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
HandleObject proto);
void trace(JSTracer* trc);
@ -979,6 +996,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
inline Node newName(PropertyName* name);
inline Node newName(PropertyName* name, TokenPos pos);
inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
inline Node newAwaitExpression(uint32_t begin, Node expr);
inline bool abortIfSyntaxParser();
@ -1005,12 +1023,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a function, given only its body. Used for the Function and
// Generator constructors.
Node standaloneFunctionBody(HandleFunction fun, HandleScope enclosingScope,
Handle<PropertyNameVector> formals, GeneratorKind generatorKind,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
Directives inheritedDirectives, Directives* newDirectives);
// Parse a function, given only its arguments and body. Used for lazily
// parsed functions.
Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind);
Node standaloneLazyFunction(HandleFunction fun, bool strict,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
// Parse an inner function given an enclosing ParseContext and a
// FunctionBox for the inner function.
@ -1027,7 +1047,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// whether it's prohibited due to strictness, JS version, or occurrence
// inside a star generator.
bool yieldExpressionsSupported() {
return versionNumber() >= JSVERSION_1_7 || pc->isGenerator();
return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
}
// Match the current token against the BindingIdentifier production with
@ -1066,8 +1086,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(YieldHandling yieldHandling, DefaultHandling defaultHandling);
Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
FunctionAsyncKind asyncKind = SyncFunction);
Node functionExpr(InvokedPrediction invoked = PredictUninvoked,
FunctionAsyncKind asyncKind = SyncFunction);
Node statementList(YieldHandling yieldHandling);
@ -1172,7 +1194,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling, PossibleError* possibleError = nullptr,
InvokedPrediction invoked = PredictUninvoked);
Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err);
Node assignExprWithoutYieldOrAwait(YieldHandling yieldHandling);
Node yieldExpression(InHandling inHandling);
Node condExpr1(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
@ -1207,7 +1229,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
Node funcpn);
Node functionDefinition(InHandling inHandling, YieldHandling yieldHandling, HandleAtom name,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
InvokedPrediction invoked = PredictUninvoked);
// Parse a function body. Pass StatementListBody if the body is a list of
@ -1232,8 +1255,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread);
Node destructuringDeclaration(DeclarationKind kind, YieldHandling yieldHandling,
TokenKind tt);
Node destructuringDeclarationWithoutYield(DeclarationKind kind, YieldHandling yieldHandling,
TokenKind tt, unsigned msg);
Node destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind, YieldHandling yieldHandling,
TokenKind tt);
bool namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet);
bool checkExportedName(JSAtom* exportName);
@ -1298,11 +1321,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB);
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, GeneratorKind generatorKind, bool tryAnnexB,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives);
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling,
YieldHandling yieldHandling, FunctionSyntaxKind kind,
GeneratorKind generatorKind, bool tryAnnexB,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives);
bool finishFunctionScopes();
bool finishFunction();

Просмотреть файл

@ -453,6 +453,8 @@ class FunctionBox : public ObjectBox, public SharedContext
uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
uint8_t asyncKindBits_; /* The FunctionAsyncKing of this function. */
bool isGenexpLambda:1; /* lambda from generator expression */
bool hasDestructuringArgs:1; /* parameter list contains destructuring expression */
bool hasParameterExprs:1; /* parameter list contains expressions */
@ -473,7 +475,8 @@ class FunctionBox : public ObjectBox, public SharedContext
FunctionContextFlags funCxFlags;
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
Directives directives, bool extraWarnings, GeneratorKind generatorKind);
Directives directives, bool extraWarnings, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind);
MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
@ -532,6 +535,8 @@ class FunctionBox : public ObjectBox, public SharedContext
bool isGenerator() const { return generatorKind() != NotGenerator; }
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
FunctionAsyncKind asyncKind() const { return AsyncKindFromBits(asyncKindBits_); }
bool isAsync() const { return asyncKind() == AsyncFunction; }
bool isArrow() const { return function()->isArrow(); }
void setGeneratorKind(GeneratorKind kind) {

Просмотреть файл

@ -289,6 +289,7 @@ class SyntaxParseHandler
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; }
Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
// Statements

Просмотреть файл

@ -107,6 +107,7 @@
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'") \

Просмотреть файл

@ -965,6 +965,12 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart)
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);

Просмотреть файл

@ -32,6 +32,8 @@ 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.
@ -430,6 +432,9 @@ class MOZ_STACK_CLASS TokenStream
{}
};
bool awaitIsKeyword = false;
friend class AutoAwaitIsKeyword;
public:
typedef Token::Modifier Modifier;
static constexpr Modifier None = Token::None;
@ -1015,6 +1020,25 @@ 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);

Просмотреть файл

@ -1181,7 +1181,7 @@ function test_syntax(postfixes, check_error, ignore_opts) {
test("for each (let x in y ");
test("for each (let x in y) ");
// asm.js
// ==== asm.js ====
test("(function() { 'use asm'; ");
test("(function() { 'use asm'; var ");
@ -1208,4 +1208,149 @@ function test_syntax(postfixes, check_error, ignore_opts) {
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; } ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; }) ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; }); ");
// ==== async/await ====
// async/await function decralation
test("async ");
test("async function ");
test("async function A ");
test("async function A( ");
test("async function A() ");
test("async function A(a ");
test("async function A(a) ");
test("async function A(a) { ");
test("async function A(a) {} ");
test("async function A(a) { await ");
test("async function A(a) { await X ");
test("async function A(a) { await X; ");
test("async function A(a) { await X; } ");
test("async function A(a) { await await ");
test("async function A(a) { await await await ");
test("async function A(a) { await await await X ");
test("async function A(a) { await await await X; ");
test("async function A(a) { await await await X; } ");
opts = { no_fun: true, no_eval: true, module: true };
test("export default async ", opts);
test("export default async function ", opts);
test("export default async function ( ", opts);
test("export default async function () ", opts);
test("export default async function (a ", opts);
test("export default async function (a) ", opts);
test("export default async function (a) { ", opts);
test("export default async function (a) {} ", opts);
test("export default async function (a) { await ", opts);
test("export default async function (a) { await X ", opts);
test("export default async function (a) { await X; ", opts);
test("export default async function (a) { await X; } ", opts);
// async/await function expression
test("(async ");
test("(async function ");
test("(async function A ");
test("(async function A( ");
test("(async function A() ");
test("(async function A(a ");
test("(async function A(a) ");
test("(async function A(a) { ");
test("(async function A(a) {} ");
test("(async function A(a) { await ");
test("(async function A(a) { await X ");
test("(async function A(a) { await X; ");
test("(async function A(a) { await X; } ");
test("(async function A(a) { await X; }) ");
test("(async function ( ");
test("(async function () ");
test("(async function (a ");
test("(async function (a) ");
test("(async function (a) { ");
test("(async function (a) {} ");
test("(async function (a) { await ");
test("(async function (a) { await X ");
test("(async function (a) { await X; ");
test("(async function (a) { await X; } ");
test("(async function (a) { await X; }) ");
// async/await method
test("({ async ");
test("({ async m ");
test("({ async m( ");
test("({ async m() ");
test("({ async m() { ");
test("({ async m() {} ");
test("({ async m() {}, ");
test("class X { async ");
test("class X { async m ");
test("class X { async m( ");
test("class X { async m() ");
test("class X { async m() { ");
test("class X { async m() {} ");
test("class X { static async ");
test("class X { static async m ");
test("class X { static async m( ");
test("class X { static async m() ");
test("class X { static async m() { ");
test("class X { static async m() {} ");
// async/await arrow
test("(async a ");
test("(async a => ");
test("(async a => b ");
test("(async a => b) ");
test("(async a => { ");
test("(async a => { b ");
test("(async a => { b } ");
test("(async a => { b }) ");
test("(async ( ");
test("(async (a ");
test("(async (a) ");
test("(async (a) => ");
test("(async (a) => b ");
test("(async (a) => b) ");
test("(async (a, ");
test("(async (a, b ");
test("(async (a, b) ");
test("(async (a, b) => ");
test("(async (a, b) => b ");
test("(async (a, b) => b) ");
test("(async ([ ");
test("(async ([a ");
test("(async ([a] ");
test("(async ([a]) ");
test("(async ([a]) => ");
test("(async ([a]) => b ");
test("(async ([a]) => b) ");
test("(async ([a, ");
test("(async ([a, b ");
test("(async ([a, b] ");
test("(async ([a, b]) ");
test("(async ([a, b]) => ");
test("(async ([a, b]) => b ");
test("(async ([a, b]) => b) ");
test("(async ({ ");
test("(async ({a ");
test("(async ({a} ");
test("(async ({a}) ");
test("(async ({a}) => ");
test("(async ({a}) => b ");
test("(async ({a}) => b) ");
test("(async ({a, ");
test("(async ({a, b ");
test("(async ({a, b} ");
test("(async ({a, b}) ");
test("(async ({a, b}) => ");
test("(async ({a, b}) => b ");
test("(async ({a, b}) => b) ");
}

Просмотреть файл

@ -2750,15 +2750,14 @@ static const VMFunction DefFunOperationInfo =
bool
BaselineCompiler::emit_JSOP_DEFFUN()
{
RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
frame.syncStack(0);
masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
frame.popRegsAndSync(1);
masm.unboxObject(R0, R0.scratchReg());
masm.loadPtr(frame.addressOfEnvironmentChain(), R1.scratchReg());
prepareVMCall();
pushArg(ImmGCPtr(fun));
pushArg(R0.scratchReg());
pushArg(R1.scratchReg());
pushArg(ImmGCPtr(script));
return callVM(DefFunOperationInfo);

Просмотреть файл

@ -2434,7 +2434,8 @@ CodeGenerator::visitLambda(LLambda* lir)
emitLambdaInit(output, envChain, info);
if (info.flags & JSFunction::EXTENDED) {
MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin());
MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin() ||
info.fun->isAsync());
static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
@ -4694,7 +4695,8 @@ CodeGenerator::visitDefFun(LDefFun* lir)
{
Register envChain = ToRegister(lir->environmentChain());
pushArg(ImmGCPtr(lir->mir()->fun()));
Register fun = ToRegister(lir->fun());
pushArg(fun);
pushArg(envChain);
pushArg(ImmGCPtr(current->mir()->info().script()));

Просмотреть файл

@ -13442,13 +13442,9 @@ IonBuilder::jsop_deflexical(uint32_t index)
bool
IonBuilder::jsop_deffun(uint32_t index)
{
JSFunction* fun = script()->getFunction(index);
if (IsAsmJSModule(fun))
return abort("asm.js module function");
MOZ_ASSERT(analysis().usesEnvironmentChain());
MDefFun* deffun = MDefFun::New(alloc(), fun, current->environmentChain());
MDefFun* deffun = MDefFun::New(alloc(), current->pop(), current->environmentChain());
current->add(deffun);
return resumeAfter(deffun);

Просмотреть файл

@ -207,7 +207,11 @@ LIRGenerator::visitDefLexical(MDefLexical* ins)
void
LIRGenerator::visitDefFun(MDefFun* ins)
{
LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(ins->environmentChain()));
MDefinition* fun = ins->fun();
MOZ_ASSERT(fun->type() == MIRType::Object);
LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(fun),
useRegisterAtStart(ins->environmentChain()));
add(lir, ins);
assignSafepoint(lir, ins);
}

Просмотреть файл

@ -8106,31 +8106,22 @@ class MDefLexical
};
class MDefFun
: public MUnaryInstruction,
public NoTypePolicy::Data
: public MBinaryInstruction,
public ObjectPolicy<0>::Data
{
CompilerFunction fun_;
private:
MDefFun(JSFunction* fun, MDefinition* envChain)
: MUnaryInstruction(envChain),
fun_(fun)
MDefFun(MDefinition* fun, MDefinition* envChain)
: MBinaryInstruction(fun, envChain)
{}
public:
INSTRUCTION_HEADER(DefFun)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, environmentChain))
NAMED_OPERANDS((0, fun), (1, environmentChain))
JSFunction* fun() const {
return fun_;
}
bool possiblyCalls() const override {
return true;
}
bool appendRoots(MRootList& roots) const override {
return roots.append(fun_);
}
};
class MRegExp : public MNullaryInstruction

Просмотреть файл

@ -1550,19 +1550,23 @@ class LDefLexical : public LCallInstructionHelper<0, 0, 0>
}
};
class LDefFun : public LCallInstructionHelper<0, 1, 0>
class LDefFun : public LCallInstructionHelper<0, 2, 0>
{
public:
LIR_HEADER(DefFun)
explicit LDefFun(const LAllocation& envChain)
LDefFun(const LAllocation& fun, const LAllocation& envChain)
{
setOperand(0, envChain);
setOperand(0, fun);
setOperand(1, envChain);
}
const LAllocation* environmentChain() {
const LAllocation* fun() {
return getOperand(0);
}
const LAllocation* environmentChain() {
return getOperand(1);
}
MDefFun* mir() const {
return mir_->toDefFun();
}

Просмотреть файл

@ -181,6 +181,8 @@ MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array compre
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initializer too large")
MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *")
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async")
MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression")
MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
@ -262,6 +264,7 @@ MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
MSG_DEF(JSMSG_LEXICAL_DECL_LABEL, 1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
MSG_DEF(JSMSG_LINE_BREAK_AFTER_AWAIT, 0, JSEXN_SYNTAXERR, "no line break is allowed after 'await'")
MSG_DEF(JSMSG_GENERATOR_LABEL, 0, JSEXN_SYNTAXERR, "generator functions cannot be labelled")
MSG_DEF(JSMSG_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions cannot be labelled")
MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks")

Просмотреть файл

@ -39,9 +39,11 @@
#include "jit/JitFrameIterator.h"
#include "js/CallNonGenericMethod.h"
#include "js/Proxy.h"
#include "vm/AsyncFunction.h"
#include "vm/Debugger.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/SelfHosting.h"
#include "vm/Shape.h"
#include "vm/SharedImmutableStringsCache.h"
#include "vm/StringBuffer.h"
@ -985,6 +987,11 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
if (IsAsmJSFunction(fun))
return AsmJSFunctionToString(cx, fun);
if (IsWrappedAsyncFunction(cx, fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
return FunctionToString(cx, unwrapped, lambdaParen);
}
StringBuffer out(cx);
RootedScript script(cx);
@ -1001,6 +1008,11 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
}
}
if (fun->isAsync()) {
if (!out.append("async "))
return nullptr;
}
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
fun->isGetter() || fun->isSetter();
@ -1012,7 +1024,12 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
return nullptr;
}
if (!fun->isArrow()) {
if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function ")))
bool ok;
if (fun->isStarGenerator() && !fun->isAsync())
ok = out.append("function* ");
else
ok = out.append("function ");
if (!ok)
return nullptr;
}
if (fun->name()) {
@ -1658,7 +1675,8 @@ const JSFunctionSpec js::function_methods[] = {
};
static bool
FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind)
FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
CallArgs args = CallArgsFromVp(argc, vp);
@ -1670,7 +1688,10 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
}
bool isStarGenerator = generatorKind == StarGenerator;
bool isAsync = asyncKind == AsyncFunction;
MOZ_ASSERT(generatorKind != LegacyGenerator);
MOZ_ASSERT_IF(isAsync, isStarGenerator);
MOZ_ASSERT_IF(!isStarGenerator, !isAsync);
RootedScript maybeScript(cx);
const char* filename;
@ -1681,7 +1702,9 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
&mutedErrors);
const char* introductionType = "Function";
if (generatorKind != NotGenerator)
if (isAsync)
introductionType = "AsyncFunction";
else if (generatorKind != NotGenerator)
introductionType = "GeneratorFunction";
const char* introducerFilename = filename;
@ -1775,6 +1798,8 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
RootedAtom anonymousAtom(cx, cx->names().anonymous);
RootedObject proto(cx);
if (isStarGenerator) {
// Unwrapped function of async function should use GeneratorFunction,
// while wrapped function isn't generator.
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
if (!proto)
return false;
@ -1784,10 +1809,11 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
}
RootedObject globalLexical(cx, &global->lexicalEnvironment());
AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
JSFunction::INTERPRETED_LAMBDA, globalLexical,
anonymousAtom, proto,
AllocKind::FUNCTION, TenuredObject));
allocKind, TenuredObject));
if (!fun)
return false;
@ -1875,7 +1901,9 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
: SourceBufferHolder::NoOwnership;
bool ok;
SourceBufferHolder srcBuf(chars.start().get(), chars.length(), ownership);
if (isStarGenerator)
if (isAsync)
ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
else if (isStarGenerator)
ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
else
ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
@ -1886,13 +1914,26 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
bool
js::Function(JSContext* cx, unsigned argc, Value* vp)
{
return FunctionConstructor(cx, argc, vp, NotGenerator);
return FunctionConstructor(cx, argc, vp, NotGenerator, SyncFunction);
}
bool
js::Generator(JSContext* cx, unsigned argc, Value* vp)
{
return FunctionConstructor(cx, argc, vp, StarGenerator);
return FunctionConstructor(cx, argc, vp, StarGenerator, SyncFunction);
}
bool
js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!FunctionConstructor(cx, argc, vp, StarGenerator, AsyncFunction))
return false;
FixedInvokeArgs<1> args2(cx);
args2[0].set(args.rval());
return CallSelfHostedFunction(cx, cx->names().AsyncFunction_wrap,
NullHandleValue, args2, args.rval());
}
bool

Просмотреть файл

@ -301,6 +301,13 @@ class JSFunction : public js::NativeObject
flags_ |= RESOLVED_NAME;
}
void setAsyncKind(js::FunctionAsyncKind asyncKind) {
if (isInterpretedLazy())
lazyScript()->setAsyncKind(asyncKind);
else
nonLazyScript()->setAsyncKind(asyncKind);
}
bool getUnresolvedLength(JSContext* cx, js::MutableHandleValue v);
JSAtom* getUnresolvedName(JSContext* cx);
@ -469,6 +476,18 @@ class JSFunction : public js::NativeObject
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
js::FunctionAsyncKind asyncKind() const {
return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind();
}
bool isAsync() const {
if (isInterpretedLazy())
return lazyScript()->asyncKind() == js::AsyncFunction;
if (hasScript())
return nonLazyScript()->asyncKind() == js::AsyncFunction;
return false;
}
void setScript(JSScript* script_) {
mutableScript() = script_;
}
@ -601,6 +620,9 @@ Function(JSContext* cx, unsigned argc, Value* vp);
extern bool
Generator(JSContext* cx, unsigned argc, Value* vp);
extern bool
AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
// Allocate a new function backed by a JSNative. Note that by default this
// creates a singleton object.
extern JSFunction*

Просмотреть файл

@ -2615,6 +2615,7 @@ JSScript::initFromFunctionBox(ExclusiveContext* cx, HandleScript script,
script->isGeneratorExp_ = funbox->isGenexpLambda;
script->setGeneratorKind(funbox->generatorKind());
script->setAsyncKind(funbox->asyncKind());
PositionalFormalParameterIter fi(script);
while (fi && !fi.closedOver())
@ -3104,6 +3105,8 @@ Rebase(JSScript* dst, JSScript* src, T* srcp)
static JSObject*
CloneInnerInterpretedFunction(JSContext* cx, HandleScope enclosingScope, HandleFunction srcFun)
{
/* async function should not appear as inner function. */
MOZ_ASSERT(!srcFun->isAsync());
/* NB: Keep this in sync with XDRInterpretedFunction. */
RootedObject cloneProto(cx);
if (srcFun->isStarGenerator()) {
@ -3272,6 +3275,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
dst->needsHomeObject_ = src->needsHomeObject();
dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
dst->isAsync_ = src->asyncKind() == AsyncFunction;
if (nconsts != 0) {
GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
@ -4004,6 +4008,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
p.version = version;
p.shouldDeclareArguments = false;
p.hasThisBinding = false;
p.isAsync = false;
p.numClosedOverBindings = closedOverBindings.length();
p.numInnerFunctions = innerFunctions.length();
p.generatorKindBits = GeneratorKindAsBits(NotGenerator);

Просмотреть файл

@ -640,6 +640,7 @@ class ScriptSourceObject : public NativeObject
};
enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
enum FunctionAsyncKind { SyncFunction, AsyncFunction };
static inline unsigned
GeneratorKindAsBits(GeneratorKind generatorKind) {
@ -652,6 +653,17 @@ GeneratorKindFromBits(unsigned val) {
return static_cast<GeneratorKind>(val);
}
static inline unsigned
AsyncKindAsBits(FunctionAsyncKind asyncKind) {
return static_cast<unsigned>(asyncKind);
}
static inline FunctionAsyncKind
AsyncKindFromBits(unsigned val) {
MOZ_ASSERT(val <= AsyncFunction);
return static_cast<FunctionAsyncKind>(val);
}
/*
* NB: after a successful XDR_DECODE, XDRScript callers must do any required
* subsequent set-up of owning function or script object and then call
@ -988,6 +1000,8 @@ class JSScript : public js::gc::TenuredCell
bool isDerivedClassConstructor_:1;
bool isDefaultClassConstructor_:1;
bool isAsync_:1;
// Add padding so JSScript is gc::Cell aligned. Make padding protected
// instead of private to suppress -Wunused-private-field compiler warnings.
protected:
@ -1276,6 +1290,14 @@ class JSScript : public js::gc::TenuredCell
generatorKindBits_ = GeneratorKindAsBits(kind);
}
js::FunctionAsyncKind asyncKind() const {
return isAsync_ ? js::AsyncFunction : js::SyncFunction;
}
void setAsyncKind(js::FunctionAsyncKind kind) {
isAsync_ = kind == js::AsyncFunction;
}
void setNeedsHomeObject() {
needsHomeObject_ = true;
}
@ -1887,7 +1909,8 @@ class LazyScript : public gc::TenuredCell
uint32_t shouldDeclareArguments : 1;
uint32_t hasThisBinding : 1;
uint32_t numClosedOverBindings : 22;
uint32_t isAsync : 1;
uint32_t numClosedOverBindings : 21;
uint32_t numInnerFunctions : 20;
uint32_t generatorKindBits : 2;
@ -2024,6 +2047,14 @@ class LazyScript : public gc::TenuredCell
p_.generatorKindBits = GeneratorKindAsBits(kind);
}
FunctionAsyncKind asyncKind() const {
return p_.isAsync ? AsyncFunction : SyncFunction;
}
void setAsyncKind(FunctionAsyncKind kind) {
p_.isAsync = kind == AsyncFunction;
}
bool strict() const {
return p_.strict;
}

Просмотреть файл

@ -324,6 +324,7 @@ UNIFIED_SOURCES += [
'threading/Mutex.cpp',
'vm/ArgumentsObject.cpp',
'vm/ArrayBufferObject.cpp',
'vm/AsyncFunction.cpp',
'vm/Caches.cpp',
'vm/CallNonGenericMethod.cpp',
'vm/CharacterEncoding.cpp',
@ -749,6 +750,7 @@ selfhosted.inputs = [
'builtin/SelfHostingDefines.h',
'builtin/Utilities.js',
'builtin/Array.js',
'builtin/AsyncFunctions.js',
'builtin/Classes.js',
'builtin/Date.js',
'builtin/Error.js',

Просмотреть файл

@ -0,0 +1,19 @@
// ObjectDefineProperties with non callable accessor throws.
const descriptors = [
{get: 1}, {set: 1},
{get: []}, {set: []},
{get: {}}, {set: {}},
{get: new Number}, {set: new Number},
{get: 1, set: 1},
{get: [], set: []},
{get: {}, set: {}},
{get: new Number, set: new Number},
];
for (const descriptor of descriptors) {
assertThrowsInstanceOf(() => Object.create(null, {x: descriptor}), TypeError);
assertThrowsInstanceOf(() => Object.defineProperties({}, {x: descriptor}), TypeError);
}
reportCompare(true, true);

Просмотреть файл

@ -149,4 +149,7 @@ testDefault(function* () {}().__proto__.__proto__, "Generator");
// ES6 25.4.5.4 Promise.prototype [ @@toStringTag ]
testDefault(Promise.prototype, "Promise");
// AsyncFunction.prototype [ @@toStringTag ]
testDefault(async function() {}.constructor.prototype, "AsyncFunction");
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,21 @@
var BUGNUMBER = 1185106;
var summary = "Bound names of async functions";
print(BUGNUMBER + ": " + summary);
async function test() {}
assertEq(test.name, "test");
var test2 = (async function test2() {});
assertEq(test2.name, "test2");
var anon = async function() {};
assertEq(anon.name, "");
if (typeof Reflect !== "undefined" && Reflect.parse) {
var tree = Reflect.parse("export default async function() {}", { target: "module" });
assertEq(tree.body[0].declaration.id.name, "*default*");
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,51 @@
var BUGNUMBER = 1185106;
var summary = "EarlyErrors for async function";
print(BUGNUMBER + ": " + summary);
function assertThrowsSE(code) {
assertThrows(() => Reflect.parse(code), SyntaxError);
}
if (typeof Reflect !== "undefined" && Reflect.parse) {
// If FormalParameters Contains AwaitExpression is true.
assertThrowsSE("async function a(k = await 3) {}");
assertThrowsSE("(async function(k = await 3) {})");
assertThrowsSE("(async function a(k = await 3) {})");
// If BindingIdentifier is `eval` or `arguments`.
assertThrowsSE("'use strict'; async function eval() {}");
assertThrowsSE("'use strict'; (async function eval() {})");
assertThrowsSE("'use strict'; async function arguments() {}");
assertThrowsSE("'use strict'; (async function arguments() {})");
// If any element of the BoundNames of FormalParameters also occurs in the
// LexicallyDeclaredNames of AsyncFunctionBody.
assertThrowsSE("async function a(x) { let x; }");
assertThrowsSE("(async function(x) { let x; })");
assertThrowsSE("(async function a(x) { let x; })");
// If FormalParameters contains SuperProperty is true.
assertThrowsSE("async function a(k = super.prop) { }");
assertThrowsSE("(async function(k = super.prop) {})");
assertThrowsSE("(async function a(k = super.prop) {})");
// If AsyncFunctionBody contains SuperProperty is true.
assertThrowsSE("async function a() { super.prop(); }");
assertThrowsSE("(async function() { super.prop(); })");
assertThrowsSE("(async function a() { super.prop(); })");
// If FormalParameters contains SuperCall is true.
assertThrowsSE("async function a(k = super()) {}");
assertThrowsSE("(async function(k = super()) {})");
assertThrowsSE("(async function a(k = super()) {})");
// If AsyncFunctionBody contains SuperCall is true.
assertThrowsSE("async function a() { super(); }");
assertThrowsSE("(async function() { super(); })");
assertThrowsSE("(async function a() { super(); })");
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,31 @@
// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
var BUGNUMBER = 1185106;
var summary = "arguments.callee in sloppy mode should return wrapped function";
print(BUGNUMBER + ": " + summary);
async function decl1() {
return arguments.callee;
}
assertEventuallyEq(decl1(), decl1);
var expr1 = async function foo() {
return arguments.callee;
};
assertEventuallyEq(expr1(), expr1);
var expr2 = async function() {
return arguments.callee;
};
assertEventuallyEq(expr2(), expr2);
var obj = {
async method1() {
return arguments.callee;
}
};
assertEventuallyEq(obj.method1(), obj.method1);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,33 @@
var BUGNUMBER = 1185106;
var summary = "async function constructor and prototype";
print(BUGNUMBER + ": " + summary);
var f1 = async function() {};
var AsyncFunction = f1.constructor;
var AsyncFunctionPrototype = AsyncFunction.prototype;
assertEq(AsyncFunction.name, "AsyncFunction");
assertEq(AsyncFunction.length, 1);
assertEq(Object.getPrototypeOf(async function() {}), AsyncFunctionPrototype);
assertEq(AsyncFunctionPrototype.constructor, AsyncFunction);
var f2 = AsyncFunction("await 1");
assertEq(f2.constructor, AsyncFunction);
assertEq(f2.length, 0);
assertEq(Object.getPrototypeOf(f2), AsyncFunctionPrototype);
var f3 = new AsyncFunction("await 1");
assertEq(f3.constructor, AsyncFunction);
assertEq(f3.length, 0);
assertEq(Object.getPrototypeOf(f3), AsyncFunctionPrototype);
var f4 = AsyncFunction("a", "b", "c", "await 1");
assertEq(f4.constructor, AsyncFunction);
assertEq(f4.length, 3);
assertEq(Object.getPrototypeOf(f4), AsyncFunctionPrototype);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,14 @@
// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
var BUGNUMBER = 1185106;
var summary = "Named async function expression should get wrapped function for the name inside it";
print(BUGNUMBER + ": " + summary);
var expr = async function foo() {
return foo;
};
assertEventuallyEq(expr(), expr);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,12 @@
var BUGNUMBER = 1185106;
var summary = "async function length";
print(BUGNUMBER + ": " + summary);
assertEq(async function() {}.length, 0);
assertEq(async function(a) {}.length, 1);
assertEq(async function(a, b, c) {}.length, 3);
assertEq(async function(a, b, c, ...d) {}.length, 3);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,61 @@
// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
var BUGNUMBER = 1185106;
var summary = "async methods semantics";
print(BUGNUMBER + ": " + summary);
class X {
constructor() {
this.value = 42;
}
async getValue() {
return this.value;
}
setValue(value) {
this.value = value;
}
async increment() {
var value = await this.getValue();
this.setValue(value + 1);
return this.getValue();
}
async getBaseClassName() {
return 'X';
}
static async getStaticValue() {
return 44;
}
async 10() {
return 46;
}
async ["foo"]() {
return 47;
}
}
class Y extends X {
async getBaseClassName() {
return super.getBaseClassName();
}
}
var objLiteral = {
async get() {
return 45;
},
someStuff: 5
};
var x = new X();
var y = new Y();
assertEventuallyEq(x.getValue(), 42);
assertEventuallyEq(x.increment(), 43);
assertEventuallyEq(x[10](), 46);
assertEventuallyEq(x.foo(), 47);
assertEventuallyEq(X.getStaticValue(), 44);
assertEventuallyEq(objLiteral.get(), 45);
assertEventuallyEq(y.getBaseClassName(), 'X');
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,39 @@
var BUGNUMBER = 1185106;
var summary = "async name token in property and object destructuring pattern";
print(BUGNUMBER + ": " + summary);
{
let a = { async: 10 };
assertEq(a.async, 10);
}
{
let a = { async() {} };
assertEq(a.async instanceof Function, true);
assertEq(a.async.name, "async");
}
{
let async = 11;
let a = { async };
assertEq(a.async, 11);
}
{
let { async } = { async: 12 };
assertEq(async, 12);
}
{
let { async = 13 } = {};
assertEq(async, 13);
}
{
let { async: a = 14 } = {};
assertEq(a, 14);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,169 @@
// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
var BUGNUMBER = 1185106;
var summary = "async functions semantics";
print(BUGNUMBER + ": " + summary);
async function empty() {
}
assertEventuallyEq(empty(), undefined);
async function simpleReturn() {
return 1;
}
assertEventuallyEq(simpleReturn(), 1);
async function simpleAwait() {
var result = await 2;
return result;
}
assertEventuallyEq(simpleAwait(), 2);
async function simpleAwaitAsync() {
var result = await simpleReturn();
return 2 + result;
}
assertEventuallyEq(simpleAwaitAsync(), 3);
async function returnOtherAsync() {
return 1 + await simpleAwaitAsync();
}
assertEventuallyEq(returnOtherAsync(), 4);
async function simpleThrower() {
throw new Error();
}
assertEventuallyThrows(simpleThrower(), Error);
async function delegatedThrower() {
var val = await simpleThrower();
return val;
}
async function tryCatch() {
try {
await delegatedThrower();
return 'FAILED';
} catch (_) {
return 5;
}
}
assertEventuallyEq(tryCatch(), 5);
async function tryCatchThrow() {
try {
await delegatedThrower();
return 'FAILED';
} catch (_) {
return delegatedThrower();
}
}
assertEventuallyThrows(tryCatchThrow(), Error);
async function wellFinally() {
try {
await delegatedThrower();
} catch (_) {
return 'FAILED';
} finally {
return 6;
}
}
assertEventuallyEq(wellFinally(), 6);
async function finallyMayFail() {
try {
await delegatedThrower();
} catch (_) {
return 5;
} finally {
return delegatedThrower();
}
}
assertEventuallyThrows(finallyMayFail(), Error);
async function embedded() {
async function inner() {
return 7;
}
return await inner();
}
assertEventuallyEq(embedded(), 7);
// recursion, it works!
async function fib(n) {
return (n == 0 || n == 1) ? n : await fib(n - 1) + await fib(n - 2);
}
assertEventuallyEq(fib(6), 8);
// mutual recursion
async function isOdd(n) {
async function isEven(n) {
return n === 0 || await isOdd(n - 1);
}
return n !== 0 && await isEven(n - 1);
}
assertEventuallyEq(isOdd(12).then(v => v ? "oops" : 12), 12);
// recursion, take three!
var hardcoreFib = async function fib2(n) {
return (n == 0 || n == 1) ? n : await fib2(n - 1) + await fib2(n - 2);
}
assertEventuallyEq(hardcoreFib(7), 13);
var asyncExpr = async function() {
return 10;
}
assertEventuallyEq(asyncExpr(), 10);
var namedAsyncExpr = async function simple() {
return 11;
}
assertEventuallyEq(namedAsyncExpr(), 11);
async function executionOrder() {
var value = 0;
async function first() {
return (value = value === 0 ? 1 : value);
}
async function second() {
return (value = value === 0 ? 2 : value);
}
async function third() {
return (value = value === 0 ? 3 : value);
}
return await first() + await second() + await third() + 6;
}
assertEventuallyEq(executionOrder(), 9);
async function miscellaneous() {
if (arguments.length === 3 &&
arguments.callee.name === "miscellaneous")
return 14;
}
assertEventuallyEq(miscellaneous(1, 2, 3), 14);
function thrower() {
throw 15;
}
async function defaultArgs(arg = thrower()) {
}
assertEventuallyEq(defaultArgs().catch(e => e), 15);
let arrowAwaitExpr = async () => await 2;
assertEventuallyEq(arrowAwaitExpr(), 2);
let arrowAwaitBlock = async () => { return await 2; };
assertEventuallyEq(arrowAwaitBlock(), 2);
// Async functions are not constructible
assertThrows(() => {
async function Person() {
}
new Person();
}, TypeError);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,26 @@
(function(global) {
function getPromiseResult(promise) {
var result, error, caught = false;
promise.then(r => { result = r; },
e => { caught = true; error = e; });
drainJobQueue();
if (caught)
throw error;
return result;
}
function assertEventuallyEq(promise, expected) {
assertEq(getPromiseResult(promise), expected);
}
global.assertEventuallyEq = assertEventuallyEq;
function assertEventuallyThrows(promise, expectedErrorType) {
assertThrowsInstanceOf(() => getPromiseResult(promise), expectedErrorType);
};
global.assertEventuallyThrows = assertEventuallyThrows;
function assertEventuallyDeepEq(promise, expected) {
assertDeepEq(getPromiseResult(promise), expected);
};
global.assertEventuallyDeepEq = assertEventuallyDeepEq;
})(this);

Просмотреть файл

@ -0,0 +1,104 @@
var BUGNUMBER = 1185106;
var summary = "async arrow function syntax";
print(BUGNUMBER + ": " + summary);
if (typeof Reflect !== "undefined" && Reflect.parse) {
// Parameters.
Reflect.parse("async () => 1");
Reflect.parse("async a => 1");
Reflect.parse("async (a) => 1");
Reflect.parse("async async => 1");
Reflect.parse("async (async) => 1");
Reflect.parse("async ([a]) => 1");
Reflect.parse("async ([a, b]) => 1");
Reflect.parse("async ({a}) => 1");
Reflect.parse("async ({a, b}) => 1");
assertThrows(() => Reflect.parse("async await => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async (await) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async ([await]) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async ({await}) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async (a=await) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async ([a=await]) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async ({a=await}) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async (a=await 1) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async ([a=await 1]) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async ({a=await 1}) => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async [a] => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async [a, b] => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async {a} => 1"), SyntaxError);
assertThrows(() => Reflect.parse("async {a: b} => 1"), SyntaxError);
// Expression body.
Reflect.parse("async a => a == b");
// Expression body with nested async function.
Reflect.parse("async a => async");
Reflect.parse("async a => async b => c");
Reflect.parse("async a => async function() {}");
Reflect.parse("async a => async function b() {}");
assertThrows(() => Reflect.parse("async a => async b"), SyntaxError);
assertThrows(() => Reflect.parse("async a => async function"), SyntaxError);
assertThrows(() => Reflect.parse("async a => async function()"), SyntaxError);
// Expression body with `await`.
Reflect.parse("async a => await 1");
Reflect.parse("async a => await await 1");
Reflect.parse("async a => await await await 1");
assertThrows(() => Reflect.parse("async a => await"), SyntaxError);
assertThrows(() => Reflect.parse("async a => await await"), SyntaxError);
// `await` is Unary Expression and it cannot have `async` function as an
// operand.
assertThrows(() => Reflect.parse("async a => await async X => Y"), SyntaxError);
Reflect.parse("async a => await (async X => Y)");
// But it can have `async` identifier as an operand.
Reflect.parse("async async => await async");
// Block body.
Reflect.parse("async X => {yield}");
// `yield` handling.
Reflect.parse("async X => yield");
Reflect.parse("async yield => X");
Reflect.parse("async yield => yield");
Reflect.parse("async X => {yield}");
Reflect.parse("async X => {yield}");
Reflect.parse("async yield => {X}");
Reflect.parse("async yield => {yield}");
Reflect.parse("function* g() { async X => yield }");
assertThrows(() => Reflect.parse("'use strict'; async yield => X"), SyntaxError);
assertThrows(() => Reflect.parse("'use strict'; async (yield) => X"), SyntaxError);
assertThrows(() => Reflect.parse("'use strict'; async X => yield"), SyntaxError);
assertThrows(() => Reflect.parse("'use strict'; async X => {yield}"), SyntaxError);
assertThrows(() => Reflect.parse("function* g() { async yield => X }"));
assertThrows(() => Reflect.parse("function* g() { async (yield) => X }"));
assertThrows(() => Reflect.parse("function* g() { async ([yield]) => X }"));
assertThrows(() => Reflect.parse("function* g() { async ({yield}) => X }"));
// Not async functions.
Reflect.parse("async ()");
Reflect.parse("async (a)");
Reflect.parse("async (async)");
Reflect.parse("async ([a])");
Reflect.parse("async ([a, b])");
Reflect.parse("async ({a})");
Reflect.parse("async ({a, b})");
// Async arrow function is assignment expression.
Reflect.parse("a ? async () => {1} : b");
Reflect.parse("a ? b : async () => {1}");
assertThrows(() => Reflect.parse("async () => {1} ? a : b"), SyntaxError);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,20 @@
var BUGNUMBER = 1185106;
var summary = "async/await syntax in module";
print(BUGNUMBER + ": " + summary);
if (typeof parseModule === "function") {
parseModule("async function f() { await 3; }");
parseModule("async function f() { await 3; }");
assertThrows(() => parseModule("var await = 5;"), SyntaxError);
assertThrows(() => parseModule("export var await;"), SyntaxError);
assertThrows(() => parseModule("async function f() { function g() { await 3; } }"), SyntaxError);
if (typeof Reflect !== "undefined" && Reflect.parse) {
assertThrows(() => Reflect.parse("export default async function() { yield; }", { target: "module" }), SyntaxError);
assertThrows(() => Reflect.parse("export default async function() { yield = 1; }", { target: "module" }), SyntaxError);
}
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,89 @@
var BUGNUMBER = 1185106;
var summary = "async/await syntax";
print(BUGNUMBER + ": " + summary);
if (typeof Reflect !== "undefined" && Reflect.parse) {
assertEq(Reflect.parse("function a() {}").body[0].async, false);
assertEq(Reflect.parse("function* a() {}").body[0].async, false);
assertEq(Reflect.parse("async function a() {}").body[0].async, true);
assertEq(Reflect.parse("() => {}").body[0].async, undefined);
// Async generators are not allowed (with regards to spec)
assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError);
// No line terminator after async
assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async");
// Async function expressions
assertEq(Reflect.parse("(async function() {})()").body[0].expression.callee.async, true);
assertEq(Reflect.parse("var k = async function() {}").body[0].declarations[0].init.async, true);
assertEq(Reflect.parse("var nmd = async function named() {}").body[0].declarations[0].init.id.name, "named");
// `await` handling for function declaration name inherits.
assertEq(Reflect.parse("async function await() {}").body[0].id.name, "await");
assertThrows(() => Reflect.parse("async function f() { async function await() {} }"), SyntaxError);
// `await` is not allowed in function expression name.
assertThrows(() => Reflect.parse("(async function await() {})"), SyntaxError);
// Awaiting not directly inside an async function is not allowed
assertThrows(() => Reflect.parse("await 4;"), SyntaxError);
assertThrows(() => Reflect.parse("function a() { await 4; }"), SyntaxError);
assertThrows(() => Reflect.parse("function* a() { await 4; }"), SyntaxError);
assertThrows(() => Reflect.parse("async function k() { function a() { await 4; } }"), SyntaxError);
// No line terminator after await is allowed
assertThrows(() => Reflect.parse("async function a() { await\n4; }"), SyntaxError);
// Await is not allowed as a default expr.
assertThrows(() => Reflect.parse("async function a(k = await 3) {}"), SyntaxError);
assertThrows(() => Reflect.parse("async function a() { async function b(k = await 3) {} }"), SyntaxError);
assertThrows(() => Reflect.parse("async function a() { async function b(k = [await 3]) {} }"), SyntaxError);
assertThrows(() => Reflect.parse("async function a() { async function b([k = await 3]) {} }"), SyntaxError);
assertThrows(() => Reflect.parse("async function a() { async function b([k = [await 3]]) {} }"), SyntaxError);
assertThrows(() => Reflect.parse("async function a() { async function b({k = await 3}) {} }"), SyntaxError);
assertThrows(() => Reflect.parse("async function a() { async function b({k = [await 3]}) {} }"), SyntaxError);
// Await is not legal as an identifier in an async function.
assertThrows(() => Reflect.parse("async function a() { var await = 4; }"), SyntaxError);
assertThrows(() => Reflect.parse("async function a() { return await; }"), SyntaxError);
// Await is still available as an identifier name in strict mode code.
Reflect.parse("function a() { 'use strict'; var await = 3; }");
Reflect.parse("'use strict'; var await = 3;");
// Await is treated differently depending on context. Various cases.
Reflect.parse("var await = 3; async function a() { await 4; }");
Reflect.parse("async function a() { await 4; } var await = 5");
Reflect.parse("async function a() { function b() { return await; } }");
Reflect.parse("async function a() { var k = { async: 4 } }");
Reflect.parse("function a() { await: 4 }");
assertEq(Reflect.parse("async function a() { await 4; }")
.body[0].body.body[0].expression.operator, "await");
assertEq(Reflect.parse("async function a() { async function b() { await 4; } }")
.body[0].body.body[0].body.body[0].expression.operator, "await");
// operator priority test
assertEq(Reflect.parse("async function a() { await 2 + 3; }")
.body[0].body.body[0].expression.left.argument.value, 2);
assertEq(Reflect.parse("async function a() { await 2 + 3; }")
.body[0].body.body[0].expression.left.operator, "await");
assertEq(Reflect.parse("async function a() { await 2 + 3; }")
.body[0].body.body[0].expression.right.value, 3);
// blocks and other constructions
assertEq(Reflect.parse("{ async function a() { return 2; } }")
.body[0].body[0].async, true);
// Async function expression is primary expression.
Reflect.parse("(async function a() {}.constructor)");
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,24 @@
var BUGNUMBER = 1185106;
var summary = "async function toString";
print(BUGNUMBER + ": " + summary);
async function f1(a, b, c) { await a; }
assertEq(f1.toString(),
"async function f1(a, b, c) { await a; }");
assertEq(async function (a, b, c) { await a; }.toString(),
"async function (a, b, c) { await a; }");
assertEq((async (a, b, c) => await a).toString(),
"async (a, b, c) => await a");
assertEq((async (a, b, c) => { await a; }).toString(),
"async (a, b, c) => { await a; }");
assertEq({ async foo(a, b, c) { await a; } }.foo.toString(),
"async function foo(a, b, c) { await a; }");
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,71 @@
var BUGNUMBER = 1185106;
var summary = "yield handling in async function";
print(BUGNUMBER + ": " + summary);
function testPassArgsBody(argsbody) {
Reflect.parse(`async function a${argsbody}`);
Reflect.parse(`(async function a${argsbody})`);
Reflect.parse(`(async function ${argsbody})`);
Reflect.parse(`({ async m${argsbody} })`);
}
function testErrorArgsBody(argsbody, prefix="") {
assertThrows(() => Reflect.parse(`${prefix} async function a${argsbody}`), SyntaxError);
assertThrows(() => Reflect.parse(`${prefix} (async function a${argsbody})`), SyntaxError);
assertThrows(() => Reflect.parse(`${prefix} (async function ${argsbody})`), SyntaxError);
assertThrows(() => Reflect.parse(`${prefix} ({ async m${argsbody} })`), SyntaxError);
}
function testErrorArgsBodyStrict(argsbody) {
testErrorArgsBody(argsbody);
testErrorArgsBody(argsbody, "'use strict'; ");
assertThrows(() => Reflect.parse(`class X { async m${argsbody} }`), SyntaxError);
assertThrows(() => Reflect.parse(`class X { static async m${argsbody} }`), SyntaxError);
assertThrows(() => Reflect.parse(`export default async function ${argsbody}`, { target: "module" }), SyntaxError);
}
if (typeof Reflect !== "undefined" && Reflect.parse) {
// `yield` handling is inherited in async function declaration name.
Reflect.parse("async function yield() {}");
Reflect.parse("function f() { async function yield() {} }");
assertThrows(() => Reflect.parse("function* g() { async function yield() {} }"), SyntaxError);
assertThrows(() => Reflect.parse("'use strict'; async function yield() {}"), SyntaxError);
// `yield` is treated as an identifier in an async function expression name.
// `yield` is not allowed as an identifier in strict code.
Reflect.parse("(async function yield() {});");
Reflect.parse("function f() { (async function yield() {}); }");
Reflect.parse("function* g() { (async function yield() {}); }");
assertThrows(() => Reflect.parse("'use strict'; (async function yield() {});"), SyntaxError);
// `yield` handling is inherited in async method name.
Reflect.parse("({ async yield() {} });");
Reflect.parse("function f() { ({ async yield() {} }); }");
Reflect.parse("function* g() { ({ async yield() {} }); }");
Reflect.parse("'use strict'; ({ async yield() {} });");
Reflect.parse("class X { async yield() {} }");
Reflect.parse("({ async [yield]() {} });");
Reflect.parse("function f() { ({ async [yield]() {} }); }");
Reflect.parse("function* g() { ({ async [yield]() {} }); }");
assertThrows(() => Reflect.parse("'use strict'; ({ async [yield]() {} });"), SyntaxError);
assertThrows(() => Reflect.parse("class X { async [yield]() {} }"), SyntaxError);
// `yield` is treated as an identifier in an async function parameter
// `yield` is not allowed as an identifier in strict code.
testPassArgsBody("(yield) {}");
testPassArgsBody("(yield = 1) {}");
testPassArgsBody("(a = yield) {}");
testErrorArgsBodyStrict("(yield 3) {}");
testErrorArgsBodyStrict("(a = yield 3) {}");
// `yield` is treated as an identifier in an async function body
// `yield` is not allowed as an identifier in strict code.
testPassArgsBody("() { yield; }");
testPassArgsBody("() { yield = 1; }");
testErrorArgsBodyStrict("() { yield 3; }");
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -47,6 +47,16 @@ function genFunDecl(style, id, params, body) {
generator: true,
style: style });
}
function asyncFunDecl(id, params, body) {
return Pattern({ type: "FunctionDeclaration",
id: id,
params: params,
defaults: [],
body: body,
generator: true,
async: true,
style: "es6" });
}
function varDecl(decls) {
return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" });
}
@ -166,11 +176,29 @@ function genFunExpr(style, id, args, body) {
generator: true,
style: style });
}
function asyncFunExpr(id, args, body) {
return Pattern({ type: "FunctionExpression",
id: id,
params: args,
body: body,
generator: true,
async: true,
style: "es6" });
}
function arrowExpr(args, body) {
return Pattern({ type: "ArrowFunctionExpression",
params: args,
body: body });
}
function asyncArrowExpr(isExpression, args, body) {
return Pattern({ type: "ArrowFunctionExpression",
params: args,
body: body,
generator: true,
async: true,
expression: isExpression,
style: "es6" });
}
function metaProperty(meta, property) {
return Pattern({ type: "MetaProperty",

Просмотреть файл

@ -0,0 +1,25 @@
// |reftest| skip-if(!xulRuntime.shell)
// async function declaration.
assertDecl("async function foo() {}", asyncFunDecl(ident("foo"), [], blockStmt([])));
// async function expression.
assertExpr("(async function() {})", asyncFunExpr(null, [], blockStmt([])));
assertExpr("(async function foo() {})", asyncFunExpr(ident("foo"), [], blockStmt([])));
// async arrow.
assertExpr("async a => 1", asyncArrowExpr(true, [ident("a")], literal(1)));
assertExpr("async a => { 1 }", asyncArrowExpr(false, [ident("a")], blockStmt([exprStmt(literal(1))])));
assertExpr("async a => { return 1 }", asyncArrowExpr(false, [ident("a")], blockStmt([returnStmt(literal(1))])));
// async method.
assertExpr("({ async foo() {} })", objExpr([{ key: ident("foo"), value: asyncFunExpr(ident("foo"), [], blockStmt([]))}]));
assertStmt("class C { async foo() {} }", classStmt(ident("C"), null, [classMethod(ident("foo"), asyncFunExpr(ident("foo"), [], blockStmt([])), "method", false)]));
assertStmt("class C { static async foo() {} }", classStmt(ident("C"), null, [classMethod(ident("foo"), asyncFunExpr(ident("foo"), [], blockStmt([])), "method", true)]));
// await expression.
assertDecl("async function foo() { await bar }", asyncFunDecl(ident("foo"), [], blockStmt([exprStmt(unExpr("await", ident("bar")))])));
if (typeof reportCompare === 'function')
reportCompare(true, true);

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/PodOperations.h"
#include "jit/JitFrames.h"
#include "vm/AsyncFunction.h"
#include "vm/GlobalObject.h"
#include "vm/Stack.h"
@ -446,8 +447,13 @@ MappedArgGetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
vp.setInt32(argsobj.initialLength());
} else {
MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().callee));
if (!argsobj.hasOverriddenCallee())
vp.setObject(argsobj.callee());
if (!argsobj.hasOverriddenCallee()) {
RootedFunction callee(cx, &argsobj.callee());
if (callee->isAsync())
vp.setObject(*GetWrappedAsyncFunction(callee));
else
vp.setObject(*callee);
}
}
return true;
}

118
js/src/vm/AsyncFunction.cpp Normal file
Просмотреть файл

@ -0,0 +1,118 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "vm/AsyncFunction.h"
#include "jscompartment.h"
#include "builtin/SelfHostingDefines.h"
#include "vm/GlobalObject.h"
#include "vm/SelfHosting.h"
using namespace js;
using namespace js::gc;
/* static */ bool
GlobalObject::initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global)
{
if (global->getReservedSlot(ASYNC_FUNCTION_PROTO).isObject())
return true;
RootedObject asyncFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
if (!asyncFunctionProto)
return false;
if (!DefineToStringTag(cx, asyncFunctionProto, cx->names().AsyncFunction))
return false;
RootedValue function(cx, global->getConstructor(JSProto_Function));
if (!function.toObjectOrNull())
return false;
RootedObject proto(cx, &function.toObject());
RootedAtom name(cx, cx->names().AsyncFunction);
RootedObject asyncFunction(cx, NewFunctionWithProto(cx, AsyncFunctionConstructor, 1,
JSFunction::NATIVE_CTOR, nullptr, name,
proto));
if (!asyncFunction)
return false;
if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto))
return false;
global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto));
return true;
}
JSFunction*
js::GetWrappedAsyncFunction(JSFunction* unwrapped)
{
MOZ_ASSERT(unwrapped->isAsync());
return &unwrapped->getExtendedSlot(ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
}
JSFunction*
js::GetUnwrappedAsyncFunction(JSFunction* wrapper)
{
JSFunction* unwrapped = &wrapper->getExtendedSlot(ASYNC_UNWRAPPED_SLOT).toObject().as<JSFunction>();
MOZ_ASSERT(unwrapped->isAsync());
return unwrapped;
}
bool
js::IsWrappedAsyncFunction(JSContext* cx, JSFunction* wrapper)
{
return IsSelfHostedFunctionWithName(wrapper, cx->names().AsyncWrapped);
}
bool
js::CreateAsyncFunction(JSContext* cx, HandleFunction wrapper, HandleFunction unwrapped,
MutableHandleFunction result)
{
// Create a new function with AsyncFunctionPrototype, reusing the script
// and the environment of `wrapper` function, and the name and the length
// of `unwrapped` function.
RootedObject proto(cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
RootedObject scope(cx, wrapper->environment());
RootedAtom atom(cx, unwrapped->name());
RootedFunction wrapped(cx, NewFunctionWithProto(cx, nullptr, 0,
JSFunction::INTERPRETED_LAMBDA,
scope, atom, proto,
AllocKind::FUNCTION_EXTENDED, TenuredObject));
if (!wrapped)
return false;
wrapped->initScript(wrapper->nonLazyScript());
// Link them each other to make GetWrappedAsyncFunction and
// GetUnwrappedAsyncFunction work.
unwrapped->setExtendedSlot(ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
wrapped->setExtendedSlot(ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
// The script of `wrapper` is self-hosted, so `wrapped` should also be
// set as self-hosted function.
wrapped->setIsSelfHostedBuiltin();
// Set LAZY_FUNCTION_NAME_SLOT to "AsyncWrapped" to make it detectable in
// IsWrappedAsyncFunction.
wrapped->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(cx->names().AsyncWrapped));
// The length of the script of `wrapper` is different than the length of
// `unwrapped`. We should set actual length as resolved length, to avoid
// using the length of the script.
uint16_t length;
if (!unwrapped->getLength(cx, &length))
return false;
RootedValue lengthValue(cx, NumberValue(length));
if (!DefineProperty(cx, wrapped, cx->names().length, lengthValue,
nullptr, nullptr, JSPROP_READONLY))
{
return false;
}
result.set(wrapped);
return true;
}

30
js/src/vm/AsyncFunction.h Normal file
Просмотреть файл

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_AsyncFunction_h
#define vm_AsyncFunction_h
#include "jscntxt.h"
#include "jsobj.h"
namespace js {
JSFunction*
GetWrappedAsyncFunction(JSFunction* unwrapped);
JSFunction*
GetUnwrappedAsyncFunction(JSFunction* wrapper);
bool
IsWrappedAsyncFunction(JSContext* cx, JSFunction* wrapper);
bool
CreateAsyncFunction(JSContext* cx, HandleFunction wrapper, HandleFunction unwrapped,
MutableHandleFunction result);
} // namespace js
#endif /* vm_AsyncFunction_h */

Просмотреть файл

@ -29,6 +29,11 @@
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
macro(as, as, "as") \
macro(Async, Async, "Async") \
macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
macro(AsyncFunction_wrap, AsyncFunction_wrap, "AsyncFunction_wrap") \
macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
macro(async, async, "async") \
macro(await, await, "await") \
macro(Bool8x16, Bool8x16, "Bool8x16") \
macro(Bool16x8, Bool16x8, "Bool16x8") \
macro(Bool32x4, Bool32x4, "Bool32x4") \

Просмотреть файл

@ -17,6 +17,7 @@
#include "frontend/ParseNode.h"
#include "gc/Policy.h"
#include "vm/ArgumentsObject.h"
#include "vm/AsyncFunction.h"
#include "vm/GlobalObject.h"
#include "vm/ProxyObject.h"
#include "vm/Shape.h"
@ -1023,7 +1024,9 @@ const Class LexicalEnvironmentObject::class_ = {
};
/* static */ NamedLambdaObject*
NamedLambdaObject::create(JSContext* cx, HandleFunction callee, HandleObject enclosing,
NamedLambdaObject::create(JSContext* cx, HandleFunction callee,
HandleFunction func,
HandleObject enclosing,
gc::InitialHeap heap)
{
MOZ_ASSERT(callee->isNamedLambda());
@ -1045,14 +1048,14 @@ NamedLambdaObject::create(JSContext* cx, HandleFunction callee, HandleObject enc
if (!obj)
return nullptr;
obj->initFixedSlot(lambdaSlot(), ObjectValue(*callee));
obj->initFixedSlot(lambdaSlot(), ObjectValue(*func));
return static_cast<NamedLambdaObject*>(obj);
}
/* static */ NamedLambdaObject*
NamedLambdaObject::createTemplateObject(JSContext* cx, HandleFunction callee, gc::InitialHeap heap)
{
return create(cx, callee, nullptr, heap);
return create(cx, callee, callee, nullptr, heap);
}
/* static */ NamedLambdaObject*
@ -1060,7 +1063,15 @@ NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame)
{
RootedFunction fun(cx, frame.callee());
RootedObject enclosing(cx, frame.environmentChain());
return create(cx, fun, enclosing, gc::DefaultHeap);
return create(cx, fun, fun, enclosing, gc::DefaultHeap);
}
/* static */ NamedLambdaObject*
NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame, HandleFunction replacement)
{
RootedFunction fun(cx, frame.callee());
RootedObject enclosing(cx, frame.environmentChain());
return create(cx, fun, replacement, enclosing, gc::DefaultHeap);
}
/* static */ size_t
@ -3365,7 +3376,15 @@ js::InitFunctionEnvironmentObjects(JSContext* cx, AbstractFramePtr frame)
// Named lambdas may have an environment that holds itself for recursion.
if (callee->needsNamedLambdaEnvironment()) {
NamedLambdaObject* declEnv = NamedLambdaObject::create(cx, frame);
NamedLambdaObject* declEnv;
if (callee->isAsync()) {
// Named async function needs special environment to return
// wrapped function for the binding.
RootedFunction fun(cx, GetWrappedAsyncFunction(callee));
declEnv = NamedLambdaObject::create(cx, frame, fun);
} else {
declEnv = NamedLambdaObject::create(cx, frame);
}
if (!declEnv)
return false;
frame.pushOnEnvironmentChain(*declEnv);

Просмотреть файл

@ -515,6 +515,7 @@ class LexicalEnvironmentObject : public EnvironmentObject
class NamedLambdaObject : public LexicalEnvironmentObject
{
static NamedLambdaObject* create(JSContext* cx, HandleFunction callee,
HandleFunction replacement,
HandleObject enclosing, gc::InitialHeap heap);
public:
@ -522,6 +523,8 @@ class NamedLambdaObject : public LexicalEnvironmentObject
gc::InitialHeap heap);
static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame);
static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame,
HandleFunction replacement);
// For JITs.
static size_t lambdaSlot();

Просмотреть файл

@ -260,8 +260,8 @@ NewSingletonObjectWithObjectPrototype(JSContext* cx, Handle<GlobalObject*> globa
return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
}
static JSObject*
NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global)
JSObject*
js::NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global)
{
RootedObject proto(cx, global->getOrCreateFunctionPrototype(cx));
if (!proto)

Просмотреть файл

@ -97,6 +97,8 @@ class GlobalObject : public NativeObject
STAR_GENERATOR_OBJECT_PROTO,
STAR_GENERATOR_FUNCTION_PROTO,
STAR_GENERATOR_FUNCTION,
ASYNC_FUNCTION_PROTO,
ASYNC_FUNCTION,
MAP_ITERATOR_PROTO,
SET_ITERATOR_PROTO,
COLLATOR_PROTO,
@ -576,6 +578,19 @@ class GlobalObject : public NativeObject
return global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION, initStarGenerators);
}
static NativeObject* getOrCreateAsyncFunctionPrototype(JSContext* cx,
Handle<GlobalObject*> global)
{
return MaybeNativeObject(global->getOrCreateObject(cx, ASYNC_FUNCTION_PROTO,
initAsyncFunction));
}
static JSObject* getOrCreateAsyncFunction(JSContext* cx,
Handle<GlobalObject*> global)
{
return global->getOrCreateObject(cx, ASYNC_FUNCTION, initAsyncFunction);
}
static JSObject* getOrCreateMapIteratorPrototype(JSContext* cx,
Handle<GlobalObject*> global)
{
@ -725,6 +740,8 @@ class GlobalObject : public NativeObject
static bool initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initStarGenerators(JSContext* cx, Handle<GlobalObject*> global);
static bool initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global);
// Implemented in builtin/MapObject.cpp.
static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
@ -985,6 +1002,9 @@ StandardProtoKeyOrNull(const JSObject* obj)
return key;
}
JSObject*
NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global);
} // namespace js
template<>

Просмотреть файл

@ -3446,9 +3446,10 @@ CASE(JSOP_DEFFUN)
* a compound statement (not at the top statement level of global code, or
* at the top level of a function body).
*/
ReservedRooted<JSFunction*> fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc)));
ReservedRooted<JSFunction*> fun(&rootFunction0, &REGS.sp[-1].toObject().as<JSFunction>());
if (!DefFunOperation(cx, script, REGS.fp()->environmentChain(), fun))
goto error;
REGS.sp--;
}
END_CASE(JSOP_DEFFUN)
@ -4330,27 +4331,8 @@ js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleVa
bool
js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
HandleFunction funArg)
HandleFunction fun)
{
/*
* If static link is not current scope, clone fun's object to link to the
* current scope via parent. We do this to enable sharing of compiled
* functions among multiple equivalent scopes, amortizing the cost of
* compilation over a number of executions. Examples include XUL scripts
* and event handlers shared among Firefox or other Mozilla app chrome
* windows, and user-defined JS functions precompiled and then shared among
* requests in server-side JS.
*/
RootedFunction fun(cx, funArg);
if (fun->isNative() || fun->environment() != envChain) {
fun = CloneFunctionObjectIfNotSingleton(cx, fun, envChain, nullptr, TenuredObject);
if (!fun)
return false;
} else {
MOZ_ASSERT(script->treatAsRunOnce());
MOZ_ASSERT(!script->functionNonDelazifying());
}
/*
* We define the function as a property of the variable object and not the
* current scope chain even for the case of function expression statements

Просмотреть файл

@ -55,6 +55,7 @@
macro(private, private_, TOK_STRICT_RESERVED) \
macro(protected, protected_, TOK_STRICT_RESERVED) \
macro(public, public_, TOK_STRICT_RESERVED) \
macro(await, await, TOK_AWAIT) \
/* \
* 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 \

Просмотреть файл

@ -1300,10 +1300,10 @@
* scripts where use of dynamic scoping inhibits optimization.
* Category: Variables and Scopes
* Type: Variables
* Operands: uint32_t funcIndex
* Stack: =>
* Operands:
* Stack: fun =>
*/ \
macro(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, JOF_OBJECT) \
macro(JSOP_DEFFUN, 127,"deffun", NULL, 1, 1, 0, JOF_BYTE) \
/* Defines the new constant binding on global lexical scope.
*
* Throws if a binding with the same name already exists on the scope, or

Просмотреть файл

@ -38,6 +38,7 @@
#include "jit/InlinableNatives.h"
#include "js/CharacterEncoding.h"
#include "js/Date.h"
#include "vm/AsyncFunction.h"
#include "vm/Compression.h"
#include "vm/GeneratorObject.h"
#include "vm/Interpreter.h"
@ -1831,6 +1832,23 @@ js::ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args)
return false;
}
bool
intrinsic_CreateAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
RootedFunction wrapper(cx, &args[0].toObject().as<JSFunction>());
RootedFunction unwrapped(cx, &args[1].toObject().as<JSFunction>());
RootedFunction wrapped(cx);
if (!CreateAsyncFunction(cx, wrapper, unwrapped, &wrapped))
return false;
args.rval().setObject(*wrapped);
return true;
}
/**
* Returns the default locale as a well-formed, but not necessarily canonicalized,
* BCP-47 language tag.
@ -2230,6 +2248,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0),
JS_FN("CreateAsyncFunction", intrinsic_CreateAsyncFunction, 1,0),
JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0,
IntrinsicIsConstructing),
JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel, 3,0,
@ -2363,6 +2383,10 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("CallWeakSetMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),
JS_FN("Promise_static_resolve", Promise_static_resolve, 1, 0),
JS_FN("Promise_static_reject", Promise_reject, 1, 0),
JS_FN("Promise_then", Promise_then, 2, 0),
// See builtin/TypedObject.h for descriptors of the typedobj functions.
JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0),
JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0),

Просмотреть файл

@ -68,17 +68,65 @@
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "mozilla/RefPtr.h"
#ifdef __cplusplus
namespace mozilla {
template<typename T>
class LinkedListElement;
namespace detail {
/**
* LinkedList supports refcounted elements using this adapter class. Clients
* using LinkedList<RefPtr<T>> will get a data structure that holds a strong
* reference to T as long as T is in the list.
*/
template<typename T>
struct LinkedListElementTraits
{
typedef T* RawType;
typedef const T* ConstRawType;
typedef T* ClientType;
typedef const T* ConstClientType;
// These static methods are called when an element is added to or removed from
// a linked list. It can be used to keep track ownership in lists that are
// supposed to own their elements. If elements are transferred from one list
// to another, no enter or exit calls happen since the elements still belong
// to a list.
static void enterList(LinkedListElement<T>* elt) {}
static void exitList(LinkedListElement<T>* elt) {}
};
template<typename T>
struct LinkedListElementTraits<RefPtr<T>>
{
typedef T* RawType;
typedef const T* ConstRawType;
typedef RefPtr<T> ClientType;
typedef RefPtr<const T> ConstClientType;
static void enterList(LinkedListElement<RefPtr<T>>* elt) { elt->asT()->AddRef(); }
static void exitList(LinkedListElement<RefPtr<T>>* elt) { elt->asT()->Release(); }
};
} /* namespace detail */
template<typename T>
class LinkedList;
template<typename T>
class LinkedListElement
{
typedef typename detail::LinkedListElementTraits<T> Traits;
typedef typename Traits::RawType RawType;
typedef typename Traits::ConstRawType ConstRawType;
typedef typename Traits::ClientType ClientType;
typedef typename Traits::ConstClientType ConstClientType;
/*
* It's convenient that we return nullptr when getNext() or getPrevious()
* hits the end of the list, but doing so costs an extra word of storage in
@ -155,21 +203,21 @@ public:
* Get the next element in the list, or nullptr if this is the last element
* in the list.
*/
T* getNext() { return mNext->asT(); }
const T* getNext() const { return mNext->asT(); }
RawType getNext() { return mNext->asT(); }
ConstRawType getNext() const { return mNext->asT(); }
/*
* Get the previous element in the list, or nullptr if this is the first
* element in the list.
*/
T* getPrevious() { return mPrev->asT(); }
const T* getPrevious() const { return mPrev->asT(); }
RawType getPrevious() { return mPrev->asT(); }
ConstRawType getPrevious() const { return mPrev->asT(); }
/*
* Insert aElem after this element in the list. |this| must be part of a
* linked list when you call setNext(); otherwise, this method will assert.
*/
void setNext(T* aElem)
void setNext(RawType aElem)
{
MOZ_ASSERT(isInList());
setNextUnsafe(aElem);
@ -180,7 +228,7 @@ public:
* linked list when you call setPrevious(); otherwise, this method will
* assert.
*/
void setPrevious(T* aElem)
void setPrevious(RawType aElem)
{
MOZ_ASSERT(isInList());
setPreviousUnsafe(aElem);
@ -198,6 +246,32 @@ public:
mNext->mPrev = mPrev;
mNext = this;
mPrev = this;
Traits::exitList(this);
}
/*
* Remove this element from the list containing it. Returns a pointer to the
* element that follows this element (before it was removed). This method
* asserts if the element does not belong to a list.
*/
ClientType removeAndGetNext()
{
ClientType r = getNext();
remove();
return r;
}
/*
* Remove this element from the list containing it. Returns a pointer to the
* previous element in the containing list (before the removal). This method
* asserts if the element does not belong to a list.
*/
ClientType removeAndGetPrevious()
{
ClientType r = getPrevious();
remove();
return r;
}
/*
@ -221,6 +295,7 @@ public:
private:
friend class LinkedList<T>;
friend struct detail::LinkedListElementTraits<T>;
enum class NodeKind {
Normal,
@ -237,20 +312,20 @@ private:
* Return |this| cast to T* if we're a normal node, or return nullptr if
* we're a sentinel node.
*/
T* asT()
RawType asT()
{
return mIsSentinel ? nullptr : static_cast<T*>(this);
return mIsSentinel ? nullptr : static_cast<RawType>(this);
}
const T* asT() const
ConstRawType asT() const
{
return mIsSentinel ? nullptr : static_cast<const T*>(this);
return mIsSentinel ? nullptr : static_cast<ConstRawType>(this);
}
/*
* Insert aElem after this element, but don't check that this element is in
* the list. This is called by LinkedList::insertFront().
*/
void setNextUnsafe(T* aElem)
void setNextUnsafe(RawType aElem)
{
LinkedListElement *listElem = static_cast<LinkedListElement*>(aElem);
MOZ_ASSERT(!listElem->isInList());
@ -259,13 +334,15 @@ private:
listElem->mPrev = this;
this->mNext->mPrev = listElem;
this->mNext = listElem;
Traits::enterList(aElem);
}
/*
* Insert aElem before this element, but don't check that this element is in
* the list. This is called by LinkedList::insertBack().
*/
void setPreviousUnsafe(T* aElem)
void setPreviousUnsafe(RawType aElem)
{
LinkedListElement<T>* listElem = static_cast<LinkedListElement<T>*>(aElem);
MOZ_ASSERT(!listElem->isInList());
@ -274,6 +351,8 @@ private:
listElem->mPrev = this->mPrev;
this->mPrev->mNext = listElem;
this->mPrev = listElem;
Traits::enterList(aElem);
}
/*
@ -288,6 +367,10 @@ private:
return;
}
if (!mIsSentinel) {
Traits::enterList(this);
}
MOZ_ASSERT(aOther.mNext->mPrev == &aOther);
MOZ_ASSERT(aOther.mPrev->mNext == &aOther);
@ -307,6 +390,10 @@ private:
*/
aOther.mNext = &aOther;
aOther.mPrev = &aOther;
if (!mIsSentinel) {
Traits::exitList(&aOther);
}
}
LinkedListElement& operator=(const LinkedListElement<T>& aOther) = delete;
@ -317,16 +404,22 @@ template<typename T>
class LinkedList
{
private:
typedef typename detail::LinkedListElementTraits<T> Traits;
typedef typename Traits::RawType RawType;
typedef typename Traits::ConstRawType ConstRawType;
typedef typename Traits::ClientType ClientType;
typedef typename Traits::ConstClientType ConstClientType;
LinkedListElement<T> sentinel;
public:
class Iterator {
T* mCurrent;
RawType mCurrent;
public:
explicit Iterator(T* aCurrent) : mCurrent(aCurrent) {}
explicit Iterator(RawType aCurrent) : mCurrent(aCurrent) {}
T* operator *() const {
RawType operator *() const {
return mCurrent;
}
@ -363,7 +456,7 @@ public:
/*
* Add aElem to the front of the list.
*/
void insertFront(T* aElem)
void insertFront(RawType aElem)
{
/* Bypass setNext()'s this->isInList() assertion. */
sentinel.setNextUnsafe(aElem);
@ -372,7 +465,7 @@ public:
/*
* Add aElem to the back of the list.
*/
void insertBack(T* aElem)
void insertBack(RawType aElem)
{
sentinel.setPreviousUnsafe(aElem);
}
@ -380,24 +473,24 @@ public:
/*
* Get the first element of the list, or nullptr if the list is empty.
*/
T* getFirst() { return sentinel.getNext(); }
const T* getFirst() const { return sentinel.getNext(); }
RawType getFirst() { return sentinel.getNext(); }
ConstRawType getFirst() const { return sentinel.getNext(); }
/*
* Get the last element of the list, or nullptr if the list is empty.
*/
T* getLast() { return sentinel.getPrevious(); }
const T* getLast() const { return sentinel.getPrevious(); }
RawType getLast() { return sentinel.getPrevious(); }
ConstRawType getLast() const { return sentinel.getPrevious(); }
/*
* Get and remove the first element of the list. If the list is empty,
* return nullptr.
*/
T* popFirst()
ClientType popFirst()
{
T* ret = sentinel.getNext();
ClientType ret = sentinel.getNext();
if (ret) {
static_cast<LinkedListElement<T>*>(ret)->remove();
static_cast<LinkedListElement<T>*>(RawType(ret))->remove();
}
return ret;
}
@ -406,11 +499,11 @@ public:
* Get and remove the last element of the list. If the list is empty,
* return nullptr.
*/
T* popLast()
ClientType popLast()
{
T* ret = sentinel.getPrevious();
ClientType ret = sentinel.getPrevious();
if (ret) {
static_cast<LinkedListElement<T>*>(ret)->remove();
static_cast<LinkedListElement<T>*>(RawType(ret))->remove();
}
return ret;
}
@ -531,10 +624,10 @@ public:
private:
friend class LinkedListElement<T>;
void assertContains(const T* aValue) const
void assertContains(const RawType aValue) const
{
#ifdef DEBUG
for (const T* elem = getFirst(); elem; elem = elem->getNext()) {
for (ConstRawType elem = getFirst(); elem; elem = elem->getNext()) {
if (elem == aValue) {
return;
}

Просмотреть файл

@ -156,6 +156,24 @@ TestMove()
list3.clear();
}
static void
TestRemoveAndGet()
{
LinkedList<SomeClass> list;
SomeClass one(1), two(2), three(3);
list.insertBack(&one);
list.insertBack(&two);
list.insertBack(&three);
{ unsigned int check[] { 1, 2, 3 }; CheckListValues(list, check); }
MOZ_RELEASE_ASSERT(two.removeAndGetNext() == &three);
{ unsigned int check[] { 1, 3 }; CheckListValues(list, check); }
MOZ_RELEASE_ASSERT(three.removeAndGetPrevious() == &one);
{ unsigned int check[] { 1 }; CheckListValues(list, check); }
}
struct PrivateClass : private LinkedListElement<PrivateClass> {
friend class mozilla::LinkedList<PrivateClass>;
friend class mozilla::LinkedListElement<PrivateClass>;
@ -177,11 +195,74 @@ TestPrivate()
MOZ_RELEASE_ASSERT(count == 2);
}
struct CountedClass : public LinkedListElement<RefPtr<CountedClass>>
{
int mCount;
void AddRef() { mCount++; }
void Release() { mCount--; }
CountedClass() : mCount(0) {}
~CountedClass() { MOZ_RELEASE_ASSERT(mCount == 0); }
};
static void
TestRefPtrList()
{
LinkedList<RefPtr<CountedClass>> list;
CountedClass* elt1 = new CountedClass;
CountedClass* elt2 = new CountedClass;
list.insertBack(elt1);
list.insertBack(elt2);
MOZ_RELEASE_ASSERT(elt1->mCount == 1);
MOZ_RELEASE_ASSERT(elt2->mCount == 1);
for (RefPtr<CountedClass> p : list) {
MOZ_RELEASE_ASSERT(p->mCount == 2);
}
RefPtr<CountedClass> ptr = list.getFirst();
while (ptr) {
MOZ_RELEASE_ASSERT(ptr->mCount == 2);
RefPtr<CountedClass> next = ptr->getNext();
ptr->remove();
ptr = Move(next);
}
ptr = nullptr;
MOZ_RELEASE_ASSERT(elt1->mCount == 0);
MOZ_RELEASE_ASSERT(elt2->mCount == 0);
list.insertBack(elt1);
elt1->setNext(elt2);
MOZ_RELEASE_ASSERT(elt1->mCount == 1);
MOZ_RELEASE_ASSERT(elt2->mCount == 1);
RefPtr<CountedClass> first = list.popFirst();
MOZ_RELEASE_ASSERT(elt1->mCount == 1);
MOZ_RELEASE_ASSERT(elt2->mCount == 1);
RefPtr<CountedClass> second = list.popFirst();
MOZ_RELEASE_ASSERT(elt1->mCount == 1);
MOZ_RELEASE_ASSERT(elt2->mCount == 1);
first = second = nullptr;
delete elt1;
delete elt2;
}
int
main()
{
TestList();
TestPrivate();
TestMove();
TestRemoveAndGet();
TestRefPtrList();
return 0;
}

Просмотреть файл

@ -147,9 +147,9 @@ public final class NotificationClient implements NotificationListener {
.setContentIntent(contentIntent)
.setDeleteIntent(deleteIntent)
.setAutoCancel(true)
.setStyle(new NotificationCompat.InboxStyle()
.addLine(alertText)
.setSummaryText(host));
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(alertText)
.setSummaryText(host));
// Fetch icon.
if (!imageUrl.isEmpty()) {

Просмотреть файл

@ -643,7 +643,8 @@ VerifyCertificate(CERTCertificate* signerCert, void* voidContext, void* pinArg)
return MapSECStatus(SECFailure);
}
Input certDER;
Result rv = certDER.Init(signerCert->derCert.data, signerCert->derCert.len);
mozilla::pkix::Result rv = certDER.Init(signerCert->derCert.data,
signerCert->derCert.len);
if (rv != Success) {
return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(rv));
}
@ -654,7 +655,7 @@ VerifyCertificate(CERTCertificate* signerCert, void* voidContext, void* pinArg)
KeyPurposeId::id_kp_codeSigning,
CertPolicyId::anyPolicy,
nullptr/*stapledOCSPResponse*/);
if (rv == Result::ERROR_EXPIRED_CERTIFICATE) {
if (rv == mozilla::pkix::Result::ERROR_EXPIRED_CERTIFICATE) {
// For code-signing you normally need trusted 3rd-party timestamps to
// handle expiration properly. The signer could always mess with their
// system clock so you can't trust the certificate was un-expired when

Просмотреть файл

@ -16,6 +16,8 @@ namespace mozilla { namespace ct {
using namespace mozilla::pkix;
typedef mozilla::pkix::Result Result;
// Note: length is always specified in bytes.
// Signed Certificate Timestamp (SCT) Version length
static const size_t kVersionLength = 1;

Просмотреть файл

@ -26,6 +26,8 @@ class MultiLogCTVerifier;
namespace mozilla { namespace psm {
typedef mozilla::pkix::Result Result;
// These values correspond to the CERT_CHAIN_KEY_SIZE_STATUS telemetry.
enum class KeySizeStatus {
NeverChecked = 0,

Просмотреть файл

@ -38,6 +38,8 @@ using namespace mozilla::pkix;
namespace mozilla { namespace psm {
typedef mozilla::pkix::Result Result;
static SECStatus
DigestLength(UniquePK11Context& context, uint32_t length)
{

Просмотреть файл

@ -9,6 +9,8 @@
using namespace mozilla;
using namespace mozilla::pkix;
namespace mozilla { namespace psm {
OCSPVerificationTrustDomain::OCSPVerificationTrustDomain(
NSSCertDBTrustDomain& certDBTrustDomain)
: mCertDBTrustDomain(certDBTrustDomain)
@ -122,3 +124,5 @@ OCSPVerificationTrustDomain::DigestBuf(
{
return mCertDBTrustDomain.DigestBuf(item, digestAlg, digestBuf, digestBufLen);
}
} } // namespace mozilla::psm

Просмотреть файл

@ -12,6 +12,8 @@
namespace mozilla { namespace psm {
typedef mozilla::pkix::Result Result;
class OCSPVerificationTrustDomain : public mozilla::pkix::TrustDomain
{
public:

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше