зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to fx-team
This commit is contained in:
Коммит
d54be5b042
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
|
@ -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)
|
|
@ -20,6 +20,7 @@ modules += [
|
|||
'react-redux.js',
|
||||
'react.js',
|
||||
'redux.js',
|
||||
'reselect.js',
|
||||
'seamless-immutable.js',
|
||||
]
|
||||
|
||||
|
|
|
@ -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(<ok, 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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, ®S.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:
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче