summaryrefslogtreecommitdiffstats
path: root/js
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2019-12-22 01:23:56 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2019-12-22 01:26:49 +0100
commit54091ecab46c93c2e1b2c689e9179a980beaabe6 (patch)
tree5cead66d889007e1b06c5dbb8e3d37b2538d0557 /js
parentc1013e9122456b342d65e4eb4c38a7281d8d83d2 (diff)
parent492624a7106ecbc18994b465ca1dd23fa472bf7e (diff)
downloadUXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.tar
UXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.tar.gz
UXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.tar.lz
UXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.tar.xz
UXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.zip
Forward to new tree structure.
Diffstat (limited to 'js')
-rw-r--r--js/moz.configure13
-rw-r--r--js/public/Class.h16
-rw-r--r--js/public/Proxy.h6
-rw-r--r--js/src/Makefile.in11
-rw-r--r--js/src/builtin/AsyncIteration.js7
-rw-r--r--js/src/builtin/IntlTimeZoneData.h2
-rw-r--r--js/src/builtin/Iterator.js41
-rw-r--r--js/src/builtin/Module.js46
-rw-r--r--js/src/builtin/ModuleObject.cpp124
-rw-r--r--js/src/builtin/ModuleObject.h7
-rw-r--r--js/src/builtin/Object.cpp95
-rw-r--r--js/src/builtin/Promise.cpp746
-rw-r--r--js/src/builtin/Promise.h30
-rw-r--r--js/src/builtin/Promise.js69
-rw-r--r--js/src/builtin/ReflectParse.cpp20
-rw-r--r--js/src/builtin/RegExp.cpp34
-rw-r--r--js/src/builtin/RegExp.h2
-rw-r--r--js/src/builtin/RegExp.js140
-rw-r--r--js/src/builtin/SelfHostingDefines.h8
-rw-r--r--js/src/builtin/String.js27
-rw-r--r--js/src/builtin/TestingFunctions.cpp65
-rw-r--r--js/src/builtin/TypedObject.cpp1
-rw-r--r--js/src/ctypes/CTypes.cpp4
-rw-r--r--js/src/ctypes/libffi/src/x86/win32.S28
-rw-r--r--js/src/doc/Debugger/Conventions.md4
-rw-r--r--js/src/frontend/BytecodeCompiler.cpp13
-rw-r--r--js/src/frontend/BytecodeCompiler.h6
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp477
-rw-r--r--js/src/frontend/BytecodeEmitter.h91
-rw-r--r--js/src/frontend/FoldConstants.cpp25
-rw-r--r--js/src/frontend/FullParseHandler.h21
-rw-r--r--js/src/frontend/NameFunctions.cpp21
-rw-r--r--js/src/frontend/ParseNode.cpp28
-rw-r--r--js/src/frontend/ParseNode.h6
-rw-r--r--js/src/frontend/Parser.cpp129
-rw-r--r--js/src/frontend/Parser.h16
-rw-r--r--js/src/frontend/SharedContext.h27
-rw-r--r--js/src/frontend/SyntaxParseHandler.h6
-rw-r--r--js/src/frontend/TokenStream.cpp2
-rw-r--r--js/src/gc/Marking.cpp7
-rw-r--r--js/src/gc/Memory.cpp17
-rw-r--r--js/src/gc/RootMarking.cpp1
-rw-r--r--js/src/irregexp/NativeRegExpMacroAssembler.cpp8
-rw-r--r--js/src/irregexp/NativeRegExpMacroAssembler.h7
-rw-r--r--js/src/irregexp/RegExpAST.cpp8
-rw-r--r--js/src/irregexp/RegExpAST.h33
-rw-r--r--js/src/irregexp/RegExpBytecode.h23
-rw-r--r--js/src/irregexp/RegExpEngine.cpp151
-rw-r--r--js/src/irregexp/RegExpEngine.h31
-rw-r--r--js/src/irregexp/RegExpInterpreter.cpp74
-rw-r--r--js/src/irregexp/RegExpMacroAssembler.cpp17
-rw-r--r--js/src/irregexp/RegExpMacroAssembler.h15
-rw-r--r--js/src/irregexp/RegExpParser.cpp205
-rw-r--r--js/src/irregexp/RegExpParser.h26
-rw-r--r--js/src/jit-test/modules/empty.js1
-rw-r--r--js/src/jit-test/modules/export-circular-nonexisting-binding-1.js4
-rw-r--r--js/src/jit-test/modules/export-circular-nonexisting-binding-2.js1
-rw-r--r--js/src/jit-test/modules/export-star-circular-1.js1
-rw-r--r--js/src/jit-test/modules/export-star-circular-2.js3
-rw-r--r--js/src/jit-test/tests/auto-regress/bug466654.js8
-rw-r--r--js/src/jit-test/tests/auto-regress/bug516897.js6
-rw-r--r--js/src/jit-test/tests/auto-regress/bug537854.js4
-rw-r--r--js/src/jit-test/tests/auto-regress/bug560796.js9
-rw-r--r--js/src/jit-test/tests/auto-regress/bug638735.js1
-rw-r--r--js/src/jit-test/tests/auto-regress/bug639413.js9
-rw-r--r--js/src/jit-test/tests/auto-regress/bug698899.js9
-rw-r--r--js/src/jit-test/tests/auto-regress/bug746397.js10
-rw-r--r--js/src/jit-test/tests/auto-regress/bug769192.js6
-rw-r--r--js/src/jit-test/tests/baseline/bug843444.js8
-rw-r--r--js/src/jit-test/tests/basic/bug1220766.js3
-rw-r--r--js/src/jit-test/tests/basic/bug510437.js13
-rw-r--r--js/src/jit-test/tests/basic/bug605015.js9
-rw-r--r--js/src/jit-test/tests/basic/bug631305.js9
-rw-r--r--js/src/jit-test/tests/basic/bug662562.js6
-rw-r--r--js/src/jit-test/tests/basic/bug690292.js12
-rw-r--r--js/src/jit-test/tests/basic/bug696748.js3
-rw-r--r--js/src/jit-test/tests/basic/bug831846.js3
-rw-r--r--js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js7
-rw-r--r--js/src/jit-test/tests/basic/testBug566556.js9
-rw-r--r--js/src/jit-test/tests/basic/testBug578044.js13
-rw-r--r--js/src/jit-test/tests/basic/testBug584650.js9
-rw-r--r--js/src/jit-test/tests/basic/testBug780288-1.js20
-rw-r--r--js/src/jit-test/tests/basic/testBug780288-2.js20
-rw-r--r--js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js3
-rw-r--r--js/src/jit-test/tests/basic/testNonStubGetter.js7
-rw-r--r--js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js7
-rw-r--r--js/src/jit-test/tests/basic/testTrueShiftTrue.js16
-rw-r--r--js/src/jit-test/tests/basic/testWatchRecursion.js63
-rw-r--r--js/src/jit-test/tests/ctypes/function-definition.js2
-rw-r--r--js/src/jit-test/tests/debug/onExceptionUnwind-resumption-async.js99
-rw-r--r--js/src/jit-test/tests/gc/bug-900405.js3
-rw-r--r--js/src/jit-test/tests/gc/bug-913261.js5
-rw-r--r--js/src/jit-test/tests/gc/bug-986864.js8
-rw-r--r--js/src/jit-test/tests/ion/bug1063182.js8
-rw-r--r--js/src/jit-test/tests/ion/bug772901.js2
-rw-r--r--js/src/jit-test/tests/ion/bug774257-1.js8
-rw-r--r--js/src/jit-test/tests/ion/bug774257-2.js10
-rw-r--r--js/src/jit-test/tests/ion/bug779631.js9
-rw-r--r--js/src/jit-test/tests/ion/bug783590.js1
-rw-r--r--js/src/jit-test/tests/jaeger/bug550665.js8
-rw-r--r--js/src/jit-test/tests/jaeger/bug557063.js7
-rw-r--r--js/src/jit-test/tests/jaeger/bug588338.js1
-rw-r--r--js/src/jit-test/tests/jaeger/bug625438.js10
-rw-r--r--js/src/jit-test/tests/jaeger/bug630366.js7
-rw-r--r--js/src/jit-test/tests/jaeger/recompile/bug641225.js1
-rw-r--r--js/src/jit-test/tests/modules/bug-1320993.js2
-rw-r--r--js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js3
-rw-r--r--js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js4
-rw-r--r--js/src/jit-test/tests/modules/export-star-circular-dependencies.js6
-rw-r--r--js/src/jit-test/tests/modules/import-namespace.js45
-rw-r--r--js/src/jit-test/tests/pic/fuzz1.js4
-rw-r--r--js/src/jit-test/tests/pic/fuzz3.js3
-rw-r--r--js/src/jit-test/tests/pic/watch1.js7
-rw-r--r--js/src/jit-test/tests/pic/watch1a.js17
-rw-r--r--js/src/jit-test/tests/pic/watch2.js8
-rw-r--r--js/src/jit-test/tests/pic/watch2a.js18
-rw-r--r--js/src/jit-test/tests/pic/watch3.js7
-rw-r--r--js/src/jit-test/tests/pic/watch3a.js19
-rw-r--r--js/src/jit-test/tests/pic/watch3b.js20
-rw-r--r--js/src/jit-test/tests/pic/watch4.js9
-rw-r--r--js/src/jit-test/tests/pic/watch5.js27
-rw-r--r--js/src/jit-test/tests/profiler/bug1140643.js14
-rw-r--r--js/src/jit/BaselineCompiler.cpp94
-rw-r--r--js/src/jit/BaselineCompiler.h11
-rw-r--r--js/src/jit/BaselineIC.cpp13
-rw-r--r--js/src/jit/BaselineJIT.cpp6
-rw-r--r--js/src/jit/BaselineJIT.h2
-rw-r--r--js/src/jit/CodeGenerator.cpp23
-rw-r--r--js/src/jit/CodeGenerator.h2
-rw-r--r--js/src/jit/InlinableNatives.h1
-rw-r--r--js/src/jit/Ion.cpp11
-rw-r--r--js/src/jit/IonAnalysis.cpp40
-rw-r--r--js/src/jit/IonAnalysis.h7
-rw-r--r--js/src/jit/IonBuilder.cpp40
-rw-r--r--js/src/jit/IonBuilder.h2
-rw-r--r--js/src/jit/IonCaches.cpp5
-rw-r--r--js/src/jit/Lowering.cpp16
-rw-r--r--js/src/jit/Lowering.h2
-rw-r--r--js/src/jit/MCallOptimize.cpp2
-rw-r--r--js/src/jit/MIR.h30
-rw-r--r--js/src/jit/MOpcodes.h2
-rw-r--r--js/src/jit/VMFunctions.cpp4
-rw-r--r--js/src/jit/arm/MacroAssembler-arm.cpp4
-rw-r--r--js/src/jit/shared/LIR-shared.h26
-rw-r--r--js/src/jit/shared/LOpcodes-shared.h2
-rw-r--r--js/src/js.msg12
-rw-r--r--js/src/jsapi-tests/moz.build6
-rw-r--r--js/src/jsapi.cpp29
-rw-r--r--js/src/jsapi.h8
-rw-r--r--js/src/jscntxt.cpp1
-rw-r--r--js/src/jscompartment.cpp12
-rw-r--r--js/src/jscompartment.h3
-rw-r--r--js/src/jsexn.cpp36
-rw-r--r--js/src/jsexn.h5
-rw-r--r--js/src/jsfriendapi.cpp2
-rw-r--r--js/src/jsfriendapi.h25
-rw-r--r--js/src/jsfun.cpp120
-rw-r--r--js/src/jsfun.h19
-rw-r--r--js/src/jsgc.cpp14
-rw-r--r--js/src/jsiter.cpp87
-rw-r--r--js/src/jsiter.h8
-rw-r--r--js/src/jsnativestack.cpp20
-rw-r--r--js/src/jsobj.cpp72
-rw-r--r--js/src/jsobj.h22
-rw-r--r--js/src/jsobjinlines.h6
-rw-r--r--js/src/jsopcode.h3
-rw-r--r--js/src/jsprototypes.h8
-rw-r--r--js/src/jsscript.cpp42
-rw-r--r--js/src/jsscript.h35
-rw-r--r--js/src/jsstr.cpp1
-rw-r--r--js/src/jsversion.h1
-rw-r--r--js/src/jswatchpoint.cpp246
-rw-r--r--js/src/jswatchpoint.h90
-rw-r--r--js/src/jswrapper.h7
-rw-r--r--js/src/moz.build18
-rw-r--r--js/src/old-configure.in8
-rw-r--r--js/src/proxy/BaseProxyHandler.cpp14
-rw-r--r--js/src/proxy/Proxy.cpp27
-rw-r--r--js/src/proxy/Proxy.h3
-rw-r--r--js/src/proxy/SecurityWrapper.cpp19
-rw-r--r--js/src/shell/OSObject.cpp5
-rw-r--r--js/src/shell/js.cpp25
-rw-r--r--js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js2
-rw-r--r--js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js2
-rw-r--r--js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js2
-rw-r--r--js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js2
-rw-r--r--js/src/tests/ecma_2017/AsyncFunctions/properties.js76
-rw-r--r--js/src/tests/ecma_5/Array/frozen-dense-array.js19
-rw-r--r--js/src/tests/ecma_5/extensions/watch-array-length.js41
-rw-r--r--js/src/tests/ecma_5/extensions/watch-inherited-property.js38
-rw-r--r--js/src/tests/ecma_5/extensions/watch-replaced-setter.js46
-rw-r--r--js/src/tests/ecma_5/extensions/watch-setter-become-setter.js44
-rw-r--r--js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js43
-rw-r--r--js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js56
-rw-r--r--js/src/tests/ecma_6/Generators/properties.js111
-rw-r--r--js/src/tests/ecma_6/Promise/self-resolve.js20
-rw-r--r--js/src/tests/ecma_6/Symbol/well-known.js3
-rw-r--r--js/src/tests/ecma_7/AsyncFunctions/syntax.js3
-rw-r--r--js/src/tests/js1_5/Object/regress-362872-01.js41
-rw-r--r--js/src/tests/js1_5/Object/regress-362872-02.js24
-rw-r--r--js/src/tests/js1_5/Regress/regress-127243.js75
-rw-r--r--js/src/tests/js1_5/Regress/regress-213482.js29
-rw-r--r--js/src/tests/js1_5/Regress/regress-240577.js37
-rw-r--r--js/src/tests/js1_5/Regress/regress-355341.js29
-rw-r--r--js/src/tests/js1_5/Regress/regress-355344.js49
-rw-r--r--js/src/tests/js1_5/Regress/regress-361467.js32
-rw-r--r--js/src/tests/js1_5/Regress/regress-361617.js35
-rw-r--r--js/src/tests/js1_5/Regress/regress-385393-06.js28
-rw-r--r--js/src/tests/js1_5/Regress/regress-506567.js45
-rw-r--r--js/src/tests/js1_5/extensions/regress-303277.js19
-rw-r--r--js/src/tests/js1_5/extensions/regress-355339.js32
-rw-r--r--js/src/tests/js1_5/extensions/regress-361346.js22
-rw-r--r--js/src/tests/js1_5/extensions/regress-361360.js32
-rw-r--r--js/src/tests/js1_5/extensions/regress-361552.js27
-rw-r--r--js/src/tests/js1_5/extensions/regress-361558.js19
-rw-r--r--js/src/tests/js1_5/extensions/regress-361571.js38
-rw-r--r--js/src/tests/js1_5/extensions/regress-361856.js35
-rw-r--r--js/src/tests/js1_5/extensions/regress-361964.js54
-rw-r--r--js/src/tests/js1_5/extensions/regress-385134.js38
-rw-r--r--js/src/tests/js1_5/extensions/regress-385393-09.js18
-rw-r--r--js/src/tests/js1_5/extensions/regress-390597.js42
-rw-r--r--js/src/tests/js1_5/extensions/regress-420612.js21
-rw-r--r--js/src/tests/js1_5/extensions/regress-435345-01.js100
-rw-r--r--js/src/tests/js1_5/extensions/regress-454040.js25
-rw-r--r--js/src/tests/js1_5/extensions/regress-454142.js30
-rw-r--r--js/src/tests/js1_5/extensions/regress-455413.js24
-rw-r--r--js/src/tests/js1_5/extensions/regress-465145.js24
-rwxr-xr-xjs/src/tests/js1_5/extensions/regress-472787.js31
-rw-r--r--js/src/tests/js1_5/extensions/regress-488995.js46
-rw-r--r--js/src/tests/js1_6/Regress/regress-476655.js40
-rw-r--r--js/src/tests/js1_6/extensions/regress-457521.js24
-rw-r--r--js/src/tests/js1_6/extensions/regress-479567.js33
-rw-r--r--js/src/tests/js1_7/extensions/regress-453955.js31
-rw-r--r--js/src/tests/js1_7/extensions/regress-473282.js20
-rw-r--r--js/src/tests/js1_7/regress/regress-385133-01.js37
-rw-r--r--js/src/tests/js1_8/extensions/regress-394709.js51
-rw-r--r--js/src/tests/js1_8/extensions/regress-481989.js19
-rw-r--r--js/src/tests/js1_8_1/extensions/regress-452498-193.js34
-rw-r--r--js/src/tests/js1_8_1/extensions/regress-452498-196.js9
-rw-r--r--js/src/tests/js1_8_1/extensions/regress-520572.js41
-rw-r--r--js/src/tests/js1_8_1/regress/regress-452498-160.js5
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-604781-1.js24
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-604781-2.js13
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-627984-1.js16
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-627984-2.js15
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-627984-3.js14
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-627984-4.js15
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-627984-5.js13
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-627984-6.js15
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-627984-7.js9
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-631723.js10
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-636697.js11
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-637985.js8
-rw-r--r--js/src/tests/js1_8_5/extensions/regress-691746.js11
-rw-r--r--js/src/tests/js1_8_5/extensions/watch-undefined-setter.js19
-rw-r--r--js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js15
-rw-r--r--js/src/tests/js1_8_5/regress/regress-533876.js23
-rw-r--r--js/src/tests/js1_8_5/regress/regress-548276.js10
-rw-r--r--js/src/tests/js1_8_5/regress/regress-584648.js16
-rw-r--r--js/src/tests/js1_8_5/regress/regress-635195.js8
-rw-r--r--js/src/tests/js1_8_5/regress/regress-636394.js10
-rw-r--r--js/src/vm/AsyncFunction.cpp31
-rw-r--r--js/src/vm/AsyncFunction.h3
-rw-r--r--js/src/vm/AsyncIteration.cpp644
-rw-r--r--js/src/vm/AsyncIteration.h256
-rw-r--r--js/src/vm/CommonPropertyNames.h6
-rw-r--r--js/src/vm/Debugger.cpp27
-rw-r--r--js/src/vm/Debugger.h14
-rw-r--r--js/src/vm/EnvironmentObject.cpp26
-rw-r--r--js/src/vm/GeneratorObject.cpp56
-rw-r--r--js/src/vm/GeneratorObject.h60
-rw-r--r--js/src/vm/GlobalObject.cpp92
-rw-r--r--js/src/vm/GlobalObject.h55
-rw-r--r--js/src/vm/Interpreter.cpp32
-rw-r--r--js/src/vm/Interpreter.h3
-rw-r--r--js/src/vm/NativeObject-inl.h8
-rw-r--r--js/src/vm/NativeObject.cpp14
-rw-r--r--js/src/vm/ObjectGroup.cpp2
-rw-r--r--js/src/vm/Opcodes.h34
-rw-r--r--js/src/vm/Probes-inl.h5
-rw-r--r--js/src/vm/RegExpObject.cpp5
-rw-r--r--js/src/vm/RegExpObject.h8
-rw-r--r--js/src/vm/Runtime.cpp1
-rw-r--r--js/src/vm/SelfHosting.cpp167
-rw-r--r--js/src/vm/Shape.h2
-rw-r--r--js/src/vm/Stack-inl.h2
-rw-r--r--js/src/vm/Stack.cpp4
-rw-r--r--js/src/vm/Stack.h3
-rw-r--r--js/src/vm/Time.cpp12
-rw-r--r--js/src/vm/TypeInference.cpp92
-rw-r--r--js/src/vm/TypeInference.h59
-rw-r--r--js/src/wasm/AsmJS.cpp5
-rw-r--r--js/src/wasm/WasmJS.cpp4
-rw-r--r--js/src/wasm/WasmSignalHandlers.cpp9
-rw-r--r--js/xpconnect/src/Sandbox.cpp7
-rw-r--r--js/xpconnect/src/XPCConvert.cpp4
-rw-r--r--js/xpconnect/src/XPCShellImpl.cpp2
-rw-r--r--js/xpconnect/src/XPCWrappedNativeJSOps.cpp2
-rw-r--r--js/xpconnect/src/moz.build2
-rw-r--r--js/xpconnect/tests/chrome/chrome.ini1
-rw-r--r--js/xpconnect/tests/chrome/test_watchpoints.xul75
-rw-r--r--js/xpconnect/tests/chrome/test_xrayToJS.xul6
302 files changed, 4509 insertions, 4714 deletions
diff --git a/js/moz.configure b/js/moz.configure
index eadd0e9ab..33bac0017 100644
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -37,19 +37,6 @@ def js_disable_shell(value):
set_config('JS_DISABLE_SHELL', js_disable_shell)
-# Use SpiderMonkey Promise implementation if it's enabled
-# =======================================================
-js_option('--enable-sm-promise', default=True,
- help='Enable SpiderMonkey promises')
-
-@depends('--enable-sm-promise')
-def sm_promise(value):
- if value:
- return True
-
-set_config('SPIDERMONKEY_PROMISE', sm_promise)
-set_define('SPIDERMONKEY_PROMISE', sm_promise)
-
# SpiderMonkey as a shared library, and how its symbols are exported
# ==================================================================
js_option('--disable-shared-js', default=building_js,
diff --git a/js/public/Class.h b/js/public/Class.h
index 3b5023875..f4fa9ccaf 100644
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -425,12 +425,6 @@ typedef bool
(* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
JS::ObjectOpResult& result);
-typedef bool
-(* WatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
-
-typedef bool
-(* UnwatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
-
class JS_FRIEND_API(ElementAdder)
{
public:
@@ -670,8 +664,6 @@ struct ObjectOps
SetPropertyOp setProperty;
GetOwnPropertyOp getOwnPropertyDescriptor;
DeletePropertyOp deleteProperty;
- WatchOp watch;
- UnwatchOp unwatch;
GetElementsOp getElements;
JSNewEnumerateOp enumerate;
JSFunToStringOp funToString;
@@ -787,7 +779,7 @@ struct JSClass {
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT \
- (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39)
+ (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 45)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \
@@ -822,8 +814,8 @@ struct Class
* Objects of this class aren't native objects. They don't have Shapes that
* describe their properties and layout. Classes using this flag must
* provide their own property behavior, either by being proxy classes (do
- * this) or by overriding all the ObjectOps except getElements, watch and
- * unwatch (don't do this).
+ * this) or by overriding all the ObjectOps except getElements
+ * (don't do this).
*/
static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
@@ -900,8 +892,6 @@ struct Class
const { return oOps ? oOps->getOwnPropertyDescriptor
: nullptr; }
DeletePropertyOp getOpsDeleteProperty() const { return oOps ? oOps->deleteProperty : nullptr; }
- WatchOp getOpsWatch() const { return oOps ? oOps->watch : nullptr; }
- UnwatchOp getOpsUnwatch() const { return oOps ? oOps->unwatch : nullptr; }
GetElementsOp getOpsGetElements() const { return oOps ? oOps->getElements : nullptr; }
JSNewEnumerateOp getOpsEnumerate() const { return oOps ? oOps->enumerate : nullptr; }
JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; }
diff --git a/js/public/Proxy.h b/js/public/Proxy.h
index 5acb91b26..f40772fb0 100644
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -341,12 +341,6 @@ class JS_FRIEND_API(BaseProxyHandler)
virtual bool isCallable(JSObject* obj) const;
virtual bool isConstructor(JSObject* obj) const;
- // These two hooks must be overridden, or not overridden, in tandem -- no
- // overriding just one!
- virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
- JS::HandleObject callable) const;
- virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const;
-
virtual bool getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder* adder) const;
diff --git a/js/src/Makefile.in b/js/src/Makefile.in
index 20678c68c..bc99e62b5 100644
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -138,6 +138,17 @@ distclean::
CFLAGS += $(MOZ_ZLIB_CFLAGS)
+ifeq ($(OS_ARCH),SunOS)
+ifeq ($(TARGET_CPU),sparc)
+
+ifdef GNU_CC
+CFLAGS += -mcpu=v9
+CXXFLAGS += -mcpu=v9
+endif #GNU_CC
+
+endif
+endif
+
$(LIBRARY_NAME).pc: js.pc
cp $^ $@
diff --git a/js/src/builtin/AsyncIteration.js b/js/src/builtin/AsyncIteration.js
new file mode 100644
index 000000000..029c7c0f8
--- /dev/null
+++ b/js/src/builtin/AsyncIteration.js
@@ -0,0 +1,7 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function AsyncIteratorIdentity() {
+ return this;
+}
diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h
index 8f963ffbc..1612f0f6b 100644
--- a/js/src/builtin/IntlTimeZoneData.h
+++ b/js/src/builtin/IntlTimeZoneData.h
@@ -1,5 +1,5 @@
// Generated by make_intl_data.py. DO NOT EDIT.
-// tzdata version = 2019a
+// tzdata version = 2019c
#ifndef builtin_IntlTimeZoneData_h
#define builtin_IntlTimeZoneData_h
diff --git a/js/src/builtin/Iterator.js b/js/src/builtin/Iterator.js
index 735eec7a0..e25b76156 100644
--- a/js/src/builtin/Iterator.js
+++ b/js/src/builtin/Iterator.js
@@ -84,44 +84,3 @@ function LegacyIteratorShim() {
function LegacyGeneratorIteratorShim() {
return NewLegacyIterator(ToObject(this), LegacyGeneratorIterator);
}
-
-// 7.4.8 CreateListIterator()
-function CreateListIterator(array) {
- let iterator = NewListIterator();
- UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, array);
- UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
-
- // 7.4.8.1 ListIterator next()
- // The spec requires that we use a new next function per iterator object.
- let next = function() {
- if (!IsObject(this) || !IsListIterator(this))
- return callFunction(CallListIteratorMethodIfWrapped, this, "ListIteratorNext");
-
- if (ActiveFunction() !== UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_METHOD))
- ThrowTypeError(JSMSG_INCOMPATIBLE_METHOD, "next", "method", ToString(this));
-
- let array = UnsafeGetObjectFromReservedSlot(this, ITERATOR_SLOT_TARGET);
- let index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
-
- if (index >= ToLength(array.length)) {
- UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, 1/0);
- return { value: undefined, done: true };
- }
-
- UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1);
- return { value: array[index], done: false };
- };
-
- UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_METHOD, next);
- iterator.next = next;
-
- iterator[std_iterator] = ListIteratorIdentity;
- return iterator;
-}
-
-function ListIteratorIdentity() {
- if (!IsObject(this) || !IsListIterator(this))
- return callFunction(CallListIteratorMethodIfWrapped, this, "ListIteratorIdentity");
-
- return this;
-}
diff --git a/js/src/builtin/Module.js b/js/src/builtin/Module.js
index 7b70a7fe8..5c3d5e147 100644
--- a/js/src/builtin/Module.js
+++ b/js/src/builtin/Module.js
@@ -65,12 +65,12 @@ function ModuleGetExportedNames(exportStarSet = [])
return exportedNames;
}
-// 15.2.1.16.3 ResolveExport(exportName, resolveSet, exportStarSet)
-function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = [])
+// 15.2.1.16.3 ResolveExport(exportName, resolveSet)
+function ModuleResolveExport(exportName, resolveSet = [])
{
if (!IsObject(this) || !IsModule(this)) {
return callFunction(CallModuleMethodIfWrapped, this, exportName, resolveSet,
- exportStarSet, "ModuleResolveExport");
+ "ModuleResolveExport");
}
// Step 1
@@ -100,38 +100,29 @@ function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = [])
let e = indirectExportEntries[i];
if (exportName === e.exportName) {
let importedModule = CallModuleResolveHook(module, e.moduleRequest,
- MODULE_STATE_INSTANTIATED);
- let indirectResolution = callFunction(importedModule.resolveExport, importedModule,
- e.importName, resolveSet, exportStarSet);
- if (indirectResolution !== null)
- return indirectResolution;
+ MODULE_STATE_PARSED);
+ return callFunction(importedModule.resolveExport, importedModule, e.importName,
+ resolveSet);
}
}
// Step 6
if (exportName === "default") {
// A default export cannot be provided by an export *.
- ThrowSyntaxError(JSMSG_BAD_DEFAULT_EXPORT);
+ return null;
}
// Step 7
- if (callFunction(ArrayIncludes, exportStarSet, module))
- return null;
-
- // Step 8
- _DefineDataProperty(exportStarSet, exportStarSet.length, module);
-
- // Step 9
let starResolution = null;
- // Step 10
+ // Step 8
let starExportEntries = module.starExportEntries;
for (let i = 0; i < starExportEntries.length; i++) {
let e = starExportEntries[i];
let importedModule = CallModuleResolveHook(module, e.moduleRequest,
- MODULE_STATE_INSTANTIATED);
+ MODULE_STATE_PARSED);
let resolution = callFunction(importedModule.resolveExport, importedModule,
- exportName, resolveSet, exportStarSet);
+ exportName, resolveSet);
if (resolution === "ambiguous")
return resolution;
@@ -148,6 +139,7 @@ function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = [])
}
}
+ // Step 9
return starResolution;
}
@@ -213,8 +205,8 @@ function GetModuleEnvironment(module)
function RecordInstantationFailure(module)
{
- // Set the module's environment slot to 'null' to indicate a failed module
- // instantiation.
+ // Set the module's state to 'failed' to indicate a failed module
+ // instantiation and reset the environment slot to 'undefined'.
assert(IsModule(module), "Non-module passed to RecordInstantationFailure");
SetModuleState(module, MODULE_STATE_FAILED);
UnsafeSetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT, undefined);
@@ -275,11 +267,13 @@ function ModuleDeclarationInstantiation()
ThrowSyntaxError(JSMSG_MISSING_IMPORT, imp.importName);
if (resolution === "ambiguous")
ThrowSyntaxError(JSMSG_AMBIGUOUS_IMPORT, imp.importName);
+ if (resolution.module.state < MODULE_STATE_INSTANTIATED)
+ ThrowInternalError(JSMSG_BAD_MODULE_STATE);
CreateImportBinding(env, imp.localName, resolution.module, resolution.bindingName);
}
}
- // Step 16.iv
+ // Step 17.a.iii
InstantiateModuleFunctionDeclarations(module);
} catch (e) {
RecordInstantationFailure(module);
@@ -318,11 +312,3 @@ function ModuleEvaluation()
return EvaluateModule(module);
}
_SetCanonicalName(ModuleEvaluation, "ModuleEvaluation");
-
-function ModuleNamespaceEnumerate()
-{
- if (!IsObject(this) || !IsModuleNamespace(this))
- return callFunction(CallModuleMethodIfWrapped, this, "ModuleNamespaceEnumerate");
-
- return CreateListIterator(ModuleNamespaceExports(this));
-}
diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp
index 798ef46e1..575bab0b0 100644
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -147,7 +147,7 @@ DEFINE_GETTER_FUNCTIONS(ExportEntryObject, moduleRequest, ModuleRequestSlot)
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, importName, ImportNameSlot)
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, localName, LocalNameSlot)
-DEFINE_ATOM_ACCESSOR_METHOD(ExportEntryObject, exportName)
+DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, exportName)
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, moduleRequest)
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, importName)
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, localName)
@@ -289,14 +289,6 @@ ModuleNamespaceObject::create(JSContext* cx, HandleModuleObject module)
if (!object)
return nullptr;
- RootedId funName(cx, INTERNED_STRING_TO_JSID(cx, cx->names().Symbol_iterator_fun));
- RootedFunction enumerateFun(cx);
- enumerateFun = JS::GetSelfHostedFunction(cx, "ModuleNamespaceEnumerate", funName, 0);
- if (!enumerateFun)
- return nullptr;
-
- SetProxyExtra(object, ProxyHandler::EnumerateFunctionSlot, ObjectValue(*enumerateFun));
-
return &object->as<ModuleNamespaceObject>();
}
@@ -338,14 +330,9 @@ ModuleNamespaceObject::addBinding(JSContext* cx, HandleAtom exportedName,
const char ModuleNamespaceObject::ProxyHandler::family = 0;
ModuleNamespaceObject::ProxyHandler::ProxyHandler()
- : BaseProxyHandler(&family, true)
+ : BaseProxyHandler(&family, false)
{}
-JS::Value ModuleNamespaceObject::ProxyHandler::getEnumerateFunction(HandleObject proxy) const
-{
- return GetProxyExtra(proxy, EnumerateFunctionSlot);
-}
-
bool
ModuleNamespaceObject::ProxyHandler::getPrototype(JSContext* cx, HandleObject proxy,
MutableHandleObject protop) const
@@ -358,6 +345,8 @@ bool
ModuleNamespaceObject::ProxyHandler::setPrototype(JSContext* cx, HandleObject proxy,
HandleObject proto, ObjectOpResult& result) const
{
+ if (!proto)
+ return result.succeed();
return result.failCantSetProto();
}
@@ -402,21 +391,12 @@ ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor(JSContext* cx, Han
Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
if (JSID_IS_SYMBOL(id)) {
Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id));
- if (symbol == cx->wellKnownSymbols().iterator) {
- RootedValue enumerateFun(cx, getEnumerateFunction(proxy));
- desc.object().set(proxy);
- desc.setConfigurable(false);
- desc.setEnumerable(false);
- desc.setValue(enumerateFun);
- return true;
- }
-
if (symbol == cx->wellKnownSymbols().toStringTag) {
RootedValue value(cx, StringValue(cx->names().Module));
desc.object().set(proxy);
desc.setWritable(false);
desc.setEnumerable(false);
- desc.setConfigurable(true);
+ desc.setConfigurable(false);
desc.setValue(value);
return true;
}
@@ -458,8 +438,8 @@ ModuleNamespaceObject::ProxyHandler::has(JSContext* cx, HandleObject proxy, Hand
Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
if (JSID_IS_SYMBOL(id)) {
Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id));
- return symbol == cx->wellKnownSymbols().iterator ||
- symbol == cx->wellKnownSymbols().toStringTag;
+ *bp = symbol == cx->wellKnownSymbols().toStringTag;
+ return true;
}
*bp = ns->bindings().has(id);
@@ -473,23 +453,21 @@ ModuleNamespaceObject::ProxyHandler::get(JSContext* cx, HandleObject proxy, Hand
Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
if (JSID_IS_SYMBOL(id)) {
Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id));
- if (symbol == cx->wellKnownSymbols().iterator) {
- vp.set(getEnumerateFunction(proxy));
- return true;
- }
-
if (symbol == cx->wellKnownSymbols().toStringTag) {
vp.setString(cx->names().Module);
return true;
}
- return false;
+ vp.setUndefined();
+ return true;
}
ModuleEnvironmentObject* env;
Shape* shape;
- if (!ns->bindings().lookup(id, &env, &shape))
- return false;
+ if (!ns->bindings().lookup(id, &env, &shape)) {
+ vp.setUndefined();
+ return true;
+ }
RootedValue value(cx, env->getSlot(shape->slot()));
if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) {
@@ -526,7 +504,7 @@ ModuleNamespaceObject::ProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject
Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
RootedObject exports(cx, &ns->exports());
uint32_t count;
- if (!GetLengthProperty(cx, exports, &count) || !props.reserve(props.length() + count))
+ if (!GetLengthProperty(cx, exports, &count) || !props.reserve(props.length() + count + 1))
return false;
Rooted<ValueVector> names(cx, ValueVector(cx));
@@ -536,6 +514,8 @@ ModuleNamespaceObject::ProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject
for (uint32_t i = 0; i < count; i++)
props.infallibleAppend(AtomToId(&names[i].toString()->asAtom()));
+ props.infallibleAppend(SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
+
return true;
}
@@ -1014,7 +994,7 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global)
static const JSFunctionSpec protoFunctions[] = {
JS_SELF_HOSTED_FN("getExportedNames", "ModuleGetExportedNames", 1, 0),
- JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 3, 0),
+ JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 2, 0),
JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleDeclarationInstantiation", 0, 0),
JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluation", 0, 0),
JS_FS_END
@@ -1164,6 +1144,13 @@ ModuleBuilder::processExport(frontend::ParseNode* pn)
bool isDefault = pn->getKind() == PNK_EXPORT_DEFAULT;
ParseNode* kid = isDefault ? pn->pn_left : pn->pn_kid;
+ if (isDefault && pn->pn_right) {
+ // This is an export default containing an expression.
+ RootedAtom localName(cx_, cx_->names().starDefaultStar);
+ RootedAtom exportName(cx_, cx_->names().default_);
+ return appendExportEntry(exportName, localName);
+ }
+
switch (kid->getKind()) {
case PNK_EXPORT_SPEC_LIST:
MOZ_ASSERT(!isDefault);
@@ -1177,53 +1164,46 @@ ModuleBuilder::processExport(frontend::ParseNode* pn)
break;
case PNK_CLASS: {
- const ClassNode& cls = kid->as<ClassNode>();
- MOZ_ASSERT(cls.names());
- RootedAtom localName(cx_, cls.names()->innerBinding()->pn_atom);
- RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
- if (!appendExportEntry(exportName, localName))
- return false;
- break;
+ const ClassNode& cls = kid->as<ClassNode>();
+ MOZ_ASSERT(cls.names());
+ RootedAtom localName(cx_, cls.names()->innerBinding()->pn_atom);
+ RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
+ if (!appendExportEntry(exportName, localName))
+ return false;
+ break;
}
case PNK_VAR:
case PNK_CONST:
case PNK_LET: {
- MOZ_ASSERT(kid->isArity(PN_LIST));
- for (ParseNode* var = kid->pn_head; var; var = var->pn_next) {
- if (var->isKind(PNK_ASSIGN))
- var = var->pn_left;
- MOZ_ASSERT(var->isKind(PNK_NAME));
- RootedAtom localName(cx_, var->pn_atom);
- RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
- if (!appendExportEntry(exportName, localName))
- return false;
- }
- break;
+ MOZ_ASSERT(kid->isArity(PN_LIST));
+ for (ParseNode* var = kid->pn_head; var; var = var->pn_next) {
+ if (var->isKind(PNK_ASSIGN))
+ var = var->pn_left;
+ MOZ_ASSERT(var->isKind(PNK_NAME));
+ RootedAtom localName(cx_, var->pn_atom);
+ RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
+ if (!appendExportEntry(exportName, localName))
+ return false;
+ }
+ break;
}
case PNK_FUNCTION: {
- RootedFunction func(cx_, kid->pn_funbox->function());
- if (!func->isArrow()) {
- RootedAtom localName(cx_, func->explicitName());
- RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
- MOZ_ASSERT_IF(isDefault, localName);
- if (!appendExportEntry(exportName, localName))
- return false;
- break;
- }
- }
-
- MOZ_FALLTHROUGH; // Arrow functions are handled below.
-
- default:
- MOZ_ASSERT(isDefault);
- RootedAtom localName(cx_, cx_->names().starDefaultStar);
- RootedAtom exportName(cx_, cx_->names().default_);
+ RootedFunction func(cx_, kid->pn_funbox->function());
+ MOZ_ASSERT(!func->isArrow());
+ RootedAtom localName(cx_, func->explicitName());
+ RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
+ MOZ_ASSERT_IF(isDefault, localName);
if (!appendExportEntry(exportName, localName))
return false;
break;
+ }
+
+ default:
+ MOZ_CRASH("Unexpected parse node");
}
+
return true;
}
diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h
index e83520ebe..22db762ac 100644
--- a/js/src/builtin/ModuleObject.h
+++ b/js/src/builtin/ModuleObject.h
@@ -142,15 +142,8 @@ class ModuleNamespaceObject : public ProxyObject
private:
struct ProxyHandler : public BaseProxyHandler
{
- enum
- {
- EnumerateFunctionSlot = 0
- };
-
ProxyHandler();
- JS::Value getEnumerateFunction(HandleObject proxy) const;
-
bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override;
bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp
index 56c77f304..bfcc8d20e 100644
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -568,97 +568,6 @@ obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
return true;
}
-#if JS_HAS_OBJ_WATCHPOINT
-
-bool
-js::WatchHandler(JSContext* cx, JSObject* obj_, jsid id_, const JS::Value& old,
- JS::Value* nvp, void* closure)
-{
- RootedObject obj(cx, obj_);
- RootedId id(cx, id_);
-
- /* Avoid recursion on (obj, id) already being watched on cx. */
- AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
- if (resolving.alreadyStarted())
- return true;
-
- FixedInvokeArgs<3> args(cx);
-
- args[0].set(IdToValue(id));
- args[1].set(old);
- args[2].set(*nvp);
-
- RootedValue callable(cx, ObjectValue(*static_cast<JSObject*>(closure)));
- RootedValue thisv(cx, ObjectValue(*obj));
- RootedValue rv(cx);
- if (!Call(cx, callable, thisv, args, &rv))
- return false;
-
- *nvp = rv;
- return true;
-}
-
-static bool
-obj_watch(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
-
- if (!GlobalObject::warnOnceAboutWatch(cx, obj))
- return false;
-
- if (args.length() <= 1) {
- ReportMissingArg(cx, args.calleev(), 1);
- return false;
- }
-
- RootedObject callable(cx, ValueToCallable(cx, args[1], args.length() - 2));
- if (!callable)
- return false;
-
- RootedId propid(cx);
- if (!ValueToId<CanGC>(cx, args[0], &propid))
- return false;
-
- if (!WatchProperty(cx, obj, propid, callable))
- return false;
-
- args.rval().setUndefined();
- return true;
-}
-
-static bool
-obj_unwatch(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
-
- if (!GlobalObject::warnOnceAboutWatch(cx, obj))
- return false;
-
- RootedId id(cx);
- if (args.length() != 0) {
- if (!ValueToId<CanGC>(cx, args[0], &id))
- return false;
- } else {
- id = JSID_VOID;
- }
-
- if (!UnwatchProperty(cx, obj, id))
- return false;
-
- args.rval().setUndefined();
- return true;
-}
-
-#endif /* JS_HAS_OBJ_WATCHPOINT */
-
/* ECMA 15.2.4.5. */
bool
js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp)
@@ -1290,10 +1199,6 @@ static const JSFunctionSpec object_methods[] = {
JS_FN(js_toString_str, obj_toString, 0,0),
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0),
JS_SELF_HOSTED_FN(js_valueOf_str, "Object_valueOf", 0,0),
-#if JS_HAS_OBJ_WATCHPOINT
- JS_FN(js_watch_str, obj_watch, 2,0),
- JS_FN(js_unwatch_str, obj_unwatch, 1,0),
-#endif
JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0),
JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0),
diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp
index ec7845e89..4900a91cb 100644
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -11,11 +11,13 @@
#include "mozilla/TimeStamp.h"
#include "jscntxt.h"
+#include "jsexn.h"
+#include "jsiter.h"
#include "gc/Heap.h"
#include "js/Debug.h"
#include "vm/AsyncFunction.h"
-#include "vm/SelfHosting.h"
+#include "vm/AsyncIteration.h"
#include "jsobjinlines.h"
@@ -31,10 +33,34 @@ MillisecondsSinceStartup()
return (now - mozilla::TimeStamp::ProcessCreation(ignored)).ToMilliseconds();
}
-#define PROMISE_HANDLER_IDENTITY 0
-#define PROMISE_HANDLER_THROWER 1
-#define PROMISE_HANDLER_AWAIT_FULFILLED 2
-#define PROMISE_HANDLER_AWAIT_REJECTED 3
+enum PromiseHandler {
+ PromiseHandlerIdentity = 0,
+ PromiseHandlerThrower,
+
+ // ES 2018 draft 25.5.5.4-5.
+ PromiseHandlerAsyncFunctionAwaitedFulfilled,
+ PromiseHandlerAsyncFunctionAwaitedRejected,
+
+ // Async Iteration proposal 4.1.
+ PromiseHandlerAsyncGeneratorAwaitedFulfilled,
+ PromiseHandlerAsyncGeneratorAwaitedRejected,
+
+ // Async Iteration proposal 11.4.3.5.1-2.
+ PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled,
+ PromiseHandlerAsyncGeneratorResumeNextReturnRejected,
+
+ // Async Iteration proposal 11.4.3.7 steps 8.c-e.
+ PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled,
+ PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected,
+
+ // Async Iteration proposal 11.1.3.2.5.
+ // Async-from-Sync iterator handlers take the resolved value and create new
+ // iterator objects. To do so it needs to forward whether the iterator is
+ // done. In spec, this is achieved via the [[Done]] internal slot. We
+ // enumerate both true and false cases here.
+ PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone,
+ PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone,
+};
enum ResolutionMode {
ResolveMode,
@@ -47,9 +73,8 @@ enum ResolveFunctionSlots {
};
enum RejectFunctionSlots {
- RejectFunctionSlot_Promise = ResolveFunctionSlot_Promise,
+ RejectFunctionSlot_Promise = 0,
RejectFunctionSlot_ResolveFunction,
- RejectFunctionSlot_PromiseAllData = RejectFunctionSlot_ResolveFunction,
};
enum PromiseAllResolveElementFunctionSlots {
@@ -86,7 +111,7 @@ class PromiseAllDataHolder : public NativeObject
static const Class class_;
JSObject* promiseObj() { return &getFixedSlot(PromiseAllDataHolderSlot_Promise).toObject(); }
JSObject* resolveObj() {
- return getFixedSlot(PromiseAllDataHolderSlot_ResolveFunction).toObjectOrNull();
+ return &getFixedSlot(PromiseAllDataHolderSlot_ResolveFunction).toObject();
}
Value valuesArray() { return getFixedSlot(PromiseAllDataHolderSlot_ValuesArray); }
int32_t remainingCount() {
@@ -126,7 +151,7 @@ NewPromiseAllDataHolder(JSContext* cx, HandleObject resultPromise, HandleValue v
dataHolder->setFixedSlot(PromiseAllDataHolderSlot_Promise, ObjectValue(*resultPromise));
dataHolder->setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(1));
dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ValuesArray, valuesArray);
- dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ResolveFunction, ObjectOrNullValue(resolve));
+ dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ResolveFunction, ObjectValue(*resolve));
return dataHolder;
}
@@ -177,13 +202,15 @@ enum ReactionRecordSlots {
ReactionRecordSlot_IncumbentGlobalObject,
ReactionRecordSlot_Flags,
ReactionRecordSlot_HandlerArg,
+ ReactionRecordSlot_Generator,
ReactionRecordSlots,
};
#define REACTION_FLAG_RESOLVED 0x1
#define REACTION_FLAG_FULFILLED 0x2
#define REACTION_FLAG_IGNORE_DEFAULT_RESOLUTION 0x4
-#define REACTION_FLAG_AWAIT 0x8
+#define REACTION_FLAG_ASYNC_FUNCTION 0x8
+#define REACTION_FLAG_ASYNC_GENERATOR 0x10
// ES2016, 25.4.1.2.
class PromiseReactionRecord : public NativeObject
@@ -210,14 +237,30 @@ class PromiseReactionRecord : public NativeObject
flags |= REACTION_FLAG_FULFILLED;
setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
}
- void setIsAwait() {
+ void setIsAsyncFunction() {
int32_t flags = this->flags();
- flags |= REACTION_FLAG_AWAIT;
+ flags |= REACTION_FLAG_ASYNC_FUNCTION;
setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
}
- bool isAwait() {
+ bool isAsyncFunction() {
+ int32_t flags = this->flags();
+ return flags & REACTION_FLAG_ASYNC_FUNCTION;
+ }
+ void setIsAsyncGenerator(Handle<AsyncGeneratorObject*> asyncGenObj) {
int32_t flags = this->flags();
- return flags & REACTION_FLAG_AWAIT;
+ flags |= REACTION_FLAG_ASYNC_GENERATOR;
+ setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
+
+ setFixedSlot(ReactionRecordSlot_Generator, ObjectValue(*asyncGenObj));
+ }
+ bool isAsyncGenerator() {
+ int32_t flags = this->flags();
+ return flags & REACTION_FLAG_ASYNC_GENERATOR;
+ }
+ AsyncGeneratorObject* asyncGenerator() {
+ MOZ_ASSERT(isAsyncGenerator());
+ return &getFixedSlot(ReactionRecordSlot_Generator).toObject()
+ .as<AsyncGeneratorObject>();
}
Value handler() {
MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
@@ -277,12 +320,6 @@ CreateResolvingFunctions(JSContext* cx, HandleValue promise,
if (!reject)
return false;
- // TODO: remove this once all self-hosted promise code is gone.
- // The resolving functions are trusted, so self-hosted code should be able
- // to call them using callFunction instead of callContentFunction.
- resolve->setFlags(resolve->flags() | JSFunction::SELF_HOSTED);
- reject->setFlags(reject->flags() | JSFunction::SELF_HOSTED);
-
resolve->setExtendedSlot(ResolveFunctionSlot_Promise, promise);
resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction, ObjectValue(*reject));
@@ -319,28 +356,27 @@ RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+ // Step 5.
+ // Here, we only remove the Promise reference from the resolution
+ // functions. Actually marking it as fulfilled/rejected happens later.
+ ClearResolutionFunctionSlots(reject);
+
RootedObject promise(cx, &promiseVal.toObject());
// In some cases the Promise reference on the resolution function won't
// have been removed during resolution, so we need to check that here,
// too.
if (promise->is<PromiseObject>() &&
- PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_RESOLVED))
+ promise->as<PromiseObject>().state() != JS::PromiseState::Pending)
{
- args.rval().setUndefined();
return true;
}
- // Step 5.
- // Here, we only remove the Promise reference from the resolution
- // functions. Actually marking it as fulfilled/rejected happens later.
- ClearResolutionFunctionSlots(reject);
-
// Step 6.
- bool result = RejectMaybeWrappedPromise(cx, promise, reasonVal);
- if (result)
- args.rval().setUndefined();
- return result;
+ if (!RejectMaybeWrappedPromise(cx, promise, reasonVal))
+ return false;
+ args.rval().setUndefined();
+ return true;
}
static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj,
@@ -351,16 +387,28 @@ static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(JSContext* cx,
HandleValue thenable,
HandleValue thenVal);
-// ES2016, 25.4.1.3.2, steps 7-13.
+// ES2016, 25.4.1.3.2, steps 6-13.
static MOZ_MUST_USE bool
ResolvePromiseInternal(JSContext* cx, HandleObject promise, HandleValue resolutionVal)
{
- // Step 7.
+ // Step 7 (reordered).
if (!resolutionVal.isObject())
return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
RootedObject resolution(cx, &resolutionVal.toObject());
+ // Step 6.
+ if (resolution == promise) {
+ // Step 6.a.
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF);
+ RootedValue selfResolutionError(cx);
+ MOZ_ALWAYS_TRUE(GetAndClearException(cx, &selfResolutionError));
+
+ // Step 6.b.
+ return RejectMaybeWrappedPromise(cx, promise, selfResolutionError);
+ }
+
// Step 8.
RootedValue thenVal(cx);
bool status = GetProperty(cx, resolution, resolution, cx->names().then, &thenVal);
@@ -398,10 +446,7 @@ ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp)
RootedFunction resolve(cx, &args.callee().as<JSFunction>());
RootedValue resolutionVal(cx, args.get(0));
- // Steps 1-2.
- RootedValue promiseVal(cx, resolve->getExtendedSlot(ResolveFunctionSlot_Promise));
-
- // Steps 3-4.
+ // Steps 3-4 (reordered).
// We use the reference to the reject function as a signal for whether
// the resolve or reject function was already called, at which point
// the references on each of the functions are cleared.
@@ -410,43 +455,28 @@ ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp)
return true;
}
- RootedObject promise(cx, &promiseVal.toObject());
+ // Steps 1-2 (reordered).
+ RootedObject promise(cx, &resolve->getExtendedSlot(ResolveFunctionSlot_Promise).toObject());
+
+ // Step 5.
+ // Here, we only remove the Promise reference from the resolution
+ // functions. Actually marking it as fulfilled/rejected happens later.
+ ClearResolutionFunctionSlots(resolve);
// In some cases the Promise reference on the resolution function won't
// have been removed during resolution, so we need to check that here,
// too.
if (promise->is<PromiseObject>() &&
- PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_RESOLVED))
+ promise->as<PromiseObject>().state() != JS::PromiseState::Pending)
{
- args.rval().setUndefined();
return true;
}
- // Step 5.
- // Here, we only remove the Promise reference from the resolution
- // functions. Actually marking it as fulfilled/rejected happens later.
- ClearResolutionFunctionSlots(resolve);
-
- // Step 6.
- if (resolutionVal == promiseVal) {
- // Step 6.a.
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
- JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF);
- RootedValue selfResolutionError(cx);
- bool status = GetAndClearException(cx, &selfResolutionError);
- MOZ_ASSERT(status);
-
- // Step 6.b.
- status = RejectMaybeWrappedPromise(cx, promise, selfResolutionError);
- if (status)
- args.rval().setUndefined();
- return status;
- }
-
- bool status = ResolvePromiseInternal(cx, promise, resolutionVal);
- if (status)
- args.rval().setUndefined();
- return status;
+ // Steps 6-13.
+ if (!ResolvePromiseInternal(cx, promise, resolutionVal))
+ return false;
+ args.rval().setUndefined();
+ return true;
}
static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
@@ -652,7 +682,7 @@ enum GetCapabilitiesExecutorSlots {
};
static MOZ_MUST_USE PromiseObject*
-CreatePromiseObjectWithDefaultResolution(JSContext* cx)
+CreatePromiseObjectWithoutResolutionFunctions(JSContext* cx)
{
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
if (!promise)
@@ -687,7 +717,7 @@ NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
// in the list passed to all/race, which (potentially) means exposing them
// to content.
if (canOmitResolutionFunctions && IsNativeFunction(cVal, PromiseConstructor)) {
- promise.set(CreatePromiseObjectWithDefaultResolution(cx));
+ promise.set(CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!promise)
return false;
return true;
@@ -795,9 +825,7 @@ RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue re
// interpreter frame active right now. If a thenable job with a
// throwing `then` function got us here, that'll not be the case,
// so we add one by throwing the error from self-hosted code.
- FixedInvokeArgs<1> getErrorArgs(cx);
- getErrorArgs[0].set(Int32Value(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON));
- if (!CallSelfHostedFunction(cx, "GetInternalError", reason, getErrorArgs, &reason))
+ if (!GetInternalError(cx, JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON, &reason))
return false;
}
}
@@ -832,10 +860,10 @@ TriggerPromiseReactions(JSContext* cx, HandleValue reactionsVal, JS::PromiseStat
}
static MOZ_MUST_USE bool
-AwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
- MutableHandleValue rval)
+AsyncFunctionPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
+ MutableHandleValue rval)
{
- MOZ_ASSERT(reaction->isAwait());
+ MOZ_ASSERT(reaction->isAsyncFunction());
RootedValue handlerVal(cx, reaction->handler());
RootedValue argument(cx, reaction->handlerArg());
@@ -843,15 +871,14 @@ AwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
RootedValue generatorVal(cx, resultPromise->getFixedSlot(PromiseSlot_AwaitGenerator));
int32_t handlerNum = int32_t(handlerVal.toNumber());
- MOZ_ASSERT(handlerNum == PROMISE_HANDLER_AWAIT_FULFILLED
- || handlerNum == PROMISE_HANDLER_AWAIT_REJECTED);
// Await's handlers don't return a value, nor throw exception.
// They fail only on OOM.
- if (handlerNum == PROMISE_HANDLER_AWAIT_FULFILLED) {
+ if (handlerNum == PromiseHandlerAsyncFunctionAwaitedFulfilled) {
if (!AsyncFunctionAwaitedFulfilled(cx, resultPromise, generatorVal, argument))
return false;
} else {
+ MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFunctionAwaitedRejected);
if (!AsyncFunctionAwaitedRejected(cx, resultPromise, generatorVal, argument))
return false;
}
@@ -860,6 +887,55 @@ AwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
return true;
}
+static MOZ_MUST_USE bool
+AsyncGeneratorPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
+ MutableHandleValue rval)
+{
+ MOZ_ASSERT(reaction->isAsyncGenerator());
+
+ RootedValue handlerVal(cx, reaction->handler());
+ RootedValue argument(cx, reaction->handlerArg());
+ Rooted<AsyncGeneratorObject*> asyncGenObj(cx, reaction->asyncGenerator());
+
+ int32_t handlerNum = int32_t(handlerVal.toNumber());
+
+ // Await's handlers don't return a value, nor throw exception.
+ // They fail only on OOM.
+ if (handlerNum == PromiseHandlerAsyncGeneratorAwaitedFulfilled) {
+ // 4.1.1.
+ if (!AsyncGeneratorAwaitedFulfilled(cx, asyncGenObj, argument))
+ return false;
+ } else if (handlerNum == PromiseHandlerAsyncGeneratorAwaitedRejected) {
+ // 4.1.2.
+ if (!AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument))
+ return false;
+ } else if (handlerNum == PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled) {
+ asyncGenObj->setCompleted();
+ // 11.4.3.5.1 step 1.
+ if (!AsyncGeneratorResolve(cx, asyncGenObj, argument, true))
+ return false;
+ } else if (handlerNum == PromiseHandlerAsyncGeneratorResumeNextReturnRejected) {
+ asyncGenObj->setCompleted();
+ // 11.4.3.5.2 step 1.
+ if (!AsyncGeneratorReject(cx, asyncGenObj, argument))
+ return false;
+ } else if (handlerNum == PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled) {
+ asyncGenObj->setExecuting();
+ // 11.4.3.7 steps 8.d-e.
+ if (!AsyncGeneratorYieldReturnAwaitedFulfilled(cx, asyncGenObj, argument))
+ return false;
+ } else {
+ MOZ_ASSERT(handlerNum == PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected);
+ asyncGenObj->setExecuting();
+ // 11.4.3.7 step 8.c.
+ if (!AsyncGeneratorYieldReturnAwaitedRejected(cx, asyncGenObj, argument))
+ return false;
+ }
+
+ rval.setUndefined();
+ return true;
+}
+
// ES2016, 25.4.2.1.
/**
* Callback triggering the fulfill/reject reaction for a resolved Promise,
@@ -903,8 +979,10 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
// Steps 1-2.
Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
- if (reaction->isAwait())
- return AwaitPromiseReactionJob(cx, reaction, args.rval());
+ if (reaction->isAsyncFunction())
+ return AsyncFunctionPromiseReactionJob(cx, reaction, args.rval());
+ if (reaction->isAsyncGenerator())
+ return AsyncGeneratorPromiseReactionJob(cx, reaction, args.rval());
// Step 3.
RootedValue handlerVal(cx, reaction->handler());
@@ -919,13 +997,23 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
int32_t handlerNum = int32_t(handlerVal.toNumber());
// Step 4.
- if (handlerNum == PROMISE_HANDLER_IDENTITY) {
+ if (handlerNum == PromiseHandlerIdentity) {
handlerResult = argument;
- } else {
+ } else if (handlerNum == PromiseHandlerThrower) {
// Step 5.
- MOZ_ASSERT(handlerNum == PROMISE_HANDLER_THROWER);
resolutionMode = RejectMode;
handlerResult = argument;
+ } else {
+ MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone ||
+ handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone);
+
+ bool done = handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone;
+ // Async Iteration proposal 11.1.3.2.5 step 1.
+ RootedObject resultObj(cx, CreateIterResultObject(cx, argument, done));
+ if (!resultObj)
+ return false;
+
+ handlerResult = ObjectValue(*resultObj);
}
} else {
// Step 6.
@@ -964,8 +1052,8 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
*
* Usage of the function's extended slots is as follows:
* ThenableJobSlot_Handler: The handler to use as the Promise reaction.
- * This can be PROMISE_HANDLER_IDENTITY,
- * PROMISE_HANDLER_THROWER, or a callable. In the
+ * This can be PromiseHandlerIdentity,
+ * PromiseHandlerThrower, or a callable. In the
* latter case, it's guaranteed to be an object
* from the same compartment as the
* PromiseReactionJob.
@@ -1100,11 +1188,17 @@ GetResolveFunctionFromReject(JSFunction* reject)
{
MOZ_ASSERT(reject->maybeNative() == RejectPromiseFunction);
Value resolveFunVal = reject->getExtendedSlot(RejectFunctionSlot_ResolveFunction);
- if (IsNativeFunction(resolveFunVal, ResolvePromiseFunction))
- return &resolveFunVal.toObject().as<JSFunction>();
+ MOZ_ASSERT(IsNativeFunction(resolveFunVal, ResolvePromiseFunction));
+ return &resolveFunVal.toObject().as<JSFunction>();
+}
- PromiseAllDataHolder* resolveFunObj = &resolveFunVal.toObject().as<PromiseAllDataHolder>();
- return &resolveFunObj->resolveObj()->as<JSFunction>();
+static JSFunction*
+GetRejectFunctionFromResolve(JSFunction* resolve)
+{
+ MOZ_ASSERT(resolve->maybeNative() == ResolvePromiseFunction);
+ Value rejectFunVal = resolve->getExtendedSlot(ResolveFunctionSlot_RejectFunction);
+ MOZ_ASSERT(IsNativeFunction(rejectFunVal, RejectPromiseFunction));
+ return &rejectFunVal.toObject().as<JSFunction>();
}
static JSFunction*
@@ -1140,8 +1234,7 @@ ClearResolutionFunctionSlots(JSFunction* resolutionFun)
JSFunction* reject;
if (resolutionFun->maybeNative() == ResolvePromiseFunction) {
resolve = resolutionFun;
- reject = &resolutionFun->getExtendedSlot(ResolveFunctionSlot_RejectFunction)
- .toObject().as<JSFunction>();
+ reject = GetRejectFunctionFromResolve(resolutionFun);
} else {
resolve = GetResolveFunctionFromReject(resolutionFun);
reject = resolutionFun;
@@ -1367,6 +1460,14 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
return promise;
}
+// ES2016, 25.4.3.1. skipping creation of resolution functions and executor
+// function invocation.
+/* static */ PromiseObject*
+PromiseObject::createSkippingExecutor(JSContext* cx)
+{
+ return CreatePromiseObjectWithoutResolutionFunctions(cx);
+}
+
static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator,
HandleObject C, HandleObject promiseObj,
HandleObject resolve, HandleObject reject,
@@ -1585,7 +1686,6 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res
if (promise->state() != JS::PromiseState::Pending)
return true;
-
if (mode == ResolveMode) {
if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION))
return true;
@@ -1595,7 +1695,6 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res
if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_REJECT_FUNCTION))
return true;
return RejectMaybeWrappedPromise(cx, promiseObj, result);
-
}
// ES2016, 25.4.4.1.1.
@@ -1669,7 +1768,7 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
// Step 6.
RootedValue nextValue(cx);
RootedId indexId(cx);
- RootedValue rejectFunVal(cx, ObjectOrNullValue(reject));
+ RootedValue rejectFunVal(cx, ObjectValue(*reject));
while (true) {
// Steps a-c, e-g.
@@ -1690,11 +1789,8 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
// Steps d.iii-iv.
if (remainingCount == 0) {
- if (resolve) {
- return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode,
- promiseObj);
- }
- return ResolvePromiseInternal(cx, promiseObj, valuesArrayVal);
+ return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode,
+ promiseObj);
}
// We're all set for now!
@@ -1817,13 +1913,8 @@ PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp)
// Step 6 (Adapted to work with PromiseAllDataHolder's layout).
RootedObject resolveAllFun(cx, data->resolveObj());
RootedObject promiseObj(cx, data->promiseObj());
- if (!resolveAllFun) {
- if (!FulfillMaybeWrappedPromise(cx, promiseObj, valuesVal))
- return false;
- } else {
- if (!RunResolutionFunction(cx, resolveAllFun, valuesVal, ResolveMode, promiseObj))
- return false;
- }
+ if (!RunResolutionFunction(cx, resolveAllFun, valuesVal, ResolveMode, promiseObj))
+ return false;
}
// Step 11.
@@ -1904,8 +1995,8 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
RootedValue CVal(cx, ObjectValue(*C));
RootedValue nextValue(cx);
- RootedValue resolveFunVal(cx, ObjectOrNullValue(resolve));
- RootedValue rejectFunVal(cx, ObjectOrNullValue(reject));
+ RootedValue resolveFunVal(cx, ObjectValue(*resolve));
+ RootedValue rejectFunVal(cx, ObjectValue(*reject));
while (true) {
// Steps a-c, e-g.
@@ -2006,6 +2097,13 @@ CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue ar
return promise;
}
+MOZ_MUST_USE JSObject*
+js::PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value)
+{
+ RootedValue C(cx, ObjectValue(*constructor));
+ return CommonStaticResolveRejectImpl(cx, C, value, ResolveMode);
+}
+
/**
* ES2016, 25.4.4.4, Promise.reject.
*/
@@ -2148,12 +2246,12 @@ static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx,
// Some async/await functions are implemented here instead of
// js/src/builtin/AsyncFunction.cpp, to call Promise internal functions.
-// Async Functions proposal 1.1.8 and 1.2.14 step 1.
+// ES 2018 draft 14.6.11 and 14.7.14 step 1.
MOZ_MUST_USE PromiseObject*
js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal)
{
// Step 1.
- Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithDefaultResolution(cx));
+ Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!promise)
return nullptr;
@@ -2162,7 +2260,7 @@ js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal)
return promise;
}
-// Async Functions proposal 2.2 steps 3.f, 3.g.
+// ES 2018 draft 25.5.5.2 steps 3.f, 3.g.
MOZ_MUST_USE bool
js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
{
@@ -2178,7 +2276,7 @@ js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
return true;
}
-// Async Functions proposal 2.2 steps 3.d-e, 3.g.
+// ES 2018 draft 25.5.5.2 steps 3.d-e, 3.g.
MOZ_MUST_USE bool
js::AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
{
@@ -2190,28 +2288,30 @@ js::AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, H
return true;
}
-// Async Functions proposal 2.3 steps 2-8.
-MOZ_MUST_USE bool
-js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
+// Helper function that performs the equivalent steps as
+// Async Iteration proposal 4.1 Await steps 2-3, 6-9 or similar.
+template <typename T>
+static MOZ_MUST_USE bool
+InternalAwait(JSContext* cx, HandleValue value, HandleObject resultPromise,
+ HandleValue onFulfilled, HandleValue onRejected, T extraStep)
{
+ MOZ_ASSERT(onFulfilled.isNumber() || onFulfilled.isObject());
+ MOZ_ASSERT(onRejected.isNumber() || onRejected.isObject());
+
// Step 2.
- Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithDefaultResolution(cx));
+ Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!promise)
return false;
- // Steps 3.
+ // Step 3.
if (!ResolvePromiseInternal(cx, promise, value))
return false;
- // Steps 4-5.
- RootedValue onFulfilled(cx, Int32Value(PROMISE_HANDLER_AWAIT_FULFILLED));
- RootedValue onRejected(cx, Int32Value(PROMISE_HANDLER_AWAIT_REJECTED));
-
RootedObject incumbentGlobal(cx);
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
return false;
- // Steps 6-7.
+ // Steps 7-8.
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
onFulfilled, onRejected,
nullptr, nullptr,
@@ -2219,12 +2319,403 @@ js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, Hand
if (!reaction)
return false;
- reaction->setIsAwait();
+ // Step 6.
+ extraStep(reaction);
- // Step 8.
+ // Step 9.
return PerformPromiseThenWithReaction(cx, promise, reaction);
}
+// ES 2018 draft 25.5.5.3 steps 2-10.
+MOZ_MUST_USE bool
+js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
+{
+ // Steps 4-5.
+ RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitedFulfilled));
+ RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitedRejected));
+
+ // Steps 2-3, 6-10.
+ auto extra = [](Handle<PromiseReactionRecord*> reaction) {
+ reaction->setIsAsyncFunction();
+ };
+ return InternalAwait(cx, value, resultPromise, onFulfilled, onRejected, extra);
+}
+
+// Async Iteration proposal 4.1 Await steps 2-9.
+MOZ_MUST_USE bool
+js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value)
+{
+ // Steps 4-5.
+ RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitedFulfilled));
+ RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitedRejected));
+
+ // Steps 2-3, 6-9.
+ auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
+ reaction->setIsAsyncGenerator(asyncGenObj);
+ };
+ return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
+}
+
+// Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
+// Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
+// Async Iteration proposal 11.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
+bool
+js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind)
+{
+ // Step 1.
+ RootedValue thisVal(cx, args.thisv());
+
+ // Step 2.
+ RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
+ if (!resultPromise)
+ return false;
+
+ // Step 3.
+ if (!thisVal.isObject() || !thisVal.toObject().is<AsyncFromSyncIteratorObject>()) {
+ // Step 3.a.
+ RootedValue badGeneratorError(cx);
+ if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_ITERATOR, &badGeneratorError))
+ return false;
+
+ // Step 3.b.
+ if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
+ return false;
+
+ // Step 3.c.
+ args.rval().setObject(*resultPromise);
+ return true;
+ }
+
+ Rooted<AsyncFromSyncIteratorObject*> asyncIter(
+ cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
+
+ // Step 4.
+ RootedObject iter(cx, asyncIter->iterator());
+
+ RootedValue resultVal(cx);
+ RootedValue func(cx);
+ if (completionKind == CompletionKind::Normal) {
+ // 11.1.3.2.1 steps 5-6 (partially).
+ if (!GetProperty(cx, iter, iter, cx->names().next, &func))
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+ } else if (completionKind == CompletionKind::Return) {
+ // 11.1.3.2.2 steps 5-6.
+ if (!GetProperty(cx, iter, iter, cx->names().return_, &func))
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+
+ // Step 7.
+ if (func.isNullOrUndefined()) {
+ // Step 7.a.
+ RootedObject resultObj(cx, CreateIterResultObject(cx, args.get(0), true));
+ if (!resultObj)
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+
+ RootedValue resultVal(cx, ObjectValue(*resultObj));
+
+ // Step 7.b.
+ if (!ResolvePromiseInternal(cx, resultPromise, resultVal))
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+
+ // Step 7.c.
+ args.rval().setObject(*resultPromise);
+ return true;
+ }
+ } else {
+ // 11.1.3.2.3 steps 5-6.
+ MOZ_ASSERT(completionKind == CompletionKind::Throw);
+ if (!GetProperty(cx, iter, iter, cx->names().throw_, &func))
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+
+ // Step 7.
+ if (func.isNullOrUndefined()) {
+ // Step 7.a.
+ if (!RejectMaybeWrappedPromise(cx, resultPromise, args.get(0)))
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+
+ // Step 7.b.
+ args.rval().setObject(*resultPromise);
+ return true;
+ }
+ }
+
+ // 11.1.3.2.1 steps 5-6 (partially).
+ // 11.1.3.2.2, 11.1.3.2.3 steps 8-9.
+ RootedValue iterVal(cx, ObjectValue(*iter));
+ FixedInvokeArgs<1> args2(cx);
+ args2[0].set(args.get(0));
+ if (!js::Call(cx, func, iterVal, args2, &resultVal))
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+
+ // 11.1.3.2.1 steps 5-6 (partially).
+ // 11.1.3.2.2, 11.1.3.2.3 steps 10.
+ if (!resultVal.isObject()) {
+ CheckIsObjectKind kind;
+ switch (completionKind) {
+ case CompletionKind::Normal:
+ kind = CheckIsObjectKind::IteratorNext;
+ break;
+ case CompletionKind::Throw:
+ kind = CheckIsObjectKind::IteratorThrow;
+ break;
+ case CompletionKind::Return:
+ kind = CheckIsObjectKind::IteratorReturn;
+ break;
+ }
+ MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, kind));
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+ }
+
+ RootedObject resultObj(cx, &resultVal.toObject());
+
+ // Following step numbers are for 11.1.3.2.1.
+ // For 11.1.3.2.2 and 11.1.3.2.3, steps 7-16 corresponds to steps 11-20.
+
+ // Steps 7-8.
+ RootedValue doneVal(cx);
+ if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+ bool done = ToBoolean(doneVal);
+
+ // Steps 9-10.
+ RootedValue value(cx);
+ if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
+ return AbruptRejectPromise(cx, args, resultPromise, nullptr);
+
+ // Steps 13-14.
+ RootedValue onFulfilled(cx, Int32Value(done
+ ? PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone
+ : PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone));
+ RootedValue onRejected(cx, Int32Value(PromiseHandlerThrower));
+
+ // Steps 11-12, 15.
+ auto extra = [](Handle<PromiseReactionRecord*> reaction) {
+ };
+ if (!InternalAwait(cx, value, resultPromise, onFulfilled, onRejected, extra))
+ return false;
+
+ // Step 16.
+ args.rval().setObject(*resultPromise);
+ return true;
+}
+
+static MOZ_MUST_USE bool
+AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
+
+// Async Iteration proposal 11.4.3.3.
+MOZ_MUST_USE bool
+js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value, bool done)
+{
+ // Step 1 (implicit).
+
+ // Steps 2-3.
+ MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
+
+ // Step 4.
+ Rooted<AsyncGeneratorRequest*> request(
+ cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
+ if (!request)
+ return false;
+
+ // Step 5.
+ RootedObject resultPromise(cx, request->promise());
+
+ // Step 6.
+ RootedObject resultObj(cx, CreateIterResultObject(cx, value, done));
+ if (!resultObj)
+ return false;
+
+ RootedValue resultValue(cx, ObjectValue(*resultObj));
+
+ // Step 7.
+ if (!ResolvePromiseInternal(cx, resultPromise, resultValue))
+ return false;
+
+ // Step 8.
+ if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
+ return false;
+
+ // Step 9.
+ return true;
+}
+
+// Async Iteration proposal 11.4.3.4.
+MOZ_MUST_USE bool
+js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue exception)
+{
+ // Step 1 (implicit).
+
+ // Steps 2-3.
+ MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
+
+ // Step 4.
+ Rooted<AsyncGeneratorRequest*> request(
+ cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
+ if (!request)
+ return false;
+
+ // Step 5.
+ RootedObject resultPromise(cx, request->promise());
+
+ // Step 6.
+ if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
+ return false;
+
+ // Step 7.
+ if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
+ return false;
+
+ // Step 8.
+ return true;
+}
+
+// Async Iteration proposal 11.4.3.5.
+static MOZ_MUST_USE bool
+AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+{
+ // Step 1 (implicit).
+
+ // Steps 2-3.
+ MOZ_ASSERT(!asyncGenObj->isExecuting());
+
+ // Step 4.
+ if (asyncGenObj->isAwaitingYieldReturn() || asyncGenObj->isAwaitingReturn())
+ return true;
+
+ // Steps 5-6.
+ if (asyncGenObj->isQueueEmpty())
+ return true;
+
+ // Steps 7-8.
+ Rooted<AsyncGeneratorRequest*> request(
+ cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
+ if (!request)
+ return false;
+
+ // Step 9.
+ CompletionKind completionKind = request->completionKind();
+
+ // Step 10.
+ if (completionKind != CompletionKind::Normal) {
+ // Step 10.a.
+ if (asyncGenObj->isSuspendedStart())
+ asyncGenObj->setCompleted();
+
+ // Step 10.b.
+ if (asyncGenObj->isCompleted()) {
+ RootedValue value(cx, request->completionValue());
+
+ // Step 10.b.i.
+ if (completionKind == CompletionKind::Return) {
+ // Steps 10.b.i.1.
+ asyncGenObj->setAwaitingReturn();
+
+ // Steps 10.b.i.4-6 (reordered).
+ RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled));
+ RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorResumeNextReturnRejected));
+
+ // Steps 10.b.i.2-3, 7-10.
+ auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
+ reaction->setIsAsyncGenerator(asyncGenObj);
+ };
+ return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
+ }
+
+ // Step 10.b.ii.1.
+ MOZ_ASSERT(completionKind == CompletionKind::Throw);
+
+ // Steps 10.b.ii.2-3.
+ return AsyncGeneratorReject(cx, asyncGenObj, value);
+ }
+ } else if (asyncGenObj->isCompleted()) {
+ // Step 11.
+ return AsyncGeneratorResolve(cx, asyncGenObj, UndefinedHandleValue, true);
+ }
+
+ // Step 12.
+ MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
+
+ // Step 16 (reordered).
+ asyncGenObj->setExecuting();
+
+ RootedValue argument(cx, request->completionValue());
+
+ if (completionKind == CompletionKind::Return) {
+ // 11.4.3.7 AsyncGeneratorYield step 8.b-e.
+ // Since we don't have the place that handles return from yield
+ // inside the generator, handle the case here, with extra state
+ // State_AwaitingYieldReturn.
+ asyncGenObj->setAwaitingYieldReturn();
+
+ RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled));
+ RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected));
+
+ auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
+ reaction->setIsAsyncGenerator(asyncGenObj);
+ };
+ return InternalAwait(cx, argument, nullptr, onFulfilled, onRejected, extra);
+ }
+
+ // Steps 13-15, 17-21.
+ return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
+}
+
+// Async Iteration proposal 11.4.3.6.
+MOZ_MUST_USE bool
+js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
+ CompletionKind completionKind, HandleValue completionValue,
+ MutableHandleValue result)
+{
+ // Step 1 (implicit).
+
+ // Step 2.
+ RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
+ if (!resultPromise)
+ return false;
+
+ // Step 3.
+ if (!asyncGenVal.isObject() || !asyncGenVal.toObject().is<AsyncGeneratorObject>()) {
+ // Step 3.a.
+ RootedValue badGeneratorError(cx);
+ if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_GENERATOR, &badGeneratorError))
+ return false;
+
+ // Step 3.b.
+ if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
+ return false;
+
+ // Step 3.c.
+ result.setObject(*resultPromise);
+ return true;
+ }
+
+ Rooted<AsyncGeneratorObject*> asyncGenObj(
+ cx, &asyncGenVal.toObject().as<AsyncGeneratorObject>());
+
+ // Step 5 (reordered).
+ Rooted<AsyncGeneratorRequest*> request(
+ cx, AsyncGeneratorRequest::create(cx, completionKind, completionValue, resultPromise));
+ if (!request)
+ return false;
+
+ // Steps 4, 6.
+ if (!AsyncGeneratorObject::enqueueRequest(cx, asyncGenObj, request))
+ return false;
+
+ // Step 7.
+ if (!asyncGenObj->isExecuting()) {
+ // Step 8.
+ if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
+ return false;
+ }
+
+ // Step 9.
+ result.setObject(*resultPromise);
+ return true;
+}
+
// ES2016, 25.4.5.3.
bool
js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
@@ -2284,12 +2775,12 @@ PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue on
// Step 3.
RootedValue onFulfilled(cx, onFulfilled_);
if (!IsCallable(onFulfilled))
- onFulfilled = Int32Value(PROMISE_HANDLER_IDENTITY);
+ onFulfilled = Int32Value(PromiseHandlerIdentity);
// Step 4.
RootedValue onRejected(cx, onRejected_);
if (!IsCallable(onRejected))
- onRejected = Int32Value(PROMISE_HANDLER_THROWER);
+ onRejected = Int32Value(PromiseHandlerThrower);
RootedObject incumbentGlobal(cx);
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
@@ -2638,6 +3129,9 @@ PromiseObject::resolve(JSContext* cx, Handle<PromiseObject*> promise, HandleValu
if (promise->state() != JS::PromiseState::Pending)
return true;
+ if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION))
+ return ResolvePromiseInternal(cx, promise, resolutionValue);
+
RootedObject resolveFun(cx, GetResolveFunctionFromPromise(promise));
RootedValue funVal(cx, ObjectValue(*resolveFun));
@@ -2661,6 +3155,9 @@ PromiseObject::reject(JSContext* cx, Handle<PromiseObject*> promise, HandleValue
if (promise->state() != JS::PromiseState::Pending)
return true;
+ if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_REJECT_FUNCTION))
+ return RejectMaybeWrappedPromise(cx, promise, rejectionValue);
+
RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction));
MOZ_ASSERT(IsCallable(funVal));
@@ -2739,6 +3236,7 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key)
static const JSFunctionSpec promise_methods[] = {
JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0),
JS_FN("then", Promise_then, 2, 0),
+ JS_SELF_HOSTED_FN("finally", "Promise_finally", 1, 0),
JS_FS_END
};
diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h
index c76dc358c..b04bd0e2a 100644
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -44,6 +44,8 @@ class PromiseObject : public NativeObject
static PromiseObject* create(JSContext* cx, HandleObject executor,
HandleObject proto = nullptr, bool needsWrapping = false);
+ static PromiseObject* createSkippingExecutor(JSContext* cx);
+
static JSObject* unforgeableResolve(JSContext* cx, HandleValue value);
static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
@@ -128,6 +130,14 @@ OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
HandleValue onFulfilled, HandleValue onRejected,
MutableHandleObject dependent, bool createDependent);
+/**
+ * PromiseResolve ( C, x )
+ *
+ * The abstract operation PromiseResolve, given a constructor and a value,
+ * returns a new promise resolved with that value.
+ */
+MOZ_MUST_USE JSObject*
+PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value);
MOZ_MUST_USE PromiseObject*
CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal);
@@ -141,6 +151,26 @@ AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise);
MOZ_MUST_USE bool
AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
+class AsyncGeneratorObject;
+
+MOZ_MUST_USE bool
+AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value);
+
+MOZ_MUST_USE bool
+AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value, bool done);
+
+MOZ_MUST_USE bool
+AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue exception);
+
+MOZ_MUST_USE bool
+AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal, CompletionKind completionKind,
+ HandleValue completionValue, MutableHandleValue result);
+
+bool
+AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind);
+
/**
* A PromiseTask represents a task that can be dispatched to a helper thread
* (via StartPromiseTask), executed (by implementing PromiseTask::execute()),
diff --git a/js/src/builtin/Promise.js b/js/src/builtin/Promise.js
index 704cbab0b..91a1e1f56 100644
--- a/js/src/builtin/Promise.js
+++ b/js/src/builtin/Promise.js
@@ -14,3 +14,72 @@ function Promise_catch(onRejected) {
// Steps 1-2.
return callContentFunction(this.then, this, undefined, onRejected);
}
+
+// Promise.prototype.finally(onFinally)
+// See https://tc39.es/proposal-promise-finally/
+function Promise_finally(onFinally) {
+ // Step 1.
+ var promise = this;
+
+ // Step 2.
+ if (!IsObject(promise))
+ ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Promise", "finally", "value");
+
+ // Step 3.
+ var C = SpeciesConstructor(promise, GetBuiltinConstructor("Promise"));
+
+ // Step 4.
+ assert(IsConstructor(C), "SpeciesConstructor returns a constructor function");
+
+ // Steps 5-6.
+ var thenFinally, catchFinally;
+ if (!IsCallable(onFinally)) {
+ thenFinally = onFinally;
+ catchFinally = onFinally;
+ } else {
+ // ThenFinally Function.
+ // The parentheses prevent the inferring of a function name.
+ (thenFinally) = function(value) {
+ // Steps 1-2 (implicit).
+
+ // Step 3.
+ var result = onFinally();
+
+ // Steps 4-5 (implicit).
+
+ // Step 6.
+ var promise = PromiseResolve(C, result);
+
+ // Step 7.
+ // FIXME: spec issue - "be equivalent to a function that" is not a defined spec term.
+ // https://github.com/tc39/ecma262/issues/933
+
+ // Step 8.
+ return callContentFunction(promise.then, promise, function() { return value; });
+ };
+
+ // CatchFinally Function.
+ // The parentheses prevent the inferring of a function name.
+ (catchFinally) = function(reason) {
+ // Steps 1-2 (implicit).
+
+ // Step 3.
+ var result = onFinally();
+
+ // Steps 4-5 (implicit).
+
+ // Step 6.
+ var promise = PromiseResolve(C, result);
+
+ // Step 7.
+ // FIXME: spec issue - "be equivalent to a function that" is not a defined spec term.
+ // https://github.com/tc39/ecma262/issues/933
+
+ // Step 8.
+ return callContentFunction(promise.then, promise, function() { throw reason; });
+ };
+ }
+
+ // Step 7.
+ return callContentFunction(promise.then, promise, thenFinally, catchFinally);
+}
diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
index 8e8bb2417..22c958d4c 100644
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2800,11 +2800,11 @@ ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
next->pn_kid->isKind(PNK_YIELD) &&
- next->pn_kid->pn_left);
+ next->pn_kid->pn_kid);
RootedValue body(cx);
- return expression(next->pn_kid->pn_left, &body) &&
+ return expression(next->pn_kid->pn_kid, &body) &&
builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
}
@@ -3146,7 +3146,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_YIELD_STAR:
{
- MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
+ MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
RootedValue arg(cx);
return expression(pn->pn_left, &arg) &&
@@ -3155,10 +3155,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_YIELD:
{
- MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
+ MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
RootedValue arg(cx);
- return optExpression(pn->pn_left, &arg) &&
+ return optExpression(pn->pn_kid, &arg) &&
builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
}
@@ -3422,10 +3422,10 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
RootedFunction func(cx, pn->pn_funbox->function());
GeneratorStyle generatorStyle =
- pn->pn_funbox->isGenerator()
- ? (pn->pn_funbox->isLegacyGenerator()
- ? GeneratorStyle::Legacy
- : GeneratorStyle::ES6)
+ pn->pn_funbox->isStarGenerator()
+ ? GeneratorStyle::ES6
+ : pn->pn_funbox->isLegacyGenerator()
+ ? GeneratorStyle::Legacy
: GeneratorStyle::None;
bool isAsync = pn->pn_funbox->isAsync();
@@ -3480,7 +3480,7 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
ParseNode* pnstart = pnbody->pn_head;
// Skip over initial yield in generator.
- if (pnstart && pnstart->isKind(PNK_YIELD)) {
+ if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
pnstart = pnstart->pn_next;
}
diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp
index 7cf20d23c..55e0c8578 100644
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -178,7 +178,7 @@ CheckPatternSyntax(JSContext* cx, HandleAtom pattern, RegExpFlag flags)
CompileOptions options(cx);
frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
return irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), pattern,
- flags & UnicodeFlag);
+ flags & UnicodeFlag, flags & DotAllFlag);
}
enum RegExpSharedUse {
@@ -664,6 +664,29 @@ js::regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp)
return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_multiline_impl>(cx, args);
}
+// ES 2018 dotAll
+MOZ_ALWAYS_INLINE bool
+regexp_dotall_impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+ if (!IsRegExpObject(args.thisv())) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
+ args.rval().setBoolean(reObj->dotall());
+ return true;
+}
+
+bool
+js::regexp_dotall(JSContext* cx, unsigned argc, JS::Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_dotall_impl>(cx, args);
+}
+
// ES 2017 draft rev32 21.2.5.10.
MOZ_ALWAYS_INLINE bool
regexp_source_impl(JSContext* cx, const CallArgs& args)
@@ -759,6 +782,7 @@ const JSPropertySpec js::regexp_properties[] = {
JS_PSG("source", regexp_source, 0),
JS_PSG("sticky", regexp_sticky, 0),
JS_PSG("unicode", regexp_unicode, 0),
+ JS_PSG("dotall", regexp_dotall, 0),
JS_PS_END
};
@@ -771,6 +795,7 @@ const JSFunctionSpec js::regexp_methods[] = {
JS_SELF_HOSTED_FN("exec", "RegExp_prototype_Exec", 1,0),
JS_SELF_HOSTED_FN("test", "RegExpTest" , 1,0),
JS_SELF_HOSTED_SYM_FN(match, "RegExpMatch", 1,0),
+ JS_SELF_HOSTED_SYM_FN(matchAll, "RegExpMatchAll", 1, 0),
JS_SELF_HOSTED_SYM_FN(replace, "RegExpReplace", 2,0),
JS_SELF_HOSTED_SYM_FN(search, "RegExpSearch", 1,0),
JS_SELF_HOSTED_SYM_FN(split, "RegExpSplit", 2,0),
@@ -1642,6 +1667,13 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto)
if (unicodeGetter != regexp_unicode)
return false;
+ JSNative dotAllGetter;
+ if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().dotall), &dotAllGetter))
+ return false;
+
+ if (dotAllGetter != regexp_dotall)
+ return false;
+
// Check if @@match, @@search, and exec are own data properties,
// those values should be tested in selfhosted JS.
bool has = false;
diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h
index 4e0ff6948..f808f5146 100644
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -153,6 +153,8 @@ extern MOZ_MUST_USE bool
regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp);
extern MOZ_MUST_USE bool
regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp);
+extern MOZ_MUST_USE bool
+regexp_dotall(JSContext* cx, unsigned argc, JS::Value* vp);
} /* namespace js */
diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js
index 0b849292c..91212066c 100644
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// ES6 draft rev34 (2015/02/20) 21.2.5.3 get RegExp.prototype.flags
+// Updated for ES2018 /s (dotAll)
function RegExpFlagsGetter() {
// Steps 1-2.
var R = this;
@@ -31,6 +32,10 @@ function RegExpFlagsGetter() {
// Steps 16-18.
if (R.sticky)
result += "y";
+
+ // ES2018
+ if (R.dotall)
+ result += "s";
// Step 19.
return result;
@@ -1026,3 +1031,138 @@ function RegExpSpecies() {
return this;
}
_SetCanonicalName(RegExpSpecies, "get [Symbol.species]");
+
+// String.prototype.matchAll proposal.
+//
+// RegExp.prototype [ @@matchAll ] ( string )
+function RegExpMatchAll(string) {
+ // Step 1.
+ var rx = this;
+
+ // Step 2.
+ if (!IsObject(rx))
+ ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, rx === null ? "null" : typeof rx);
+
+ if (rx.flags === undefined || rx.flags === null)
+ ThrowTypeError(JSMSG_FLAGS_UNDEFINED_OR_NULL);
+
+ // Step 3.
+ var str = ToString(string);
+
+ // Step 4.
+ var C = SpeciesConstructor(rx, GetBuiltinConstructor("RegExp"));
+
+ // Step 5.
+ var flags = ToString(rx.flags);
+
+ // Step 2.b.iii; located here because it needs to check |flags|.
+ if (!callFunction(std_String_includes, flags, "g")) {
+ ThrowTypeError(JSMSG_REQUIRES_GLOBAL_REGEXP, "matchAll");
+ }
+
+ // Step 6.
+ var matcher = new C(rx, flags);
+
+ // Steps 7-8.
+ matcher.lastIndex = ToLength(rx.lastIndex);
+
+ // Steps 9-12.
+ // Note, always global because non-global throws as per
+ // https://github.com/tc39/ecma262/pull/1716
+ var flags = REGEXP_GLOBAL_FLAG |
+ (callFunction(std_String_includes, flags, "u") ? REGEXP_UNICODE_FLAG : 0);
+
+ // Step 13.
+ return CreateRegExpStringIterator(matcher, str, flags);
+}
+
+// String.prototype.matchAll proposal.
+//
+// CreateRegExpStringIterator ( R, S, global, fullUnicode )
+function CreateRegExpStringIterator(regexp, string, flags) {
+ // Step 1.
+ assert(typeof string === "string", "|string| is a string value");
+
+ // Steps 2-3.
+ assert(typeof flags === "number", "|flags| is a number value");
+
+ // Steps 4-9.
+ var iterator = NewRegExpStringIterator();
+ UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_REGEXP_SLOT, regexp);
+ UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_STRING_SLOT, string);
+ UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_FLAGS_SLOT, flags | 0);
+ UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_DONE_SLOT, false);
+
+ // Step 10.
+ return iterator;
+}
+
+// String.prototype.matchAll proposal.
+//
+// %RegExpStringIteratorPrototype%.next ( )
+function RegExpStringIteratorNext() {
+ // Steps 1-3.
+ var obj;
+ if (!IsObject(this) || (obj = GuardToRegExpStringIterator(this)) === null) {
+ return callFunction(CallRegExpStringIteratorMethodIfWrapped, this,
+ "RegExpStringIteratorNext");
+ }
+
+ var result = { value: undefined, done: false };
+
+ // Step 4.
+ var done = UnsafeGetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT);
+ if (done) {
+ result.done = true;
+ return result;
+ }
+
+ // Step 5.
+ var regexp = UnsafeGetObjectFromReservedSlot(obj, REGEXP_STRING_ITERATOR_REGEXP_SLOT);
+
+ // Step 6.
+ var string = UnsafeGetStringFromReservedSlot(obj, REGEXP_STRING_ITERATOR_STRING_SLOT);
+
+ // Steps 7-8.
+ var flags = UnsafeGetInt32FromReservedSlot(obj, REGEXP_STRING_ITERATOR_FLAGS_SLOT);
+ var global = !!(flags & REGEXP_GLOBAL_FLAG);
+ var fullUnicode = !!(flags & REGEXP_UNICODE_FLAG);
+
+ // Step 9.
+ var match = RegExpExec(regexp, string, false);
+
+ // Step 10.
+ if (match === null) {
+ // Step 10.a.
+ UnsafeSetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT, true);
+
+ // Step 10.b.
+ result.done = true;
+ return result;
+ }
+
+ // Step 11.a.
+ if (global) {
+ // Step 11.a.i.
+ var matchStr = ToString(match[0]);
+
+ // Step 11.a.ii.
+ if (matchStr.length === 0) {
+ // Step 11.a.ii.1.
+ var thisIndex = ToLength(regexp.lastIndex);
+
+ // Step 11.a.ii.2.
+ var nextIndex = fullUnicode ? AdvanceStringIndex(string, thisIndex) : thisIndex + 1;
+
+ // Step 11.a.ii.3.
+ regexp.lastIndex = nextIndex;
+ }
+ } else {
+ // Step 11.b.i.
+ UnsafeSetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT, true);
+ }
+
+ // Steps 11.a.iii and 11.b.ii.
+ result.value = match;
+ return result;
+}
diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h
index b57c17269..117ac7ffd 100644
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -71,8 +71,6 @@
// Used for list, i.e. Array and String, iterators.
#define ITERATOR_SLOT_NEXT_INDEX 1
#define ITERATOR_SLOT_ITEM_KIND 2
-// Used for ListIterator.
-#define ITERATOR_SLOT_NEXT_METHOD 2
#define ITEM_KIND_KEY 0
#define ITEM_KIND_VALUE 1
@@ -92,6 +90,12 @@
#define REGEXP_MULTILINE_FLAG 0x04
#define REGEXP_STICKY_FLAG 0x08
#define REGEXP_UNICODE_FLAG 0x10
+#define REGEXP_DOTALL_FLAG 0x20
+
+#define REGEXP_STRING_ITERATOR_REGEXP_SLOT 0
+#define REGEXP_STRING_ITERATOR_STRING_SLOT 1
+#define REGEXP_STRING_ITERATOR_FLAGS_SLOT 2
+#define REGEXP_STRING_ITERATOR_DONE_SLOT 3
#define MODULE_OBJECT_ENVIRONMENT_SLOT 2
diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js
index f830b1aa2..d07ec6127 100644
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -63,6 +63,33 @@ function String_generic_match(thisValue, regexp) {
return callFunction(String_match, thisValue, regexp);
}
+// String.prototype.matchAll proposal.
+//
+// String.prototype.matchAll ( regexp )
+function String_matchAll(regexp) {
+ // Step 1.
+ RequireObjectCoercible(this);
+
+ // Step 2.
+ if (regexp !== undefined && regexp !== null) {
+ // Step 2.a.
+ var matcher = GetMethod(regexp, std_matchAll);
+
+ // Step 2.b.
+ if (matcher !== undefined)
+ return callContentFunction(matcher, regexp, this);
+ }
+
+ // Step 3.
+ var string = ToString(this);
+
+ // Step 4.
+ var rx = RegExpCreate(regexp, "g");
+
+ // Step 5.
+ return callContentFunction(GetMethod(rx, std_matchAll), rx, string);
+}
+
/**
* A helper function implementing the logic for both String.prototype.padStart
* and String.prototype.padEnd as described in ES7 Draft March 29, 2016
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
index 992fe2c97..a9a307da7 100644
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -239,8 +239,11 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp)
value = BooleanValue(true);
if (!JS_SetProperty(cx, info, "intl-api", value))
return false;
-
+#ifdef XP_SOLARIS
+ value = BooleanValue(false);
+#else
value = BooleanValue(true);
+#endif
if (!JS_SetProperty(cx, info, "mapped-array-buffer", value))
return false;
@@ -1325,7 +1328,6 @@ OOMTest(JSContext* cx, unsigned argc, Value* vp)
}
#endif
-#ifdef SPIDERMONKEY_PROMISE
static bool
SettlePromiseNow(JSContext* cx, unsigned argc, Value* vp)
{
@@ -1434,43 +1436,6 @@ RejectPromise(JSContext* cx, unsigned argc, Value* vp)
return result;
}
-#else
-
-static const js::Class FakePromiseClass = {
- "Promise", JSCLASS_IS_ANONYMOUS
-};
-
-static bool
-MakeFakePromise(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- RootedObject obj(cx, NewObjectWithGivenProto(cx, &FakePromiseClass, nullptr));
- if (!obj)
- return false;
-
- JS::dbg::onNewPromise(cx, obj);
- args.rval().setObject(*obj);
- return true;
-}
-
-static bool
-SettleFakePromise(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- if (!args.requireAtLeast(cx, "settleFakePromise", 1))
- return false;
- if (!args[0].isObject() || args[0].toObject().getClass() != &FakePromiseClass) {
- JS_ReportErrorASCII(cx, "first argument must be a (fake) Promise object");
- return false;
- }
-
- RootedObject promise(cx, &args[0].toObject());
- JS::dbg::onPromiseSettled(cx, promise);
- return true;
-}
-#endif // SPIDERMONKEY_PROMISE
-
static unsigned finalizeCount = 0;
static void
@@ -3897,10 +3862,10 @@ ConvertRegExpTreeToObject(JSContext* cx, irregexp::RegExpTree* tree)
return nullptr;
return obj;
}
- if (tree->IsLookahead()) {
- if (!StringProp(cx, obj, "type", "Lookahead"))
+ if (tree->IsLookaround()) {
+ if (!StringProp(cx, obj, "type", "Lookaround"))
return nullptr;
- irregexp::RegExpLookahead* t = tree->AsLookahead();
+ irregexp::RegExpLookaround* t = tree->AsLookaround();
if (!BooleanProp(cx, obj, "is_positive", t->is_positive()))
return nullptr;
if (!TreeProp(cx, obj, "body", t->body()))
@@ -3972,6 +3937,7 @@ ParseRegExp(JSContext* cx, unsigned argc, Value* vp)
flags & MultilineFlag, match_only,
flags & UnicodeFlag, flags & IgnoreCaseFlag,
flags & GlobalFlag, flags & StickyFlag,
+ flags & DotAllFlag,
&data))
{
return false;
@@ -4186,7 +4152,6 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
" This is also disabled when --fuzzing-safe is specified."),
#endif
-#ifdef SPIDERMONKEY_PROMISE
JS_FN_HELP("settlePromiseNow", SettlePromiseNow, 1, 0,
"settlePromiseNow(promise)",
" 'Settle' a 'promise' immediately. This just marks the promise as resolved\n"
@@ -4203,20 +4168,6 @@ JS_FN_HELP("resolvePromise", ResolvePromise, 2, 0,
JS_FN_HELP("rejectPromise", RejectPromise, 2, 0,
"rejectPromise(promise, reason)",
" Reject a Promise by calling the JSAPI function JS::RejectPromise."),
-#else
- JS_FN_HELP("makeFakePromise", MakeFakePromise, 0, 0,
-"makeFakePromise()",
-" Create an object whose [[Class]] name is 'Promise' and call\n"
-" JS::dbg::onNewPromise on it before returning it. It doesn't actually have\n"
-" any of the other behavior associated with promises."),
-
- JS_FN_HELP("settleFakePromise", SettleFakePromise, 1, 0,
-"settleFakePromise(promise)",
-" 'Settle' a 'promise' created by makeFakePromise(). This doesn't have any\n"
-" observable effects outside of firing any onPromiseSettled hooks set on\n"
-" Debugger instances that are observing the given promise's global as a\n"
-" debuggee."),
-#endif // SPIDERMONKEY_PROMISE
JS_FN_HELP("makeFinalizeObserver", MakeFinalizeObserver, 0, 0,
"makeFinalizeObserver()",
diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp
index ff3680774..50bf0b836 100644
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2215,7 +2215,6 @@ const ObjectOps TypedObject::objectOps_ = {
TypedObject::obj_setProperty,
TypedObject::obj_getOwnPropertyDescriptor,
TypedObject::obj_deleteProperty,
- nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
TypedObject::obj_enumerate,
nullptr, /* thisValue */
diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp
index d6adfac2c..aed1114bd 100644
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -20,6 +20,10 @@
#include <float.h>
#endif
+#if defined(XP_SOLARIS)
+#include <ieeefp.h>
+#endif
+
#ifdef HAVE_SSIZE_T
#include <sys/types.h>
#endif
diff --git a/js/src/ctypes/libffi/src/x86/win32.S b/js/src/ctypes/libffi/src/x86/win32.S
index daf0e799c..4f702e8b1 100644
--- a/js/src/ctypes/libffi/src/x86/win32.S
+++ b/js/src/ctypes/libffi/src/x86/win32.S
@@ -1158,8 +1158,24 @@ L_ffi_closure_SYSV_inner$stub:
.byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
.byte 0x8 /* CIE RA Column */
#ifdef __PIC__
- .byte 0x1 /* .uleb128 0x1; Augmentation size */
- .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+# if defined __sun__ && defined __svr4__
+/* 32-bit Solaris 2/x86 uses datarel encoding for PIC. GNU ld before 2.22
+ doesn't correctly sort .eh_frame_hdr with mixed encodings, so match this. */
+# define FDE_ENCODING 0x30 /* datarel */
+# define FDE_ENCODE(X) X@GOTOFF
+# else
+# define FDE_ENCODING 0x1b /* pcrel sdata4 */
+# if defined HAVE_AS_X86_PCREL
+# define FDE_ENCODE(X) X-.
+# else
+# define FDE_ENCODE(X) X@rel
+# endif
+# endif
+#else
+# define FDE_ENCODING 0 /* absolute */
+# define FDE_ENCODE(X) X
+.byte 0x1 /* .uleb128 0x1; Augmentation size */
+.byte FDE_ENCODING
#endif
.byte 0xc /* DW_CFA_def_cfa CFA = r4 + 4 = 4(%esp) */
.byte 0x4 /* .uleb128 0x4 */
@@ -1176,7 +1192,7 @@ L_ffi_closure_SYSV_inner$stub:
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
.long .LFB1-. /* FDE initial location */
#else
- .long .LFB1
+ .long FDE_ENCODE(.LFB1)
#endif
.long .LFE1-.LFB1 /* FDE address range */
#ifdef __PIC__
@@ -1207,7 +1223,7 @@ L_ffi_closure_SYSV_inner$stub:
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
.long .LFB3-. /* FDE initial location */
#else
- .long .LFB3
+ .long FDE_ENCODE(.LFB3)
#endif
.long .LFE3-.LFB3 /* FDE address range */
#ifdef __PIC__
@@ -1240,7 +1256,7 @@ L_ffi_closure_SYSV_inner$stub:
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
.long .LFB4-. /* FDE initial location */
#else
- .long .LFB4
+ .long FDE_ENCODE(.LFB4)
#endif
.long .LFE4-.LFB4 /* FDE address range */
#ifdef __PIC__
@@ -1278,7 +1294,7 @@ L_ffi_closure_SYSV_inner$stub:
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
.long .LFB5-. /* FDE initial location */
#else
- .long .LFB5
+ .long FDE_ENCODE(.LFB5)
#endif
.long .LFE5-.LFB5 /* FDE address range */
#ifdef __PIC__
diff --git a/js/src/doc/Debugger/Conventions.md b/js/src/doc/Debugger/Conventions.md
index e8bd3ee43..5de7bc171 100644
--- a/js/src/doc/Debugger/Conventions.md
+++ b/js/src/doc/Debugger/Conventions.md
@@ -110,8 +110,8 @@ resumption value has one of the following forms:
the `new` expression returns the frame's `this` value. Similarly, if
the function is the constructor for a subclass, then a non-object
value may result in a TypeError.
- If the frame is a generator or async function, then <i>value</i> must
- conform to the iterator protocol: it must be a non-proxy object of the form
+ If the frame is a generator function, then <i>value</i> must conform to the
+ iterator protocol: it must be a non-proxy object of the form
<code>{ done: <i>boolean</i>, value: <i>v</i> }</code>, where
both `done` and `value` are ordinary properties.
diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
index a1abbfeda..ccfe3cd2e 100644
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -727,5 +727,18 @@ frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fu
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
TraceLogger_ParserCompileFunction);
+ return compiler.compileStandaloneFunction(fun, NotGenerator, AsyncFunction, parameterListEnd);
+}
+
+bool
+frontend::CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ Maybe<uint32_t> parameterListEnd)
+{
+ RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+
+ BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
+ TraceLogger_ParserCompileFunction);
return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
}
diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h
index 0bc1ab2ab..029fbe632 100644
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -85,6 +85,12 @@ CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool
+CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ mozilla::Maybe<uint32_t> parameterListEnd);
+
+MOZ_MUST_USE bool
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 309d6c290..f4574b248 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -100,7 +100,7 @@ class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::Nestab
NestableControl(BytecodeEmitter* bce, StatementKind kind)
: Nestable<NestableControl>(&bce->innermostNestableControl),
kind_(kind),
- emitterScope_(bce->innermostEmitterScope)
+ emitterScope_(bce->innermostEmitterScopeNoCheck())
{ }
public:
@@ -389,7 +389,10 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
nextFrameSlot_ = bi.nextFrameSlot();
if (nextFrameSlot_ > bce->maxFixedSlots)
bce->maxFixedSlots = nextFrameSlot_;
- MOZ_ASSERT_IF(bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->isGenerator(),
+ MOZ_ASSERT_IF(bce->sc->isFunctionBox() &&
+ (bce->sc->asFunctionBox()->isStarGenerator() ||
+ bce->sc->asFunctionBox()->isLegacyGenerator() ||
+ bce->sc->asFunctionBox()->isAsync()),
bce->maxFixedSlots == 0);
}
@@ -423,7 +426,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
// enclosing BCE.
if ((*bce)->parent) {
*bce = (*bce)->parent;
- return (*bce)->innermostEmitterScope;
+ return (*bce)->innermostEmitterScopeNoCheck();
}
return nullptr;
@@ -457,7 +460,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
public:
explicit EmitterScope(BytecodeEmitter* bce)
- : Nestable<EmitterScope>(&bce->innermostEmitterScope),
+ : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
nameCache_(bce->cx->frontendCollectionPool()),
hasEnvironment_(false),
environmentChainLength_(0),
@@ -863,7 +866,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
Handle<LexicalScope::Data*> bindings)
{
MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce))
return false;
@@ -932,7 +935,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
bool
BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
MOZ_ASSERT(funbox->namedLambdaBindings());
if (!ensureCache(bce))
@@ -999,7 +1002,7 @@ BytecodeEmitter::EmitterScope::enterComprehensionFor(BytecodeEmitter* bce,
bool
BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce))
return false;
@@ -1032,7 +1035,7 @@ BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
bool
BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
// If there are parameter expressions, there is an extra var scope.
if (!funbox->hasExtraBodyVarScope())
@@ -1123,7 +1126,7 @@ BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, F
MOZ_ASSERT(funbox->hasParameterExprs);
MOZ_ASSERT(funbox->extraVarScopeBindings() ||
funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
// The extra var scope is never popped once it's entered. It replaces the
// function scope as the var emitter scope.
@@ -1209,7 +1212,7 @@ class DynamicBindingIter : public BindingIter
bool
BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this);
@@ -1269,7 +1272,7 @@ BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedCon
bool
BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this);
@@ -1324,7 +1327,7 @@ BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext
bool
BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this);
@@ -1381,7 +1384,7 @@ BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedCon
bool
BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce))
return false;
@@ -1409,7 +1412,7 @@ BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
{
// If we aren't leaving the scope due to a non-local jump (e.g., break),
// we must be the innermost scope.
- MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope);
+ MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
ScopeKind kind = scope(bce)->kind();
switch (kind) {
@@ -1985,6 +1988,8 @@ class MOZ_STACK_CLASS IfThenElseEmitter
class ForOfLoopControl : public LoopControl
{
+ using EmitterScope = BytecodeEmitter::EmitterScope;
+
// The stack depth of the iterator.
int32_t iterDepth_;
@@ -2026,12 +2031,16 @@ class ForOfLoopControl : public LoopControl
bool allowSelfHosted_;
+ IteratorKind iterKind_;
+
public:
- ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted)
+ ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
+ IteratorKind iterKind)
: LoopControl(bce, StatementKind::ForOfLoop),
iterDepth_(iterDepth),
numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
- allowSelfHosted_(allowSelfHosted)
+ allowSelfHosted_(allowSelfHosted),
+ iterKind_(iterKind)
{
}
@@ -2043,7 +2052,7 @@ class ForOfLoopControl : public LoopControl
return false;
MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
- numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldOffsetList.numYields;
+ numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
return true;
}
@@ -2073,8 +2082,8 @@ class ForOfLoopControl : public LoopControl
MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
return false;
- if (!emitIteratorClose(bce, CompletionKind::Throw)) // ITER ... EXCEPTION
- return false;
+ if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Throw))
+ return false; // ITER ... EXCEPTION
if (!ifIteratorIsNotClosed.emitEnd()) // ITER ... EXCEPTION
return false;
@@ -2085,7 +2094,7 @@ class ForOfLoopControl : public LoopControl
// If any yields were emitted, then this for-of loop is inside a star
// generator and must handle the case of Generator.return. Like in
// yield*, it is handled with a finally block.
- uint32_t numYieldsEmitted = bce->yieldOffsetList.numYields;
+ uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
if (!tryCatch_->emitFinally())
return false;
@@ -2097,8 +2106,8 @@ class ForOfLoopControl : public LoopControl
return false;
if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
return false;
- if (!emitIteratorClose(bce, CompletionKind::Normal)) // ITER ... FTYPE FVALUE
- return false;
+ if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Normal))
+ return false; // ITER ... FTYPE FVALUE
if (!ifGeneratorClosing.emitEnd()) // ITER ... FTYPE FVALUE
return false;
}
@@ -2112,16 +2121,27 @@ class ForOfLoopControl : public LoopControl
return true;
}
- bool emitIteratorClose(BytecodeEmitter* bce,
- CompletionKind completionKind = CompletionKind::Normal) {
+ bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
+ CompletionKind completionKind = CompletionKind::Normal) {
+ return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(), completionKind);
+ }
+
+ bool emitIteratorCloseInScope(BytecodeEmitter* bce,
+ EmitterScope& currentScope,
+ CompletionKind completionKind = CompletionKind::Normal) {
ptrdiff_t start = bce->offset();
- if (!bce->emitIteratorClose(completionKind, allowSelfHosted_))
+ if (!bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
+ allowSelfHosted_))
+ {
return false;
+ }
ptrdiff_t end = bce->offset();
return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
}
- bool emitPrepareForNonLocalJump(BytecodeEmitter* bce, bool isTarget) {
+ bool emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
+ EmitterScope& currentScope,
+ bool isTarget) {
// Pop unnecessary values from the stack. Effectively this means
// leaving try-catch block. However, the performing IteratorClose can
// reach the depth for try-catch, and effectively re-enter the
@@ -2138,7 +2158,7 @@ class ForOfLoopControl : public LoopControl
if (!bce->emit1(JSOP_SWAP)) // UNDEF ITER
return false;
- if (!emitIteratorClose(bce)) // UNDEF
+ if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) // UNDEF
return false;
if (isTarget) {
@@ -2181,13 +2201,16 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
bodyScopeIndex(UINT32_MAX),
varEmitterScope(nullptr),
innermostNestableControl(nullptr),
- innermostEmitterScope(nullptr),
+ innermostEmitterScope_(nullptr),
innermostTDZCheckCache(nullptr),
+#ifdef DEBUG
+ unstableEmitterScope(false),
+#endif
constList(cx),
scopeList(cx),
tryNoteList(cx),
scopeNoteList(cx),
- yieldOffsetList(cx),
+ yieldAndAwaitOffsetList(cx),
typesetCount(0),
hasSingletons(false),
hasTryFinally(false),
@@ -2239,13 +2262,13 @@ BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
NameLocation
BytecodeEmitter::lookupName(JSAtom* name)
{
- return innermostEmitterScope->lookup(this, name);
+ return innermostEmitterScope()->lookup(this, name);
}
Maybe<NameLocation>
BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
{
- return innermostEmitterScope->locationBoundInScope(this, name, target);
+ return innermostEmitterScope()->locationBoundInScope(this, name, target);
}
Maybe<NameLocation>
@@ -2706,7 +2729,7 @@ class NonLocalExitControl
: bce_(bce),
savedScopeNoteIndex_(bce->scopeNoteList.length()),
savedDepth_(bce->stackDepth),
- openScopeNoteIndex_(bce->innermostEmitterScope->noteIndex()),
+ openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
kind_(kind)
{ }
@@ -2752,9 +2775,11 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
using NestableControl = BytecodeEmitter::NestableControl;
using EmitterScope = BytecodeEmitter::EmitterScope;
- EmitterScope* es = bce_->innermostEmitterScope;
+ EmitterScope* es = bce_->innermostEmitterScope();
int npops = 0;
+ AutoCheckUnstableEmitterScope cues(bce_);
+
// For 'continue', 'break', and 'return' statements, emit IteratorClose
// bytecode inline. 'continue' statements do not call IteratorClose for
// the loop they are continuing.
@@ -2805,8 +2830,11 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
return false;
ForOfLoopControl& loopinfo = control->as<ForOfLoopControl>();
- if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ false)) // ...
+ if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
+ /* isTarget = */ false))
+ { // ...
return false;
+ }
} else {
npops += 3;
}
@@ -2833,8 +2861,11 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
- if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ true)) // ... UNDEF UNDEF UNDEF
+ if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
+ /* isTarget = */ true))
+ { // ... UNDEF UNDEF UNDEF
return false;
+ }
}
EmitterScope* targetEmitterScope = target ? target->emitterScope() : bce_->varEmitterScope;
@@ -2869,7 +2900,7 @@ BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist, SrcNoteTy
Scope*
BytecodeEmitter::innermostScope() const
{
- return innermostEmitterScope->scope(this);
+ return innermostEmitterScope()->scope(this);
}
bool
@@ -3172,10 +3203,11 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = true;
return true;
+ case PNK_INITIALYIELD:
case PNK_YIELD_STAR:
case PNK_YIELD:
case PNK_AWAIT:
- MOZ_ASSERT(pn->isArity(PN_BINARY));
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
@@ -3528,7 +3560,7 @@ BytecodeEmitter::needsImplicitThis()
return true;
// Otherwise see if the current point is under a 'with'.
- for (EmitterScope* es = innermostEmitterScope; es; es = es->enclosingInFrame()) {
+ for (EmitterScope* es = innermostEmitterScope(); es; es = es->enclosingInFrame()) {
if (es->scope(this)->kind() == ScopeKind::With)
return true;
}
@@ -3718,6 +3750,18 @@ BytecodeEmitter::emitFinishIteratorResult(bool done)
}
bool
+BytecodeEmitter::emitToIteratorResult(bool done)
+{
+ if (!emitPrepareIteratorResult()) // VALUE OBJ
+ return false;
+ if (!emit1(JSOP_SWAP)) // OBJ VALUE
+ return false;
+ if (!emitFinishIteratorResult(done)) // RESULT
+ return false;
+ return true;
+}
+
+bool
BytecodeEmitter::emitGetNameAtLocation(JSAtom* name, const NameLocation& loc, bool callContext)
{
switch (loc.kind()) {
@@ -4783,7 +4827,9 @@ BytecodeEmitter::isRunOnceLambda()
FunctionBox* funbox = sc->asFunctionBox();
return !funbox->argumentsHasLocalBinding() &&
- !funbox->isGenerator() &&
+ !funbox->isStarGenerator() &&
+ !funbox->isLegacyGenerator() &&
+ !funbox->isAsync() &&
!funbox->function()->explicitName();
}
@@ -4793,26 +4839,26 @@ BytecodeEmitter::emitYieldOp(JSOp op)
if (op == JSOP_FINALYIELDRVAL)
return emit1(JSOP_FINALYIELDRVAL);
- MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD);
+ MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT);
ptrdiff_t off;
if (!emitN(op, 3, &off))
return false;
- uint32_t yieldIndex = yieldOffsetList.length();
- if (yieldIndex >= JS_BIT(24)) {
+ uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
+ if (yieldAndAwaitIndex >= JS_BIT(24)) {
reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
return false;
}
if (op == JSOP_YIELD)
- yieldOffsetList.numYields++;
+ yieldAndAwaitOffsetList.numYields++;
else
- yieldOffsetList.numAwaits++;
+ yieldAndAwaitOffsetList.numAwaits++;
- SET_UINT24(code(off), yieldIndex);
+ SET_UINT24(code(off), yieldAndAwaitIndex);
- if (!yieldOffsetList.append(offset()))
+ if (!yieldAndAwaitOffsetList.append(offset()))
return false;
return emit1(JSOP_DEBUGAFTERYIELD);
@@ -5165,7 +5211,7 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
// destructuring declaration needs to initialize the name in
// the function scope. The innermost scope is the var scope,
// and its enclosing scope is the function scope.
- EmitterScope* funScope = innermostEmitterScope->enclosingInFrame();
+ EmitterScope* funScope = innermostEmitterScope()->enclosingInFrame();
NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true))
return false;
@@ -5228,7 +5274,8 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
}
bool
-BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false */)
+BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = IteratorKind::Sync */,
+ bool allowSelfHosted /* = false */)
{
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
".next() iteration is prohibited in self-hosted code because it "
@@ -5242,6 +5289,12 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false
return false;
if (!emitCall(JSOP_CALL, 0, pn)) // ... RESULT
return false;
+
+ if (iterKind == IteratorKind::Async) {
+ if (!emitAwaitInInnermostScope()) // ... RESULT
+ return false;
+ }
+
if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
return false;
checkTypeSet(JSOP_CALL);
@@ -5249,8 +5302,10 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false
}
bool
-BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = CompletionKind::Normal */,
- bool allowSelfHosted /* = false */)
+BytecodeEmitter::emitIteratorCloseInScope(EmitterScope& currentScope,
+ IteratorKind iterKind /* = IteratorKind::Sync */,
+ CompletionKind completionKind /* = CompletionKind::Normal */,
+ bool allowSelfHosted /* = false */)
{
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
".close() on iterators is prohibited in self-hosted code because it "
@@ -5334,6 +5389,18 @@ BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = Completion
return false;
checkTypeSet(JSOP_CALL);
+ if (iterKind == IteratorKind::Async) {
+ if (completionKind != CompletionKind::Throw) {
+ // Await clobbers rval, so save the current rval.
+ if (!emit1(JSOP_GETRVAL)) // ... ... RESULT RVAL
+ return false;
+ if (!emit1(JSOP_SWAP)) // ... ... RVAL RESULT
+ return false;
+ }
+ if (!emitAwaitInScope(currentScope)) // ... ... RVAL? RESULT
+ return false;
+ }
+
if (completionKind == CompletionKind::Throw) {
if (!emit1(JSOP_SWAP)) // ... RET ITER RESULT UNDEF
return false;
@@ -5343,7 +5410,7 @@ BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = Completion
if (!tryCatch->emitCatch()) // ... RET ITER RESULT
return false;
- // Just ignore the exception thrown by call.
+ // Just ignore the exception thrown by call and await.
if (!emit1(JSOP_EXCEPTION)) // ... RET ITER RESULT EXC
return false;
if (!emit1(JSOP_POP)) // ... RET ITER RESULT
@@ -5360,8 +5427,15 @@ BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = Completion
if (!emit1(JSOP_POP)) // ... RESULT
return false;
} else {
- if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ... RESULT
+ if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ... RVAL? RESULT
return false;
+
+ if (iterKind == IteratorKind::Async) {
+ if (!emit1(JSOP_SWAP)) // ... RESULT RVAL
+ return false;
+ if (!emit1(JSOP_SETRVAL)) // ... RESULT
+ return false;
+ }
}
if (!ifReturnMethodIsDefined.emitElse())
@@ -5587,7 +5661,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
// For an empty pattern [], call IteratorClose unconditionally. Nothing
// else needs to be done.
if (!pattern->pn_head)
- return emitIteratorClose(); // ... OBJ
+ return emitIteratorCloseInInnermostScope(); // ... OBJ
// Push an initial FALSE value for DONE.
if (!emit1(JSOP_FALSE)) // ... OBJ ITER FALSE
@@ -5788,7 +5862,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
return false;
if (!ifDone.emitElse()) // ... OBJ ITER
return false;
- if (!emitIteratorClose()) // ... OBJ
+ if (!emitIteratorCloseInInnermostScope()) // ... OBJ
return false;
if (!ifDone.emitEnd())
return false;
@@ -6966,6 +7040,63 @@ BytecodeEmitter::emitIterator()
}
bool
+BytecodeEmitter::emitAsyncIterator()
+{
+ // Convert iterable to iterator.
+ if (!emit1(JSOP_DUP)) // OBJ OBJ
+ return false;
+ if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::asyncIterator))) // OBJ OBJ @@ASYNCITERATOR
+ return false;
+ if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
+ return false;
+
+ IfThenElseEmitter ifAsyncIterIsUndefined(this);
+ if (!emit1(JSOP_DUP)) // OBJ ITERFN ITERFN
+ return false;
+ if (!emit1(JSOP_UNDEFINED)) // OBJ ITERFN ITERFN UNDEF
+ return false;
+ if (!emit1(JSOP_EQ)) // OBJ ITERFN EQ
+ return false;
+ if (!ifAsyncIterIsUndefined.emitIfElse()) // OBJ ITERFN
+ return false;
+
+ if (!emit1(JSOP_POP)) // OBJ
+ return false;
+ if (!emit1(JSOP_DUP)) // OBJ OBJ
+ return false;
+ if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
+ return false;
+ if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
+ return false;
+ if (!emit1(JSOP_SWAP)) // ITERFN OBJ
+ return false;
+ if (!emitCall(JSOP_CALLITER, 0)) // ITER
+ return false;
+ checkTypeSet(JSOP_CALLITER);
+ if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
+ return false;
+
+ if (!emit1(JSOP_TOASYNCITER)) // ITER
+ return false;
+
+ if (!ifAsyncIterIsUndefined.emitElse()) // OBJ ITERFN
+ return false;
+
+ if (!emit1(JSOP_SWAP)) // ITERFN OBJ
+ return false;
+ if (!emitCall(JSOP_CALLITER, 0)) // ITER
+ return false;
+ checkTypeSet(JSOP_CALLITER);
+ if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
+ return false;
+
+ if (!ifAsyncIterIsUndefined.emitEnd()) // ITER
+ return false;
+
+ return true;
+}
+
+bool
BytecodeEmitter::emitSpread(bool allowSelfHosted)
{
LoopControl loopInfo(this, StatementKind::Spread);
@@ -7018,7 +7149,7 @@ BytecodeEmitter::emitSpread(bool allowSelfHosted)
if (!emitDupAt(2)) // ITER ARR I ITER
return false;
- if (!emitIteratorNext(nullptr, allowSelfHosted)) // ITER ARR I RESULT
+ if (!emitIteratorNext(nullptr, IteratorKind::Sync, allowSelfHosted)) // ITER ARR I RESULT
return false;
if (!emit1(JSOP_DUP)) // ITER ARR I RESULT RESULT
return false;
@@ -7118,6 +7249,13 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
MOZ_ASSERT(forOfHead->isKind(PNK_FOROF));
MOZ_ASSERT(forOfHead->isArity(PN_TERNARY));
+ unsigned iflags = forOfLoop->pn_iflags;
+ IteratorKind iterKind = (iflags & JSITER_FORAWAITOF)
+ ? IteratorKind::Async
+ : IteratorKind::Sync;
+ MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox());
+ MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox()->isAsync());
+
ParseNode* forHeadExpr = forOfHead->pn_kid3;
// Certain builtins (e.g. Array.from) are implemented in self-hosting
@@ -7133,8 +7271,13 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
// Evaluate the expression being iterated.
if (!emitTree(forHeadExpr)) // ITERABLE
return false;
- if (!emitIterator()) // ITER
- return false;
+ if (iterKind == IteratorKind::Async) {
+ if (!emitAsyncIterator()) // ITER
+ return false;
+ } else {
+ if (!emitIterator()) // ITER
+ return false;
+ }
int32_t iterDepth = stackDepth;
@@ -7145,7 +7288,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT UNDEF
return false;
- ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter);
+ ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
// Annotate so IonMonkey can find the loop-closing jump.
unsigned noteIndex;
@@ -7170,7 +7313,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
// bindings inducing an environment, recreate the current environment.
DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
MOZ_ASSERT(forOfTarget->isKind(PNK_LET) || forOfTarget->isKind(PNK_CONST));
- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
@@ -7241,7 +7384,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
if (!emitDupAt(1)) // ITER UNDEF ITER
return false;
- if (!emitIteratorNext(forOfHead, allowSelfHostedIter)) // ITER UNDEF RESULT
+ if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter)) // ITER UNDEF RESULT
return false;
if (!emit1(JSOP_SWAP)) // ITER RESULT UNDEF
@@ -7352,7 +7495,7 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte
// it must be the innermost one. If that scope has closed-over
// bindings inducing an environment, recreate the current environment.
MOZ_ASSERT(forInTarget->isKind(PNK_LET) || forInTarget->isKind(PNK_CONST));
- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
@@ -7481,7 +7624,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
// exists for the head, it must be the innermost one. If that scope
// has closed-over bindings inducing an environment, recreate the
// current environment.
- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
@@ -7529,7 +7672,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
// ES 13.7.4.8 step 3.e. The per-iteration freshening.
if (forLoopRequiresFreshening) {
- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
@@ -8061,7 +8204,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
if (funbox->isAsync()) {
MOZ_ASSERT(!needsProto);
- return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow());
+ return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow(),
+ fun->isStarGenerator());
}
if (fun->isArrow()) {
@@ -8116,8 +8260,11 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
MOZ_ASSERT(pn->getOp() == JSOP_NOP);
switchToPrologue();
if (funbox->isAsync()) {
- if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow()))
+ if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow(),
+ fun->isStarGenerator()))
+ {
return false;
+ }
} else {
if (!emitIndex32(JSOP_LAMBDA, index))
return false;
@@ -8133,10 +8280,12 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
// initialize the binding name of the function in the current scope.
bool isAsync = funbox->isAsync();
- auto emitLambda = [index, isAsync](BytecodeEmitter* bce, const NameLocation&, bool) {
+ bool isStarGenerator = funbox->isStarGenerator();
+ auto emitLambda = [index, isAsync, isStarGenerator](BytecodeEmitter* bce,
+ const NameLocation&, bool) {
if (isAsync) {
return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
- /* isArrow = */ false);
+ /* isArrow = */ false, isStarGenerator);
}
return bce->emitIndexOp(JSOP_LAMBDA, index);
};
@@ -8171,7 +8320,8 @@ BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
}
bool
-BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow)
+BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
+ bool isStarGenerator)
{
// needsHomeObject can be true for propertyList for extended class.
// In that case push both unwrapped and wrapped function, in order to
@@ -8203,8 +8353,13 @@ BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isA
if (!emit1(JSOP_DUP))
return false;
}
- if (!emit1(JSOP_TOASYNC))
- return false;
+ if (isStarGenerator) {
+ if (!emit1(JSOP_TOASYNCGEN))
+ return false;
+ } else {
+ if (!emit1(JSOP_TOASYNC))
+ return false;
+ }
return true;
}
@@ -8438,7 +8593,8 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
if (!updateSourceCoordNotes(pn->pn_pos.begin))
return false;
- if (sc->isFunctionBox() && sc->asFunctionBox()->isStarGenerator()) {
+ bool needsIteratorResult = sc->isFunctionBox() && sc->asFunctionBox()->needsIteratorResult();
+ if (needsIteratorResult) {
if (!emitPrepareIteratorResult())
return false;
}
@@ -8447,13 +8603,20 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
if (ParseNode* pn2 = pn->pn_kid) {
if (!emitTree(pn2))
return false;
+
+ bool isAsyncGenerator = sc->asFunctionBox()->isAsync() &&
+ sc->asFunctionBox()->isStarGenerator();
+ if (isAsyncGenerator) {
+ if (!emitAwaitInInnermostScope())
+ return false;
+ }
} else {
/* No explicit return value provided */
if (!emit1(JSOP_UNDEFINED))
return false;
}
- if (sc->isFunctionBox() && sc->asFunctionBox()->isStarGenerator()) {
+ if (needsIteratorResult) {
if (!emitFinishIteratorResult(true))
return false;
}
@@ -8478,11 +8641,11 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
*/
ptrdiff_t top = offset();
- bool isGenerator = sc->isFunctionBox() && sc->asFunctionBox()->isGenerator();
+ bool needsFinalYield = sc->isFunctionBox() && sc->asFunctionBox()->needsFinalYield();
bool isDerivedClassConstructor =
sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
- if (!emit1((isGenerator || isDerivedClassConstructor) ? JSOP_SETRVAL : JSOP_RETURN))
+ if (!emit1((needsFinalYield || isDerivedClassConstructor) ? JSOP_SETRVAL : JSOP_RETURN))
return false;
// Make sure that we emit this before popping the blocks in prepareForNonLocalJump,
@@ -8497,7 +8660,7 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
if (!nle.prepareForNonLocalJumpToOutermost())
return false;
- if (isGenerator) {
+ if (needsFinalYield) {
// We know that .generator is on the function scope, as we just exited
// all nested scopes.
NameLocation loc =
@@ -8520,52 +8683,105 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
}
bool
+BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope& currentScope)
+{
+ NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator, &currentScope);
+ return emitGetNameAtLocation(cx->names().dotGenerator, loc);
+}
+
+bool
+BytecodeEmitter::emitInitialYield(ParseNode* pn)
+{
+ if (!emitTree(pn->pn_kid))
+ return false;
+
+ if (!emitYieldOp(JSOP_INITIALYIELD))
+ return false;
+
+ if (!emit1(JSOP_POP))
+ return false;
+
+ return true;
+}
+
+bool
BytecodeEmitter::emitYield(ParseNode* pn)
{
MOZ_ASSERT(sc->isFunctionBox());
+ MOZ_ASSERT(pn->getOp() == JSOP_YIELD);
- if (pn->getOp() == JSOP_YIELD) {
- if (sc->asFunctionBox()->isStarGenerator()) {
- if (!emitPrepareIteratorResult())
- return false;
- }
- if (pn->pn_left) {
- if (!emitTree(pn->pn_left))
- return false;
- } else {
- if (!emit1(JSOP_UNDEFINED))
- return false;
- }
- if (sc->asFunctionBox()->isStarGenerator()) {
- if (!emitFinishIteratorResult(false))
- return false;
- }
+ bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
+ if (needsIteratorResult) {
+ if (!emitPrepareIteratorResult())
+ return false;
+ }
+ if (pn->pn_kid) {
+ if (!emitTree(pn->pn_kid))
+ return false;
} else {
- MOZ_ASSERT(pn->getOp() == JSOP_INITIALYIELD);
+ if (!emit1(JSOP_UNDEFINED))
+ return false;
}
- if (!emitTree(pn->pn_right))
+ // 11.4.3.7 AsyncGeneratorYield step 5.
+ bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
+ if (isAsyncGenerator) {
+ if (!emitAwaitInInnermostScope()) // RESULT
+ return false;
+ }
+
+ if (needsIteratorResult) {
+ if (!emitFinishIteratorResult(false))
+ return false;
+ }
+
+ if (!emitGetDotGeneratorInInnermostScope())
return false;
- if (!emitYieldOp(pn->getOp()))
+ if (!emitYieldOp(JSOP_YIELD))
return false;
- if (pn->getOp() == JSOP_INITIALYIELD && !emit1(JSOP_POP))
+ return true;
+}
+
+bool
+BytecodeEmitter::emitAwaitInInnermostScope(ParseNode* pn)
+{
+ MOZ_ASSERT(sc->isFunctionBox());
+ MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
+
+ if (!emitTree(pn->pn_kid))
return false;
+ return emitAwaitInInnermostScope();
+}
+bool
+BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope)
+{
+ if (!emitGetDotGeneratorInScope(currentScope))
+ return false;
+ if (!emitYieldOp(JSOP_AWAIT))
+ return false;
return true;
}
bool
-BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
+BytecodeEmitter::emitYieldStar(ParseNode* iter)
{
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(sc->asFunctionBox()->isStarGenerator());
+ bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
+
if (!emitTree(iter)) // ITERABLE
return false;
- if (!emitIterator()) // ITER
- return false;
+ if (isAsyncGenerator) {
+ if (!emitAsyncIterator()) // ITER
+ return false;
+ } else {
+ if (!emitIterator()) // ITER
+ return false;
+ }
// Initial send value is undefined.
if (!emit1(JSOP_UNDEFINED)) // ITER RECEIVED
@@ -8586,8 +8802,14 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
MOZ_ASSERT(this->stackDepth == startDepth);
+ // 11.4.3.7 AsyncGeneratorYield step 5.
+ if (isAsyncGenerator) {
+ if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT
+ return false;
+ }
+
// Load the generator object.
- if (!emitTree(gen)) // ITER RESULT GENOBJ
+ if (!emitGetDotGeneratorInInnermostScope()) // NEXT ITER RESULT GENOBJ
return false;
// Yield RESULT as-is, without re-boxing.
@@ -8623,7 +8845,8 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
//
// If the iterator does not have a "throw" method, it calls IteratorClose
// and then throws a TypeError.
- if (!emitIteratorClose()) // ITER RESULT EXCEPTION
+ IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
+ if (!emitIteratorCloseInInnermostScope(iterKind)) // NEXT ITER RESULT EXCEPTION
return false;
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
return false;
@@ -8639,6 +8862,12 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
if (!emitCall(JSOP_CALL, 1, iter)) // ITER OLDRESULT RESULT
return false;
checkTypeSet(JSOP_CALL);
+
+ if (isAsyncGenerator) {
+ if (!emitAwaitInInnermostScope()) // NEXT ITER OLDRESULT RESULT
+ return false;
+ }
+
if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) // ITER OLDRESULT RESULT
return false;
if (!emit1(JSOP_SWAP)) // ITER RESULT OLDRESULT
@@ -8705,6 +8934,11 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
return false;
checkTypeSet(JSOP_CALL);
+ if (iterKind == IteratorKind::Async) {
+ if (!emitAwaitInInnermostScope()) // ... FTYPE FVALUE RESULT
+ return false;
+ }
+
// Step v.
if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ITER OLDRESULT FTYPE FVALUE RESULT
return false;
@@ -8779,9 +9013,15 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
return false;
if (!emitCall(JSOP_CALL, 1, iter)) // ITER RESULT
return false;
+ checkTypeSet(JSOP_CALL);
+
+ if (isAsyncGenerator) {
+ if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT RESULT
+ return false;
+ }
+
if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ITER RESULT
return false;
- checkTypeSet(JSOP_CALL);
MOZ_ASSERT(this->stackDepth == startDepth);
if (!emitJumpTargetAndPatch(checkResult)) // checkResult:
@@ -10131,7 +10371,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
{
ParseNode* funBody = pn->last();
FunctionBox* funbox = sc->asFunctionBox();
- EmitterScope* funScope = innermostEmitterScope;
+ EmitterScope* funScope = innermostEmitterScope();
bool hasParameterExprs = funbox->hasParameterExprs;
bool hasRest = funbox->hasRest();
@@ -10312,22 +10552,26 @@ BytecodeEmitter::emitFunctionBody(ParseNode* funBody)
if (!emitTree(funBody))
return false;
- if (funbox->isGenerator()) {
+ if (funbox->needsFinalYield()) {
// If we fall off the end of a generator, do a final yield.
- if (funbox->isStarGenerator() && !emitPrepareIteratorResult())
- return false;
+ bool needsIteratorResult = funbox->needsIteratorResult();
+ if (needsIteratorResult) {
+ if (!emitPrepareIteratorResult())
+ return false;
+ }
if (!emit1(JSOP_UNDEFINED))
return false;
- if (sc->asFunctionBox()->isStarGenerator() && !emitFinishIteratorResult(true))
- return false;
+ if (needsIteratorResult) {
+ if (!emitFinishIteratorResult(true))
+ return false;
+ }
if (!emit1(JSOP_SETRVAL))
return false;
- NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
- if (!emitGetNameAtLocation(cx->names().dotGenerator, loc))
+ if (!emitGetDotGeneratorInInnermostScope())
return false;
// No need to check for finally blocks, etc as in EmitReturn.
@@ -10587,7 +10831,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break;
case PNK_YIELD_STAR:
- if (!emitYieldStar(pn->pn_left, pn->pn_right))
+ if (!emitYieldStar(pn->pn_kid))
return false;
break;
@@ -10596,12 +10840,21 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
return false;
break;
+ case PNK_INITIALYIELD:
+ if (!emitInitialYield(pn))
+ return false;
+ break;
+
case PNK_YIELD:
- case PNK_AWAIT:
if (!emitYield(pn))
return false;
break;
+ case PNK_AWAIT:
+ if (!emitAwaitInInnermostScope(pn))
+ return false;
+ break;
+
case PNK_STATEMENTLIST:
if (!emitStatementList(pn))
return false;
@@ -11281,7 +11534,7 @@ CGScopeNoteList::finish(ScopeNoteArray* array, uint32_t prologueLength)
}
void
-CGYieldOffsetList::finish(YieldOffsetArray& array, uint32_t prologueLength)
+CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength)
{
MOZ_ASSERT(length() == array.length());
diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
index 595ee6405..8ad409c11 100644
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -10,6 +10,7 @@
#define frontend_BytecodeEmitter_h
#include "jscntxt.h"
+#include "jsiter.h"
#include "jsopcode.h"
#include "jsscript.h"
@@ -98,15 +99,15 @@ struct CGScopeNoteList {
void finish(ScopeNoteArray* array, uint32_t prologueLength);
};
-struct CGYieldOffsetList {
+struct CGYieldAndAwaitOffsetList {
Vector<uint32_t> list;
uint32_t numYields;
uint32_t numAwaits;
- explicit CGYieldOffsetList(ExclusiveContext* cx) : list(cx), numYields(0), numAwaits(0) {}
+ explicit CGYieldAndAwaitOffsetList(ExclusiveContext* cx) : list(cx), numYields(0), numAwaits(0) {}
MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
size_t length() const { return list.length(); }
- void finish(YieldOffsetArray& array, uint32_t prologueLength);
+ void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength);
};
static size_t MaxBytecodeLength = INT32_MAX;
@@ -227,9 +228,23 @@ struct MOZ_STACK_CLASS BytecodeEmitter
EmitterScope* varEmitterScope;
NestableControl* innermostNestableControl;
- EmitterScope* innermostEmitterScope;
+ EmitterScope* innermostEmitterScope_;
TDZCheckCache* innermostTDZCheckCache;
+#ifdef DEBUG
+ bool unstableEmitterScope;
+
+ friend class AutoCheckUnstableEmitterScope;
+#endif
+
+ EmitterScope* innermostEmitterScope() const {
+ MOZ_ASSERT(!unstableEmitterScope);
+ return innermostEmitterScopeNoCheck();
+ }
+ EmitterScope* innermostEmitterScopeNoCheck() const {
+ return innermostEmitterScope_;
+ }
+
CGConstList constList; /* constants to be included with the script */
CGObjectList objectList; /* list of emitted objects */
CGScopeList scopeList; /* list of emitted scopes */
@@ -237,10 +252,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter
CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */
/*
- * For each yield op, map the yield index (stored as bytecode operand) to
- * the offset of the next op.
+ * For each yield or await op, map the yield and await index (stored as
+ * bytecode operand) to the offset of the next op.
*/
- CGYieldOffsetList yieldOffsetList;
+ CGYieldAndAwaitOffsetList yieldAndAwaitOffsetList;
uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */
@@ -318,7 +333,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
EmitterScope* source);
mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name) {
- return locationOfNameBoundInFunctionScope(name, innermostEmitterScope);
+ return locationOfNameBoundInFunctionScope(name, innermostEmitterScope());
}
void setVarEmitterScope(EmitterScope* emitterScope) {
@@ -606,17 +621,29 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitPrepareIteratorResult();
MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
+ MOZ_MUST_USE bool emitToIteratorResult(bool done);
+ MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
+ return emitGetDotGeneratorInScope(*innermostEmitterScope());
+ }
+ MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope);
+
+ MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
MOZ_MUST_USE bool emitYield(ParseNode* pn);
MOZ_MUST_USE bool emitYieldOp(JSOp op);
- MOZ_MUST_USE bool emitYieldStar(ParseNode* iter, ParseNode* gen);
-
+ MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
+ MOZ_MUST_USE bool emitAwaitInInnermostScope() {
+ return emitAwaitInScope(*innermostEmitterScope());
+ }
+ MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn);
+ MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
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 emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
+ bool isStarGenerator);
MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);
@@ -703,11 +730,22 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// It will replace that stack value with the corresponding iterator
MOZ_MUST_USE bool emitIterator();
+ MOZ_MUST_USE bool emitAsyncIterator();
+
// Pops iterator from the top of the stack. Pushes the result of |.next()|
// onto the stack.
- MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, bool allowSelfHosted = false);
- MOZ_MUST_USE bool emitIteratorClose(CompletionKind completionKind = CompletionKind::Normal,
- bool allowSelfHosted = false);
+ MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
+ bool allowSelfHosted = false);
+ MOZ_MUST_USE bool emitIteratorCloseInScope(EmitterScope& currentScope,
+ IteratorKind iterKind = IteratorKind::Sync,
+ CompletionKind completionKind = CompletionKind::Normal,
+ bool allowSelfHosted = false);
+ MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
+ CompletionKind completionKind = CompletionKind::Normal,
+ bool allowSelfHosted = false) {
+ return emitIteratorCloseInScope(*innermostEmitterScope(), iterKind, completionKind,
+ allowSelfHosted);
+ }
template <typename InnerEmitter>
MOZ_MUST_USE bool wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth,
@@ -805,6 +843,31 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
};
+class MOZ_RAII AutoCheckUnstableEmitterScope {
+#ifdef DEBUG
+ bool prev_;
+ BytecodeEmitter* bce_;
+#endif
+
+ public:
+ AutoCheckUnstableEmitterScope() = delete;
+ explicit AutoCheckUnstableEmitterScope(BytecodeEmitter* bce)
+#ifdef DEBUG
+ : bce_(bce)
+#endif
+ {
+#ifdef DEBUG
+ prev_ = bce_->unstableEmitterScope;
+ bce_->unstableEmitterScope = true;
+#endif
+ }
+ ~AutoCheckUnstableEmitterScope() {
+#ifdef DEBUG
+ bce_->unstableEmitterScope = prev_;
+#endif
+ }
+};
+
} /* namespace frontend */
} /* namespace js */
diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp
index 689fa02b4..16294c4a8 100644
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -117,9 +117,10 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
// These two aren't statements in the spec, but we sometimes insert them
// in statement lists anyway.
+ case PNK_INITIALYIELD:
case PNK_YIELD_STAR:
case PNK_YIELD:
- MOZ_ASSERT(node->isArity(PN_BINARY));
+ MOZ_ASSERT(node->isArity(PN_UNARY));
*result = false;
return true;
@@ -1775,21 +1776,23 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_GENEXP:
return FoldList(cx, pn, parser, inGenexpLambda);
+ case PNK_INITIALYIELD:
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
+ pn->pn_kid->pn_left->isKind(PNK_NAME) &&
+ pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
+ return true;
+
case PNK_YIELD_STAR:
- MOZ_ASSERT(pn->isArity(PN_BINARY));
- MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME));
- return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ return Fold(cx, &pn->pn_kid, 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) &&
- pn->pn_right->pn_left->isKind(PNK_NAME) &&
- pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
- if (!pn->pn_left)
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ if (!pn->pn_kid)
return true;
- return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
+ return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
case PNK_RETURN:
return FoldReturn(cx, pn, parser, inGenexpLambda);
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index 2d7f57e1e..44694298b 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -440,20 +440,24 @@ class FullParseHandler
return true;
}
- ParseNode* newYieldExpression(uint32_t begin, ParseNode* value, ParseNode* gen,
- JSOp op = JSOP_YIELD) {
+ ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
+ TokenPos pos(begin, begin + 1);
+ return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
+ }
+
+ ParseNode* newYieldExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
- return new_<BinaryNode>(PNK_YIELD, op, pos, value, gen);
+ return new_<UnaryNode>(PNK_YIELD, JSOP_YIELD, pos, value);
}
- ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
+ ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value->pn_pos.end);
- return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);
+ return new_<UnaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value);
}
- ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
+ ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
- return new_<BinaryNode>(PNK_AWAIT, JSOP_YIELD, pos, value, gen);
+ return new_<UnaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value);
}
// Statements
@@ -506,8 +510,7 @@ class FullParseHandler
if (!genInit)
return false;
- ParseNode* initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit,
- JSOP_INITIALYIELD);
+ ParseNode* initialYield = newInitialYieldExpression(yieldPos.begin, genInit);
if (!initialYield)
return false;
diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp
index dc54d0a88..376be7624 100644
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -501,24 +501,25 @@ class NameResolver
return false;
break;
+ case PNK_INITIALYIELD:
+ MOZ_ASSERT(cur->pn_kid->isKind(PNK_ASSIGN) &&
+ cur->pn_kid->pn_left->isKind(PNK_NAME) &&
+ cur->pn_kid->pn_right->isKind(PNK_GENERATOR));
+ break;
+
case PNK_YIELD_STAR:
- MOZ_ASSERT(cur->isArity(PN_BINARY));
- MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME));
- if (!resolve(cur->pn_left, prefix))
+ MOZ_ASSERT(cur->isArity(PN_UNARY));
+ if (!resolve(cur->pn_kid, prefix))
return false;
break;
case PNK_YIELD:
case PNK_AWAIT:
- MOZ_ASSERT(cur->isArity(PN_BINARY));
- if (cur->pn_left) {
- if (!resolve(cur->pn_left, prefix))
+ MOZ_ASSERT(cur->isArity(PN_UNARY));
+ if (cur->pn_kid) {
+ if (!resolve(cur->pn_kid, prefix))
return false;
}
- MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME) ||
- (cur->pn_right->isKind(PNK_ASSIGN) &&
- cur->pn_right->pn_left->isKind(PNK_NAME) &&
- cur->pn_right->pn_right->isKind(PNK_GENERATOR)));
break;
case PNK_RETURN:
diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp
index 5fe64e3d3..42ae9451a 100644
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -286,22 +286,24 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
return PushResult::Recyclable;
}
- // The left half is the expression being yielded. The right half is
- // internal goop: a name reference to the invisible '.generator' local
- // variable, or an assignment of a PNK_GENERATOR node to the '.generator'
- // local, for a synthesized, prepended initial yield. Yum!
+ // The child is an assignment of a PNK_GENERATOR node to the
+ // '.generator' local, for a synthesized, prepended initial yield.
+ case PNK_INITIALYIELD: {
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
+ pn->pn_kid->pn_left->isKind(PNK_NAME) &&
+ pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
+ stack->push(pn->pn_kid);
+ return PushResult::Recyclable;
+ }
+
+ // The child is the expression being yielded.
case PNK_YIELD_STAR:
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) ||
- (pn->pn_right->isKind(PNK_ASSIGN) &&
- pn->pn_right->pn_left->isKind(PNK_NAME) &&
- pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
- if (pn->pn_left)
- stack->push(pn->pn_left);
- stack->push(pn->pn_right);
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ if (pn->pn_kid)
+ stack->push(pn->pn_kid);
return PushResult::Recyclable;
}
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index 1f20f3988..9a435e270 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -83,6 +83,7 @@ class ObjectBox;
F(THROW) \
F(DEBUGGER) \
F(GENERATOR) \
+ F(INITIALYIELD) \
F(YIELD) \
F(YIELD_STAR) \
F(GENEXP) \
@@ -418,8 +419,9 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings
* pn_u.scope.body: scope body
* PNK_GENERATOR nullary
- * PNK_YIELD, binary pn_left: expr or null; pn_right: generator object
- * PNK_YIELD_STAR
+ * PNK_INITIALYIELD unary pn_kid: generator object
+ * PNK_YIELD, unary pn_kid: expr or null
+ * PNK_YIELD_STAR,
* PNK_ARRAYCOMP list pn_count: 1
* pn_head: list of 1 element, which is block
* enclosing for loop(s) and optionally
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 0c279591f..cf9f1e27c 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2474,10 +2474,8 @@ Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false
}
static YieldHandling
-GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
+GetYieldHandling(GeneratorKind generatorKind)
{
- if (asyncKind == AsyncFunction)
- return YieldIsName;
if (generatorKind == NotGenerator)
return YieldIsName;
return YieldIsKeyword;
@@ -2541,7 +2539,7 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
return null();
funpc.setIsStandaloneFunctionBody();
- YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind);
AutoAwaitIsKeyword<FullParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction);
if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
parameterListEnd, /* isStandaloneFunction = */ true))
@@ -2699,7 +2697,7 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
switch (pc->generatorKind()) {
case NotGenerator:
- MOZ_ASSERT(pc->lastYieldOffset == startYieldOffset);
+ MOZ_ASSERT_IF(!pc->isAsync(), pc->lastYieldOffset == startYieldOffset);
break;
case LegacyGenerator:
@@ -2715,12 +2713,12 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
break;
case StarGenerator:
- MOZ_ASSERT_IF(!pc->isAsync(), kind != Arrow);
- MOZ_ASSERT_IF(!pc->isAsync(), type == StatementListBody);
+ MOZ_ASSERT(kind != Arrow);
+ MOZ_ASSERT(type == StatementListBody);
break;
}
- if (pc->isGenerator()) {
+ if (pc->needsDotGeneratorName()) {
MOZ_ASSERT_IF(!pc->isAsync(), type == StatementListBody);
if (!declareDotGeneratorName())
return null();
@@ -2761,9 +2759,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
#endif
switch (kind) {
case Expression:
- flags = (generatorKind == NotGenerator
+ flags = (generatorKind == NotGenerator && asyncKind == SyncFunction
? JSFunction::INTERPRETED_LAMBDA
- : JSFunction::INTERPRETED_LAMBDA_GENERATOR);
+ : JSFunction::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC);
break;
case Arrow:
flags = JSFunction::INTERPRETED_LAMBDA_ARROW;
@@ -2771,9 +2769,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
break;
case Method:
MOZ_ASSERT(generatorKind == NotGenerator || generatorKind == StarGenerator);
- flags = (generatorKind == NotGenerator
+ flags = (generatorKind == NotGenerator && asyncKind == SyncFunction
? JSFunction::INTERPRETED_METHOD
- : JSFunction::INTERPRETED_METHOD_GENERATOR);
+ : JSFunction::INTERPRETED_METHOD_GENERATOR_OR_ASYNC);
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case ClassConstructor:
@@ -2799,9 +2797,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
}
#endif
- flags = (generatorKind == NotGenerator
+ flags = (generatorKind == NotGenerator && asyncKind == SyncFunction
? JSFunction::INTERPRETED_NORMAL
- : JSFunction::INTERPRETED_GENERATOR);
+ : JSFunction::INTERPRETED_GENERATOR_OR_ASYNC);
}
// We store the async wrapper in a slot for later access.
@@ -3324,7 +3322,6 @@ Parser<ParseHandler>::functionDefinition(uint32_t toStringStart, Node pn, InHand
bool tryAnnexB /* = false */)
{
MOZ_ASSERT_IF(kind == Statement, funName);
- MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator);
// When fully parsing a LazyScript, we do not fully reparse its inner
// functions, which are also lazy. Instead, their free variables and
@@ -3336,7 +3333,7 @@ Parser<ParseHandler>::functionDefinition(uint32_t toStringStart, Node pn, InHand
}
RootedObject proto(context);
- if (generatorKind == StarGenerator) {
+ if (generatorKind == StarGenerator || asyncKind == AsyncFunction) {
// If we are off the main thread, the generator meta-objects have
// already been created by js::StartOffThreadParseScript, so cx will not
// be necessary.
@@ -3408,7 +3405,7 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
// parse to avoid the overhead of a lazy syntax-only parse. Although
// the prediction may be incorrect, IIFEs are common enough that it
// pays off for lots of code.
- if (pn->isLikelyIIFE() && generatorKind == NotGenerator)
+ if (pn->isLikelyIIFE() && generatorKind == NotGenerator && asyncKind == SyncFunction)
break;
Parser<SyntaxParseHandler>* parser = handler.syntaxParser;
@@ -3584,7 +3581,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
if (!tokenStream.peekTokenPos(&pn->pn_pos, modifier))
return null();
- YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind);
FunctionSyntaxKind syntaxKind = Statement;
if (fun->isClassConstructor())
syntaxKind = ClassConstructor;
@@ -3665,7 +3662,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
return false;
uint32_t openedPos = 0;
if (tt != TOK_LC) {
- if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method ||
+ if (funbox->isStarGenerator() || kind == Method ||
kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
IsConstructorKind(kind)) {
error(JSMSG_CURLY_BEFORE_BODY);
@@ -3695,7 +3692,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
// 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.
// The same goes when parsing |await| in arrow functions.
- YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind(), pc->asyncKind());
+ YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind());
Node body;
{
AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, funbox->isAsync());
@@ -3786,12 +3783,8 @@ Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHa
if (!tokenStream.getToken(&tt))
return null();
- GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
+ GeneratorKind generatorKind = NotGenerator;
if (tt == TOK_MUL) {
- if (asyncKind != SyncFunction) {
- error(JSMSG_ASYNC_GENERATOR);
- return null();
- }
generatorKind = StarGenerator;
if (!tokenStream.getToken(&tt))
return null();
@@ -3817,7 +3810,7 @@ Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHa
MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
- if (!pc->sc()->strict() && generatorKind == NotGenerator) {
+ if (!pc->sc()->strict() && generatorKind == NotGenerator && asyncKind == SyncFunction) {
// In sloppy mode, try Annex B.3.3 semantics. If making an
// additional 'var' binding of the same name does not throw an
// early error, do so. This 'var' binding would be assigned
@@ -3841,7 +3834,7 @@ Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHa
if (!pn)
return null();
- YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
+ YieldHandling newYieldHandling = GetYieldHandling(generatorKind);
return functionDefinition(toStringStart, pn, InAllowed, newYieldHandling,
name, Statement, generatorKind, asyncKind, tryAnnexB);
}
@@ -3854,22 +3847,18 @@ Parser<ParseHandler>::functionExpr(uint32_t toStringStart, InvokedPrediction inv
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction);
- GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
+ GeneratorKind generatorKind = NotGenerator;
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
if (tt == TOK_MUL) {
- if (asyncKind != SyncFunction) {
- error(JSMSG_ASYNC_GENERATOR);
- return null();
- }
generatorKind = StarGenerator;
if (!tokenStream.getToken(&tt))
return null();
}
- YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind);
RootedPropertyName name(context);
if (TokenKindIsPossibleIdentifier(tt)) {
@@ -5971,6 +5960,7 @@ Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp)
template <class ParseHandler>
bool
Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
+ IteratorKind iterKind,
ParseNodeKind* forHeadKind,
Node* forInitialPart,
Maybe<ParseContext::Scope>& forLoopLexicalScope,
@@ -6061,6 +6051,11 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
if (!matchInOrOf(&isForIn, &isForOf))
return false;
+ if (iterKind == IteratorKind::Async && !isForOf) {
+ error(JSMSG_FOR_AWAIT_NOT_OF);
+ return false;
+ }
+
// If we don't encounter 'in'/'of', we have a for(;;) loop. We've handled
// the init expression; the caller handles the rest. Allow the Operand
// modifier when regetting: Operand must be used to examine the ';' in
@@ -6134,6 +6129,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
ParseContext::Statement stmt(pc, StatementKind::ForLoop);
bool isForEach = false;
+ IteratorKind iterKind = IteratorKind::Sync;
unsigned iflags = 0;
if (allowsForEachIn()) {
@@ -6148,6 +6144,17 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
}
}
+ if (pc->isAsync()) {
+ bool matched;
+ if (!tokenStream.matchToken(&matched, TOK_AWAIT))
+ return null();
+
+ if (matched) {
+ iflags |= JSITER_FORAWAITOF;
+ iterKind = IteratorKind::Async;
+ }
+ }
+
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
// PNK_FORHEAD, PNK_FORIN, or PNK_FOROF depending on the loop type.
@@ -6185,7 +6192,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
//
// In either case the subsequent token can be consistently accessed using
// TokenStream::None semantics.
- if (!forHeadStart(yieldHandling, &headKind, &startNode, forLoopLexicalScope,
+ if (!forHeadStart(yieldHandling, iterKind, &headKind, &startNode, forLoopLexicalScope,
&iteratedExpr))
{
return null();
@@ -6551,29 +6558,6 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr,
- bool isYieldStar)
-{
- Node generator = newDotGeneratorName();
- if (!generator)
- return null();
- if (isYieldStar)
- return handler.newYieldStarExpression(begin, expr, generator);
- 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)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_YIELD));
@@ -6620,7 +6604,9 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
if (!exprNode)
return null();
}
- return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
+ if (kind == PNK_YIELD_STAR)
+ return handler.newYieldStarExpression(begin, exprNode);
+ return handler.newYieldExpression(begin, exprNode);
}
case NotGenerator:
@@ -6697,7 +6683,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
return null();
}
- return newYieldExpression(begin, exprNode);
+ return handler.newYieldExpression(begin, exprNode);
}
}
@@ -8187,7 +8173,6 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
uint32_t toStringStart = pos().begin;
tokenStream.ungetToken();
- GeneratorKind generatorKind = NotGenerator;
FunctionAsyncKind asyncKind = SyncFunction;
if (next == TOK_ASYNC) {
@@ -8200,7 +8185,6 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (nextSameLine == TOK_ARROW) {
tokenStream.ungetToken();
} else {
- generatorKind = StarGenerator;
asyncKind = AsyncFunction;
}
}
@@ -8210,7 +8194,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
return null();
Node arrowFunc = functionDefinition(toStringStart, pn, inHandling, yieldHandling, nullptr,
- Arrow, generatorKind, asyncKind);
+ Arrow, NotGenerator, asyncKind);
if (!arrowFunc)
return null();
@@ -8454,7 +8438,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
if (!kid)
return null();
pc->lastAwaitOffset = begin;
- return newAwaitExpression(begin, kid);
+ return handler.newAwaitExpression(begin, kid);
}
}
@@ -8712,7 +8696,7 @@ Parser<ParseHandler>::comprehensionTail(GeneratorKind comprehensionKind)
return handler.newArrayPush(begin, bodyExpr);
MOZ_ASSERT(comprehensionKind == StarGenerator);
- Node yieldExpr = newYieldExpression(begin, bodyExpr);
+ Node yieldExpr = handler.newYieldExpression(begin, bodyExpr);
if (!yieldExpr)
return null();
yieldExpr = handler.parenthesize(yieldExpr);
@@ -9494,11 +9478,6 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling,
bool isGenerator = false;
bool isAsync = false;
- if (ltok == TOK_MUL) {
- isGenerator = true;
- if (!tokenStream.getToken(&ltok))
- return null();
- }
if (ltok == TOK_ASYNC) {
// AsyncMethod[Yield, Await]:
@@ -9526,9 +9505,10 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling,
}
}
- if (isAsync && isGenerator) {
- error(JSMSG_ASYNC_GENERATOR);
- return null();
+ if (ltok == TOK_MUL) {
+ isGenerator = true;
+ if (!tokenStream.getToken(&ltok))
+ return null();
}
propAtom.set(nullptr);
@@ -9950,8 +9930,7 @@ Parser<ParseHandler>::methodDefinition(uint32_t toStringStart, PropertyType prop
MOZ_CRASH("Parser: methodDefinition: unexpected property type");
}
- GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod ||
- propType == PropertyType::AsyncMethod)
+ GeneratorKind generatorKind = propType == PropertyType::GeneratorMethod
? StarGenerator
: NotGenerator;
@@ -9959,7 +9938,7 @@ Parser<ParseHandler>::methodDefinition(uint32_t toStringStart, PropertyType prop
? AsyncFunction
: SyncFunction;
- YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind);
Node pn = handler.newFunctionExpression();
if (!pn)
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index 88d2dad18..243a77083 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -12,6 +12,7 @@
#include "mozilla/Array.h"
#include "mozilla/Maybe.h"
+#include "jsiter.h"
#include "jspubtd.h"
#include "frontend/BytecodeCompiler.h"
@@ -496,10 +497,6 @@ class ParseContext : public Nestable<ParseContext>
return sc_->isFunctionBox() ? sc_->asFunctionBox()->generatorKind() : NotGenerator;
}
- bool isGenerator() const {
- return generatorKind() != NotGenerator;
- }
-
bool isLegacyGenerator() const {
return generatorKind() == LegacyGenerator;
}
@@ -512,6 +509,10 @@ class ParseContext : public Nestable<ParseContext>
return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
}
+ bool needsDotGeneratorName() const {
+ return isStarGenerator() || isLegacyGenerator() || isAsync();
+ }
+
FunctionAsyncKind asyncKind() const {
return isAsync() ? AsyncFunction : SyncFunction;
}
@@ -818,7 +819,9 @@ class ParserBase : 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()) && !pc->isAsync();
+ return (versionNumber() >= JSVERSION_1_7 && !pc->isAsync()) ||
+ pc->isStarGenerator() ||
+ pc->isLegacyGenerator();
}
virtual bool strictMode() { return pc->sc()->strict(); }
@@ -1108,8 +1111,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
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();
@@ -1196,6 +1197,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
Node forStatement(YieldHandling yieldHandling);
bool forHeadStart(YieldHandling yieldHandling,
+ IteratorKind iterKind,
ParseNodeKind* forHeadKind,
Node* forInitialPart,
mozilla::Maybe<ParseContext::Scope>& forLetImpliedScope,
diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
index 013444690..8a5f6c0bd 100644
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -520,7 +520,9 @@ class FunctionBox : public ObjectBox, public SharedContext
return hasExtensibleScope() ||
needsHomeObject() ||
isDerivedClassConstructor() ||
- isGenerator();
+ isStarGenerator() ||
+ isLegacyGenerator() ||
+ isAsync();
}
bool hasExtraBodyVarScope() const {
@@ -531,7 +533,7 @@ class FunctionBox : public ObjectBox, public SharedContext
bool needsExtraBodyVarEnvironmentRegardlessOfBindings() const {
MOZ_ASSERT(hasParameterExprs);
- return hasExtensibleScope() || isGenerator();
+ return hasExtensibleScope() || needsDotGeneratorName();
}
bool isLikelyConstructorWrapper() const {
@@ -539,10 +541,21 @@ class FunctionBox : public ObjectBox, public SharedContext
}
GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
- 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 needsFinalYield() const {
+ return isStarGenerator() || isLegacyGenerator() || isAsync();
+ }
+ bool needsDotGeneratorName() const {
+ return isStarGenerator() || isLegacyGenerator() || isAsync();
+ }
+
+ bool needsIteratorResult() const {
+ return isStarGenerator();
+ }
+
bool isAsync() const { return asyncKind() == AsyncFunction; }
bool isArrow() const { return function()->isArrow(); }
@@ -560,7 +573,7 @@ class FunctionBox : public ObjectBox, public SharedContext
// A generator kind can be set at initialization, or when "yield" is
// first seen. In both cases the transition can only happen from
// NotGenerator.
- MOZ_ASSERT(!isGenerator());
+ MOZ_ASSERT(!isStarGenerator() && !isLegacyGenerator());
generatorKindBits_ = GeneratorKindAsBits(kind);
}
@@ -655,7 +668,11 @@ SharedContext::asModuleContext()
inline bool
SharedContext::allBindingsClosedOver()
{
- return bindingsAccessedDynamically() || (isFunctionBox() && asFunctionBox()->isGenerator());
+ return bindingsAccessedDynamically() ||
+ (isFunctionBox() &&
+ (asFunctionBox()->isStarGenerator() ||
+ asFunctionBox()->isLegacyGenerator() ||
+ asFunctionBox()->isAsync()));
}
} // namespace frontend
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
index a604b599f..d919f1354 100644
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -301,9 +301,9 @@ class SyntaxParseHandler
MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; }
MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
- Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
- Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
- Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
+ Node newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
+ Node newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
+ Node newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
// Statements
diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
index b8623d545..e07f8df8a 100644
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1843,6 +1843,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
reflags = RegExpFlag(reflags | StickyFlag);
else if (c == 'u' && !(reflags & UnicodeFlag))
reflags = RegExpFlag(reflags | UnicodeFlag);
+ else if (c == 's' && !(reflags & DotAllFlag))
+ reflags = RegExpFlag(reflags | DotAllFlag);
else
break;
getChar();
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
index da3ef7d0d..262fc8cbc 100644
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2846,10 +2846,9 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
*
* There is an additional complication for certain kinds of edges that are not
* contained explicitly in the source object itself, such as from a weakmap key
- * to its value, and from an object being watched by a watchpoint to the
- * watchpoint's closure. These "implicit edges" are represented in some other
- * container object, such as the weakmap or the watchpoint itself. In these
- * cases, calling unmark gray on an object won't find all of its children.
+ * to its value. These "implicit edges" are represented in some other
+ * container object, such as the weakmap itself. In these cases, calling unmark
+ * gray on an object won't find all of its children.
*
* Handling these implicit edges has two parts:
* - A special pass enumerating all of the containers that know about the
diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp
index 268e1e489..418984057 100644
--- a/js/src/gc/Memory.cpp
+++ b/js/src/gc/Memory.cpp
@@ -415,8 +415,15 @@ InitMemorySubsystem()
static inline void*
MapMemoryAt(void* desired, size_t length, int prot = PROT_READ | PROT_WRITE,
int flags = MAP_PRIVATE | MAP_ANON, int fd = -1, off_t offset = 0)
+
+// Solaris manages 64-bit address space in a different manner from every other
+// AMD64 operating system, but fortunately the fix is the same one
+// required for every operating system on 64-bit SPARC, Itanium, and ARM.
+// Most people's intuition failed them here and they thought this couldn't
+// possibly be correct on AMD64, but for Solaris/illumos it is.
+
{
-#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__)
+#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__) || (defined(__sun) && defined(__x86_64__))
MOZ_ASSERT((0xffff800000000000ULL & (uintptr_t(desired) + length - 1)) == 0);
#endif
void* region = mmap(desired, length, prot, flags, fd, offset);
@@ -466,7 +473,7 @@ MapMemory(size_t length, int prot = PROT_READ | PROT_WRITE,
return nullptr;
}
return region;
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || (defined(__sun) && defined(__x86_64__))
/*
* There might be similar virtual address issue on arm64 which depends on
* hardware and kernel configurations. But the work around is slightly
@@ -678,7 +685,11 @@ MarkPagesUnused(void* p, size_t size)
return false;
MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
- int result = madvise(p, size, MADV_DONTNEED);
+#ifdef XP_SOLARIS
+ int result = posix_madvise(p, size, POSIX_MADV_DONTNEED);
+#else
+ int result = madvise(p, size, MADV_DONTNEED);
+#endif
return result != -1;
}
diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp
index f5969bc1f..7d665e8eb 100644
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -14,7 +14,6 @@
#include "jsgc.h"
#include "jsprf.h"
#include "jstypes.h"
-#include "jswatchpoint.h"
#include "builtin/MapObject.h"
#include "frontend/BytecodeCompiler.h"
diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
index 0fb507297..e17eecb9b 100644
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -582,7 +582,7 @@ NativeRegExpMacroAssembler::CheckAtStart(Label* on_at_start)
}
void
-NativeRegExpMacroAssembler::CheckNotAtStart(Label* on_not_at_start)
+NativeRegExpMacroAssembler::CheckNotAtStart(int cp_offset, Label* on_not_at_start)
{
JitSpew(SPEW_PREFIX "CheckNotAtStart");
@@ -673,7 +673,7 @@ NativeRegExpMacroAssembler::CheckGreedyLoop(Label* on_tos_equals_current_positio
}
void
-NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, Label* on_no_match)
+NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, bool read_backward, Label* on_no_match)
{
JitSpew(SPEW_PREFIX "CheckNotBackReference(%d)", start_reg);
@@ -744,8 +744,8 @@ NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, Label* on_no_ma
}
void
-NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label* on_no_match,
- bool unicode)
+NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward,
+ Label* on_no_match, bool unicode)
{
JitSpew(SPEW_PREFIX "CheckNotBackReferenceIgnoreCase(%d, %d)", start_reg, unicode);
diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.h b/js/src/irregexp/NativeRegExpMacroAssembler.h
index 7a72e252f..fc582dccf 100644
--- a/js/src/irregexp/NativeRegExpMacroAssembler.h
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.h
@@ -105,9 +105,10 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler final : public RegExpMacroAssem
void CheckCharacterGT(char16_t limit, jit::Label* on_greater);
void CheckCharacterLT(char16_t limit, jit::Label* on_less);
void CheckGreedyLoop(jit::Label* on_tos_equals_current_position);
- void CheckNotAtStart(jit::Label* on_not_at_start);
- void CheckNotBackReference(int start_reg, jit::Label* on_no_match);
- void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match, bool unicode);
+ void CheckNotAtStart(int cp_offset, jit::Label* on_not_at_start);
+ void CheckNotBackReference(int start_reg, bool read_backward, jit::Label* on_no_match);
+ void CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward,
+ jit::Label* on_no_match, bool unicode);
void CheckNotCharacter(unsigned c, jit::Label* on_not_equal);
void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, jit::Label* on_not_equal);
void CheckNotCharacterAfterMinusAnd(char16_t c, char16_t minus, char16_t and_with,
diff --git a/js/src/irregexp/RegExpAST.cpp b/js/src/irregexp/RegExpAST.cpp
index 8dfd99057..43867c312 100644
--- a/js/src/irregexp/RegExpAST.cpp
+++ b/js/src/irregexp/RegExpAST.cpp
@@ -250,16 +250,16 @@ RegExpCapture::CaptureRegisters()
}
// ----------------------------------------------------------------------------
-// RegExpLookahead
+// RegExpLookaround
Interval
-RegExpLookahead::CaptureRegisters()
+RegExpLookaround::CaptureRegisters()
{
return body()->CaptureRegisters();
}
bool
-RegExpLookahead::IsAnchoredAtStart()
+RegExpLookaround::IsAnchoredAtStart()
{
- return is_positive() && body()->IsAnchoredAtStart();
+ return is_positive() && type() == LOOKAHEAD && body()->IsAnchoredAtStart();
}
diff --git a/js/src/irregexp/RegExpAST.h b/js/src/irregexp/RegExpAST.h
index 7bda6fc7e..6f59842bc 100644
--- a/js/src/irregexp/RegExpAST.h
+++ b/js/src/irregexp/RegExpAST.h
@@ -360,6 +360,7 @@ class RegExpCapture : public RegExpTree
virtual int min_match() { return body_->min_match(); }
virtual int max_match() { return body_->max_match(); }
RegExpTree* body() { return body_; }
+ void set_body(RegExpTree* body) { body_ = body; }
int index() { return index_; }
static int StartRegister(int index) { return index * 2; }
static int EndRegister(int index) { return index * 2 + 1; }
@@ -369,25 +370,29 @@ class RegExpCapture : public RegExpTree
int index_;
};
-class RegExpLookahead : public RegExpTree
+class RegExpLookaround : public RegExpTree
{
public:
- RegExpLookahead(RegExpTree* body,
- bool is_positive,
- int capture_count,
- int capture_from)
+ enum Type { LOOKAHEAD, LOOKBEHIND };
+
+ RegExpLookaround(RegExpTree* body,
+ bool is_positive,
+ int capture_count,
+ int capture_from,
+ Type type)
: body_(body),
is_positive_(is_positive),
capture_count_(capture_count),
- capture_from_(capture_from)
+ capture_from_(capture_from),
+ type_(type)
{}
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success);
- virtual RegExpLookahead* AsLookahead();
+ virtual RegExpLookaround* AsLookaround();
virtual Interval CaptureRegisters();
- virtual bool IsLookahead();
+ virtual bool IsLookaround();
virtual bool IsAnchoredAtStart();
virtual int min_match() { return 0; }
virtual int max_match() { return 0; }
@@ -395,12 +400,14 @@ class RegExpLookahead : public RegExpTree
bool is_positive() { return is_positive_; }
int capture_count() { return capture_count_; }
int capture_from() { return capture_from_; }
+ Type type() { return type_; }
private:
RegExpTree* body_;
bool is_positive_;
int capture_count_;
int capture_from_;
+ Type type_;
};
typedef InfallibleVector<RegExpCapture*, 1> RegExpCaptureVector;
@@ -417,8 +424,14 @@ class RegExpBackReference : public RegExpTree
RegExpNode* on_success);
virtual RegExpBackReference* AsBackReference();
virtual bool IsBackReference();
- virtual int min_match() { return 0; }
- virtual int max_match() { return capture_->max_match(); }
+ virtual int min_match() override { return 0; }
+ // The capture may not be completely parsed yet, if the reference occurs
+ // before the capture. In the ordinary case, nothing has been captured yet,
+ // so the back reference must have the length 0. If the back reference is
+ // inside a lookbehind, effectively making it a forward reference, we return
+ virtual int max_match() override {
+ return capture_->body() ? capture_->max_match() : 0;
+ }
int index() { return capture_->index(); }
RegExpCapture* capture() { return capture_; }
private:
diff --git a/js/src/irregexp/RegExpBytecode.h b/js/src/irregexp/RegExpBytecode.h
index f31b78c59..ea3f80b4f 100644
--- a/js/src/irregexp/RegExpBytecode.h
+++ b/js/src/irregexp/RegExpBytecode.h
@@ -82,16 +82,19 @@ V(CHECK_LT, 35, 8) /* bc8 pad8 uc16 addr32 */ \
V(CHECK_GT, 36, 8) /* bc8 pad8 uc16 addr32 */ \
V(CHECK_NOT_BACK_REF, 37, 8) /* bc8 reg_idx24 addr32 */ \
V(CHECK_NOT_BACK_REF_NO_CASE, 38, 8) /* bc8 reg_idx24 addr32 */ \
-V(CHECK_NOT_REGS_EQUAL, 39, 12) /* bc8 regidx24 reg_idx32 addr32 */ \
-V(CHECK_REGISTER_LT, 40, 12) /* bc8 reg_idx24 value32 addr32 */ \
-V(CHECK_REGISTER_GE, 41, 12) /* bc8 reg_idx24 value32 addr32 */ \
-V(CHECK_REGISTER_EQ_POS, 42, 8) /* bc8 reg_idx24 addr32 */ \
-V(CHECK_AT_START, 43, 8) /* bc8 pad24 addr32 */ \
-V(CHECK_NOT_AT_START, 44, 8) /* bc8 pad24 addr32 */ \
-V(CHECK_GREEDY, 45, 8) /* bc8 pad24 addr32 */ \
-V(ADVANCE_CP_AND_GOTO, 46, 8) /* bc8 offset24 addr32 */ \
-V(SET_CURRENT_POSITION_FROM_END, 47, 4) /* bc8 idx24 */ \
-V(CHECK_NOT_BACK_REF_NO_CASE_UNICODE, 48, 8) /* bc8 reg_idx24 addr32 */
+V(CHECK_NOT_BACK_REF_BACKWARD, 39, 8) /* bc8 reg_idx24 addr32 */ \
+V(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD, 40, 8) /* bc8 reg_idx24 addr32 */ \
+V(CHECK_NOT_REGS_EQUAL, 41, 12) /* bc8 regidx24 reg_idx32 addr32 */ \
+V(CHECK_REGISTER_LT, 42, 12) /* bc8 reg_idx24 value32 addr32 */ \
+V(CHECK_REGISTER_GE, 43, 12) /* bc8 reg_idx24 value32 addr32 */ \
+V(CHECK_REGISTER_EQ_POS, 44, 8) /* bc8 reg_idx24 addr32 */ \
+V(CHECK_AT_START, 45, 8) /* bc8 pad24 addr32 */ \
+V(CHECK_NOT_AT_START, 46, 8) /* bc8 pad24 addr32 */ \
+V(CHECK_GREEDY, 47, 8) /* bc8 pad24 addr32 */ \
+V(ADVANCE_CP_AND_GOTO, 48, 8) /* bc8 offset24 addr32 */ \
+V(SET_CURRENT_POSITION_FROM_END, 49, 4) /* bc8 idx24 */ \
+V(CHECK_NOT_BACK_REF_NO_CASE_UNICODE, 50, 8) /* bc8 reg_idx24 addr32 */ \
+V(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_UNICODE, 51, 8) /* bc8 reg_idx24 addr32 */
#define DECLARE_BYTECODES(name, code, length) \
static const int BC_##name = code;
diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp
index 4d691a5dc..62f94c3e7 100644
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -721,6 +721,8 @@ ActionNode::EmptyMatchCheck(int start_register,
int
TextNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
{
+ if (read_backward())
+ return 0;
int answer = Length();
if (answer >= still_to_find)
return answer;
@@ -736,8 +738,7 @@ TextNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
int
TextNode::GreedyLoopTextLength()
{
- TextElement elm = elements()[elements().length() - 1];
- return elm.cp_offset() + elm.length();
+ return Length();
}
RegExpNode*
@@ -887,6 +888,8 @@ AssertionNode::FillInBMInfo(int offset, int budget, BoyerMooreLookahead* bm, boo
int
BackReferenceNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
{
+ if (read_backward())
+ return 0;
if (budget <= 0)
return 0;
return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
@@ -1578,6 +1581,9 @@ class irregexp::RegExpCompiler
current_expansion_factor_ = value;
}
+ bool read_backward() { return read_backward_; }
+ void set_read_backward(bool value) { read_backward_ = value; }
+
JSContext* cx() const { return cx_; }
LifoAlloc* alloc() const { return alloc_; }
@@ -1595,6 +1601,7 @@ class irregexp::RegExpCompiler
bool unicode_;
bool reg_exp_too_big_;
int current_expansion_factor_;
+ bool read_backward_;
FrequencyCollator frequency_collator_;
JSContext* cx_;
LifoAlloc* alloc_;
@@ -1624,6 +1631,7 @@ RegExpCompiler::RegExpCompiler(JSContext* cx, LifoAlloc* alloc, int capture_coun
unicode_(unicode),
reg_exp_too_big_(false),
current_expansion_factor_(1),
+ read_backward_(false),
frequency_collator_(),
cx_(cx),
alloc_(alloc)
@@ -1747,7 +1755,7 @@ irregexp::CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData*
// at the start of input.
ChoiceNode* first_step_node = alloc.newInfallible<ChoiceNode>(&alloc, 2);
RegExpNode* char_class =
- alloc.newInfallible<TextNode>(alloc.newInfallible<RegExpCharacterClass>('*'), loop_node);
+ alloc.newInfallible<TextNode>(alloc.newInfallible<RegExpCharacterClass>('*'), false, loop_node);
first_step_node->AddAlternative(GuardedAlternative(captured_body));
first_step_node->AddAlternative(GuardedAlternative(char_class));
node = first_step_node;
@@ -1850,19 +1858,19 @@ RegExpAtom::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
TextElementVector* elms =
compiler->alloc()->newInfallible<TextElementVector>(*compiler->alloc());
elms->append(TextElement::Atom(this));
- return compiler->alloc()->newInfallible<TextNode>(elms, on_success);
+ return compiler->alloc()->newInfallible<TextNode>(elms, compiler->read_backward(), on_success);
}
RegExpNode*
RegExpText::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
- return compiler->alloc()->newInfallible<TextNode>(&elements_, on_success);
+ return compiler->alloc()->newInfallible<TextNode>(&elements_, compiler->read_backward(), on_success);
}
RegExpNode*
RegExpCharacterClass::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
- return compiler->alloc()->newInfallible<TextNode>(this, on_success);
+ return compiler->alloc()->newInfallible<TextNode>(this, compiler->read_backward(), on_success);
}
RegExpNode*
@@ -2003,7 +2011,8 @@ RegExpQuantifier::ToNode(int min,
alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler, answer)));
}
answer = alternation;
- if (not_at_start) alternation->set_not_at_start();
+ if (not_at_start && !compiler->read_backward())
+ alternation->set_not_at_start();
}
return answer;
}
@@ -2015,8 +2024,9 @@ RegExpQuantifier::ToNode(int min,
int reg_ctr = needs_counter
? compiler->AllocateRegister()
: RegExpCompiler::kNoRegister;
- LoopChoiceNode* center = alloc->newInfallible<LoopChoiceNode>(alloc, body->min_match() == 0);
- if (not_at_start)
+ LoopChoiceNode* center = alloc->newInfallible<LoopChoiceNode>(alloc, body->min_match() == 0,
+ compiler->read_backward());
+ if (not_at_start && !compiler->read_backward())
center->set_not_at_start();
RegExpNode* loop_return = needs_counter
? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center))
@@ -2092,7 +2102,7 @@ RegExpAssertion::ToNode(RegExpCompiler* compiler,
CharacterRange::AddClassEscape(alloc, 'n', newline_ranges);
RegExpCharacterClass* newline_atom = alloc->newInfallible<RegExpCharacterClass>('n');
TextNode* newline_matcher =
- alloc->newInfallible<TextNode>(newline_atom,
+ alloc->newInfallible<TextNode>(newline_atom, false,
ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
position_register,
0, // No captures inside.
@@ -2124,6 +2134,7 @@ RegExpBackReference::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
return compiler->alloc()->newInfallible<BackReferenceNode>(RegExpCapture::StartRegister(index()),
RegExpCapture::EndRegister(index()),
+ compiler->read_backward(),
on_success);
}
@@ -2134,7 +2145,7 @@ RegExpEmpty::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
}
RegExpNode*
-RegExpLookahead::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+RegExpLookaround::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
int stack_pointer_register = compiler->AllocateRegister();
int position_register = compiler->AllocateRegister();
@@ -2145,6 +2156,10 @@ RegExpLookahead::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
int register_start =
register_of_first_capture + capture_from_ * registers_per_capture;
+ RegExpNode* result;
+ bool was_reading_backward = compiler->read_backward();
+ compiler->set_read_backward(type() == LOOKBEHIND);
+
if (is_positive()) {
RegExpNode* bodyNode =
body()->ToNode(compiler,
@@ -2153,37 +2168,39 @@ RegExpLookahead::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
register_count,
register_start,
on_success));
- return ActionNode::BeginSubmatch(stack_pointer_register,
+ result = ActionNode::BeginSubmatch(stack_pointer_register,
+ position_register,
+ bodyNode);
+ } else {
+ // We use a ChoiceNode for a negative lookahead because it has most of
+ // the characteristics we need. It has the body of the lookahead as its
+ // first alternative and the expression after the lookahead of the second
+ // alternative. If the first alternative succeeds then the
+ // NegativeSubmatchSuccess will unwind the stack including everything the
+ // choice node set up and backtrack. If the first alternative fails then
+ // the second alternative is tried, which is exactly the desired result
+ // for a negative lookahead. The NegativeLookaheadChoiceNode is a special
+ // ChoiceNode that knows to ignore the first exit when calculating quick
+ // checks.
+ LifoAlloc* alloc = compiler->alloc();
+
+ RegExpNode* success =
+ alloc->newInfallible<NegativeSubmatchSuccess>(alloc,
+ stack_pointer_register,
+ position_register,
+ register_count,
+ register_start);
+ GuardedAlternative body_alt(body()->ToNode(compiler, success));
+
+ ChoiceNode* choice_node =
+ alloc->newInfallible<NegativeLookaheadChoiceNode>(alloc, body_alt, GuardedAlternative(on_success));
+
+ result = ActionNode::BeginSubmatch(stack_pointer_register,
position_register,
- bodyNode);
- }
-
- // We use a ChoiceNode for a negative lookahead because it has most of
- // the characteristics we need. It has the body of the lookahead as its
- // first alternative and the expression after the lookahead of the second
- // alternative. If the first alternative succeeds then the
- // NegativeSubmatchSuccess will unwind the stack including everything the
- // choice node set up and backtrack. If the first alternative fails then
- // the second alternative is tried, which is exactly the desired result
- // for a negative lookahead. The NegativeLookaheadChoiceNode is a special
- // ChoiceNode that knows to ignore the first exit when calculating quick
- // checks.
- LifoAlloc* alloc = compiler->alloc();
-
- RegExpNode* success =
- alloc->newInfallible<NegativeSubmatchSuccess>(alloc,
- stack_pointer_register,
- position_register,
- register_count,
- register_start);
- GuardedAlternative body_alt(body()->ToNode(compiler, success));
-
- ChoiceNode* choice_node =
- alloc->newInfallible<NegativeLookaheadChoiceNode>(alloc, body_alt, GuardedAlternative(on_success));
-
- return ActionNode::BeginSubmatch(stack_pointer_register,
- position_register,
- choice_node);
+ choice_node);
+ }
+ compiler->set_read_backward(was_reading_backward);
+ return result;
}
RegExpNode*
@@ -2198,8 +2215,14 @@ RegExpCapture::ToNode(RegExpTree* body,
RegExpCompiler* compiler,
RegExpNode* on_success)
{
+ MOZ_ASSERT(body);
int start_reg = RegExpCapture::StartRegister(index);
int end_reg = RegExpCapture::EndRegister(index);
+ if (compiler->read_backward()) {
+ // std::swap(start_reg, end_reg);
+ start_reg = RegExpCapture::EndRegister(index);
+ end_reg = RegExpCapture::StartRegister(index);
+ }
RegExpNode* store_end = ActionNode::StorePosition(end_reg, true, on_success);
RegExpNode* body_node = body->ToNode(compiler, store_end);
return ActionNode::StorePosition(start_reg, true, body_node);
@@ -2210,8 +2233,15 @@ RegExpAlternative::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
const RegExpTreeVector& children = nodes();
RegExpNode* current = on_success;
- for (int i = children.length() - 1; i >= 0; i--)
- current = children[i]->ToNode(compiler, current);
+ if (compiler->read_backward()) {
+ for (int i = 0; i < children.length(); i++) {
+ current = children[i]->ToNode(compiler, current);
+ }
+ } else {
+ for (int i = children.length() - 1; i >= 0; i--) {
+ current = children[i]->ToNode(compiler, current);
+ }
+ }
return current;
}
@@ -2764,7 +2794,6 @@ Trace::InvalidateCurrentCharacter()
void
Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler)
{
- MOZ_ASSERT(by > 0);
// We don't have an instruction for shifting the current character register
// down or for using a shifted value for anything so lets just forget that
// we preloaded any characters into it.
@@ -3109,9 +3138,9 @@ AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace)
return;
}
if (trace->at_start() == Trace::UNKNOWN) {
- assembler->CheckNotAtStart(trace->backtrack());
+ assembler->CheckNotAtStart(trace->cp_offset(), trace->backtrack());
Trace at_start_trace = *trace;
- at_start_trace.set_at_start(true);
+ at_start_trace.set_at_start(Trace::TRUE_VALUE);
on_success()->Emit(compiler, &at_start_trace);
return;
}
@@ -3814,9 +3843,10 @@ TextNode::TextEmitPass(RegExpCompiler* compiler,
jit::Label* backtrack = trace->backtrack();
QuickCheckDetails* quick_check = trace->quick_check_performed();
int element_count = elements().length();
+ int backward_offset = read_backward() ? -Length() : 0;
for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) {
TextElement elm = elements()[i];
- int cp_offset = trace->cp_offset() + elm.cp_offset();
+ int cp_offset = trace->cp_offset() + elm.cp_offset() + backward_offset;
if (elm.text_type() == TextElement::ATOM) {
const CharacterVector& quarks = elm.atom()->data();
for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) {
@@ -3844,11 +3874,12 @@ TextNode::TextEmitPass(RegExpCompiler* compiler,
break;
}
if (emit_function != nullptr) {
+ bool bounds_check = *checked_up_to < cp_offset + j || read_backward();
bool bound_checked = emit_function(compiler,
quarks[j],
backtrack,
cp_offset + j,
- *checked_up_to < cp_offset + j,
+ bounds_check,
preloaded);
if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to);
}
@@ -3859,13 +3890,14 @@ TextNode::TextEmitPass(RegExpCompiler* compiler,
if (first_element_checked && i == 0) continue;
if (DeterminedAlready(quick_check, elm.cp_offset())) continue;
RegExpCharacterClass* cc = elm.char_class();
+ bool bounds_check = *checked_up_to < cp_offset || read_backward();
EmitCharClass(alloc(),
assembler,
cc,
ascii,
backtrack,
cp_offset,
- *checked_up_to < cp_offset,
+ bounds_check,
preloaded);
UpdateBoundsCheck(cp_offset, checked_up_to);
}
@@ -3945,8 +3977,11 @@ TextNode::Emit(RegExpCompiler* compiler, Trace* trace)
}
Trace successor_trace(*trace);
- successor_trace.set_at_start(false);
- successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler);
+ // If we advance backward, we may end up at the start.
+ successor_trace.AdvanceCurrentPositionInTrace(
+ read_backward() ? -Length() : Length(), compiler);
+ successor_trace.set_at_start(read_backward() ? Trace::UNKNOWN
+ : Trace::FALSE_VALUE);
RecursionCheck rc(compiler);
on_success()->Emit(compiler, &successor_trace);
}
@@ -4118,6 +4153,8 @@ ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler, int eats_at_lea
RegExpNode*
TextNode::GetSuccessorOfOmnivorousTextNode(RegExpCompiler* compiler)
{
+ if (read_backward()) return NULL;
+
if (elements().length() != 1)
return nullptr;
@@ -4165,7 +4202,7 @@ ChoiceNode::GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative)
SeqRegExpNode* seq_node = static_cast<SeqRegExpNode*>(node);
node = seq_node->on_success();
}
- return length;
+ return read_backward() ? -length : length;
}
// Creates a list of AlternativeGenerations. If the list has a reasonable
@@ -4240,7 +4277,7 @@ ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace)
jit::Label greedy_loop_label;
Trace counter_backtrack_trace;
counter_backtrack_trace.set_backtrack(&greedy_loop_label);
- if (not_at_start()) counter_backtrack_trace.set_at_start(false);
+ if (not_at_start()) counter_backtrack_trace.set_at_start(Trace::FALSE_VALUE);
if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) {
// Here we have special handling for greedy loops containing only text nodes
@@ -4256,7 +4293,7 @@ ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace)
current_trace = &counter_backtrack_trace;
jit::Label greedy_match_failed;
Trace greedy_match_trace;
- if (not_at_start()) greedy_match_trace.set_at_start(false);
+ if (not_at_start()) greedy_match_trace.set_at_start(Trace::FALSE_VALUE);
greedy_match_trace.set_backtrack(&greedy_match_failed);
jit::Label loop_label;
macro_assembler->Bind(&loop_label);
@@ -4605,11 +4642,14 @@ BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace)
MOZ_ASSERT(start_reg_ + 1 == end_reg_);
if (compiler->ignore_case()) {
assembler->CheckNotBackReferenceIgnoreCase(start_reg_,
+ read_backward(),
trace->backtrack(),
compiler->unicode());
} else {
- assembler->CheckNotBackReference(start_reg_, trace->backtrack());
+ assembler->CheckNotBackReference(start_reg_, read_backward(), trace->backtrack());
}
+ // We are going to advance backward, so we may end up at the start.
+ if (read_backward()) trace->set_at_start(Trace::UNKNOWN);
on_success()->Emit(compiler, trace);
}
@@ -4977,7 +5017,6 @@ QuickCheckDetails::Clear()
void
QuickCheckDetails::Advance(int by, bool ascii)
{
- MOZ_ASSERT(by >= 0);
if (by >= characters_) {
Clear();
return;
diff --git a/js/src/irregexp/RegExpEngine.h b/js/src/irregexp/RegExpEngine.h
index 1a8fd4b22..c4409dcca 100644
--- a/js/src/irregexp/RegExpEngine.h
+++ b/js/src/irregexp/RegExpEngine.h
@@ -119,7 +119,7 @@ InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* chars, size_t
VISIT(Atom) \
VISIT(Quantifier) \
VISIT(Capture) \
- VISIT(Lookahead) \
+ VISIT(Lookaround) \
VISIT(BackReference) \
VISIT(Empty) \
VISIT(Text)
@@ -763,15 +763,19 @@ class TextNode : public SeqRegExpNode
{
public:
TextNode(TextElementVector* elements,
+ bool read_backward,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
- elements_(elements)
+ elements_(elements),
+ read_backward_(read_backward)
{}
TextNode(RegExpCharacterClass* that,
+ bool read_backward,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
- elements_(alloc()->newInfallible<TextElementVector>(*alloc()))
+ elements_(alloc()->newInfallible<TextElementVector>(*alloc())),
+ read_backward_(read_backward)
{
elements_->append(TextElement::CharClass(that));
}
@@ -784,6 +788,7 @@ class TextNode : public SeqRegExpNode
int characters_filled_in,
bool not_at_start);
TextElementVector& elements() { return *elements_; }
+ bool read_backward() { return read_backward_; }
void MakeCaseIndependent(bool is_ascii, bool unicode);
virtual int GreedyLoopTextLength();
virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
@@ -814,6 +819,7 @@ class TextNode : public SeqRegExpNode
int* checked_up_to);
int Length();
TextElementVector* elements_;
+ bool read_backward_;
};
class AssertionNode : public SeqRegExpNode
@@ -882,15 +888,18 @@ class BackReferenceNode : public SeqRegExpNode
public:
BackReferenceNode(int start_reg,
int end_reg,
+ bool read_backward,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
start_reg_(start_reg),
- end_reg_(end_reg)
+ end_reg_(end_reg),
+ read_backward_(read_backward)
{}
virtual void Accept(NodeVisitor* visitor);
int start_register() { return start_reg_; }
int end_register() { return end_reg_; }
+ bool read_backward() { return read_backward_; }
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
@@ -909,6 +918,7 @@ class BackReferenceNode : public SeqRegExpNode
private:
int start_reg_;
int end_reg_;
+ bool read_backward_;
};
class EndNode : public RegExpNode
@@ -1053,6 +1063,7 @@ class ChoiceNode : public RegExpNode
void set_being_calculated(bool b) { being_calculated_ = b; }
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode);
+ virtual bool read_backward() { return false; }
protected:
int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
@@ -1111,11 +1122,13 @@ class NegativeLookaheadChoiceNode : public ChoiceNode
class LoopChoiceNode : public ChoiceNode
{
public:
- explicit LoopChoiceNode(LifoAlloc* alloc, bool body_can_be_zero_length)
+ explicit LoopChoiceNode(LifoAlloc* alloc, bool body_can_be_zero_length,
+ bool read_backward)
: ChoiceNode(alloc, 2),
loop_node_(nullptr),
continue_node_(nullptr),
- body_can_be_zero_length_(body_can_be_zero_length)
+ body_can_be_zero_length_(body_can_be_zero_length),
+ read_backward_(read_backward)
{}
void AddLoopAlternative(GuardedAlternative alt);
@@ -1133,6 +1146,7 @@ class LoopChoiceNode : public ChoiceNode
RegExpNode* loop_node() { return loop_node_; }
RegExpNode* continue_node() { return continue_node_; }
bool body_can_be_zero_length() { return body_can_be_zero_length_; }
+ virtual bool read_backward() { return read_backward_; }
virtual void Accept(NodeVisitor* visitor);
virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode);
@@ -1147,6 +1161,7 @@ class LoopChoiceNode : public ChoiceNode
RegExpNode* loop_node_;
RegExpNode* continue_node_;
bool body_can_be_zero_length_;
+ bool read_backward_;
};
// Improve the speed that we scan for an initial point where a non-anchored
@@ -1422,8 +1437,8 @@ class Trace
}
TriBool at_start() { return at_start_; }
- void set_at_start(bool at_start) {
- at_start_ = at_start ? TRUE_VALUE : FALSE_VALUE;
+ void set_at_start(TriBool at_start) {
+ at_start_ = at_start;
}
jit::Label* backtrack() { return backtrack_; }
jit::Label* loop_label() { return loop_label_; }
diff --git a/js/src/irregexp/RegExpInterpreter.cpp b/js/src/irregexp/RegExpInterpreter.cpp
index 7fd2d983a..d09b4671e 100644
--- a/js/src/irregexp/RegExpInterpreter.cpp
+++ b/js/src/irregexp/RegExpInterpreter.cpp
@@ -222,8 +222,8 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
}
break;
BYTECODE(LOAD_CURRENT_CHAR) {
- size_t pos = current + (insn >> BYTECODE_SHIFT);
- if (pos >= length) {
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ if (pos >= (int)length || pos < 0) {
pc = byteCode + Load32Aligned(pc + 4);
} else {
current_char = chars[pos];
@@ -238,8 +238,8 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
break;
}
BYTECODE(LOAD_2_CURRENT_CHARS) {
- size_t pos = current + (insn >> BYTECODE_SHIFT);
- if (pos + 2 > length) {
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ if (pos + 2 > (int)length || pos < 0) {
pc = byteCode + Load32Aligned(pc + 4);
} else {
CharT next = chars[pos + 1];
@@ -425,6 +425,30 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
pc += BC_CHECK_NOT_BACK_REF_LENGTH;
break;
}
+ BYTECODE(CHECK_NOT_BACK_REF_BACKWARD) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from < 0 || len <= 0) {
+ pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
+ break;
+ }
+ if (int(current) - len < 0) {
+ pc = byteCode + Load32Aligned(pc + 4);
+ break;
+ } else {
+ int i;
+ for (i = 0; i < len; i++) {
+ if (chars[from + i] != chars[int(current) - len + i]) {
+ pc = byteCode + Load32Aligned(pc + 4);
+ break;
+ }
+ }
+ if (i < len) break;
+ current -= len;
+ }
+ pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
+ break;
+ }
BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
int from = registers[insn >> BYTECODE_SHIFT];
int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
@@ -465,6 +489,46 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
}
break;
}
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from < 0 || len <= 0) {
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+ break;
+ }
+ if (int(current) - len < 0) {
+ pc = byteCode + Load32Aligned(pc + 4);
+ break;
+ }
+ if (CaseInsensitiveCompareStrings(chars + from, chars + int(current) - len, len * sizeof(CharT))) {
+ current -= len;
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+ } else {
+ pc = byteCode + Load32Aligned(pc + 4);
+ }
+ break;
+
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_UNICODE) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from < 0 || len <= 0) {
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+ break;
+ }
+ if (int(current) - len < 0) {
+ pc = byteCode + Load32Aligned(pc + 4);
+ break;
+ }
+ if (CaseInsensitiveCompareUCStrings(chars + from, chars + int(current) - len, len * sizeof(CharT))) {
+ current -= len;
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+ } else {
+ pc = byteCode + Load32Aligned(pc + 4);
+ }
+ break;
+
+ }
BYTECODE(CHECK_AT_START)
if (current == 0)
pc = byteCode + Load32Aligned(pc + 4);
@@ -472,7 +536,7 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
pc += BC_CHECK_AT_START_LENGTH;
break;
BYTECODE(CHECK_NOT_AT_START)
- if (current == 0)
+ if (current + (insn >> BYTECODE_SHIFT) == 0)
pc += BC_CHECK_NOT_AT_START_LENGTH;
else
pc = byteCode + Load32Aligned(pc + 4);
diff --git a/js/src/irregexp/RegExpMacroAssembler.cpp b/js/src/irregexp/RegExpMacroAssembler.cpp
index d66d0d204..6b1ceba8a 100644
--- a/js/src/irregexp/RegExpMacroAssembler.cpp
+++ b/js/src/irregexp/RegExpMacroAssembler.cpp
@@ -226,32 +226,37 @@ InterpretedRegExpMacroAssembler::CheckGreedyLoop(jit::Label* on_tos_equals_curre
}
void
-InterpretedRegExpMacroAssembler::CheckNotAtStart(jit::Label* on_not_at_start)
+InterpretedRegExpMacroAssembler::CheckNotAtStart(int cp_offset, jit::Label* on_not_at_start)
{
- Emit(BC_CHECK_NOT_AT_START, 0);
+ Emit(BC_CHECK_NOT_AT_START, cp_offset);
EmitOrLink(on_not_at_start);
}
void
-InterpretedRegExpMacroAssembler::CheckNotBackReference(int start_reg, jit::Label* on_no_match)
+InterpretedRegExpMacroAssembler::CheckNotBackReference(int start_reg, bool read_backward,
+ jit::Label* on_no_match)
{
MOZ_ASSERT(start_reg >= 0);
MOZ_ASSERT(start_reg <= kMaxRegister);
- Emit(BC_CHECK_NOT_BACK_REF, start_reg);
+ Emit(read_backward ? BC_CHECK_NOT_BACK_REF_BACKWARD : BC_CHECK_NOT_BACK_REF,
+ start_reg);
EmitOrLink(on_no_match);
}
void
InterpretedRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg,
+ bool read_backward,
jit::Label* on_no_match,
bool unicode)
{
MOZ_ASSERT(start_reg >= 0);
MOZ_ASSERT(start_reg <= kMaxRegister);
if (unicode)
- Emit(BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE, start_reg);
+ Emit(read_backward ? BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_UNICODE : BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE,
+ start_reg);
else
- Emit(BC_CHECK_NOT_BACK_REF_NO_CASE, start_reg);
+ Emit(read_backward ? BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD : BC_CHECK_NOT_BACK_REF_NO_CASE,
+ start_reg);
EmitOrLink(on_no_match);
}
diff --git a/js/src/irregexp/RegExpMacroAssembler.h b/js/src/irregexp/RegExpMacroAssembler.h
index dca2edf90..c5def92f2 100644
--- a/js/src/irregexp/RegExpMacroAssembler.h
+++ b/js/src/irregexp/RegExpMacroAssembler.h
@@ -110,10 +110,10 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
virtual void CheckCharacterGT(char16_t limit, jit::Label* on_greater) = 0;
virtual void CheckCharacterLT(char16_t limit, jit::Label* on_less) = 0;
virtual void CheckGreedyLoop(jit::Label* on_tos_equals_current_position) = 0;
- virtual void CheckNotAtStart(jit::Label* on_not_at_start) = 0;
- virtual void CheckNotBackReference(int start_reg, jit::Label* on_no_match) = 0;
- virtual void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match,
- bool unicode) = 0;
+ virtual void CheckNotAtStart(int cp_offset, jit::Label* on_not_at_start) = 0;
+ virtual void CheckNotBackReference(int start_reg, bool read_backward, jit::Label* on_no_match) = 0;
+ virtual void CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward,
+ jit::Label* on_no_match, bool unicode) = 0;
// Check the current character for a match with a literal character. If we
// fail to match then goto the on_failure label. End of input always
@@ -245,9 +245,10 @@ class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler final : public RegExpMacro
void CheckCharacterGT(char16_t limit, jit::Label* on_greater);
void CheckCharacterLT(char16_t limit, jit::Label* on_less);
void CheckGreedyLoop(jit::Label* on_tos_equals_current_position);
- void CheckNotAtStart(jit::Label* on_not_at_start);
- void CheckNotBackReference(int start_reg, jit::Label* on_no_match);
- void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match, bool unicode);
+ void CheckNotAtStart(int cp_offset, jit::Label* on_not_at_start);
+ void CheckNotBackReference(int start_reg, bool read_backward, jit::Label* on_no_match);
+ void CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward,
+ jit::Label* on_no_match, bool unicode);
void CheckNotCharacter(unsigned c, jit::Label* on_not_equal);
void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, jit::Label* on_not_equal);
void CheckNotCharacterAfterMinusAnd(char16_t c, char16_t minus, char16_t and_with,
diff --git a/js/src/irregexp/RegExpParser.cpp b/js/src/irregexp/RegExpParser.cpp
index 8bd88047a..1ad044e8e 100644
--- a/js/src/irregexp/RegExpParser.cpp
+++ b/js/src/irregexp/RegExpParser.cpp
@@ -222,11 +222,12 @@ RegExpBuilder::AddQuantifierToAtom(int min, int max,
template <typename CharT>
RegExpParser<CharT>::RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc,
const CharT* chars, const CharT* end, bool multiline_mode,
- bool unicode, bool ignore_case)
+ bool unicode, bool ignore_case, bool dotall)
: ts(ts),
alloc(alloc),
captures_(nullptr),
next_pos_(chars),
+ captures_started_(0),
end_(end),
current_(kEndMarker),
capture_count_(0),
@@ -234,6 +235,7 @@ RegExpParser<CharT>::RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc,
multiline_(multiline_mode),
unicode_(unicode),
ignore_case_(ignore_case),
+ dotall_(dotall),
simple_(false),
contains_anchor_(false),
is_scanned_for_captures_(false)
@@ -418,7 +420,8 @@ RangeAtom(LifoAlloc* alloc, char16_t from, char16_t to)
static inline RegExpTree*
NegativeLookahead(LifoAlloc* alloc, char16_t from, char16_t to)
{
- return alloc->newInfallible<RegExpLookahead>(RangeAtom(alloc, from, to), false, 0, 0);
+ return alloc->newInfallible<RegExpLookaround>(RangeAtom(alloc, from, to), false,
+ 0, 0, RegExpLookaround::LOOKAHEAD);
}
static bool
@@ -1213,6 +1216,38 @@ RegExpParser<CharT>::ParseBackReferenceIndex(int* index_out)
return true;
}
+template <typename CharT>
+RegExpCapture*
+RegExpParser<CharT>::GetCapture(int index) {
+ // The index for the capture groups are one-based. Its index in the list is
+ // zero-based.
+ int known_captures =
+ is_scanned_for_captures_ ? capture_count_ : captures_started_;
+ MOZ_ASSERT(index <= known_captures);
+ if (captures_ == NULL) {
+ captures_ = alloc->newInfallible<RegExpCaptureVector>(*alloc);
+ }
+ while ((int)captures_->length() < known_captures) {
+ RegExpCapture* capture = alloc->newInfallible<RegExpCapture>(nullptr, captures_->length() + 1);
+ captures_->append(capture);
+ }
+ return (*captures_)[index - 1];
+}
+
+
+template <typename CharT>
+bool
+RegExpParser<CharT>::RegExpParserState::IsInsideCaptureGroup(int index) {
+ for (RegExpParserState* s = this; s != NULL; s = s->previous_state()) {
+ if (s->group_type() != CAPTURE) continue;
+ // Return true if we found the matching capture index.
+ if (index == s->capture_index()) return true;
+ // Abort if index is larger than what has been parsed up till this state.
+ if (index > s->capture_index()) return false;
+ }
+ return false;
+}
+
// QuantifierPrefix ::
// { DecimalDigits }
// { DecimalDigits , }
@@ -1350,7 +1385,7 @@ UnicodeEverythingAtom(LifoAlloc* alloc)
{
RegExpBuilder* builder = alloc->newInfallible<RegExpBuilder>(alloc);
- // everything except \x0a, \x0d, \u2028 and \u2029
+ // Everything except \x0a, \x0d, \u2028 and \u2029
CharacterRangeVector* ranges = alloc->newInfallible<CharacterRangeVector>(*alloc);
ranges->append(CharacterRange::Range(0x0, 0x09));
@@ -1380,6 +1415,38 @@ UnicodeEverythingAtom(LifoAlloc* alloc)
return builder->ToRegExp();
}
+static inline RegExpTree*
+UnicodeDotAllAtom(LifoAlloc* alloc)
+{
+ RegExpBuilder* builder = alloc->newInfallible<RegExpBuilder>(alloc);
+
+ // Full range excluding surrogates because /s was specified
+
+ CharacterRangeVector* ranges = alloc->newInfallible<CharacterRangeVector>(*alloc);
+ ranges->append(CharacterRange::Range(0x0, unicode::LeadSurrogateMin - 1));
+ ranges->append(CharacterRange::Range(unicode::TrailSurrogateMax + 1, unicode::UTF16Max));
+ builder->AddAtom(alloc->newInfallible<RegExpCharacterClass>(ranges, false));
+
+ builder->NewAlternative();
+
+ builder->AddAtom(RangeAtom(alloc, unicode::LeadSurrogateMin, unicode::LeadSurrogateMax));
+ builder->AddAtom(NegativeLookahead(alloc, unicode::TrailSurrogateMin,
+ unicode::TrailSurrogateMax));
+
+ builder->NewAlternative();
+
+ builder->AddAssertion(alloc->newInfallible<RegExpAssertion>(
+ RegExpAssertion::NOT_AFTER_LEAD_SURROGATE));
+ builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, unicode::TrailSurrogateMax));
+
+ builder->NewAlternative();
+
+ builder->AddAtom(RangeAtom(alloc, unicode::LeadSurrogateMin, unicode::LeadSurrogateMax));
+ builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, unicode::TrailSurrogateMax));
+
+ return builder->ToRegExp();
+}
+
RegExpTree*
UnicodeCharacterClassEscapeAtom(LifoAlloc* alloc, char16_t char_class, bool ignore_case)
{
@@ -1423,24 +1490,24 @@ RegExpTree*
RegExpParser<CharT>::ParseDisjunction()
{
// Used to store current state while parsing subexpressions.
- RegExpParserState initial_state(alloc, nullptr, INITIAL, 0);
- RegExpParserState* stored_state = &initial_state;
+ RegExpParserState initial_state(alloc, nullptr, INITIAL, RegExpLookaround::LOOKAHEAD, 0);
+ RegExpParserState* state = &initial_state;
// Cache the builder in a local variable for quick access.
RegExpBuilder* builder = initial_state.builder();
while (true) {
switch (current()) {
case kEndMarker:
- if (stored_state->IsSubexpression()) {
+ if (state->IsSubexpression()) {
// Inside a parenthesized group when hitting end of input.
return ReportError(JSMSG_MISSING_PAREN);
}
- MOZ_ASSERT(INITIAL == stored_state->group_type());
+ MOZ_ASSERT(INITIAL == state->group_type());
// Parsing completed successfully.
return builder->ToRegExp();
case ')': {
- if (!stored_state->IsSubexpression())
+ if (!state->IsSubexpression())
return ReportError(JSMSG_UNMATCHED_RIGHT_PAREN);
- MOZ_ASSERT(INITIAL != stored_state->group_type());
+ MOZ_ASSERT(INITIAL != state->group_type());
Advance();
// End disjunction parsing and convert builder content to new single
@@ -1449,29 +1516,30 @@ RegExpParser<CharT>::ParseDisjunction()
int end_capture_index = captures_started();
- int capture_index = stored_state->capture_index();
- SubexpressionType group_type = stored_state->group_type();
-
- // Restore previous state.
- stored_state = stored_state->previous_state();
- builder = stored_state->builder();
+ int capture_index = state->capture_index();
+ SubexpressionType group_type = state->group_type();
// Build result of subexpression.
if (group_type == CAPTURE) {
- RegExpCapture* capture = alloc->newInfallible<RegExpCapture>(body, capture_index);
- (*captures_)[capture_index - 1] = capture;
+ RegExpCapture* capture = GetCapture(capture_index);
+ capture->set_body(body);
body = capture;
} else if (group_type != GROUPING) {
- MOZ_ASSERT(group_type == POSITIVE_LOOKAHEAD ||
- group_type == NEGATIVE_LOOKAHEAD);
- bool is_positive = (group_type == POSITIVE_LOOKAHEAD);
- body = alloc->newInfallible<RegExpLookahead>(body,
+ MOZ_ASSERT(group_type == POSITIVE_LOOKAROUND ||
+ group_type == NEGATIVE_LOOKAROUND);
+ bool is_positive = (group_type == POSITIVE_LOOKAROUND);
+ body = alloc->newInfallible<RegExpLookaround>(body,
is_positive,
end_capture_index - capture_index,
- capture_index);
+ capture_index,
+ state->lookaround_type());
}
+
+ // Restore previous state.
+ state = state->previous_state();
+ builder = state->builder();
builder->AddAtom(body);
- if (unicode_ && (group_type == POSITIVE_LOOKAHEAD || group_type == NEGATIVE_LOOKAHEAD))
+ if (unicode_ && (group_type == POSITIVE_LOOKAROUND || group_type == NEGATIVE_LOOKAROUND))
continue;
// For compatability with JSC and ES3, we allow quantifiers after
// lookaheads, and break in all cases.
@@ -1506,19 +1574,32 @@ RegExpParser<CharT>::ParseDisjunction()
}
case '.': {
Advance();
- // everything except \x0a, \x0d, \u2028 and \u2029
+
if (unicode_) {
- builder->AddAtom(UnicodeEverythingAtom(alloc));
+ if (dotall_) {
+ // Everything
+ builder->AddAtom(UnicodeDotAllAtom(alloc));
+ } else {
+ // Everything except \x0a, \x0d, \u2028 and \u2029
+ builder->AddAtom(UnicodeEverythingAtom(alloc));
+ }
break;
}
CharacterRangeVector* ranges = alloc->newInfallible<CharacterRangeVector>(*alloc);
- CharacterRange::AddClassEscape(alloc, '.', ranges);
+ if (dotall_) {
+ // Everything
+ CharacterRange::AddClassEscape(alloc, '*', ranges);
+ } else {
+ // Everything except \x0a, \x0d, \u2028 and \u2029
+ CharacterRange::AddClassEscape(alloc, '.', ranges);
+ }
RegExpTree* atom = alloc->newInfallible<RegExpCharacterClass>(ranges, false);
builder->AddAtom(atom);
break;
}
case '(': {
SubexpressionType subexpr_type = CAPTURE;
+ RegExpLookaround::Type lookaround_type = state->lookaround_type();
Advance();
if (current() == '?') {
switch (Next()) {
@@ -1526,26 +1607,39 @@ RegExpParser<CharT>::ParseDisjunction()
subexpr_type = GROUPING;
break;
case '=':
- subexpr_type = POSITIVE_LOOKAHEAD;
+ lookaround_type = RegExpLookaround::LOOKAHEAD;
+ subexpr_type = POSITIVE_LOOKAROUND;
break;
case '!':
- subexpr_type = NEGATIVE_LOOKAHEAD;
+ lookaround_type = RegExpLookaround::LOOKAHEAD;
+ subexpr_type = NEGATIVE_LOOKAROUND;
break;
+ case '<':
+ Advance();
+ lookaround_type = RegExpLookaround::LOOKBEHIND;
+ if (Next() == '=') {
+ subexpr_type = POSITIVE_LOOKAROUND;
+ break;
+ } else if (Next() == '!') {
+ subexpr_type = NEGATIVE_LOOKAROUND;
+ break;
+ }
+ // We didn't get a positive or negative after '<'.
+ // That's an error.
+ return ReportError(JSMSG_INVALID_GROUP);
default:
return ReportError(JSMSG_INVALID_GROUP);
}
Advance(2);
} else {
- if (captures_ == nullptr)
- captures_ = alloc->newInfallible<RegExpCaptureVector>(*alloc);
if (captures_started() >= kMaxCaptures)
return ReportError(JSMSG_TOO_MANY_PARENS);
- captures_->append((RegExpCapture*) nullptr);
+ captures_started_++;
}
// Store current state and begin new disjunction parsing.
- stored_state = alloc->newInfallible<RegExpParserState>(alloc, stored_state, subexpr_type,
- captures_started());
- builder = stored_state->builder();
+ state = alloc->newInfallible<RegExpParserState>(alloc, state, subexpr_type,
+ lookaround_type, captures_started_);
+ builder = state->builder();
continue;
}
case '[': {
@@ -1600,19 +1694,18 @@ RegExpParser<CharT>::ParseDisjunction()
case '7': case '8': case '9': {
int index = 0;
if (ParseBackReferenceIndex(&index)) {
- RegExpCapture* capture = nullptr;
- if (captures_ != nullptr && index <= (int) captures_->length()) {
- capture = (*captures_)[index - 1];
- }
- if (capture == nullptr) {
- builder->AddEmpty();
- break;
+ if (state->IsInsideCaptureGroup(index)) {
+ // The backreference is inside the capture group it refers to.
+ // Nothing can possibly have been captured yet.
+ builder->AddEmpty();
+ } else {
+ RegExpCapture* capture = GetCapture(index);
+ RegExpTree* atom = alloc->newInfallible<RegExpBackReference>(capture);
+ if (unicode_)
+ builder->AddAtom(UnicodeBackReferenceAtom(alloc, atom));
+ else
+ builder->AddAtom(atom);
}
- RegExpTree* atom = alloc->newInfallible<RegExpBackReference>(capture);
- if (unicode_)
- builder->AddAtom(UnicodeBackReferenceAtom(alloc, atom));
- else
- builder->AddAtom(atom);
break;
}
if (unicode_)
@@ -1832,7 +1925,7 @@ template <typename CharT>
static bool
ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, size_t length,
bool multiline, bool match_only, bool unicode, bool ignore_case,
- bool global, bool sticky, RegExpCompileData* data)
+ bool global, bool sticky, bool dotall, RegExpCompileData* data)
{
if (match_only) {
// Try to strip a leading '.*' from the RegExp, but only if it is not
@@ -1859,7 +1952,7 @@ ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, si
}
}
- RegExpParser<CharT> parser(ts, &alloc, chars, chars + length, multiline, unicode, ignore_case);
+ RegExpParser<CharT> parser(ts, &alloc, chars, chars + length, multiline, unicode, ignore_case, dotall);
data->tree = parser.ParsePattern();
if (!data->tree)
return false;
@@ -1873,33 +1966,33 @@ ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, si
bool
irregexp::ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str,
bool multiline, bool match_only, bool unicode, bool ignore_case,
- bool global, bool sticky, RegExpCompileData* data)
+ bool global, bool sticky, bool dotall, RegExpCompileData* data)
{
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? ::ParsePattern(ts, alloc, str->latin1Chars(nogc), str->length(),
- multiline, match_only, unicode, ignore_case, global, sticky, data)
+ multiline, match_only, unicode, ignore_case, global, sticky, dotall, data)
: ::ParsePattern(ts, alloc, str->twoByteChars(nogc), str->length(),
- multiline, match_only, unicode, ignore_case, global, sticky, data);
+ multiline, match_only, unicode, ignore_case, global, sticky, dotall, data);
}
template <typename CharT>
static bool
ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, size_t length,
- bool unicode)
+ bool unicode, bool dotall)
{
LifoAllocScope scope(&alloc);
- RegExpParser<CharT> parser(ts, &alloc, chars, chars + length, false, unicode, false);
+ RegExpParser<CharT> parser(ts, &alloc, chars, chars + length, false, unicode, dotall, false);
return parser.ParsePattern() != nullptr;
}
bool
irregexp::ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str,
- bool unicode)
+ bool unicode, bool dotall)
{
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
- ? ::ParsePatternSyntax(ts, alloc, str->latin1Chars(nogc), str->length(), unicode)
- : ::ParsePatternSyntax(ts, alloc, str->twoByteChars(nogc), str->length(), unicode);
+ ? ::ParsePatternSyntax(ts, alloc, str->latin1Chars(nogc), str->length(), unicode, dotall)
+ : ::ParsePatternSyntax(ts, alloc, str->twoByteChars(nogc), str->length(), unicode, dotall);
}
diff --git a/js/src/irregexp/RegExpParser.h b/js/src/irregexp/RegExpParser.h
index 0a7e61858..ee57f0436 100644
--- a/js/src/irregexp/RegExpParser.h
+++ b/js/src/irregexp/RegExpParser.h
@@ -44,11 +44,11 @@ namespace irregexp {
bool
ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str,
bool multiline, bool match_only, bool unicode, bool ignore_case,
- bool global, bool sticky, RegExpCompileData* data);
+ bool global, bool sticky, bool dotall, RegExpCompileData* data);
bool
ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str,
- bool unicode);
+ bool unicode, bool dotall);
// A BufferedVector is an automatically growing list, just like (and backed
// by) a Vector, that is optimized for the case of adding and removing
@@ -178,7 +178,7 @@ class RegExpParser
public:
RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc,
const CharT* chars, const CharT* end, bool multiline_mode, bool unicode,
- bool ignore_case);
+ bool ignore_case, bool dotall);
RegExpTree* ParsePattern();
RegExpTree* ParseDisjunction();
@@ -229,7 +229,7 @@ class RegExpParser
bool simple() { return simple_; }
bool contains_anchor() { return contains_anchor_; }
void set_contains_anchor() { contains_anchor_ = true; }
- int captures_started() { return captures_ == nullptr ? 0 : captures_->length(); }
+ int captures_started() { return captures_started_; }
const CharT* position() { return next_pos_ - 1; }
static const int kMaxCaptures = 1 << 16;
@@ -239,8 +239,8 @@ class RegExpParser
enum SubexpressionType {
INITIAL,
CAPTURE, // All positive values represent captures.
- POSITIVE_LOOKAHEAD,
- NEGATIVE_LOOKAHEAD,
+ POSITIVE_LOOKAROUND,
+ NEGATIVE_LOOKAROUND,
GROUPING
};
@@ -249,10 +249,12 @@ class RegExpParser
RegExpParserState(LifoAlloc* alloc,
RegExpParserState* previous_state,
SubexpressionType group_type,
+ RegExpLookaround::Type lookaround_type,
int disjunction_capture_index)
: previous_state_(previous_state),
builder_(alloc->newInfallible<RegExpBuilder>(alloc)),
group_type_(group_type),
+ lookaround_type_(lookaround_type),
disjunction_capture_index_(disjunction_capture_index)
{}
// Parser state of containing expression, if any.
@@ -262,11 +264,16 @@ class RegExpParser
RegExpBuilder* builder() { return builder_; }
// Type of regexp being parsed (parenthesized group or entire regexp).
SubexpressionType group_type() { return group_type_; }
+ // Lookahead or Lookbehind.
+ RegExpLookaround::Type lookaround_type() { return lookaround_type_; }
// Index in captures array of first capture in this sub-expression, if any.
// Also the capture index of this sub-expression itself, if group_type
// is CAPTURE.
int capture_index() { return disjunction_capture_index_; }
+ // Check whether the parser is inside a capture group with the given index.
+ bool IsInsideCaptureGroup(int index);
+
private:
// Linked list implementation of stack of states.
RegExpParserState* previous_state_;
@@ -274,10 +281,15 @@ class RegExpParser
RegExpBuilder* builder_;
// Stored disjunction type (capture, look-ahead or grouping), if any.
SubexpressionType group_type_;
+ // Stored read direction.
+ RegExpLookaround::Type lookaround_type_;
// Stored disjunction's capture index (if any).
int disjunction_capture_index_;
};
+ // Return the 1-indexed RegExpCapture object, allocate if necessary.
+ RegExpCapture* GetCapture(int index);
+
widechar current() { return current_; }
bool has_more() { return has_more_; }
bool has_next() { return next_pos_ < end_; }
@@ -294,12 +306,14 @@ class RegExpParser
const CharT* next_pos_;
const CharT* end_;
widechar current_;
+ int captures_started_;
// The capture count is only valid after we have scanned for captures.
int capture_count_;
bool has_more_;
bool multiline_;
bool unicode_;
bool ignore_case_;
+ bool dotall_;
bool simple_;
bool contains_anchor_;
bool is_scanned_for_captures_;
diff --git a/js/src/jit-test/modules/empty.js b/js/src/jit-test/modules/empty.js
new file mode 100644
index 000000000..bd9ec079d
--- /dev/null
+++ b/js/src/jit-test/modules/empty.js
@@ -0,0 +1 @@
+// Intentionally empty.
diff --git a/js/src/jit-test/modules/export-circular-nonexisting-binding-1.js b/js/src/jit-test/modules/export-circular-nonexisting-binding-1.js
new file mode 100644
index 000000000..2b91b6a28
--- /dev/null
+++ b/js/src/jit-test/modules/export-circular-nonexisting-binding-1.js
@@ -0,0 +1,4 @@
+import "export-circular-nonexisting-binding-2.js";
+
+export* from "empty.js";
+export {x} from "empty.js";
diff --git a/js/src/jit-test/modules/export-circular-nonexisting-binding-2.js b/js/src/jit-test/modules/export-circular-nonexisting-binding-2.js
new file mode 100644
index 000000000..ba7dcc1b4
--- /dev/null
+++ b/js/src/jit-test/modules/export-circular-nonexisting-binding-2.js
@@ -0,0 +1 @@
+export {x} from "export-circular-nonexisting-binding-1.js";
diff --git a/js/src/jit-test/modules/export-star-circular-1.js b/js/src/jit-test/modules/export-star-circular-1.js
new file mode 100644
index 000000000..9a0771b02
--- /dev/null
+++ b/js/src/jit-test/modules/export-star-circular-1.js
@@ -0,0 +1 @@
+export* from "export-star-circular-2.js";
diff --git a/js/src/jit-test/modules/export-star-circular-2.js b/js/src/jit-test/modules/export-star-circular-2.js
new file mode 100644
index 000000000..b273d9cef
--- /dev/null
+++ b/js/src/jit-test/modules/export-star-circular-2.js
@@ -0,0 +1,3 @@
+export {y as x} from "export-star-circular-1.js";
+
+export var y = "pass";
diff --git a/js/src/jit-test/tests/auto-regress/bug466654.js b/js/src/jit-test/tests/auto-regress/bug466654.js
deleted file mode 100644
index 6c82c425b..000000000
--- a/js/src/jit-test/tests/auto-regress/bug466654.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// |jit-test| error:TypeError
-
-// Binary: cache/js-dbg-32-29add08d84ae-linux
-// Flags: -j
-//
-this.watch('y', /x/g );
-for each (y in ['q', 'q', 'q']) continue;
-gc();
diff --git a/js/src/jit-test/tests/auto-regress/bug516897.js b/js/src/jit-test/tests/auto-regress/bug516897.js
deleted file mode 100644
index e3caf4e6e..000000000
--- a/js/src/jit-test/tests/auto-regress/bug516897.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// Binary: cache/js-dbg-64-38754465ffde-linux
-// Flags:
-//
-this.__defineSetter__("x", gc);
-this.watch("x",function(){return});
-x = 3;
diff --git a/js/src/jit-test/tests/auto-regress/bug537854.js b/js/src/jit-test/tests/auto-regress/bug537854.js
deleted file mode 100644
index 80fb3c14a..000000000
--- a/js/src/jit-test/tests/auto-regress/bug537854.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// Binary: cache/js-dbg-64-9d51f2a931f7-linux
-// Flags:
-//
-({x:function(){}}).watch('x',function(){});
diff --git a/js/src/jit-test/tests/auto-regress/bug560796.js b/js/src/jit-test/tests/auto-regress/bug560796.js
deleted file mode 100644
index 4ab93567e..000000000
--- a/js/src/jit-test/tests/auto-regress/bug560796.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Binary: cache/js-dbg-64-a6d7a5677b4c-linux
-// Flags:
-//
-this.__defineSetter__("x", function(){})
-this.watch("x", "".localeCompare)
-window = x
-Object.defineProperty(this, "x", ({
- set: window
-}))
diff --git a/js/src/jit-test/tests/auto-regress/bug638735.js b/js/src/jit-test/tests/auto-regress/bug638735.js
index 63071aa7c..c941f5369 100644
--- a/js/src/jit-test/tests/auto-regress/bug638735.js
+++ b/js/src/jit-test/tests/auto-regress/bug638735.js
@@ -4,7 +4,6 @@
var o9 = Function.prototype;
var o13 = Array;
function f5(o) {
-o.watch('p3', function() {});
ox1 = new Proxy(o, {});
}
f5(o9);
diff --git a/js/src/jit-test/tests/auto-regress/bug639413.js b/js/src/jit-test/tests/auto-regress/bug639413.js
deleted file mode 100644
index d8dd58eaf..000000000
--- a/js/src/jit-test/tests/auto-regress/bug639413.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// |jit-test| error:TypeError
-
-// Binary: cache/js-dbg-32-1c8e91b2e3a4-linux
-// Flags:
-//
-a = evalcx("lazy");
-a.watch("x", function() {});
-({}).watch("x", function() {});
-a.__defineGetter__("y", {});
diff --git a/js/src/jit-test/tests/auto-regress/bug698899.js b/js/src/jit-test/tests/auto-regress/bug698899.js
deleted file mode 100644
index 644f45ec2..000000000
--- a/js/src/jit-test/tests/auto-regress/bug698899.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Binary: cache/js-dbg-32-f951e9151626-linux
-// Flags: -m -n
-//
-o = evalcx("lazy").__proto__
-gc()
-try {
- o.watch()
-} catch (e) {}
-o.constructor()
diff --git a/js/src/jit-test/tests/auto-regress/bug746397.js b/js/src/jit-test/tests/auto-regress/bug746397.js
deleted file mode 100644
index d915ca7bb..000000000
--- a/js/src/jit-test/tests/auto-regress/bug746397.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// |jit-test| error:ReferenceError
-
-// Binary: cache/js-dbg-64-67bf9a4a1f77-linux
-// Flags: --ion-eager
-//
-
-(function () {
- var a = ['x', 'y'];
- obj.watch(a[+("0")], counter);
-})();
diff --git a/js/src/jit-test/tests/auto-regress/bug769192.js b/js/src/jit-test/tests/auto-regress/bug769192.js
deleted file mode 100644
index 531e37912..000000000
--- a/js/src/jit-test/tests/auto-regress/bug769192.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// |jit-test| error:TypeError
-
-// Binary: cache/js-dbg-64-bf8f2961d0cc-linux
-// Flags:
-//
-Object.watch.call(new Uint8ClampedArray, "length", function() {});
diff --git a/js/src/jit-test/tests/baseline/bug843444.js b/js/src/jit-test/tests/baseline/bug843444.js
deleted file mode 100644
index 3a77402ac..000000000
--- a/js/src/jit-test/tests/baseline/bug843444.js
+++ /dev/null
@@ -1,8 +0,0 @@
-gczeal(8, 1)
-function recurse(x) {
- recurse;
- if (x < 20)
- recurse(x + 1);
-};
-this.watch(5, (function () {}))
-recurse(0)
diff --git a/js/src/jit-test/tests/basic/bug1220766.js b/js/src/jit-test/tests/basic/bug1220766.js
deleted file mode 100644
index fca11eafe..000000000
--- a/js/src/jit-test/tests/basic/bug1220766.js
+++ /dev/null
@@ -1,3 +0,0 @@
-iter = getSelfHostedValue("CreateListIterator")([]);
-iter.next();
-iter.next();
diff --git a/js/src/jit-test/tests/basic/bug510437.js b/js/src/jit-test/tests/basic/bug510437.js
deleted file mode 100644
index 2418b9b11..000000000
--- a/js/src/jit-test/tests/basic/bug510437.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Don't crash or assert.
-
-var d;
-this.watch("d", eval);
-(function () {
- (eval("\
- (function () {\
- for (let x = 0; x < 2; ++x) {\
- d = x\
- }\
- })\
-"))()
-})()
diff --git a/js/src/jit-test/tests/basic/bug605015.js b/js/src/jit-test/tests/basic/bug605015.js
deleted file mode 100644
index a35f7b6c7..000000000
--- a/js/src/jit-test/tests/basic/bug605015.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// |jit-test| error: TypeError
-// don't assert
-
-print(this.watch("x",
-function() {
- Object.defineProperty(this, "x", ({
- get: (Int8Array)
- }))
-}))(x = /x/)
diff --git a/js/src/jit-test/tests/basic/bug631305.js b/js/src/jit-test/tests/basic/bug631305.js
deleted file mode 100644
index b0cbbbb24..000000000
--- a/js/src/jit-test/tests/basic/bug631305.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var n = 0;
-var a = [];
-for (var i = 0; i < 20; i++)
- a[i] = {};
-a[18].watch("p", function () { n++; });
-delete a[18].p;
-for (var i = 0; i < 20; i++)
- a[i].p = 0;
-assertEq(n, 1);
diff --git a/js/src/jit-test/tests/basic/bug662562.js b/js/src/jit-test/tests/basic/bug662562.js
deleted file mode 100644
index 45b48589a..000000000
--- a/js/src/jit-test/tests/basic/bug662562.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// |jit-test| error: TypeError
-function f(o) {
- o.watch("x", this);
-}
-var c = evalcx("");
-f(c);
diff --git a/js/src/jit-test/tests/basic/bug690292.js b/js/src/jit-test/tests/basic/bug690292.js
deleted file mode 100644
index 43ab56dd7..000000000
--- a/js/src/jit-test/tests/basic/bug690292.js
+++ /dev/null
@@ -1,12 +0,0 @@
-
-done = false;
-try {
- function x() {}
- print(this.watch("d", Object.create))
- var d = {}
-} catch (e) {}
-try {
- eval("d = ''")
- done = true;
-} catch (e) {}
-assertEq(done, false);
diff --git a/js/src/jit-test/tests/basic/bug696748.js b/js/src/jit-test/tests/basic/bug696748.js
index fe171f976..33fb4d52f 100644
--- a/js/src/jit-test/tests/basic/bug696748.js
+++ b/js/src/jit-test/tests/basic/bug696748.js
@@ -1,6 +1,3 @@
-try {
-this.watch("b", "".substring);
-} catch(exc1) {}
eval("\
var URI = '';\
test();\
diff --git a/js/src/jit-test/tests/basic/bug831846.js b/js/src/jit-test/tests/basic/bug831846.js
deleted file mode 100644
index 30bb3aa86..000000000
--- a/js/src/jit-test/tests/basic/bug831846.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// |jit-test| error:TypeError
-
-evalcx('').watch("", /()/);
diff --git a/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js b/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js
deleted file mode 100644
index c22eabed0..000000000
--- a/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var o = {};
-o.watch("p", function() { });
-
-for (var i = 0; i < 10; i++) {
- o.p = 123;
- delete o.p;
-}
diff --git a/js/src/jit-test/tests/basic/testBug566556.js b/js/src/jit-test/tests/basic/testBug566556.js
deleted file mode 100644
index 244be57d2..000000000
--- a/js/src/jit-test/tests/basic/testBug566556.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var msg = "";
-try {
- this.__defineSetter__('x', Object.create);
- this.watch('x', function() {});
- x = 3;
-} catch (e) {
- msg = e.toString();
-}
-assertEq(msg, "TypeError: undefined is not an object or null");
diff --git a/js/src/jit-test/tests/basic/testBug578044.js b/js/src/jit-test/tests/basic/testBug578044.js
deleted file mode 100644
index c5b811dc9..000000000
--- a/js/src/jit-test/tests/basic/testBug578044.js
+++ /dev/null
@@ -1,13 +0,0 @@
-this.watch("x", Object.create)
-try {
- (function() {
- this.__defineGetter__("x",
- function() {
- return this
- })
- })()
-} catch(e) {}
-Object.defineProperty(x, "x", ({
- set: Uint16Array
-}))
-
diff --git a/js/src/jit-test/tests/basic/testBug584650.js b/js/src/jit-test/tests/basic/testBug584650.js
deleted file mode 100644
index b6c9d8ab7..000000000
--- a/js/src/jit-test/tests/basic/testBug584650.js
+++ /dev/null
@@ -1,9 +0,0 @@
-if (typeof gczeal != "function")
- gczeal = function() {}
-
-// don't crash
-x = (evalcx('lazy'))
-x.watch("", function () {})
-gczeal(1)
-for (w in x) {}
-
diff --git a/js/src/jit-test/tests/basic/testBug780288-1.js b/js/src/jit-test/tests/basic/testBug780288-1.js
deleted file mode 100644
index 90746a04a..000000000
--- a/js/src/jit-test/tests/basic/testBug780288-1.js
+++ /dev/null
@@ -1,20 +0,0 @@
-s = newGlobal()
-try {
- evalcx("\
- Object.defineProperty(this,\"i\",{enumerable:true,get:function(){t}});\
- for each(y in this)true\
- ", s)
-} catch (e) {}
-try {
- evalcx("\
- for(z=0,(7).watch(\"\",eval);;g){\
- if(z=1){({t:function(){}})\
- }\
- ", s)
-} catch (e) {}
-try {
- evalcx("\
- Object.defineProperty(this,\"g2\",{get:function(){return this}});\
- g2.y()\
- ", s)
-} catch (e) {}
diff --git a/js/src/jit-test/tests/basic/testBug780288-2.js b/js/src/jit-test/tests/basic/testBug780288-2.js
deleted file mode 100644
index 8c4c1737c..000000000
--- a/js/src/jit-test/tests/basic/testBug780288-2.js
+++ /dev/null
@@ -1,20 +0,0 @@
-s = newGlobal()
-try {
- evalcx("\
- Object.defineProperty(this,\"i\",{enumerable:true,get:function(){t}});\
- for each(y in this)true\
- ", s)
-} catch (e) {}
-try {
- evalcx("\
- for(z=0,(7).watch(\"\",eval);;g){\
- if(z=1){({t:function(){}})\
- }\
- ", s)
-} catch (e) {}
-try {
- evalcx("\
- Object.defineProperty(this,\"g2\",{get:function(){return this}});\
- g2.y(\"\")\
- ", s)
-} catch (e) {}
diff --git a/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js b/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js
deleted file mode 100644
index bcd60fd80..000000000
--- a/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js
+++ /dev/null
@@ -1,3 +0,0 @@
-this.__defineSetter__("x", function(){});
-this.watch("x", eval);
-x = 0;
diff --git a/js/src/jit-test/tests/basic/testNonStubGetter.js b/js/src/jit-test/tests/basic/testNonStubGetter.js
deleted file mode 100644
index 58a698eb4..000000000
--- a/js/src/jit-test/tests/basic/testNonStubGetter.js
+++ /dev/null
@@ -1,7 +0,0 @@
-function testNonStubGetter() {
- { let [] = []; (this.watch("x", function(p, o, n) { return /a/g.exec(p, o, n); })); };
- (function () { (eval("(function(){for each (x in [1, 2, 2]);});"))(); })();
- this.unwatch("x");
- return "ok";
-}
-assertEq(testNonStubGetter(), "ok");
diff --git a/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js b/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js
deleted file mode 100644
index 78c281f05..000000000
--- a/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js
+++ /dev/null
@@ -1,7 +0,0 @@
-for (var i = 0; i < 5; ++i) {
- var o = {}
- Object.defineProperty(o, 'x', { value:"cow", writable:false });
- var r = o.watch('x', function() {});
- assertEq(r, undefined);
- o.x = 4;
-}
diff --git a/js/src/jit-test/tests/basic/testTrueShiftTrue.js b/js/src/jit-test/tests/basic/testTrueShiftTrue.js
deleted file mode 100644
index 44c1290d8..000000000
--- a/js/src/jit-test/tests/basic/testTrueShiftTrue.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Test no assert or crash from outer recorders (bug 465145)
-function testBug465145() {
- this.__defineSetter__("x", function(){});
- this.watch("x", function(){});
- y = this;
- for (var z = 0; z < 2; ++z) { x = y };
- this.__defineSetter__("x", function(){});
- for (var z = 0; z < 2; ++z) { x = y };
-}
-
-function testTrueShiftTrue() {
- var a = new Array(5);
- for (var i=0;i<5;++i) a[i] = "" + (true << true);
- return a.join(",");
-}
-assertEq(testTrueShiftTrue(), "2,2,2,2,2");
diff --git a/js/src/jit-test/tests/basic/testWatchRecursion.js b/js/src/jit-test/tests/basic/testWatchRecursion.js
deleted file mode 100644
index e5d5877df..000000000
--- a/js/src/jit-test/tests/basic/testWatchRecursion.js
+++ /dev/null
@@ -1,63 +0,0 @@
-// Test that the watch handler is not called recursively for the same object
-// and property.
-(function() {
- var obj1 = {}, obj2 = {};
- var handler_entry_count = 0;
- var handler_exit_count = 0;
-
- obj1.watch('x', handler);
- obj1.watch('y', handler);
- obj2.watch('x', handler);
- obj1.x = 1;
- assertEq(handler_entry_count, 3);
- assertEq(handler_exit_count, 3);
-
- function handler(id) {
- handler_entry_count++;
- assertEq(handler_exit_count, 0);
- switch (true) {
- case this === obj1 && id === "x":
- assertEq(handler_entry_count, 1);
- obj2.x = 3;
- assertEq(handler_exit_count, 2);
- break;
- case this === obj2 && id === "x":
- assertEq(handler_entry_count, 2);
- obj1.y = 4;
- assertEq(handler_exit_count, 1);
- break;
- default:
- assertEq(this, obj1);
- assertEq(id, "y");
- assertEq(handler_entry_count, 3);
-
- // We expect no more watch handler invocations
- obj1.x = 5;
- obj1.y = 6;
- obj2.x = 7;
- assertEq(handler_exit_count, 0);
- break;
- }
- ++handler_exit_count;
- assertEq(handler_entry_count, 3);
- }
-})();
-
-
-// Test that run-away recursion in watch handlers is properly handled.
-(function() {
- var obj = {};
- var i = 0;
- try {
- handler();
- throw new Error("Unreachable");
- } catch(e) {
- assertEq(e instanceof InternalError, true);
- }
-
- function handler() {
- var prop = "a" + ++i;
- obj.watch(prop, handler);
- obj[prop] = 2;
- }
-})();
diff --git a/js/src/jit-test/tests/ctypes/function-definition.js b/js/src/jit-test/tests/ctypes/function-definition.js
index 4df317a09..5882ba889 100644
--- a/js/src/jit-test/tests/ctypes/function-definition.js
+++ b/js/src/jit-test/tests/ctypes/function-definition.js
@@ -27,7 +27,7 @@ function test() {
let lib;
try {
- lib = ctypes.open(ctypes.libraryName("c"));
+ lib = ctypes.open(ctypes.libraryName("m"));
} catch (e) {
}
if (!lib)
diff --git a/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-async.js b/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-async.js
index d4e7e8576..0b2ee766b 100644
--- a/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-async.js
+++ b/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-async.js
@@ -9,28 +9,6 @@ async function f() {
}
`);
-// To continue testing after uncaught exception, remember the exception and
-// return normal completeion.
-var currentFrame;
-var uncaughtException;
-dbg.uncaughtExceptionHook = function(e) {
- uncaughtException = e;
- return {
- return: currentFrame.eval("({ done: true, value: 'uncaught' })").return
- };
-};
-function testUncaughtException() {
- uncaughtException = undefined;
- var val = g.eval(`
-var val;
-f().then(v => { val = v });
-drainJobQueue();
-val;
-`);
- assertEq(val, "uncaught");
- assertEq(uncaughtException instanceof TypeError, true);
-}
-
// Just continue
dbg.onExceptionUnwind = function(frame) {
return undefined;
@@ -42,83 +20,10 @@ drainJobQueue();
assertEq(exc instanceof ReferenceError, true);
`);
-// Should return object.
-dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
- return {
- return: "foo"
- };
-};
-testUncaughtException();
-
-// The object should have `done` property and `value` property.
-dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
- return {
- return: frame.eval("({})").return
- };
-};
-testUncaughtException();
-
-// The object should have `done` property.
-dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
- return {
- return: frame.eval("({ value: 10 })").return
- };
-};
-testUncaughtException();
-
-// The object should have `value` property.
-dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
- return {
- return: frame.eval("({ done: true })").return
- };
-};
-testUncaughtException();
-
-// `done` property should be a boolean value.
-dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
- return {
- return: frame.eval("({ done: 10, value: 10 })").return
- };
-};
-testUncaughtException();
-
-// `done` property shouldn't be an accessor.
-dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
- return {
- return: frame.eval("({ get done() { return true; }, value: 10 })").return
- };
-};
-testUncaughtException();
-
-// `value` property shouldn't be an accessor.
-dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
- return {
- return: frame.eval("({ done: true, get value() { return 10; } })").return
- };
-};
-testUncaughtException();
-
-// The object shouldn't be a Proxy.
-dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
- return {
- return: frame.eval("new Proxy({ done: true, value: 10 }, {})").return
- };
-};
-testUncaughtException();
-
-// Correct resumption value.
+// Return with resumption value.
dbg.onExceptionUnwind = function(frame) {
- currentFrame = frame;
return {
- return: frame.eval("({ done: true, value: 10 })").return
+ return: 10
};
};
var val = g.eval(`
diff --git a/js/src/jit-test/tests/gc/bug-900405.js b/js/src/jit-test/tests/gc/bug-900405.js
deleted file mode 100644
index eeec6f25f..000000000
--- a/js/src/jit-test/tests/gc/bug-900405.js
+++ /dev/null
@@ -1,3 +0,0 @@
-(function() {
- [{ "9": [] }.watch([], function(){})]
-})()
diff --git a/js/src/jit-test/tests/gc/bug-913261.js b/js/src/jit-test/tests/gc/bug-913261.js
deleted file mode 100644
index 43066053f..000000000
--- a/js/src/jit-test/tests/gc/bug-913261.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// |jit-test| error: InternalError: too much recursion
-(function f() {
- "".watch(2, function() {});
- f();
-})()
diff --git a/js/src/jit-test/tests/gc/bug-986864.js b/js/src/jit-test/tests/gc/bug-986864.js
deleted file mode 100644
index abb8de6b2..000000000
--- a/js/src/jit-test/tests/gc/bug-986864.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// |jit-test| slow
-function x() {}
-for (var j = 0; j < 9999; ++j) {
- (function() {
- x += x.watch("endsWith", ArrayBuffer);
- return 0 >> Function(x)
- })()
-}
diff --git a/js/src/jit-test/tests/ion/bug1063182.js b/js/src/jit-test/tests/ion/bug1063182.js
deleted file mode 100644
index 9cda48099..000000000
--- a/js/src/jit-test/tests/ion/bug1063182.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// |jit-test| error: ReferenceError
-
-eval("(function() { " + "\
-var o = {};\
-o.watch('p', function() { });\
-for (var i = 0; i < 10; \u5ede ++)\
- o.p = 123;\
-" + " })();");
diff --git a/js/src/jit-test/tests/ion/bug772901.js b/js/src/jit-test/tests/ion/bug772901.js
index eb71f6afb..164afd151 100644
--- a/js/src/jit-test/tests/ion/bug772901.js
+++ b/js/src/jit-test/tests/ion/bug772901.js
@@ -4,4 +4,4 @@ function f(x) {
delete ((x)++);
arguments[0] !== undefined;
}
-f(1, x = [f.ArrayBuffer,unwatch.Int32Array], this, this, this) ;
+f(1, x = [f.ArrayBuffer, undefined], this, this, this) ;
diff --git a/js/src/jit-test/tests/ion/bug774257-1.js b/js/src/jit-test/tests/ion/bug774257-1.js
deleted file mode 100644
index 9c998a028..000000000
--- a/js/src/jit-test/tests/ion/bug774257-1.js
+++ /dev/null
@@ -1,8 +0,0 @@
-Object.defineProperty(Object.prototype, 'x', {
- set: function() { evalcx('lazy'); }
-});
-var obj = {};
-obj.watch("x", function (id, oldval, newval) {});
-for (var str in 'A') {
- obj.x = 1;
-}
diff --git a/js/src/jit-test/tests/ion/bug774257-2.js b/js/src/jit-test/tests/ion/bug774257-2.js
deleted file mode 100644
index b31043b08..000000000
--- a/js/src/jit-test/tests/ion/bug774257-2.js
+++ /dev/null
@@ -1,10 +0,0 @@
-Object.defineProperty(Object.prototype, 'x', {
- set: function() { evalcx('lazy'); }
-});
-var obj = {};
-var prot = {};
-obj.__proto__ = prot;
-obj.watch("x", function (id, oldval, newval) {});
-for (var str in 'A') {
- obj.x = 1;
-}
diff --git a/js/src/jit-test/tests/ion/bug779631.js b/js/src/jit-test/tests/ion/bug779631.js
deleted file mode 100644
index 087aa01ac..000000000
--- a/js/src/jit-test/tests/ion/bug779631.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var flag = 0;
-var a = {};
-Object.defineProperty(a, "value", {set: function(x) {}});
-a.watch("value", function(){flag++;});
-
-for(var i = 0; i < 100; i++) {
- a.value = i;
- assertEq(flag, i+1);
-}
diff --git a/js/src/jit-test/tests/ion/bug783590.js b/js/src/jit-test/tests/ion/bug783590.js
index d48cb609e..9d277e02c 100644
--- a/js/src/jit-test/tests/ion/bug783590.js
+++ b/js/src/jit-test/tests/ion/bug783590.js
@@ -7,7 +7,6 @@ Object.defineProperty(arr, 0, {
glob.__proto__;
})
});
-this.watch("s", function() {});
try {
arr.pop();
} catch (e) {}
diff --git a/js/src/jit-test/tests/jaeger/bug550665.js b/js/src/jit-test/tests/jaeger/bug550665.js
deleted file mode 100644
index 816888b5e..000000000
--- a/js/src/jit-test/tests/jaeger/bug550665.js
+++ /dev/null
@@ -1,8 +0,0 @@
-(function () {
- var a;
- eval("for(w in ((function(x,y){b:0})())) ;");
-})();
-
-this.__defineSetter__("l", function() { gc() });
-this.watch("l", function(x) { yield {} });
-l = true;
diff --git a/js/src/jit-test/tests/jaeger/bug557063.js b/js/src/jit-test/tests/jaeger/bug557063.js
deleted file mode 100644
index ea77fd2c8..000000000
--- a/js/src/jit-test/tests/jaeger/bug557063.js
+++ /dev/null
@@ -1,7 +0,0 @@
-(function() {
- for (a = 0; a < 2; a++)
- ''.watch("", function() {})
-})()
-
-/* Don't crash or assert. */
-
diff --git a/js/src/jit-test/tests/jaeger/bug588338.js b/js/src/jit-test/tests/jaeger/bug588338.js
index 457be238a..c400d7687 100644
--- a/js/src/jit-test/tests/jaeger/bug588338.js
+++ b/js/src/jit-test/tests/jaeger/bug588338.js
@@ -9,7 +9,6 @@ function f() {
}
}
})(/x/)))
-for (z = 0; z < 100; x.unwatch(), z++)
for (e in [0]) {
gczeal(2)
} ( [1,2,3])("")
diff --git a/js/src/jit-test/tests/jaeger/bug625438.js b/js/src/jit-test/tests/jaeger/bug625438.js
deleted file mode 100644
index 32586d8ab..000000000
--- a/js/src/jit-test/tests/jaeger/bug625438.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// vim: set ts=8 sts=4 et sw=4 tw=99:
-
-var count = 0;
-this.watch("x", function() {
- count++;
-});
-for(var i=0; i<10; i++) {
- x = 2;
-}
-assertEq(count, 10);
diff --git a/js/src/jit-test/tests/jaeger/bug630366.js b/js/src/jit-test/tests/jaeger/bug630366.js
deleted file mode 100644
index acac8d3ef..000000000
--- a/js/src/jit-test/tests/jaeger/bug630366.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var o = {};
-for(var i=0; i<5; i++) {
- o.p = 2;
- o.watch("p", function() { });
- o.p = 2;
- delete o.p;
-}
diff --git a/js/src/jit-test/tests/jaeger/recompile/bug641225.js b/js/src/jit-test/tests/jaeger/recompile/bug641225.js
index a6e3a86c7..7b7978197 100644
--- a/js/src/jit-test/tests/jaeger/recompile/bug641225.js
+++ b/js/src/jit-test/tests/jaeger/recompile/bug641225.js
@@ -118,7 +118,6 @@ for(var o2 in f5) {
f2(o5);
f2(o5);
f0(o3);
- o9.watch('p3', function() {});
o8[o8] = o8;
f0(o5);
f1(o6);
diff --git a/js/src/jit-test/tests/modules/bug-1320993.js b/js/src/jit-test/tests/modules/bug-1320993.js
new file mode 100644
index 000000000..bece5731a
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1320993.js
@@ -0,0 +1,2 @@
+parseModule("export default (class {})");
+parseModule("export default (class A {})");
diff --git a/js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js b/js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js
new file mode 100644
index 000000000..387c7c369
--- /dev/null
+++ b/js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js
@@ -0,0 +1,3 @@
+// |jit-test| module; error:SyntaxError
+
+import "export-circular-nonexisting-binding-1.js";
diff --git a/js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js b/js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js
new file mode 100644
index 000000000..f87829d89
--- /dev/null
+++ b/js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js
@@ -0,0 +1,4 @@
+// |jit-test| module; error:SyntaxError
+
+export { a } from "empty.js";
+export* from "module1.js";
diff --git a/js/src/jit-test/tests/modules/export-star-circular-dependencies.js b/js/src/jit-test/tests/modules/export-star-circular-dependencies.js
new file mode 100644
index 000000000..9aa612f08
--- /dev/null
+++ b/js/src/jit-test/tests/modules/export-star-circular-dependencies.js
@@ -0,0 +1,6 @@
+// |jit-test| module
+
+import { x, y } from "export-star-circular-1.js";
+
+assertEq(x, "pass");
+assertEq(y, "pass");
diff --git a/js/src/jit-test/tests/modules/import-namespace.js b/js/src/jit-test/tests/modules/import-namespace.js
index f44d4568a..0287f7a60 100644
--- a/js/src/jit-test/tests/modules/import-namespace.js
+++ b/js/src/jit-test/tests/modules/import-namespace.js
@@ -19,9 +19,19 @@ function testHasNames(names, expected) {
});
}
+function testEqualArrays(actual, expected) {
+ assertEq(Array.isArray(actual), true);
+ assertEq(Array.isArray(expected), true);
+ assertEq(actual.length, expected.length);
+ for (let i = 0; i < expected.length; i++) {
+ assertEq(actual[i], expected[i]);
+ }
+}
+
let a = moduleRepo['a'] = parseModule(
- `export var a = 1;
- export var b = 2;`
+ `// Reflection methods should return these exports alphabetically sorted.
+ export var b = 2;
+ export var a = 1;`
);
let b = moduleRepo['b'] = parseModule(
@@ -35,11 +45,16 @@ b.evaluation();
testHasNames(getModuleEnvironmentNames(b), ["ns", "x"]);
let ns = getModuleEnvironmentValue(b, "ns");
testHasNames(Object.keys(ns), ["a", "b"]);
+assertEq(ns.a, 1);
+assertEq(ns.b, 2);
+assertEq(ns.c, undefined);
assertEq(getModuleEnvironmentValue(b, "x"), 3);
// Test module namespace internal methods as defined in 9.4.6
assertEq(Object.getPrototypeOf(ns), null);
-assertThrowsInstanceOf(() => Object.setPrototypeOf(ns, null), TypeError);
+assertEq(Reflect.setPrototypeOf(ns, null), true);
+assertEq(Reflect.setPrototypeOf(ns, Object.prototype), false);
+assertThrowsInstanceOf(() => Object.setPrototypeOf(ns, {}), TypeError);
assertThrowsInstanceOf(function() { ns.foo = 1; }, TypeError);
assertEq(Object.isExtensible(ns), false);
Object.preventExtensions(ns);
@@ -59,29 +74,15 @@ desc = Object.getOwnPropertyDescriptor(ns, Symbol.toStringTag);
assertEq(desc.value, "Module");
assertEq(desc.writable, false);
assertEq(desc.enumerable, false);
-assertEq(desc.configurable, true);
+assertEq(desc.configurable, false);
assertEq(typeof desc.get, "undefined");
assertEq(typeof desc.set, "undefined");
assertEq(Object.prototype.toString.call(ns), "[object Module]");
-// Test @@iterator method.
-let iteratorFun = ns[Symbol.iterator];
-assertEq(iteratorFun.name, "[Symbol.iterator]");
-
-let iterator = ns[Symbol.iterator]();
-assertEq(iterator[Symbol.iterator](), iterator);
-assertIteratorNext(iterator, "a");
-assertIteratorNext(iterator, "b");
-assertIteratorDone(iterator);
-
-// The iterator's next method can only be called on the object it was originally
-// associated with.
-iterator = ns[Symbol.iterator]();
-let iterator2 = ns[Symbol.iterator]();
-assertThrowsInstanceOf(() => iterator.next.call({}), TypeError);
-assertThrowsInstanceOf(() => iterator.next.call(iterator2), TypeError);
-assertEq(iterator.next.call(iterator).value, "a");
-assertEq(iterator2.next.call(iterator2).value, "a");
+// Test [[OwnPropertyKeys]] internal method.
+testEqualArrays(Reflect.ownKeys(ns), ["a", "b", Symbol.toStringTag]);
+testEqualArrays(Object.getOwnPropertyNames(ns), ["a", "b"]);
+testEqualArrays(Object.getOwnPropertySymbols(ns), [Symbol.toStringTag]);
// Test cyclic namespace import and access in module evaluation.
let c = moduleRepo['c'] =
diff --git a/js/src/jit-test/tests/pic/fuzz1.js b/js/src/jit-test/tests/pic/fuzz1.js
deleted file mode 100644
index 2481a1314..000000000
--- a/js/src/jit-test/tests/pic/fuzz1.js
+++ /dev/null
@@ -1,4 +0,0 @@
-(function() {
- for (a = 0; a < 2; a++)
- ''.watch("", function() {})
-})()
diff --git a/js/src/jit-test/tests/pic/fuzz3.js b/js/src/jit-test/tests/pic/fuzz3.js
deleted file mode 100644
index 17613b6f5..000000000
--- a/js/src/jit-test/tests/pic/fuzz3.js
+++ /dev/null
@@ -1,3 +0,0 @@
-for each(let w in [[], 0, [], 0]) {
- w.unwatch()
-}
diff --git a/js/src/jit-test/tests/pic/watch1.js b/js/src/jit-test/tests/pic/watch1.js
deleted file mode 100644
index 09d6347bf..000000000
--- a/js/src/jit-test/tests/pic/watch1.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// assignments to watched objects must not be cached
-var obj = {x: 0};
-var hits = 0;
-obj.watch("x", function (id, oldval, newval) { hits++; return newval; });
-for (var i = 0; i < 10; i++)
- obj.x = i;
-assertEq(hits, 10);
diff --git a/js/src/jit-test/tests/pic/watch1a.js b/js/src/jit-test/tests/pic/watch1a.js
deleted file mode 100644
index 4b404f507..000000000
--- a/js/src/jit-test/tests/pic/watch1a.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// assignments to watched objects must not be traced
-var hits = 0;
-function counter(id, oldval, newval) {
- hits++;
- return newval;
-}
-
-(function () {
- var obj = {x: 0, y: 0};
- var a = ['x', 'y'];
- obj.watch('z', counter);
- for (var i = 0; i < 14; i++) {
- obj.watch(a[+(i > 8)], counter);
- obj.y = i;
- }
-})();
-assertEq(hits, 5);
diff --git a/js/src/jit-test/tests/pic/watch2.js b/js/src/jit-test/tests/pic/watch2.js
deleted file mode 100644
index fb3e29617..000000000
--- a/js/src/jit-test/tests/pic/watch2.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// assignments to watched properties via ++ must not be cached
-var obj = {x: 0};
-var hits = 0;
-obj.watch("x", function (id, oldval, newval) { hits++; return newval; });
-for (var i = 0; i < 10; i++)
- obj.x++;
-assertEq(hits, 10);
-
diff --git a/js/src/jit-test/tests/pic/watch2a.js b/js/src/jit-test/tests/pic/watch2a.js
deleted file mode 100644
index ce3294ba3..000000000
--- a/js/src/jit-test/tests/pic/watch2a.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// assignments to watched properties via ++ must not be traced
-var hits = 0;
-function counter(id, oldval, newval) {
- hits++;
- return newval;
-}
-
-(function () {
- var obj = {x: 0, y: 0};
- var a = ['x', 'y'];
- obj.watch('z', counter);
- for (var i = 0; i < 14; i++) {
- obj.watch(a[+(i > 8)], counter);
- obj.y++;
- }
-})();
-assertEq(hits, 5);
-
diff --git a/js/src/jit-test/tests/pic/watch3.js b/js/src/jit-test/tests/pic/watch3.js
deleted file mode 100644
index 4c5c93d8b..000000000
--- a/js/src/jit-test/tests/pic/watch3.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// assignment to watched global properties must not be cached
-x = 0;
-var hits = 0;
-this.watch("x", function (id, oldval, newval) { hits++; return newval; });
-for (var i = 0; i < 10; i++)
- x = i;
-assertEq(hits, 10);
diff --git a/js/src/jit-test/tests/pic/watch3a.js b/js/src/jit-test/tests/pic/watch3a.js
deleted file mode 100644
index 700daf6af..000000000
--- a/js/src/jit-test/tests/pic/watch3a.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// assignment to watched global properties must not be traced
-var hits = 0;
-function counter(id, oldval, newval) {
- hits++;
- return newval;
-}
-
-var x = 0;
-var y = 0;
-(function () {
- var a = ['x', 'y'];
- this.watch('z', counter);
- for (var i = 0; i < 14; i++) {
- this.watch(a[+(i > 8)], counter);
- y = 1;
- }
-})();
-assertEq(hits, 5);
-
diff --git a/js/src/jit-test/tests/pic/watch3b.js b/js/src/jit-test/tests/pic/watch3b.js
deleted file mode 100644
index 9b0dc8cc9..000000000
--- a/js/src/jit-test/tests/pic/watch3b.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// assignment to watched global properties must not be traced
-var hits = 0;
-function counter(id, oldval, newval) {
- hits++;
- return newval;
-}
-
-var x = 0;
-var y = 0;
-function f() {
- var a = [{}, this];
- for (var i = 0; i < 14; i++) {
- print(shapeOf(this));
- Object.prototype.watch.call(a[+(i > 8)], "y", counter);
- y++;
- }
-}
-f();
-assertEq(hits, 5);
-
diff --git a/js/src/jit-test/tests/pic/watch4.js b/js/src/jit-test/tests/pic/watch4.js
deleted file mode 100644
index 4b640c4df..000000000
--- a/js/src/jit-test/tests/pic/watch4.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// adding assignment + watchpoint vs. caching
-var hits = 0;
-var obj = {};
-obj.watch("x", function (id, oldval, newval) { hits++; return newval; });
-for (var i = 0; i < 10; i++) {
- obj.x = 1;
- delete obj.x;
-}
-assertEq(hits, 10);
diff --git a/js/src/jit-test/tests/pic/watch5.js b/js/src/jit-test/tests/pic/watch5.js
deleted file mode 100644
index 6b22951a4..000000000
--- a/js/src/jit-test/tests/pic/watch5.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// test against future pic support for symbols
-
-// assignments to watched objects must not be cached
-var obj = {};
-var x = Symbol.for("x");
-obj[x] = 0;
-var hits = 0;
-obj.watch(x, function (id, oldval, newval) { hits++; return newval; });
-for (var i = 0; i < 10; i++)
- obj[x] = i;
-assertEq(hits, 10);
-
-// assignments to watched properties via ++ must not be cached
-hits = 0;
-for (var i = 0; i < 10; i++)
- obj[x]++;
-assertEq(hits, 10);
-
-// adding assignment + watchpoint vs. caching
-hits = 0;
-obj = {};
-obj.watch(x, function (id, oldval, newval) { hits++; return newval; });
-for (var i = 0; i < 10; i++) {
- obj[x] = 1;
- delete obj[x];
-}
-assertEq(hits, 10);
diff --git a/js/src/jit-test/tests/profiler/bug1140643.js b/js/src/jit-test/tests/profiler/bug1140643.js
deleted file mode 100644
index 1b171aea2..000000000
--- a/js/src/jit-test/tests/profiler/bug1140643.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// |jit-test| allow-oom
-enableSPSProfiling();
-loadFile('\
-for (var i = 0; i < 2; i++) {\
- obj = { m: function () {} };\
- obj.watch("m", function () { float32 = 0 + obj.foo; });\
- obj.m = 0;\
-}\
-');
-gcparam("maxBytes", gcparam("gcBytes") + (1)*1024);
-newGlobal("same-compartment");
-function loadFile(lfVarx) {
- evaluate(lfVarx, { noScriptRval : true, isRunOnce : true });
-}
diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp
index b2f9d3b23..d254b9826 100644
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -25,6 +25,7 @@
#include "jit/VMFunctions.h"
#include "js/UniquePtr.h"
#include "vm/AsyncFunction.h"
+#include "vm/AsyncIteration.h"
#include "vm/EnvironmentObject.h"
#include "vm/Interpreter.h"
#include "vm/TraceLogging.h"
@@ -43,7 +44,7 @@ using mozilla::AssertedCast;
BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript* script)
: BaselineCompilerSpecific(cx, alloc, script),
- yieldOffsets_(cx),
+ yieldAndAwaitOffsets_(cx),
modifiesArguments_(false)
{
}
@@ -210,7 +211,7 @@ BaselineCompiler::compile()
pcMappingIndexEntries.length(),
pcEntries.length(),
bytecodeTypeMapEntries,
- yieldOffsets_.length(),
+ yieldAndAwaitOffsets_.length(),
traceLoggerToggleOffsets_.length()),
JS::DeletePolicy<BaselineScript>(cx->runtime()));
if (!baselineScript) {
@@ -275,7 +276,7 @@ BaselineCompiler::compile()
// searches for the sought entry when queries are in linear order.
bytecodeMap[script->nTypeSets()] = 0;
- baselineScript->copyYieldEntries(script, yieldOffsets_);
+ baselineScript->copyYieldAndAwaitEntries(script, yieldAndAwaitOffsets_);
if (compileDebugInstrumentation_)
baselineScript->setHasDebugInstrumentation();
@@ -3908,6 +3909,50 @@ BaselineCompiler::emit_JSOP_TOASYNC()
return true;
}
+typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
+static const VMFunction ToAsyncGenInfo =
+ FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
+
+bool
+BaselineCompiler::emit_JSOP_TOASYNCGEN()
+{
+ frame.syncStack(0);
+ masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
+
+ prepareVMCall();
+ pushArg(R0.scratchReg());
+
+ if (!callVM(ToAsyncGenInfo))
+ return false;
+
+ masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
+ frame.pop();
+ frame.push(R0);
+ return true;
+}
+
+typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject);
+static const VMFunction ToAsyncIterInfo =
+ FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
+
+bool
+BaselineCompiler::emit_JSOP_TOASYNCITER()
+{
+ frame.syncStack(0);
+ masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
+
+ prepareVMCall();
+ pushArg(R0.scratchReg());
+
+ if (!callVM(ToAsyncIterInfo))
+ return false;
+
+ masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
+ frame.pop();
+ frame.push(R0);
+ return true;
+}
+
typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue);
static const VMFunction ThrowObjectCoercibleInfo =
FunctionInfo<ThrowObjectCoercibleFn>(ThrowObjectCoercible, "ThrowObjectCoercible");
@@ -4174,27 +4219,28 @@ BaselineCompiler::emit_JSOP_GENERATOR()
}
bool
-BaselineCompiler::addYieldOffset()
+BaselineCompiler::addYieldAndAwaitOffset()
{
- MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
+ MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
- uint32_t yieldIndex = GET_UINT24(pc);
+ uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
- while (yieldIndex >= yieldOffsets_.length()) {
- if (!yieldOffsets_.append(0))
+ while (yieldAndAwaitIndex >= yieldAndAwaitOffsets_.length()) {
+ if (!yieldAndAwaitOffsets_.append(0))
return false;
}
- static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH,
- "code below assumes INITIALYIELD and YIELD have same length");
- yieldOffsets_[yieldIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH);
+ static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH &&
+ JSOP_INITIALYIELD_LENGTH == JSOP_AWAIT_LENGTH,
+ "code below assumes INITIALYIELD and YIELD and AWAIT have same length");
+ yieldAndAwaitOffsets_[yieldAndAwaitIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH);
return true;
}
bool
BaselineCompiler::emit_JSOP_INITIALYIELD()
{
- if (!addYieldOffset())
+ if (!addYieldAndAwaitOffset())
return false;
frame.syncStack(0);
@@ -4204,7 +4250,8 @@ BaselineCompiler::emit_JSOP_INITIALYIELD()
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), genObj);
MOZ_ASSERT(GET_UINT24(pc) == 0);
- masm.storeValue(Int32Value(0), Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
+ masm.storeValue(Int32Value(0),
+ Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
Register envObj = R0.scratchReg();
Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
@@ -4233,7 +4280,7 @@ static const VMFunction NormalSuspendInfo =
bool
BaselineCompiler::emit_JSOP_YIELD()
{
- if (!addYieldOffset())
+ if (!addYieldAndAwaitOffset())
return false;
// Store generator in R0.
@@ -4250,7 +4297,7 @@ BaselineCompiler::emit_JSOP_YIELD()
// generator is in the closing state, see GeneratorObject::suspend.
masm.storeValue(Int32Value(GET_UINT24(pc)),
- Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
+ Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
Register envObj = R0.scratchReg();
Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
@@ -4282,6 +4329,12 @@ BaselineCompiler::emit_JSOP_YIELD()
return emitReturn();
}
+bool
+BaselineCompiler::emit_JSOP_AWAIT()
+{
+ return emit_JSOP_YIELD();
+}
+
typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*);
static const VMFunction DebugAfterYieldInfo =
FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield");
@@ -4501,16 +4554,17 @@ BaselineCompiler::emit_JSOP_RESUME()
masm.pushValue(retVal);
if (resumeKind == GeneratorObject::NEXT) {
- // Determine the resume address based on the yieldIndex and the
- // yieldIndex -> native table in the BaselineScript.
+ // Determine the resume address based on the yieldAndAwaitIndex and the
+ // yieldAndAwaitIndex -> native table in the BaselineScript.
masm.load32(Address(scratch1, BaselineScript::offsetOfYieldEntriesOffset()), scratch2);
masm.addPtr(scratch2, scratch1);
- masm.unboxInt32(Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()), scratch2);
+ masm.unboxInt32(Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()),
+ scratch2);
masm.loadPtr(BaseIndex(scratch1, scratch2, ScaleFromElemWidth(sizeof(uintptr_t))), scratch1);
// Mark as running and jump to the generator's JIT code.
- masm.storeValue(Int32Value(GeneratorObject::YIELD_INDEX_RUNNING),
- Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
+ masm.storeValue(Int32Value(GeneratorObject::YIELD_AND_AWAIT_INDEX_RUNNING),
+ Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
masm.jump(scratch1);
} else {
MOZ_ASSERT(resumeKind == GeneratorObject::THROW || resumeKind == GeneratorObject::CLOSE);
diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h
index 95e0c77ad..a200f7ab9 100644
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -196,6 +196,8 @@ namespace jit {
_(JSOP_RUNONCE) \
_(JSOP_REST) \
_(JSOP_TOASYNC) \
+ _(JSOP_TOASYNCGEN) \
+ _(JSOP_TOASYNCITER) \
_(JSOP_TOID) \
_(JSOP_TOSTRING) \
_(JSOP_TABLESWITCH) \
@@ -207,6 +209,7 @@ namespace jit {
_(JSOP_GENERATOR) \
_(JSOP_INITIALYIELD) \
_(JSOP_YIELD) \
+ _(JSOP_AWAIT) \
_(JSOP_DEBUGAFTERYIELD) \
_(JSOP_FINALYIELDRVAL) \
_(JSOP_RESUME) \
@@ -255,9 +258,9 @@ class BaselineCompiler : public BaselineCompilerSpecific
// equivalent positions when debug mode is off.
CodeOffset postDebugPrologueOffset_;
- // For each INITIALYIELD or YIELD op, this Vector maps the yield index
- // to the bytecode offset of the next op.
- Vector<uint32_t> yieldOffsets_;
+ // For each INITIALYIELD or YIELD or AWAIT op, this Vector maps the yield
+ // index to the bytecode offset of the next op.
+ Vector<uint32_t> yieldAndAwaitOffsets_;
// Whether any on stack arguments are modified.
bool modifiesArguments_;
@@ -349,7 +352,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
MOZ_MUST_USE bool addPCMappingEntry(bool addIndexEntry);
- MOZ_MUST_USE bool addYieldOffset();
+ MOZ_MUST_USE bool addYieldAndAwaitOffset();
void getEnvironmentCoordinateObject(Register reg);
Address getEnvironmentCoordinateAddressFromObject(Register objReg, Register reg);
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
index a001357f8..e65f10aac 100644
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -4053,9 +4053,6 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
{
MOZ_ASSERT(!*attached);
- if (obj->watched())
- return true;
-
RootedShape shape(cx);
RootedObject holder(cx);
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
@@ -4151,9 +4148,6 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
MOZ_ASSERT(!*attached);
MOZ_ASSERT(!*isTemporarilyUnoptimizable);
- if (obj->watched())
- return true;
-
RootedShape shape(cx);
RootedObject holder(cx);
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
@@ -6606,12 +6600,13 @@ ICCall_IsSuspendedStarGenerator::Compiler::generateStubCode(MacroAssembler& masm
masm.branchTestObjClass(Assembler::NotEqual, genObj, scratch, &StarGeneratorObject::class_,
&returnFalse);
- // If the yield index slot holds an int32 value < YIELD_INDEX_CLOSING,
+ // If the yield index slot holds an int32 value < YIELD_AND_AWAIT_INDEX_CLOSING,
// the generator is suspended.
- masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()), argVal);
+ masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()), argVal);
masm.branchTestInt32(Assembler::NotEqual, argVal, &returnFalse);
masm.unboxInt32(argVal, scratch);
- masm.branch32(Assembler::AboveOrEqual, scratch, Imm32(StarGeneratorObject::YIELD_INDEX_CLOSING),
+ masm.branch32(Assembler::AboveOrEqual, scratch,
+ Imm32(StarGeneratorObject::YIELD_AND_AWAIT_INDEX_CLOSING),
&returnFalse);
masm.moveValue(BooleanValue(true), R0);
diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp
index 5c21926b5..94e018252 100644
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -760,12 +760,12 @@ BaselineScript::icEntryFromReturnAddress(uint8_t* returnAddr)
}
void
-BaselineScript::copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets)
+BaselineScript::copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets)
{
uint8_t** entries = yieldEntryList();
- for (size_t i = 0; i < yieldOffsets.length(); i++) {
- uint32_t offset = yieldOffsets[i];
+ for (size_t i = 0; i < yieldAndAwaitOffsets.length(); i++) {
+ uint32_t offset = yieldAndAwaitOffsets[i];
entries[i] = nativeCodeForPC(script, script->offsetToPC(offset));
}
}
diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h
index 5e7775a61..b6ccd2ff9 100644
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -397,7 +397,7 @@ struct BaselineScript
void copyICEntries(JSScript* script, const BaselineICEntry* entries, MacroAssembler& masm);
void adoptFallbackStubs(FallbackICStubSpace* stubSpace);
- void copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets);
+ void copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets);
PCMappingIndexEntry& pcMappingIndexEntry(size_t index);
CompactBufferReader pcMappingReader(size_t indexEntry);
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index 205812942..2b1c671d1 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -41,6 +41,7 @@
#include "jit/RangeAnalysis.h"
#include "jit/SharedICHelpers.h"
#include "vm/AsyncFunction.h"
+#include "vm/AsyncIteration.h"
#include "vm/MatchPairs.h"
#include "vm/RegExpObject.h"
#include "vm/RegExpStatics.h"
@@ -10213,6 +10214,28 @@ CodeGenerator::visitToAsync(LToAsync* lir)
callVM(ToAsyncInfo, lir);
}
+typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
+static const VMFunction ToAsyncGenInfo =
+ FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
+
+void
+CodeGenerator::visitToAsyncGen(LToAsyncGen* lir)
+{
+ pushArg(ToRegister(lir->unwrapped()));
+ callVM(ToAsyncGenInfo, lir);
+}
+
+typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject);
+static const VMFunction ToAsyncIterInfo =
+ FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
+
+void
+CodeGenerator::visitToAsyncIter(LToAsyncIter* lir)
+{
+ pushArg(ToRegister(lir->unwrapped()));
+ callVM(ToAsyncIterInfo, lir);
+}
+
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue,
MutableHandleValue);
static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation, "ToIdOperation");
diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h
index 12f1238ef..65acfe274 100644
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -286,6 +286,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitTypeOfV(LTypeOfV* lir);
void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);
void visitToAsync(LToAsync* lir);
+ void visitToAsyncGen(LToAsyncGen* lir);
+ void visitToAsyncIter(LToAsyncIter* lir);
void visitToIdV(LToIdV* lir);
template<typename T> void emitLoadElementT(LLoadElementT* lir, const T& source);
void visitLoadElementT(LLoadElementT* lir);
diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h
index 1d0506f74..9c864515d 100644
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -119,7 +119,6 @@
_(IntrinsicGuardToArrayIterator) \
_(IntrinsicGuardToMapIterator) \
_(IntrinsicGuardToSetIterator) \
- _(IntrinsicIsListIterator) \
_(IntrinsicGuardToStringIterator) \
\
_(IntrinsicGuardToMapObject) \
diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
index b8a2d2fba..9337f6150 100644
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2320,7 +2320,9 @@ IonCompile(JSContext* cx, JSScript* script,
static bool
CheckFrame(JSContext* cx, BaselineFrame* frame)
{
- MOZ_ASSERT(!frame->script()->isGenerator());
+ MOZ_ASSERT(!frame->script()->isStarGenerator());
+ MOZ_ASSERT(!frame->script()->isLegacyGenerator());
+ MOZ_ASSERT(!frame->script()->isAsync());
MOZ_ASSERT(!frame->isDebuggerEvalFrame());
MOZ_ASSERT(!frame->isEvalFrame());
@@ -2351,11 +2353,16 @@ CheckScript(JSContext* cx, JSScript* script, bool osr)
return false;
}
- if (script->isGenerator()) {
+ if (script->isStarGenerator() || script->isLegacyGenerator()) {
TrackAndSpewIonAbort(cx, script, "generator script");
return false;
}
+ if (script->isAsync()) {
+ TrackAndSpewIonAbort(cx, script, "async script");
+ return false;
+ }
+
if (script->hasNonSyntacticScope() && !script->functionNonDelazifying()) {
// Support functions with a non-syntactic global scope but not other
// scripts. For global scripts, IonBuilder currently uses the global
diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp
index 5fc624fb1..a4724bca4 100644
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -4005,7 +4005,7 @@ jit::ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const Lin
}
static bool
-AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
+AnalyzePoppedThis(JSContext* cx, DPAConstraintInfo& constraintInfo, ObjectGroup* group,
MDefinition* thisValue, MInstruction* ins, bool definitelyExecuted,
HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList,
@@ -4046,7 +4046,12 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
return true;
RootedId id(cx, NameToId(setprop->name()));
- if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, group, id)) {
+ bool added = false;
+ if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, constraintInfo,
+ group, id, &added)) {
+ return false;
+ }
+ if (!added) {
// The prototype chain already contains a getter/setter for this
// property, or type information is too imprecise.
return true;
@@ -4106,7 +4111,12 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
if (!baseobj->lookup(cx, id) && !accessedProperties->append(get->name()))
return false;
- if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, group, id)) {
+ bool added = false;
+ if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, constraintInfo,
+ group, id, &added)) {
+ return false;
+ }
+ if (!added) {
// The |this| value can escape if any property reads it does go
// through a getter.
return true;
@@ -4132,8 +4142,11 @@ CmpInstructions(const void* a, const void* b)
}
bool
-jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
- ObjectGroup* group, HandlePlainObject baseobj,
+jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx,
+ DPAConstraintInfo& constraintInfo,
+ HandleFunction fun,
+ ObjectGroup* group,
+ HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList)
{
MOZ_ASSERT(cx->zone()->types.activeAnalysis);
@@ -4293,7 +4306,7 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
bool handled = false;
size_t slotSpan = baseobj->slotSpan();
- if (!AnalyzePoppedThis(cx, group, thisValue, ins, definitelyExecuted,
+ if (!AnalyzePoppedThis(cx, constraintInfo, group, thisValue, ins, definitelyExecuted,
baseobj, initializerList, &accessedProperties, &handled))
{
return false;
@@ -4312,7 +4325,6 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
// contingent on the correct frames being inlined. Add constraints to
// invalidate the definite properties if additional functions could be
// called at the inline frame sites.
- Vector<MBasicBlock*> exitBlocks(cx);
for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
// Inlining decisions made after the last new property was added to
// the object don't need to be frozen.
@@ -4320,9 +4332,11 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
break;
if (MResumePoint* rp = block->callerResumePoint()) {
if (block->numPredecessors() == 1 && block->getPredecessor(0) == rp->block()) {
- JSScript* script = rp->block()->info().script();
- if (!AddClearDefiniteFunctionUsesInScript(cx, group, script, block->info().script()))
+ JSScript* caller = rp->block()->info().script();
+ JSScript* callee = block->info().script();
+ if (!constraintInfo.addInliningConstraint(caller, callee)) {
return false;
+ }
}
}
}
@@ -4388,8 +4402,14 @@ jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg)
// direct eval is present.
//
// FIXME: Don't build arguments for ES6 generator expressions.
- if (scriptArg->isDebuggee() || script->isGenerator() || script->bindingsAccessedDynamically())
+ if (scriptArg->isDebuggee() ||
+ script->isStarGenerator() ||
+ script->isLegacyGenerator() ||
+ script->isAsync() ||
+ script->bindingsAccessedDynamically())
+ {
return true;
+ }
if (!jit::IsIonEnabled(cx))
return true;
diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h
index efd31415b..49bc0b591 100644
--- a/js/src/jit/IonAnalysis.h
+++ b/js/src/jit/IonAnalysis.h
@@ -196,8 +196,11 @@ MCompare*
ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum);
MOZ_MUST_USE bool
-AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
- ObjectGroup* group, HandlePlainObject baseobj,
+AnalyzeNewScriptDefiniteProperties(JSContext* cx,
+ DPAConstraintInfo& constraintInfo,
+ HandleFunction fun,
+ ObjectGroup* group,
+ HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList);
MOZ_MUST_USE bool
diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
index 2d053de5a..1e12f5dbe 100644
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2130,6 +2130,12 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_TOASYNC:
return jsop_toasync();
+ case JSOP_TOASYNCGEN:
+ return jsop_toasyncgen();
+
+ case JSOP_TOASYNCITER:
+ return jsop_toasynciter();
+
case JSOP_TOID:
return jsop_toid();
@@ -3351,7 +3357,7 @@ IonBuilder::whileOrForInLoop(jssrcnote* sn)
unsigned stackPhiCount;
if (SN_TYPE(sn) == SRC_FOR_OF)
- stackPhiCount = 2;
+ stackPhiCount = 3;
else if (SN_TYPE(sn) == SRC_FOR_IN)
stackPhiCount = 1;
else
@@ -8895,10 +8901,8 @@ IonBuilder::jsop_getimport(PropertyName* name)
if (!emitted) {
// This can happen if we don't have type information.
- TypeSet::ObjectKey* staticKey = TypeSet::ObjectKey::get(targetEnv);
TemporaryTypeSet* types = bytecodeTypes(pc);
- BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticKey,
- name, types, /* updateObserved = */ true);
+ BarrierKind barrier = BarrierKind::TypeSet;
if (!loadStaticSlot(targetEnv, barrier, types, shape->slot()))
return false;
@@ -13198,6 +13202,34 @@ IonBuilder::jsop_toasync()
}
bool
+IonBuilder::jsop_toasyncgen()
+{
+ MDefinition* unwrapped = current->pop();
+ MOZ_ASSERT(unwrapped->type() == MIRType::Object);
+
+ MToAsyncGen* ins = MToAsyncGen::New(alloc(), unwrapped);
+
+ current->add(ins);
+ current->push(ins);
+
+ return resumeAfter(ins);
+}
+
+bool
+IonBuilder::jsop_toasynciter()
+{
+ MDefinition* unwrapped = current->pop();
+ MOZ_ASSERT(unwrapped->type() == MIRType::Object);
+
+ MToAsyncIter* ins = MToAsyncIter::New(alloc(), unwrapped);
+
+ current->add(ins);
+ current->push(ins);
+
+ return resumeAfter(ins);
+}
+
+bool
IonBuilder::jsop_toid()
{
// No-op if the index is an integer.
diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h
index 1f763a4f2..6a3b61232 100644
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -762,6 +762,8 @@ class IonBuilder
MOZ_MUST_USE bool jsop_globalthis();
MOZ_MUST_USE bool jsop_typeof();
MOZ_MUST_USE bool jsop_toasync();
+ MOZ_MUST_USE bool jsop_toasyncgen();
+ MOZ_MUST_USE bool jsop_toasynciter();
MOZ_MUST_USE bool jsop_toid();
MOZ_MUST_USE bool jsop_iter(uint8_t flags);
MOZ_MUST_USE bool jsop_itermore();
diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp
index 48e0792bb..fb4291188 100644
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -3232,7 +3232,7 @@ SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript*
MOZ_ASSERT(!*emitted);
MOZ_ASSERT(!*tryNativeAddSlot);
- if (!canAttachStub() || obj->watched())
+ if (!canAttachStub())
return true;
// Fail cache emission if the object is frozen
@@ -3897,9 +3897,6 @@ IsDenseElementSetInlineable(JSObject* obj, const Value& idval, const ConstantOrR
if (!obj->is<ArrayObject>())
return false;
- if (obj->watched())
- return false;
-
if (!idval.isInt32())
return false;
diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
index 22f1d5f70..108450983 100644
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1176,6 +1176,22 @@ LIRGenerator::visitToAsync(MToAsync* ins)
}
void
+LIRGenerator::visitToAsyncGen(MToAsyncGen* ins)
+{
+ LToAsyncGen* lir = new(alloc()) LToAsyncGen(useRegisterAtStart(ins->input()));
+ defineReturn(lir, ins);
+ assignSafepoint(lir, ins);
+}
+
+void
+LIRGenerator::visitToAsyncIter(MToAsyncIter* ins)
+{
+ LToAsyncIter* lir = new(alloc()) LToAsyncIter(useRegisterAtStart(ins->input()));
+ defineReturn(lir, ins);
+ assignSafepoint(lir, ins);
+}
+
+void
LIRGenerator::visitToId(MToId* ins)
{
LToIdV* lir = new(alloc()) LToIdV(useBox(ins->input()), tempDouble());
diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h
index 9342ef471..81e6abbbb 100644
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -121,6 +121,8 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitCompare(MCompare* comp);
void visitTypeOf(MTypeOf* ins);
void visitToAsync(MToAsync* ins);
+ void visitToAsyncGen(MToAsyncGen* ins);
+ void visitToAsyncIter(MToAsyncIter* ins);
void visitToId(MToId* ins);
void visitBitNot(MBitNot* ins);
void visitBitAnd(MBitAnd* ins);
diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp
index 5eee30e49..236354530 100644
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -285,8 +285,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineGuardToClass(callInfo, &SetIteratorObject::class_);
case InlinableNative::IntrinsicGuardToStringIterator:
return inlineGuardToClass(callInfo, &StringIteratorObject::class_);
- case InlinableNative::IntrinsicIsListIterator:
- return inlineHasClass(callInfo, &ListIteratorObject::class_);
case InlinableNative::IntrinsicDefineDataProperty:
return inlineDefineDataProperty(callInfo);
case InlinableNative::IntrinsicObjectHasPrototype:
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 6c376d528..e7186ed30 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5784,6 +5784,36 @@ class MToAsync
TRIVIAL_NEW_WRAPPERS
};
+class MToAsyncGen
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ explicit MToAsyncGen(MDefinition* unwrapped)
+ : MUnaryInstruction(unwrapped)
+ {
+ setResultType(MIRType::Object);
+ }
+
+ public:
+ INSTRUCTION_HEADER(ToAsyncGen)
+ TRIVIAL_NEW_WRAPPERS
+};
+
+class MToAsyncIter
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ explicit MToAsyncIter(MDefinition* unwrapped)
+ : MUnaryInstruction(unwrapped)
+ {
+ setResultType(MIRType::Object);
+ }
+
+ public:
+ INSTRUCTION_HEADER(ToAsyncIter)
+ TRIVIAL_NEW_WRAPPERS
+};
+
class MToId
: public MUnaryInstruction,
public BoxInputsPolicy::Data
diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h
index 9e460a2ba..589dde077 100644
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -79,6 +79,8 @@ namespace jit {
_(BitNot) \
_(TypeOf) \
_(ToAsync) \
+ _(ToAsyncGen) \
+ _(ToAsyncIter) \
_(ToId) \
_(BitAnd) \
_(BitOr) \
diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp
index 1ff7adfd1..652c23bf1 100644
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -735,7 +735,7 @@ bool
NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc,
uint32_t stackDepth)
{
- MOZ_ASSERT(*pc == JSOP_YIELD);
+ MOZ_ASSERT(*pc == JSOP_YIELD || *pc == JSOP_AWAIT);
// Return value is still on the stack.
MOZ_ASSERT(stackDepth >= 1);
@@ -816,7 +816,7 @@ GeneratorThrowOrClose(JSContext* cx, BaselineFrame* frame, Handle<GeneratorObjec
// work. This function always returns false, so we're guaranteed to enter
// the exception handler where we will clear the pc.
JSScript* script = frame->script();
- uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
+ uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
frame->setOverridePc(script->offsetToPC(offset));
MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame));
diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp
index a4161ab00..3421001f7 100644
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -3462,8 +3462,8 @@ MacroAssemblerARMCompat::storePayload(const Value& val, const Address& dest)
ScratchRegisterScope scratch(asMasm());
SecondScratchRegisterScope scratch2(asMasm());
- if (val.isMarkable())
- ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch);
+ if (val.isGCThing())
+ ma_mov(ImmGCPtr(val.toGCThing()), scratch);
else
ma_mov(Imm32(val.toNunboxPayload()), scratch);
ma_str(scratch, ToPayload(dest), scratch2);
diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
index ecf02816e..ff4915d1a 100644
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -1606,6 +1606,32 @@ class LToAsync : public LCallInstructionHelper<1, 1, 0>
}
};
+class LToAsyncGen : public LCallInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(ToAsyncGen)
+ explicit LToAsyncGen(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* unwrapped() {
+ return getOperand(0);
+ }
+};
+
+class LToAsyncIter : public LCallInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(ToAsyncIter)
+ explicit LToAsyncIter(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* unwrapped() {
+ return getOperand(0);
+ }
+};
+
class LToIdV : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
{
public:
diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h
index e260d7e94..56b98940a 100644
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -353,6 +353,8 @@
_(Rest) \
_(TypeOfV) \
_(ToAsync) \
+ _(ToAsyncGen) \
+ _(ToAsyncIter) \
_(ToIdV) \
_(Floor) \
_(FloorF) \
diff --git a/js/src/js.msg b/js/src/js.msg
index f57b36a90..9dc5f4e9f 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -47,7 +47,6 @@ MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, JSEXN_TYPEERR, "{0} requires more than
MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor")
MSG_DEF(JSMSG_BAD_SORT_ARG, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
-MSG_DEF(JSMSG_CANT_WATCH, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}")
MSG_DEF(JSMSG_READ_ONLY, 1, JSEXN_TYPEERR, "{0} is read-only")
MSG_DEF(JSMSG_CANT_DELETE, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY, 0, JSEXN_TYPEERR, "can't delete non-configurable array element")
@@ -72,7 +71,6 @@ MSG_DEF(JSMSG_UNDEFINED_PROP, 1, JSEXN_REFERENCEERR, "reference to unde
MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 1, JSEXN_TYPEERR, "iterable for {0} should have array-like objects")
MSG_DEF(JSMSG_NESTING_GENERATOR, 0, JSEXN_TYPEERR, "already executing generator")
MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
-MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_WARN, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
MSG_DEF(JSMSG_ARRAYBUFFER_SLICE_DEPRECATED, 0, JSEXN_WARN, "ArrayBuffer.slice is deprecated; use ArrayBuffer.prototype.slice instead")
MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate character {0}")
MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
@@ -134,6 +132,8 @@ MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM, 0, JSEXN_RANGEERR, "form must be one of '
MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 0, JSEXN_RANGEERR, "repeat count must be non-negative")
MSG_DEF(JSMSG_NOT_A_CODEPOINT, 1, JSEXN_RANGEERR, "{0} is not a valid code point")
MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size")
+MSG_DEF(JSMSG_FLAGS_UNDEFINED_OR_NULL, 0, JSEXN_TYPEERR, "'flags' property must neither be undefined nor null")
+MSG_DEF(JSMSG_REQUIRES_GLOBAL_REGEXP, 1, JSEXN_TYPEERR, "{0} must be called with a global RegExp")
// Number
MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36")
@@ -185,7 +185,6 @@ 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_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
@@ -438,7 +437,6 @@ MSG_DEF(JSMSG_SC_SAB_DISABLED, 0, JSEXN_TYPEERR, "SharedArrayBuffer not
// Debugger
MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
-MSG_DEF(JSMSG_DEBUG_BAD_AWAIT, 0, JSEXN_TYPEERR, "await expression received invalid value")
MSG_DEF(JSMSG_DEBUG_BAD_LINE, 0, JSEXN_TYPEERR, "invalid line number")
MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 0, JSEXN_TYPEERR, "invalid script offset")
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
@@ -594,3 +592,9 @@ MSG_DEF(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,0, JSEXN_INTERNALERR, "P
// Iterator
MSG_DEF(JSMSG_RETURN_NOT_CALLABLE, 0, JSEXN_TYPEERR, "property 'return' of iterator is not callable")
MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have a 'throw' method")
+
+// Async Iteration
+MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_TYPEERR, "'for await' loop should be used with 'of'")
+MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")
+MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator")
+MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value")
diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build
index c176fbf0a..f3757f5a4 100644
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -77,6 +77,7 @@ UNIFIED_SOURCES += [
'testPrintf.cpp',
'testPrivateGCThingValue.cpp',
'testProfileStrings.cpp',
+ 'testPromise.cpp',
'testPropCache.cpp',
'testRegExp.cpp',
'testResolveRecursion.cpp',
@@ -124,11 +125,6 @@ if CONFIG['ENABLE_ION']:
'testJitRValueAlloc.cpp',
]
-if CONFIG['SPIDERMONKEY_PROMISE']:
- UNIFIED_SOURCES += [
- 'testPromise.cpp',
- ]
-
DEFINES['EXPORT_JS_API'] = True
LOCAL_INCLUDES += [
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 84a315587..6483641f3 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -39,7 +39,6 @@
#include "jsstr.h"
#include "jstypes.h"
#include "jsutil.h"
-#include "jswatchpoint.h"
#include "jsweakmap.h"
#include "jswrapper.h"
@@ -71,6 +70,7 @@
#include "js/StructuredClone.h"
#include "js/Utility.h"
#include "vm/AsyncFunction.h"
+#include "vm/AsyncIteration.h"
#include "vm/DateObject.h"
#include "vm/Debugger.h"
#include "vm/EnvironmentObject.h"
@@ -2011,6 +2011,28 @@ JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* n
}
JS_PUBLIC_API(bool)
+JS_GetOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp)
+{
+ RootedId id(cx);
+ if (!IndexToId(cx, index, &id)) {
+ return false;
+ }
+
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
+ return false;
+ }
+
+ if (desc.object() && desc.isDataDescriptor()) {
+ vp.set(desc.value());
+ } else {
+ vp.setUndefined();
+ }
+
+ return true;
+}
+
+JS_PUBLIC_API(bool)
JS_GetPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id,
MutableHandle<PropertyDescriptor> desc)
{
@@ -3570,6 +3592,11 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject env, Handle
return nullptr;
}
+ if (IsWrappedAsyncGenerator(fun)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
+ return nullptr;
+ }
+
if (CanReuseScriptForClone(cx->compartment(), fun, env)) {
// If the script is to be reused, either the script can already handle
// non-syntactic scopes, or there is only the standard global lexical
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index 67b3d4267..7795c5e4c 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2922,6 +2922,9 @@ extern JS_PUBLIC_API(bool)
JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
JS::MutableHandle<JS::PropertyDescriptor> desc);
+extern JS_PUBLIC_API(bool)
+JS_GetOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp);
+
/**
* Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain
* if no own property is found directly on obj. The object on which the
@@ -5084,7 +5087,9 @@ GetSymbolDescription(HandleSymbol symbol);
macro(split) \
macro(toPrimitive) \
macro(toStringTag) \
- macro(unscopables)
+ macro(unscopables) \
+ macro(asyncIterator) \
+ macro(matchAll)
enum class SymbolCode : uint32_t {
// There is one SymbolCode for each well-known symbol.
@@ -5701,6 +5706,7 @@ JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate);
#define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */
#define JSREG_STICKY 0x08u /* only match starting at lastIndex */
#define JSREG_UNICODE 0x10u /* unicode */
+#define JSREG_DOTALL 0x20u /* match . to everything including newlines */
extern JS_PUBLIC_API(JSObject*)
JS_NewRegExpObject(JSContext* cx, const char* bytes, size_t length, unsigned flags);
diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp
index e505a4b34..23b9d27ae 100644
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -37,7 +37,6 @@
#include "jsscript.h"
#include "jsstr.h"
#include "jstypes.h"
-#include "jswatchpoint.h"
#include "gc/Marking.h"
#include "jit/Ion.h"
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index d0caeb558..8ba186b08 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -13,7 +13,6 @@
#include "jsfriendapi.h"
#include "jsgc.h"
#include "jsiter.h"
-#include "jswatchpoint.h"
#include "jswrapper.h"
#include "gc/Marking.h"
@@ -76,7 +75,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
gcIncomingGrayPointers(nullptr),
debugModeBits(0),
randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
- watchpointMap(nullptr),
scriptCountsMap(nullptr),
debugScriptMap(nullptr),
debugEnvs(nullptr),
@@ -103,7 +101,6 @@ JSCompartment::~JSCompartment()
rt->lcovOutput.writeLCovResult(lcovOutput);
js_delete(jitCompartment_);
- js_delete(watchpointMap);
js_delete(scriptCountsMap);
js_delete(debugScriptMap);
js_delete(debugEnvs);
@@ -662,12 +659,6 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
if (traceOrMark == js::gc::GCRuntime::MarkRuntime && !zone()->isCollecting())
return;
- // During a GC, these are treated as weak pointers.
- if (traceOrMark == js::gc::GCRuntime::TraceRuntime) {
- if (watchpointMap)
- watchpointMap->markAll(trc);
- }
-
/* Mark debug scopes, if present */
if (debugEnvs)
debugEnvs->mark(trc);
@@ -712,9 +703,6 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
void
JSCompartment::finishRoots()
{
- if (watchpointMap)
- watchpointMap->clear();
-
if (debugEnvs)
debugEnvs->finish();
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 83c15da3b..05ff40b43 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -282,7 +282,6 @@ class MOZ_RAII AutoSetNewObjectMetadata : private JS::CustomAutoRooter
namespace js {
class DebugEnvironments;
class ObjectWeakMap;
-class WatchpointMap;
class WeakMapBase;
} // namespace js
@@ -811,8 +810,6 @@ struct JSCompartment
void sweepBreakpoints(js::FreeOp* fop);
public:
- js::WatchpointMap* watchpointMap;
-
js::ScriptCountsMap* scriptCountsMap;
js::DebugScriptMap* debugScriptMap;
diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp
index 65cc81a1a..72f03ea55 100644
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -32,6 +32,7 @@
#include "vm/ErrorObject.h"
#include "vm/GlobalObject.h"
#include "vm/SavedStacks.h"
+#include "vm/SelfHosting.h"
#include "vm/StringBuffer.h"
#include "jsobjinlines.h"
@@ -205,7 +206,12 @@ size_t
ExtraMallocSize(JSErrorReport* report)
{
if (report->linebuf())
- return (report->linebufLength() + 1) * sizeof(char16_t);
+ /*
+ * Mozilla bug 1352449. Count with null
+ * terminator and alignment. See CopyExtraData for
+ * the details about alignment.
+ */
+ return (report->linebufLength() + 1) * sizeof(char16_t) + 1;
return 0;
}
@@ -220,10 +226,20 @@ bool
CopyExtraData(JSContext* cx, uint8_t** cursor, JSErrorReport* copy, JSErrorReport* report)
{
if (report->linebuf()) {
+ /*
+ * Make sure cursor is properly aligned for char16_t for platforms
+ * which need it and it's at the end of the buffer on exit.
+ */
+ size_t alignment_backlog = 0;
+ if (size_t(*cursor) % 2)
+ (*cursor)++;
+ else
+ alignment_backlog = 1;
+
size_t linebufSize = (report->linebufLength() + 1) * sizeof(char16_t);
const char16_t* linebufCopy = (const char16_t*)(*cursor);
js_memcpy(*cursor, report->linebuf(), linebufSize);
- *cursor += linebufSize;
+ *cursor += linebufSize + alignment_backlog;
copy->initBorrowedLinebuf(linebufCopy, report->linebufLength(), report->tokenOffset());
}
@@ -1076,3 +1092,19 @@ js::ValueToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& byte
return "<<error converting value to string>>";
return bytes.encodeLatin1(cx, str);
}
+
+bool
+js::GetInternalError(JSContext* cx, unsigned errorNumber, MutableHandleValue error)
+{
+ FixedInvokeArgs<1> args(cx);
+ args[0].set(Int32Value(errorNumber));
+ return CallSelfHostedFunction(cx, "GetInternalError", NullHandleValue, args, error);
+}
+
+bool
+js::GetTypeError(JSContext* cx, unsigned errorNumber, MutableHandleValue error)
+{
+ FixedInvokeArgs<1> args(cx);
+ args[0].set(Int32Value(errorNumber));
+ return CallSelfHostedFunction(cx, "GetTypeError", NullHandleValue, args, error);
+}
diff --git a/js/src/jsexn.h b/js/src/jsexn.h
index 00120d89c..ee69e3c50 100644
--- a/js/src/jsexn.h
+++ b/js/src/jsexn.h
@@ -131,6 +131,11 @@ class AutoAssertNoPendingException
extern const char*
ValueToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& bytes);
+bool
+GetInternalError(JSContext* cx, unsigned errorNumber, MutableHandleValue error);
+bool
+GetTypeError(JSContext* cx, unsigned errorNumber, MutableHandleValue error);
+
} // namespace js
#endif /* jsexn_h */
diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp
index f7622cb44..bdb3c0a4d 100644
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -15,7 +15,6 @@
#include "jsgc.h"
#include "jsobj.h"
#include "jsprf.h"
-#include "jswatchpoint.h"
#include "jsweakmap.h"
#include "jswrapper.h"
@@ -579,7 +578,6 @@ void
js::TraceWeakMaps(WeakMapTracer* trc)
{
WeakMapBase::traceAllMappings(trc);
- WatchpointMap::traceAll(trc);
}
extern JS_FRIEND_API(bool)
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index 351667fb3..7b59689ff 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -948,6 +948,7 @@ IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */
#define JSITER_SYMBOLS 0x20 /* also include symbol property keys */
#define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
+#define JSITER_FORAWAITOF 0x80 /* for-await-of */
JS_FRIEND_API(bool)
RunningWithTrustedPrincipals(JSContext* cx);
@@ -2110,30 +2111,6 @@ JS_FRIEND_API(void*)
JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&);
namespace js {
-
-/**
- * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the
- * property |id|, using the callable object |callable| as the function to be
- * called for notifications.
- *
- * This is an internal function exposed -- temporarily -- only so that DOM
- * proxies can be watchable. Don't use it! We'll soon kill off the
- * Object.prototype.{,un}watch functions, at which point this will go too.
- */
-extern JS_FRIEND_API(bool)
-WatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
-
-/**
- * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for
- * the property |id|.
- *
- * This is an internal function exposed -- temporarily -- only so that DOM
- * proxies can be watchable. Don't use it! We'll soon kill off the
- * Object.prototype.{,un}watch functions, at which point this will go too.
- */
-extern JS_FRIEND_API(bool)
-UnwatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
-
namespace jit {
enum class InlinableNative : uint16_t;
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index 9edf238ef..ce1ca33fe 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -41,6 +41,7 @@
#include "js/CallNonGenericMethod.h"
#include "js/Proxy.h"
#include "vm/AsyncFunction.h"
+#include "vm/AsyncIteration.h"
#include "vm/Debugger.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
@@ -131,7 +132,11 @@ IsFunctionInStrictMode(JSFunction* fun)
static bool
IsNewerTypeFunction(JSFunction* fun) {
- return fun->isArrow() || fun->isGenerator() || fun->isAsync() || fun->isMethod();
+ return fun->isArrow() ||
+ fun->isStarGenerator() ||
+ fun->isLegacyGenerator() ||
+ fun->isAsync() ||
+ fun->isMethod();
}
// Beware: this function can be invoked on *any* function! That includes
@@ -308,6 +313,8 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args)
JSFunction* callerFun = &callerObj->as<JSFunction>();
if (IsWrappedAsyncFunction(callerFun))
callerFun = GetUnwrappedAsyncFunction(callerFun);
+ else if (IsWrappedAsyncGenerator(callerFun))
+ callerFun = GetUnwrappedAsyncGenerator(callerFun);
MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?");
if (callerFun->strict()) {
@@ -360,13 +367,15 @@ static const JSPropertySpec function_properties[] = {
static bool
ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId id)
{
- MOZ_ASSERT(fun->isInterpreted() || fun->isAsmJSNative());
+ bool isAsyncGenerator = IsWrappedAsyncGenerator(fun);
+
+ MOZ_ASSERT_IF(!isAsyncGenerator, fun->isInterpreted() || fun->isAsmJSNative());
MOZ_ASSERT(id == NameToId(cx->names().prototype));
// Assert that fun is not a compiler-created function object, which
// must never leak to script or embedding code and then be mutated.
// Also assert that fun is not bound, per the ES5 15.3.4.5 ref above.
- MOZ_ASSERT(!IsInternalFunctionObject(*fun));
+ MOZ_ASSERT_IF(!isAsyncGenerator, !IsInternalFunctionObject(*fun));
MOZ_ASSERT(!fun->isBoundFunction());
// Make the prototype object an instance of Object with the same parent as
@@ -376,7 +385,9 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId
bool isStarGenerator = fun->isStarGenerator();
Rooted<GlobalObject*> global(cx, &fun->global());
RootedObject objProto(cx);
- if (isStarGenerator)
+ if (isAsyncGenerator)
+ objProto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, global);
+ else if (isStarGenerator)
objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
else
objProto = GlobalObject::getOrCreateObjectPrototype(cx, global);
@@ -392,7 +403,7 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId
// non-enumerable, and writable. However, per the 15 July 2013 ES6 draft,
// section 15.19.3, the .prototype of a generator function does not link
// back with a .constructor.
- if (!isStarGenerator) {
+ if (!isStarGenerator && !isAsyncGenerator) {
RootedValue objVal(cx, ObjectValue(*fun));
if (!DefineProperty(cx, proto, cx->names().constructor, objVal, nullptr, nullptr, 0))
return false;
@@ -442,8 +453,14 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
* - Arrow functions
* - Function.prototype
*/
- if (fun->isBuiltin() || (!fun->isConstructor() && !fun->isGenerator()))
- return true;
+ if (!IsWrappedAsyncGenerator(fun)) {
+ if (fun->isBuiltin())
+ return true;
+ if (!fun->isConstructor()) {
+ if (!fun->isStarGenerator() && !fun->isLegacyGenerator() && !fun->isAsync())
+ return true;
+ }
+ }
if (!ResolveInterpretedFunctionPrototype(cx, fun, id))
return false;
@@ -515,7 +532,7 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
{
enum FirstWordFlag {
HasAtom = 0x1,
- IsStarGenerator = 0x2,
+ HasStarGeneratorProto = 0x2,
IsLazy = 0x4,
HasSingletonType = 0x8
};
@@ -544,8 +561,8 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
if (fun->explicitName() || fun->hasCompileTimeName() || fun->hasGuessedAtom())
firstword |= HasAtom;
- if (fun->isStarGenerator())
- firstword |= IsStarGenerator;
+ if (fun->isStarGenerator() || fun->isAsync())
+ firstword |= HasStarGeneratorProto;
if (fun->isInterpretedLazy()) {
// Encode a lazy script.
@@ -581,7 +598,7 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
if (mode == XDR_DECODE) {
RootedObject proto(cx);
- if (firstword & IsStarGenerator) {
+ if (firstword & HasStarGeneratorProto) {
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!proto)
return false;
@@ -938,6 +955,11 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
return FunctionToString(cx, unwrapped, prettyPrint);
}
+ if (IsWrappedAsyncGenerator(fun)) {
+ RootedFunction unwrapped(cx, GetUnwrappedAsyncGenerator(fun));
+ return FunctionToString(cx, unwrapped, prettyPrint);
+ }
+
StringBuffer out(cx);
RootedScript script(cx);
@@ -1556,7 +1578,7 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
return true;
}
- args.rval().setBoolean(fun->isGenerator());
+ args.rval().setBoolean(fun->isStarGenerator() || fun->isLegacyGenerator());
return true;
}
@@ -1588,8 +1610,6 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
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;
@@ -1600,10 +1620,14 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
&mutedErrors);
const char* introductionType = "Function";
- if (isAsync)
- introductionType = "AsyncFunction";
- else if (generatorKind != NotGenerator)
+ if (isAsync) {
+ if (isStarGenerator)
+ introductionType = "AsyncGenerator";
+ else
+ introductionType = "AsyncFunction";
+ } else if (generatorKind != NotGenerator) {
introductionType = "GeneratorFunction";
+ }
const char* introducerFilename = filename;
if (maybeScript && maybeScript->scriptSource()->introducerFilename())
@@ -1701,7 +1725,7 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
// Step 4.d, use %Generator% as the fallback prototype.
// Also use %Generator% for the unwrapped function of async functions.
- if (!proto && isStarGenerator) {
+ if (!proto && (isStarGenerator || isAsync)) {
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
if (!proto)
return false;
@@ -1731,12 +1755,20 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
: SourceBufferHolder::NoOwnership;
bool ok;
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
- if (isAsync)
- ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
- else if (isStarGenerator)
- ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
- else
- ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
+ if (isAsync) {
+ if (isStarGenerator) {
+ ok = frontend::CompileStandaloneAsyncGenerator(cx, &fun, options, srcBuf,
+ parameterListEnd);
+ } else {
+ ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf,
+ parameterListEnd);
+ }
+ } else {
+ if (isStarGenerator)
+ ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
+ else
+ ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
+ }
// Step 33.
args.rval().setObject(*fun);
@@ -1762,14 +1794,14 @@ js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- // Save the callee before its reset in FunctionConstructor().
+ // Save the callee before it's reset in FunctionConstructor().
RootedObject newTarget(cx);
if (args.isConstructing())
newTarget = &args.newTarget().toObject();
else
newTarget = &args.callee();
- if (!FunctionConstructor(cx, args, StarGenerator, AsyncFunction))
+ if (!FunctionConstructor(cx, args, NotGenerator, AsyncFunction))
return false;
// ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
@@ -1795,6 +1827,40 @@ js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
}
bool
+js::AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Save the callee before its reset in FunctionConstructor().
+ RootedObject newTarget(cx);
+ if (args.isConstructing())
+ newTarget = &args.newTarget().toObject();
+ else
+ newTarget = &args.callee();
+
+ if (!FunctionConstructor(cx, args, StarGenerator, AsyncFunction))
+ return false;
+
+ RootedObject proto(cx);
+ if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+ return false;
+
+ if (!proto) {
+ proto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
+ if (!proto)
+ return false;
+ }
+
+ RootedFunction unwrapped(cx, &args.rval().toObject().as<JSFunction>());
+ RootedObject wrapped(cx, WrapAsyncGeneratorWithProto(cx, unwrapped, proto));
+ if (!wrapped)
+ return false;
+
+ args.rval().setObject(*wrapped);
+ return true;
+}
+
+bool
JSFunction::isBuiltinFunctionConstructor()
{
return maybeNative() == Function || maybeNative() == Generator;
@@ -1965,7 +2031,7 @@ NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind,
gc::AllocKind allocKind, HandleObject proto)
{
RootedObject cloneProto(cx, proto);
- if (!proto && fun->isStarGenerator()) {
+ if (!proto && (fun->isStarGenerator() || fun->isAsync())) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto)
return nullptr;
diff --git a/js/src/jsfun.h b/js/src/jsfun.h
index 234169507..ea9e7af9b 100644
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -89,15 +89,15 @@ class JSFunction : public js::NativeObject
ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
- INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND,
+ INTERPRETED_METHOD_GENERATOR_OR_ASYNC = INTERPRETED | METHOD_KIND,
INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
- INTERPRETED_LAMBDA_GENERATOR = INTERPRETED | LAMBDA,
+ INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = INTERPRETED | LAMBDA,
INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
- INTERPRETED_GENERATOR = INTERPRETED,
+ INTERPRETED_GENERATOR_OR_ASYNC = INTERPRETED,
NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
STABLE_ACROSS_CLONES = CONSTRUCTOR | HAS_GUESSED_ATOM | LAMBDA |
@@ -146,7 +146,9 @@ class JSFunction : public js::NativeObject
MOZ_ASSERT_IF(nonLazyScript()->funHasExtensibleScope() ||
nonLazyScript()->needsHomeObject() ||
nonLazyScript()->isDerivedClassConstructor() ||
- isGenerator(),
+ isStarGenerator() ||
+ isLegacyGenerator() ||
+ isAsync(),
nonLazyScript()->bodyScope()->hasEnvironment());
return nonLazyScript()->bodyScope()->hasEnvironment();
@@ -501,8 +503,6 @@ class JSFunction : public js::NativeObject
return js::NotGenerator;
}
- bool isGenerator() const { return generatorKind() != js::NotGenerator; }
-
bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
@@ -513,9 +513,9 @@ class JSFunction : public js::NativeObject
bool isAsync() const {
if (isInterpretedLazy())
- return lazyScript()->asyncKind() == js::AsyncFunction;
+ return lazyScript()->isAsync();
if (hasScript())
- return nonLazyScript()->asyncKind() == js::AsyncFunction;
+ return nonLazyScript()->isAsync();
return false;
}
@@ -660,6 +660,9 @@ Generator(JSContext* cx, unsigned argc, Value* vp);
extern bool
AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
+extern bool
+AsyncGeneratorConstructor(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*
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
index b2ee8d67b..5a9d732b6 100644
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -207,7 +207,6 @@
#include "jsscript.h"
#include "jstypes.h"
#include "jsutil.h"
-#include "jswatchpoint.h"
#include "jsweakmap.h"
#ifdef XP_WIN
# include "jswin.h"
@@ -2392,11 +2391,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess
Debugger::markIncomingCrossCompartmentEdges(&trc);
WeakMapBase::markAll(zone, &trc);
- for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
- c->trace(&trc);
- if (c->watchpointMap)
- c->watchpointMap->markAll(&trc);
- }
// Mark all gray roots, making sure we call the trace callback to get the
// current set.
@@ -2405,7 +2399,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess
}
// Sweep everything to fix up weak pointers
- WatchpointMap::sweepAll(rt);
Debugger::sweepAll(rt->defaultFreeOp());
jit::JitRuntime::SweepJitcodeGlobalTable(rt);
rt->gc.sweepZoneAfterCompacting(zone);
@@ -3850,10 +3843,6 @@ GCRuntime::markWeakReferences(gcstats::Phase phase)
for (ZoneIterT zone(rt); !zone.done(); zone.next())
markedAny |= WeakMapBase::markZoneIteratively(zone, &marker);
}
- for (CompartmentsIterT<ZoneIterT> c(rt); !c.done(); c.next()) {
- if (c->watchpointMap)
- markedAny |= c->watchpointMap->markIteratively(&marker);
- }
markedAny |= Debugger::markAllIteratively(&marker);
markedAny |= jit::JitRuntime::MarkJitcodeGlobalTableIteratively(&marker);
@@ -4625,9 +4614,6 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock)
// Bug 1071218: the following two methods have not yet been
// refactored to work on a single zone-group at once.
- // Collect watch points associated with unreachable objects.
- WatchpointMap::sweepAll(rt);
-
// Detach unreachable debuggers and global objects from each other.
Debugger::sweepAll(&fop);
diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp
index 749e15d27..c58f32382 100644
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -24,6 +24,7 @@
#include "jstypes.h"
#include "jsutil.h"
+#include "builtin/SelfHostingDefines.h"
#include "ds/Sort.h"
#include "gc/Marking.h"
#include "js/Proxy.h"
@@ -915,28 +916,30 @@ js::GetIteratorObject(JSContext* cx, HandleObject obj, uint32_t flags)
return iterator;
}
+// ES 2017 draft 7.4.7.
JSObject*
-js::CreateItrResultObject(JSContext* cx, HandleValue value, bool done)
+js::CreateIterResultObject(JSContext* cx, HandleValue value, bool done)
{
- // FIXME: We can cache the iterator result object shape somewhere.
- AssertHeapIsIdle(cx);
+ // Step 1 (implicit).
- RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global()));
- if (!proto)
+ // Step 2.
+ RootedObject resultObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!resultObj)
return nullptr;
- RootedPlainObject obj(cx, NewObjectWithGivenProto<PlainObject>(cx, proto));
- if (!obj)
- return nullptr;
-
- if (!DefineProperty(cx, obj, cx->names().value, value))
+ // Step 3.
+ if (!DefineProperty(cx, resultObj, cx->names().value, value))
return nullptr;
- RootedValue doneBool(cx, BooleanValue(done));
- if (!DefineProperty(cx, obj, cx->names().done, doneBool))
+ // Step 4.
+ if (!DefineProperty(cx, resultObj, cx->names().done,
+ done ? TrueHandleValue : FalseHandleValue))
+ {
return nullptr;
+ }
- return obj;
+ // Step 5.
+ return resultObj;
}
bool
@@ -1135,16 +1138,36 @@ static const JSFunctionSpec string_iterator_methods[] = {
JS_FS_END
};
+static const Class RegExpStringIteratorPrototypeClass = {
+ "RegExp String Iterator",
+ 0
+};
+
enum {
- ListIteratorSlotIteratedObject,
- ListIteratorSlotNextIndex,
- ListIteratorSlotNextMethod,
- ListIteratorSlotCount
+ RegExpStringIteratorSlotRegExp,
+ RegExpStringIteratorSlotString,
+ RegExpStringIteratorSlotFlags,
+ RegExpStringIteratorSlotDone,
+ RegExpStringIteratorSlotCount
+};
+
+static_assert(RegExpStringIteratorSlotRegExp == REGEXP_STRING_ITERATOR_REGEXP_SLOT,
+ "RegExpStringIteratorSlotRegExp must match self-hosting define for regexp slot.");
+static_assert(RegExpStringIteratorSlotString == REGEXP_STRING_ITERATOR_STRING_SLOT,
+ "RegExpStringIteratorSlotString must match self-hosting define for string slot.");
+static_assert(RegExpStringIteratorSlotFlags == REGEXP_STRING_ITERATOR_FLAGS_SLOT,
+ "RegExpStringIteratorSlotFlags must match self-hosting define for flags slot.");
+static_assert(RegExpStringIteratorSlotDone == REGEXP_STRING_ITERATOR_DONE_SLOT,
+ "RegExpStringIteratorSlotDone must match self-hosting define for done slot.");
+
+const Class RegExpStringIteratorObject::class_ = {
+ "RegExp String Iterator",
+ JSCLASS_HAS_RESERVED_SLOTS(RegExpStringIteratorSlotCount)
};
-const Class ListIteratorObject::class_ = {
- "List Iterator",
- JSCLASS_HAS_RESERVED_SLOTS(ListIteratorSlotCount)
+static const JSFunctionSpec regexp_string_iterator_methods[] = {
+ JS_SELF_HOSTED_FN("next", "RegExpStringIteratorNext", 0, 0),
+ JS_FS_END
};
JSObject*
@@ -1553,6 +1576,30 @@ GlobalObject::initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> globa
return true;
}
+/* static */ bool
+GlobalObject::initRegExpStringIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
+{
+ if (global->getReservedSlot(REGEXP_STRING_ITERATOR_PROTO).isObject())
+ return true;
+
+ RootedObject iteratorProto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));
+ if (!iteratorProto)
+ return false;
+
+ const Class* cls = &RegExpStringIteratorPrototypeClass;
+ RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, cls,
+ iteratorProto));
+ if (!proto ||
+ !DefinePropertiesAndFunctions(cx, proto, nullptr, regexp_string_iterator_methods) ||
+ !DefineToStringTag(cx, proto, cx->names().RegExpStringIterator))
+ {
+ return false;
+ }
+
+ global->setReservedSlot(REGEXP_STRING_ITERATOR_PROTO, ObjectValue(*proto));
+ return true;
+}
+
JSObject*
js::InitLegacyIteratorClass(JSContext* cx, HandleObject obj)
{
diff --git a/js/src/jsiter.h b/js/src/jsiter.h
index f11f09b55..0b324a014 100644
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -151,7 +151,7 @@ class StringIteratorObject : public JSObject
static const Class class_;
};
-class ListIteratorObject : public JSObject
+class RegExpStringIteratorObject : public JSObject
{
public:
static const Class class_;
@@ -216,10 +216,10 @@ ThrowStopIteration(JSContext* cx);
/*
* Create an object of the form { value: VALUE, done: DONE }.
- * ES6 draft from 2013-09-05, section 25.4.3.4.
+ * ES 2017 draft 7.4.7.
*/
extern JSObject*
-CreateItrResultObject(JSContext* cx, HandleValue value, bool done);
+CreateIterResultObject(JSContext* cx, HandleValue value, bool done);
extern JSObject*
InitLegacyIteratorClass(JSContext* cx, HandleObject obj);
@@ -227,6 +227,8 @@ InitLegacyIteratorClass(JSContext* cx, HandleObject obj);
extern JSObject*
InitStopIterationClass(JSContext* cx, HandleObject obj);
+enum class IteratorKind { Sync, Async };
+
} /* namespace js */
#endif /* jsiter_h */
diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp
index 98f8fc741..4e96e01e8 100644
--- a/js/src/jsnativestack.cpp
+++ b/js/src/jsnativestack.cpp
@@ -26,11 +26,7 @@
# include <sys/syscall.h>
# include <sys/types.h>
# include <unistd.h>
-static pid_t
-gettid()
-{
- return syscall(__NR_gettid);
-}
+# define gettid() static_cast<pid_t>(syscall(SYS_gettid))
# endif
#else
@@ -71,6 +67,20 @@ js::GetNativeStackBaseImpl()
# endif
}
+#elif defined(XP_SOLARIS)
+
+#include <ucontext.h>
+
+JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0);
+
+void*
+js::GetNativeStackBaseImpl()
+{
+ stack_t st;
+ stack_getbounds(&st);
+ return static_cast<char*>(st.ss_sp) + st.ss_size;
+}
+
#elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__)
void*
js::GetNativeStackBaseImpl()
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index 6f9596924..ef1291079 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -33,7 +33,6 @@
#include "jsstr.h"
#include "jstypes.h"
#include "jsutil.h"
-#include "jswatchpoint.h"
#include "jswin.h"
#include "jswrapper.h"
@@ -1011,13 +1010,7 @@ js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTa
JSObject::nonNativeSetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result)
{
- RootedValue value(cx, v);
- if (MOZ_UNLIKELY(obj->watched())) {
- WatchpointMap* wpmap = cx->compartment()->watchpointMap;
- if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &value))
- return false;
- }
- return obj->getOpsSetProperty()(cx, obj, id, value, receiver, result);
+ return obj->getOpsSetProperty()(cx, obj, id, v, receiver, result);
}
/* static */ bool
@@ -2795,68 +2788,6 @@ js::GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
return true;
}
-bool
-js::WatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id, JS::HandleObject callable)
-{
- RootedObject obj(cx, ToWindowIfWindowProxy(origObj));
- if (obj->isNative()) {
- // Use sparse indexes for watched objects, as dense elements can be
- // written to without checking the watchpoint map.
- if (!NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>()))
- return false;
-
- MarkTypePropertyNonData(cx, obj, id);
- }
-
- WatchpointMap* wpmap = cx->compartment()->watchpointMap;
- if (!wpmap) {
- wpmap = cx->runtime()->new_<WatchpointMap>();
- if (!wpmap || !wpmap->init()) {
- ReportOutOfMemory(cx);
- js_delete(wpmap);
- return false;
- }
- cx->compartment()->watchpointMap = wpmap;
- }
-
- return wpmap->watch(cx, obj, id, js::WatchHandler, callable);
-}
-
-bool
-js::UnwatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id)
-{
- // Looking in the map for an unsupported object will never hit, so we don't
- // need to check for nativeness or watchable-ness here.
- RootedObject obj(cx, ToWindowIfWindowProxy(origObj));
- if (WatchpointMap* wpmap = cx->compartment()->watchpointMap)
- wpmap->unwatch(obj, id, nullptr, nullptr);
- return true;
-}
-
-bool
-js::WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
-{
- if (WatchOp op = obj->getOpsWatch())
- return op(cx, obj, id, callable);
-
- if (!obj->isNative() || obj->is<TypedArrayObject>()) {
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH,
- obj->getClass()->name);
- return false;
- }
-
- return WatchGuts(cx, obj, id, callable);
-}
-
-bool
-js::UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id)
-{
- if (UnwatchOp op = obj->getOpsUnwatch())
- return op(cx, obj, id);
-
- return UnwatchGuts(cx, obj, id);
-}
-
const char*
js::GetObjectClassName(JSContext* cx, HandleObject obj)
{
@@ -3416,7 +3347,6 @@ JSObject::dump(FILE* fp) const
if (obj->isBoundFunction()) fprintf(fp, " bound_function");
if (obj->isQualifiedVarObj()) fprintf(fp, " varobj");
if (obj->isUnqualifiedVarObj()) fprintf(fp, " unqualified_varobj");
- if (obj->watched()) fprintf(fp, " watched");
if (obj->isIteratedSingleton()) fprintf(fp, " iterated_singleton");
if (obj->isNewGroupUnknown()) fprintf(fp, " new_type_unknown");
if (obj->hasUncacheableProto()) fprintf(fp, " has_uncacheable_proto");
diff --git a/js/src/jsobj.h b/js/src/jsobj.h
index db2c22b76..01845d7e6 100644
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -141,8 +141,6 @@ class JSObject : public js::gc::Cell
js::GetOwnPropertyOp getOpsGetOwnPropertyDescriptor()
const { return getClass()->getOpsGetOwnPropertyDescriptor(); }
js::DeletePropertyOp getOpsDeleteProperty() const { return getClass()->getOpsDeleteProperty(); }
- js::WatchOp getOpsWatch() const { return getClass()->getOpsWatch(); }
- js::UnwatchOp getOpsUnwatch() const { return getClass()->getOpsUnwatch(); }
js::GetElementsOp getOpsGetElements() const { return getClass()->getOpsGetElements(); }
JSNewEnumerateOp getOpsEnumerate() const { return getClass()->getOpsEnumerate(); }
JSFunToStringOp getOpsFunToString() const { return getClass()->getOpsFunToString(); }
@@ -221,11 +219,6 @@ class JSObject : public js::gc::Cell
inline bool isBoundFunction() const;
inline bool hasSpecialEquality() const;
- inline bool watched() const;
- static bool setWatched(js::ExclusiveContext* cx, JS::HandleObject obj) {
- return setFlags(cx, obj, js::BaseShape::WATCHED, GENERATE_SHAPE);
- }
-
// A "qualified" varobj is the object on which "qualified" variable
// declarations (i.e., those defined with "var") are kept.
//
@@ -1032,21 +1025,6 @@ extern bool
DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
DefineAsIntrinsic intrinsic);
-/*
- * Set a watchpoint: a synchronous callback when the given property of the
- * given object is set.
- *
- * Watchpoints are nonstandard and do not fit in well with the way ES6
- * specifies [[Set]]. They are also insufficient for implementing
- * Object.observe.
- */
-extern bool
-WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
-
-/* Clear a watchpoint. */
-extern bool
-UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id);
-
/* ES6 draft rev 36 (2015 March 17) 7.1.1 ToPrimitive(vp[, preferredType]) */
extern bool
ToPrimitiveSlow(JSContext* cx, JSType hint, MutableHandleValue vp);
diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h
index c132ee6b2..98e740142 100644
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -464,12 +464,6 @@ JSObject::isBoundFunction() const
}
inline bool
-JSObject::watched() const
-{
- return hasAllFlags(js::BaseShape::WATCHED);
-}
-
-inline bool
JSObject::isDelegate() const
{
return hasAllFlags(js::BaseShape::DELEGATE);
diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h
index e56eebb2d..e417e3a64 100644
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -655,7 +655,8 @@ IsValidBytecodeOffset(JSContext* cx, JSScript* script, size_t offset);
inline bool
FlowsIntoNext(JSOp op)
{
- /* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
+ // JSOP_YIELD/JSOP_AWAIT is considered to flow into the next instruction,
+ // like JSOP_CALL.
switch (op) {
case JSOP_RETRVAL:
case JSOP_RETURN:
diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h
index dc7cdb85a..3cf8621cc 100644
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -57,12 +57,6 @@
#define IF_SAB(real,imaginary) imaginary
#endif
-#ifdef SPIDERMONKEY_PROMISE
-#define IF_PROMISE(real,imaginary) real
-#else
-#define IF_PROMISE(real,imaginary) imaginary
-#endif
-
#define JS_FOR_PROTOTYPES(real,imaginary) \
imaginary(Null, 0, InitNullClass, dummy) \
real(Object, 1, InitViaClassSpec, OCLASP(Plain)) \
@@ -118,7 +112,7 @@ IF_SAB(real,imaginary)(Atomics, 47, InitAtomicsClass, OCLASP(Atomics)) \
imaginary(WasmInstance, 51, dummy, dummy) \
imaginary(WasmMemory, 52, dummy, dummy) \
imaginary(WasmTable, 53, dummy, dummy) \
-IF_PROMISE(real,imaginary)(Promise, 54, InitViaClassSpec, OCLASP(Promise)) \
+ real(Promise, 54, InitViaClassSpec, OCLASP(Promise)) \
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
index fc7438e3b..bdd411d04 100644
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -402,8 +402,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
ntrynotes = script->trynotes()->length;
if (script->hasScopeNotes())
nscopenotes = script->scopeNotes()->length;
- if (script->hasYieldOffsets())
- nyieldoffsets = script->yieldOffsets().length();
+ if (script->hasYieldAndAwaitOffsets())
+ nyieldoffsets = script->yieldAndAwaitOffsets().length();
nTypeSets = script->nTypeSets();
funLength = script->funLength();
@@ -902,7 +902,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
}
for (i = 0; i < nyieldoffsets; ++i) {
- uint32_t* offset = &script->yieldOffsets()[i];
+ uint32_t* offset = &script->yieldAndAwaitOffsets()[i];
if (!xdr->codeUint32(offset))
return false;
}
@@ -2456,7 +2456,7 @@ ScriptDataSize(uint32_t nscopes, uint32_t nconsts, uint32_t nobjects,
if (nscopenotes != 0)
size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
if (nyieldoffsets != 0)
- size += sizeof(YieldOffsetArray) + nyieldoffsets * sizeof(uint32_t);
+ size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
return size;
}
@@ -2558,10 +2558,10 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t nsco
cursor += sizeof(ScopeNoteArray);
}
- YieldOffsetArray* yieldOffsets = nullptr;
+ YieldAndAwaitOffsetArray* yieldAndAwaitOffsets = nullptr;
if (nyieldoffsets != 0) {
- yieldOffsets = reinterpret_cast<YieldOffsetArray*>(cursor);
- cursor += sizeof(YieldOffsetArray);
+ yieldAndAwaitOffsets = reinterpret_cast<YieldAndAwaitOffsetArray*>(cursor);
+ cursor += sizeof(YieldAndAwaitOffsetArray);
}
if (nconsts != 0) {
@@ -2602,8 +2602,8 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t nsco
}
if (nyieldoffsets != 0) {
- yieldOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
- size_t vectorSize = nyieldoffsets * sizeof(script->yieldOffsets()[0]);
+ yieldAndAwaitOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
+ size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsets()[0]);
#ifdef DEBUG
memset(cursor, 0, vectorSize);
#endif
@@ -2623,10 +2623,10 @@ JSScript::initFunctionPrototype(ExclusiveContext* cx, Handle<JSScript*> script,
uint32_t numObjects = 0;
uint32_t numTryNotes = 0;
uint32_t numScopeNotes = 0;
- uint32_t numYieldOffsets = 0;
+ uint32_t numYieldAndAwaitOffsets = 0;
uint32_t numTypeSets = 0;
if (!partiallyInit(cx, script, numScopes, numConsts, numObjects, numTryNotes,
- numScopeNotes, numYieldOffsets, numTypeSets))
+ numScopeNotes, numYieldAndAwaitOffsets, numTypeSets))
{
return false;
}
@@ -2739,7 +2739,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
if (!partiallyInit(cx, script,
bce->scopeList.length(), bce->constList.length(), bce->objectList.length,
bce->tryNoteList.length(), bce->scopeNoteList.length(),
- bce->yieldOffsetList.length(), bce->typesetCount))
+ bce->yieldAndAwaitOffsetList.length(), bce->typesetCount))
{
return false;
}
@@ -2794,8 +2794,8 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
// Copy yield offsets last, as the generator kind is set in
// initFromFunctionBox.
- if (bce->yieldOffsetList.length() != 0)
- bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength);
+ if (bce->yieldAndAwaitOffsetList.length() != 0)
+ bce->yieldAndAwaitOffsetList.finish(script->yieldAndAwaitOffsets(), prologueLength);
#ifdef DEBUG
script->assertValidJumpTargets();
@@ -3188,7 +3188,7 @@ CloneInnerInterpretedFunction(JSContext* cx, HandleScope enclosingScope, HandleF
{
/* NB: Keep this in sync with XDRInterpretedFunction. */
RootedObject cloneProto(cx);
- if (srcFun->isStarGenerator()) {
+ if (srcFun->isStarGenerator() || srcFun->isAsync()) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto)
return nullptr;
@@ -3242,7 +3242,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
uint32_t nscopes = src->scopes()->length;
uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->length : 0;
- uint32_t nyieldoffsets = src->hasYieldOffsets() ? src->yieldOffsets().length() : 0;
+ uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().length() : 0;
/* Script data */
@@ -3380,8 +3380,10 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
if (nscopenotes != 0)
dst->scopeNotes()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotes()->vector);
- if (nyieldoffsets != 0)
- dst->yieldOffsets().vector_ = Rebase<uint32_t>(dst, src, src->yieldOffsets().vector_);
+ if (nyieldoffsets != 0) {
+ dst->yieldAndAwaitOffsets().vector_ =
+ Rebase<uint32_t>(dst, src, src->yieldAndAwaitOffsets().vector_);
+ }
/*
* Function delazification assumes that their script does not have a
@@ -3917,7 +3919,9 @@ JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script)
if (script->needsArgsObj())
return true;
- MOZ_ASSERT(!script->isGenerator());
+ MOZ_ASSERT(!script->isStarGenerator());
+ MOZ_ASSERT(!script->isLegacyGenerator());
+ MOZ_ASSERT(!script->isAsync());
script->needsArgsObj_ = true;
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
index 85eb2938d..c19fbfc71 100644
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -156,7 +156,7 @@ struct ScopeNoteArray {
uint32_t length; // Count of indexed try notes.
};
-class YieldOffsetArray {
+class YieldAndAwaitOffsetArray {
friend bool
detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
MutableHandle<GCVector<Scope*>> scopes);
@@ -1327,13 +1327,12 @@ class JSScript : public js::gc::TenuredCell
js::GeneratorKind generatorKind() const {
return js::GeneratorKindFromBits(generatorKindBits_);
}
- bool isGenerator() const { return generatorKind() != js::NotGenerator; }
bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
void setGeneratorKind(js::GeneratorKind kind) {
// A script only gets its generator kind set as part of initialization,
// so it can only transition from not being a generator.
- MOZ_ASSERT(!isGenerator());
+ MOZ_ASSERT(!isStarGenerator() && !isLegacyGenerator());
generatorKindBits_ = GeneratorKindAsBits(kind);
}
@@ -1341,6 +1340,10 @@ class JSScript : public js::gc::TenuredCell
return isAsync_ ? js::AsyncFunction : js::SyncFunction;
}
+ bool isAsync() const {
+ return isAsync_;
+ }
+
void setAsyncKind(js::FunctionAsyncKind kind) {
isAsync_ = kind == js::AsyncFunction;
}
@@ -1493,7 +1496,8 @@ class JSScript : public js::gc::TenuredCell
bool isRelazifiable() const {
return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
- !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() &&
+ !isStarGenerator() && !isLegacyGenerator() && !isAsync() &&
+ !hasBaselineScript() && !hasAnyIonScript() &&
!isDefaultClassConstructor() &&
!doNotRelazify_;
}
@@ -1695,7 +1699,9 @@ class JSScript : public js::gc::TenuredCell
bool hasObjects() const { return hasArray(OBJECTS); }
bool hasTrynotes() const { return hasArray(TRYNOTES); }
bool hasScopeNotes() const { return hasArray(SCOPENOTES); }
- bool hasYieldOffsets() const { return isGenerator(); }
+ bool hasYieldAndAwaitOffsets() const {
+ return isStarGenerator() || isLegacyGenerator() || isAsync();
+ }
#define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0))
@@ -1704,7 +1710,9 @@ class JSScript : public js::gc::TenuredCell
size_t objectsOffset() const { return OFF(constsOffset, hasConsts, js::ConstArray); }
size_t trynotesOffset() const { return OFF(objectsOffset, hasObjects, js::ObjectArray); }
size_t scopeNotesOffset() const { return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); }
- size_t yieldOffsetsOffset() const { return OFF(scopeNotesOffset, hasScopeNotes, js::ScopeNoteArray); }
+ size_t yieldAndAwaitOffsetsOffset() const {
+ return OFF(scopeNotesOffset, hasScopeNotes, js::ScopeNoteArray);
+ }
#undef OFF
@@ -1734,9 +1742,10 @@ class JSScript : public js::gc::TenuredCell
return reinterpret_cast<js::ScopeNoteArray*>(data + scopeNotesOffset());
}
- js::YieldOffsetArray& yieldOffsets() {
- MOZ_ASSERT(hasYieldOffsets());
- return *reinterpret_cast<js::YieldOffsetArray*>(data + yieldOffsetsOffset());
+ js::YieldAndAwaitOffsetArray& yieldAndAwaitOffsets() {
+ MOZ_ASSERT(hasYieldAndAwaitOffsets());
+ return *reinterpret_cast<js::YieldAndAwaitOffsetArray*>(data +
+ yieldAndAwaitOffsetsOffset());
}
bool hasLoops();
@@ -2112,8 +2121,6 @@ class LazyScript : public gc::TenuredCell
GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); }
- bool isGenerator() const { return generatorKind() != NotGenerator; }
-
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
@@ -2121,7 +2128,7 @@ class LazyScript : public gc::TenuredCell
void setGeneratorKind(GeneratorKind kind) {
// A script only gets its generator kind set as part of initialization,
// so it can only transition from NotGenerator.
- MOZ_ASSERT(!isGenerator());
+ MOZ_ASSERT(!isStarGenerator() && !isLegacyGenerator());
// Legacy generators cannot currently be lazy.
MOZ_ASSERT(kind != LegacyGenerator);
p_.generatorKindBits = GeneratorKindAsBits(kind);
@@ -2131,6 +2138,10 @@ class LazyScript : public gc::TenuredCell
return p_.isAsync ? AsyncFunction : SyncFunction;
}
+ bool isAsync() const {
+ return p_.isAsync;
+ }
+
void setAsyncKind(FunctionAsyncKind kind) {
p_.isAsync = kind == AsyncFunction;
}
diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp
index 74f61b87d..3964ab84e 100644
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2584,6 +2584,7 @@ static const JSFunctionSpec string_methods[] = {
/* Perl-ish methods (search is actually Python-esque). */
JS_SELF_HOSTED_FN("match", "String_match", 1,0),
+ JS_SELF_HOSTED_FN("matchAll", "String_matchAll", 1,0),
JS_SELF_HOSTED_FN("search", "String_search", 1,0),
JS_SELF_HOSTED_FN("replace", "String_replace", 2,0),
JS_SELF_HOSTED_FN("split", "String_split", 2,0),
diff --git a/js/src/jsversion.h b/js/src/jsversion.h
index 8bdfe47b6..cf4c6e73a 100644
--- a/js/src/jsversion.h
+++ b/js/src/jsversion.h
@@ -12,7 +12,6 @@
*/
#define JS_HAS_STR_HTML_HELPERS 1 /* (no longer used) */
#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
-#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */
#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */
#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */
diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp
deleted file mode 100644
index 34479a990..000000000
--- a/js/src/jswatchpoint.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/* -*- 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 "jswatchpoint.h"
-
-#include "jsatom.h"
-#include "jscompartment.h"
-#include "jsfriendapi.h"
-
-#include "gc/Marking.h"
-#include "vm/Shape.h"
-
-#include "jsgcinlines.h"
-
-using namespace js;
-using namespace js::gc;
-
-inline HashNumber
-WatchKeyHasher::hash(const Lookup& key)
-{
- return MovableCellHasher<PreBarrieredObject>::hash(key.object) ^ HashId(key.id);
-}
-
-namespace {
-
-class AutoEntryHolder {
- typedef WatchpointMap::Map Map;
- Generation gen;
- Map& map;
- Map::Ptr p;
- RootedObject obj;
- RootedId id;
-
- public:
- AutoEntryHolder(JSContext* cx, Map& map, Map::Ptr p)
- : gen(map.generation()), map(map), p(p), obj(cx, p->key().object), id(cx, p->key().id)
- {
- MOZ_ASSERT(!p->value().held);
- p->value().held = true;
- }
-
- ~AutoEntryHolder() {
- if (gen != map.generation())
- p = map.lookup(WatchKey(obj, id));
- if (p)
- p->value().held = false;
- }
-};
-
-} /* anonymous namespace */
-
-bool
-WatchpointMap::init()
-{
- return map.init();
-}
-
-bool
-WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id,
- JSWatchPointHandler handler, HandleObject closure)
-{
- MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id));
-
- if (!JSObject::setWatched(cx, obj))
- return false;
-
- Watchpoint w(handler, closure, false);
- if (!map.put(WatchKey(obj, id), w)) {
- ReportOutOfMemory(cx);
- return false;
- }
- /*
- * For generational GC, we don't need to post-barrier writes to the
- * hashtable here because we mark all watchpoints as part of root marking in
- * markAll().
- */
- return true;
-}
-
-void
-WatchpointMap::unwatch(JSObject* obj, jsid id,
- JSWatchPointHandler* handlerp, JSObject** closurep)
-{
- if (Map::Ptr p = map.lookup(WatchKey(obj, id))) {
- if (handlerp)
- *handlerp = p->value().handler;
- if (closurep) {
- // Read barrier to prevent an incorrectly gray closure from escaping the
- // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp
- JS::ExposeObjectToActiveJS(p->value().closure);
- *closurep = p->value().closure;
- }
- map.remove(p);
- }
-}
-
-void
-WatchpointMap::unwatchObject(JSObject* obj)
-{
- for (Map::Enum e(map); !e.empty(); e.popFront()) {
- Map::Entry& entry = e.front();
- if (entry.key().object == obj)
- e.removeFront();
- }
-}
-
-void
-WatchpointMap::clear()
-{
- map.clear();
-}
-
-bool
-WatchpointMap::triggerWatchpoint(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
-{
- Map::Ptr p = map.lookup(WatchKey(obj, id));
- if (!p || p->value().held)
- return true;
-
- AutoEntryHolder holder(cx, map, p);
-
- /* Copy the entry, since GC would invalidate p. */
- JSWatchPointHandler handler = p->value().handler;
- RootedObject closure(cx, p->value().closure);
-
- /* Determine the property's old value. */
- Value old;
- old.setUndefined();
- if (obj->isNative()) {
- NativeObject* nobj = &obj->as<NativeObject>();
- if (Shape* shape = nobj->lookup(cx, id)) {
- if (shape->hasSlot())
- old = nobj->getSlot(shape->slot());
- }
- }
-
- // Read barrier to prevent an incorrectly gray closure from escaping the
- // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp
- JS::ExposeObjectToActiveJS(closure);
-
- /* Call the handler. */
- return handler(cx, obj, id, old, vp.address(), closure);
-}
-
-bool
-WatchpointMap::markIteratively(JSTracer* trc)
-{
- bool marked = false;
- for (Map::Enum e(map); !e.empty(); e.popFront()) {
- Map::Entry& entry = e.front();
- JSObject* priorKeyObj = entry.key().object;
- jsid priorKeyId(entry.key().id.get());
- bool objectIsLive =
- IsMarked(trc->runtime(), const_cast<PreBarrieredObject*>(&entry.key().object));
- if (objectIsLive || entry.value().held) {
- if (!objectIsLive) {
- TraceEdge(trc, const_cast<PreBarrieredObject*>(&entry.key().object),
- "held Watchpoint object");
- marked = true;
- }
-
- MOZ_ASSERT(JSID_IS_STRING(priorKeyId) ||
- JSID_IS_INT(priorKeyId) ||
- JSID_IS_SYMBOL(priorKeyId));
- TraceEdge(trc, const_cast<PreBarrieredId*>(&entry.key().id), "WatchKey::id");
-
- if (entry.value().closure && !IsMarked(trc->runtime(), &entry.value().closure)) {
- TraceEdge(trc, &entry.value().closure, "Watchpoint::closure");
- marked = true;
- }
-
- /* We will sweep this entry in sweepAll if !objectIsLive. */
- if (priorKeyObj != entry.key().object || priorKeyId != entry.key().id)
- e.rekeyFront(WatchKey(entry.key().object, entry.key().id));
- }
- }
- return marked;
-}
-
-void
-WatchpointMap::markAll(JSTracer* trc)
-{
- for (Map::Enum e(map); !e.empty(); e.popFront()) {
- Map::Entry& entry = e.front();
- JSObject* object = entry.key().object;
- jsid id = entry.key().id;
- JSObject* priorObject = object;
- jsid priorId = id;
- MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId));
-
- TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object");
- TraceManuallyBarrieredEdge(trc, &id, "WatchKey::id");
- TraceEdge(trc, &entry.value().closure, "Watchpoint::closure");
-
- if (priorObject != object || priorId != id)
- e.rekeyFront(WatchKey(object, id));
- }
-}
-
-void
-WatchpointMap::sweepAll(JSRuntime* rt)
-{
- for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
- if (WatchpointMap* wpmap = c->watchpointMap)
- wpmap->sweep();
- }
-}
-
-void
-WatchpointMap::sweep()
-{
- for (Map::Enum e(map); !e.empty(); e.popFront()) {
- Map::Entry& entry = e.front();
- JSObject* obj(entry.key().object);
- if (IsAboutToBeFinalizedUnbarriered(&obj)) {
- MOZ_ASSERT(!entry.value().held);
- e.removeFront();
- } else if (obj != entry.key().object) {
- e.rekeyFront(WatchKey(obj, entry.key().id));
- }
- }
-}
-
-void
-WatchpointMap::traceAll(WeakMapTracer* trc)
-{
- JSRuntime* rt = trc->context;
- for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
- if (WatchpointMap* wpmap = comp->watchpointMap)
- wpmap->trace(trc);
- }
-}
-
-void
-WatchpointMap::trace(WeakMapTracer* trc)
-{
- for (Map::Range r = map.all(); !r.empty(); r.popFront()) {
- Map::Entry& entry = r.front();
- trc->trace(nullptr,
- JS::GCCellPtr(entry.key().object.get()),
- JS::GCCellPtr(entry.value().closure.get()));
- }
-}
diff --git a/js/src/jswatchpoint.h b/js/src/jswatchpoint.h
deleted file mode 100644
index bba6c38ce..000000000
--- a/js/src/jswatchpoint.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*- 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 jswatchpoint_h
-#define jswatchpoint_h
-
-#include "jsalloc.h"
-
-#include "gc/Barrier.h"
-#include "js/HashTable.h"
-
-namespace js {
-
-struct WeakMapTracer;
-
-struct WatchKey {
- WatchKey() {}
- WatchKey(JSObject* obj, jsid id) : object(obj), id(id) {}
- WatchKey(const WatchKey& key) : object(key.object.get()), id(key.id.get()) {}
-
- // These are traced unconditionally during minor GC, so do not require
- // post-barriers.
- PreBarrieredObject object;
- PreBarrieredId id;
-
- bool operator!=(const WatchKey& other) const {
- return object != other.object || id != other.id;
- }
-};
-
-typedef bool
-(* JSWatchPointHandler)(JSContext* cx, JSObject* obj, jsid id, const JS::Value& old,
- JS::Value* newp, void* closure);
-
-struct Watchpoint {
- JSWatchPointHandler handler;
- PreBarrieredObject closure; /* This is always marked in minor GCs and so doesn't require a postbarrier. */
- bool held; /* true if currently running handler */
- Watchpoint(JSWatchPointHandler handler, JSObject* closure, bool held)
- : handler(handler), closure(closure), held(held) {}
-};
-
-struct WatchKeyHasher
-{
- typedef WatchKey Lookup;
- static inline js::HashNumber hash(const Lookup& key);
-
- static bool match(const WatchKey& k, const Lookup& l) {
- return MovableCellHasher<PreBarrieredObject>::match(k.object, l.object) &&
- DefaultHasher<PreBarrieredId>::match(k.id, l.id);
- }
-
- static void rekey(WatchKey& k, const WatchKey& newKey) {
- k.object.unsafeSet(newKey.object);
- k.id.unsafeSet(newKey.id);
- }
-};
-
-class WatchpointMap {
- public:
- typedef HashMap<WatchKey, Watchpoint, WatchKeyHasher, SystemAllocPolicy> Map;
-
- bool init();
- bool watch(JSContext* cx, HandleObject obj, HandleId id,
- JSWatchPointHandler handler, HandleObject closure);
- void unwatch(JSObject* obj, jsid id,
- JSWatchPointHandler* handlerp, JSObject** closurep);
- void unwatchObject(JSObject* obj);
- void clear();
-
- bool triggerWatchpoint(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp);
-
- bool markIteratively(JSTracer* trc);
- void markAll(JSTracer* trc);
- static void sweepAll(JSRuntime* rt);
- void sweep();
-
- static void traceAll(WeakMapTracer* trc);
- void trace(WeakMapTracer* trc);
-
- private:
- Map map;
-};
-
-} // namespace js
-
-#endif /* jswatchpoint_h */
diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h
index 5f3704e32..32336c68b 100644
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -315,13 +315,6 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
- // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
- // against.
-
- virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
- JS::HandleObject callable) const override;
- virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override;
-
/*
* Allow our subclasses to select the superclass behavior they want without
* needing to specify an exact superclass.
diff --git a/js/src/moz.build b/js/src/moz.build
index a0f074d1c..5287aef00 100644
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -291,7 +291,6 @@ UNIFIED_SOURCES += [
'jspropertytree.cpp',
'jsscript.cpp',
'jsstr.cpp',
- 'jswatchpoint.cpp',
'jsweakmap.cpp',
'perf/jsperf.cpp',
'proxy/BaseProxyHandler.cpp',
@@ -306,6 +305,7 @@ UNIFIED_SOURCES += [
'vm/ArgumentsObject.cpp',
'vm/ArrayBufferObject.cpp',
'vm/AsyncFunction.cpp',
+ 'vm/AsyncIteration.cpp',
'vm/Caches.cpp',
'vm/CallNonGenericMethod.cpp',
'vm/CharacterEncoding.cpp',
@@ -721,6 +721,14 @@ if CONFIG['OS_ARCH'] == 'Linux':
'dl',
]
+if CONFIG['OS_ARCH'] == 'SunOS':
+ OS_LIBS += [
+ 'posix4',
+ 'dl',
+ 'nsl',
+ 'socket',
+ ]
+
OS_LIBS += CONFIG['REALTIME_LIBS']
CFLAGS += CONFIG['MOZ_ICU_CFLAGS']
@@ -740,6 +748,7 @@ selfhosted.inputs = [
'builtin/SelfHostingDefines.h',
'builtin/Utilities.js',
'builtin/Array.js',
+ 'builtin/AsyncIteration.js',
'builtin/Classes.js',
'builtin/Date.js',
'builtin/Error.js',
@@ -752,6 +761,7 @@ selfhosted.inputs = [
'builtin/Module.js',
'builtin/Number.js',
'builtin/Object.js',
+ 'builtin/Promise.js',
'builtin/Reflect.js',
'builtin/RegExp.js',
'builtin/RegExpGlobalReplaceOpt.h.js',
@@ -765,9 +775,6 @@ selfhosted.inputs = [
'builtin/WeakSet.js'
]
-if CONFIG['SPIDERMONKEY_PROMISE']:
- selfhosted.inputs += ['builtin/Promise.js']
-
if CONFIG['JS_HAS_CTYPES']:
if CONFIG['MOZ_SYSTEM_FFI']:
CXXFLAGS += CONFIG['MOZ_FFI_CFLAGS']
@@ -783,3 +790,6 @@ if CONFIG['GNU_CXX']:
# Suppress warnings in third-party code.
if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
SOURCES['jsdtoa.cpp'].flags += ['-Wno-implicit-fallthrough']
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+ DEFINES['NOMINMAX'] = True
diff --git a/js/src/old-configure.in b/js/src/old-configure.in
index 45108ee59..6566ce05e 100644
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -923,6 +923,14 @@ case "$target" in
fi
;;
+i*86-*-solaris*)
+ MOZ_FIX_LINK_PATHS="-L${DIST}/bin -R'\$\$ORIGIN':/usr/gcc/7/lib"
+ ;;
+
+x86_64-*-solaris*)
+ MOZ_FIX_LINK_PATHS="-L${DIST}/bin -R'\$\$ORIGIN':/usr/gcc/7/lib/amd64"
+ ;;
+
esac
dnl Only one oddball right now (QNX), but this gives us flexibility
diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp
index 8d5f30a19..423aa8671 100644
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -419,20 +419,6 @@ BaseProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool*
}
bool
-BaseProxyHandler::watch(JSContext* cx, HandleObject proxy, HandleId id, HandleObject callable) const
-{
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH,
- proxy->getClass()->name);
- return false;
-}
-
-bool
-BaseProxyHandler::unwatch(JSContext* cx, HandleObject proxy, HandleId id) const
-{
- return true;
-}
-
-bool
BaseProxyHandler::getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder* adder) const
{
diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp
index 2c1cffb77..6b3a3d1e9 100644
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -505,20 +505,6 @@ Proxy::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp
JSObject * const TaggedProto::LazyProto = reinterpret_cast<JSObject*>(0x1);
/* static */ bool
-Proxy::watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleObject callable)
-{
- JS_CHECK_RECURSION(cx, return false);
- return proxy->as<ProxyObject>().handler()->watch(cx, proxy, id, callable);
-}
-
-/* static */ bool
-Proxy::unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id)
-{
- JS_CHECK_RECURSION(cx, return false);
- return proxy->as<ProxyObject>().handler()->unwatch(cx, proxy, id);
-}
-
-/* static */ bool
Proxy::getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder* adder)
{
@@ -699,18 +685,6 @@ js::proxy_Construct(JSContext* cx, unsigned argc, Value* vp)
}
bool
-js::proxy_Watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
-{
- return Proxy::watch(cx, obj, id, callable);
-}
-
-bool
-js::proxy_Unwatch(JSContext* cx, HandleObject obj, HandleId id)
-{
- return Proxy::unwatch(cx, obj, id);
-}
-
-bool
js::proxy_GetElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder* adder)
{
@@ -750,7 +724,6 @@ const ObjectOps js::ProxyObjectOps = {
js::proxy_SetProperty,
js::proxy_GetOwnPropertyDescriptor,
js::proxy_DeleteProperty,
- js::proxy_Watch, js::proxy_Unwatch,
js::proxy_GetElements,
nullptr, /* enumerate */
js::proxy_FunToString
diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h
index 89909a085..4a8ecf8ab 100644
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -65,9 +65,6 @@ class Proxy
static bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g);
static bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp);
- static bool watch(JSContext* cx, HandleObject proxy, HandleId id, HandleObject callable);
- static bool unwatch(JSContext* cx, HandleObject proxy, HandleId id);
-
static bool getElements(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end,
ElementAdder* adder);
diff --git a/js/src/proxy/SecurityWrapper.cpp b/js/src/proxy/SecurityWrapper.cpp
index 710faf9b0..71d22fca6 100644
--- a/js/src/proxy/SecurityWrapper.cpp
+++ b/js/src/proxy/SecurityWrapper.cpp
@@ -130,24 +130,5 @@ SecurityWrapper<Base>::defineProperty(JSContext* cx, HandleObject wrapper, Handl
return Base::defineProperty(cx, wrapper, id, desc, result);
}
-template <class Base>
-bool
-SecurityWrapper<Base>::watch(JSContext* cx, HandleObject proxy,
- HandleId id, HandleObject callable) const
-{
- ReportUnwrapDenied(cx);
- return false;
-}
-
-template <class Base>
-bool
-SecurityWrapper<Base>::unwatch(JSContext* cx, HandleObject proxy,
- HandleId id) const
-{
- ReportUnwrapDenied(cx);
- return false;
-}
-
-
template class js::SecurityWrapper<Wrapper>;
template class js::SecurityWrapper<CrossCompartmentWrapper>;
diff --git a/js/src/shell/OSObject.cpp b/js/src/shell/OSObject.cpp
index 846ec7b15..4fb3d4e77 100644
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -184,6 +184,11 @@ FileAsTypedArray(JSContext* cx, JS::HandleString pathnameStr)
return nullptr;
JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.ptr());
} else {
+ if (len > INT32_MAX) {
+ JS_ReportErrorUTF8(cx, "file %s is too large for a Uint8Array",
+ pathname.ptr());
+ return nullptr;
+ }
obj = JS_NewUint8Array(cx, len);
if (!obj)
return nullptr;
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 51cd11fe8..36558a694 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -85,6 +85,7 @@
#include "threading/Thread.h"
#include "vm/ArgumentsObject.h"
#include "vm/AsyncFunction.h"
+#include "vm/AsyncIteration.h"
#include "vm/Compression.h"
#include "vm/Debugger.h"
#include "vm/HelperThreads.h"
@@ -153,7 +154,6 @@ static const double MAX_TIMEOUT_SECONDS = 1800.0;
# define SHARED_MEMORY_DEFAULT 0
#endif
-#ifdef SPIDERMONKEY_PROMISE
using JobQueue = GCVector<JSObject*, 0, SystemAllocPolicy>;
struct ShellAsyncTasks
@@ -166,7 +166,6 @@ struct ShellAsyncTasks
size_t outstanding;
Vector<JS::AsyncTask*> finished;
};
-#endif // SPIDERMONKEY_PROMISE
enum class ScriptKind
{
@@ -271,12 +270,10 @@ struct ShellContext
JS::PersistentRootedValue interruptFunc;
bool lastWarningEnabled;
JS::PersistentRootedValue lastWarning;
-#ifdef SPIDERMONKEY_PROMISE
JS::PersistentRootedValue promiseRejectionTrackerCallback;
JS::PersistentRooted<JobQueue> jobQueue;
ExclusiveData<ShellAsyncTasks> asyncTasks;
bool drainingJobQueue;
-#endif // SPIDERMONKEY_PROMISE
/*
* Watchdog thread state.
@@ -434,11 +431,9 @@ ShellContext::ShellContext(JSContext* cx)
interruptFunc(cx, NullValue()),
lastWarningEnabled(false),
lastWarning(cx, NullValue()),
-#ifdef SPIDERMONKEY_PROMISE
promiseRejectionTrackerCallback(cx, NullValue()),
asyncTasks(mutexid::ShellAsyncTasks, cx),
drainingJobQueue(false),
-#endif // SPIDERMONKEY_PROMISE
watchdogLock(mutexid::ShellContextWatchdog),
exitCode(0),
quitting(false),
@@ -738,7 +733,6 @@ RunModule(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
return JS_CallFunction(cx, loaderObj, importFun, args, &value);
}
-#ifdef SPIDERMONKEY_PROMISE
static JSObject*
ShellGetIncumbentGlobalCallback(JSContext* cx)
{
@@ -775,12 +769,10 @@ ShellFinishAsyncTaskCallback(JS::AsyncTask* task)
asyncTasks->outstanding--;
return asyncTasks->finished.append(task);
}
-#endif // SPIDERMONKEY_PROMISE
static bool
DrainJobQueue(JSContext* cx)
{
-#ifdef SPIDERMONKEY_PROMISE
ShellContext* sc = GetShellContext(cx);
if (sc->quitting || sc->drainingJobQueue)
return true;
@@ -831,7 +823,6 @@ DrainJobQueue(JSContext* cx)
}
sc->jobQueue.clear();
sc->drainingJobQueue = false;
-#endif // SPIDERMONKEY_PROMISE
return true;
}
@@ -846,7 +837,6 @@ DrainJobQueue(JSContext* cx, unsigned argc, Value* vp)
return true;
}
-#ifdef SPIDERMONKEY_PROMISE
static void
ForwardingPromiseRejectionTrackerCallback(JSContext* cx, JS::HandleObject promise,
PromiseRejectionHandlingState state, void* data)
@@ -869,14 +859,12 @@ ForwardingPromiseRejectionTrackerCallback(JSContext* cx, JS::HandleObject promis
if (!Call(cx, callback, UndefinedHandleValue, args, &rval))
JS_ClearPendingException(cx);
}
-#endif // SPIDERMONKEY_PROMISE
static bool
SetPromiseRejectionTrackerCallback(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
-#ifdef SPIDERMONKEY_PROMISE
if (!IsCallable(args.get(0))) {
JS_ReportErrorASCII(cx,
"setPromiseRejectionTrackerCallback expects a function as its sole "
@@ -887,7 +875,6 @@ SetPromiseRejectionTrackerCallback(JSContext* cx, unsigned argc, Value* vp)
GetShellContext(cx)->promiseRejectionTrackerCallback = args[0];
JS::SetPromiseRejectionTrackerCallback(cx, ForwardingPromiseRejectionTrackerCallback);
-#endif // SPIDERMONKEY_PROMISE
args.rval().setUndefined();
return true;
}
@@ -2304,6 +2291,8 @@ ValueToScript(JSContext* cx, HandleValue v, JSFunction** funp = nullptr)
// Get unwrapped async function.
if (IsWrappedAsyncFunction(fun))
fun = GetUnwrappedAsyncFunction(fun);
+ if (IsWrappedAsyncGenerator(fun))
+ fun = GetUnwrappedAsyncGenerator(fun);
if (!fun->isInterpreted()) {
JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_SCRIPTS_ONLY);
@@ -3346,12 +3335,10 @@ WorkerMain(void* arg)
return;
}
-#ifdef SPIDERMONKEY_PROMISE
sc->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
JS::SetEnqueuePromiseJobCallback(cx, ShellEnqueuePromiseJobCallback);
JS::SetGetIncumbentGlobalCallback(cx, ShellGetIncumbentGlobalCallback);
JS::SetAsyncTaskCallbacks(cx, ShellStartAsyncTaskCallback, ShellFinishAsyncTaskCallback);
-#endif // SPIDERMONKEY_PROMISE
EnvironmentPreparer environmentPreparer(cx);
@@ -3382,11 +3369,9 @@ WorkerMain(void* arg)
JS::SetLargeAllocationFailureCallback(cx, nullptr, nullptr);
-#ifdef SPIDERMONKEY_PROMISE
JS::SetGetIncumbentGlobalCallback(cx, nullptr);
JS::SetEnqueuePromiseJobCallback(cx, nullptr);
sc->jobQueue.reset();
-#endif // SPIDERMONKEY_PROMISE
KillWatchdog(cx);
@@ -7942,12 +7927,10 @@ main(int argc, char** argv, char** envp)
if (!JS::InitSelfHostedCode(cx))
return 1;
-#ifdef SPIDERMONKEY_PROMISE
sc->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
JS::SetEnqueuePromiseJobCallback(cx, ShellEnqueuePromiseJobCallback);
JS::SetGetIncumbentGlobalCallback(cx, ShellGetIncumbentGlobalCallback);
JS::SetAsyncTaskCallbacks(cx, ShellStartAsyncTaskCallback, ShellFinishAsyncTaskCallback);
-#endif // SPIDERMONKEY_PROMISE
EnvironmentPreparer environmentPreparer(cx);
@@ -7977,11 +7960,9 @@ main(int argc, char** argv, char** envp)
JS::SetLargeAllocationFailureCallback(cx, nullptr, nullptr);
-#ifdef SPIDERMONKEY_PROMISE
JS::SetGetIncumbentGlobalCallback(cx, nullptr);
JS::SetEnqueuePromiseJobCallback(cx, nullptr);
sc->jobQueue.reset();
-#endif // SPIDERMONKEY_PROMISE
KillWatchdog(cx);
diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js
index 8cda44d87..8bd0512c5 100644
--- a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js
+++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js
@@ -1,7 +1,7 @@
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
// Generated by make_intl_data.py. DO NOT EDIT.
-// tzdata version = 2019a
+// tzdata version = 2019c
const tzMapper = [
x => x,
diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js
index a3efe0310..c760fd85e 100644
--- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js
+++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js
@@ -1,7 +1,7 @@
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
// Generated by make_intl_data.py. DO NOT EDIT.
-// tzdata version = 2019a
+// tzdata version = 2019c
const tzMapper = [
x => x,
diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js
index b61593f78..38db5e77d 100644
--- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js
+++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js
@@ -1,7 +1,7 @@
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
// Generated by make_intl_data.py. DO NOT EDIT.
-// tzdata version = 2019a
+// tzdata version = 2019c
const tzMapper = [
x => x,
diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js
index 12b55c214..64a25c241 100644
--- a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js
+++ b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js
@@ -1,7 +1,7 @@
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
// Generated by make_intl_data.py. DO NOT EDIT.
-// tzdata version = 2019a
+// tzdata version = 2019c
const tzMapper = [
x => x,
diff --git a/js/src/tests/ecma_2017/AsyncFunctions/properties.js b/js/src/tests/ecma_2017/AsyncFunctions/properties.js
new file mode 100644
index 000000000..ca383901b
--- /dev/null
+++ b/js/src/tests/ecma_2017/AsyncFunctions/properties.js
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function assertOwnDescriptor(object, propertyKey, expected) {
+ var desc = Object.getOwnPropertyDescriptor(object, propertyKey);
+ if (desc === undefined) {
+ assertEq(expected, undefined, "Property shouldn't be present");
+ return;
+ }
+
+ assertEq(desc.enumerable, expected.enumerable, `${String(propertyKey)}.[[Enumerable]]`);
+ assertEq(desc.configurable, expected.configurable, `${String(propertyKey)}.[[Configurable]]`);
+
+ if (Object.prototype.hasOwnProperty.call(desc, "value")) {
+ assertEq(desc.value, expected.value, `${String(propertyKey)}.[[Value]]`);
+ assertEq(desc.writable, expected.writable, `${String(propertyKey)}.[[Writable]]`);
+ } else {
+ assertEq(desc.get, expected.get, `${String(propertyKey)}.[[Get]]`);
+ assertEq(desc.set, expected.set, `${String(propertyKey)}.[[Set]]`);
+ }
+}
+
+async function asyncFunc(){}
+var AsyncFunctionPrototype = Object.getPrototypeOf(asyncFunc);
+var AsyncFunction = AsyncFunctionPrototype.constructor;
+
+
+// ES2017, 25.5.2 Properties of the AsyncFunction Constructor
+
+assertEqArray(Object.getOwnPropertyNames(AsyncFunction).sort(), ["length", "name", "prototype"]);
+assertEqArray(Object.getOwnPropertySymbols(AsyncFunction), []);
+
+assertOwnDescriptor(AsyncFunction, "length", {
+ value: 1, writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(AsyncFunction, "name", {
+ value: "AsyncFunction", writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(AsyncFunction, "prototype", {
+ value: AsyncFunctionPrototype, writable: false, enumerable: false, configurable: false
+});
+
+
+// ES2017, 25.5.3 Properties of the AsyncFunction Prototype Object
+
+assertEqArray(Object.getOwnPropertyNames(AsyncFunctionPrototype).sort(), ["constructor"]);
+assertEqArray(Object.getOwnPropertySymbols(AsyncFunctionPrototype), [Symbol.toStringTag]);
+
+assertOwnDescriptor(AsyncFunctionPrototype, "constructor", {
+ value: AsyncFunction, writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(AsyncFunctionPrototype, Symbol.toStringTag, {
+ value: "AsyncFunction", writable: false, enumerable: false, configurable: true
+});
+
+
+// ES2017, 25.5.4 AsyncFunction Instances
+
+assertEqArray(Object.getOwnPropertyNames(asyncFunc).sort(), ["length", "name"]);
+assertEqArray(Object.getOwnPropertySymbols(asyncFunc), []);
+
+assertOwnDescriptor(asyncFunc, "length", {
+ value: 0, writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(asyncFunc, "name", {
+ value: "asyncFunc", writable: false, enumerable: false, configurable: true
+});
+
+
+if (typeof reportCompare == "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_5/Array/frozen-dense-array.js b/js/src/tests/ecma_5/Array/frozen-dense-array.js
index 9db63036f..cdb86daa3 100644
--- a/js/src/tests/ecma_5/Array/frozen-dense-array.js
+++ b/js/src/tests/ecma_5/Array/frozen-dense-array.js
@@ -38,24 +38,5 @@ assertEq(delete a[0], false);
assertArrayIsExpected();
-var watchpointCalled = false;
-// NOTE: Be careful with the position of this test, since this sparsifies the
-// elements and you might not test what you think you're testing otherwise.
-a.watch(2, function(prop, oldValue, newValue) {
- watchpointCalled = true;
- assertEq(prop, 2);
- assertEq(oldValue, 1);
- assertEq(newValue, "foo");
-});
-
-assertArrayIsExpected();
-
-a.length = 5;
-a[2] = "foo";
-assertEq(watchpointCalled, true);
-assertEq(delete a[0], false);
-
-assertArrayIsExpected();
-
if (typeof reportCompare === "function")
reportCompare(true, true);
diff --git a/js/src/tests/ecma_5/extensions/watch-array-length.js b/js/src/tests/ecma_5/extensions/watch-array-length.js
deleted file mode 100644
index e9b356efa..000000000
--- a/js/src/tests/ecma_5/extensions/watch-array-length.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-var hitCount;
-function watcher(p,o,n) { hitCount++; return n; }
-
-var a = [1];
-a.watch('length', watcher);
-hitCount = 0;
-a.length = 0;
-reportCompare(1, hitCount, "lenient; configurable: watchpoint hit");
-
-var b = Object.defineProperty([1],'0',{configurable:false});
-b.watch('length', watcher);
-hitCount = 0;
-var result;
-try {
- b.length = 0;
- result = "no error";
-} catch (x) {
- result = x.toString();
-}
-reportCompare(1, hitCount, "lenient; non-configurable: watchpoint hit");
-reportCompare(1, b.length, "lenient; non-configurable: length unchanged");
-reportCompare("no error", result, "lenient; non-configurable: no error thrown");
-
-var c = Object.defineProperty([1],'0',{configurable:false});
-c.watch('length', watcher);
-hitCount = 0;
-var threwTypeError;
-try {
- (function(){'use strict'; c.length = 0;})();
- threwTypeError = false;
-} catch (x) {
- threwTypeError = x instanceof TypeError;
-}
-reportCompare(1, hitCount, "strict; non-configurable: watchpoint hit");
-reportCompare(1, c.length, "strict; non-configurable: length unchanged");
-reportCompare(true, threwTypeError, "strict; non-configurable: TypeError thrown");
diff --git a/js/src/tests/ecma_5/extensions/watch-inherited-property.js b/js/src/tests/ecma_5/extensions/watch-inherited-property.js
deleted file mode 100644
index 1a0ad566b..000000000
--- a/js/src/tests/ecma_5/extensions/watch-inherited-property.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-/* Create a prototype object with a setter property. */
-var protoSetterCount;
-var proto = ({ set x(v) { protoSetterCount++; } });
-
-/* Put a watchpoint on that setter. */
-var protoWatchCount;
-proto.watch('x', function() { protoWatchCount++; });
-
-/* Make an object with the above as its prototype. */
-function C() { }
-C.prototype = proto;
-var o = new C();
-
-/*
- * Set a watchpoint on the property in the inheriting object. We have
- * defined this to mean "duplicate the property, setter and all, in the
- * inheriting object." I don't think debugging observation mechanisms
- * should mutate the program being run, but that's what we've got.
- */
-var oWatchCount;
-o.watch('x', function() { oWatchCount++; });
-
-/*
- * Assign to the property. This should trip the watchpoint on the inheriting object and
- * the setter.
- */
-protoSetterCount = protoWatchCount = oWatchCount = 0;
-o.x = 1;
-assertEq(protoWatchCount, 0);
-assertEq(oWatchCount, 1);
-assertEq(protoSetterCount, 1);
-
-reportCompare(true, true);
diff --git a/js/src/tests/ecma_5/extensions/watch-replaced-setter.js b/js/src/tests/ecma_5/extensions/watch-replaced-setter.js
deleted file mode 100644
index 05cf60aff..000000000
--- a/js/src/tests/ecma_5/extensions/watch-replaced-setter.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-/* A stock watcher function. */
-var watcherCount;
-function watcher(id, oldval, newval) { watcherCount++; return newval; }
-
-/* Create an object with a JavaScript setter. */
-var setterCount;
-var o = { w:2, set x(v) { setterCount++; } };
-
-/*
- * Put the object in dictionary mode, so that JSObject::putProperty will
- * mutate its shapes instead of creating new ones.
- */
-delete o.w;
-
-/*
- * Place a watchpoint on the property. The watchpoint structure holds the
- * original JavaScript setter, and a pointer to the shape.
- */
-o.watch('x', watcher);
-
-/*
- * Replace the accessor property with a value property. The shape's setter
- * should become a non-JS setter, js_watch_set, and the watchpoint
- * structure's saved setter should be updated (in this case, cleared).
- */
-Object.defineProperty(o, 'x', { value:3,
- writable:true,
- enumerable:true,
- configurable:true });
-
-/*
- * Assign to the property. This should trigger js_watch_set, which should
- * call the handler, and then see that there is no JS-level setter to pass
- * control on to, and return.
- */
-watcherCount = setterCount = 0;
-o.x = 3;
-assertEq(watcherCount, 1);
-assertEq(setterCount, 0);
-
-reportCompare(true, true);
diff --git a/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js b/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js
deleted file mode 100644
index f5eff98b8..000000000
--- a/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-/* Create an object with a JavaScript setter. */
-var firstSetterCount;
-var o = { w:2, set x(v) { firstSetterCount++; } };
-
-/*
- * Put the object in dictionary mode, so that JSObject::putProperty will
- * mutate its shapes instead of creating new ones.
- */
-delete o.w;
-
-/* A stock watcher function. */
-var watcherCount;
-function watcher(id, oldval, newval) { watcherCount++; return newval; }
-
-/*
- * Place a watchpoint on the property. The property's shape now has the
- * watchpoint setter, with the original setter saved in the watchpoint
- * structure.
- */
-o.watch('x', watcher);
-
-/*
- * Replace the setter with a new setter. The shape should get updated to
- * refer to the new setter, and then the watchpoint setter should be
- * re-established.
- */
-var secondSetterCount;
-Object.defineProperty(o, 'x', { set: function () { secondSetterCount++ } });
-
-/*
- * Assign to the property. This should trigger the watchpoint and the new setter.
- */
-watcherCount = firstSetterCount = secondSetterCount = 0;
-o.x = 3;
-assertEq(watcherCount, 1);
-assertEq(firstSetterCount, 0);
-assertEq(secondSetterCount, 1);
-
-reportCompare(true, true);
diff --git a/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js b/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js
deleted file mode 100644
index 03cdd788e..000000000
--- a/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-/* A stock watcher function. */
-var watcherCount;
-function watcher(id, old, newval) {
- watcherCount++;
- return newval;
-}
-
-/* Create an object with a value property. */
-var o = { w:2, x:3 };
-
-/*
- * Place a watchpoint on the value property. The watchpoint structure holds
- * the original JavaScript setter, and a pointer to the shape.
- */
-o.watch('x', watcher);
-
-/*
- * Put the object in dictionary mode, so that JSObject::putProperty will
- * mutate its shapes instead of creating new ones.
- */
-delete o.w;
-
-/*
- * Replace the value property with a setter.
- */
-var setterCount;
-o.__defineSetter__('x', function() { setterCount++; });
-
-/*
- * Trigger the watchpoint. The watchpoint handler should run, and then the
- * setter should run.
- */
-watcherCount = setterCount = 0;
-o.x = 4;
-assertEq(watcherCount, 1);
-assertEq(setterCount, 1);
-
-reportCompare(true, true);
diff --git a/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js b/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js
deleted file mode 100644
index 85410bbd4..000000000
--- a/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-function make_watcher(name) {
- return function (id, oldv, newv) {
- print("watched " + name + "[0]");
- };
-}
-
-var o, p;
-function f(flag) {
- if (flag) {
- o = arguments;
- } else {
- p = arguments;
- o.watch(0, make_watcher('o'));
- p.watch(0, make_watcher('p'));
-
- /*
- * Previously, the watchpoint implementation actually substituted its magic setter
- * functions for the setters of shared shapes, and then 1) carefully ignored calls
- * to its magic setter from unrelated objects, and 2) avoided restoring the
- * original setter until all watchpoints on that shape had been removed.
- *
- * However, when the watchpoint code began using JSObject::changeProperty and
- * js_ChangeNativePropertyAttrs to change shapes' setters, the shape tree code
- * became conscious of the presence of watchpoints, and shared shapes between
- * objects only when their watchpoint nature coincided. Clearing the magic setter
- * from one object's shape would not affect other objects, because the
- * watchpointed and non-watchpointed shapes were distinct if they were shared.
- *
- * Thus, the first unwatch call must go ahead and fix p's shape, even though a
- * watchpoint exists on the same shape in o. o's watchpoint's presence shouldn't
- * cause 'unwatch' to leave p's magic setter in place.
- */
-
- /* DropWatchPointAndUnlock would see o's watchpoint, and not change p's property. */
- p.unwatch(0);
-
- /* DropWatchPointAndUnlock would fix o's property, but not p's; p's setter would be gone. */
- o.unwatch(0);
-
- /* This would fail to invoke the arguments object's setter. */
- p[0] = 4;
-
- /* And the formal parameter would not get updated. */
- assertEq(flag, 4);
- }
-}
-
-f(true);
-f(false);
-
-reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/Generators/properties.js b/js/src/tests/ecma_6/Generators/properties.js
new file mode 100644
index 000000000..7782e64c0
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/properties.js
@@ -0,0 +1,111 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function assertOwnDescriptor(object, propertyKey, expected) {
+ var desc = Object.getOwnPropertyDescriptor(object, propertyKey);
+ if (desc === undefined) {
+ assertEq(expected, undefined, "Property shouldn't be present");
+ return;
+ }
+
+ assertEq(desc.enumerable, expected.enumerable, `${String(propertyKey)}.[[Enumerable]]`);
+ assertEq(desc.configurable, expected.configurable, `${String(propertyKey)}.[[Configurable]]`);
+
+ if (Object.prototype.hasOwnProperty.call(desc, "value")) {
+ assertEq(desc.value, expected.value, `${String(propertyKey)}.[[Value]]`);
+ assertEq(desc.writable, expected.writable, `${String(propertyKey)}.[[Writable]]`);
+ } else {
+ assertEq(desc.get, expected.get, `${String(propertyKey)}.[[Get]]`);
+ assertEq(desc.set, expected.set, `${String(propertyKey)}.[[Set]]`);
+ }
+}
+
+function* generator(){}
+var GeneratorFunctionPrototype = Object.getPrototypeOf(generator);
+var GeneratorFunction = GeneratorFunctionPrototype.constructor;
+var GeneratorPrototype = GeneratorFunctionPrototype.prototype;
+
+
+// ES2017, 25.2.2 Properties of the GeneratorFunction Constructor
+
+assertEqArray(Object.getOwnPropertyNames(GeneratorFunction).sort(), ["length", "name", "prototype"]);
+assertEqArray(Object.getOwnPropertySymbols(GeneratorFunction), []);
+
+assertOwnDescriptor(GeneratorFunction, "length", {
+ value: 1, writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(GeneratorFunction, "name", {
+ value: "GeneratorFunction", writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(GeneratorFunction, "prototype", {
+ value: GeneratorFunctionPrototype, writable: false, enumerable: false, configurable: false
+});
+
+
+// ES2017, 25.2.3 Properties of the GeneratorFunction Prototype Object
+
+assertEqArray(Object.getOwnPropertyNames(GeneratorFunctionPrototype).sort(), ["constructor", "prototype"]);
+assertEqArray(Object.getOwnPropertySymbols(GeneratorFunctionPrototype), [Symbol.toStringTag]);
+
+assertOwnDescriptor(GeneratorFunctionPrototype, "constructor", {
+ value: GeneratorFunction, writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(GeneratorFunctionPrototype, "prototype", {
+ value: GeneratorPrototype, writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(GeneratorFunctionPrototype, Symbol.toStringTag, {
+ value: "GeneratorFunction", writable: false, enumerable: false, configurable: true
+});
+
+
+// ES2017, 25.2.4 GeneratorFunction Instances
+
+assertEqArray(Object.getOwnPropertyNames(generator).sort(), ["length", "name", "prototype"]);
+assertEqArray(Object.getOwnPropertySymbols(generator), []);
+
+assertOwnDescriptor(generator, "length", {
+ value: 0, writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(generator, "name", {
+ value: "generator", writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(generator, "prototype", {
+ value: generator.prototype, writable: true, enumerable: false, configurable: false
+});
+
+
+// ES2017, 25.3.1 Properties of Generator Prototype
+
+assertEqArray(Object.getOwnPropertyNames(GeneratorPrototype).sort(), ["constructor", "next", "return", "throw"]);
+assertEqArray(Object.getOwnPropertySymbols(GeneratorPrototype), [Symbol.toStringTag]);
+
+assertOwnDescriptor(GeneratorPrototype, "constructor", {
+ value: GeneratorFunctionPrototype, writable: false, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(GeneratorPrototype, "next", {
+ value: GeneratorPrototype.next, writable: true, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(GeneratorPrototype, "return", {
+ value: GeneratorPrototype.return, writable: true, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(GeneratorPrototype, "throw", {
+ value: GeneratorPrototype.throw, writable: true, enumerable: false, configurable: true
+});
+
+assertOwnDescriptor(GeneratorPrototype, Symbol.toStringTag, {
+ value: "Generator", writable: false, enumerable: false, configurable: true
+});
+
+
+if (typeof reportCompare == "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/Promise/self-resolve.js b/js/src/tests/ecma_6/Promise/self-resolve.js
index e16a2ceb3..4e7e36c6c 100644
--- a/js/src/tests/ecma_6/Promise/self-resolve.js
+++ b/js/src/tests/ecma_6/Promise/self-resolve.js
@@ -5,6 +5,7 @@ if (!this.Promise) {
quit(0);
}
+// Resolve Promise with itself by directly calling the "Promise Resolve Function".
let resolve;
let promise = new Promise(function(x) { resolve = x; });
resolve(promise)
@@ -20,4 +21,23 @@ drainJobQueue()
assertEq(results.length, 1);
assertEq(results[0], "rejected");
+// Resolve Promise with itself when the "Promise Resolve Function" is called
+// from (the fast path in) PromiseReactionJob.
+results = [];
+
+promise = new Promise(x => { resolve = x; });
+let promise2 = promise.then(() => promise2);
+
+promise2.then(() => assertEq(true, false, "not reached"), res => {
+ assertEq(res instanceof TypeError, true);
+ results.push("rejected");
+});
+
+resolve();
+
+drainJobQueue();
+
+assertEq(results.length, 1);
+assertEq(results[0], "rejected");
+
this.reportCompare && reportCompare(0, 0, "ok");
diff --git a/js/src/tests/ecma_6/Symbol/well-known.js b/js/src/tests/ecma_6/Symbol/well-known.js
index 8c5de1279..095d333a0 100644
--- a/js/src/tests/ecma_6/Symbol/well-known.js
+++ b/js/src/tests/ecma_6/Symbol/well-known.js
@@ -11,7 +11,8 @@ var names = [
"hasInstance",
"split",
"toPrimitive",
- "unscopables"
+ "unscopables",
+ "asyncIterator"
];
for (var name of names) {
diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax.js b/js/src/tests/ecma_7/AsyncFunctions/syntax.js
index 28e5febc1..0b4b50af4 100644
--- a/js/src/tests/ecma_7/AsyncFunctions/syntax.js
+++ b/js/src/tests/ecma_7/AsyncFunctions/syntax.js
@@ -9,9 +9,6 @@ if (typeof Reflect !== "undefined" && Reflect.parse) {
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");
diff --git a/js/src/tests/js1_5/Object/regress-362872-01.js b/js/src/tests/js1_5/Object/regress-362872-01.js
deleted file mode 100644
index 0808ee82b..000000000
--- a/js/src/tests/js1_5/Object/regress-362872-01.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 362872;
-var summary = 'script should not drop watchpoint that is in use';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- function exploit() {
- var rooter = {}, object = {}, filler1 = "", filler2 = "\u5555";
- for(var i = 0; i < 32/2-2; i++) { filler1 += "\u5050"; }
- object.watch("foo", function(){
- object.unwatch("foo");
- object.unwatch("foo");
- for(var i = 0; i < 8 * 1024; i++) {
- rooter[i] = filler1 + filler2;
- }
- });
- object.foo = "bar";
- }
- exploit();
-
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/Object/regress-362872-02.js b/js/src/tests/js1_5/Object/regress-362872-02.js
deleted file mode 100644
index edee43a4a..000000000
--- a/js/src/tests/js1_5/Object/regress-362872-02.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- * Contributor: Blake Kaplan
- */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 362872;
-var summary = 'script should not drop watchpoint that is in use';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-this.watch('x', function f() {
- print("before");
- x = 3;
- print("after");
- });
-x = 3;
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/Regress/regress-127243.js b/js/src/tests/js1_5/Regress/regress-127243.js
deleted file mode 100644
index 11779f803..000000000
--- a/js/src/tests/js1_5/Regress/regress-127243.js
+++ /dev/null
@@ -1,75 +0,0 @@
-// |reftest| skip-if(xulRuntime.OS=="WINNT"&&isDebugBuild) slow
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 127243;
-var summary = 'Do not crash on watch';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-if (typeof window != 'undefined' && typeof document != 'undefined')
-{
- // delay test driver end
- gDelayTestDriverEnd = true;
- window.addEventListener('load', handleLoad, false);
-}
-else
-{
- printStatus('This test must be run in the browser');
- reportCompare(expect, actual, summary);
-
-}
-
-var div;
-
-function handleLoad()
-{
- div = document.createElement('div');
- document.body.appendChild(div);
- div.setAttribute('id', 'id1');
- div.style.width = '50px';
- div.style.height = '100px';
- div.style.overflow = 'auto';
-
- for (var i = 0; i < 5; i++)
- {
- var p = document.createElement('p');
- var t = document.createTextNode('blah');
- p.appendChild(t);
- div.appendChild(p);
- }
-
- div.watch('scrollTop', wee);
-
- setTimeout('setScrollTop()', 1000);
-}
-
-function wee(id, oldval, newval)
-{
- var t = document.createTextNode('setting ' + id +
- ' value ' + div.scrollTop +
- ' oldval ' + oldval +
- ' newval ' + newval);
- var p = document.createElement('p');
- p.appendChild(t);
- document.body.appendChild(p);
-
- return newval;
-}
-
-function setScrollTop()
-{
- div.scrollTop = 42;
-
- reportCompare(expect, actual, summary);
-
- gDelayTestDriverEnd = false;
- jsTestDriverEnd();
-
-}
diff --git a/js/src/tests/js1_5/Regress/regress-213482.js b/js/src/tests/js1_5/Regress/regress-213482.js
deleted file mode 100644
index 26ed7e894..000000000
--- a/js/src/tests/js1_5/Regress/regress-213482.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 213482;
-var summary = 'Do not crash watching property when watcher sets property';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-var testobj = {value: 'foo'};
-
-function watched (a, b, c) {
- testobj.value = (new Date()).getTime();
-}
-
-function setTest() {
- testobj.value = 'b';
-}
-
-testobj.watch("value", watched);
-
-setTest();
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/Regress/regress-240577.js b/js/src/tests/js1_5/Regress/regress-240577.js
deleted file mode 100644
index ba8330aa0..000000000
--- a/js/src/tests/js1_5/Regress/regress-240577.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- * Contributor: Bob Clary
- */
-
-//-----------------------------------------------------------------------------
-// originally reported by Jens Thiele <karme@unforgettable.com> in
-var BUGNUMBER = 240577;
-var summary = 'object.watch execution context';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-var createWatcher = function ( watchlabel )
-{
- var watcher = function (property, oldvalue, newvalue)
- {
- actual += watchlabel; return newvalue;
- };
- return watcher;
-};
-
-var watcher1 = createWatcher('watcher1');
-
-var object = {property: 'value'};
-
-object.watch('property', watcher1);
-
-object.property = 'newvalue';
-
-expect = 'watcher1';
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/Regress/regress-355341.js b/js/src/tests/js1_5/Regress/regress-355341.js
deleted file mode 100644
index ab2a4b884..000000000
--- a/js/src/tests/js1_5/Regress/regress-355341.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 355341;
-var summary = 'Do not crash with watch and setter';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- Object.defineProperty(this, "x", { set: Function, enumerable: true, configurable: true });
- this.watch('x', function () { }); x = 3;
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/Regress/regress-355344.js b/js/src/tests/js1_5/Regress/regress-355344.js
deleted file mode 100644
index 00bd39147..000000000
--- a/js/src/tests/js1_5/Regress/regress-355344.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 355344;
-var summary = 'Exceptions thrown by watch point';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- var o = {};
-
- expect = 'setter: yikes';
-
- o.watch('x', function(){throw 'yikes'});
- try
- {
- o.x = 3;
- }
- catch(ex)
- {
- actual = "setter: " + ex;
- }
-
- try
- {
- eval("") ;
- }
- catch(e)
- {
- actual = "eval: " + e;
- }
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/Regress/regress-361467.js b/js/src/tests/js1_5/Regress/regress-361467.js
deleted file mode 100644
index 371c0a8b5..000000000
--- a/js/src/tests/js1_5/Regress/regress-361467.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361467;
-var summary = 'Do not crash with certain watchers';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- expect = actual = 'No Crash';
-
- var x;
- this.watch('x', print);
- x = 5;
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/Regress/regress-361617.js b/js/src/tests/js1_5/Regress/regress-361617.js
deleted file mode 100644
index 5d20fd78f..000000000
--- a/js/src/tests/js1_5/Regress/regress-361617.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361617;
-var summary = 'Do not crash with getter, watch and gc';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- (function() {
- Object.defineProperty(this, "x", { get: function(){}, enumerable: true, configurable: true });
- })();
- this.watch('x', print);
- Object.defineProperty(this, "x", { get: function(){}, enumerable: true, configurable: true });
- gc();
- this.unwatch('x');
- x;
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/Regress/regress-385393-06.js b/js/src/tests/js1_5/Regress/regress-385393-06.js
deleted file mode 100644
index 327103f39..000000000
--- a/js/src/tests/js1_5/Regress/regress-385393-06.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 385393;
-var summary = 'Regression test for bug 385393';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- reportCompare(expect, actual, summary);
-
- true.watch("x", function(){});
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/Regress/regress-506567.js b/js/src/tests/js1_5/Regress/regress-506567.js
deleted file mode 100644
index e78dfe1db..000000000
--- a/js/src/tests/js1_5/Regress/regress-506567.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 506567;
-var summary = 'Do not crash with watched variables';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- if (typeof clearInterval == 'undefined')
- {
- clearInterval = (function () {});
- }
-
- var obj = new Object();
- obj.test = null;
- obj.watch("test", (function(prop, oldval, newval)
- {
- if(false)
- {
- var test = newval % oldval;
- var func = (function(){clearInterval(myInterval);});
- }
- }));
-
- obj.test = 'null';
- print(obj.test);
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/extensions/regress-303277.js b/js/src/tests/js1_5/extensions/regress-303277.js
deleted file mode 100644
index 319d9a2ed..000000000
--- a/js/src/tests/js1_5/extensions/regress-303277.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 303277;
-var summary = 'Do not crash with crash with a watchpoint for __proto__ property ';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-var o = {};
-o.watch("__proto__", function(){return null;});
-o.__proto__ = null;
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-355339.js b/js/src/tests/js1_5/extensions/regress-355339.js
deleted file mode 100644
index 9b15bd742..000000000
--- a/js/src/tests/js1_5/extensions/regress-355339.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 355339;
-var summary = 'Do not assert: sprop->setter != js_watch_set';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- expect = actual = 'No Crash';
- o = {};
- o.watch("j", function(a,b,c) { print("*",a,b,c) });
- o.unwatch("j");
- o.watch("j", function(a,b,c) { print("*",a,b,c) });
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/extensions/regress-361346.js b/js/src/tests/js1_5/extensions/regress-361346.js
deleted file mode 100644
index 297c3b1f2..000000000
--- a/js/src/tests/js1_5/extensions/regress-361346.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361346;
-var summary = 'Crash with setter, watch, GC';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-expect = actual = 'No Crash';
-
-Object.defineProperty(this, "x", { set: new Function, enumerable: true, configurable: true });
-this.watch('x', function(){});
-gc();
-x = {};
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-361360.js b/js/src/tests/js1_5/extensions/regress-361360.js
deleted file mode 100644
index 98e6575d9..000000000
--- a/js/src/tests/js1_5/extensions/regress-361360.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361360;
-var summary = 'Do not assert: !caller || caller->pc involving setter and watch';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- expect = actual = 'No Crash';
-
- this.__defineSetter__('x', eval);
- this.watch('x', function(){});
- x = 3;
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/extensions/regress-361552.js b/js/src/tests/js1_5/extensions/regress-361552.js
deleted file mode 100644
index eed54e6dd..000000000
--- a/js/src/tests/js1_5/extensions/regress-361552.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361552;
-var summary = 'Crash with setter, watch, Script';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-expect = actual = 'No Crash';
-
-if (typeof Script == 'undefined')
-{
- print('Test skipped. Script not defined.');
-}
-else
-{
- this.__defineSetter__('x', gc);
- this.watch('x', new Script(''));
- x = 3;
-}
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-361558.js b/js/src/tests/js1_5/extensions/regress-361558.js
deleted file mode 100644
index a9a3ae725..000000000
--- a/js/src/tests/js1_5/extensions/regress-361558.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361558;
-var summary = 'Do not assert: sprop->setter != js_watch_set';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-expect = actual = 'No Crash';
-
-({}.__proto__.watch('x', print)); ({}.watch('x', print));
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-361571.js b/js/src/tests/js1_5/extensions/regress-361571.js
deleted file mode 100644
index bf89d794b..000000000
--- a/js/src/tests/js1_5/extensions/regress-361571.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361571;
-var summary = 'Do not assert: fp->scopeChain == parent';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- try
- {
- o = {};
- o.__defineSetter__('y', eval);
- o.watch('y', function () { return "";});
- o.y = 1;
- }
- catch(ex)
- {
- printStatus('Note eval can no longer be called directly');
- expect = 'EvalError: function eval must be called directly, and not by way of a function of another name';
- actual = ex + '';
- }
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/extensions/regress-361856.js b/js/src/tests/js1_5/extensions/regress-361856.js
deleted file mode 100644
index e7e2f675b..000000000
--- a/js/src/tests/js1_5/extensions/regress-361856.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361856;
-var summary = 'Do not assert: overwriting @ js_AddScopeProperty';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- function testit() {
- var obj = {};
- obj.watch("foo", function(){});
- delete obj.foo;
- obj = null;
- gc();
- }
- testit();
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/extensions/regress-361964.js b/js/src/tests/js1_5/extensions/regress-361964.js
deleted file mode 100644
index fcb8bba01..000000000
--- a/js/src/tests/js1_5/extensions/regress-361964.js
+++ /dev/null
@@ -1,54 +0,0 @@
-// |reftest| skip -- slow, alert not dismissed, now busted by harness
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 361964;
-var summary = 'Crash [@ MarkGCThingChildren] involving watch and setter';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- var doc;
- if (typeof document == 'undefined')
- {
- doc = {};
- }
- else
- {
- doc = document;
- }
-
- if (typeof alert == 'undefined')
- {
- alert = print;
- }
-
-// Crash:
- doc.watch("title", function(a,b,c,d) {
- return { toString : function() { alert(1); } };
- });
- doc.title = "xxx";
-
-// No crash:
- doc.watch("title", function() {
- return { toString : function() { alert(1); } };
- });
- doc.title = "xxx";
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/extensions/regress-385134.js b/js/src/tests/js1_5/extensions/regress-385134.js
deleted file mode 100644
index 041f4d6e7..000000000
--- a/js/src/tests/js1_5/extensions/regress-385134.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 385134;
-var summary = 'Do not crash with setter, watch, uneval';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- if (typeof this.__defineSetter__ != 'undefined' &&
- typeof this.watch != 'undefined' &&
- typeof uneval != 'undefined')
- {
- try {
- this.__defineSetter__(0, function(){});
- } catch (exc) {
- // In the browser, this fails. Ignore the error.
- }
- this.watch(0, function(){});
- uneval(this);
- }
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/extensions/regress-385393-09.js b/js/src/tests/js1_5/extensions/regress-385393-09.js
deleted file mode 100644
index 42834824a..000000000
--- a/js/src/tests/js1_5/extensions/regress-385393-09.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 385393;
-var summary = 'Regression test for bug 385393';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-eval("this.__defineSetter__('x', gc); this.watch('x', [].slice); x = 1;");
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-390597.js b/js/src/tests/js1_5/extensions/regress-390597.js
deleted file mode 100644
index 9f8596adc..000000000
--- a/js/src/tests/js1_5/extensions/regress-390597.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 390597;
-var summary = 'watch point + eval-as-setter allows access to dead JSStackFrame';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- function exploit() {
- try
- {
- var obj = this, args = null;
- obj.__defineSetter__("evil", eval);
- obj.watch("evil", function() { return "args = arguments;"; });
- obj.evil = null;
- eval("print(args[0]);");
- }
- catch(ex)
- {
- print('Caught ' + ex);
- }
- }
- exploit();
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_5/extensions/regress-420612.js b/js/src/tests/js1_5/extensions/regress-420612.js
deleted file mode 100644
index a4491095e..000000000
--- a/js/src/tests/js1_5/extensions/regress-420612.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 420612;
-var summary = 'Do not assert: obj == pobj';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-var obj = Object.create([]);
-obj.unwatch("x");
-
-if (typeof reportCompare === "function")
- reportCompare(true, true);
-
-print("Tests complete");
diff --git a/js/src/tests/js1_5/extensions/regress-435345-01.js b/js/src/tests/js1_5/extensions/regress-435345-01.js
deleted file mode 100644
index 28beab473..000000000
--- a/js/src/tests/js1_5/extensions/regress-435345-01.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// |reftest| fails
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 435345;
-var summary = 'Watch the length property of arrays';
-var actual = '';
-var expect = '';
-
-// see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Object:watch
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- var arr;
-
- try
- {
- expect = 'watcher: propname=length, oldval=0, newval=1; ';
- actual = '';
- arr = [];
- arr.watch('length', watcher);
- arr[0] = '0';
- }
- catch(ex)
- {
- actual = ex + '';
- }
- reportCompare(expect, actual, summary + ': 1');
-
- try
- {
- expect = 'watcher: propname=length, oldval=1, newval=2; ' +
- 'watcher: propname=length, oldval=2, newval=2; ';
- actual = '';
- arr.push(5);
- }
- catch(ex)
- {
- actual = ex + '';
- }
- reportCompare(expect, actual, summary + ': 2');
-
- try
- {
- expect = 'watcher: propname=length, oldval=2, newval=1; ';
- actual = '';
- arr.pop();
- }
- catch(ex)
- {
- actual = ex + '';
- }
- reportCompare(expect, actual, summary + ': 3');
-
- try
- {
- expect = 'watcher: propname=length, oldval=1, newval=2; ';
- actual = '';
- arr.length++;
- }
- catch(ex)
- {
- actual = ex + '';
- }
- reportCompare(expect, actual, summary + ': 4');
-
- try
- {
- expect = 'watcher: propname=length, oldval=2, newval=5; ';
- actual = '';
- arr.length = 5;
- }
- catch(ex)
- {
- actual = ex + '';
- }
- reportCompare(expect, actual, summary + ': 5');
-
- exitFunc ('test');
-}
-
-function watcher(propname, oldval, newval)
-{
- actual += 'watcher: propname=' + propname + ', oldval=' + oldval +
- ', newval=' + newval + '; ';
-
- return newval;
-}
-
diff --git a/js/src/tests/js1_5/extensions/regress-454040.js b/js/src/tests/js1_5/extensions/regress-454040.js
deleted file mode 100644
index 63b5e1488..000000000
--- a/js/src/tests/js1_5/extensions/regress-454040.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 454040;
-var summary = 'Do not crash @ js_ComputeFilename';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-try
-{
- this.__defineGetter__("x", Function);
- this.__defineSetter__("x", Function);
- this.watch("x", x.__proto__);
- x = 1;
-}
-catch(ex)
-{
-}
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-454142.js b/js/src/tests/js1_5/extensions/regress-454142.js
deleted file mode 100644
index 05f331278..000000000
--- a/js/src/tests/js1_5/extensions/regress-454142.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// |reftest| skip-if(Android)
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 454142;
-var summary = 'Do not crash with gczeal, setter, watch';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-this.watch("x", function(){});
-delete x;
-if (typeof gczeal == 'function')
-{
- gczeal(2);
-}
-
-this.__defineSetter__("x", function(){});
-
-if (typeof gczeal == 'function')
-{
- gczeal(0);
-}
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-455413.js b/js/src/tests/js1_5/extensions/regress-455413.js
deleted file mode 100644
index d00ab135b..000000000
--- a/js/src/tests/js1_5/extensions/regress-455413.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 455413;
-var summary = 'Do not assert with JIT: (m != JSVAL_INT) || isInt32(*vp)';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-
-this.watch('x', Math.pow); (function() { for(var j=0;j<4;++j){x=1;} })();
-
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-465145.js b/js/src/tests/js1_5/extensions/regress-465145.js
deleted file mode 100644
index 84f81703b..000000000
--- a/js/src/tests/js1_5/extensions/regress-465145.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 465145;
-var summary = 'Do not crash with watched defined setter';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-
-this.__defineSetter__("x", function(){});
-this.watch("x", function(){});
-y = this;
-for (var z = 0; z < 2; ++z) { x = y };
-this.__defineSetter__("x", function(){});
-for (var z = 0; z < 2; ++z) { x = y };
-
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-472787.js b/js/src/tests/js1_5/extensions/regress-472787.js
deleted file mode 100755
index d3196f05f..000000000
--- a/js/src/tests/js1_5/extensions/regress-472787.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// |reftest| skip-if(Android)
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 472787;
-var summary = 'Do not hang with gczeal, watch and concat';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-this.__defineSetter__("x", Math.sin);
-this.watch("x", '' .concat);
-
-if (typeof gczeal == 'function')
-{
- gczeal(2);
-}
-
-x = 1;
-
-if (typeof gczeal == 'function')
-{
- gczeal(0);
-}
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_5/extensions/regress-488995.js b/js/src/tests/js1_5/extensions/regress-488995.js
deleted file mode 100644
index f7abbe439..000000000
--- a/js/src/tests/js1_5/extensions/regress-488995.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 488995;
-var summary = 'Do not crash with watch, __defineSetter__ on svg';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- if (typeof document == 'undefined')
- {
- print('Test skipped: requires browser.');
- }
- else
- {
- try
- {
- var o=document.createElementNS("http://www.w3.org/2000/svg", "svg");
- var p=o.y;
- p.watch('animVal', function(id, oldvar, newval) {} );
- p.type='xxx';
- p.__defineSetter__('animVal', function() {});
- p.animVal=0;
- }
- catch(ex)
- {
- }
- }
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_6/Regress/regress-476655.js b/js/src/tests/js1_6/Regress/regress-476655.js
deleted file mode 100644
index 9077ba3a0..000000000
--- a/js/src/tests/js1_6/Regress/regress-476655.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 476655;
-var summary = 'TM: Do not assert: count <= (size_t) (fp->regs->sp - StackBase(fp) - depth)';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
-
- try
- {
- eval(
- "(function (){ for (var y in this) {} })();" +
- "[''.watch(\"\", function(){}) for each (x in ['', '', eval, '', '']) if " +
- "(x)].map(Function)"
- );
- }
- catch(ex)
- {
- }
-
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_6/extensions/regress-457521.js b/js/src/tests/js1_6/extensions/regress-457521.js
deleted file mode 100644
index 6f4fbda50..000000000
--- a/js/src/tests/js1_6/extensions/regress-457521.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 457521;
-var summary = 'Do not crash @ js_DecompileValueGenerator';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-try
-{
- this.__defineSetter__("x", [,,,].map);
- this.watch("x", (new Function("var y, eval")));
- x = true;
-}
-catch(ex)
-{
-}
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_6/extensions/regress-479567.js b/js/src/tests/js1_6/extensions/regress-479567.js
deleted file mode 100644
index 6f3525130..000000000
--- a/js/src/tests/js1_6/extensions/regress-479567.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 479567;
-var summary = 'Do not assert: thing';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-
-function f()
-{
- (eval("(function(){for each (y in [false, false, false]);});"))();
-}
-
-try
-{
- this.__defineGetter__("x", gc);
- uneval(this.watch("y", this.toSource))
- f();
- throw x;
-}
-catch(ex)
-{
-}
-
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_7/extensions/regress-453955.js b/js/src/tests/js1_7/extensions/regress-453955.js
deleted file mode 100644
index 454f712f3..000000000
--- a/js/src/tests/js1_7/extensions/regress-453955.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 453955;
-var summary = 'Do not assert: sprop->setter != js_watch_set || pobj != obj';
-var actual = '';
-var expect = '';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- for (var z = 0; z < 2; ++z)
- {
- [].filter.watch("9", function(y) { yield y; });
- }
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_7/extensions/regress-473282.js b/js/src/tests/js1_7/extensions/regress-473282.js
deleted file mode 100644
index c50ac9234..000000000
--- a/js/src/tests/js1_7/extensions/regress-473282.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 473282;
-var summary = 'Do not assert: thing';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-this.watch("b", "".substring);
-this.__defineGetter__("a", gc);
-for each (b in [this, null, null]);
-a;
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_7/regress/regress-385133-01.js b/js/src/tests/js1_7/regress/regress-385133-01.js
deleted file mode 100644
index 03b09f535..000000000
--- a/js/src/tests/js1_7/regress/regress-385133-01.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 385133;
-var summary = 'Do not crash due to recursion with watch, setter, delete, generator';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- try
- {
- Object.defineProperty(this, "x", { set: {}.watch, enumerable: true, configurable: true });
- this.watch('x', 'foo'.split);
- delete x;
- function g(){ x = 1; yield; }
- for (i in g()) { }
- }
- catch(ex)
- {
- }
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_8/extensions/regress-394709.js b/js/src/tests/js1_8/extensions/regress-394709.js
deleted file mode 100644
index d04d8832f..000000000
--- a/js/src/tests/js1_8/extensions/regress-394709.js
+++ /dev/null
@@ -1,51 +0,0 @@
-// |reftest| skip-if(!xulRuntime.shell)
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 394709;
-var summary = 'Do not leak with object.watch and closure';
-var actual = 'No Leak';
-var expect = 'No Leak';
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- assertEq(finalizeCount(), 0, "invalid initial state");
-
- runtest();
- gc();
- assertEq(finalizeCount(), 1, "leaked");
-
- runtest();
- gc();
- assertEq(finalizeCount(), 2, "leaked");
-
- runtest();
- gc();
- assertEq(finalizeCount(), 3, "leaked");
-
-
- function runtest () {
- var obj = { b: makeFinalizeObserver() };
- obj.watch('b', watcher);
-
- function watcher(id, old, value) {
- ++obj.n;
- return value;
- }
- }
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_8/extensions/regress-481989.js b/js/src/tests/js1_8/extensions/regress-481989.js
deleted file mode 100644
index 36efb7567..000000000
--- a/js/src/tests/js1_8/extensions/regress-481989.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 481989;
-var summary = 'TM: Do not assert: SPROP_HAS_STUB_SETTER(sprop)';
-var actual = '';
-var expect = '';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-
-
-y = this.watch("x", function(){}); for each (let y in ['', '']) x = y;
-
-
-reportCompare(expect, actual, summary);
diff --git a/js/src/tests/js1_8_1/extensions/regress-452498-193.js b/js/src/tests/js1_8_1/extensions/regress-452498-193.js
deleted file mode 100644
index 1397bf4bb..000000000
--- a/js/src/tests/js1_8_1/extensions/regress-452498-193.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 452498;
-var summary = 'TM: upvar2 regression tests';
-var actual = '';
-var expect = '';
-
-//------- Comment #193 From Gary Kwong
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
-// Assertion failure: afunbox->parent, at ../jsparse.cpp:1912
-
- this.x = undefined;
- this.watch("x", Function);
- NaN = uneval({ get \u3056 (){ return undefined } });
- x+=NaN;
-
- reportCompare(expect, actual, summary);
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_8_1/extensions/regress-452498-196.js b/js/src/tests/js1_8_1/extensions/regress-452498-196.js
index 69d5a3586..5b9191199 100644
--- a/js/src/tests/js1_8_1/extensions/regress-452498-196.js
+++ b/js/src/tests/js1_8_1/extensions/regress-452498-196.js
@@ -21,15 +21,6 @@ function test()
printBugNumber(BUGNUMBER);
printStatus (summary);
-// Assertion failure: localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST, at ../jsfun.cpp:916
-
- this.x = undefined;
- this.watch("x", Function);
- NaN = uneval({ get \u3056 (){ return undefined } });
- x+=NaN;
-
- reportCompare(expect, actual, summary + ': 1');
-
// Assertion failure: lexdep->isLet(), at ../jsparse.cpp:1900
(function (){
diff --git a/js/src/tests/js1_8_1/extensions/regress-520572.js b/js/src/tests/js1_8_1/extensions/regress-520572.js
deleted file mode 100644
index 97f00029a..000000000
--- a/js/src/tests/js1_8_1/extensions/regress-520572.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- * Contributor: Blake Kaplan
- */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 520572;
-var summary = 'watch should innerize the object being watched';
-var actual = 0;
-var expect = 2;
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
- enterFunc ('test');
- printBugNumber(BUGNUMBER);
- printStatus (summary);
-
- if ("evalcx" in this) {
- // shell
- let s = evalcx("lazy");
- s.n = 0;
- evalcx('this.watch("x", function(){ n++; }); this.x = 4; x = 6', s);
- actual = s.n;
- reportCompare(expect, actual, summary);
- } else {
- // browser
- this.watch('x', function(){ actual++; });
- this.x = 4;
- x = 6;
- reportCompare(expect, actual, summary);
- }
-
- exitFunc ('test');
-}
diff --git a/js/src/tests/js1_8_1/regress/regress-452498-160.js b/js/src/tests/js1_8_1/regress/regress-452498-160.js
index 6498a0b5a..305b41795 100644
--- a/js/src/tests/js1_8_1/regress/regress-452498-160.js
+++ b/js/src/tests/js1_8_1/regress/regress-452498-160.js
@@ -21,11 +21,6 @@ function test()
printBugNumber(BUGNUMBER);
printStatus (summary);
-// crash [@ js_Interpret]
- (eval("(function(){ this.watch(\"x\", function () { new function ()y } ); const y = undefined });"))();
- x = NaN;
- reportCompare(expect, actual, summary + ': 2');
-
// Assertion failure: JOF_OPTYPE(op) == JOF_ATOM, at ../jsemit.cpp:5916
({ set z(v){}, set y(v)--x, set w(v)--w });
reportCompare(expect, actual, summary + ': 3');
diff --git a/js/src/tests/js1_8_5/extensions/regress-604781-1.js b/js/src/tests/js1_8_5/extensions/regress-604781-1.js
deleted file mode 100644
index a7c43f95d..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-604781-1.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var watcherCount, setterCount;
-function watcher(id, oldval, newval) { watcherCount++; return newval; }
-function setter(newval) { setterCount++; }
-
-var p = { set x(v) { setter(v); } };
-p.watch('x', watcher);
-
-watcherCount = setterCount = 0;
-p.x = 2;
-assertEq(setterCount, 1);
-assertEq(watcherCount, 1);
-
-var o = Object.defineProperty({}, 'x', { set:setter, enumerable:true, configurable:true });
-o.watch('x', watcher);
-
-watcherCount = setterCount = 0;
-o.x = 2;
-assertEq(setterCount, 1);
-assertEq(watcherCount, 1);
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-604781-2.js b/js/src/tests/js1_8_5/extensions/regress-604781-2.js
deleted file mode 100644
index 7aba4a274..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-604781-2.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var log;
-function watcher(id, old, newval) { log += 'watcher'; return newval; }
-var o = { set x(v) { log += 'setter'; } };
-o.watch('x', watcher);
-Object.defineProperty(o, 'x', {value: 3, writable: true});
-log = '';
-o.x = 3;
-assertEq(log, 'watcher');
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-1.js b/js/src/tests/js1_8_5/extensions/regress-627984-1.js
deleted file mode 100644
index a3726630a..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-627984-1.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-// See bug 627984, comment 17, item 1.
-var obj;
-var methods = [];
-for (var i = 0; i < 2; i++) {
- obj = {m: function () { return this.x; }};
- obj.watch("m", function (id, oldval, newval) { methods[i] = oldval; });
- obj.m = 0;
-}
-assertEq(typeof methods[0], "function");
-assertEq(typeof methods[1], "function");
-assertEq(methods[0] !== methods[1], true);
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-2.js b/js/src/tests/js1_8_5/extensions/regress-627984-2.js
deleted file mode 100644
index c4f1b508c..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-627984-2.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-// See bug 627984, comment 17, item 2.
-var obj = {};
-var x;
-obj.watch("m", function (id, oldval, newval) {
- x = this.m;
- return newval;
- });
-delete obj.m;
-obj.m = function () { return this.method; };
-obj.m = 2;
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-3.js b/js/src/tests/js1_8_5/extensions/regress-627984-3.js
deleted file mode 100644
index cbe4e10fa..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-627984-3.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-// Don't write string value to method slot.
-// See bug 627984, comment 17, item 2.
-var obj = {};
-obj.watch("m", function (id, oldval, newval) {
- return 'ok';
- });
-delete obj.m;
-obj.m = function () { return this.x; };
-assertEq(obj.m, 'ok');
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-4.js b/js/src/tests/js1_8_5/extensions/regress-627984-4.js
deleted file mode 100644
index bbc017ffb..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-627984-4.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-// See bug 627984, comment 17, item 3.
-var obj = {};
-obj.watch("m", function (id, oldval, newval) {
- delete obj.m;
- obj.m = function () {};
- return newval;
- });
-delete obj.m;
-obj.m = 1;
-assertEq(obj.m, 1);
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-5.js b/js/src/tests/js1_8_5/extensions/regress-627984-5.js
deleted file mode 100644
index 704d8421c..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-627984-5.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-// Bug 627984 comment 11.
-var o = ({});
-o.p = function() {};
-o.watch('p', function() { });
-o.q = function() {}
-delete o.p;
-o.p = function() {};
-assertEq(o.p, void 0);
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-6.js b/js/src/tests/js1_8_5/extensions/regress-627984-6.js
deleted file mode 100644
index cb1a0fca9..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-627984-6.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-// Bug 627984 description.
-var o = Array;
-o.p = function() {};
-o.watch('p', function() { });
-for(var x in o) {
- o[x];
-}
-delete o.p;
-o.p = function() {};
-assertEq(o.p, void 0);
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-7.js b/js/src/tests/js1_8_5/extensions/regress-627984-7.js
deleted file mode 100644
index b13a0e912..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-627984-7.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-// See bug 627984 comment 20.
-var obj = {m: function () {}};
-obj.watch("m", function () { throw 'FAIL'; });
-var f = obj.m; // don't call the watchpoint
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-631723.js b/js/src/tests/js1_8_5/extensions/regress-631723.js
deleted file mode 100644
index f7c755603..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-631723.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var o = {a:1, b:2};
-o.watch("p", function() { return 13; });
-delete o.p;
-o.p = 0;
-assertEq(o.p, 13);
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-636697.js b/js/src/tests/js1_8_5/extensions/regress-636697.js
deleted file mode 100644
index 6b3b1de37..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-636697.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var a = {set p(x) {}};
-a.watch('p', function () {});
-var b = Object.create(a);
-b.watch('p', function () {});
-delete b.p;
-b.p = 0;
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/regress-637985.js b/js/src/tests/js1_8_5/extensions/regress-637985.js
deleted file mode 100644
index 305bfc820..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-637985.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var obj = {};
-obj.watch(-1, function(){});
-obj.unwatch("-1"); // don't assert
-
-reportCompare(0, 0, 'ok'); \ No newline at end of file
diff --git a/js/src/tests/js1_8_5/extensions/regress-691746.js b/js/src/tests/js1_8_5/extensions/regress-691746.js
deleted file mode 100644
index 26f732d07..000000000
--- a/js/src/tests/js1_8_5/extensions/regress-691746.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var obj = {};
-try {
- obj.watch(QName(), function () {});
-} catch (exc) {
-}
-gc();
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/extensions/watch-undefined-setter.js b/js/src/tests/js1_8_5/extensions/watch-undefined-setter.js
deleted file mode 100644
index 92608de0e..000000000
--- a/js/src/tests/js1_8_5/extensions/watch-undefined-setter.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- * Contributor:
- * Gary Kwong
- */
-
-var gTestfile = 'watch-undefined-setter.js';
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 560277;
-var summary =
- 'Crash [@ JSObject::getParent] or [@ js_WrapWatchedSetter] or ' +
- '[@ js_GetClassPrototype]';
-
-this.watch("x", function() { });
-Object.defineProperty(this, "x", { set: undefined, configurable: true });
-
-reportCompare(true, true);
diff --git a/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js b/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
index be65bd76e..51b7c6926 100644
--- a/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
+++ b/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
@@ -53,9 +53,8 @@ function asyncFunDecl(id, params, body) {
params: params,
defaults: [],
body: body,
- generator: true,
- async: true,
- style: "es6" });
+ generator: false,
+ async: true });
}
function varDecl(decls) {
return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" });
@@ -181,9 +180,8 @@ function asyncFunExpr(id, args, body) {
id: id,
params: args,
body: body,
- generator: true,
- async: true,
- style: "es6" });
+ generator: false,
+ async: true });
}
function arrowExpr(args, body) {
return Pattern({ type: "ArrowFunctionExpression",
@@ -194,10 +192,9 @@ function asyncArrowExpr(isExpression, args, body) {
return Pattern({ type: "ArrowFunctionExpression",
params: args,
body: body,
- generator: true,
+ generator: false,
async: true,
- expression: isExpression,
- style: "es6" });
+ expression: isExpression });
}
function metaProperty(meta, property) {
diff --git a/js/src/tests/js1_8_5/regress/regress-533876.js b/js/src/tests/js1_8_5/regress/regress-533876.js
deleted file mode 100644
index e44bc8a4f..000000000
--- a/js/src/tests/js1_8_5/regress/regress-533876.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- * Contributors: Gary Kwong and Jason Orendorff
- */
-
-var savedEval = eval;
-var x = [0];
-eval();
-
-x.__proto__ = this; // x has non-dictionary scope
-try {
- DIE;
-} catch(e) {
-}
-
-delete eval; // force dictionary scope for global
-gc();
-eval = savedEval;
-var f = eval("(function () { return /x/; })");
-x.watch('x', f); // clone property from global to x, including SPROP_IN_DICTIONARY flag
-
-reportCompare("ok", "ok", "bug 533876");
diff --git a/js/src/tests/js1_8_5/regress/regress-548276.js b/js/src/tests/js1_8_5/regress/regress-548276.js
deleted file mode 100644
index 5e306eba1..000000000
--- a/js/src/tests/js1_8_5/regress/regress-548276.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// |reftest| skip
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- * Contributors: Gary Kwong and Jason Orendorff
- */
-var obj = {};
-obj.__defineSetter__("x", function() {});
-obj.watch("x", function() {});
-obj.__defineSetter__("x", /a/);
diff --git a/js/src/tests/js1_8_5/regress/regress-584648.js b/js/src/tests/js1_8_5/regress/regress-584648.js
deleted file mode 100644
index a1635ea51..000000000
--- a/js/src/tests/js1_8_5/regress/regress-584648.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// |reftest| skip
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-// Contributors: Gary Kwong <gary@rumblingedge.com>
-// Jason Orendorff <jorendorff@mozilla.com>
-
-// on a non-global object
-var x = {};
-x.watch("p", function () { evalcx(''); });
-x.p = 0;
-
-// on the global
-watch("e", (function () { evalcx(''); }));
-e = function () {};
-
-reportCompare(0, 0, "ok");
diff --git a/js/src/tests/js1_8_5/regress/regress-635195.js b/js/src/tests/js1_8_5/regress/regress-635195.js
deleted file mode 100644
index 89980b05a..000000000
--- a/js/src/tests/js1_8_5/regress/regress-635195.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var obj = {set x(v) {}};
-obj.watch("x", function() { delete obj.x; });
-obj.x = "hi"; // don't assert
-
-reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/js1_8_5/regress/regress-636394.js b/js/src/tests/js1_8_5/regress/regress-636394.js
deleted file mode 100644
index d1a249786..000000000
--- a/js/src/tests/js1_8_5/regress/regress-636394.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var a = {p0: function () {}};
-var b = /f/;
-b.__proto__ = a;
-b.watch("p0", function () {});
-b.p0;
-
-reportCompare(0, 0, "ok");
diff --git a/js/src/vm/AsyncFunction.cpp b/js/src/vm/AsyncFunction.cpp
index e14b77424..7132ed984 100644
--- a/js/src/vm/AsyncFunction.cpp
+++ b/js/src/vm/AsyncFunction.cpp
@@ -40,8 +40,11 @@ GlobalObject::initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global)
proto));
if (!asyncFunction)
return false;
- if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto))
+ if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto,
+ JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
+ {
return false;
+ }
global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto));
@@ -109,7 +112,7 @@ WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
JSObject*
js::WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
{
- MOZ_ASSERT(unwrapped->isStarGenerator());
+ MOZ_ASSERT(unwrapped->isAsync());
MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
"%FunctionPrototype% fallback in NewFunctionWithProto().");
@@ -171,22 +174,14 @@ AsyncFunctionResume(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleV
: cx->names().StarGeneratorThrow;
FixedInvokeArgs<1> args(cx);
args[0].set(valueOrReason);
- RootedValue result(cx);
- if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result))
- return AsyncFunctionThrown(cx, resultPromise);
-
- RootedObject resultObj(cx, &result.toObject());
- RootedValue doneVal(cx);
RootedValue value(cx);
- if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
- return false;
- if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
- return false;
+ if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &value))
+ return AsyncFunctionThrown(cx, resultPromise);
- if (doneVal.toBoolean())
- return AsyncFunctionReturned(cx, resultPromise, value);
+ if (generatorVal.toObject().as<GeneratorObject>().isAfterAwait())
+ return AsyncFunctionAwait(cx, resultPromise, value);
- return AsyncFunctionAwait(cx, resultPromise, value);
+ return AsyncFunctionReturned(cx, resultPromise, value);
}
// Async Functions proposal 2.2 steps 3-8.
@@ -242,9 +237,3 @@ js::IsWrappedAsyncFunction(JSFunction* fun)
{
return fun->maybeNative() == WrappedAsyncFunction;
}
-
-MOZ_MUST_USE bool
-js::CheckAsyncResumptionValue(JSContext* cx, HandleValue v)
-{
- return CheckStarGeneratorResumptionValue(cx, v);
-}
diff --git a/js/src/vm/AsyncFunction.h b/js/src/vm/AsyncFunction.h
index d7f2c1311..de7c87d13 100644
--- a/js/src/vm/AsyncFunction.h
+++ b/js/src/vm/AsyncFunction.h
@@ -35,9 +35,6 @@ MOZ_MUST_USE bool
AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise,
HandleValue generatorVal, HandleValue reason);
-MOZ_MUST_USE bool
-CheckAsyncResumptionValue(JSContext* cx, HandleValue v);
-
} // namespace js
#endif /* vm_AsyncFunction_h */
diff --git a/js/src/vm/AsyncIteration.cpp b/js/src/vm/AsyncIteration.cpp
new file mode 100644
index 000000000..300179374
--- /dev/null
+++ b/js/src/vm/AsyncIteration.cpp
@@ -0,0 +1,644 @@
+/* -*- 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/AsyncIteration.h"
+
+#include "jsarray.h"
+#include "jscompartment.h"
+
+#include "builtin/Promise.h"
+#include "vm/GeneratorObject.h"
+#include "vm/GlobalObject.h"
+#include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
+
+#include "jscntxtinlines.h"
+#include "jsobjinlines.h"
+
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+#define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
+#define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
+
+// Async Iteration proposal 8.3.10 Runtime Semantics: EvaluateBody.
+static bool
+WrappedAsyncGenerator(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedFunction wrapped(cx, &args.callee().as<JSFunction>());
+ RootedValue unwrappedVal(cx, wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT));
+ RootedFunction unwrapped(cx, &unwrappedVal.toObject().as<JSFunction>());
+ RootedValue thisValue(cx, args.thisv());
+
+ // Step 1.
+ RootedValue generatorVal(cx);
+ InvokeArgs args2(cx);
+ if (!args2.init(cx, argc))
+ return false;
+ for (size_t i = 0, len = argc; i < len; i++)
+ args2[i].set(args[i]);
+ if (!Call(cx, unwrappedVal, thisValue, args2, &generatorVal))
+ return false;
+
+ // Step 2.
+ Rooted<AsyncGeneratorObject*> asyncGenObj(
+ cx, AsyncGeneratorObject::create(cx, wrapped, generatorVal));
+ if (!asyncGenObj)
+ return false;
+
+ // Step 3 (skipped).
+ // Done in AsyncGeneratorObject::create and generator.
+
+ // Step 4.
+ args.rval().setObject(*asyncGenObj);
+ return true;
+}
+
+JSObject*
+js::WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
+{
+ MOZ_ASSERT(unwrapped->isAsync());
+ MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
+ "%FunctionPrototype% fallback in NewFunctionWithProto().");
+
+ // Create a new function with AsyncGeneratorPrototype, reusing the name and
+ // the length of `unwrapped`.
+
+ RootedAtom funName(cx, unwrapped->explicitName());
+ uint16_t length;
+ if (!JSFunction::getLength(cx, unwrapped, &length))
+ return nullptr;
+
+ RootedFunction wrapped(cx, NewFunctionWithProto(cx, WrappedAsyncGenerator, length,
+ JSFunction::NATIVE_FUN, nullptr,
+ funName, proto,
+ AllocKind::FUNCTION_EXTENDED,
+ TenuredObject));
+ if (!wrapped)
+ return nullptr;
+
+ if (unwrapped->hasCompileTimeName())
+ wrapped->setCompileTimeName(unwrapped->compileTimeName());
+
+ // Link them to each other to make GetWrappedAsyncGenerator and
+ // GetUnwrappedAsyncGenerator work.
+ unwrapped->setExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
+ wrapped->setExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
+
+ return wrapped;
+}
+
+JSObject*
+js::WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped)
+{
+ RootedObject proto(cx, GlobalObject::getOrCreateAsyncGenerator(cx, cx->global()));
+ if (!proto)
+ return nullptr;
+
+ return WrapAsyncGeneratorWithProto(cx, unwrapped, proto);
+}
+
+bool
+js::IsWrappedAsyncGenerator(JSFunction* fun)
+{
+ return fun->maybeNative() == WrappedAsyncGenerator;
+}
+
+JSFunction*
+js::GetWrappedAsyncGenerator(JSFunction* unwrapped)
+{
+ MOZ_ASSERT(unwrapped->isAsync());
+ return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
+}
+
+JSFunction*
+js::GetUnwrappedAsyncGenerator(JSFunction* wrapped)
+{
+ MOZ_ASSERT(IsWrappedAsyncGenerator(wrapped));
+ JSFunction* unwrapped = &wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT)
+ .toObject().as<JSFunction>();
+ MOZ_ASSERT(unwrapped->isAsync());
+ return unwrapped;
+}
+
+// Async Iteration proposal 4.1.1 Await Fulfilled Functions.
+MOZ_MUST_USE bool
+js::AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value)
+{
+ return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Normal, value);
+}
+
+// Async Iteration proposal 4.1.2 Await Rejected Functions.
+MOZ_MUST_USE bool
+js::AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue reason)
+{
+ return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
+}
+
+// Async Iteration proposal 11.4.3.7 step 8.d-e.
+MOZ_MUST_USE bool
+js::AsyncGeneratorYieldReturnAwaitedFulfilled(JSContext* cx,
+ Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value)
+{
+ return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Return, value);
+}
+
+// Async Iteration proposal 11.4.3.7 step 8.d-e.
+MOZ_MUST_USE bool
+js::AsyncGeneratorYieldReturnAwaitedRejected(JSContext* cx,
+ Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue reason)
+{
+ return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
+}
+
+const Class AsyncFromSyncIteratorObject::class_ = {
+ "AsyncFromSyncIteratorObject",
+ JSCLASS_HAS_RESERVED_SLOTS(AsyncFromSyncIteratorObject::Slots)
+};
+
+// Async Iteration proposal 11.1.3.1.
+JSObject*
+js::CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter)
+{
+ // Step 1 (implicit).
+ // Done in bytecode emitted by emitAsyncIterator.
+
+ // Steps 2-4.
+ return AsyncFromSyncIteratorObject::create(cx, iter);
+}
+
+// Async Iteration proposal 11.1.3.1 steps 2-4.
+/* static */ JSObject*
+AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter)
+{
+ // Step 2.
+ RootedObject proto(cx, GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(cx,
+ cx->global()));
+ if (!proto)
+ return nullptr;
+
+ RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, proto));
+ if (!obj)
+ return nullptr;
+
+ Handle<AsyncFromSyncIteratorObject*> asyncIter = obj.as<AsyncFromSyncIteratorObject>();
+
+ // Step 3.
+ asyncIter->setIterator(iter);
+
+ // Step 4.
+ return asyncIter;
+}
+
+// Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
+static bool
+AsyncFromSyncIteratorNext(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Normal);
+}
+
+// Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return.
+static bool
+AsyncFromSyncIteratorReturn(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Return);
+}
+
+// Async Iteration proposal 11.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw.
+static bool
+AsyncFromSyncIteratorThrow(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Throw);
+}
+
+// Async Iteration proposal 11.4.1.2 AsyncGenerator.prototype.next.
+static bool
+AsyncGeneratorNext(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Steps 1-3.
+ return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Normal, args.get(0),
+ args.rval());
+}
+
+// Async Iteration proposal 11.4.1.3 AsyncGenerator.prototype.return.
+static bool
+AsyncGeneratorReturn(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Steps 1-3.
+ return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Return, args.get(0),
+ args.rval());
+}
+
+// Async Iteration proposal 11.4.1.4 AsyncGenerator.prototype.throw.
+static bool
+AsyncGeneratorThrow(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Steps 1-3.
+ return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Throw, args.get(0),
+ args.rval());
+}
+
+const Class AsyncGeneratorObject::class_ = {
+ "AsyncGenerator",
+ JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorObject::Slots)
+};
+
+// ES 2017 draft 9.1.13.
+template <typename ProtoGetter>
+static JSObject*
+OrdinaryCreateFromConstructor(JSContext* cx, HandleFunction fun,
+ ProtoGetter protoGetter, const Class* clasp)
+{
+ // Step 1 (skipped).
+
+ // Step 2.
+ RootedValue protoVal(cx);
+ if (!GetProperty(cx, fun, fun, cx->names().prototype, &protoVal))
+ return nullptr;
+
+ RootedObject proto(cx, protoVal.isObject() ? &protoVal.toObject() : nullptr);
+ if (!proto) {
+ proto = protoGetter(cx, cx->global());
+ if (!proto)
+ return nullptr;
+ }
+
+ // Step 3.
+ return NewNativeObjectWithGivenProto(cx, clasp, proto);
+}
+
+/* static */ AsyncGeneratorObject*
+AsyncGeneratorObject::create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal)
+{
+ MOZ_ASSERT(generatorVal.isObject());
+ MOZ_ASSERT(generatorVal.toObject().is<GeneratorObject>());
+
+ RootedObject obj(
+ cx, OrdinaryCreateFromConstructor(cx, asyncGen,
+ GlobalObject::getOrCreateAsyncGeneratorPrototype,
+ &class_));
+ if (!obj)
+ return nullptr;
+
+ Handle<AsyncGeneratorObject*> asyncGenObj = obj.as<AsyncGeneratorObject>();
+
+ // Async Iteration proposal 6.4.3.2 AsyncGeneratorStart.
+ // Step 6.
+ asyncGenObj->setGenerator(generatorVal);
+
+ // Step 7.
+ asyncGenObj->setSuspendedStart();
+
+ // Step 8.
+ asyncGenObj->clearSingleQueueRequest();
+
+ return asyncGenObj;
+}
+
+static MOZ_MUST_USE bool
+InternalEnqueue(JSContext* cx, HandleArrayObject queue, HandleValue val)
+{
+ uint32_t length;
+ if (!GetLengthProperty(cx, queue, &length))
+ return false;
+
+ if (length >= MAX_ARRAY_INDEX) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ if (!DefineElement(cx, queue, length, val))
+ return false;
+ return SetLengthProperty(cx, queue, length + 1);
+}
+
+static MOZ_MUST_USE bool
+InternalDequeue(JSContext* cx, HandleArrayObject queue, MutableHandleValue val)
+{
+ uint32_t length;
+ if (!GetLengthProperty(cx, queue, &length))
+ return false;
+
+ MOZ_ASSERT(length != 0, "Queue should not be empty here");
+
+ if (!GetElement(cx, queue, queue, 0, val))
+ return false;
+
+ uint32_t newlength = length - 1;
+ RootedValue tmp(cx);
+ for (uint32_t i = 0; i < newlength; i++) {
+ if (!GetElement(cx, queue, queue, i + 1, &tmp))
+ return false;
+ if (!DefineElement(cx, queue, i, tmp))
+ return false;
+ }
+ ObjectOpResult result;
+ if (!DeleteElement(cx, queue, newlength, result))
+ return false;
+ if (!result) {
+ RootedId id(cx, INT_TO_JSID(newlength));
+ return result.reportError(cx, queue, id);
+ }
+ return SetLengthProperty(cx, queue, newlength);
+}
+
+/* static */ MOZ_MUST_USE bool
+AsyncGeneratorObject::enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ Handle<AsyncGeneratorRequest*> request)
+{
+ if (asyncGenObj->isSingleQueue()) {
+ if (asyncGenObj->isSingleQueueEmpty()) {
+ asyncGenObj->setSingleQueueRequest(request);
+ return true;
+ }
+
+ RootedArrayObject queue(cx, NewDenseEmptyArray(cx));
+ if (!queue)
+ return false;
+
+ if (!NewbornArrayPush(cx, queue, ObjectValue(*asyncGenObj->singleQueueRequest())))
+ return false;
+ if (!NewbornArrayPush(cx, queue, ObjectValue(*request)))
+ return false;
+
+ asyncGenObj->setQueue(queue);
+ return true;
+ }
+
+ RootedArrayObject queue(cx, asyncGenObj->queue());
+ RootedValue requestVal(cx, ObjectValue(*request));
+ return InternalEnqueue(cx, queue, requestVal);
+}
+
+/* static */ AsyncGeneratorRequest*
+AsyncGeneratorObject::dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+{
+ if (asyncGenObj->isSingleQueue()) {
+ AsyncGeneratorRequest* request = asyncGenObj->singleQueueRequest();
+ asyncGenObj->clearSingleQueueRequest();
+ return request;
+ }
+
+ RootedArrayObject queue(cx, asyncGenObj->queue());
+ RootedValue requestVal(cx);
+ if (!InternalDequeue(cx, queue, &requestVal))
+ return nullptr;
+
+ return &requestVal.toObject().as<AsyncGeneratorRequest>();
+}
+
+/* static */ AsyncGeneratorRequest*
+AsyncGeneratorObject::peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+{
+ if (asyncGenObj->isSingleQueue())
+ return asyncGenObj->singleQueueRequest();
+
+ RootedArrayObject queue(cx, asyncGenObj->queue());
+
+ RootedValue requestVal(cx);
+ if (!GetElement(cx, queue, queue, 0, &requestVal))
+ return nullptr;
+
+ return &requestVal.toObject().as<AsyncGeneratorRequest>();
+}
+
+const Class AsyncGeneratorRequest::class_ = {
+ "AsyncGeneratorRequest",
+ JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots)
+};
+
+// Async Iteration proposal 11.4.3.1.
+/* static */ AsyncGeneratorRequest*
+AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind_,
+ HandleValue completionValue_, HandleObject promise_)
+{
+ RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
+ if (!obj)
+ return nullptr;
+
+ Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
+ request->setCompletionKind(completionKind_);
+ request->setCompletionValue(completionValue_);
+ request->setPromise(promise_);
+ return request;
+}
+
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart steps 5.d-g.
+static MOZ_MUST_USE bool
+AsyncGeneratorReturned(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value)
+{
+ // Step 5.d.
+ asyncGenObj->setCompleted();
+
+ // Step 5.e (done in bytecode).
+ // Step 5.f.i (implicit).
+
+ // Step 5.g.
+ return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
+}
+
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart steps 5.d, f.
+static MOZ_MUST_USE bool
+AsyncGeneratorThrown(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+{
+ // Step 5.d.
+ asyncGenObj->setCompleted();
+
+ // Not much we can do about uncatchable exceptions, so just bail.
+ if (!cx->isExceptionPending())
+ return false;
+
+ // Step 5.f.i.
+ RootedValue value(cx);
+ if (!GetAndClearException(cx, &value))
+ return false;
+
+ // Step 5.f.ii.
+ return AsyncGeneratorReject(cx, asyncGenObj, value);
+}
+
+// Async Iteration proposal 11.4.3.7 (partially).
+// Most steps are done in generator.
+static MOZ_MUST_USE bool
+AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value)
+{
+ // Step 5 is done in bytecode.
+
+ // Step 6.
+ asyncGenObj->setSuspendedYield();
+
+ // Step 9.
+ return AsyncGeneratorResolve(cx, asyncGenObj, value, false);
+}
+
+// Async Iteration proposal 4.1 Await steps 2-9.
+// Async Iteration proposal 8.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart step 5.f-g.
+// Async Iteration proposal 11.4.3.5 AsyncGeneratorResumeNext
+// steps 12-14, 16-20.
+// Execution context switching is handled in generator.
+MOZ_MUST_USE bool
+js::AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ CompletionKind completionKind, HandleValue argument)
+{
+ RootedValue generatorVal(cx, asyncGenObj->generatorVal());
+
+ // 11.4.3.5 steps 12-14, 16-20.
+ HandlePropertyName funName = completionKind == CompletionKind::Normal
+ ? cx->names().StarGeneratorNext
+ : completionKind == CompletionKind::Throw
+ ? cx->names().StarGeneratorThrow
+ : cx->names().StarGeneratorReturn;
+ FixedInvokeArgs<1> args(cx);
+ args[0].set(argument);
+ RootedValue result(cx);
+ if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result)) {
+ // 11.4.3.2 step 5.d, f.
+ return AsyncGeneratorThrown(cx, asyncGenObj);
+ }
+
+ // 4.1 steps 2-9.
+ if (asyncGenObj->generatorObj()->isAfterAwait())
+ return AsyncGeneratorAwait(cx, asyncGenObj, result);
+
+ // The following code corresponds to the following 3 cases:
+ // * yield
+ // * yield*
+ // * return
+ // For yield and return, property access is done on an internal result
+ // object and it's not observable.
+ // For yield*, it's done on a possibly user-provided result object, and
+ // it's observable.
+ //
+ // Note that IteratorComplete steps in 8.2.1 are done in bytecode.
+
+ // 8.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
+ RootedObject resultObj(cx, &result.toObject());
+ RootedValue value(cx);
+
+ if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
+ return false;
+
+ if (asyncGenObj->generatorObj()->isAfterYield())
+ return AsyncGeneratorYield(cx, asyncGenObj, value);
+
+ // 11.4.3.2 step 5.d-g.
+ return AsyncGeneratorReturned(cx, asyncGenObj, value);
+}
+
+static const JSFunctionSpec async_iterator_proto_methods[] = {
+ JS_SELF_HOSTED_SYM_FN(asyncIterator, "AsyncIteratorIdentity", 0, 0),
+ JS_FS_END
+};
+
+static const JSFunctionSpec async_from_sync_iter_methods[] = {
+ JS_FN("next", AsyncFromSyncIteratorNext, 1, 0),
+ JS_FN("throw", AsyncFromSyncIteratorThrow, 1, 0),
+ JS_FN("return", AsyncFromSyncIteratorReturn, 1, 0),
+ JS_FS_END
+};
+
+static const JSFunctionSpec async_generator_methods[] = {
+ JS_FN("next", AsyncGeneratorNext, 1, 0),
+ JS_FN("throw", AsyncGeneratorThrow, 1, 0),
+ JS_FN("return", AsyncGeneratorReturn, 1, 0),
+ JS_FS_END
+};
+
+/* static */ MOZ_MUST_USE bool
+GlobalObject::initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global)
+{
+ if (global->getReservedSlot(ASYNC_ITERATOR_PROTO).isObject())
+ return true;
+
+ // Async Iteration proposal 11.1.2 %AsyncIteratorPrototype%.
+ RootedObject asyncIterProto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
+ if (!asyncIterProto)
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr, async_iterator_proto_methods))
+ return false;
+
+ // Async Iteration proposal 11.1.3.2 %AsyncFromSyncIteratorPrototype%.
+ RootedObject asyncFromSyncIterProto(
+ cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
+ asyncIterProto));
+ if (!asyncFromSyncIterProto)
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, asyncFromSyncIterProto, nullptr,
+ async_from_sync_iter_methods) ||
+ !DefineToStringTag(cx, asyncFromSyncIterProto, cx->names().AsyncFromSyncIterator))
+ {
+ return false;
+ }
+
+ // Async Iteration proposal 11.4.1 %AsyncGeneratorPrototype%.
+ RootedObject asyncGenProto(
+ cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
+ asyncIterProto));
+ if (!asyncGenProto)
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr, async_generator_methods) ||
+ !DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator))
+ {
+ return false;
+ }
+
+ // Async Iteration proposal 11.3.3 %AsyncGenerator%.
+ RootedObject asyncGenerator(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
+ if (!asyncGenerator)
+ return false;
+ if (!JSObject::setDelegate(cx, asyncGenerator))
+ return false;
+ if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto, JSPROP_READONLY,
+ JSPROP_READONLY) ||
+ !DefineToStringTag(cx, asyncGenerator, cx->names().AsyncGeneratorFunction))
+ {
+ return false;
+ }
+
+ RootedValue function(cx, global->getConstructor(JSProto_Function));
+ if (!function.toObjectOrNull())
+ return false;
+ RootedObject proto(cx, &function.toObject());
+ RootedAtom name(cx, cx->names().AsyncGeneratorFunction);
+
+ // Async Iteration proposal 11.3.2 %AsyncGeneratorFunction%.
+ RootedObject asyncGenFunction(
+ cx, NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1, JSFunction::NATIVE_CTOR,
+ nullptr, name, proto, gc::AllocKind::FUNCTION, SingletonObject));
+ if (!asyncGenFunction)
+ return false;
+ if (!LinkConstructorAndPrototype(cx, asyncGenFunction, asyncGenerator,
+ JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ global->setReservedSlot(ASYNC_ITERATOR_PROTO, ObjectValue(*asyncIterProto));
+ global->setReservedSlot(ASYNC_FROM_SYNC_ITERATOR_PROTO, ObjectValue(*asyncFromSyncIterProto));
+ global->setReservedSlot(ASYNC_GENERATOR, ObjectValue(*asyncGenerator));
+ global->setReservedSlot(ASYNC_GENERATOR_FUNCTION, ObjectValue(*asyncGenFunction));
+ global->setReservedSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*asyncGenProto));
+ return true;
+}
diff --git a/js/src/vm/AsyncIteration.h b/js/src/vm/AsyncIteration.h
new file mode 100644
index 000000000..58c43131b
--- /dev/null
+++ b/js/src/vm/AsyncIteration.h
@@ -0,0 +1,256 @@
+/* -*- 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_AsyncIteration_h
+#define vm_AsyncIteration_h
+
+#include "jscntxt.h"
+#include "jsobj.h"
+
+#include "builtin/Promise.h"
+#include "vm/GeneratorObject.h"
+
+namespace js {
+
+// Async generator consists of 2 functions, |wrapped| and |unwrapped|.
+// |unwrapped| is a generator function compiled from async generator script,
+// |await| behaves just like |yield| there. |unwrapped| isn't exposed to user
+// script.
+// |wrapped| is a native function that is the value of async generator.
+
+JSObject*
+WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto);
+
+JSObject*
+WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped);
+
+bool
+IsWrappedAsyncGenerator(JSFunction* fun);
+
+JSFunction*
+GetWrappedAsyncGenerator(JSFunction* unwrapped);
+
+JSFunction*
+GetUnwrappedAsyncGenerator(JSFunction* wrapped);
+
+MOZ_MUST_USE bool
+AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value);
+MOZ_MUST_USE bool
+AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue reason);
+MOZ_MUST_USE bool
+AsyncGeneratorYieldReturnAwaitedFulfilled(JSContext* cx,
+ Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value);
+MOZ_MUST_USE bool
+AsyncGeneratorYieldReturnAwaitedRejected(JSContext* cx,
+ Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue reason);
+
+class AsyncGeneratorRequest : public NativeObject
+{
+ private:
+ enum AsyncGeneratorRequestSlots {
+ Slot_CompletionKind = 0,
+ Slot_CompletionValue,
+ Slot_Promise,
+ Slots,
+ };
+
+ void setCompletionKind(CompletionKind completionKind_) {
+ setFixedSlot(Slot_CompletionKind,
+ Int32Value(static_cast<int32_t>(completionKind_)));
+ }
+ void setCompletionValue(HandleValue completionValue_) {
+ setFixedSlot(Slot_CompletionValue, completionValue_);
+ }
+ void setPromise(HandleObject promise_) {
+ setFixedSlot(Slot_Promise, ObjectValue(*promise_));
+ }
+
+ public:
+ static const Class class_;
+
+ static AsyncGeneratorRequest*
+ create(JSContext* cx, CompletionKind completionKind, HandleValue completionValue,
+ HandleObject promise);
+
+ CompletionKind completionKind() const {
+ return static_cast<CompletionKind>(getFixedSlot(Slot_CompletionKind).toInt32());
+ }
+ JS::Value completionValue() const {
+ return getFixedSlot(Slot_CompletionValue);
+ }
+ JSObject* promise() const {
+ return &getFixedSlot(Slot_Promise).toObject();
+ }
+};
+
+class AsyncGeneratorObject : public NativeObject
+{
+ private:
+ enum AsyncGeneratorObjectSlots {
+ Slot_State = 0,
+ Slot_Generator,
+ Slot_QueueOrRequest,
+ Slots
+ };
+
+ enum State {
+ State_SuspendedStart,
+ State_SuspendedYield,
+ State_Executing,
+ // State_AwaitingYieldReturn corresponds to the case that
+ // AsyncGenerator#return is called while State_Executing,
+ // just like the case that AsyncGenerator#return is called
+ // while State_Completed.
+ State_AwaitingYieldReturn,
+ State_AwaitingReturn,
+ State_Completed
+ };
+
+ State state() const {
+ return static_cast<State>(getFixedSlot(Slot_State).toInt32());
+ }
+ void setState(State state_) {
+ setFixedSlot(Slot_State, Int32Value(state_));
+ }
+
+ void setGenerator(const Value& value) {
+ setFixedSlot(Slot_Generator, value);
+ }
+
+ // Queue is implemented in 2 ways. If only one request is queued ever,
+ // request is stored directly to the slot. Once 2 requests are queued, an
+ // array is created and requests are pushed into it, and the array is
+ // stored to the slot.
+
+ bool isSingleQueue() const {
+ return getFixedSlot(Slot_QueueOrRequest).isNull() ||
+ getFixedSlot(Slot_QueueOrRequest).toObject().is<AsyncGeneratorRequest>();
+ }
+ bool isSingleQueueEmpty() const {
+ return getFixedSlot(Slot_QueueOrRequest).isNull();
+ }
+ void setSingleQueueRequest(AsyncGeneratorRequest* request) {
+ setFixedSlot(Slot_QueueOrRequest, ObjectValue(*request));
+ }
+ void clearSingleQueueRequest() {
+ setFixedSlot(Slot_QueueOrRequest, NullHandleValue);
+ }
+ AsyncGeneratorRequest* singleQueueRequest() const {
+ return &getFixedSlot(Slot_QueueOrRequest).toObject().as<AsyncGeneratorRequest>();
+ }
+
+ ArrayObject* queue() const {
+ return &getFixedSlot(Slot_QueueOrRequest).toObject().as<ArrayObject>();
+ }
+ void setQueue(JSObject* queue_) {
+ setFixedSlot(Slot_QueueOrRequest, ObjectValue(*queue_));
+ }
+
+ public:
+ static const Class class_;
+
+ static AsyncGeneratorObject*
+ create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal);
+
+ bool isSuspendedStart() const {
+ return state() == State_SuspendedStart;
+ }
+ bool isSuspendedYield() const {
+ return state() == State_SuspendedYield;
+ }
+ bool isExecuting() const {
+ return state() == State_Executing;
+ }
+ bool isAwaitingYieldReturn() const {
+ return state() == State_AwaitingYieldReturn;
+ }
+ bool isAwaitingReturn() const {
+ return state() == State_AwaitingReturn;
+ }
+ bool isCompleted() const {
+ return state() == State_Completed;
+ }
+
+ void setSuspendedStart() {
+ setState(State_SuspendedStart);
+ }
+ void setSuspendedYield() {
+ setState(State_SuspendedYield);
+ }
+ void setExecuting() {
+ setState(State_Executing);
+ }
+ void setAwaitingYieldReturn() {
+ setState(State_AwaitingYieldReturn);
+ }
+ void setAwaitingReturn() {
+ setState(State_AwaitingReturn);
+ }
+ void setCompleted() {
+ setState(State_Completed);
+ }
+
+ JS::Value generatorVal() const {
+ return getFixedSlot(Slot_Generator);
+ }
+ GeneratorObject* generatorObj() const {
+ return &getFixedSlot(Slot_Generator).toObject().as<GeneratorObject>();
+ }
+
+ static MOZ_MUST_USE bool
+ enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ Handle<AsyncGeneratorRequest*> request);
+
+ static AsyncGeneratorRequest*
+ dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
+
+ static AsyncGeneratorRequest*
+ peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
+
+ bool isQueueEmpty() const {
+ if (isSingleQueue())
+ return isSingleQueueEmpty();
+ return queue()->length() == 0;
+ }
+};
+
+JSObject*
+CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter);
+
+class AsyncFromSyncIteratorObject : public NativeObject
+{
+ private:
+ enum AsyncFromSyncIteratorObjectSlots {
+ Slot_Iterator = 0,
+ Slots
+ };
+
+ void setIterator(HandleObject iterator_) {
+ setFixedSlot(Slot_Iterator, ObjectValue(*iterator_));
+ }
+
+ public:
+ static const Class class_;
+
+ static JSObject*
+ create(JSContext* cx, HandleObject iter);
+
+ JSObject* iterator() const {
+ return &getFixedSlot(Slot_Iterator).toObject();
+ }
+};
+
+MOZ_MUST_USE bool
+AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ CompletionKind completionKind, HandleValue argument);
+
+} // namespace js
+
+#endif /* vm_AsyncIteration_h */
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
index fd1c9f5e6..6a8afb56b 100644
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -29,7 +29,10 @@
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
macro(as, as, "as") \
macro(Async, Async, "Async") \
+ macro(AsyncFromSyncIterator, AsyncFromSyncIterator, "Async-from-Sync Iterator") \
macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
+ macro(AsyncGenerator, AsyncGenerator, "AsyncGenerator") \
+ macro(AsyncGeneratorFunction, AsyncGeneratorFunction, "AsyncGeneratorFunction") \
macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
macro(async, async, "async") \
macro(await, await, "await") \
@@ -97,6 +100,7 @@
macro(displayURL, displayURL, "displayURL") \
macro(do, do_, "do") \
macro(done, done, "done") \
+ macro(dotall, dotall, "dotall") \
macro(dotGenerator, dotGenerator, ".generator") \
macro(dotThis, dotThis, ".this") \
macro(each, each, "each") \
@@ -281,6 +285,7 @@
macro(RegExpFlagsGetter, RegExpFlagsGetter, "RegExpFlagsGetter") \
macro(RegExpMatcher, RegExpMatcher, "RegExpMatcher") \
macro(RegExpSearcher, RegExpSearcher, "RegExpSearcher") \
+ macro(RegExpStringIterator, RegExpStringIterator, "RegExp String Iterator") \
macro(RegExpTester, RegExpTester, "RegExpTester") \
macro(RegExp_prototype_Exec, RegExp_prototype_Exec, "RegExp_prototype_Exec") \
macro(Reify, Reify, "Reify") \
@@ -309,6 +314,7 @@
macro(star, star, "*") \
macro(starDefaultStar, starDefaultStar, "*default*") \
macro(StarGeneratorNext, StarGeneratorNext, "StarGeneratorNext") \
+ macro(StarGeneratorReturn, StarGeneratorReturn, "StarGeneratorReturn") \
macro(StarGeneratorThrow, StarGeneratorThrow, "StarGeneratorThrow") \
macro(startTimestamp, startTimestamp, "startTimestamp") \
macro(state, state, "state") \
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
index d68d1b75e..c49df5aa9 100644
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -32,7 +32,6 @@
#include "js/Vector.h"
#include "proxy/ScriptedProxyHandler.h"
#include "vm/ArgumentsObject.h"
-#include "vm/AsyncFunction.h"
#include "vm/DebuggerMemory.h"
#include "vm/GeneratorObject.h"
#include "vm/SPSProfiler.h"
@@ -1560,16 +1559,11 @@ CheckResumptionValue(JSContext* cx, AbstractFramePtr frame, const Maybe<HandleVa
JSTrapStatus status, MutableHandleValue vp)
{
if (status == JSTRAP_RETURN && frame && frame.isFunctionFrame()) {
- // Don't let a { return: ... } resumption value make a generator or
- // async function violate the iterator protocol. The return value from
+ // Don't let a { return: ... } resumption value make a generator
+ // function violate the iterator protocol. The return value from
// such a frame must have the form { done: <bool>, value: <anything> }.
RootedFunction callee(cx, frame.callee());
- if (callee->isAsync()) {
- if (!CheckAsyncResumptionValue(cx, vp)) {
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_AWAIT);
- return false;
- }
- } else if (callee->isStarGenerator()) {
+ if (callee->isStarGenerator()) {
if (!CheckStarGeneratorResumptionValue(cx, vp)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_YIELD);
return false;
@@ -7356,7 +7350,8 @@ DebuggerFrame::getEnvironment(JSContext* cx, HandleDebuggerFrame frame,
/* static */ bool
DebuggerFrame::getIsGenerator(HandleDebuggerFrame frame)
{
- return DebuggerFrame::getReferent(frame).script()->isGenerator();
+ return DebuggerFrame::getReferent(frame).script()->isStarGenerator() ||
+ DebuggerFrame::getReferent(frame).script()->isLegacyGenerator();
}
/* static */ bool
@@ -8733,7 +8728,6 @@ DebuggerObject::proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp)
return true;
}
-#ifdef SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::isPromiseGetter(JSContext* cx, unsigned argc, Value* vp)
{
@@ -8902,7 +8896,6 @@ DebuggerObject::promiseDependentPromisesGetter(JSContext* cx, unsigned argc, Val
args.rval().setObject(*promises);
return true;
}
-#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp)
@@ -9341,7 +9334,6 @@ const JSPropertySpec DebuggerObject::properties_[] = {
JS_PS_END
};
-#ifdef SPIDERMONKEY_PROMISE
const JSPropertySpec DebuggerObject::promiseProperties_[] = {
JS_PSG("isPromise", DebuggerObject::isPromiseGetter, 0),
JS_PSG("promiseState", DebuggerObject::promiseStateGetter, 0),
@@ -9355,7 +9347,6 @@ const JSPropertySpec DebuggerObject::promiseProperties_[] = {
JS_PSG("promiseDependentPromises", DebuggerObject::promiseDependentPromisesGetter, 0),
JS_PS_END
};
-#endif // SPIDERMONKEY_PROMISE
const JSFunctionSpec DebuggerObject::methods_[] = {
JS_FN("isExtensible", DebuggerObject::isExtensibleMethod, 0, 0),
@@ -9395,10 +9386,8 @@ DebuggerObject::initClass(JSContext* cx, HandleObject obj, HandleObject debugCto
if (!objectProto)
return nullptr;
-#ifdef SPIDERMONKEY_PROMISE
if (!DefinePropertiesAndFunctions(cx, objectProto, promiseProperties_, nullptr))
return nullptr;
-#endif // SPIDERMONKEY_PROMISE
return objectProto;
}
@@ -9466,7 +9455,6 @@ DebuggerObject::isScriptedProxy() const
return js::IsScriptedProxy(referent());
}
-#ifdef SPIDERMONKEY_PROMISE
bool
DebuggerObject::isPromise() const
{
@@ -9480,7 +9468,6 @@ DebuggerObject::isPromise() const
return referent->is<PromiseObject>();
}
-#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::getClassName(JSContext* cx, HandleDebuggerObject object,
@@ -9763,7 +9750,6 @@ DebuggerObject::getErrorColumnNumber(JSContext* cx, HandleDebuggerObject object,
return true;
}
-#ifdef SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::getPromiseValue(JSContext* cx, HandleDebuggerObject object,
MutableHandleValue result)
@@ -9783,7 +9769,6 @@ DebuggerObject::getPromiseReason(JSContext* cx, HandleDebuggerObject object,
result.set(object->promise()->reason());
return object->owner()->wrapDebuggeeValue(cx, result);
}
-#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::isExtensible(JSContext* cx, HandleDebuggerObject object, bool& result)
@@ -10253,7 +10238,6 @@ DebuggerObject::requireGlobal(JSContext* cx, HandleDebuggerObject object)
return true;
}
-#ifdef SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::requirePromise(JSContext* cx, HandleDebuggerObject object)
{
@@ -10275,7 +10259,6 @@ DebuggerObject::requirePromise(JSContext* cx, HandleDebuggerObject object)
return true;
}
-#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h
index cdcf2d67f..204d1ca3e 100644
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -1256,12 +1256,10 @@ class DebuggerObject : public NativeObject
MutableHandleDebuggerObject result);
static MOZ_MUST_USE bool getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result);
-#ifdef SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool getPromiseValue(JSContext* cx, HandleDebuggerObject object,
MutableHandleValue result);
static MOZ_MUST_USE bool getPromiseReason(JSContext* cx, HandleDebuggerObject object,
MutableHandleValue result);
-#endif // SPIDERMONKEY_PROMISE
// Methods
static MOZ_MUST_USE bool isExtensible(JSContext* cx, HandleDebuggerObject object,
@@ -1311,16 +1309,12 @@ class DebuggerObject : public NativeObject
bool isArrowFunction() const;
bool isGlobal() const;
bool isScriptedProxy() const;
-#ifdef SPIDERMONKEY_PROMISE
bool isPromise() const;
-#endif // SPIDERMONKEY_PROMISE
JSAtom* name() const;
JSAtom* displayName() const;
-#ifdef SPIDERMONKEY_PROMISE
JS::PromiseState promiseState() const;
double promiseLifetime() const;
double promiseTimeToResolution() const;
-#endif // SPIDERMONKEY_PROMISE
private:
enum {
@@ -1332,9 +1326,7 @@ class DebuggerObject : public NativeObject
static const ClassOps classOps_;
static const JSPropertySpec properties_[];
-#ifdef SPIDERMONKEY_PROMISE
static const JSPropertySpec promiseProperties_[];
-#endif // SPIDERMONKEY_PROMISE
static const JSFunctionSpec methods_[];
JSObject* referent() const {
@@ -1345,14 +1337,10 @@ class DebuggerObject : public NativeObject
Debugger* owner() const;
-#ifdef SPIDERMONKEY_PROMISE
PromiseObject* promise() const;
-#endif // SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool requireGlobal(JSContext* cx, HandleDebuggerObject object);
-#ifdef SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool requirePromise(JSContext* cx, HandleDebuggerObject object);
-#endif // SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
@@ -1379,7 +1367,6 @@ class DebuggerObject : public NativeObject
static MOZ_MUST_USE bool isProxyGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool proxyTargetGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp);
-#ifdef SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool isPromiseGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool promiseStateGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool promiseValueGetter(JSContext* cx, unsigned argc, Value* vp);
@@ -1390,7 +1377,6 @@ class DebuggerObject : public NativeObject
static MOZ_MUST_USE bool promiseResolutionSiteGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool promiseIDGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool promiseDependentPromisesGetter(JSContext* cx, unsigned argc, Value* vp);
-#endif // SPIDERMONKEY_PROMISE
// JSNative methods
static MOZ_MUST_USE bool isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp);
diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp
index a5aac2ab4..7834940f1 100644
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -408,7 +408,6 @@ const ObjectOps ModuleEnvironmentObject::objectOps_ = {
ModuleEnvironmentObject::setProperty,
ModuleEnvironmentObject::getOwnPropertyDescriptor,
ModuleEnvironmentObject::deleteProperty,
- nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
ModuleEnvironmentObject::enumerate,
nullptr
@@ -491,7 +490,7 @@ ModuleEnvironmentObject::createImportBinding(JSContext* cx, HandleAtom importNam
{
RootedId importNameId(cx, AtomToId(importName));
RootedId localNameId(cx, AtomToId(localName));
- RootedModuleEnvironmentObject env(cx, module->environment());
+ RootedModuleEnvironmentObject env(cx, &module->initialEnvironment());
if (!importBindings().putNew(cx, importNameId, env, localNameId)) {
ReportOutOfMemory(cx);
return false;
@@ -790,7 +789,6 @@ static const ObjectOps WithEnvironmentObjectOps = {
with_SetProperty,
with_GetOwnPropertyDescriptor,
with_DeleteProperty,
- nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
nullptr, /* enumerate (native enumeration of target doesn't work) */
nullptr,
@@ -1159,7 +1157,6 @@ static const ObjectOps RuntimeLexicalErrorObjectObjectOps = {
lexicalError_SetProperty,
lexicalError_GetOwnPropertyDescriptor,
lexicalError_DeleteProperty,
- nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
nullptr, /* enumerate (native enumeration of target doesn't work) */
nullptr, /* this */
@@ -2451,7 +2448,9 @@ DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
// Generators should always have environments.
MOZ_ASSERT_IF(ei.scope().is<FunctionScope>(),
- !ei.scope().as<FunctionScope>().canonicalFunction()->isGenerator());
+ !ei.scope().as<FunctionScope>().canonicalFunction()->isStarGenerator() &&
+ !ei.scope().as<FunctionScope>().canonicalFunction()->isLegacyGenerator() &&
+ !ei.scope().as<FunctionScope>().canonicalFunction()->isAsync());
if (!CanUseDebugEnvironmentMaps(cx))
return true;
@@ -2597,8 +2596,11 @@ DebugEnvironments::onPopCall(JSContext* cx, AbstractFramePtr frame)
if (!frame.environmentChain()->is<CallObject>())
return;
- if (frame.callee()->isGenerator())
+ if (frame.callee()->isStarGenerator() || frame.callee()->isLegacyGenerator() ||
+ frame.callee()->isAsync())
+ {
return;
+ }
CallObject& callobj = frame.environmentChain()->as<CallObject>();
envs->liveEnvs.remove(&callobj);
@@ -2729,8 +2731,13 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
if (frame.environmentChain()->compartment() != cx->compartment())
continue;
- if (frame.isFunctionFrame() && frame.callee()->isGenerator())
- continue;
+ if (frame.isFunctionFrame()) {
+ if (frame.callee()->isStarGenerator() || frame.callee()->isLegacyGenerator() ||
+ frame.callee()->isAsync())
+ {
+ continue;
+ }
+ }
if (!frame.isDebuggee())
continue;
@@ -2885,7 +2892,8 @@ GetDebugEnvironmentForMissing(JSContext* cx, const EnvironmentIter& ei)
if (ei.scope().is<FunctionScope>()) {
RootedFunction callee(cx, ei.scope().as<FunctionScope>().canonicalFunction());
// Generators should always reify their scopes.
- MOZ_ASSERT(!callee->isGenerator());
+ MOZ_ASSERT(!callee->isStarGenerator() && !callee->isLegacyGenerator() &&
+ !callee->isAsync());
JS::ExposeObjectToActiveJS(callee);
Rooted<CallObject*> callobj(cx, CallObject::createHollowForDebug(cx, callee));
diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp
index ba28501e6..2f5c63c28 100644
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -19,12 +19,13 @@ using namespace js;
JSObject*
GeneratorObject::create(JSContext* cx, AbstractFramePtr frame)
{
- MOZ_ASSERT(frame.script()->isGenerator());
+ MOZ_ASSERT(frame.script()->isStarGenerator() || frame.script()->isLegacyGenerator() ||
+ frame.script()->isAsync());
MOZ_ASSERT(frame.script()->nfixed() == 0);
Rooted<GlobalObject*> global(cx, cx->global());
RootedNativeObject obj(cx);
- if (frame.script()->isStarGenerator()) {
+ if (frame.script()->isStarGenerator() || frame.script()->isAsync()) {
RootedValue pval(cx);
RootedObject fun(cx, frame.callee());
// FIXME: This would be faster if we could avoid doing a lookup to get
@@ -63,10 +64,14 @@ bool
GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
Value* vp, unsigned nvalues)
{
- MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
+ MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
MOZ_ASSERT(!genObj->hasExpressionStack());
+ MOZ_ASSERT_IF(*pc == JSOP_AWAIT, genObj->callee().isAsync());
+ MOZ_ASSERT_IF(*pc == JSOP_YIELD,
+ genObj->callee().isStarGenerator() ||
+ genObj->callee().isLegacyGenerator());
if (*pc == JSOP_YIELD && genObj->isClosing() && genObj->is<LegacyGeneratorObject>()) {
RootedValue val(cx, ObjectValue(*frame.callee()));
@@ -74,8 +79,8 @@ GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame
return false;
}
- uint32_t yieldIndex = GET_UINT24(pc);
- genObj->setYieldIndex(yieldIndex);
+ uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
+ genObj->setYieldAndAwaitIndex(yieldAndAwaitIndex);
genObj->setEnvironmentChain(*frame.environmentChain());
if (nvalues) {
@@ -172,7 +177,7 @@ GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
}
JSScript* script = callee->nonLazyScript();
- uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
+ uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
activation.regs().pc = script->offsetToPC(offset);
// Always push on a value, even if we are raising an exception. In the
@@ -311,7 +316,8 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
if (!genFunctionProto || !JSObject::setDelegate(cx, genFunctionProto))
return false;
- if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto) ||
+ if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto, JSPROP_READONLY,
+ JSPROP_READONLY) ||
!DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction))
{
return false;
@@ -328,8 +334,11 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
SingletonObject));
if (!genFunction)
return false;
- if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
+ if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto,
+ JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
+ {
return false;
+ }
global->setReservedSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
global->setReservedSlot(STAR_GENERATOR_FUNCTION, ObjectValue(*genFunction));
@@ -365,3 +374,34 @@ js::CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v)
return true;
}
+
+bool
+GeneratorObject::isAfterYield()
+{
+ return isAfterYieldOrAwait(JSOP_YIELD);
+}
+
+bool
+GeneratorObject::isAfterAwait()
+{
+ return isAfterYieldOrAwait(JSOP_AWAIT);
+}
+
+bool
+GeneratorObject::isAfterYieldOrAwait(JSOp op)
+{
+ if (isClosed() || isClosing() || isRunning())
+ return false;
+
+ JSScript* script = callee().nonLazyScript();
+ jsbytecode* code = script->code();
+ uint32_t nextOffset = script->yieldAndAwaitOffsets()[yieldAndAwaitIndex()];
+ if (code[nextOffset] != JSOP_DEBUGAFTERYIELD)
+ return false;
+
+ uint32_t offset = nextOffset - JSOP_YIELD_LENGTH;
+ MOZ_ASSERT(code[offset] == JSOP_INITIALYIELD || code[offset] == JSOP_YIELD ||
+ code[offset] == JSOP_AWAIT);
+
+ return code[offset] == op;
+}
diff --git a/js/src/vm/GeneratorObject.h b/js/src/vm/GeneratorObject.h
index ca1452b34..f19ca2aac 100644
--- a/js/src/vm/GeneratorObject.h
+++ b/js/src/vm/GeneratorObject.h
@@ -21,15 +21,15 @@ class GeneratorObject : public NativeObject
public:
// Magic values stored in the yield index slot when the generator is
// running or closing. See the yield index comment below.
- static const int32_t YIELD_INDEX_RUNNING = INT32_MAX;
- static const int32_t YIELD_INDEX_CLOSING = INT32_MAX - 1;
+ static const int32_t YIELD_AND_AWAIT_INDEX_RUNNING = INT32_MAX;
+ static const int32_t YIELD_AND_AWAIT_INDEX_CLOSING = INT32_MAX - 1;
enum {
CALLEE_SLOT = 0,
ENV_CHAIN_SLOT,
ARGS_OBJ_SLOT,
EXPRESSION_STACK_SLOT,
- YIELD_INDEX_SLOT,
+ YIELD_AND_AWAIT_INDEX_SLOT,
NEWTARGET_SLOT,
RESERVED_SLOTS
};
@@ -124,47 +124,48 @@ class GeneratorObject : public NativeObject
// The yield index slot is abused for a few purposes. It's undefined if
// it hasn't been set yet (before the initial yield), and null if the
// generator is closed. If the generator is running, the yield index is
- // YIELD_INDEX_RUNNING. If the generator is in that bizarre "closing"
- // state, the yield index is YIELD_INDEX_CLOSING.
+ // YIELD_AND_AWAIT_INDEX_RUNNING. If the generator is in that bizarre
+ // "closing" state, the yield index is YIELD_AND_AWAIT_INDEX_CLOSING.
//
// If the generator is suspended, it's the yield index (stored as
- // JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction that
- // suspended the generator. The yield index can be mapped to the bytecode
- // offset (interpreter) or to the native code offset (JIT).
+ // JSOP_INITIALYIELD/JSOP_YIELD/JSOP_AWAIT operand) of the yield
+ // instruction that suspended the generator. The yield index can be mapped
+ // to the bytecode offset (interpreter) or to the native code offset (JIT).
bool isRunning() const {
MOZ_ASSERT(!isClosed());
- return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_RUNNING;
+ return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_RUNNING;
}
bool isClosing() const {
- return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_CLOSING;
+ return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_CLOSING;
}
bool isSuspended() const {
// Note: also update Baseline's IsSuspendedStarGenerator code if this
// changes.
MOZ_ASSERT(!isClosed());
- static_assert(YIELD_INDEX_CLOSING < YIELD_INDEX_RUNNING,
- "test below should return false for YIELD_INDEX_RUNNING");
- return getFixedSlot(YIELD_INDEX_SLOT).toInt32() < YIELD_INDEX_CLOSING;
+ static_assert(YIELD_AND_AWAIT_INDEX_CLOSING < YIELD_AND_AWAIT_INDEX_RUNNING,
+ "test below should return false for YIELD_AND_AWAIT_INDEX_RUNNING");
+ return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() < YIELD_AND_AWAIT_INDEX_CLOSING;
}
void setRunning() {
MOZ_ASSERT(isSuspended());
- setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_RUNNING));
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_RUNNING));
}
void setClosing() {
MOZ_ASSERT(isSuspended());
- setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_CLOSING));
- }
- void setYieldIndex(uint32_t yieldIndex) {
- MOZ_ASSERT_IF(yieldIndex == 0, getFixedSlot(YIELD_INDEX_SLOT).isUndefined());
- MOZ_ASSERT_IF(yieldIndex != 0, isRunning() || isClosing());
- MOZ_ASSERT(yieldIndex < uint32_t(YIELD_INDEX_CLOSING));
- setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex));
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_CLOSING));
+ }
+ void setYieldAndAwaitIndex(uint32_t yieldAndAwaitIndex) {
+ MOZ_ASSERT_IF(yieldAndAwaitIndex == 0,
+ getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).isUndefined());
+ MOZ_ASSERT_IF(yieldAndAwaitIndex != 0, isRunning() || isClosing());
+ MOZ_ASSERT(yieldAndAwaitIndex < uint32_t(YIELD_AND_AWAIT_INDEX_CLOSING));
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(yieldAndAwaitIndex));
MOZ_ASSERT(isSuspended());
}
- uint32_t yieldIndex() const {
+ uint32_t yieldAndAwaitIndex() const {
MOZ_ASSERT(isSuspended());
- return getFixedSlot(YIELD_INDEX_SLOT).toInt32();
+ return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32();
}
bool isClosed() const {
return getFixedSlot(CALLEE_SLOT).isNull();
@@ -174,10 +175,17 @@ class GeneratorObject : public NativeObject
setFixedSlot(ENV_CHAIN_SLOT, NullValue());
setFixedSlot(ARGS_OBJ_SLOT, NullValue());
setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
- setFixedSlot(YIELD_INDEX_SLOT, NullValue());
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, NullValue());
setFixedSlot(NEWTARGET_SLOT, NullValue());
}
+ bool isAfterYield();
+ bool isAfterAwait();
+
+private:
+ bool isAfterYieldOrAwait(JSOp op);
+
+public:
static size_t offsetOfCalleeSlot() {
return getFixedSlotOffset(CALLEE_SLOT);
}
@@ -187,8 +195,8 @@ class GeneratorObject : public NativeObject
static size_t offsetOfArgsObjSlot() {
return getFixedSlotOffset(ARGS_OBJ_SLOT);
}
- static size_t offsetOfYieldIndexSlot() {
- return getFixedSlotOffset(YIELD_INDEX_SLOT);
+ static size_t offsetOfYieldAndAwaitIndexSlot() {
+ return getFixedSlotOffset(YIELD_AND_AWAIT_INDEX_SLOT);
}
static size_t offsetOfExpressionStackSlot() {
return getFixedSlotOffset(EXPRESSION_STACK_SLOT);
diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp
index 85707e1c6..a8d401af4 100644
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -21,9 +21,7 @@
#include "builtin/MapObject.h"
#include "builtin/ModuleObject.h"
#include "builtin/Object.h"
-#ifdef SPIDERMONKEY_PROMISE
#include "builtin/Promise.h"
-#endif
#include "builtin/RegExp.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/SymbolObject.h"
@@ -468,62 +466,29 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> globa
return false;
}
- RootedValue std_isConcatSpreadable(cx);
- std_isConcatSpreadable.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::isConcatSpreadable));
- if (!JS_DefineProperty(cx, global, "std_isConcatSpreadable", std_isConcatSpreadable,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- // Define a top-level property 'std_iterator' with the name of the method
- // used by for-of loops to create an iterator.
- RootedValue std_iterator(cx);
- std_iterator.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::iterator));
- if (!JS_DefineProperty(cx, global, "std_iterator", std_iterator,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_match(cx);
- std_match.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::match));
- if (!JS_DefineProperty(cx, global, "std_match", std_match,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_replace(cx);
- std_replace.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::replace));
- if (!JS_DefineProperty(cx, global, "std_replace", std_replace,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_search(cx);
- std_search.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::search));
- if (!JS_DefineProperty(cx, global, "std_search", std_search,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_species(cx);
- std_species.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::species));
- if (!JS_DefineProperty(cx, global, "std_species", std_species,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_split(cx);
- std_split.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::split));
- if (!JS_DefineProperty(cx, global, "std_split", std_split,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
+ struct SymbolAndName {
+ JS::SymbolCode code;
+ const char* name;
+ };
+
+ SymbolAndName wellKnownSymbols[] = {
+ {JS::SymbolCode::isConcatSpreadable, "std_isConcatSpreadable"},
+ {JS::SymbolCode::iterator, "std_iterator"},
+ {JS::SymbolCode::match, "std_match"},
+ {JS::SymbolCode::matchAll, "std_matchAll"},
+ {JS::SymbolCode::replace, "std_replace"},
+ {JS::SymbolCode::search, "std_search"},
+ {JS::SymbolCode::species, "std_species"},
+ {JS::SymbolCode::split, "std_split"},
+ };
+
+ RootedValue symVal(cx);
+ for (const auto& sym : wellKnownSymbols) {
+ symVal.setSymbol(cx->wellKnownSymbols().get(sym.code));
+ if (!JS_DefineProperty(cx, global, sym.name, symVal,
+ JSPROP_PERMANENT | JSPROP_READONLY)) {
+ return false;
+ }
}
return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
@@ -619,17 +584,18 @@ GlobalObject::createBlankPrototypeInheriting(JSContext* cx, Handle<GlobalObject*
}
bool
-js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_)
+js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_,
+ unsigned prototypeAttrs, unsigned constructorAttrs)
{
RootedObject ctor(cx, ctor_), proto(cx, proto_);
RootedValue protoVal(cx, ObjectValue(*proto));
RootedValue ctorVal(cx, ObjectValue(*ctor));
- return DefineProperty(cx, ctor, cx->names().prototype, protoVal,
- nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY) &&
- DefineProperty(cx, proto, cx->names().constructor, ctorVal,
- nullptr, nullptr, 0);
+ return DefineProperty(cx, ctor, cx->names().prototype, protoVal, nullptr, nullptr,
+ prototypeAttrs) &&
+ DefineProperty(cx, proto, cx->names().constructor, ctorVal, nullptr, nullptr,
+ constructorAttrs);
}
bool
diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h
index 5aacfc5dc..3fd2762f8 100644
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -93,12 +93,18 @@ class GlobalObject : public NativeObject
ITERATOR_PROTO,
ARRAY_ITERATOR_PROTO,
STRING_ITERATOR_PROTO,
+ REGEXP_STRING_ITERATOR_PROTO,
LEGACY_GENERATOR_OBJECT_PROTO,
STAR_GENERATOR_OBJECT_PROTO,
STAR_GENERATOR_FUNCTION_PROTO,
STAR_GENERATOR_FUNCTION,
ASYNC_FUNCTION_PROTO,
ASYNC_FUNCTION,
+ ASYNC_ITERATOR_PROTO,
+ ASYNC_FROM_SYNC_ITERATOR_PROTO,
+ ASYNC_GENERATOR,
+ ASYNC_GENERATOR_FUNCTION,
+ ASYNC_GENERATOR_PROTO,
MAP_ITERATOR_PROTO,
SET_ITERATOR_PROTO,
COLLATOR_PROTO,
@@ -583,6 +589,12 @@ class GlobalObject : public NativeObject
}
static NativeObject*
+ getOrCreateRegExpStringIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ return MaybeNativeObject(getOrCreateObject(cx, global, REGEXP_STRING_ITERATOR_PROTO,
+ initRegExpStringIteratorProto));
+ }
+
+ static NativeObject*
getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx, Handle<GlobalObject*> global) {
return MaybeNativeObject(getOrCreateObject(cx, global, LEGACY_GENERATOR_OBJECT_PROTO,
initLegacyGeneratorProto));
@@ -617,6 +629,36 @@ class GlobalObject : public NativeObject
return getOrCreateObject(cx, global, ASYNC_FUNCTION, initAsyncFunction);
}
+ static NativeObject*
+ getOrCreateAsyncIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_ITERATOR_PROTO,
+ initAsyncGenerators));
+ }
+
+ static NativeObject*
+ getOrCreateAsyncFromSyncIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_FROM_SYNC_ITERATOR_PROTO,
+ initAsyncGenerators));
+ }
+
+ static NativeObject*
+ getOrCreateAsyncGenerator(JSContext* cx, Handle<GlobalObject*> global) {
+ return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_GENERATOR,
+ initAsyncGenerators));
+ }
+
+ static JSObject*
+ getOrCreateAsyncGeneratorFunction(JSContext* cx, Handle<GlobalObject*> global) {
+ return getOrCreateObject(cx, global, ASYNC_GENERATOR_FUNCTION, initAsyncGenerators);
+ }
+
+ static NativeObject*
+ getOrCreateAsyncGeneratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_GENERATOR_PROTO,
+ initAsyncGenerators));
+ }
+
static JSObject*
getOrCreateMapIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
return getOrCreateObject(cx, global, MAP_ITERATOR_PROTO, initMapIteratorProto);
@@ -767,6 +809,7 @@ class GlobalObject : public NativeObject
static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initArrayIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initRegExpStringIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
// Implemented in vm/GeneratorObject.cpp.
static bool initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> global);
@@ -774,6 +817,8 @@ class GlobalObject : public NativeObject
static bool initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initAsyncGenerators(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);
@@ -977,12 +1022,14 @@ GlobalObject::createArrayFromBuffer<uint8_clamped>() const
}
/*
- * Define ctor.prototype = proto as non-enumerable, non-configurable, and
- * non-writable; define proto.constructor = ctor as non-enumerable but
- * configurable and writable.
+ * Unless otherwise specified, define ctor.prototype = proto as non-enumerable,
+ * non-configurable, and non-writable; and define proto.constructor = ctor as
+ * non-enumerable but configurable and writable.
*/
extern bool
-LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor, JSObject* proto);
+LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor, JSObject* proto,
+ unsigned prototypeAttrs = JSPROP_PERMANENT | JSPROP_READONLY,
+ unsigned constructorAttrs = 0);
/*
* Define properties and/or functions on any object. Either ps or fs, or both,
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index 030f0f3b6..3cf9b57f6 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -39,6 +39,7 @@
#include "jit/Ion.h"
#include "jit/IonAnalysis.h"
#include "vm/AsyncFunction.h"
+#include "vm/AsyncIteration.h"
#include "vm/Debugger.h"
#include "vm/GeneratorObject.h"
#include "vm/Opcodes.h"
@@ -1939,9 +1940,6 @@ CASE(EnableInterruptsPseudoOpcode)
CASE(JSOP_NOP)
CASE(JSOP_NOP_DESTRUCTURING)
CASE(JSOP_UNUSED126)
-CASE(JSOP_UNUSED192)
-CASE(JSOP_UNUSED209)
-CASE(JSOP_UNUSED210)
CASE(JSOP_UNUSED211)
CASE(JSOP_TRY_DESTRUCTURING_ITERCLOSE)
CASE(JSOP_UNUSED221)
@@ -3585,6 +3583,29 @@ CASE(JSOP_TOASYNC)
}
END_CASE(JSOP_TOASYNC)
+CASE(JSOP_TOASYNCGEN)
+{
+ ReservedRooted<JSFunction*> unwrapped(&rootFunction0,
+ &REGS.sp[-1].toObject().as<JSFunction>());
+ JSObject* wrapped = WrapAsyncGenerator(cx, unwrapped);
+ if (!wrapped)
+ goto error;
+
+ REGS.sp[-1].setObject(*wrapped);
+}
+END_CASE(JSOP_TOASYNCGEN)
+
+CASE(JSOP_TOASYNCITER)
+{
+ ReservedRooted<JSObject*> iter(&rootObject1, &REGS.sp[-1].toObject());
+ JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter);
+ if (!asyncIter)
+ goto error;
+
+ REGS.sp[-1].setObject(*asyncIter);
+}
+END_CASE(JSOP_TOASYNCITER)
+
CASE(JSOP_SETFUNNAME)
{
MOZ_ASSERT(REGS.stackDepth() >= 2);
@@ -3994,6 +4015,7 @@ CASE(JSOP_INITIALYIELD)
}
CASE(JSOP_YIELD)
+CASE(JSOP_AWAIT)
{
MOZ_ASSERT(!cx->isExceptionPending());
MOZ_ASSERT(REGS.fp()->isFunctionFrame());
@@ -5126,6 +5148,10 @@ js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind)
case CheckIsObjectKind::GetIterator:
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_GET_ITER_RETURNED_PRIMITIVE);
break;
+ case CheckIsObjectKind::GetAsyncIterator:
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
+ break;
default:
MOZ_CRASH("Unknown kind");
}
diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h
index 9fefd75cc..5e7087f7f 100644
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -561,7 +561,8 @@ enum class CheckIsObjectKind : uint8_t {
IteratorNext,
IteratorReturn,
IteratorThrow,
- GetIterator
+ GetIterator,
+ GetAsyncIterator
};
bool
diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
index e55e3db04..030d92c12 100644
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -158,11 +158,11 @@ NativeObject::extendDenseElements(ExclusiveContext* cx,
MOZ_ASSERT(!denseElementsAreFrozen());
/*
- * Don't grow elements for non-extensible objects or watched objects. Dense
- * elements can be added/written with no extensible or watchpoint checks as
- * long as there is capacity for them.
+ * Don't grow elements for non-extensible objects. Dense elements can be
+ * added/written with no extensible checks as long as there is capacity
+ * for them.
*/
- if (!nonProxyIsExtensible() || watched()) {
+ if (!nonProxyIsExtensible()) {
MOZ_ASSERT(getDenseCapacity() == 0);
return DenseElementResult::Incomplete;
}
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
index da0f59fe2..d801fad06 100644
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -9,8 +9,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
-#include "jswatchpoint.h"
-
#include "gc/Marking.h"
#include "js/Value.h"
#include "vm/Debugger.h"
@@ -602,7 +600,7 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO
return DenseElementResult::Incomplete;
/* Watch for conditions under which an object's elements cannot be dense. */
- if (!obj->nonProxyIsExtensible() || obj->watched())
+ if (!obj->nonProxyIsExtensible())
return DenseElementResult::Incomplete;
/*
@@ -2410,17 +2408,9 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa
}
bool
-js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue value,
+js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
HandleValue receiver, QualifiedBool qualified, ObjectOpResult& result)
{
- // Fire watchpoints, if any.
- RootedValue v(cx, value);
- if (MOZ_UNLIKELY(obj->watched())) {
- WatchpointMap* wpmap = cx->compartment()->watchpointMap;
- if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &v))
- return false;
- }
-
// Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
// method for ordinary objects. We substitute our own names for these names
// used in the spec: O -> pobj, P -> id, ownDesc -> shape.
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
index ec0a7aec1..91070b3f6 100644
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -184,7 +184,7 @@ ObjectGroup::useSingletonForNewObject(JSContext* cx, JSScript* script, jsbytecod
* Sub2 lets us continue to distinguish the two subclasses and any extra
* properties added to those prototype objects.
*/
- if (script->isGenerator())
+ if (script->isStarGenerator() || script->isLegacyGenerator() || script->isAsync())
return false;
if (JSOp(*pc) != JSOP_NEW)
return false;
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
index 3c4d61a67..e13cd6221 100644
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1952,7 +1952,15 @@
* Stack: this => this
*/ \
macro(JSOP_CHECKTHISREINIT,191,"checkthisreinit",NULL,1, 1, 1, JOF_BYTE) \
- macro(JSOP_UNUSED192, 192,"unused192", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Pops the top of stack value as 'unwrapped', converts it to async
+ * generator 'wrapped', and pushes 'wrapped' back on the stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: unwrapped => wrapped
+ */ \
+ macro(JSOP_TOASYNCGEN, 192, "toasyncgen", NULL, 1, 1, 1, JOF_BYTE) \
\
/*
* Pops the top two values on the stack as 'propval' and 'obj', pushes
@@ -2055,7 +2063,7 @@
* interpretation.
* Category: Statements
* Type: Generator
- * Operands: uint24_t yieldIndex
+ * Operands: uint24_t yieldAndAwaitIndex
* Stack: generator =>
*/ \
macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 4, 1, 1, JOF_UINT24) \
@@ -2064,7 +2072,7 @@
* returns 'rval1'. Pushes sent value from 'send()' onto the stack.
* Category: Statements
* Type: Generator
- * Operands: uint24_t yieldIndex
+ * Operands: uint24_t yieldAndAwaitIndex
* Stack: rval1, gen => rval2
*/ \
macro(JSOP_YIELD, 203,"yield", NULL, 4, 2, 1, JOF_UINT24) \
@@ -2119,8 +2127,24 @@
* Stack: =>
*/ \
macro(JSOP_DEBUGAFTERYIELD, 208, "debugafteryield", NULL, 1, 0, 0, JOF_BYTE) \
- macro(JSOP_UNUSED209, 209, "unused209", NULL, 1, 0, 0, JOF_BYTE) \
- macro(JSOP_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Pops the generator and the return value 'promise', stops interpretation
+ * and returns 'promise'. Pushes resolved value onto the stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint24_t yieldAndAwaitIndex
+ * Stack: promise, gen => resolved
+ */ \
+ macro(JSOP_AWAIT, 209, "await", NULL, 4, 2, 1, JOF_UINT24) \
+ /*
+ * Pops the iterator from the top of the stack, and create async iterator
+ * from it and push the async iterator back onto the stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: iter => asynciter
+ */ \
+ macro(JSOP_TOASYNCITER, 210, "toasynciter", NULL, 1, 1, 1, JOF_BYTE) \
macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \
/*
* Initializes generator frame, creates a generator and pushes it on the
diff --git a/js/src/vm/Probes-inl.h b/js/src/vm/Probes-inl.h
index 347f842b8..822a8ac59 100644
--- a/js/src/vm/Probes-inl.h
+++ b/js/src/vm/Probes-inl.h
@@ -41,7 +41,10 @@ probes::EnterScript(JSContext* cx, JSScript* script, JSFunction* maybeFun,
if (rt->spsProfiler.enabled()) {
if (!rt->spsProfiler.enter(cx, script, maybeFun))
return false;
- MOZ_ASSERT_IF(!fp->script()->isGenerator(), !fp->hasPushedSPSFrame());
+ MOZ_ASSERT_IF(!fp->script()->isStarGenerator() &&
+ !fp->script()->isLegacyGenerator() &&
+ !fp->script()->isAsync(),
+ !fp->hasPushedSPSFrame());
fp->setPushedSPSFrame();
}
diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp
index ef97ed816..cd0b54c9d 100644
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -49,6 +49,7 @@ JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
JS_STATIC_ASSERT(UnicodeFlag == JSREG_UNICODE);
+JS_STATIC_ASSERT(DotAllFlag == JSREG_DOTALL);
RegExpObject*
js::RegExpAlloc(ExclusiveContext* cx, HandleObject proto /* = nullptr */)
@@ -267,7 +268,7 @@ RegExpObject::create(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags,
tokenStream = dummyTokenStream.ptr();
}
- if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source, flags & UnicodeFlag))
+ if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source, flags & UnicodeFlag, flags & DotAllFlag))
return nullptr;
Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx));
@@ -1017,7 +1018,7 @@ RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString inpu
irregexp::RegExpCompileData data;
if (!irregexp::ParsePattern(dummyTokenStream, cx->tempLifoAlloc(), pattern,
multiline(), mode == MatchOnly, unicode(), ignoreCase(),
- global(), sticky(), &data))
+ global(), sticky(), dotall(), &data))
{
return false;
}
diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h
index f1ea101ed..95c64fa67 100644
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -53,16 +53,18 @@ enum RegExpFlag
MultilineFlag = 0x04,
StickyFlag = 0x08,
UnicodeFlag = 0x10,
+ DotAllFlag = 0x20,
NoFlags = 0x00,
- AllFlags = 0x1f
+ AllFlags = 0x3f
};
static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
GlobalFlag == REGEXP_GLOBAL_FLAG &&
MultilineFlag == REGEXP_MULTILINE_FLAG &&
StickyFlag == REGEXP_STICKY_FLAG &&
- UnicodeFlag == REGEXP_UNICODE_FLAG,
+ UnicodeFlag == REGEXP_UNICODE_FLAG &&
+ DotAllFlag == REGEXP_DOTALL_FLAG,
"Flag values should be in sync with self-hosted JS");
enum RegExpRunStatus
@@ -193,6 +195,7 @@ class RegExpShared
bool multiline() const { return flags & MultilineFlag; }
bool sticky() const { return flags & StickyFlag; }
bool unicode() const { return flags & UnicodeFlag; }
+ bool dotall() const { return flags & DotAllFlag; }
bool isCompiled(CompilationMode mode, bool latin1,
ForceByteCodeEnum force = DontForceByteCode) const {
@@ -480,6 +483,7 @@ class RegExpObject : public NativeObject
bool multiline() const { return getFlags() & MultilineFlag; }
bool sticky() const { return getFlags() & StickyFlag; }
bool unicode() const { return getFlags() & UnicodeFlag; }
+ bool dotall() const { return getFlags() & DotAllFlag; }
static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
index 5fc8e0e17..284a4f3d7 100644
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -34,7 +34,6 @@
#include "jsnativestack.h"
#include "jsobj.h"
#include "jsscript.h"
-#include "jswatchpoint.h"
#include "jswin.h"
#include "jswrapper.h"
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index 792a00490..2216bf91e 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -27,6 +27,7 @@
#include "builtin/MapObject.h"
#include "builtin/ModuleObject.h"
#include "builtin/Object.h"
+#include "builtin/Promise.h"
#include "builtin/Reflect.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/SIMD.h"
@@ -857,33 +858,20 @@ intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp)
}
static bool
-intrinsic_NewListIterator(JSContext* cx, unsigned argc, Value* vp)
+intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0);
- RootedObject proto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, cx->global()));
+ RootedObject proto(cx, GlobalObject::getOrCreateRegExpStringIteratorPrototype(cx, cx->global()));
if (!proto)
return false;
- RootedObject iterator(cx);
- iterator = NewObjectWithGivenProto(cx, &ListIteratorObject::class_, proto);
- if (!iterator)
+ JSObject* obj = NewObjectWithGivenProto(cx, &RegExpStringIteratorObject::class_, proto);
+ if (!obj)
return false;
- args.rval().setObject(*iterator);
- return true;
-}
-
-static bool
-intrinsic_ActiveFunction(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- MOZ_ASSERT(args.length() == 0);
-
- ScriptFrameIter iter(cx);
- MOZ_ASSERT(iter.isFunctionFrame());
- args.rval().setObject(*iter.callee(cx));
+ args.rval().setObject(*obj);
return true;
}
@@ -2133,6 +2121,120 @@ intrinsic_ModuleNamespaceExports(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+static bool
+intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+
+ RootedObject constructor(cx, &args[0].toObject());
+ JSObject* promise = js::PromiseResolve(cx, constructor, args[1]);
+ if (!promise)
+ return false;
+
+ args.rval().setObject(*promise);
+ return true;
+}
+
+static bool
+intrinsic_CreatePendingPromise(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+ RootedObject promise(cx, PromiseObject::createSkippingExecutor(cx));
+ if (!promise)
+ return false;
+ args.rval().setObject(*promise);
+ return true;
+}
+
+static bool
+intrinsic_CreatePromiseResolvedWith(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, args[0]));
+ if (!promise)
+ return false;
+ args.rval().setObject(*promise);
+ return true;
+}
+
+static bool
+intrinsic_CreatePromiseRejectedWith(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedObject promise(cx, PromiseObject::unforgeableReject(cx, args[0]));
+ if (!promise)
+ return false;
+ args.rval().setObject(*promise);
+ return true;
+}
+
+static bool
+intrinsic_ResolvePromise(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
+ if (!PromiseObject::resolve(cx, promise, args[1]))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_RejectPromise(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
+ if (!PromiseObject::reject(cx, promise, args[1]))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_CallOriginalPromiseThen(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() >= 2);
+
+ RootedObject promise(cx, &args[0].toObject());
+ Value val = args[1];
+ RootedObject onResolvedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
+ val = args.get(2);
+ RootedObject onRejectedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
+
+ RootedObject resultPromise(cx, JS::CallOriginalPromiseThen(cx, promise, onResolvedObj,
+ onRejectedObj));
+ if (!resultPromise)
+ return false;
+ args.rval().setObject(*resultPromise);
+ return true;
+}
+
+static bool
+intrinsic_AddPromiseReactions(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() >= 2);
+
+ RootedObject promise(cx, &args[0].toObject());
+ Value val = args[1];
+ RootedObject onResolvedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
+ val = args.get(2);
+ RootedObject onRejectedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
+
+ bool result = JS::AddPromiseReactions(cx, promise, onResolvedObj, onRejectedObj);
+ if (!result)
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
// The self-hosting global isn't initialized with the normal set of builtins.
// Instead, individual C++-implemented functions that're required by
// self-hosted code are defined as global functions. Accessing these
@@ -2290,11 +2392,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("CallArrayIteratorMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2,0),
- JS_FN("NewListIterator", intrinsic_NewListIterator, 0,0),
- JS_FN("CallListIteratorMethodIfWrapped",
- CallNonGenericSelfhostedMethod<Is<ListIteratorObject>>, 2,0),
- JS_FN("ActiveFunction", intrinsic_ActiveFunction, 0,0),
-
JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0),
JS_INLINABLE_FN("GuardToArrayIterator",
@@ -2309,9 +2406,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_INLINABLE_FN("GuardToStringIterator",
intrinsic_GuardToBuiltin<StringIteratorObject>, 1,0,
IntrinsicGuardToStringIterator),
- JS_INLINABLE_FN("IsListIterator",
- intrinsic_IsInstanceOfBuiltin<ListIteratorObject>, 1,0,
- IntrinsicIsListIterator),
+ JS_FN("GuardToRegExpStringIterator",
+ intrinsic_GuardToBuiltin<RegExpStringIteratorObject>, 1,0),
JS_FN("_CreateMapIterationResultPair", intrinsic_CreateMapIterationResultPair, 0, 0),
JS_INLINABLE_FN("_GetNextMapEntryForIterator", intrinsic_GetNextMapEntryForIterator, 2,0,
@@ -2329,6 +2425,9 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("NewStringIterator", intrinsic_NewStringIterator, 0,0),
JS_FN("CallStringIteratorMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2,0),
+ JS_FN("NewRegExpStringIterator", intrinsic_NewRegExpStringIterator, 0,0),
+ JS_FN("CallRegExpStringIteratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<RegExpStringIteratorObject>>, 2,0),
JS_FN("IsStarGeneratorObject",
intrinsic_IsInstanceOfBuiltin<StarGeneratorObject>, 1,0),
@@ -2533,11 +2632,22 @@ static const JSFunctionSpec intrinsic_functions[] = {
intrinsic_InstantiateModuleFunctionDeclarations, 1, 0),
JS_FN("SetModuleState", intrinsic_SetModuleState, 1, 0),
JS_FN("EvaluateModule", intrinsic_EvaluateModule, 1, 0),
- JS_FN("IsModuleNamespace", intrinsic_IsInstanceOfBuiltin<ModuleNamespaceObject>, 1, 0),
JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0),
JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
+ JS_FN("CreatePendingPromise", intrinsic_CreatePendingPromise, 0, 0),
+ JS_FN("CreatePromiseResolvedWith", intrinsic_CreatePromiseResolvedWith, 1, 0),
+ JS_FN("CreatePromiseRejectedWith", intrinsic_CreatePromiseRejectedWith, 1, 0),
+ JS_FN("ResolvePromise", intrinsic_ResolvePromise, 2, 0),
+ JS_FN("RejectPromise", intrinsic_RejectPromise, 2, 0),
+ JS_FN("AddPromiseReactions", intrinsic_AddPromiseReactions, 3, 0),
+ JS_FN("CallOriginalPromiseThen", intrinsic_CallOriginalPromiseThen, 3, 0),
+
+ JS_FN("IsPromiseObject", intrinsic_IsInstanceOfBuiltin<PromiseObject>, 1, 0),
+ JS_FN("CallPromiseMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<PromiseObject>>, 2, 0),
+ JS_FN("PromiseResolve", intrinsic_PromiseResolve, 2, 0),
+
JS_FS_END
};
@@ -3003,7 +3113,8 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
return false;
// JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
// aren't any.
- MOZ_ASSERT(!sourceFun->isGenerator());
+ MOZ_ASSERT(!sourceFun->isStarGenerator() && !sourceFun->isLegacyGenerator() &&
+ !sourceFun->isAsync());
MOZ_ASSERT(targetFun->isExtended());
MOZ_ASSERT(targetFun->isInterpretedLazy());
MOZ_ASSERT(targetFun->isSelfHostedBuiltin());
diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
index fd6d843e0..85bc044a5 100644
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -387,7 +387,7 @@ class BaseShape : public gc::TenuredCell
INDEXED = 0x20,
/* (0x40 is unused) */
HAD_ELEMENTS_ACCESS = 0x80,
- WATCHED = 0x100,
+ /* (0x100 is unused) */
ITERATED_SINGLETON = 0x200,
NEW_GROUP_UNKNOWN = 0x400,
UNCACHEABLE_PROTO = 0x800,
diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h
index 11a19d175..2f2b591e5 100644
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -335,7 +335,7 @@ InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
HandleFunction callee, HandleValue newTarget,
HandleObject envChain)
{
- MOZ_ASSERT(callee->isGenerator());
+ MOZ_ASSERT(callee->isStarGenerator() || callee->isLegacyGenerator() || callee->isAsync());
RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee));
InterpreterFrame* prev = regs.fp();
jsbytecode* prevpc = regs.pc;
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index c5f2cf5f3..95940eeaf 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -270,7 +270,9 @@ InterpreterFrame::epilogue(JSContext* cx, jsbytecode* pc)
UnwindAllEnvironmentsInFrame(cx, ei);
if (isFunctionFrame()) {
- if (!callee().isGenerator() &&
+ if (!callee().isStarGenerator() &&
+ !callee().isLegacyGenerator() &&
+ !callee().isAsync() &&
isConstructing() &&
thisArgument().isObject() &&
returnValue().isPrimitive())
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
index 23e621344..fe04a00f2 100644
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -693,7 +693,8 @@ class InterpreterFrame
}
void resumeGeneratorFrame(JSObject* envChain) {
- MOZ_ASSERT(script()->isGenerator());
+ MOZ_ASSERT(script()->isStarGenerator() || script()->isLegacyGenerator() ||
+ script()->isAsync());
MOZ_ASSERT(isFunctionFrame());
flags_ |= HAS_INITIAL_ENV;
envChain_ = envChain;
diff --git a/js/src/vm/Time.cpp b/js/src/vm/Time.cpp
index 87531c148..a9a5b7f0f 100644
--- a/js/src/vm/Time.cpp
+++ b/js/src/vm/Time.cpp
@@ -11,6 +11,10 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
+#ifdef XP_SOLARIS
+#define _REENTRANT 1
+#endif
+
#include <string.h>
#include <time.h>
@@ -30,6 +34,10 @@
#ifdef XP_UNIX
+#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
+extern int gettimeofday(struct timeval* tv);
+#endif
+
#include <sys/time.h>
#endif /* XP_UNIX */
@@ -42,7 +50,11 @@ PRMJ_Now()
{
struct timeval tv;
+#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
+ gettimeofday(&tv);
+#else
gettimeofday(&tv, 0);
+#endif /* _SVID_GETTOD */
return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec);
}
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 7c2c0194e..2b1fa0e3b 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2670,14 +2670,6 @@ ObjectGroup::updateNewPropertyTypes(ExclusiveContext* cx, JSObject* objArg, jsid
if (shape)
UpdatePropertyType(cx, types, obj, shape, false);
}
-
- if (obj->watched()) {
- /*
- * Mark the property as non-data, to inhibit optimizations on it
- * and avoid bypassing the watchpoint handler.
- */
- types->setNonDataProperty(cx);
- }
}
void
@@ -3084,29 +3076,39 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
};
bool
-js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id)
+js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx,
+ DPAConstraintInfo& constraintInfo,
+ ObjectGroup* group,
+ HandleId id,
+ bool* added)
{
/*
* Ensure that if the properties named here could have a getter, setter or
* a permanent property in any transitive prototype, the definite
* properties get cleared from the group.
*/
+
+ *added = false;
+
RootedObject proto(cx, group->proto().toObjectOrNull());
while (proto) {
ObjectGroup* protoGroup = JSObject::getGroup(cx, proto);
if (!protoGroup) {
- cx->recoverFromOutOfMemory();
return false;
}
if (protoGroup->unknownProperties())
- return false;
+ return true;
HeapTypeSet* protoTypes = protoGroup->getProperty(cx, proto, id);
- if (!protoTypes || protoTypes->nonDataProperty() || protoTypes->nonWritableProperty())
+ if (!protoTypes)
return false;
- if (!protoTypes->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(group)))
+ if (protoTypes->nonDataProperty() || protoTypes->nonWritableProperty())
+ return true;
+ if (!constraintInfo.addProtoConstraint(proto, id))
return false;
proto = proto->staticPrototype();
}
+
+ *added = true;
return true;
}
@@ -3612,6 +3614,43 @@ struct DestroyTypeNewScript
} // namespace
+bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) {
+ for (const ProtoConstraint& constraint : protoConstraints_) {
+ ObjectGroup* protoGroup = constraint.proto->group();
+
+ // Note: we rely on the group's type information being unchanged since
+ // AddClearDefiniteGetterSetterForPrototypeChain.
+
+ bool unknownProperties = protoGroup->unknownProperties();
+ MOZ_RELEASE_ASSERT(!unknownProperties);
+
+ HeapTypeSet* protoTypes =
+ protoGroup->getProperty(cx, constraint.proto, constraint.id);
+ MOZ_RELEASE_ASSERT(protoTypes);
+
+ MOZ_ASSERT(!protoTypes->nonDataProperty());
+ MOZ_ASSERT(!protoTypes->nonWritableProperty());
+
+ if (!protoTypes->addConstraint(
+ cx,
+ cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(
+ group))) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ for (const InliningConstraint& constraint : inliningConstraints_) {
+ if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller,
+ constraint.callee)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool
TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force)
{
@@ -3715,10 +3754,17 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
return false;
Vector<Initializer> initializerVector(cx);
+
+ DPAConstraintInfo constraintInfo(cx);
RootedPlainObject templateRoot(cx, templateObject());
RootedFunction fun(cx, function());
- if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector))
+ if (!jit::AnalyzeNewScriptDefiniteProperties(cx,
+ constraintInfo,
+ fun,
+ group,
+ templateRoot,
+ &initializerVector))
return false;
if (!group->newScript())
@@ -3772,6 +3818,14 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
// The definite properties analysis found exactly the properties that
// are held in common by the preliminary objects. No further analysis
// is needed.
+
+ if (!constraintInfo.finishConstraints(cx, group)) {
+ return false;
+ }
+ if (!group->newScript()) {
+ return true;
+ }
+
group->addDefiniteProperties(cx, templateObject()->lastProperty());
destroyNewScript.group = nullptr;
@@ -3793,6 +3847,16 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
if (!initialGroup)
return false;
+ // Add the constraints. Use the initialGroup as group referenced by the
+ // constraints because that's the group that will have the TypeNewScript
+ // associated with it. See the detachNewScript and setNewScript calls below.
+ if (!constraintInfo.finishConstraints(cx, initialGroup)) {
+ return false;
+ }
+ if (!group->newScript()) {
+ return true;
+ }
+
initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty());
group->addDefiniteProperties(cx, prefixShape);
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
index 94ce7e871..fd021fc96 100644
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -789,8 +789,65 @@ class TemporaryTypeSet : public TypeSet
TypedArraySharedness* sharedness);
};
+// Stack class to record information about constraints that need to be added
+// after finishing the Definite Properties Analysis. When the analysis succeeds,
+// the |finishConstraints| method must be called to add the constraints to the
+// TypeSets.
+//
+// There are two constraint types managed here:
+//
+// 1. Proto constraints for HeapTypeSets, to guard against things like getters
+// and setters on the proto chain.
+//
+// 2. Inlining constraints for StackTypeSets, to invalidate when additional
+// functions could be called at call sites where we inlined a function.
+//
+// This class uses bare GC-thing pointers because GC is suppressed when the
+// analysis runs.
+class MOZ_RAII DPAConstraintInfo {
+ struct ProtoConstraint {
+ JSObject* proto;
+ jsid id;
+ ProtoConstraint(JSObject* proto, jsid id) : proto(proto), id(id) {}
+ };
+ struct InliningConstraint {
+ JSScript* caller;
+ JSScript* callee;
+ InliningConstraint(JSScript* caller, JSScript* callee)
+ : caller(caller), callee(callee) {}
+ };
+
+ JS::AutoCheckCannotGC nogc_;
+ Vector<ProtoConstraint, 8> protoConstraints_;
+ Vector<InliningConstraint, 4> inliningConstraints_;
+
+public:
+ explicit DPAConstraintInfo(JSContext* cx)
+ : nogc_(cx)
+ , protoConstraints_(cx)
+ , inliningConstraints_(cx)
+ {
+ }
+
+ DPAConstraintInfo(const DPAConstraintInfo&) = delete;
+ void operator=(const DPAConstraintInfo&) = delete;
+
+ MOZ_MUST_USE bool addProtoConstraint(JSObject* proto, jsid id) {
+ return protoConstraints_.emplaceBack(proto, id);
+ }
+ MOZ_MUST_USE bool addInliningConstraint(JSScript* caller, JSScript* callee) {
+ return inliningConstraints_.emplaceBack(caller, callee);
+ }
+
+ MOZ_MUST_USE bool finishConstraints(JSContext* cx, ObjectGroup* group);
+};
+
bool
-AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id);
+AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx,
+ DPAConstraintInfo& constraintInfo,
+ ObjectGroup* group,
+ HandleId id,
+ bool* added);
bool
AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,
diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
index 52b8eeed1..f3eebb85e 100644
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -8608,9 +8608,12 @@ EstablishPreconditions(ExclusiveContext* cx, AsmJSParser& parser)
break;
}
- if (parser.pc->isGenerator())
+ if (parser.pc->isStarGenerator() || parser.pc->isLegacyGenerator())
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by generator context");
+ if (parser.pc->isAsync())
+ return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by async context");
+
if (parser.pc->isArrowFunction())
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by arrow function context");
diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp
index 8d4f575b2..fd9530e20 100644
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -1640,7 +1640,6 @@ WebAssembly_toSource(JSContext* cx, unsigned argc, Value* vp)
}
#endif
-#ifdef SPIDERMONKEY_PROMISE
static bool
Nop(JSContext* cx, unsigned argc, Value* vp)
{
@@ -1914,7 +1913,6 @@ WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp)
callArgs.rval().setObject(*promise);
return true;
}
-#endif
static bool
WebAssembly_validate(JSContext* cx, unsigned argc, Value* vp)
@@ -1949,10 +1947,8 @@ static const JSFunctionSpec WebAssembly_static_methods[] =
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, WebAssembly_toSource, 0, 0),
#endif
-#ifdef SPIDERMONKEY_PROMISE
JS_FN("compile", WebAssembly_compile, 1, 0),
JS_FN("instantiate", WebAssembly_instantiate, 2, 0),
-#endif
JS_FN("validate", WebAssembly_validate, 1, 0),
JS_FS_END
};
diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp
index c4733cc96..21093ca9a 100644
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -130,11 +130,16 @@ class AutoSetHandlingSegFault
# define EPC_sig(p) ((p)->sc_pc)
# define RFP_sig(p) ((p)->sc_regs[30])
# endif
-#elif defined(__linux__)
+#elif defined(__linux__) || defined(__sun)
# if defined(__linux__)
# define XMM_sig(p,i) ((p)->uc_mcontext.fpregs->_xmm[i])
# define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP])
-# else
+# else // defined(__sun)
+/* See https://www.illumos.org/issues/5876. They keep arguing over whether
+ * <ucontext.h> should provide the register index defines in regset.h or
+ * require applications to request them specifically, and we need them here. */
+#include <ucontext.h>
+#include <sys/regset.h>
# define XMM_sig(p,i) ((p)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.xmm[i])
# define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_PC])
# endif
diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp
index a516cf73f..d6e1cb173 100644
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1206,13 +1206,6 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
if (!options.globalProperties.DefineInSandbox(cx, sandbox))
return NS_ERROR_XPC_UNEXPECTED;
-
-#ifndef SPIDERMONKEY_PROMISE
- // Promise is supposed to be part of ES, and therefore should appear on
- // every global.
- if (!dom::PromiseBinding::GetConstructorObject(cx))
- return NS_ERROR_XPC_UNEXPECTED;
-#endif // SPIDERMONKEY_PROMISE
}
// We handle the case where the context isn't in a compartment for the
diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp
index 77f09f4a5..d158cdd62 100644
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -799,7 +799,6 @@ XPCConvert::NativeInterface2JSObject(MutableHandleValue d,
return CreateHolderIfNeeded(flat, d, dest);
}
-#ifdef SPIDERMONKEY_PROMISE
if (iid->Equals(NS_GET_IID(nsISupports))) {
// Check for a Promise being returned via nsISupports. In that
// situation, we want to dig out its underlying JS object and return
@@ -812,7 +811,6 @@ XPCConvert::NativeInterface2JSObject(MutableHandleValue d,
return CreateHolderIfNeeded(flat, d, dest);
}
}
-#endif // SPIDERMONKEY_PROMISE
// Don't double wrap CPOWs. This is a temporary measure for compatibility
// with objects that don't provide necessary QIs (such as objects under
@@ -955,7 +953,6 @@ XPCConvert::JSObject2NativeInterface(void** dest, HandleObject src,
return false;
}
-#ifdef SPIDERMONKEY_PROMISE
// Deal with Promises being passed as nsISupports. In that situation we
// want to create a dom::Promise and use that.
if (iid->Equals(NS_GET_IID(nsISupports))) {
@@ -966,7 +963,6 @@ XPCConvert::JSObject2NativeInterface(void** dest, HandleObject src,
return p && NS_SUCCEEDED(p->QueryInterface(*iid, dest));
}
}
-#endif // SPIDERMONKEY_PROMISE
}
RefPtr<nsXPCWrappedJS> wrapper;
diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp
index 4ddc8deb3..abe50f449 100644
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -644,6 +644,7 @@ env_setProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
ObjectOpResult& result)
{
/* XXX porting may be easy, but these don't seem to supply setenv by default */
+#if !defined XP_SOLARIS
RootedString valstr(cx);
RootedString idstr(cx);
int rv;
@@ -686,6 +687,7 @@ env_setProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
return false;
}
vp.setString(valstr);
+#endif /* !defined XP_SOLARIS */
return result.succeed();
}
diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
index 12b203b70..08ba8241a 100644
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -924,8 +924,6 @@ const js::ObjectOps XPC_WN_ObjectOpsWithEnumerate = {
nullptr, // setProperty
nullptr, // getOwnPropertyDescriptor
nullptr, // deleteProperty
- nullptr, // watch
- nullptr, // unwatch
nullptr, // getElements
XPC_WN_JSOp_Enumerate,
nullptr, // funToString
diff --git a/js/xpconnect/src/moz.build b/js/xpconnect/src/moz.build
index 7d9cd5b37..29cfc4776 100644
--- a/js/xpconnect/src/moz.build
+++ b/js/xpconnect/src/moz.build
@@ -66,4 +66,4 @@ LOCAL_INCLUDES += [
]
if CONFIG['GNU_CXX']:
- CXXFLAGS += ['-Wno-shadow', '-Werror=format']
+ CXXFLAGS += ['-Wno-shadow']
diff --git a/js/xpconnect/tests/chrome/chrome.ini b/js/xpconnect/tests/chrome/chrome.ini
index 5a7b98214..d89c89b54 100644
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -106,7 +106,6 @@ skip-if = os == 'win' || os == 'mac' # bug 1131110
[test_precisegc.xul]
[test_sandboxImport.xul]
[test_scriptSettings.xul]
-[test_watchpoints.xul]
[test_weakmap_keys_preserved.xul]
[test_weakmap_keys_preserved2.xul]
[test_weakmaps.xul]
diff --git a/js/xpconnect/tests/chrome/test_watchpoints.xul b/js/xpconnect/tests/chrome/test_watchpoints.xul
deleted file mode 100644
index 2262b1a90..000000000
--- a/js/xpconnect/tests/chrome/test_watchpoints.xul
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=693527
--->
-<window title="Mozilla Bug "
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-
- <!-- test results are displayed in the html:body -->
- <body xmlns="http://www.w3.org/1999/xhtml">
- <a href="https://bugzilla.mozilla.org/show_bug.cgi?id="
- target="_blank">Mozilla Bug 693527</a>
- </body>
-
- <!-- test code goes here -->
- <script type="application/javascript">
- <![CDATA[
- /** Test for Bug 693527 **/
-
- let Cu = Components.utils;
- let Ci = Components.interfaces;
-
- /* Create a weak reference, with a single-element weak map. */
- let make_weak_ref = function (obj) {
- let m = new WeakMap;
- m.set(obj, {});
- return m;
- };
-
- /* Check to see if a weak reference is dead. */
- let weak_ref_dead = function (r) {
- return ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(r).length == 0;
- }
-
-
- let make_cycle = function () {
- var p = document.createElement("p");
- p.children.x = p;
- var f = function() { };
- p.watch("y", f);
- var d = document.createElement("div");
- d.appendChild(p);
- f.loop = d;
- f.bar = {}; // observing f directly makes the leak go away even without the CC somehow
- return make_weak_ref(f.bar);
- };
-
- var cycle_ref = make_cycle();
-
-
- /* set up for running precise GC/CC then checking the results */
-
- SimpleTest.waitForExplicitFinish();
-
- Cu.schedulePreciseGC(function () {
- window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .cycleCollect();
- window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .garbageCollect();
- window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .garbageCollect();
-
- ok(weak_ref_dead(cycle_ref), "Garbage gray watchpoint cycle should be collected.");
-
- SimpleTest.finish();
- });
-
- ]]>
- </script>
-</window>
diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul
index 73de267a1..38f3f447d 100644
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -182,8 +182,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
"toGMTString", Symbol.toPrimitive];
gConstructorProperties['Date'] = constructorProps(["UTC", "parse", "now"]);
gPrototypeProperties['Object'] =
- ["constructor", "toSource", "toString", "toLocaleString", "valueOf", "watch",
- "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
+ ["constructor", "toSource", "toString", "toLocaleString", "valueOf",
+ "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
"__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__",
"__proto__"];
gConstructorProperties['Object'] =
@@ -243,7 +243,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
"$`", "$'", Symbol.species])
gPrototypeProperties['Promise'] =
- ["constructor", "catch", "then", Symbol.toStringTag];
+ ["constructor", "catch", "then", "finally", Symbol.toStringTag];
gConstructorProperties['Promise'] =
constructorProps(["resolve", "reject", "all", "race", Symbol.species]);