From 69d1f32ff7a2ca94648584be63a44f6990741118 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Wed, 21 Aug 2024 10:45:07 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1268085 - Remove unused post barrier callbacks r=terrence (0ab13411c9) - Bug 1267699 - Move some public types to the right namespace; r=sfink (3d5008e610) - Bug 1267550 (part 1) - Rename MOZ_MUST_USE as MOZ_MUST_USE_TYPE. r=ehsan. (6f47375796) - Bug 1259021 - Rename Vector::extractRawBuffer to extractOrCopyRawBuffer r=Waldo (97ca94495b) - Bug 1259021 - Add Vector::extractRawBuffer method that doesn't copy the buffer r=Waldo (e58deec48f) - Bug 1265892 - Change Vector to use Impl::new_ consistently. r=Waldo (7a52d21b29) - Bug 1267912 - Rename nsNetUtil.inl as nsNetUtilInlines.h. r=valentin. (548a41b293) - Bug 1265690 part 1 - Mark StringBuffer methods WARN_UNUSED_RESULT, fix OOM issues. r=jonco (0d7e6837e3) - Bug 1265690 part 2 - Fix some more OOM issues in TypedObject code. r=jonco (b60902453e) - Bug 1263490 - Part 2: Add GetFirstDollarIndex intrinsic and use it inRegExpReplace. r=till (4ba19db8c4) - Bug 1263490 - Part 3: Inline GetFirstDollarIndex intrinsic. r=h4writer (e7d9b5d1cc) - Bug 1263490 - Part 4: Fold GetFirstDollarIndex into a integer constant. r=h4writer (3479c7d1af) - Bug 1267269 - Make MIRType an enum class. r=bbouvier (d580ef372a) - Bug 1259295 - BaldrMonkey: Postorder (r=luke) (6ef7a77663) - Bug 1254142: BaldrMonkey: make br_table yield (r=luke) (80e7635e58) - Bug 1263202 - BaldrMonkey: switch to arities on branches, calls and return (r=bbouvier) (f5a0358634) - Bug 1236358 - Improper reading of string16 in Pickle::ReadString16. r=jld (8370ba6a0b) - Bug 1263205 - BaldrMonkey: Update section headers for proposed spec changes (r=luke) (0def2e6bc2) - Bug 1263205 - BaldrMonkey: Update for proposed new section names (r=luke) (e57f0e3367) - Bug 1263205 - BaldrMonkey: Add 'form' field to types section (r=bbouvier) (794edc890f) - Bug 1259021 - Use in-place storage in AutoStableStringChars to avoid allocation for short strings r=jandem r=Waldo (ffb53cbcf4) - Bug 1267550 (part 2) - Rename MOZ_WARN_UNUSED_RESULT as MOZ_MUST_USE. r=froydnj. (47bc674b86) - Bug 1268518: Baldr: implement int32/int64 rotations; r=luke (0d5eedccce) - Bug 1255008: IonMonkey - Add a by default disabled flow sensitive alias analysis pass, r=jandem (521c585d75) - Bug 1266781: Baldr: implement proper checked truncations to integer types; r=sunfish (46078fb3d3) - Bug 1266781: Rename MTruncateToInt64 into MWasmTruncateInt64; r=sunfish (c7d7d1ac11) - Bug 1266781: Add new traps; r=luke (b7ed3d44e6) - Bug 1268024: Pass the atomic attribute down to EmitHeapAccess; r=luke (6195f7d7a3) - Bug 1268024: A few cleanups related to loads/stores; r=luke (88141e3a01) - Bug 1258312 - Make Pickle::Resize infallible r=jld (241ee9b60d) - Bug 1162772, part 1 - Allow CompartmentCreationOptions to store Secure Context state. r=jorendorff (ff666384cf) - Bug 1162772, part 2 - Expose whether SEC_FORCE_INHERIT_PRINCIPAL was dropped from an nsILoadInfo. r=bz (ada46f86bf) - Bug 1162772, part 3 - Add a getChannelResultPrincipalIfNotSandboxed method to nsIScriptSecurityManager. r=bz (5b1d9f6807) - Bug 1162772, part 4 - Implement nsGlobalWindow::IsSecureContext. r=bz (f392f439c9) - Bug 1162772, part 5 - Expose Window.isSecureContext to content. r=bz (e7296e2cf1) - Bug 1267509 - Make nsContentSecurityManager::IsURIPotentiallyTrustworthy act on an nsIPrincipal. r=bz (83de80350a) - Bug 1219098 - Use UniquePtr in UncompressedSourceCache, for it is good (r=jandem) (b68769c729) - Bug 1244279 - Part 1: Take a bit in ObjectElements::Flags to indicate whether the object is in the whole cell store buffer. r=terrence (968cf373f9) - Bug 1244279 - Part 0: Add a GC ubench for large arrays with both elements and properties. r=terrence (ec76b48323) - Bug 1255925 - Give a name to getters/setters and integer-named methods. r=efaust (f978cc6916) - Bug 888969 - Make the getPrototypeOf/setPrototypeOf traps scriptable. r=efaust, r=bholley (eb2325a9ea) - Bug 1267557 part 0 - Move JS poison constants to jsutil.h. r=jonco (65afc690d2) - Bug 1267557 part 1 - Also poison bytes allocated before the actual jitcode. r=nbp (70f0b327d3) - Bug 1267557 part 2 - Use different jitcode poison values. r=nbp (08008ab9dc) - Bug 1267557 part 3 - Define JS_SWEPT_CODE_PATTERN for mips. r=nbp (17e894d59d) - Bug 1267449 - Do not infinite loop in js_fputs; r=jimb (67f961b6cd) - Bug 1219098 - Reenable compression on large sources, but revert to uncompressed if decompression happens (r=jandem) (b44ee8d77d) - Bug 1267551 (part 1) - Use MOZ_MUST_USE more in jsnum.h. r=jonco. (d2476bf8f4) - Bug 1267551 (part 2) - Use MOZ_MUST_USE more in js/src/ds/. r=jonco. (4ff5d9aa88) - Bug 1267412 - Use MutableHandleValue instead of pointer-to-AutoValueVector; r=sfink (3f6dd284bb) - Bug 1266406 - Use EnumSet to simplify GC sweeping phase information r=terrence (64811500e7) - Bug 1266457 - Update pointers in GC things in two phases when compacting r=terrence (f6f5bc4e4d) - Bug 1266457 - Simplify typed object trace hook r=terence (3b06c8d1e5) - Bug 1268541 - Compact arenas containing base shapes r=terrence (b458b92eea) - Bug 1268805 - Implement PrivateGCThingValue. (r=terrence) (deec9a83ae) - Bug 1268415: Initialize members in UpdatePointerTasks; r=jonco (6cb219005a) - Bug 1268501 - Release the GC lock periodically when releasing arenas on the backgound thread r=terrence (37f0997682) - Bug 1263572 - Wait for background sweeping to finish before checking base shapes r=terrence (354801a411) - Bug 1266887 - Store Rooted heads on the Zone; r=sfink (91c0101ee3) - Bug 1266402 - Add iteration to EnumSet so that it can be used in range-based for loops r=Waldo (e9507a2524) - Bug 1266404 - Allow construction of an EnumSet using an initializer list r=Waldo (1b6d340e99) - Bug 1254020 - Always compute theme scaling factor when per-monitor dpi aware, even if only a single display is currently present. r=emk (a00cda21f4) - Bug 1263525 - Add dedicated function for std_Array self-hosted intrinsic. r=efaust (449d8bb7eb) - Bug 1255925 - Change JSFunction::name to return a JSAtom. r=efaust (5ab396ce83) - Bug 888969 - Make our tree's sole implementation of nsIRemoteTagService.getRemoteObjectTag not depend upon the infallibility of [[GetPrototypeOf]] on the object provided to it. r=bz (f388f4bf1f) - Bug 1264896 - Kill off nsIRemoteTagService and do what it does, in its sole caller, in far-faster C++. r=billm (5ed3fb103d) - Bug 1268246 - Add a simple Poison class lifetime checker. r=froydnj (7b237bc70e) - Bug 1249496 - Don't apply dpi-based scaling for window titlebar dimensions when on a secondary display, because windows doesn't scale it. r=emk (64dd706dbc) - Bug 1164518 - Avoid unnecessary DB updates when caching Safe Browsing results. r=gcp (3cafd9a4df) - Bug 1264472 - Use nsRunnables in FIDO U2F. r=keeler (3aa9570132) - Bug 1236060 - Dispatch error should advance queue. r=smaug (74155b75dd) - Bug 1251697 part 1. Thread an ErrorResult reference through the worker XHR WorkerThreadProxySyncRunnable implementations. r=khuey (77804cbb7c) - Bug 1251697 part 2. Have WorkerThreadProxySyncRunnable hand the ErrorResult reference it holds to its ResponseRunnable so it can report exceptions on there instead of on a JSContext. r=khuey (355c9ee313) - Bug 1251697 part 3. Remove the JSContext argument of StopSyncLoopRunnable::MaybeSetException. r=khuey (010f5b1058) - Bug 1155328. r=smaug (e1f8dac304) - Bug 1265927: Move nsRunnable to mozilla::Runnable, CancelableRunnable to mozilla::CancelableRunnable. r=froydnj (f83bfcae02) - Bug 1239946 - Change test to return error on Speak. r=eeejay (1d402beb02) - Bug 1254378 - Update synth tests and introduce no voiceschanged test. r=smaug (f5823bb70e) - Bug 1251627. Fix XMLHttpRequest.send() to follow the spec better in terms of the exceptions it throws. r=khuey (cd0e321948) - Bug 1268868: [MSE] P1. Re-enable gap detection within a media segment. r=gerald (b8b8df4bc2) - Bug 1268868: [MSE] P2. Reset longest duration after keyframe is seen. r=gerald (2b1401465c) - Bug 1268868: [MSE] P3. Prevent crash should gap be detected in content. r=gerald (063d9376fc) - Bug 1254378 - Implement nsISynthVoiceRegistry.notifyVoicesChanged. r=smaug (4b63b1c360) - Bug 1266804 - Un-inline js::Unbox(); r=jorendorff (0f288b6173) - Bug 1268863 - Report ScriptSources that are only reachable via AsmJSModule (r=njn) (5ba40acb64) - bump version to 45.1b1 (1414db0ca8) - Bug 1262062 - remove old futex names. r=bbouvier (62662bdd2e) - memory: build fix after renaming MOZ_WARN_UNUSED_RESULT (7254dc8d53) - import from mozilla: - Bug 1268725 - BaldrMonkey: Refactor away the internal storage from ExprIter. r=luke (1931bd636f17) - Bug 1268725 - BaldrMonkey: Convert default arguments into explicit arguments. r=luke (c8a11b8b6bbd) (867ec715d6) --- accessible/generic/Accessible.cpp | 2 +- accessible/ipc/DocAccessibleParent.h | 2 +- build/clang-plugin/clang-plugin.cpp | 2 +- .../tests/TestMultipleAnnotations.cpp | 4 +- build/clang-plugin/tests/TestMustUse.cpp | 4 +- caps/nsIScriptSecurityManager.idl | 20 +- caps/nsScriptSecurityManager.cpp | 32 +- caps/nsScriptSecurityManager.h | 4 + docshell/base/nsDocShell.cpp | 4 +- docshell/base/nsDocShell.h | 2 +- docshell/shistory/src/nsSHEntryShared.cpp | 2 +- dom/archivereader/ArchiveEvent.h | 2 +- dom/archivereader/ArchiveRequest.cpp | 2 +- dom/asmjscache/AsmJSCache.cpp | 4 +- dom/audiochannel/AudioChannelService.cpp | 6 +- dom/base/Console.cpp | 2 +- dom/base/DOMRequest.cpp | 4 +- dom/base/Element.h | 2 +- dom/base/File.cpp | 2 +- dom/base/FragmentOrElement.cpp | 2 +- dom/base/FragmentOrElement.h | 2 +- dom/base/ImageEncoder.cpp | 6 +- dom/base/ImportManager.cpp | 2 +- dom/base/PostMessageEvent.h | 2 +- dom/base/WebSocket.cpp | 8 +- dom/base/WindowNamedPropertiesHandler.h | 5 + dom/base/nsContentUtils.cpp | 2 +- dom/base/nsContentUtils.h | 10 +- dom/base/nsDOMMutationObserver.cpp | 2 +- .../nsDocElementCreatedNotificationRunner.h | 2 +- dom/base/nsDocument.cpp | 20 +- dom/base/nsFocusManager.cpp | 4 +- dom/base/nsFrameLoader.cpp | 4 +- dom/base/nsFrameMessageManager.cpp | 2 +- dom/base/nsFrameMessageManager.h | 2 +- dom/base/nsGenericDOMDataNode.h | 2 +- dom/base/nsGlobalWindow.cpp | 222 +- dom/base/nsGlobalWindow.h | 8 + dom/base/nsHTMLContentSerializer.h | 4 +- dom/base/nsIContent.h | 2 +- dom/base/nsIGlobalObject.cpp | 2 +- dom/base/nsInProcessTabChildGlobal.cpp | 2 +- dom/base/nsJSEnvironment.cpp | 4 +- dom/base/nsJSEnvironment.h | 2 +- dom/base/nsObjectLoadingContent.cpp | 14 +- dom/base/nsReferencedElement.cpp | 2 +- dom/base/nsReferencedElement.h | 2 +- dom/base/nsScriptLoader.cpp | 6 +- dom/base/nsScriptLoader.h | 4 +- dom/base/nsTextFragment.h | 4 +- dom/base/nsXHTMLContentSerializer.h | 8 +- dom/base/nsXMLContentSerializer.h | 34 +- dom/base/nsXMLHttpRequest.cpp | 7 +- dom/bindings/MozMap.h | 2 +- dom/bindings/ToJSValue.h | 46 +- .../BrowserElementAudioChannel.cpp | 2 +- dom/cache/Manager.cpp | 4 +- dom/cache/PrincipalVerifier.h | 2 +- dom/camera/CameraControlImpl.cpp | 4 +- dom/camera/DOMCameraCapabilities.cpp | 2 +- dom/camera/DOMCameraControlListener.cpp | 2 +- dom/camera/GonkCameraControl.cpp | 10 +- dom/canvas/ImageBitmap.cpp | 4 +- dom/canvas/WebGLQuery.h | 2 +- .../DeviceStorageRequestParent.h | 3 +- dom/devicestorage/nsDeviceStorage.cpp | 2 +- dom/devicestorage/nsDeviceStorage.h | 4 +- dom/events/IMEContentObserver.h | 2 +- dom/events/IMEStateManager.cpp | 2 +- dom/events/TextComposition.h | 2 +- dom/fetch/Fetch.cpp | 4 +- dom/filehandle/ActorsParent.cpp | 4 +- dom/filesystem/FileSystemTaskBase.h | 2 +- dom/geolocation/nsGeolocation.cpp | 6 +- dom/html/HTMLFormElement.h | 2 +- dom/html/HTMLImageElement.cpp | 2 +- dom/html/HTMLMediaElement.cpp | 2 +- dom/html/HTMLObjectElement.cpp | 2 +- dom/html/nsGenericHTMLElement.cpp | 2 +- dom/html/nsHTMLDocument.cpp | 2 +- dom/html/nsTextEditorState.cpp | 4 +- dom/html/nsTextEditorState.h | 3 +- dom/indexedDB/ActorsChild.cpp | 2 +- dom/indexedDB/ActorsParent.cpp | 27 +- dom/indexedDB/FileInfo.cpp | 4 +- dom/indexedDB/FileSnapshot.cpp | 4 +- dom/indexedDB/ScriptErrorHelper.cpp | 2 +- dom/inputport/FakeInputPortService.cpp | 2 +- .../security/nsIContentSecurityManager.idl | 10 +- dom/ipc/Blob.cpp | 8 +- dom/ipc/ContentParent.cpp | 2 +- dom/ipc/CrashReporterParent.cpp | 2 +- dom/ipc/FilePickerParent.h | 2 +- dom/ipc/ProcessHangMonitor.cpp | 4 +- dom/ipc/TabChild.cpp | 4 +- dom/ipc/TabParent.cpp | 4 +- dom/ipc/nsIContentParent.h | 4 +- dom/media/FileBlockCache.h | 2 +- dom/media/GraphDriver.cpp | 4 +- dom/media/GraphDriver.h | 2 +- dom/media/Latency.cpp | 2 +- dom/media/MediaCache.cpp | 2 +- dom/media/MediaDecoderReader.cpp | 4 +- dom/media/MediaEventSource.h | 2 +- dom/media/MediaFormatReader.cpp | 2 +- dom/media/MediaManager.cpp | 14 +- dom/media/MediaManager.h | 4 +- dom/media/MediaRecorder.cpp | 10 +- dom/media/MediaStreamGraph.cpp | 14 +- dom/media/TextTrackList.cpp | 2 +- dom/media/VideoUtils.h | 4 +- dom/media/android/AndroidMediaPluginHost.cpp | 2 +- .../android/AndroidMediaResourceServer.cpp | 2 +- .../android/AndroidMediaResourceServer.h | 2 +- dom/media/gmp/GMPContentParent.cpp | 2 +- dom/media/gmp/GMPParent.cpp | 4 +- dom/media/gmp/GMPService.cpp | 2 +- dom/media/gmp/GMPServiceChild.cpp | 2 +- dom/media/gmp/GMPServiceParent.cpp | 13 +- dom/media/gmp/GMPServiceParent.h | 2 +- dom/media/gtest/TestGMPCrossOrigin.cpp | 4 +- dom/media/gtest/TestMP4Demuxer.cpp | 2 +- dom/media/gtest/TestMediaFormatReader.cpp | 2 +- dom/media/gtest/TestMozPromise.cpp | 2 +- dom/media/imagecapture/CaptureTask.cpp | 2 +- dom/media/mediasink/DecodedStream.cpp | 2 +- dom/media/mediasource/AsyncEventRunner.h | 2 +- dom/media/mediasource/TrackBuffersManager.cpp | 72 +- dom/media/mediasource/TrackBuffersManager.h | 7 +- dom/media/omx/MediaOmxReader.cpp | 2 +- .../platforms/agnostic/BlankDecoderModule.cpp | 2 +- .../agnostic/gmp/MediaDataDecoderProxy.h | 2 +- .../platforms/wmf/WMFVideoMFTManager.cpp | 2 +- dom/media/systemservices/CamerasChild.cpp | 12 +- dom/media/systemservices/CamerasParent.cpp | 30 +- dom/media/systemservices/CamerasParent.h | 2 +- dom/media/systemservices/CamerasUtils.h | 6 +- dom/media/systemservices/LoadMonitor.cpp | 6 +- dom/media/systemservices/MediaUtils.h | 8 +- dom/media/webaudio/AlignedTArray.h | 2 +- dom/media/webaudio/AnalyserNode.cpp | 2 +- dom/media/webaudio/AudioBufferSourceNode.cpp | 2 +- dom/media/webaudio/AudioContext.cpp | 2 +- dom/media/webaudio/AudioContext.h | 2 +- dom/media/webaudio/AudioDestinationNode.cpp | 4 +- dom/media/webaudio/AudioNode.cpp | 2 +- dom/media/webaudio/DynamicsCompressorNode.cpp | 2 +- dom/media/webaudio/MediaBufferDecoder.cpp | 4 +- dom/media/webaudio/OscillatorNode.cpp | 2 +- dom/media/webaudio/PlayingRefChangeHandler.h | 2 +- dom/media/webaudio/ReportDecodeResultTask.h | 2 +- dom/media/webaudio/ScriptProcessorNode.cpp | 2 +- .../webaudio/blink/HRTFDatabaseLoader.cpp | 2 +- .../webrtc/MediaEngineGonkVideoSource.cpp | 4 +- dom/media/webrtc/MediaEngineTabVideoSource.h | 6 +- .../PocketSphinxSpeechRecognitionService.cpp | 4 +- .../webspeech/recognition/SpeechRecognition.h | 2 +- .../cocoa/OSXSpeechSynthesizerService.mm | 7 +- .../webspeech/synth/ipc/PSpeechSynthesis.ipdl | 2 + .../synth/ipc/SpeechSynthesisChild.cpp | 7 + .../synth/ipc/SpeechSynthesisChild.h | 2 + dom/media/webspeech/synth/moz.build | 1 + .../webspeech/synth/nsISynthVoiceRegistry.idl | 8 +- dom/media/webspeech/synth/nsSpeechTask.cpp | 10 + .../webspeech/synth/nsSynthVoiceRegistry.cpp | 32 + .../webspeech/synth/nsSynthVoiceRegistry.h | 2 + .../webspeech/synth/pico/nsPicoService.cpp | 8 +- .../synth/speechd/SpeechDispatcherService.cpp | 4 +- .../webspeech/synth/test/FakeSynthModule.cpp | 2 +- dom/media/webspeech/synth/test/common.js | 35 +- .../synth/test/file_speech_error.html | 2 +- .../synth/test/file_speech_queue.html | 6 +- .../synth/test/nsFakeSynthServices.cpp | 48 +- .../test/startup/file_voiceschanged.html | 32 + .../synth/test/startup/mochitest.ini | 7 + .../test/startup/test_voiceschanged.html | 32 + .../webspeech/synth/test/test_bfcache.html | 10 +- .../synth/test/test_global_queue.html | 7 +- .../synth/test/test_global_queue_cancel.html | 7 +- .../synth/test/test_global_queue_pause.html | 7 +- .../test/test_indirect_service_events.html | 2 +- .../synth/test/test_speech_cancel.html | 2 +- .../synth/test/test_speech_error.html | 2 +- .../synth/test/test_speech_queue.html | 4 +- .../synth/test/test_speech_simple.html | 5 +- .../webspeech/synth/windows/SapiService.cpp | 2 + dom/network/UDPSocket.cpp | 2 +- dom/notification/DesktopNotification.cpp | 4 +- dom/notification/Notification.cpp | 8 +- dom/plugins/base/android/ANPAudio.cpp | 2 +- dom/plugins/base/nsJSNPRuntime.cpp | 6 +- dom/plugins/base/nsNPAPIPlugin.cpp | 2 +- dom/plugins/base/nsNPAPIPluginInstance.cpp | 4 +- dom/plugins/base/nsPluginHost.cpp | 4 +- dom/plugins/base/nsPluginInstanceOwner.cpp | 2 +- dom/plugins/base/nsPluginNativeWindowWin.cpp | 4 +- dom/plugins/ipc/PluginHangUIParent.cpp | 2 +- dom/plugins/ipc/PluginMessageUtils.cpp | 2 +- dom/promise/Promise.cpp | 4 +- dom/push/PushManager.cpp | 4 +- dom/push/PushSubscription.cpp | 2 +- dom/quota/QuotaManager.cpp | 8 +- dom/security/nsCSPContext.cpp | 2 +- dom/security/nsContentSecurityManager.cpp | 34 +- dom/security/nsMixedContentBlocker.cpp | 2 +- ...=> test_isOriginPotentiallyTrustworthy.js} | 9 +- dom/security/test/unit/xpcshell.ini | 2 +- dom/smil/nsSMILTimedElement.cpp | 2 +- dom/storage/DOMStorage.cpp | 2 +- dom/storage/DOMStorageCache.cpp | 2 +- dom/storage/DOMStorageIPC.cpp | 6 +- dom/system/nsDeviceSensors.cpp | 2 +- dom/u2f/U2F.cpp | 1204 ++++---- dom/u2f/U2F.h | 114 +- dom/u2f/tests/facet/facetList-good | 8 - dom/u2f/tests/facet/facetList-good^headers^ | 1 - dom/u2f/tests/facet/facetList-invalid_format | 6 - .../facet/facetList-invalid_format^headers^ | 1 - dom/u2f/tests/facet/facetList-no_overlap | 9 - .../tests/facet/facetList-no_overlap^headers^ | 1 - dom/u2f/tests/facet/facetList.txt | 8 - dom/u2f/tests/mochitest.ini | 8 - dom/u2f/tests/test_frame.html | 1 - .../test_frame_appid_facet_remoteload.html | 57 - dom/u2f/tests/test_frame_register_sign.html | 12 +- dom/webidl/Window.webidl | 6 + dom/workers/RuntimeService.cpp | 12 +- dom/workers/ScriptLoader.cpp | 2 +- dom/workers/ServiceWorkerClient.cpp | 2 +- dom/workers/ServiceWorkerClients.cpp | 8 +- dom/workers/ServiceWorkerEvents.cpp | 2 +- dom/workers/ServiceWorkerEvents.h | 2 +- dom/workers/ServiceWorkerInfo.cpp | 2 +- dom/workers/ServiceWorkerManager.cpp | 35 +- dom/workers/ServiceWorkerManagerParent.cpp | 10 +- dom/workers/ServiceWorkerPrivate.cpp | 4 +- dom/workers/ServiceWorkerPrivate.h | 2 +- dom/workers/ServiceWorkerRegistrar.cpp | 9 +- dom/workers/ServiceWorkerRegistration.cpp | 8 +- dom/workers/ServiceWorkerWindowClient.cpp | 2 +- dom/workers/URL.cpp | 2 +- dom/workers/WorkerDebuggerManager.cpp | 4 +- dom/workers/WorkerPrivate.cpp | 12 +- dom/workers/WorkerRunnable.cpp | 2 +- dom/workers/WorkerRunnable.h | 12 +- dom/workers/WorkerScope.cpp | 2 +- dom/workers/XMLHttpRequest.cpp | 210 +- dom/xbl/nsXBLMaybeCompiled.h | 6 +- dom/xslt/xslt/txMozillaXSLTProcessor.cpp | 2 +- dom/xul/nsXULElement.cpp | 57 +- editor/composer/nsEditorSpellCheck.cpp | 2 +- editor/libeditor/nsEditor.cpp | 2 +- extensions/gio/nsGIOProtocolHandler.cpp | 2 +- .../spellcheck/src/mozInlineSpellChecker.cpp | 2 +- .../spellcheck/src/mozPersonalDictionary.cpp | 4 +- gfx/2d/BaseRect.h | 10 +- gfx/layers/AsyncCanvasRenderer.cpp | 8 +- gfx/layers/ImageContainer.h | 4 +- gfx/layers/LayerScope.cpp | 2 +- gfx/layers/apz/util/APZCCallbackHelper.cpp | 4 +- ...SafeRefcountingWithMainThreadDestruction.h | 2 +- gfx/src/gfxCrashReporterUtils.cpp | 2 +- gfx/src/nsPoint.h | 6 +- gfx/src/nsRect.h | 26 +- gfx/src/nsRegion.h | 4 +- gfx/src/nsSize.h | 2 +- gfx/thebes/gfxFontInfoLoader.cpp | 12 +- gfx/thebes/gfxPlatform.cpp | 8 +- image/DecodePool.cpp | 8 +- image/DrawResult.h | 2 +- image/ProgressTracker.cpp | 4 +- image/RasterImage.cpp | 2 +- image/RasterImage.h | 2 +- image/imgFrame.cpp | 2 +- image/imgRequest.cpp | 6 +- image/imgRequestProxy.h | 2 +- image/test/gtest/TestDecodeToSurface.cpp | 2 +- intl/uconv/nsIUnicodeDecoder.h | 6 +- intl/uconv/nsIUnicodeEncoder.h | 6 +- intl/uconv/nsReplacementToUnicode.h | 6 +- intl/uconv/nsUTF8ToUnicode.h | 6 +- intl/uconv/nsUnicodeToUTF8.h | 6 +- intl/uconv/ucvlatin/nsUTF16ToUnicode.h | 6 +- intl/uconv/ucvlatin/nsUnicodeToUTF16.h | 6 +- intl/uconv/ucvtw/nsUnicodeToBIG5.h | 6 +- ipc/chromium/src/base/pickle.cc | 51 +- ipc/chromium/src/base/pickle.h | 44 +- ipc/glue/BackgroundImpl.cpp | 61 +- ipc/glue/BackgroundParentImpl.cpp | 6 +- ipc/ipdl/ipdl/cxx/cgen.py | 2 +- js/ipc/JavaScriptBase.h | 10 + js/ipc/JavaScriptShared.cpp | 14 +- js/ipc/JavaScriptShared.h | 6 +- js/ipc/PJavaScript.ipdl | 1 + js/ipc/WrapperAnswer.cpp | 28 + js/ipc/WrapperAnswer.h | 2 + js/ipc/WrapperOwner.cpp | 66 +- js/ipc/WrapperOwner.h | 4 + js/public/Class.h | 2 +- js/public/Debug.h | 2 +- js/public/GCHashTable.h | 76 +- js/public/GCPolicyAPI.h | 8 +- js/public/GCVariant.h | 10 +- js/public/GCVector.h | 28 +- js/public/HashTable.h | 36 +- js/public/HeapAPI.h | 5 + js/public/Id.h | 22 +- js/public/Proxy.h | 6 +- js/public/RootingAPI.h | 30 +- js/public/SweepingAPI.h | 2 +- js/public/Utility.h | 20 +- js/public/Value.h | 147 +- js/src/NamespaceImports.h | 11 +- js/src/asmjs/AsmJS.cpp | 1096 ++++--- js/src/asmjs/Wasm.cpp | 893 ++---- js/src/asmjs/WasmBinary.h | 213 +- js/src/asmjs/WasmBinaryIterator.cpp | 368 +++ js/src/asmjs/WasmBinaryIterator.h | 1781 +++++++++++ js/src/asmjs/WasmBinaryToText.cpp | 120 +- js/src/asmjs/WasmGenerator.cpp | 33 +- js/src/asmjs/WasmGenerator.h | 87 +- js/src/asmjs/WasmIonCompile.cpp | 2653 +++++++++-------- js/src/asmjs/WasmIonCompile.h | 8 +- js/src/asmjs/WasmModule.h | 3 +- js/src/asmjs/WasmSignalHandlers.cpp | 3 +- js/src/asmjs/WasmStubs.cpp | 58 +- js/src/asmjs/WasmTextToBinary.cpp | 244 +- js/src/asmjs/WasmTypes.cpp | 18 + js/src/asmjs/WasmTypes.h | 98 +- js/src/builtin/AtomicsObject.cpp | 2 - js/src/builtin/AtomicsObject.h | 2 +- js/src/builtin/MapObject.cpp | 10 +- js/src/builtin/MapObject.h | 4 +- js/src/builtin/ModuleObject.cpp | 11 +- js/src/builtin/ModuleObject.h | 2 + js/src/builtin/Promise.cpp | 2 +- js/src/builtin/Promise.h | 2 +- js/src/builtin/ReflectParse.cpp | 2 +- js/src/builtin/RegExp.cpp | 68 +- js/src/builtin/RegExp.h | 9 + js/src/builtin/RegExp.js | 2 +- js/src/builtin/TestingFunctions.cpp | 8 +- js/src/builtin/TypedObject.cpp | 70 +- .../largeArrayPropertyAndElements.js | 34 + js/src/devtools/gc-ubench/index.html | 1 + js/src/ds/Fifo.h | 6 +- js/src/ds/IdValuePair.h | 2 +- js/src/ds/InlineMap.h | 8 +- js/src/ds/LifoAlloc.h | 4 +- js/src/ds/OrderedHashTable.h | 20 +- js/src/ds/PriorityQueue.h | 4 +- js/src/ds/Sort.h | 2 +- js/src/ds/TraceableFifo.h | 4 +- js/src/frontend/BytecodeEmitter.cpp | 8 +- js/src/frontend/FullParseHandler.h | 4 +- js/src/frontend/ParseNode-inl.h | 2 +- js/src/frontend/Parser.cpp | 77 +- js/src/frontend/Parser.h | 9 +- js/src/frontend/SyntaxParseHandler.h | 4 +- js/src/gc/Barrier.cpp | 21 +- js/src/gc/Barrier.h | 34 +- js/src/gc/GCInternals.h | 1 + js/src/gc/GCRuntime.h | 7 +- js/src/gc/Marking.cpp | 13 +- js/src/gc/Marking.h | 34 +- js/src/gc/Policy.h | 29 +- js/src/gc/RootMarking.cpp | 6 +- js/src/gc/Rooting.h | 8 +- js/src/gc/StoreBuffer-inl.h | 30 + js/src/gc/StoreBuffer.h | 32 +- js/src/gc/Tracer.cpp | 2 +- js/src/gc/Zone.h | 10 +- js/src/irregexp/RegExpEngine.h | 2 +- js/src/jit-test/lib/wasm.js | 12 + .../jit-test/tests/TypedObject/bug1265690.js | 14 + .../tests/arrays/std_Array-prototype.js | 6 + .../jit-test/tests/asm.js/testBug1219098.js | 14 + .../jit-test/tests/asm.js/testExpressions.js | 8 + .../tests/basic/function-tosource-getset.js | 8 +- js/src/jit-test/tests/parser/bug-1264568.js | 6 + .../tests/profiler/AutoEntryMonitor-01.js | 4 +- .../jit-test/tests/wasm/basic-control-flow.js | 53 +- .../jit-test/tests/wasm/basic-conversion.js | 65 +- js/src/jit-test/tests/wasm/basic-memory.js | 4 +- js/src/jit-test/tests/wasm/basic.js | 13 +- js/src/jit-test/tests/wasm/binary.js | 68 +- js/src/jit-test/tests/wasm/totext1.js | 5 +- js/src/jit/AliasAnalysis.cpp | 48 +- js/src/jit/AliasAnalysis.h | 12 +- js/src/jit/AliasAnalysisShared.cpp | 44 + js/src/jit/AliasAnalysisShared.h | 77 + js/src/jit/AlignmentMaskAnalysis.cpp | 6 +- js/src/jit/BaselineBailouts.cpp | 6 +- js/src/jit/BaselineCacheIR.cpp | 6 +- js/src/jit/BaselineCompiler.cpp | 10 +- js/src/jit/BaselineFrame.cpp | 8 +- js/src/jit/BaselineFrame.h | 2 +- js/src/jit/BaselineIC.cpp | 22 +- js/src/jit/BaselineIC.h | 2 +- js/src/jit/BaselineInspector.cpp | 54 +- js/src/jit/BaselineJIT.cpp | 4 +- js/src/jit/CodeGenerator.cpp | 260 +- js/src/jit/CodeGenerator.h | 2 + js/src/jit/EagerSimdUnbox.cpp | 2 +- js/src/jit/EffectiveAddressAnalysis.cpp | 10 +- js/src/jit/ExecutableAllocator.h | 6 +- js/src/jit/FixedList.h | 4 +- js/src/jit/FlowAliasAnalysis.cpp | 942 ++++++ js/src/jit/FlowAliasAnalysis.h | 70 + js/src/jit/InlinableNatives.h | 1 + js/src/jit/InstructionReordering.cpp | 2 +- js/src/jit/Ion.cpp | 50 +- js/src/jit/Ion.h | 3 +- js/src/jit/IonAnalysis.cpp | 211 +- js/src/jit/IonBuilder.cpp | 458 +-- js/src/jit/IonBuilder.h | 5 +- js/src/jit/IonCaches.cpp | 61 +- js/src/jit/IonOptimizationLevels.h | 4 + js/src/jit/IonTypes.h | 218 +- js/src/jit/JSONSpewer.cpp | 2 +- js/src/jit/JitCompartment.h | 10 +- js/src/jit/JitFrames.cpp | 2 +- js/src/jit/JitOptions.cpp | 3 + js/src/jit/JitOptions.h | 1 + js/src/jit/JitSpewer.cpp | 3 + js/src/jit/JitSpewer.h | 2 + js/src/jit/LICM.cpp | 2 +- js/src/jit/LIR.cpp | 4 +- js/src/jit/LIR.h | 36 +- js/src/jit/Linker.cpp | 64 + js/src/jit/Linker.h | 43 +- js/src/jit/Lowering.cpp | 890 +++--- js/src/jit/Lowering.h | 3 + js/src/jit/MCallOptimize.cpp | 367 +-- js/src/jit/MIR.cpp | 841 +++--- js/src/jit/MIR.h | 996 ++++--- js/src/jit/MIRGraph.cpp | 14 +- js/src/jit/MIRGraph.h | 30 +- js/src/jit/MOpcodes.h | 5 +- js/src/jit/MacroAssembler-inl.h | 22 +- js/src/jit/MacroAssembler.cpp | 104 +- js/src/jit/MacroAssembler.h | 31 +- js/src/jit/OptimizationTracking.cpp | 2 +- js/src/jit/PerfSpewer.cpp | 1 + js/src/jit/RangeAnalysis.cpp | 136 +- js/src/jit/Recover.cpp | 20 +- js/src/jit/RegisterSets.h | 8 +- js/src/jit/ScalarReplacement.cpp | 10 +- js/src/jit/TypePolicy.cpp | 282 +- js/src/jit/VMFunctions.cpp | 8 +- js/src/jit/VMFunctions.h | 10 +- js/src/jit/ValueNumbering.cpp | 2 +- js/src/jit/arm/Assembler-arm.cpp | 16 +- js/src/jit/arm/CodeGenerator-arm.cpp | 165 +- js/src/jit/arm/CodeGenerator-arm.h | 2 + js/src/jit/arm/Lowering-arm.cpp | 60 +- js/src/jit/arm/Lowering-arm.h | 2 +- js/src/jit/arm/MacroAssembler-arm-inl.h | 34 +- js/src/jit/arm/MacroAssembler-arm.cpp | 3 +- js/src/jit/arm64/Assembler-arm64.cpp | 10 +- js/src/jit/arm64/Lowering-arm64.cpp | 2 +- js/src/jit/arm64/Lowering-arm64.h | 4 +- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 23 + js/src/jit/arm64/MacroAssembler-arm64.h | 10 +- .../mips-shared/CodeGenerator-mips-shared.cpp | 30 +- .../jit/mips-shared/Lowering-mips-shared.cpp | 48 +- js/src/jit/mips-shared/Lowering-mips-shared.h | 2 +- .../MacroAssembler-mips-shared-inl.h | 23 + js/src/jit/mips32/Assembler-mips32.cpp | 8 +- js/src/jit/mips32/CodeGenerator-mips32.cpp | 2 +- js/src/jit/mips32/Lowering-mips32.cpp | 12 +- js/src/jit/mips32/MacroAssembler-mips32.cpp | 2 +- js/src/jit/mips64/Assembler-mips64.cpp | 10 +- js/src/jit/mips64/CodeGenerator-mips64.cpp | 32 +- js/src/jit/mips64/Lowering-mips64.cpp | 12 +- js/src/jit/mips64/MacroAssembler-mips64.cpp | 6 +- js/src/jit/mips64/MacroAssembler-mips64.h | 4 +- js/src/jit/none/Lowering-none.h | 2 +- js/src/jit/shared/CodeGenerator-shared.cpp | 54 +- js/src/jit/shared/CodeGenerator-shared.h | 35 +- js/src/jit/shared/LIR-shared.h | 66 + js/src/jit/shared/LOpcodes-shared.h | 4 + js/src/jit/shared/Lowering-shared-inl.h | 66 +- js/src/jit/shared/Lowering-shared.cpp | 20 +- js/src/jit/x64/Assembler-x64.cpp | 34 +- js/src/jit/x64/Assembler-x64.h | 12 + js/src/jit/x64/BaseAssembler-x64.h | 60 +- js/src/jit/x64/CodeGenerator-x64.cpp | 166 +- js/src/jit/x64/CodeGenerator-x64.h | 5 +- js/src/jit/x64/LIR-x64.h | 10 +- js/src/jit/x64/LOpcodes-x64.h | 2 +- js/src/jit/x64/Lowering-x64.cpp | 30 +- js/src/jit/x64/Lowering-x64.h | 2 +- js/src/jit/x64/MacroAssembler-x64.cpp | 6 +- js/src/jit/x64/MacroAssembler-x64.h | 2 +- js/src/jit/x86-shared/Assembler-x86-shared.h | 13 + .../jit/x86-shared/BaseAssembler-x86-shared.h | 48 +- .../x86-shared/CodeGenerator-x86-shared.cpp | 136 +- .../jit/x86-shared/CodeGenerator-x86-shared.h | 12 +- js/src/jit/x86-shared/Encoding-x86-shared.h | 2 + js/src/jit/x86-shared/Lowering-x86-shared.cpp | 56 +- .../MacroAssembler-x86-shared-inl.h | 34 + js/src/jit/x86/Assembler-x86.cpp | 14 +- js/src/jit/x86/CodeGenerator-x86.cpp | 72 +- js/src/jit/x86/CodeGenerator-x86.h | 1 + js/src/jit/x86/Lowering-x86.cpp | 24 +- js/src/jit/x86/Lowering-x86.h | 2 +- js/src/jit/x86/MacroAssembler-x86.cpp | 2 +- js/src/js.msg | 7 + js/src/jsapi-tests/moz.build | 1 + js/src/jsapi-tests/testGCUniqueId.cpp | 2 +- js/src/jsapi-tests/testJitDCEinGVN.cpp | 6 +- js/src/jsapi-tests/testJitFoldsTo.cpp | 8 +- js/src/jsapi-tests/testJitRangeAnalysis.cpp | 8 +- .../jsapi-tests/testPrivateGCThingValue.cpp | 57 + js/src/jsapi.cpp | 16 +- js/src/jsapi.h | 31 +- js/src/jsarray.cpp | 62 +- js/src/jsarray.h | 4 + js/src/jsatom.h | 2 +- js/src/jscntxt.cpp | 5 +- js/src/jscntxt.h | 2 +- js/src/jscompartment.cpp | 10 + js/src/jscompartment.h | 24 +- js/src/jsexn.cpp | 52 +- js/src/jsfriendapi.cpp | 39 +- js/src/jsfriendapi.h | 54 +- js/src/jsfun.cpp | 12 +- js/src/jsfun.h | 6 +- js/src/jsfuninlines.h | 5 +- js/src/jsgc.cpp | 324 +- js/src/jsgc.h | 3 +- js/src/jsgcinlines.h | 17 +- js/src/jsnum.h | 36 +- js/src/jsobj.cpp | 53 +- js/src/jsobj.h | 13 +- js/src/jsobjinlines.h | 22 +- js/src/jsopcode.cpp | 215 +- js/src/jspropertytree.cpp | 2 +- js/src/jsscript.cpp | 85 +- js/src/jsscript.h | 12 +- js/src/jsstr.cpp | 5 +- js/src/jsutil.h | 30 + js/src/jswrapper.h | 4 + js/src/moz.build | 4 + js/src/proxy/BaseProxyHandler.cpp | 9 +- js/src/proxy/CrossCompartmentWrapper.cpp | 18 + js/src/proxy/DeadObjectProxy.cpp | 8 + js/src/proxy/DeadObjectProxy.h | 2 + js/src/proxy/DirectProxyHandler.cpp | 8 + .../proxy/OpaqueCrossCompartmentWrapper.cpp | 9 + js/src/proxy/Proxy.cpp | 10 + js/src/proxy/Proxy.h | 2 + js/src/proxy/ScriptedDirectProxyHandler.cpp | 137 +- js/src/proxy/ScriptedDirectProxyHandler.h | 3 + js/src/shell/js.cpp | 14 +- js/src/tests/ecma_6/Class/methodName.js | 40 + js/src/tests/ecma_6/Object/accessor-name.js | 36 + js/src/tests/ecma_6/Proxy/getPrototypeOf.js | 285 ++ js/src/tests/ecma_6/Proxy/setPrototypeOf.js | 258 ++ js/src/tests/ecma_6/Reflect/getPrototypeOf.js | 9 +- js/src/tests/ecma_6/Reflect/setPrototypeOf.js | 25 +- js/src/tests/js1_8_5/reflect-parse/classes.js | 15 +- .../tests/js1_8_5/reflect-parse/methodDefn.js | 4 +- js/src/vm/ArrayBufferObject.h | 2 +- js/src/vm/CommonPropertyNames.h | 4 + js/src/vm/Debugger.cpp | 4 +- js/src/vm/GlobalObject.cpp | 4 +- js/src/vm/Interpreter.cpp | 10 +- js/src/vm/MemoryMetrics.cpp | 74 +- js/src/vm/NativeObject.cpp | 6 + js/src/vm/NativeObject.h | 35 +- js/src/vm/ObjectGroup.cpp | 2 +- js/src/vm/ObjectGroup.h | 4 +- js/src/vm/SavedFrame.h | 6 +- js/src/vm/ScopeObject.cpp | 6 +- js/src/vm/SelfHosting.cpp | 12 +- js/src/vm/Shape-inl.h | 8 + js/src/vm/Shape.cpp | 5 +- js/src/vm/Shape.h | 5 +- js/src/vm/Stack-inl.h | 2 +- js/src/vm/Stack.cpp | 8 +- js/src/vm/Stack.h | 4 +- js/src/vm/String.cpp | 43 +- js/src/vm/String.h | 2 +- js/src/vm/StringBuffer.cpp | 2 +- js/src/vm/StringBuffer.h | 45 +- js/src/vm/StructuredClone.cpp | 10 +- js/src/vm/Symbol.cpp | 2 +- js/src/vm/TypeInference.cpp | 64 +- js/src/vm/TypeInference.h | 4 +- js/src/vm/TypedArrayObject.cpp | 1 + js/src/vm/UnboxedObject-inl.h | 1 + js/src/vm/UnboxedObject.cpp | 29 +- js/src/vm/UnboxedObject.h | 4 +- js/xpconnect/idl/moz.build | 1 - js/xpconnect/idl/nsIRemoteTagService.idl | 13 - js/xpconnect/loader/mozJSSubScriptLoader.cpp | 2 +- js/xpconnect/src/XPCComponents.cpp | 2 +- js/xpconnect/src/XPCJSRuntime.cpp | 9 +- js/xpconnect/src/XPCMaps.h | 2 +- .../tests/unit/test_classesByID_instanceof.js | 43 + js/xpconnect/wrappers/WaiveXrayWrapper.cpp | 8 + js/xpconnect/wrappers/WaiveXrayWrapper.h | 3 + js/xpconnect/wrappers/XrayWrapper.cpp | 16 + js/xpconnect/wrappers/XrayWrapper.h | 2 + layout/base/nsDocumentViewer.cpp | 2 +- layout/base/nsLayoutUtils.h | 4 +- layout/base/nsPresContext.cpp | 4 +- layout/base/nsPresContext.h | 2 +- layout/base/nsPresShell.cpp | 6 +- layout/forms/nsComboboxControlFrame.cpp | 6 +- layout/forms/nsComboboxControlFrame.h | 2 +- layout/forms/nsFileControlFrame.h | 2 +- layout/forms/nsNumberControlFrame.cpp | 2 +- layout/forms/nsNumberControlFrame.h | 2 +- layout/forms/nsTextControlFrame.h | 4 +- layout/generic/Selection.h | 2 +- layout/generic/nsGfxScrollFrame.h | 7 +- layout/generic/nsPluginFrame.h | 2 +- layout/generic/nsSubDocumentFrame.cpp | 4 +- layout/generic/nsVideoFrame.cpp | 4 +- layout/printing/nsPagePrintTimer.cpp | 2 +- layout/printing/nsPagePrintTimer.h | 2 +- layout/printing/nsPrintEngine.cpp | 2 +- layout/style/ErrorReporter.cpp | 2 +- layout/svg/AutoReferenceLimiter.h | 2 +- layout/svg/SVGTextFrame.h | 2 +- layout/tables/nsTableFrame.cpp | 2 +- layout/xul/nsImageBoxFrame.cpp | 2 +- layout/xul/nsListBoxBodyFrame.h | 2 +- layout/xul/nsMenuBarFrame.cpp | 2 +- layout/xul/nsMenuFrame.cpp | 4 +- layout/xul/nsMenuPopupFrame.cpp | 2 +- layout/xul/nsMenuPopupFrame.h | 3 +- layout/xul/nsProgressMeterFrame.cpp | 2 +- layout/xul/nsSliderFrame.cpp | 4 +- layout/xul/nsXULPopupManager.h | 6 +- layout/xul/tree/nsTreeBodyFrame.cpp | 2 +- layout/xul/tree/nsTreeBodyFrame.h | 2 +- media/mtransport/nr_socket_prsock.cpp | 2 +- media/mtransport/runnable_utils.h | 2 +- media/mtransport/test/TestSyncRunnable.cpp | 2 +- .../test/runnable_utils_unittest.cpp | 8 +- .../test/sockettransportservice_unittest.cpp | 6 +- .../src/media-conduit/VideoConduit.cpp | 2 +- .../src/media-conduit/WebrtcGmpVideoCodec.h | 2 +- .../WebrtcMediaCodecVP8VideoCodec.cpp | 2 +- .../media-conduit/WebrtcOMXH264VideoCodec.cpp | 2 +- .../src/mediapipeline/MediaPipeline.h | 2 +- memory/mozalloc/mozalloc.h | 8 +- mfbt/AlreadyAddRefed.h | 4 +- mfbt/Assertions.h | 8 +- mfbt/Attributes.h | 24 +- mfbt/Endian.h | 24 +- mfbt/EnumSet.h | 153 +- mfbt/FloatingPoint.h | 2 +- mfbt/HashFunctions.h | 30 +- mfbt/Poison.h | 46 + mfbt/SegmentedVector.h | 2 +- mfbt/ThreadLocal.h | 2 +- mfbt/UniquePtr.h | 4 +- mfbt/Vector.h | 151 +- mfbt/tests/TestEnumSet.cpp | 40 + mfbt/tests/TestSegmentedVector.cpp | 2 +- mfbt/tests/TestVector.cpp | 134 +- modules/libpref/Preferences.cpp | 2 +- netwerk/base/BackgroundFileSaver.cpp | 2 +- netwerk/base/LoadInfo.cpp | 2 + netwerk/base/NetStatistics.h | 2 +- netwerk/base/NetworkActivityMonitor.cpp | 2 +- netwerk/base/Predictor.cpp | 6 +- netwerk/base/TLSServerSocket.cpp | 2 +- netwerk/base/Tickler.cpp | 2 +- netwerk/base/moz.build | 2 +- netwerk/base/nsAsyncRedirectVerifyHelper.cpp | 2 +- netwerk/base/nsAsyncStreamCopier.cpp | 2 +- netwerk/base/nsBaseChannel.cpp | 2 +- netwerk/base/nsBaseChannel.h | 2 +- netwerk/base/nsILoadInfo.idl | 13 +- netwerk/base/nsIOService.cpp | 4 +- netwerk/base/nsIncrementalStreamLoader.cpp | 4 +- netwerk/base/nsNetUtil.cpp | 2 +- netwerk/base/nsNetUtil.h | 4 +- .../{nsNetUtil.inl => nsNetUtilInlines.h} | 2 +- netwerk/base/nsPACMan.cpp | 10 +- netwerk/base/nsPACMan.h | 4 +- netwerk/base/nsPreloadedStream.cpp | 2 +- netwerk/base/nsRequestObserverProxy.h | 2 +- netwerk/base/nsServerSocket.cpp | 4 +- netwerk/base/nsSocketTransport2.cpp | 4 +- netwerk/base/nsStreamLoader.cpp | 2 +- netwerk/base/nsTransportUtils.cpp | 2 +- netwerk/base/nsUDPSocket.cpp | 14 +- netwerk/cache/nsCacheEntryDescriptor.cpp | 2 +- netwerk/cache/nsCacheService.cpp | 16 +- netwerk/cache/nsCacheService.h | 2 +- netwerk/cache/nsCacheUtils.cpp | 2 +- netwerk/cache/nsCacheUtils.h | 2 +- netwerk/cache/nsDeleteDir.cpp | 2 +- netwerk/cache/nsDiskCacheDevice.cpp | 4 +- netwerk/cache/nsDiskCacheDeviceSQL.cpp | 4 +- netwerk/cache2/CacheEntry.h | 6 +- netwerk/cache2/CacheFile.cpp | 4 +- netwerk/cache2/CacheFileChunk.cpp | 4 +- netwerk/cache2/CacheFileIOManager.cpp | 28 +- netwerk/cache2/CacheIndex.h | 2 +- netwerk/cache2/CacheStorageService.cpp | 14 +- netwerk/cache2/CacheStorageService.h | 4 +- netwerk/cache2/OldWrappers.cpp | 6 +- netwerk/cache2/OldWrappers.h | 4 +- netwerk/cookie/CookieServiceParent.cpp | 2 +- netwerk/cookie/CookieServiceParent.h | 2 +- netwerk/dns/DNSListenerProxy.h | 2 +- netwerk/dns/DNSRequestChild.cpp | 2 +- netwerk/dns/mdns/libmdns/MDNSResponderReply.h | 8 +- netwerk/dns/nsDNSService2.cpp | 2 +- netwerk/ipc/NeckoParent.h | 4 +- netwerk/ipc/RemoteOpenFileChild.cpp | 2 +- netwerk/protocol/app/AppProtocolHandler.cpp | 4 +- netwerk/protocol/file/nsFileChannel.cpp | 2 +- netwerk/protocol/ftp/FTPChannelParent.cpp | 2 +- netwerk/protocol/ftp/nsFTPChannel.cpp | 2 +- .../protocol/ftp/nsFtpConnectionThread.cpp | 4 +- netwerk/protocol/http/AlternateServices.cpp | 2 +- netwerk/protocol/http/Http2Push.cpp | 2 +- netwerk/protocol/http/Http2Session.cpp | 2 +- netwerk/protocol/http/HttpBaseChannel.cpp | 2 +- netwerk/protocol/http/HttpChannelChild.cpp | 2 +- netwerk/protocol/http/HttpChannelParent.cpp | 2 +- .../http/HttpChannelParentListener.cpp | 2 +- .../http/nsHttpActivityDistributor.cpp | 2 +- netwerk/protocol/http/nsHttpChannel.cpp | 2 +- netwerk/protocol/http/nsHttpConnection.cpp | 2 +- netwerk/protocol/http/nsHttpConnectionMgr.cpp | 2 +- netwerk/protocol/http/nsHttpTransaction.cpp | 4 +- netwerk/protocol/http/nsHttpTransaction.h | 2 +- .../protocol/websocket/WebSocketChannel.cpp | 4 +- .../websocket/WebSocketChannelChild.cpp | 8 +- .../websocket/WebSocketEventService.cpp | 2 +- netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp | 2 +- netwerk/sctp/datachannel/DataChannel.cpp | 4 +- netwerk/sctp/datachannel/DataChannel.h | 4 +- .../linux/nsNotifyAddrListener_Linux.cpp | 2 +- .../system/linux/nsNotifyAddrListener_Linux.h | 2 +- netwerk/system/win32/nsNotifyAddrListener.h | 2 +- parser/html/nsHtml5RefPtr.h | 2 +- parser/html/nsHtml5SVGLoadDispatcher.h | 2 +- parser/html/nsHtml5StreamParser.cpp | 12 +- parser/html/nsHtml5TreeOpExecutor.cpp | 2 +- parser/htmlparser/nsParser.cpp | 2 +- security/manager/ssl/CryptoTask.h | 2 +- security/manager/ssl/DataStorage.cpp | 4 +- security/manager/ssl/PSMRunnable.h | 4 +- .../manager/ssl/SSLServerCertVerification.cpp | 6 +- .../manager/ssl/nsCertVerificationThread.cpp | 2 +- security/manager/ssl/nsNSSCallbacks.cpp | 4 +- security/manager/ssl/nsNSSComponent.h | 2 +- security/manager/ssl/nsNSSIOLayer.cpp | 4 +- .../manager/ssl/nsPSMBackgroundThread.cpp | 2 +- security/sandbox/linux/Sandbox.cpp | 2 +- storage/StorageBaseStatementInternal.cpp | 4 +- storage/mozStorageAsyncStatementExecution.cpp | 6 +- storage/mozStorageConnection.cpp | 4 +- storage/mozStorageConnection.h | 2 +- storage/mozStoragePrivateHelpers.cpp | 2 +- storage/mozStorageService.cpp | 2 +- storage/test/storage_test_harness.h | 2 +- .../test_service_init_background_thread.cpp | 2 +- storage/test/test_unlock_notify.cpp | 2 +- testing/web-platform/meta/MANIFEST.json | 4 + .../XMLHttpRequest/abort-during-open.htm.ini | 5 - .../XMLHttpRequest/abort-event-abort.htm.ini | 5 - .../send-data-unexpected-tostring.htm.ini | 8 - .../meta/XMLHttpRequest/send-send.htm.ini | 5 - .../xmlhttprequest-unsent.htm.ini | 5 - .../XMLHttpRequest/abort-during-open.htm | 17 +- .../tests/XMLHttpRequest/abort-during-open.js | 14 + .../abort-during-open.worker.js | 3 + .../tests/XMLHttpRequest/send-send.htm | 10 +- .../tests/XMLHttpRequest/send-send.js | 7 + .../tests/XMLHttpRequest/send-send.worker.js | 3 + .../downloads/nsDownloadManager.cpp | 2 +- .../downloads/nsDownloadScanner.cpp | 2 +- .../components/downloads/nsDownloadScanner.h | 2 +- .../filewatcher/NativeFileWatcherWin.cpp | 10 +- .../FinalizationWitnessService.cpp | 2 +- .../osfile/NativeOSFileInternals.cpp | 6 +- .../components/places/AsyncFaviconHelpers.cpp | 2 +- .../components/places/AsyncFaviconHelpers.h | 2 +- toolkit/components/places/Helpers.cpp | 2 +- toolkit/components/places/Helpers.h | 4 +- toolkit/components/places/History.cpp | 18 +- toolkit/components/places/nsNavHistory.cpp | 2 +- .../tests/cpp/places_test_harness_tail.h | 2 +- .../satchel/nsFormFillController.cpp | 2 +- toolkit/components/startup/nsAppStartup.cpp | 2 +- toolkit/components/telemetry/Telemetry.cpp | 2 +- toolkit/components/url-classifier/Entries.h | 7 + toolkit/components/url-classifier/HashStore.h | 27 +- .../components/url-classifier/LookupCache.h | 7 + .../nsIUrlClassifierDBService.idl | 5 + .../nsUrlClassifierDBService.cpp | 25 +- .../url-classifier/nsUrlClassifierDBService.h | 3 + .../url-classifier/nsUrlClassifierProxies.cpp | 13 + .../url-classifier/nsUrlClassifierProxies.h | 42 +- toolkit/components/utils/simpleServices.js | 30 +- toolkit/crashreporter/InjectCrashReporter.h | 2 +- toolkit/crashreporter/nsExceptionHandler.cpp | 4 +- toolkit/identity/IdentityCryptoService.cpp | 10 +- toolkit/xre/ProfileReset.h | 4 +- toolkit/xre/nsEmbedFunctions.cpp | 2 +- tools/profiler/gecko/SaveProfileTask.h | 2 +- tools/profiler/gecko/ThreadResponsiveness.cpp | 5 +- view/nsView.cpp | 2 +- widget/PuppetWidget.h | 2 +- widget/nsBaseAppShell.cpp | 2 +- widget/nsBaseFilePicker.cpp | 2 +- widget/tests/TestAppShellSteadyState.cpp | 8 +- widget/windows/LSPAnnotator.cpp | 2 +- widget/windows/WidgetTraceEvent.cpp | 2 +- widget/windows/nsColorPicker.h | 2 +- widget/windows/nsNativeThemeWin.cpp | 4 +- widget/windows/nsSound.cpp | 4 +- xpcom/base/CycleCollectedJSRuntime.cpp | 6 +- xpcom/base/nsConsoleService.cpp | 4 +- xpcom/base/nsCycleCollector.cpp | 4 +- xpcom/base/nsMemoryInfoDumper.cpp | 6 +- xpcom/base/nsMemoryReporterManager.cpp | 2 +- xpcom/base/nsStatusReporterManager.cpp | 2 +- xpcom/components/nsCategoryManager.cpp | 2 +- xpcom/components/nsNativeModuleLoader.cpp | 2 +- xpcom/ds/Tokenizer.h | 22 +- xpcom/glue/nsBaseHashtable.h | 4 +- xpcom/glue/nsDeque.h | 4 +- xpcom/glue/nsProxyRelease.h | 2 +- xpcom/glue/nsRefPtrHashtable.h | 4 +- xpcom/glue/nsTArray.h | 42 +- xpcom/glue/nsTHashtable.h | 2 +- xpcom/glue/nsThreadUtils.cpp | 6 +- xpcom/glue/nsThreadUtils.h | 20 +- xpcom/io/nsAnonymousTemporaryFile.cpp | 2 +- xpcom/io/nsInputStreamTee.cpp | 2 +- xpcom/io/nsLocalFileWin.cpp | 4 +- xpcom/string/nsReadableUtils.h | 29 +- xpcom/string/nsTString.h | 12 +- xpcom/string/nsTSubstring.h | 100 +- xpcom/tests/TestRacingServiceManager.cpp | 8 +- xpcom/tests/TestThreadPoolListener.cpp | 2 +- xpcom/tests/TestThreadUtils.cpp | 2 +- xpcom/tests/TestTimers.cpp | 2 +- xpcom/tests/gtest/TestThreadPool.cpp | 6 +- xpcom/threads/LazyIdleThread.cpp | 2 +- xpcom/threads/MozPromise.h | 8 +- xpcom/threads/SyncRunnable.h | 2 +- xpcom/threads/TaskDispatcher.h | 2 +- xpcom/threads/TaskQueue.h | 2 +- xpcom/threads/TimerThread.cpp | 2 +- xpcom/threads/nsMemoryPressure.cpp | 2 +- xpcom/threads/nsThread.cpp | 11 +- xpcom/threads/nsThreadSyncDispatch.h | 2 +- xpfe/appshell/nsAppShellService.cpp | 2 +- xpfe/appshell/nsContentTreeOwner.cpp | 2 +- 863 files changed, 15904 insertions(+), 9408 deletions(-) create mode 100644 dom/media/webspeech/synth/test/startup/file_voiceschanged.html create mode 100644 dom/media/webspeech/synth/test/startup/mochitest.ini create mode 100644 dom/media/webspeech/synth/test/startup/test_voiceschanged.html rename dom/security/test/unit/{test_isURIPotentiallyTrustworthy.js => test_isOriginPotentiallyTrustworthy.js} (70%) delete mode 100644 dom/u2f/tests/facet/facetList-good delete mode 100644 dom/u2f/tests/facet/facetList-good^headers^ delete mode 100644 dom/u2f/tests/facet/facetList-invalid_format delete mode 100644 dom/u2f/tests/facet/facetList-invalid_format^headers^ delete mode 100644 dom/u2f/tests/facet/facetList-no_overlap delete mode 100644 dom/u2f/tests/facet/facetList-no_overlap^headers^ delete mode 100644 dom/u2f/tests/facet/facetList.txt delete mode 100644 dom/u2f/tests/test_frame_appid_facet_remoteload.html create mode 100644 js/src/asmjs/WasmBinaryIterator.cpp create mode 100644 js/src/asmjs/WasmBinaryIterator.h create mode 100644 js/src/devtools/gc-ubench/benchmarks/largeArrayPropertyAndElements.js create mode 100644 js/src/gc/StoreBuffer-inl.h create mode 100644 js/src/jit-test/tests/TypedObject/bug1265690.js create mode 100644 js/src/jit-test/tests/arrays/std_Array-prototype.js create mode 100644 js/src/jit-test/tests/asm.js/testBug1219098.js create mode 100644 js/src/jit-test/tests/parser/bug-1264568.js create mode 100644 js/src/jit/AliasAnalysisShared.cpp create mode 100644 js/src/jit/AliasAnalysisShared.h create mode 100644 js/src/jit/FlowAliasAnalysis.cpp create mode 100644 js/src/jit/FlowAliasAnalysis.h create mode 100644 js/src/jit/Linker.cpp create mode 100644 js/src/jsapi-tests/testPrivateGCThingValue.cpp create mode 100644 js/src/tests/ecma_6/Class/methodName.js create mode 100644 js/src/tests/ecma_6/Object/accessor-name.js create mode 100644 js/src/tests/ecma_6/Proxy/getPrototypeOf.js create mode 100644 js/src/tests/ecma_6/Proxy/setPrototypeOf.js delete mode 100644 js/xpconnect/idl/nsIRemoteTagService.idl rename netwerk/base/{nsNetUtil.inl => nsNetUtilInlines.h} (99%) delete mode 100644 testing/web-platform/meta/XMLHttpRequest/abort-during-open.htm.ini delete mode 100644 testing/web-platform/meta/XMLHttpRequest/abort-event-abort.htm.ini delete mode 100644 testing/web-platform/meta/XMLHttpRequest/send-data-unexpected-tostring.htm.ini delete mode 100644 testing/web-platform/meta/XMLHttpRequest/send-send.htm.ini delete mode 100644 testing/web-platform/meta/XMLHttpRequest/xmlhttprequest-unsent.htm.ini create mode 100644 testing/web-platform/tests/XMLHttpRequest/abort-during-open.js create mode 100644 testing/web-platform/tests/XMLHttpRequest/abort-during-open.worker.js create mode 100644 testing/web-platform/tests/XMLHttpRequest/send-send.js create mode 100644 testing/web-platform/tests/XMLHttpRequest/send-send.worker.js diff --git a/accessible/generic/Accessible.cpp b/accessible/generic/Accessible.cpp index 48b80bf0d8..521ed298e8 100644 --- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -1760,7 +1760,7 @@ Accessible::GetNativeInterface(void** aNativeAccessible) void Accessible::DoCommand(nsIContent *aContent, uint32_t aActionIndex) { - class Runnable final : public nsRunnable + class Runnable final : public mozilla::Runnable { public: Runnable(Accessible* aAcc, nsIContent* aContent, uint32_t aIdx) : diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index e2ef6239ff..0240a312aa 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -162,7 +162,7 @@ private: uint32_t AddSubtree(ProxyAccessible* aParent, const nsTArray& aNewTree, uint32_t aIdx, uint32_t aIdxInParent); - MOZ_WARN_UNUSED_RESULT bool CheckDocTree() const; + MOZ_MUST_USE bool CheckDocTree() const; xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy); nsTArray mChildDocs; diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index f2779bebb0..18bcf1ba56 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -334,7 +334,7 @@ static CustomTypeAnnotation HeapClass = static CustomTypeAnnotation NonTemporaryClass = CustomTypeAnnotation("moz_non_temporary_class", "non-temporary"); static CustomTypeAnnotation MustUse = - CustomTypeAnnotation("moz_must_use", "must-use"); + CustomTypeAnnotation("moz_must_use_type", "must-use"); class MemMoveAnnotation final : public CustomTypeAnnotation { public: diff --git a/build/clang-plugin/tests/TestMultipleAnnotations.cpp b/build/clang-plugin/tests/TestMultipleAnnotations.cpp index 37a43a5d2c..aa927259db 100644 --- a/build/clang-plugin/tests/TestMultipleAnnotations.cpp +++ b/build/clang-plugin/tests/TestMultipleAnnotations.cpp @@ -1,7 +1,7 @@ -#define MOZ_MUST_USE __attribute__((annotate("moz_must_use"))) +#define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type"))) #define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) -class MOZ_MUST_USE MOZ_STACK_CLASS TestClass {}; +class MOZ_MUST_USE_TYPE MOZ_STACK_CLASS TestClass {}; TestClass foo; // expected-error {{variable of type 'TestClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} diff --git a/build/clang-plugin/tests/TestMustUse.cpp b/build/clang-plugin/tests/TestMustUse.cpp index 03fcb063ce..91b16f9a09 100644 --- a/build/clang-plugin/tests/TestMustUse.cpp +++ b/build/clang-plugin/tests/TestMustUse.cpp @@ -1,6 +1,6 @@ -#define MOZ_MUST_USE __attribute__((annotate("moz_must_use"))) +#define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type"))) -class MOZ_MUST_USE MustUse {}; +class MOZ_MUST_USE_TYPE MustUse {}; class MayUse {}; MustUse producesMustUse(); diff --git a/caps/nsIScriptSecurityManager.idl b/caps/nsIScriptSecurityManager.idl index dced0afcd7..deea706b21 100644 --- a/caps/nsIScriptSecurityManager.idl +++ b/caps/nsIScriptSecurityManager.idl @@ -26,7 +26,7 @@ class DomainPolicyClone; [ptr] native JSObjectPtr(JSObject); [ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone); -[scriptable, uuid(b7ae2310-576e-11e5-a837-0800200c9a66)] +[scriptable, uuid(da831650-4241-4892-806c-cce8465a2ba8)] interface nsIScriptSecurityManager : nsISupports { /** @@ -240,6 +240,24 @@ interface nsIScriptSecurityManager : nsISupports */ nsIPrincipal getChannelResultPrincipal(in nsIChannel aChannel); + /** + * Temporary API until bug 1220687 is fixed. + * + * Returns the same value as getChannelResultPrincipal, but ignoring + * sandboxing. Specifically, if sandboxing would have prevented the + * channel's triggering principal from being returned by + * getChannelResultPrincipal, the triggering principal will be returned + * by this method. + * + * Note that this method only ignores sandboxing of the channel in + * question, it does not ignore sandboxing of any channels further up a + * document chain. The triggering principal itself may still be the null + * principal due to sandboxing further up a document chain. In that regard + * the ignoring of sandboxing is limited. + */ + [noscript, nostdcall] + nsIPrincipal getChannelResultPrincipalIfNotSandboxed(in nsIChannel aChannel); + /** * Get the codebase principal for the channel's URI. * aChannel must not be null. diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index afb9b2cc5f..7f0fb2afc2 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -11,6 +11,7 @@ #include "xpcprivate.h" #include "XPCWrapper.h" #include "nsIAppsService.h" +#include "nsIInputStreamChannel.h" #include "nsILoadContext.h" #include "nsIServiceManager.h" #include "nsIScriptObjectPrincipal.h" @@ -326,6 +327,23 @@ nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin) NS_IMETHODIMP nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel, nsIPrincipal** aPrincipal) +{ + return GetChannelResultPrincipal(aChannel, aPrincipal, + /*aIgnoreSandboxing*/ false); +} + +nsresult +nsScriptSecurityManager::GetChannelResultPrincipalIfNotSandboxed(nsIChannel* aChannel, + nsIPrincipal** aPrincipal) +{ + return GetChannelResultPrincipal(aChannel, aPrincipal, + /*aIgnoreSandboxing*/ true); +} + +nsresult +nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel, + nsIPrincipal** aPrincipal, + bool aIgnoreSandboxing) { NS_PRECONDITION(aChannel, "Must have channel!"); nsCOMPtr owner; @@ -341,7 +359,7 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel, nsCOMPtr loadInfo; aChannel->GetLoadInfo(getter_AddRefs(loadInfo)); if (loadInfo) { - if (loadInfo->GetLoadingSandboxed()) { + if (!aIgnoreSandboxing && loadInfo->GetLoadingSandboxed()) { RefPtr prin; if (loadInfo->LoadingPrincipal()) { prin = @@ -357,7 +375,17 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel, return NS_OK; } - if (loadInfo->GetForceInheritPrincipal()) { + bool forceInterit = loadInfo->GetForceInheritPrincipal(); + if (aIgnoreSandboxing && !forceInterit) { + // Check if SEC_FORCE_INHERIT_PRINCIPAL was dropped because of + // sandboxing: + if (loadInfo->GetLoadingSandboxed() && + (loadInfo->GetSecurityFlags() & + nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL_WAS_DROPPED)) { + forceInterit = true; + } + } + if (forceInterit) { NS_ADDREF(*aPrincipal = loadInfo->TriggeringPrincipal()); return NS_OK; } diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index 6fb58d86d2..b9265b090e 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -120,6 +120,10 @@ private: // If aURI is a moz-extension:// URI, set mAddonId to the associated addon. nsresult MaybeSetAddonIdFromURI(mozilla::OriginAttributes& aAttrs, nsIURI* aURI); + nsresult GetChannelResultPrincipal(nsIChannel* aChannel, + nsIPrincipal** aPrincipal, + bool aIgnoreSandboxing); + nsCOMPtr mSystemPrincipal; bool mPrefInitialized; bool mIsJavaScriptEnabled; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index e567b65143..a845b61720 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -9461,7 +9461,7 @@ nsDocShell::CopyFavicon(nsIURI* aOldURI, #endif } -class InternalLoadEvent : public nsRunnable +class InternalLoadEvent : public Runnable { public: InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI, @@ -13565,7 +13565,7 @@ nsDocShell::SelectNone(void) // link handling -class OnLinkClickEvent : public nsRunnable +class OnLinkClickEvent : public Runnable { public: OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent, diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 272fb6c869..15dfd353df 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -757,7 +757,7 @@ protected: public: // Event type dispatched by RestorePresentation - class RestorePresentationEvent : public nsRunnable + class RestorePresentationEvent : public mozilla::Runnable { public: NS_DECL_NSIRUNNABLE diff --git a/docshell/shistory/src/nsSHEntryShared.cpp b/docshell/shistory/src/nsSHEntryShared.cpp index fc5f4536c9..aafc101305 100644 --- a/docshell/shistory/src/nsSHEntryShared.cpp +++ b/docshell/shistory/src/nsSHEntryShared.cpp @@ -248,7 +248,7 @@ nsSHEntryShared::RemoveFromBFCacheSync() return NS_OK; } -class DestroyViewerEvent : public nsRunnable +class DestroyViewerEvent : public mozilla::Runnable { public: DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument) diff --git a/dom/archivereader/ArchiveEvent.h b/dom/archivereader/ArchiveEvent.h index 15b541f93e..92ac2774d0 100644 --- a/dom/archivereader/ArchiveEvent.h +++ b/dom/archivereader/ArchiveEvent.h @@ -49,7 +49,7 @@ protected: * This class runs in a different thread and it calls the 'exec()' method. * The exec() must populate mFileList and mStatus then it must call RunShare(); */ -class ArchiveReaderEvent : public nsRunnable +class ArchiveReaderEvent : public Runnable { public: NS_DECL_NSIRUNNABLE diff --git a/dom/archivereader/ArchiveRequest.cpp b/dom/archivereader/ArchiveRequest.cpp index fa40abf4d4..13cbedcd92 100644 --- a/dom/archivereader/ArchiveRequest.cpp +++ b/dom/archivereader/ArchiveRequest.cpp @@ -18,7 +18,7 @@ USING_ARCHIVEREADER_NAMESPACE /** * Class used to make asynchronous the ArchiveRequest. */ -class ArchiveRequestEvent : public nsRunnable +class ArchiveRequestEvent : public Runnable { public: NS_DECL_NSIRUNNABLE diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp index ccf20e5d44..b8c28437ed 100644 --- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -238,7 +238,7 @@ EvictEntries(nsIFile* aDirectory, const nsACString& aGroup, // FileDescriptorHolder owns a file descriptor and its memory mapping. // FileDescriptorHolder is derived by two runnable classes (that is, // (Parent|Child)Runnable. -class FileDescriptorHolder : public nsRunnable +class FileDescriptorHolder : public Runnable { public: FileDescriptorHolder() @@ -330,7 +330,7 @@ protected: }; class UnlockDirectoryRunnable final - : public nsRunnable + : public Runnable { RefPtr mDirectoryLock; diff --git a/dom/audiochannel/AudioChannelService.cpp b/dom/audiochannel/AudioChannelService.cpp index a4d10167e5..2ae78f563c 100644 --- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -43,7 +43,7 @@ namespace { bool sAudioChannelMutedByDefault = false; bool sXPCOMShuttingDown = false; -class NotifyChannelActiveRunnable final : public nsRunnable +class NotifyChannelActiveRunnable final : public Runnable { public: NotifyChannelActiveRunnable(uint64_t aWindowID, AudioChannel aAudioChannel, @@ -98,7 +98,7 @@ void NotifyChannelActive(uint64_t aWindowID, AudioChannel aAudioChannel, bool aActive) { - RefPtr runnable = + RefPtr runnable = new NotifyChannelActiveRunnable(aWindowID, aAudioChannel, aActive); NS_DispatchToCurrentThread(runnable); } @@ -122,7 +122,7 @@ IsParentProcess() return XRE_GetProcessType() == GeckoProcessType_Default; } -class MediaPlaybackRunnable : public nsRunnable +class MediaPlaybackRunnable : public Runnable { public: MediaPlaybackRunnable(nsIDOMWindow* aWindow, bool aActive) diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index b4091f6535..c2465e9a9b 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -311,7 +311,7 @@ private: JSContext* mCx; }; -class ConsoleRunnable : public nsRunnable +class ConsoleRunnable : public Runnable , public WorkerFeature , public StructuredCloneHolderBase { diff --git a/dom/base/DOMRequest.cpp b/dom/base/DOMRequest.cpp index 92531cc73e..4e8683f573 100644 --- a/dom/base/DOMRequest.cpp +++ b/dom/base/DOMRequest.cpp @@ -296,7 +296,7 @@ DOMRequestService::FireDetailedError(nsIDOMDOMRequest* aRequest, return NS_OK; } -class FireSuccessAsyncTask : public nsRunnable +class FireSuccessAsyncTask : public mozilla::Runnable { FireSuccessAsyncTask(DOMRequest* aRequest, @@ -333,7 +333,7 @@ private: JS::PersistentRooted mResult; }; -class FireErrorAsyncTask : public nsRunnable +class FireErrorAsyncTask : public mozilla::Runnable { public: FireErrorAsyncTask(DOMRequest* aRequest, diff --git a/dom/base/Element.h b/dom/base/Element.h index 09ed24068a..bfed799cf9 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -1366,7 +1366,7 @@ private: EventStates mState; }; -class RemoveFromBindingManagerRunnable : public nsRunnable +class RemoveFromBindingManagerRunnable : public mozilla::Runnable { public: RemoveFromBindingManagerRunnable(nsBindingManager* aManager, diff --git a/dom/base/File.cpp b/dom/base/File.cpp index b729381513..ad9d2a1798 100644 --- a/dom/base/File.cpp +++ b/dom/base/File.cpp @@ -866,7 +866,7 @@ BlobImplFile::GetSize(ErrorResult& aRv) namespace { -class GetTypeRunnable final : public nsRunnable +class GetTypeRunnable final : public Runnable { public: GetTypeRunnable(WorkerPrivate* aWorkerPrivate, diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 8a845847eb..dbf4240850 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -1237,7 +1237,7 @@ FragmentOrElement::FireNodeInserted(nsIDocument* aDoc, #define SUBTREE_UNBINDINGS_PER_RUNNABLE 500 -class ContentUnbinder : public nsRunnable +class ContentUnbinder : public Runnable { public: ContentUnbinder() diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h index dc29fc63fa..bf7f5ef02c 100644 --- a/dom/base/FragmentOrElement.h +++ b/dom/base/FragmentOrElement.h @@ -142,7 +142,7 @@ public: virtual bool TextIsOnlyWhitespace() override; virtual bool HasTextForTranslation() override; virtual void AppendTextTo(nsAString& aResult) override; - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) override; virtual nsIContent *GetBindingParent() const override; virtual nsXBLBinding *GetXBLBinding() const override; diff --git a/dom/base/ImageEncoder.cpp b/dom/base/ImageEncoder.cpp index 113dcf0623..706e258978 100644 --- a/dom/base/ImageEncoder.cpp +++ b/dom/base/ImageEncoder.cpp @@ -26,7 +26,7 @@ namespace dom { // This class should be placed inside GetBRGADataSourceSurfaceSync(). However, // due to B2G ICS uses old complier (C++98/03) which forbids local class as // template parameter, we need to move this class outside. -class SurfaceHelper : public nsRunnable { +class SurfaceHelper : public Runnable { public: explicit SurfaceHelper(already_AddRefed aImage) : mImage(aImage) {} @@ -135,7 +135,7 @@ private: bool mFailed; }; -class EncodingRunnable : public nsRunnable +class EncodingRunnable : public Runnable { virtual ~EncodingRunnable() {} @@ -236,7 +236,7 @@ private: bool mUsingCustomOptions; }; -NS_IMPL_ISUPPORTS_INHERITED0(EncodingRunnable, nsRunnable); +NS_IMPL_ISUPPORTS_INHERITED0(EncodingRunnable, Runnable); StaticRefPtr ImageEncoder::sThreadPool; diff --git a/dom/base/ImportManager.cpp b/dom/base/ImportManager.cpp index db6f51aaa1..2f5fdcd708 100644 --- a/dom/base/ImportManager.cpp +++ b/dom/base/ImportManager.cpp @@ -378,7 +378,7 @@ ImportLoader::RemoveLinkElement(nsINode* aNode) // be set on the link element before the load event is fired even // if ImportLoader::Get returns an already loaded import and we // fire the load event immediately on the new referring link element. -class AsyncEvent : public nsRunnable { +class AsyncEvent : public Runnable { public: AsyncEvent(nsINode* aNode, bool aSuccess) : mNode(aNode) diff --git a/dom/base/PostMessageEvent.h b/dom/base/PostMessageEvent.h index 96b4f3768e..c1d95e6657 100644 --- a/dom/base/PostMessageEvent.h +++ b/dom/base/PostMessageEvent.h @@ -25,7 +25,7 @@ namespace dom { * Class used to represent events generated by calls to Window.postMessage, * which asynchronously creates and dispatches events. */ -class PostMessageEvent final : public nsRunnable +class PostMessageEvent final : public Runnable , public StructuredCloneHolder { public: diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp index 14fc2e1fbc..6f41912a50 100644 --- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -390,7 +390,7 @@ WebSocketImpl::PrintErrorOnConsole(const char *aBundleURI, namespace { -class CancelWebSocketRunnable final : public nsRunnable +class CancelWebSocketRunnable final : public Runnable { public: CancelWebSocketRunnable(nsIWebSocketChannel* aChannel, uint16_t aReasonCode, @@ -438,7 +438,7 @@ private: WebSocketImpl* mImpl; }; -class CloseConnectionRunnable final : public nsRunnable +class CloseConnectionRunnable final : public Runnable { public: CloseConnectionRunnable(WebSocketImpl* aImpl, @@ -467,9 +467,9 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode, const nsACString& aReasonString) { if (!IsTargetThread()) { - RefPtr runnable = + nsCOMPtr runnable = new CloseConnectionRunnable(this, aReasonCode, aReasonString); - return Dispatch(runnable, NS_DISPATCH_NORMAL); + return Dispatch(runnable.forget(), NS_DISPATCH_NORMAL); } AssertIsOnTargetThread(); diff --git a/dom/base/WindowNamedPropertiesHandler.h b/dom/base/WindowNamedPropertiesHandler.h index e17010d7d4..628a27b608 100644 --- a/dom/base/WindowNamedPropertiesHandler.h +++ b/dom/base/WindowNamedPropertiesHandler.h @@ -36,6 +36,11 @@ public: virtual bool delete_(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, JS::ObjectOpResult &aResult) const override; + + // No need for getPrototypeIfOrdinary here: this object shouldn't have a + // lazy prototype, so this trap would never be called (and the inherited + // version, from BaseProxyHandler, just crashes). + virtual bool preventExtensions(JSContext* aCx, JS::Handle aProxy, JS::ObjectOpResult& aResult) const override diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index fe5f5cfa74..272d4aaada 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -4719,7 +4719,7 @@ nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode, return nodeAsContent->GetBindingParent() == aContent->GetBindingParent(); } -class AnonymousContentDestroyer : public nsRunnable { +class AnonymousContentDestroyer : public Runnable { public: explicit AnonymousContentDestroyer(nsCOMPtr* aContent) { mContent.swap(*aContent); diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 279cf34a22..0c0634d13f 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1375,7 +1375,7 @@ public: * @param aResult the result. Out param. * @return false on out of memory errors, true otherwise. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static bool GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult, const mozilla::fallible_t&); @@ -1747,7 +1747,7 @@ public: */ static bool CanAccessNativeAnon(); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static nsresult WrapNative(JSContext *cx, nsISupports *native, const nsIID* aIID, JS::MutableHandle vp, bool aAllowWrapping = true) @@ -1756,7 +1756,7 @@ public: } // Same as the WrapNative above, but use this one if aIID is nsISupports' IID. - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static nsresult WrapNative(JSContext *cx, nsISupports *native, JS::MutableHandle vp, bool aAllowWrapping = true) @@ -1764,7 +1764,7 @@ public: return WrapNative(cx, native, nullptr, nullptr, vp, aAllowWrapping); } - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static nsresult WrapNative(JSContext *cx, nsISupports *native, nsWrapperCache *cache, JS::MutableHandle vp, @@ -1797,7 +1797,7 @@ public: * @param aString the string to convert the newlines inside [in/out] */ static void PlatformToDOMLineBreaks(nsString &aString); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static bool PlatformToDOMLineBreaks(nsString &aString, const mozilla::fallible_t&); diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp index 1a65cf2051..b1acacfba4 100644 --- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -855,7 +855,7 @@ nsDOMMutationObserver::HandleMutation() mCallback->Call(this, mutations, *this); } -class AsyncMutationHandler : public nsRunnable +class AsyncMutationHandler : public mozilla::Runnable { public: NS_IMETHOD Run() diff --git a/dom/base/nsDocElementCreatedNotificationRunner.h b/dom/base/nsDocElementCreatedNotificationRunner.h index 834c0f2edf..1e53c3dd0b 100644 --- a/dom/base/nsDocElementCreatedNotificationRunner.h +++ b/dom/base/nsDocElementCreatedNotificationRunner.h @@ -14,7 +14,7 @@ #include "nsCOMPtr.h" #include "nsIDocument.h" -class nsDocElementCreatedNotificationRunner : public nsRunnable +class nsDocElementCreatedNotificationRunner : public mozilla::Runnable { public: explicit nsDocElementCreatedNotificationRunner(nsIDocument* aDoc) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index b9280c095a..66cabedfd3 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1358,7 +1358,7 @@ void nsIDocument::SelectorCache::CacheList(const nsAString& aSelector, AddObject(key); } -class nsIDocument::SelectorCacheKeyDeleter final : public nsRunnable +class nsIDocument::SelectorCacheKeyDeleter final : public Runnable { public: explicit SelectorCacheKeyDeleter(SelectorCacheKey* aToDelete) @@ -9115,7 +9115,7 @@ nsDocument::UnblockOnload(bool aFireSync) } } -class nsUnblockOnloadEvent : public nsRunnable { +class nsUnblockOnloadEvent : public Runnable { public: explicit nsUnblockOnloadEvent(nsDocument* aDoc) : mDoc(aDoc) {} NS_IMETHOD Run() { @@ -9973,7 +9973,7 @@ nsDocument::LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet, return CSSLoader()->LoadSheetSync(uri, mode, isAgentSheet, aSheet); } -class nsDelayedEventDispatcher : public nsRunnable +class nsDelayedEventDispatcher : public Runnable { public: explicit nsDelayedEventDispatcher(nsTArray>& aDocuments) @@ -11136,7 +11136,7 @@ nsIDocument::MozCancelFullScreen() // run script. nsGlobalWindow::SetFullScreen() dispatches a synchronous event // (handled in chome code) which is unsafe to run if this is called in // Element::UnbindFromTree(). -class nsSetWindowFullScreen : public nsRunnable { +class nsSetWindowFullScreen : public Runnable { public: nsSetWindowFullScreen(nsIDocument* aDoc, bool aValue, gfx::VRDeviceProxy* aHMD = nullptr) : mDoc(aDoc), mValue(aValue), mHMD(aHMD) {} @@ -11186,7 +11186,7 @@ SetWindowFullScreen(nsIDocument* aDoc, bool aValue, gfx::VRDeviceProxy *aVRHMD = } } -class nsCallExitFullscreen : public nsRunnable { +class nsCallExitFullscreen : public Runnable { public: explicit nsCallExitFullscreen(nsIDocument* aDoc) : mDoc(aDoc) {} @@ -11521,7 +11521,7 @@ FullScreenOptions::FullScreenOptions() { } -class nsCallRequestFullScreen : public nsRunnable +class nsCallRequestFullScreen : public Runnable { public: explicit nsCallRequestFullScreen(Element* aElement, FullScreenOptions& aOptions) @@ -12104,8 +12104,8 @@ nsDocument::IsFullScreenEnabled(bool aCallerIsChrome, bool aLogFailure) if (nsContentUtils::IsFullScreenApiEnabled() && aCallerIsChrome) { // Chrome code can always use the full-screen API, provided it's not // explicitly disabled. Note IsCallerChrome() returns true when running - // in an nsRunnable, so don't use GetMozFullScreenEnabled() from an - // nsRunnable! + // in an Runnable, so don't use GetMozFullScreenEnabled() from an + // Runnable! return true; } @@ -12199,7 +12199,7 @@ static const uint8_t kPointerLockRequestLimit = 2; mozilla::StaticRefPtr gPendingPointerLockRequest; -class nsPointerLockPermissionRequest : public nsRunnable, +class nsPointerLockPermissionRequest : public Runnable, public nsIContentPermissionRequest { public: @@ -12276,7 +12276,7 @@ protected: }; NS_IMPL_ISUPPORTS_INHERITED(nsPointerLockPermissionRequest, - nsRunnable, + Runnable, nsIContentPermissionRequest) NS_IMETHODIMP diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index af5f516f74..d22a65e694 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1971,7 +1971,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow, mFirstFocusEvent = nullptr; } -class FocusBlurEvent : public nsRunnable +class FocusBlurEvent : public Runnable { public: FocusBlurEvent(nsISupports* aTarget, EventMessage aEventMessage, @@ -3425,7 +3425,7 @@ nsFocusManager::GetFocusInSelection(nsPIDOMWindow* aWindow, while (selectionNode && selectionNode != endSelectionNode); } -class PointerUnlocker : public nsRunnable +class PointerUnlocker : public Runnable { public: PointerUnlocker() diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 652297d71e..81b32e4c99 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -1412,7 +1412,7 @@ nsFrameLoader::Destroy() return NS_OK; } -class nsFrameLoaderDestroyRunnable : public nsRunnable +class nsFrameLoaderDestroyRunnable : public Runnable { enum DestroyPhase { @@ -2528,7 +2528,7 @@ nsFrameLoader::DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlob } class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase, - public nsRunnable + public Runnable { public: nsAsyncMessageToChild(JSContext* aCx, JS::Handle aCpows, nsFrameLoader* aFrameLoader) diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 0474edb093..11cf4de6f4 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1890,7 +1890,7 @@ nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr; nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr; class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase, - public nsRunnable + public Runnable { public: nsAsyncMessageToSameProcessChild(JSContext* aCx, JS::Handle aCpows) diff --git a/dom/base/nsFrameMessageManager.h b/dom/base/nsFrameMessageManager.h index 73748c7ff0..e27648e7fa 100644 --- a/dom/base/nsFrameMessageManager.h +++ b/dom/base/nsFrameMessageManager.h @@ -317,7 +317,7 @@ private: /* A helper class for taking care of many details for async message sending within a single process. Intended to be used like so: - class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public nsRunnable + class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public Runnable { NS_IMETHOD Run() { ReceiveMessage(..., ...); diff --git a/dom/base/nsGenericDOMDataNode.h b/dom/base/nsGenericDOMDataNode.h index 38153152ec..6d8fcb357c 100644 --- a/dom/base/nsGenericDOMDataNode.h +++ b/dom/base/nsGenericDOMDataNode.h @@ -146,7 +146,7 @@ public: virtual bool TextIsOnlyWhitespace() override; virtual bool HasTextForTranslation() override; virtual void AppendTextTo(nsAString& aResult) override; - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) override; virtual void SaveSubtreeState() override; diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index caeed4e12c..b56ff88ebb 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -12,6 +12,7 @@ // Local Includes #include "Navigator.h" +#include "nsContentSecurityManager.h" #include "nsScreen.h" #include "nsHistory.h" #include "nsPerformance.h" @@ -669,6 +670,12 @@ public: virtual bool delete_(JSContext *cx, JS::Handle proxy, JS::Handle id, JS::ObjectOpResult &aResult) const override; + + virtual bool getPrototypeIfOrdinary(JSContext* cx, + JS::Handle proxy, + bool* isOrdinary, + JS::MutableHandle protop) const override; + virtual bool enumerate(JSContext *cx, JS::Handle proxy, JS::MutableHandle vp) const override; virtual bool preventExtensions(JSContext* cx, @@ -894,6 +901,27 @@ nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle proxy, return js::Wrapper::delete_(cx, proxy, id, result); } +bool +nsOuterWindowProxy::getPrototypeIfOrdinary(JSContext* cx, + JS::Handle proxy, + bool* isOrdinary, + JS::MutableHandle protop) const +{ + // Window's [[GetPrototypeOf]] trap isn't the ordinary definition: + // + // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof + // + // We nonetheless can implement it here using a non-"lazy" [[Prototype]], + // because wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) + // supply all the non-ordinary behavior. + // + // But from a spec point of view, it's the exact same object in both cases -- + // only the observer's changed. So both cases *must* report non-ordinary, + // even if non-"lazy" [[Prototype]] usually means ordinary. + *isOrdinary = false; + return true; +} + bool nsOuterWindowProxy::preventExtensions(JSContext* cx, JS::Handle proxy, @@ -1138,6 +1166,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mInClose(false), mHavePendingClose(false), mHadOriginalOpener(false), + mOriginalOpenerWasSecureContext(false), mIsPopupSpam(false), mBlockScriptedClosingFlag(false), mWasOffline(false), @@ -2291,6 +2320,165 @@ InitializeLegacyNetscapeObject(JSContext* aCx, JS::Handle aGlobal) return JS_DefineFunctions(aCx, obj, EnablePrivilegeSpec); } +/** + * Returns true if the "HTTPS state" of the document should be "modern". See: + * + * https://html.spec.whatwg.org/#concept-document-https-state + * https://fetch.spec.whatwg.org/#concept-response-https-state + * + * Note: this function only relates to figuring out HTTPS state, which is an + * input to the Secure Context algorithm. We are not actually implementing any + * part of the Secure Context algorithm itself here. + * + * This is a bit of a hack. Ideally we'd propagate HTTPS state through + * nsIChannel as described in the Fetch and HTML specs, but making channels + * know about whether they should inherit HTTPS state, propagating information + * about who the channel's "client" is, exposing GetHttpsState API on channels + * and modifying the various cache implementations to store and retrieve HTTPS + * state involves a huge amount of code (see bug 1220687). We avoid that for + * now using this function. + * + * This function takes advantage of the observation that we can return true if + * nsIContentSecurityManager::IsOriginPotentiallyTrustworthy returns true for + * the document's origin (e.g. the origin has a scheme of 'https' or host + * 'localhost' etc.). Since we generally propagate a creator document's origin + * onto data:, blob:, etc. documents, this works for them too. + * + * The scenario where this observation breaks down is sandboxing without the + * 'allow-same-origin' flag, since in this case a document is given a unique + * origin (IsOriginPotentiallyTrustworthy would return false). We handle that + * by using the origin that the document would have had had it not been + * sandboxed. + * + * DEFICIENCIES: Note that this function uses nsIScriptSecurityManager's + * getChannelResultPrincipalIfNotSandboxed, and that method's ignoring of + * sandboxing is limited to the immediate sandbox. In the case that aDocument + * should inherit its origin (e.g. data: URI) but its parent has ended up + * with a unique origin due to sandboxing further up the parent chain we may + * end up returning false when we would ideally return true (since we will + * examine the parent's origin for 'https' and not finding it.) This means + * that we may restrict the privileges of some pages unnecessarily in this + * edge case. + */ +static bool HttpsStateIsModern(nsIDocument* aDocument) +{ + nsCOMPtr principal = aDocument->NodePrincipal(); + + // If aDocument is sandboxed, try and get the principal that it would have + // been given had it not been sandboxed: + if (principal->GetIsNullPrincipal() && + (aDocument->GetSandboxFlags() & SANDBOXED_ORIGIN)) { + nsIChannel* channel = aDocument->GetChannel(); + if (channel) { + nsCOMPtr ssm = + nsContentUtils::GetSecurityManager(); + nsresult rv = + ssm->GetChannelResultPrincipalIfNotSandboxed(channel, + getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + return false; + } + } + } + + if (principal->GetIsNullPrincipal()) { + return false; + } + + MOZ_ASSERT(principal->GetIsCodebasePrincipal()); + + nsCOMPtr csm = + do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID); + NS_WARN_IF(!csm); + if (csm) { + bool isTrustworthyOrigin = false; + csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin); + if (isTrustworthyOrigin) { + return true; + } + } + + return false; +} + +bool +nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument) +{ + MOZ_ASSERT(IsOuterWindow()); + + nsCOMPtr principal = aDocument->NodePrincipal(); + if (nsContentUtils::IsSystemPrincipal(principal)) { + return true; + } + + // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object + + bool hadNonSecureContextCreator = false; + + nsPIDOMWindow* parentOuterWin = GetScriptableParent(); + MOZ_ASSERT(parentOuterWin, "How can we get here? No docShell somehow?"); + if (nsGlobalWindow::Cast(parentOuterWin) != this) { + // There may be a small chance that parentOuterWin has navigated in + // the time that it took us to start loading this sub-document. If that + // were the case then parentOuterWin->GetCurrentInnerWindow() wouldn't + // return the window for the document that is embedding us. For this + // reason we only use the GetScriptableParent call above to check that we + // have a same-type parent, but actually get the inner window via the + // document that we know is embedding us. + nsIDocument* creatorDoc = aDocument->GetParentDocument(); + if (!creatorDoc) { + return false; // we must be tearing down + } + nsGlobalWindow* parentWin = + nsGlobalWindow::Cast(creatorDoc->GetInnerWindow()); + if (!parentWin) { + return false; // we must be tearing down + } + MOZ_ASSERT(parentWin == + nsGlobalWindow::Cast(parentOuterWin->GetCurrentInnerWindow()), + "Creator window mismatch while setting Secure Context state"); + hadNonSecureContextCreator = !parentWin->IsSecureContext(); + } else if (mHadOriginalOpener) { + hadNonSecureContextCreator = !mOriginalOpenerWasSecureContext; + } + + if (hadNonSecureContextCreator) { + return false; + } + + if (HttpsStateIsModern(aDocument)) { + return true; + } + + if (principal->GetIsNullPrincipal()) { + nsCOMPtr uri = aDocument->GetOriginalURI(); + // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so + // it doesn't actually matter what we use here, but reusing the document + // principal's attributes is convenient. + const OriginAttributes& attrs = + BasePrincipal::Cast(principal)->OriginAttributesRef(); + // CreateCodebasePrincipal correctly gets a useful principal for blob: and + // other URI_INHERITS_SECURITY_CONTEXT URIs. + principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs); + if (NS_WARN_IF(!principal)) { + return false; + } + } + + nsCOMPtr csm = + do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID); + NS_WARN_IF(!csm); + if (csm) { + bool isTrustworthyOrigin = false; + csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin); + if (isTrustworthyOrigin) { + return true; + } + } + + return false; +} + /** * Create a new global object that will be used for an inner window. * Return the native global and an nsISupports 'holder' that can be used @@ -2301,7 +2489,8 @@ CreateNativeGlobalForInner(JSContext* aCx, nsGlobalWindow* aNewInner, nsIURI* aURI, nsIPrincipal* aPrincipal, - JS::MutableHandle aGlobal) + JS::MutableHandle aGlobal, + bool aIsSecureContext) { MOZ_ASSERT(aCx); MOZ_ASSERT(aNewInner); @@ -2331,6 +2520,8 @@ CreateNativeGlobalForInner(JSContext* aCx, options.creationOptions().setSameZoneAs(top->GetGlobalJSObject()); } + options.creationOptions().setSecureContext(aIsSecureContext); + xpc::InitGlobalObjectOptions(options, aPrincipal); // Determine if we need the Components object. @@ -2559,7 +2750,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, rv = CreateNativeGlobalForInner(cx, newInnerWindow, aDocument->GetDocumentURI(), aDocument->NodePrincipal(), - &newInnerGlobal); + &newInnerGlobal, + ComputeIsSecureContext(aDocument)); NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal, "Failed to get script global"); @@ -3007,7 +3199,11 @@ nsGlobalWindow::SetOpenerWindow(nsPIDOMWindow* aOpener, NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!"); if (aOriginalOpener) { + MOZ_ASSERT(!mHadOriginalOpener, + "Probably too late to call ComputeIsSecureContext again"); mHadOriginalOpener = true; + mOriginalOpenerWasSecureContext = + nsGlobalWindow::Cast(aOpener->GetCurrentInnerWindow())->IsSecureContext(); } #ifdef DEBUG @@ -8580,7 +8776,7 @@ nsGlobalWindow::PostMessageMoz(JS::Handle aMessage, return rv.StealNSResult(); } -class nsCloseEvent : public nsRunnable { +class nsCloseEvent : public Runnable { RefPtr mWindow; bool mIndirect; @@ -8959,7 +9155,7 @@ nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow, } } -class nsPendingTimeoutRunner : public nsRunnable +class nsPendingTimeoutRunner : public Runnable { public: explicit nsPendingTimeoutRunner(nsGlobalWindow* aWindow) @@ -9059,7 +9255,7 @@ struct BrowserCompartmentMatcher : public js::CompartmentFilter { }; -class WindowDestroyedEvent : public nsRunnable +class WindowDestroyedEvent : public Runnable { public: WindowDestroyedEvent(nsPIDOMWindow* aWindow, uint64_t aID, @@ -9542,7 +9738,7 @@ nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs_, return rv.StealNSResult(); } -class ChildCommandDispatcher : public nsRunnable +class ChildCommandDispatcher : public Runnable { public: ChildCommandDispatcher(nsGlobalWindow* aWindow, @@ -9572,7 +9768,7 @@ private: nsString mAction; }; -class CommandDispatcher : public nsRunnable +class CommandDispatcher : public Runnable { public: CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher, @@ -10416,7 +10612,7 @@ nsGlobalWindow::PageHidden() mNeedsFocus = true; } -class HashchangeCallback : public nsRunnable +class HashchangeCallback : public Runnable { public: HashchangeCallback(const nsAString &aOldURL, @@ -11085,7 +11281,7 @@ nsGlobalWindow::FireOfflineStatusEventIfChanged() nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, true, false); } -class NotifyIdleObserverRunnable : public nsRunnable +class NotifyIdleObserverRunnable : public Runnable { public: NotifyIdleObserverRunnable(nsIIdleObserver* aIdleObserver, @@ -14494,6 +14690,14 @@ nsGlobalWindow::GetConsole(ErrorResult& aRv) return mConsole; } +bool +nsGlobalWindow::IsSecureContext() const +{ + MOZ_RELEASE_ASSERT(IsInnerWindow()); + + return JS_GetIsSecureContext(js::GetObjectCompartment(GetWrapperPreserveColor())); +} + already_AddRefed nsGlobalWindow::GetExternal(ErrorResult& aRv) { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 916b68cef1..d0b0fedbf1 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -885,6 +885,9 @@ public: mozilla::dom::Console* GetConsole(mozilla::ErrorResult& aRv); + // https://w3c.github.io/webappsec-secure-contexts/#dom-window-issecurecontext + bool IsSecureContext() const; + void GetSidebar(mozilla::dom::OwningExternalOrWindowProxy& aResult, mozilla::ErrorResult& aRv); already_AddRefed GetExternal(mozilla::ErrorResult& aRv); @@ -1613,6 +1616,10 @@ private: void DisconnectEventTargetObjects(); + // Called only on outer windows to compute the value that will be returned by + // IsSecureContext() for the inner window that corresponds to aDocument. + bool ComputeIsSecureContext(nsIDocument* aDocument); + protected: // This member is also used on both inner and outer windows, but // for slightly different purposes. On inner windows it means the @@ -1633,6 +1640,7 @@ protected: // event posted. If this is set, just ignore window.close() calls. bool mHavePendingClose : 1; bool mHadOriginalOpener : 1; + bool mOriginalOpenerWasSecureContext : 1; bool mIsPopupSpam : 1; // Indicates whether scripts are allowed to close this window. diff --git a/dom/base/nsHTMLContentSerializer.h b/dom/base/nsHTMLContentSerializer.h index 8539eadb86..6f3500e012 100644 --- a/dom/base/nsHTMLContentSerializer.h +++ b/dom/base/nsHTMLContentSerializer.h @@ -37,7 +37,7 @@ class nsHTMLContentSerializer final : public nsXHTMLContentSerializer { nsAString& aStr) override; protected: - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool SerializeHTMLAttributes(nsIContent* aContent, nsIContent *aOriginalElement, nsAString& aTagPrefix, @@ -46,7 +46,7 @@ class nsHTMLContentSerializer final : public nsXHTMLContentSerializer { int32_t aNamespace, nsAString& aStr); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool AppendAndTranslateEntities(const nsAString& aStr, nsAString& aOutputStr) override; diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h index f7cab4f7ec..058052f33a 100644 --- a/dom/base/nsIContent.h +++ b/dom/base/nsIContent.h @@ -558,7 +558,7 @@ public: * Append the text content to aResult. * NOTE: This asserts and returns for elements */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) = 0; /** diff --git a/dom/base/nsIGlobalObject.cpp b/dom/base/nsIGlobalObject.cpp index 62c51ceb36..cc89972fec 100644 --- a/dom/base/nsIGlobalObject.cpp +++ b/dom/base/nsIGlobalObject.cpp @@ -39,7 +39,7 @@ nsIGlobalObject::UnregisterHostObjectURI(const nsACString& aURI) namespace { -class UnlinkHostObjectURIsRunnable final : public nsRunnable +class UnlinkHostObjectURIsRunnable final : public mozilla::Runnable { public: explicit UnlinkHostObjectURIsRunnable(nsTArray& aURIs) diff --git a/dom/base/nsInProcessTabChildGlobal.cpp b/dom/base/nsInProcessTabChildGlobal.cpp index 95ce868eb6..20ee4a56f7 100644 --- a/dom/base/nsInProcessTabChildGlobal.cpp +++ b/dom/base/nsInProcessTabChildGlobal.cpp @@ -306,7 +306,7 @@ nsInProcessTabChildGlobal::InitTabChildGlobal() return NS_OK; } -class nsAsyncScriptLoad : public nsRunnable +class nsAsyncScriptLoad : public Runnable { public: nsAsyncScriptLoad(nsInProcessTabChildGlobal* aTabChild, const nsAString& aURL, diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 3b35c651e6..ed35445aa0 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -419,7 +419,7 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal, return called; } -class ScriptErrorEvent : public nsRunnable +class ScriptErrorEvent : public Runnable { public: ScriptErrorEvent(nsPIDOMWindow* aWindow, @@ -2180,7 +2180,7 @@ nsJSContext::KillICCTimer() } } -class NotifyGCEndRunnable : public nsRunnable +class NotifyGCEndRunnable : public Runnable { nsString mMessage; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index 71ab2cc7b1..3c28b2eb8a 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -189,7 +189,7 @@ nsScriptNameSpaceManager* GetNameSpaceManager(); nsScriptNameSpaceManager* PeekNameSpaceManager(); // Runnable that's used to do async error reporting -class AsyncErrorReporter final : public nsRunnable +class AsyncErrorReporter final : public mozilla::Runnable { public: // aWindow may be null if this error report is not associated with a window diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index a1ea750f9b..c37ef5e9ff 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -140,7 +140,7 @@ InActiveDocument(nsIContent *aContent) /// Runnables and helper classes /// -class nsAsyncInstantiateEvent : public nsRunnable { +class nsAsyncInstantiateEvent : public Runnable { public: explicit nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent) : mContent(aContent) {} @@ -173,7 +173,7 @@ nsAsyncInstantiateEvent::Run() // (outside an active document) or stopped (in a document but unrendered). This // is used to allow scripts to move a plugin around the document hierarchy // without re-instantiating it. -class CheckPluginStopEvent : public nsRunnable { +class CheckPluginStopEvent : public Runnable { public: explicit CheckPluginStopEvent(nsObjectLoadingContent* aContent) : mContent(aContent) {} @@ -248,7 +248,7 @@ CheckPluginStopEvent::Run() /** * Helper task for firing simple events */ -class nsSimplePluginEvent : public nsRunnable { +class nsSimplePluginEvent : public Runnable { public: nsSimplePluginEvent(nsIContent* aTarget, const nsAString &aEvent) : mTarget(aTarget) @@ -301,7 +301,7 @@ nsSimplePluginEvent::Run() /** * A task for firing PluginCrashed DOM Events. */ -class nsPluginCrashedEvent : public nsRunnable { +class nsPluginCrashedEvent : public Runnable { public: nsCOMPtr mContent; nsString mPluginDumpID; @@ -360,7 +360,7 @@ nsPluginCrashedEvent::Run() return NS_OK; } -class nsStopPluginRunnable : public nsRunnable, public nsITimerCallback +class nsStopPluginRunnable : public Runnable, public nsITimerCallback { public: NS_DECL_ISUPPORTS_INHERITED @@ -374,7 +374,7 @@ public: NS_ASSERTION(aContent, "need a nsObjectLoadingContent"); } - // nsRunnable + // Runnable NS_IMETHOD Run() override; // nsITimerCallback @@ -389,7 +389,7 @@ private: nsCOMPtr mContent; }; -NS_IMPL_ISUPPORTS_INHERITED(nsStopPluginRunnable, nsRunnable, nsITimerCallback) +NS_IMPL_ISUPPORTS_INHERITED(nsStopPluginRunnable, Runnable, nsITimerCallback) NS_IMETHODIMP nsStopPluginRunnable::Notify(nsITimer *aTimer) diff --git a/dom/base/nsReferencedElement.cpp b/dom/base/nsReferencedElement.cpp index bd029c380f..65fe4a40c2 100644 --- a/dom/base/nsReferencedElement.cpp +++ b/dom/base/nsReferencedElement.cpp @@ -215,7 +215,7 @@ nsReferencedElement::Observe(Element* aOldElement, } NS_IMPL_ISUPPORTS_INHERITED0(nsReferencedElement::ChangeNotification, - nsRunnable) + mozilla::Runnable) NS_IMPL_ISUPPORTS(nsReferencedElement::DocumentLoadNotification, nsIObserver) diff --git a/dom/base/nsReferencedElement.h b/dom/base/nsReferencedElement.h index e792245724..5a576fecdf 100644 --- a/dom/base/nsReferencedElement.h +++ b/dom/base/nsReferencedElement.h @@ -123,7 +123,7 @@ private: nsReferencedElement* mTarget; }; - class ChangeNotification : public nsRunnable, + class ChangeNotification : public mozilla::Runnable, public Notification { public: diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 60788f237f..935c83a83b 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -373,7 +373,7 @@ nsScriptLoader::PreloadURIComparator::Equals(const PreloadInfo &aPi, same; } -class nsScriptRequestProcessor : public nsRunnable +class nsScriptRequestProcessor : public Runnable { private: RefPtr mLoader; @@ -748,7 +748,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) namespace { -class NotifyOffThreadScriptLoadCompletedRunnable : public nsRunnable +class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable { RefPtr mRequest; RefPtr mLoader; @@ -1581,7 +1581,7 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, if (!aString.empty()) { aRequest->mScriptTextLength = aString.length(); - aRequest->mScriptTextBuf = aString.extractRawBuffer(); + aRequest->mScriptTextBuf = aString.extractOrCopyRawBuffer(); } // This assertion could fire errorously if we ran out of memory when diff --git a/dom/base/nsScriptLoader.h b/dom/base/nsScriptLoader.h index 338f8a62b8..7da39d9a47 100644 --- a/dom/base/nsScriptLoader.h +++ b/dom/base/nsScriptLoader.h @@ -179,14 +179,14 @@ public: insertBack(aElem); } - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE already_AddRefed Steal(nsScriptLoadRequest* aElem) { aElem->removeFrom(*this); return dont_AddRef(aElem); } - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE already_AddRefed StealFirst() { MOZ_ASSERT(!isEmpty()); diff --git a/dom/base/nsTextFragment.h b/dom/base/nsTextFragment.h index 984fa022e8..28441ad7b3 100644 --- a/dom/base/nsTextFragment.h +++ b/dom/base/nsTextFragment.h @@ -137,7 +137,7 @@ public: * Append the contents of this string fragment to aString * @return false if an out of memory condition is detected, true otherwise */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendTo(nsAString& aString, const mozilla::fallible_t& aFallible) const { if (mState.mIs2b) { @@ -171,7 +171,7 @@ public: * @param aLength the length of the substring * @return false if an out of memory condition is detected, true otherwise */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength, const mozilla::fallible_t& aFallible) const { diff --git a/dom/base/nsXHTMLContentSerializer.h b/dom/base/nsXHTMLContentSerializer.h index 6fc7dce669..7473ba0747 100644 --- a/dom/base/nsXHTMLContentSerializer.h +++ b/dom/base/nsXHTMLContentSerializer.h @@ -47,7 +47,7 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer { nsAString& aStr, nsresult& aResult) override; - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool AfterElementStart(nsIContent* aContent, nsIContent* aOriginalElement, nsAString& aStr) override; @@ -70,7 +70,7 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer { virtual void MaybeEnterInPreContent(nsIContent* aNode) override; virtual void MaybeLeaveFromPreContent(nsIContent* aNode) override; - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool SerializeAttributes(nsIContent* aContent, nsIContent *aOriginalElement, nsAString& aTagPrefix, @@ -82,13 +82,13 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer { bool IsFirstChildOfOL(nsIContent* aElement); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool SerializeLIValueAttribute(nsIContent* aElement, nsAString& aStr); bool IsShorthandAttr(const nsIAtom* aAttrName, const nsIAtom* aElementName); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool AppendAndTranslateEntities(const nsAString& aStr, nsAString& aOutputStr) override; diff --git a/dom/base/nsXMLContentSerializer.h b/dom/base/nsXMLContentSerializer.h index 6c265825b2..ce2967f1b3 100644 --- a/dom/base/nsXMLContentSerializer.h +++ b/dom/base/nsXMLContentSerializer.h @@ -72,14 +72,14 @@ class nsXMLContentSerializer : public nsIContentSerializer { /** * Appends a char16_t character and increments the column position */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendToString(const char16_t aChar, nsAString& aOutputStr); /** * Appends a nsAString string and increments the column position */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendToString(const nsAString& aStr, nsAString& aOutputStr); @@ -88,7 +88,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { * by mLineBreak, except in the case of raw output. * It increments the column position. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendToStringConvertLF(const nsAString& aStr, nsAString& aOutputStr); @@ -96,7 +96,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { * Appends a string by wrapping it when necessary. * It updates the column position. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendToStringWrapped(const nsASingleFragmentString& aStr, nsAString& aOutputStr); @@ -104,12 +104,12 @@ class nsXMLContentSerializer : public nsIContentSerializer { * Appends a string by formating and wrapping it when necessary * It updates the column position. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendToStringFormatedWrapped(const nsASingleFragmentString& aStr, nsAString& aOutputStr); // used by AppendToStringWrapped - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendWrapped_WhitespaceSequence( nsASingleFragmentString::const_char_iterator &aPos, const nsASingleFragmentString::const_char_iterator aEnd, @@ -117,7 +117,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { nsAString &aOutputStr); // used by AppendToStringFormatedWrapped - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendFormatedWrapped_WhitespaceSequence( nsASingleFragmentString::const_char_iterator &aPos, const nsASingleFragmentString::const_char_iterator aEnd, @@ -126,7 +126,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { nsAString &aOutputStr); // used by AppendToStringWrapped and AppendToStringFormatedWrapped - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendWrapped_NonWhitespaceSequence( nsASingleFragmentString::const_char_iterator &aPos, const nsASingleFragmentString::const_char_iterator aEnd, @@ -139,7 +139,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { * add mLineBreak to the string * It updates the column position and other flags. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendNewLineToString(nsAString& aOutputStr); @@ -147,7 +147,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { * Appends a string by translating entities * It doesn't increment the column position */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool AppendAndTranslateEntities(const nsAString& aStr, nsAString& aOutputStr); @@ -197,7 +197,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { nsIContent *aOriginalElement, const nsAString& aTagNamespaceURI); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool SerializeAttributes(nsIContent* aContent, nsIContent *aOriginalElement, nsAString& aTagPrefix, @@ -207,7 +207,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { uint32_t aSkipAttr, bool aAddNSAttr); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool SerializeAttr(const nsAString& aPrefix, const nsAString& aName, const nsAString& aValue, @@ -239,7 +239,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { * aElement and aOriginalElement are the same as the corresponding arguments * to AppendElementStart. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendEndOfElementStart(mozilla::dom::Element* aEleemnt, mozilla::dom::Element* aOriginalElement, nsAString& aStr); @@ -249,7 +249,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { * after the serialization ot the start tag. * (called at the end of AppendElementStart) */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE virtual bool AfterElementStart(nsIContent* aContent, nsIContent* aOriginalElement, nsAString& aStr) { return true; }; @@ -298,16 +298,16 @@ class nsXMLContentSerializer : public nsIContentSerializer { * add intendation. Call only in the case of formating and if the current * position is at 0. It updates the column position. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool AppendIndentation(nsAString& aStr); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool IncrIndentation(nsIAtom* aName); void DecrIndentation(nsIAtom* aName); // Functions to check for newlines that needs to be added between nodes in // the root of a document. See mAddNewlineForRootNode - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool MaybeAddNewlineForRootNode(nsAString& aStr); void MaybeFlagNewlineForRootNode(nsINode* aNode); diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index ccaac1373b..c59ad3e2dd 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -153,7 +153,7 @@ using namespace mozilla::dom; NS_IMPL_ISUPPORTS(nsXHRParseEndListener, nsIDOMEventListener) -class nsResumeTimeoutsEvent : public nsRunnable +class nsResumeTimeoutsEvent : public Runnable { public: explicit nsResumeTimeoutsEvent(nsPIDOMWindow* aWindow) : mWindow(aWindow) {} @@ -2573,15 +2573,14 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable& aBody) // Return error if we're already processing a request if (XML_HTTP_REQUEST_SENT & mState) { - return NS_ERROR_FAILURE; + return NS_ERROR_DOM_INVALID_STATE_ERR; } // Make sure we've been opened if (!mChannel || !(XML_HTTP_REQUEST_OPENED & mState)) { - return NS_ERROR_NOT_INITIALIZED; + return NS_ERROR_DOM_INVALID_STATE_ERR; } - // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active, which // in turn keeps STOP button from becoming active. If the consumer passed in // a progress event handler we must load with nsIRequest::LOAD_NORMAL or diff --git a/dom/bindings/MozMap.h b/dom/bindings/MozMap.h index 1e9e862c40..1e920c098e 100644 --- a/dom/bindings/MozMap.h +++ b/dom/bindings/MozMap.h @@ -104,7 +104,7 @@ public: } } - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE DataType* AddEntry(const nsAString& aKey) { EntryType* ent = this->PutEntry(aKey, fallible); diff --git a/dom/bindings/ToJSValue.h b/dom/bindings/ToJSValue.h index b5125208af..fad270aa0a 100644 --- a/dom/bindings/ToJSValue.h +++ b/dom/bindings/ToJSValue.h @@ -25,7 +25,7 @@ class Promise; // JSContext. // Accept strings. -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, const nsAString& aArgument, JS::MutableHandle aValue); @@ -36,7 +36,7 @@ ToJSValue(JSContext* aCx, // desirable. So make this a template that only gets used if the argument type // is actually boolean template -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE typename EnableIf::value, bool>::Type ToJSValue(JSContext* aCx, T aArgument, @@ -124,7 +124,7 @@ ToJSValue(JSContext* aCx, } // Accept CallbackObjects -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool ToJSValue(JSContext* aCx, CallbackObject& aArgument, JS::MutableHandle aValue) @@ -140,7 +140,7 @@ ToJSValue(JSContext* aCx, // Accept objects that inherit from nsWrapperCache (e.g. most // DOM objects). template -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE typename EnableIf::value, bool>::Type ToJSValue(JSContext* aCx, T& aArgument, @@ -156,7 +156,7 @@ ToJSValue(JSContext* aCx, // Accept typed arrays built from appropriate nsTArray values template -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE typename EnableIf::value, bool>::Type ToJSValue(JSContext* aCx, const TypedArrayCreator& aArgument, @@ -176,7 +176,7 @@ ToJSValue(JSContext* aCx, // Accept objects that inherit from nsISupports but not nsWrapperCache (e.g. // DOM File). template -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE typename EnableIf::value && !IsBaseOf::value && IsBaseOf::value, bool>::Type @@ -194,7 +194,7 @@ ToJSValue(JSContext* aCx, // Accept nsRefPtr/nsCOMPtr template -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, const nsCOMPtr& aArgument, JS::MutableHandle aValue) @@ -203,7 +203,7 @@ ToJSValue(JSContext* aCx, } template -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, const RefPtr& aArgument, JS::MutableHandle aValue) @@ -212,7 +212,7 @@ ToJSValue(JSContext* aCx, } template -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, const NonNull& aArgument, JS::MutableHandle aValue) @@ -222,7 +222,7 @@ ToJSValue(JSContext* aCx, // Accept WebIDL dictionaries template -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE typename EnableIf::value, bool>::Type ToJSValue(JSContext* aCx, const T& aArgument, @@ -232,7 +232,7 @@ ToJSValue(JSContext* aCx, } // Accept existing JS values (which may not be same-compartment with us -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool ToJSValue(JSContext* aCx, JS::Handle aArgument, JS::MutableHandle aValue) { @@ -241,7 +241,7 @@ ToJSValue(JSContext* aCx, JS::Handle aArgument, } // Accept existing JS values on the Heap (which may not be same-compartment with us -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool ToJSValue(JSContext* aCx, const JS::Heap& aArgument, JS::MutableHandle aValue) { @@ -250,7 +250,7 @@ ToJSValue(JSContext* aCx, const JS::Heap& aArgument, } // Accept existing rooted JS values (which may not be same-compartment with us -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool ToJSValue(JSContext* aCx, const JS::Rooted& aArgument, JS::MutableHandle aValue) { @@ -260,7 +260,7 @@ ToJSValue(JSContext* aCx, const JS::Rooted& aArgument, // Accept existing rooted JS objects (which may not be same-compartment with // us). -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool ToJSValue(JSContext* aCx, const JS::Rooted& aArgument, JS::MutableHandle aValue) { @@ -270,7 +270,7 @@ ToJSValue(JSContext* aCx, const JS::Rooted& aArgument, // Accept nsresult, for use in rejections, and create an XPCOM // exception object representing that nsresult. -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, nsresult aArgument, JS::MutableHandle aValue); @@ -278,14 +278,14 @@ ToJSValue(JSContext* aCx, // Accept ErrorResult, for use in rejections, and create an exception // representing the failure. Note, the ErrorResult must indicate a failure // with aArgument.Failure() returning true. -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, ErrorResult& aArgument, JS::MutableHandle aValue); // Accept owning WebIDL unions. template -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE typename EnableIf::value, bool>::Type ToJSValue(JSContext* aCx, const T& aArgument, @@ -297,7 +297,7 @@ ToJSValue(JSContext* aCx, // Accept pointers to other things we accept template -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE typename EnableIf::value, bool>::Type ToJSValue(JSContext* aCx, T aArgument, @@ -308,7 +308,7 @@ ToJSValue(JSContext* aCx, #ifdef SPIDERMONKEY_PROMISE // Accept Promise objects, which need special handling. -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, Promise& aArgument, JS::MutableHandle aValue); @@ -316,7 +316,7 @@ ToJSValue(JSContext* aCx, // Accept arrays of other things we accept template -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, T* aArguments, size_t aLength, @@ -343,7 +343,7 @@ ToJSValue(JSContext* aCx, } template -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, const nsTArray& aArgument, JS::MutableHandle aValue) @@ -353,7 +353,7 @@ ToJSValue(JSContext* aCx, } template -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, const FallibleTArray& aArgument, JS::MutableHandle aValue) @@ -363,7 +363,7 @@ ToJSValue(JSContext* aCx, } template -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool ToJSValue(JSContext* aCx, const T(&aArgument)[N], JS::MutableHandle aValue) diff --git a/dom/browser-element/BrowserElementAudioChannel.cpp b/dom/browser-element/BrowserElementAudioChannel.cpp index 44fd49fb62..60d1e68c8b 100644 --- a/dom/browser-element/BrowserElementAudioChannel.cpp +++ b/dom/browser-element/BrowserElementAudioChannel.cpp @@ -171,7 +171,7 @@ BrowserElementAudioChannel::Name() const namespace { -class BaseRunnable : public nsRunnable +class BaseRunnable : public Runnable { protected: nsCOMPtr mParentWindow; diff --git a/dom/cache/Manager.cpp b/dom/cache/Manager.cpp index 19c95e3210..d61b7a2b70 100644 --- a/dom/cache/Manager.cpp +++ b/dom/cache/Manager.cpp @@ -436,7 +436,7 @@ private: MaybeDestroyInstance(); } - class AbortRunnable final : public nsRunnable + class AbortRunnable final : public Runnable { public: explicit AbortRunnable(const nsACString& aOrigin) @@ -456,7 +456,7 @@ private: const nsCString mOrigin; }; - class ShutdownAllRunnable final : public nsRunnable + class ShutdownAllRunnable final : public Runnable { public: NS_IMETHOD diff --git a/dom/cache/PrincipalVerifier.h b/dom/cache/PrincipalVerifier.h index f22c8739db..d9bc980054 100644 --- a/dom/cache/PrincipalVerifier.h +++ b/dom/cache/PrincipalVerifier.h @@ -22,7 +22,7 @@ namespace cache { class ManagerId; -class PrincipalVerifier final : public nsRunnable +class PrincipalVerifier final : public Runnable { public: // An interface to be implemented by code wishing to use the diff --git a/dom/camera/CameraControlImpl.cpp b/dom/camera/CameraControlImpl.cpp index 20c1ef9ff6..5b3f8083f2 100644 --- a/dom/camera/CameraControlImpl.cpp +++ b/dom/camera/CameraControlImpl.cpp @@ -26,7 +26,7 @@ CameraControlImpl::CameraControlImpl() DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); mCurrentConfiguration.mMode = ICameraControl::kUnspecifiedMode; - class Delegate : public nsRunnable + class Delegate : public Runnable { public: NS_IMETHOD @@ -329,7 +329,7 @@ CameraControlImpl::OnSystemError(CameraControlListener::SystemContext aContext, // Camera control asynchronous message; these are dispatched from // the Main Thread to the Camera Thread, where they are consumed. -class CameraControlImpl::ControlMessage : public nsRunnable +class CameraControlImpl::ControlMessage : public Runnable { public: ControlMessage(CameraControlImpl* aCameraControl, diff --git a/dom/camera/DOMCameraCapabilities.cpp b/dom/camera/DOMCameraCapabilities.cpp index c8d465c934..366f48c9a8 100644 --- a/dom/camera/DOMCameraCapabilities.cpp +++ b/dom/camera/DOMCameraCapabilities.cpp @@ -22,7 +22,7 @@ namespace dom { * CameraClosedListenerProxy and CameraClosedMessage */ template -class CameraClosedMessage : public nsRunnable +class CameraClosedMessage : public Runnable { public: explicit CameraClosedMessage(nsMainThreadPtrHandle aListener) diff --git a/dom/camera/DOMCameraControlListener.cpp b/dom/camera/DOMCameraControlListener.cpp index 83a3d9ea6d..a3b3ad5144 100644 --- a/dom/camera/DOMCameraControlListener.cpp +++ b/dom/camera/DOMCameraControlListener.cpp @@ -30,7 +30,7 @@ DOMCameraControlListener::~DOMCameraControlListener() } // Boilerplate callback runnable -class DOMCameraControlListener::DOMCallback : public nsRunnable +class DOMCameraControlListener::DOMCallback : public Runnable { public: explicit DOMCallback(nsMainThreadPtrHandle aDOMCameraControl) diff --git a/dom/camera/GonkCameraControl.cpp b/dom/camera/GonkCameraControl.cpp index 4f5e6f225e..ae61d6243b 100644 --- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -968,7 +968,7 @@ nsGonkCameraControl::GetCameraHw() nsresult nsGonkCameraControl::SetThumbnailSize(const Size& aSize) { - class SetThumbnailSize : public nsRunnable + class SetThumbnailSize : public Runnable { public: SetThumbnailSize(nsGonkCameraControl* aCameraControl, const Size& aSize) @@ -1086,7 +1086,7 @@ nsGonkCameraControl::RationalizeRotation(int32_t aRotation) nsresult nsGonkCameraControl::SetPictureSize(const Size& aSize) { - class SetPictureSize : public nsRunnable + class SetPictureSize : public Runnable { public: SetPictureSize(nsGonkCameraControl* aCameraControl, const Size& aSize) @@ -1288,7 +1288,7 @@ nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescri nsresult nsGonkCameraControl::StopRecordingImpl() { - class RecordingComplete : public nsRunnable + class RecordingComplete : public Runnable { public: RecordingComplete(already_AddRefed aFile) @@ -1472,7 +1472,7 @@ nsGonkCameraControl::OnAutoFocusMoving(bool aIsMoving) void nsGonkCameraControl::OnAutoFocusComplete(bool aSuccess, bool aExpired) { - class AutoFocusComplete : public nsRunnable + class AutoFocusComplete : public Runnable { public: AutoFocusComplete(nsGonkCameraControl* aCameraControl, bool aSuccess, bool aExpired) @@ -2247,7 +2247,7 @@ nsGonkCameraControl::OnRateLimitPreview(bool aLimit) void nsGonkCameraControl::CreatePoster(Image* aImage, uint32_t aWidth, uint32_t aHeight, int32_t aRotation) { - class PosterRunnable : public nsRunnable { + class PosterRunnable : public Runnable { public: PosterRunnable(nsGonkCameraControl* aTarget, Image* aImage, uint32_t aWidth, uint32_t aHeight, int32_t aRotation) diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp index 4e7b85a595..1aef404eb8 100644 --- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -851,7 +851,7 @@ private: RefPtr mImageBitmap; }; -class FulfillImageBitmapPromiseTask final : public nsRunnable, +class FulfillImageBitmapPromiseTask final : public Runnable, public FulfillImageBitmapPromise { public: @@ -1041,7 +1041,7 @@ protected: Maybe mCropRect; }; -class CreateImageBitmapFromBlobTask final : public nsRunnable, +class CreateImageBitmapFromBlobTask final : public Runnable, public CreateImageBitmapFromBlob { public: diff --git a/dom/canvas/WebGLQuery.h b/dom/canvas/WebGLQuery.h index a9fbaabbbe..2e831052be 100644 --- a/dom/canvas/WebGLQuery.h +++ b/dom/canvas/WebGLQuery.h @@ -23,7 +23,7 @@ class WebGLQuery final public: explicit WebGLQuery(WebGLContext* webgl); - class AvailableRunnable final : public nsRunnable + class AvailableRunnable final : public Runnable { public: explicit AvailableRunnable(WebGLQuery* query) : mQuery(query) { } diff --git a/dom/devicestorage/DeviceStorageRequestParent.h b/dom/devicestorage/DeviceStorageRequestParent.h index f24f48ad10..9b7e0efa42 100644 --- a/dom/devicestorage/DeviceStorageRequestParent.h +++ b/dom/devicestorage/DeviceStorageRequestParent.h @@ -41,7 +41,8 @@ private: NS_DECL_OWNINGTHREAD DeviceStorageParams mParams; - class CancelableRunnable : public nsRunnable + // XXXkhuey name collision :( + class CancelableRunnable : public Runnable { public: explicit CancelableRunnable(DeviceStorageRequestParent* aParent) diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index b451d8e4bc..a94cd83f35 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -487,7 +487,7 @@ DeviceStorageTypeChecker::IsSharedMediaRoot(const nsAString& aType) #endif } -class IOEventComplete : public nsRunnable +class IOEventComplete : public Runnable { public: IOEventComplete(DeviceStorageFile *aFile, const char *aType) diff --git a/dom/devicestorage/nsDeviceStorage.h b/dom/devicestorage/nsDeviceStorage.h index fc06d1cf56..ec9dddf939 100644 --- a/dom/devicestorage/nsDeviceStorage.h +++ b/dom/devicestorage/nsDeviceStorage.h @@ -101,7 +101,7 @@ public: ~DeviceStorageUsedSpaceCache(); - class InvalidateRunnable final : public nsRunnable + class InvalidateRunnable final : public mozilla::Runnable { public: InvalidateRunnable(DeviceStorageUsedSpaceCache* aCache, @@ -305,7 +305,7 @@ private: }; class DeviceStorageRequest - : public nsRunnable + : public mozilla::Runnable { protected: DeviceStorageRequest(); diff --git a/dom/events/IMEContentObserver.h b/dom/events/IMEContentObserver.h index 694c0bc81a..139bdf5c45 100644 --- a/dom/events/IMEContentObserver.h +++ b/dom/events/IMEContentObserver.h @@ -195,7 +195,7 @@ private: * Helper classes to notify IME. */ - class AChangeEvent: public nsRunnable + class AChangeEvent: public Runnable { protected: enum ChangeEventType diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 1aca8bd234..210ae3e587 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -890,7 +890,7 @@ IMEStateManager::GetNewIMEState(nsPresContext* aPresContext, } // Helper class, used for IME enabled state change notification -class IMEEnabledStateChangedEvent : public nsRunnable { +class IMEEnabledStateChangedEvent : public Runnable { public: explicit IMEEnabledStateChangedEvent(uint32_t aState) : mState(aState) diff --git a/dom/events/TextComposition.h b/dom/events/TextComposition.h index 103d0b81e2..b05fd0d233 100644 --- a/dom/events/TextComposition.h +++ b/dom/events/TextComposition.h @@ -380,7 +380,7 @@ private: * CompositionEventDispatcher dispatches the specified composition (or text) * event. */ - class CompositionEventDispatcher : public nsRunnable + class CompositionEventDispatcher : public Runnable { public: CompositionEventDispatcher(TextComposition* aTextComposition, diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index 2ed4420ec7..76c08f3cde 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -106,7 +106,7 @@ private: ~MainThreadFetchResolver(); }; -class MainThreadFetchRunnable : public nsRunnable +class MainThreadFetchRunnable : public Runnable { RefPtr mResolver; RefPtr mRequest; @@ -696,7 +696,7 @@ NS_INTERFACE_MAP_BEGIN(ConsumeBodyDoneObserver) NS_INTERFACE_MAP_END template -class BeginConsumeBodyRunnable final : public nsRunnable +class BeginConsumeBodyRunnable final : public Runnable { FetchBody* mFetchBody; public: diff --git a/dom/filehandle/ActorsParent.cpp b/dom/filehandle/ActorsParent.cpp index 3f708bf1ba..bd6a9deeab 100644 --- a/dom/filehandle/ActorsParent.cpp +++ b/dom/filehandle/ActorsParent.cpp @@ -61,7 +61,7 @@ const uint32_t kStreamCopyBlockSize = 32768; } // namespace class FileHandleThreadPool::FileHandleQueue final - : public nsRunnable + : public Runnable { friend class FileHandleThreadPool; @@ -570,7 +570,7 @@ protected: }; class CopyFileHandleOp::ProgressRunnable final - : public nsRunnable + : public Runnable { RefPtr mCopyFileHandleOp; uint64_t mProgress; diff --git a/dom/filesystem/FileSystemTaskBase.h b/dom/filesystem/FileSystemTaskBase.h index d97001374d..bc71ce30e8 100644 --- a/dom/filesystem/FileSystemTaskBase.h +++ b/dom/filesystem/FileSystemTaskBase.h @@ -207,7 +207,7 @@ private: // This class is the 'alter ego' of FileSystemTaskChildBase in the PBackground // world. -class FileSystemTaskParentBase : public nsRunnable +class FileSystemTaskParentBase : public Runnable { public: /* diff --git a/dom/geolocation/nsGeolocation.cpp b/dom/geolocation/nsGeolocation.cpp index 675ff84048..ff70892541 100644 --- a/dom/geolocation/nsGeolocation.cpp +++ b/dom/geolocation/nsGeolocation.cpp @@ -223,7 +223,7 @@ public: NS_IMPL_ISUPPORTS(GeolocationSettingsCallback, nsISettingsServiceCallback) -class RequestPromptEvent : public nsRunnable +class RequestPromptEvent : public Runnable { public: RequestPromptEvent(nsGeolocationRequest* aRequest, nsWeakPtr aWindow) @@ -244,7 +244,7 @@ private: nsWeakPtr mWindow; }; -class RequestAllowEvent : public nsRunnable +class RequestAllowEvent : public Runnable { public: RequestAllowEvent(int allow, nsGeolocationRequest* request) @@ -267,7 +267,7 @@ private: RefPtr mRequest; }; -class RequestSendLocationEvent : public nsRunnable +class RequestSendLocationEvent : public Runnable { public: RequestSendLocationEvent(nsIDOMGeoPosition* aPosition, diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index f0b8649bf3..2bba4f0ce7 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -436,7 +436,7 @@ protected: class RemoveElementRunnable; friend class RemoveElementRunnable; - class RemoveElementRunnable : public nsRunnable { + class RemoveElementRunnable : public Runnable { public: explicit RemoveElementRunnable(HTMLFormElement* aForm) : mForm(aForm) diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index d0d4cbb490..63daceb986 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -77,7 +77,7 @@ namespace dom { // Calls LoadSelectedImage on host element unless it has been superseded or // canceled -- this is the synchronous section of "update the image data". // https://html.spec.whatwg.org/multipage/embedded-content.html#update-the-image-data -class ImageLoadTask : public nsRunnable +class ImageLoadTask : public Runnable { public: ImageLoadTask(HTMLImageElement *aElement, bool aAlwaysLoad) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 80faedcda3..7da76d3bde 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -206,7 +206,7 @@ static const double THRESHOLD_LOW_PLAYBACKRATE_AUDIO = 0.5; // receive events. If we neglect to remove the self-reference then the element // just lives longer than it needs to. -class nsMediaEvent : public nsRunnable +class nsMediaEvent : public Runnable { public: diff --git a/dom/html/HTMLObjectElement.cpp b/dom/html/HTMLObjectElement.cpp index 84c670dede..a955a0c8bf 100644 --- a/dom/html/HTMLObjectElement.cpp +++ b/dom/html/HTMLObjectElement.cpp @@ -122,7 +122,7 @@ static nsIWidget* GetWidget(Element* aElement) Element* HTMLObjectElement::sLastFocused = nullptr; // Weak -class PluginFocusSetter : public nsRunnable +class PluginFocusSetter : public Runnable { public: PluginFocusSetter(nsIWidget* aWidget, Element* aElement) diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index be8f155995..cfa8713a24 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -118,7 +118,7 @@ using namespace mozilla::dom; * nsGenericHTMLFormElement is binded to the tree with the autofocus attribute * enabled. */ -class nsAutoFocusEvent : public nsRunnable +class nsAutoFocusEvent : public Runnable { public: explicit nsAutoFocusEvent(nsGenericHTMLFormElement* aElement) : mElement(aElement) {} diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index 4b3d299767..54298d185f 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -2525,7 +2525,7 @@ nsHTMLDocument::EndUpdate(nsUpdateType aUpdateType) // Helper class, used below in ChangeContentEditableCount(). -class DeferredContentEditableCountChangeEvent : public nsRunnable +class DeferredContentEditableCountChangeEvent : public Runnable { public: DeferredContentEditableCountChangeEvent(nsHTMLDocument *aDoc, diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index d79c08eaee..a97ea71ce0 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -83,7 +83,7 @@ private: bool mOuterTransaction; }; -class RestoreSelectionState : public nsRunnable { +class RestoreSelectionState : public Runnable { public: RestoreSelectionState(nsTextEditorState *aState, nsTextControlFrame *aFrame) : mFrame(aFrame), @@ -1088,7 +1088,7 @@ nsTextEditorState::GetSelectionController() const } // Helper class, used below in BindToFrame(). -class PrepareEditorEvent : public nsRunnable { +class PrepareEditorEvent : public Runnable { public: PrepareEditorEvent(nsTextEditorState &aState, nsIContent *aOwnerContent, diff --git a/dom/html/nsTextEditorState.h b/dom/html/nsTextEditorState.h index f2e5e83b45..06aefcabad 100644 --- a/dom/html/nsTextEditorState.h +++ b/dom/html/nsTextEditorState.h @@ -155,8 +155,7 @@ public: // Whether the value change should be notified to the frame/contet nor not. eSetValue_Notify = 1 << 2 }; - MOZ_WARN_UNUSED_RESULT bool SetValue(const nsAString& aValue, - uint32_t aFlags); + MOZ_MUST_USE bool SetValue(const nsAString& aValue, uint32_t aFlags); void GetValue(nsAString& aValue, bool aIgnoreWrap) const; void EmptyValue() { if (mValue) mValue->Truncate(); } bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; } diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp index d8a6946712..bc88d7d6d1 100644 --- a/dom/indexedDB/ActorsChild.cpp +++ b/dom/indexedDB/ActorsChild.cpp @@ -898,7 +898,7 @@ protected: Recv__delete__(const uint32_t& aPermission) override; }; -class WorkerPermissionChallenge final : public nsRunnable +class WorkerPermissionChallenge final : public Runnable , public WorkerFeature { public: diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index 656c66c082..e316f4c6c9 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -5374,7 +5374,7 @@ private: }; class ConnectionPool::ConnectionRunnable - : public nsRunnable + : public Runnable { protected: DatabaseInfo* mDatabaseInfo; @@ -5522,7 +5522,7 @@ protected: }; class ConnectionPool::FinishCallbackWrapper final - : public nsRunnable + : public Runnable { RefPtr mConnectionPool; RefPtr mCallback; @@ -5615,7 +5615,7 @@ public: }; class ConnectionPool::ThreadRunnable final - : public nsRunnable + : public Runnable { // Only touched on the background thread. static uint32_t sNextSerialNumber; @@ -5698,7 +5698,7 @@ private: ******************************************************************************/ class DatabaseOperationBase - : public nsRunnable + : public Runnable , public mozIStorageProgressHandler { friend class UpgradeFileIdsFunction; @@ -6083,7 +6083,7 @@ private: }; class WaitForTransactionsHelper final - : public nsRunnable + : public Runnable { nsCOMPtr mOwningThread; const nsCString mDatabaseId; @@ -6135,7 +6135,7 @@ private: }; class UnlockDirectoryRunnable final - : public nsRunnable + : public Runnable { RefPtr mDirectoryLock; @@ -9074,7 +9074,7 @@ struct QuotaClient::MultipleMaintenanceInfo final }; class QuotaClient::ShutdownWorkThreadsRunnable final - : public nsRunnable + : public Runnable { RefPtr mQuotaClient; @@ -11705,7 +11705,7 @@ ConnectionPool::ScheduleTransaction(TransactionInfo* aTransactionInfo, // We need a thread right now so force all idle processing to stop by // posting a dummy runnable to each thread that might be doing idle // maintenance. - nsCOMPtr runnable = new nsRunnable(); + nsCOMPtr runnable = new Runnable(); for (uint32_t index = mDatabasesPerformingIdleMaintenance.Length(); index > 0; @@ -12340,7 +12340,7 @@ FinishCallbackWrapper::~FinishCallbackWrapper() MOZ_ASSERT(!mCallback); } -NS_IMPL_ISUPPORTS_INHERITED0(ConnectionPool::FinishCallbackWrapper, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(ConnectionPool::FinishCallbackWrapper, Runnable) nsresult ConnectionPool:: @@ -12400,7 +12400,7 @@ ThreadRunnable::~ThreadRunnable() MOZ_ASSERT(!mContinueRunning); } -NS_IMPL_ISUPPORTS_INHERITED0(ConnectionPool::ThreadRunnable, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(ConnectionPool::ThreadRunnable, Runnable) nsresult ConnectionPool:: @@ -13107,8 +13107,7 @@ WaitForTransactionsHelper::CallCallback() mState = State::Complete; } -NS_IMPL_ISUPPORTS_INHERITED0(WaitForTransactionsHelper, - nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(WaitForTransactionsHelper, Runnable) NS_IMETHODIMP WaitForTransactionsHelper::Run() @@ -18127,7 +18126,7 @@ AutoProgressHandler::OnProgress(mozIStorageConnection* aConnection, } NS_IMPL_ISUPPORTS_INHERITED0(QuotaClient::ShutdownWorkThreadsRunnable, - nsRunnable) + Runnable) NS_IMETHODIMP QuotaClient:: @@ -19153,7 +19152,7 @@ DatabaseOperationBase::ObjectStoreHasIndexes(DatabaseConnection* aConnection, } NS_IMPL_ISUPPORTS_INHERITED(DatabaseOperationBase, - nsRunnable, + Runnable, mozIStorageProgressHandler) NS_IMETHODIMP diff --git a/dom/indexedDB/FileInfo.cpp b/dom/indexedDB/FileInfo.cpp index 85b5353b78..471007273a 100644 --- a/dom/indexedDB/FileInfo.cpp +++ b/dom/indexedDB/FileInfo.cpp @@ -50,7 +50,7 @@ private: }; class CleanupFileRunnable final - : public nsRunnable + : public Runnable { RefPtr mFileManager; int64_t mFileId; @@ -243,7 +243,7 @@ CleanupFileRunnable::DoCleanup(FileManager* aFileManager, int64_t aFileId) } } -NS_IMPL_ISUPPORTS_INHERITED0(CleanupFileRunnable, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(CleanupFileRunnable, Runnable) NS_IMETHODIMP CleanupFileRunnable::Run() diff --git a/dom/indexedDB/FileSnapshot.cpp b/dom/indexedDB/FileSnapshot.cpp index e06be6404c..3faecdd62e 100644 --- a/dom/indexedDB/FileSnapshot.cpp +++ b/dom/indexedDB/FileSnapshot.cpp @@ -99,7 +99,7 @@ private: }; class StreamWrapper::CloseRunnable final - : public nsRunnable + : public Runnable { friend class StreamWrapper; @@ -283,7 +283,7 @@ StreamWrapper::Deserialize(const InputStreamParams& aParams, } NS_IMPL_ISUPPORTS_INHERITED0(StreamWrapper::CloseRunnable, - nsRunnable) + Runnable) NS_IMETHODIMP StreamWrapper:: diff --git a/dom/indexedDB/ScriptErrorHelper.cpp b/dom/indexedDB/ScriptErrorHelper.cpp index 13db32f35d..6c38febc68 100644 --- a/dom/indexedDB/ScriptErrorHelper.cpp +++ b/dom/indexedDB/ScriptErrorHelper.cpp @@ -16,7 +16,7 @@ namespace { -class ScriptErrorRunnable final : public nsRunnable +class ScriptErrorRunnable final : public mozilla::Runnable { nsString mMessage; nsCString mMessageName; diff --git a/dom/inputport/FakeInputPortService.cpp b/dom/inputport/FakeInputPortService.cpp index 1c145e111e..4bd74252f6 100644 --- a/dom/inputport/FakeInputPortService.cpp +++ b/dom/inputport/FakeInputPortService.cpp @@ -16,7 +16,7 @@ namespace mozilla { namespace dom { namespace { -class InputPortServiceNotifyRunnable final : public nsRunnable +class InputPortServiceNotifyRunnable final : public Runnable { public: InputPortServiceNotifyRunnable( diff --git a/dom/interfaces/security/nsIContentSecurityManager.idl b/dom/interfaces/security/nsIContentSecurityManager.idl index 8a54d16991..1a1c910217 100644 --- a/dom/interfaces/security/nsIContentSecurityManager.idl +++ b/dom/interfaces/security/nsIContentSecurityManager.idl @@ -5,6 +5,7 @@ #include "nsISupports.idl" interface nsIChannel; +interface nsIPrincipal; interface nsIStreamListener; interface nsIURI; @@ -13,7 +14,7 @@ interface nsIURI; * Describes an XPCOM component used to perform security checks. */ -[scriptable, uuid(ec955006-747d-4151-aeec-70bd0edc3341)] +[scriptable, uuid(3a9a1818-2ae8-4ec5-a340-8b29d31fca3b)] interface nsIContentSecurityManager : nsISupports { /** @@ -45,10 +46,11 @@ interface nsIContentSecurityManager : nsISupports * Implementation of * https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy * - * This method should only be used when the context of the URI isn't available - * since isSecureContext is preferred as it handles parent contexts. + * The value returned by this method feeds into the the Secure Context + * algorithm that determins the value of Window.isSecureContext and + * WorkerGlobalScope.isSecureContext. * * This method returns false instead of throwing upon errors. */ - boolean isURIPotentiallyTrustworthy(in nsIURI aURI); + boolean isOriginPotentiallyTrustworthy(in nsIPrincipal aPrincipal); }; diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp index 689e647041..adddee64e2 100644 --- a/dom/ipc/Blob.cpp +++ b/dom/ipc/Blob.cpp @@ -1456,7 +1456,7 @@ private: // dispatch itself to the thread pool again in order to close the file input // stream. class BlobParent::OpenStreamRunnable final - : public nsRunnable + : public Runnable { friend class nsRevocableEventPtr; @@ -1685,7 +1685,7 @@ private: } }; -NS_IMPL_ISUPPORTS_INHERITED0(BlobParent::OpenStreamRunnable, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(BlobParent::OpenStreamRunnable, Runnable) /******************************************************************************* * BlobChild::RemoteBlobImpl Declaration @@ -1824,7 +1824,7 @@ protected: }; class BlobChild::RemoteBlobImpl::CreateStreamHelper final - : public nsRunnable + : public Runnable { Monitor mMonitor; RefPtr mRemoteBlobImpl; @@ -2428,7 +2428,7 @@ CreateStreamHelper::RunInternal(RemoteBlobImpl* aBaseRemoteBlobImpl, } NS_IMPL_ISUPPORTS_INHERITED0(BlobChild::RemoteBlobImpl::CreateStreamHelper, - nsRunnable) + Runnable) NS_IMETHODIMP BlobChild::RemoteBlobImpl:: diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 4eb746e7c0..431e947c21 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1991,7 +1991,7 @@ namespace { // This runnable only exists to delegate ownership of the // ContentParent to this runnable, until it's deleted by the event // system. -struct DelayedDeleteContentParentTask : public nsRunnable +struct DelayedDeleteContentParentTask : public Runnable { explicit DelayedDeleteContentParentTask(ContentParent* aObj) : mObj(aObj) { } diff --git a/dom/ipc/CrashReporterParent.cpp b/dom/ipc/CrashReporterParent.cpp index 8a5ed30d72..f61dcfeea7 100644 --- a/dom/ipc/CrashReporterParent.cpp +++ b/dom/ipc/CrashReporterParent.cpp @@ -168,7 +168,7 @@ CrashReporterParent::FinalizeChildData() } nsCOMPtr mainThread = do_GetMainThread(); - class NotifyOnMainThread : public nsRunnable + class NotifyOnMainThread : public Runnable { public: explicit NotifyOnMainThread(CrashReporterParent* aCR) diff --git a/dom/ipc/FilePickerParent.h b/dom/ipc/FilePickerParent.h index a11b89c7a3..b10a02a631 100644 --- a/dom/ipc/FilePickerParent.h +++ b/dom/ipc/FilePickerParent.h @@ -76,7 +76,7 @@ class FilePickerParent : public PFilePickerParent bool CreateFilePicker(); // This runnable is used to do some I/O operation on a separate thread. - class IORunnable : public nsRunnable + class IORunnable : public Runnable { FilePickerParent* mFilePickerParent; nsTArray> mFiles; diff --git a/dom/ipc/ProcessHangMonitor.cpp b/dom/ipc/ProcessHangMonitor.cpp index c5b2f5d85f..221a434dd1 100644 --- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -556,7 +556,7 @@ HangMonitorParent::Open(Transport* aTransport, ProcessId aPid, MOZ_ASSERT(ok); } -class HangObserverNotifier final : public nsRunnable +class HangObserverNotifier final : public Runnable { public: HangObserverNotifier(HangMonitoredProcess* aProcess, @@ -637,7 +637,7 @@ HangMonitorParent::RecvHangEvidence(const HangData& aHangData) return true; } -class ClearHangNotifier final : public nsRunnable +class ClearHangNotifier final : public Runnable { public: explicit ClearHangNotifier(HangMonitoredProcess* aProcess) diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 44b4e7511f..ff2e5aed54 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -337,7 +337,7 @@ public: } }; -class TabChild::CachedFileDescriptorCallbackRunnable : public nsRunnable +class TabChild::CachedFileDescriptorCallbackRunnable : public Runnable { typedef TabChild::CachedFileDescriptorInfo CachedFileDescriptorInfo; @@ -373,7 +373,7 @@ private: }; class TabChild::DelayedDeleteRunnable final - : public nsRunnable + : public Runnable { RefPtr mTabChild; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 208a6140d6..3f63a675e2 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -109,7 +109,7 @@ using namespace mozilla::jsipc; // from the ones registered by webProgressListeners. #define NOTIFY_FLAG_SHIFT 16 -class OpenFileAndSendFDRunnable : public nsRunnable +class OpenFileAndSendFDRunnable : public mozilla::Runnable { const nsString mPath; RefPtr mTabParent; @@ -2810,7 +2810,7 @@ TabParent::NavigateByKey(bool aForward, bool aForDocumentNavigation) } class LayerTreeUpdateRunnable final - : public nsRunnable + : public mozilla::Runnable { uint64_t mLayersId; bool mActive; diff --git a/dom/ipc/nsIContentParent.h b/dom/ipc/nsIContentParent.h index b0fc0f153f..31bb84cb86 100644 --- a/dom/ipc/nsIContentParent.h +++ b/dom/ipc/nsIContentParent.h @@ -59,11 +59,11 @@ public: virtual bool IsForApp() const = 0; virtual bool IsForBrowser() const = 0; - MOZ_WARN_UNUSED_RESULT virtual PBlobParent* + MOZ_MUST_USE virtual PBlobParent* SendPBlobConstructor(PBlobParent* aActor, const BlobConstructorParams& aParams) = 0; - MOZ_WARN_UNUSED_RESULT virtual PBrowserParent* + MOZ_MUST_USE virtual PBrowserParent* SendPBrowserConstructor(PBrowserParent* actor, const TabId& aTabId, const IPCTabContext& context, diff --git a/dom/media/FileBlockCache.h b/dom/media/FileBlockCache.h index e803e40759..863e1586fe 100644 --- a/dom/media/FileBlockCache.h +++ b/dom/media/FileBlockCache.h @@ -51,7 +51,7 @@ namespace mozilla { // changes listed in mBlockChanges to file. Read() checks mBlockChanges and // determines the current data to return, reading from file or from // mBlockChanges as necessary. -class FileBlockCache : public nsRunnable { +class FileBlockCache : public Runnable { public: enum { BLOCK_SIZE = MediaCacheStream::BLOCK_SIZE diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index 99d8a09525..2165157b9d 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -164,7 +164,7 @@ ThreadedDriver::~ThreadedDriver() mThread->Shutdown(); } } -class MediaStreamGraphInitThreadRunnable : public nsRunnable { +class MediaStreamGraphInitThreadRunnable : public Runnable { public: explicit MediaStreamGraphInitThreadRunnable(ThreadedDriver* aDriver) : mDriver(aDriver) @@ -406,7 +406,7 @@ OfflineClockDriver::OfflineClockDriver(MediaStreamGraphImpl* aGraphImpl, GraphTi } -class MediaStreamGraphShutdownThreadRunnable : public nsRunnable { +class MediaStreamGraphShutdownThreadRunnable : public Runnable { public: explicit MediaStreamGraphShutdownThreadRunnable(nsIThread* aThread) : mThread(aThread) diff --git a/dom/media/GraphDriver.h b/dom/media/GraphDriver.h index f1248217e9..e835f1eea3 100644 --- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -528,7 +528,7 @@ private: bool mMicrophoneActive; }; -class AsyncCubebTask : public nsRunnable +class AsyncCubebTask : public Runnable { public: diff --git a/dom/media/Latency.cpp b/dom/media/Latency.cpp index d3400777ad..4bf39fcb1d 100644 --- a/dom/media/Latency.cpp +++ b/dom/media/Latency.cpp @@ -44,7 +44,7 @@ GetLatencyLog() return sLog; } -class LogEvent : public nsRunnable +class LogEvent : public Runnable { public: LogEvent(AsyncLatencyLogger::LatencyLogIndex aIndex, uint64_t aID, int64_t aValue, diff --git a/dom/media/MediaCache.cpp b/dom/media/MediaCache.cpp index 6582113738..8f49f31a85 100644 --- a/dom/media/MediaCache.cpp +++ b/dom/media/MediaCache.cpp @@ -1376,7 +1376,7 @@ MediaCache::Update() mSuspendedStatusToNotify.Clear(); } -class UpdateEvent : public nsRunnable +class UpdateEvent : public Runnable { public: NS_IMETHOD Run() diff --git a/dom/media/MediaDecoderReader.cpp b/dom/media/MediaDecoderReader.cpp index ea99c5eaf1..65a06c57f6 100644 --- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -224,7 +224,7 @@ MediaDecoderReader::AsyncReadMetadata() return MetadataPromise::CreateAndResolve(metadata, __func__); } -class ReRequestVideoWithSkipTask : public nsRunnable +class ReRequestVideoWithSkipTask : public Runnable { public: ReRequestVideoWithSkipTask(MediaDecoderReader* aReader, @@ -251,7 +251,7 @@ private: const int64_t mTimeThreshold; }; -class ReRequestAudioTask : public nsRunnable +class ReRequestAudioTask : public Runnable { public: explicit ReRequestAudioTask(MediaDecoderReader* aReader) diff --git a/dom/media/MediaEventSource.h b/dom/media/MediaEventSource.h index 26c4cca4ad..5703caff12 100644 --- a/dom/media/MediaEventSource.h +++ b/dom/media/MediaEventSource.h @@ -133,7 +133,7 @@ class ListenerHelper { // NS_NewRunnableFunction will result in 2 copies of the event data. // One is captured by the lambda and the other is the copy of the lambda. template - class R : public nsRunnable { + class R : public Runnable { public: template R(RevocableToken* aToken, const Function& aFunction, Us&&... aEvents) diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 3c09799e86..bde842f7e5 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -192,7 +192,7 @@ MediaFormatReader::Init() } #ifdef MOZ_EME -class DispatchKeyNeededEvent : public nsRunnable { +class DispatchKeyNeededEvent : public Runnable { public: DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder, nsTArray& aInitData, diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 2631d02965..4080a04e62 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -398,7 +398,7 @@ private: * so it can be released correctly. */ template -class ErrorCallbackRunnable : public nsRunnable +class ErrorCallbackRunnable : public Runnable { public: ErrorCallbackRunnable( @@ -449,7 +449,7 @@ private: }; // Handle removing GetUserMediaCallbackMediaStreamListener from main thread -class GetUserMediaListenerRemove: public nsRunnable +class GetUserMediaListenerRemove: public Runnable { public: GetUserMediaListenerRemove(uint64_t aWindowID, @@ -734,7 +734,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(FakeTrackSourceGetter, * GetUserMedia spec does not allow for more than 2 streams to be obtained in * one call, to simplify handling of constraints. */ -class GetUserMediaStreamRunnable : public nsRunnable +class GetUserMediaStreamRunnable : public Runnable { public: GetUserMediaStreamRunnable( @@ -1297,7 +1297,7 @@ private: }; #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK) -class GetUserMediaRunnableWrapper : public nsRunnable +class GetUserMediaRunnableWrapper : public Runnable { public: // This object must take ownership of task @@ -1795,7 +1795,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, bool isApp; docURI->SchemeIs("app", &isApp); // Same localhost check as ServiceWorkers uses - // (see IsURIPotentiallyTrustworthy()) + // (see IsOriginPotentiallyTrustworthy()) bool isLocalhost = NS_SUCCEEDED(rv) && (host.LowerCaseEqualsLiteral("localhost") || host.LowerCaseEqualsLiteral("127.0.0.1") || @@ -2593,7 +2593,7 @@ MediaManager::Shutdown() { public: ShutdownTask(MediaManager* aManager, - nsRunnable* aReply) + Runnable* aReply) : mManager(aManager) , mReply(aReply) {} private: @@ -2617,7 +2617,7 @@ MediaManager::Shutdown() } } RefPtr mManager; - RefPtr mReply; + RefPtr mReply; }; // Post ShutdownTask to execute on mMediaThread and pass in a lambda diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index a2e4881a7e..55941ba972 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -339,7 +339,7 @@ private: RefPtr mStream; // threadsafe refcnt }; -class GetUserMediaNotificationEvent: public nsRunnable +class GetUserMediaNotificationEvent: public Runnable { public: enum GetUserMediaStatus { @@ -389,7 +389,7 @@ typedef enum { class MediaManager; class GetUserMediaTask; -class ReleaseMediaOperationResource : public nsRunnable +class ReleaseMediaOperationResource : public Runnable { public: ReleaseMediaOperationResource(already_AddRefed aStream, diff --git a/dom/media/MediaRecorder.cpp b/dom/media/MediaRecorder.cpp index 523197472e..b006fb77e1 100644 --- a/dom/media/MediaRecorder.cpp +++ b/dom/media/MediaRecorder.cpp @@ -179,7 +179,7 @@ class MediaRecorder::Session: public nsIObserver, // Main thread task. // Create a blob event and send back to client. - class PushBlobRunnable : public nsRunnable + class PushBlobRunnable : public Runnable { public: explicit PushBlobRunnable(Session* aSession) @@ -209,7 +209,7 @@ class MediaRecorder::Session: public nsIObserver, }; // Notify encoder error, run in main thread task. (Bug 1095381) - class EncoderErrorNotifierRunnable : public nsRunnable + class EncoderErrorNotifierRunnable : public Runnable { public: explicit EncoderErrorNotifierRunnable(Session* aSession) @@ -237,7 +237,7 @@ class MediaRecorder::Session: public nsIObserver, }; // Fire start event and set mimeType, run in main thread task. - class DispatchStartEventRunnable : public nsRunnable + class DispatchStartEventRunnable : public Runnable { public: DispatchStartEventRunnable(Session* aSession, const nsAString & aEventName) @@ -266,7 +266,7 @@ class MediaRecorder::Session: public nsIObserver, // Record thread task and it run in Media Encoder thread. // Fetch encoded Audio/Video data from MediaEncoder. - class ExtractRunnable : public nsRunnable + class ExtractRunnable : public Runnable { public: explicit ExtractRunnable(Session* aSession) @@ -366,7 +366,7 @@ class MediaRecorder::Session: public nsIObserver, }; // Main thread task. // To delete RecordingSession object. - class DestroyRunnable : public nsRunnable + class DestroyRunnable : public Runnable { public: explicit DestroyRunnable(Session* aSession) diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index d6ba69a9b1..772ff253b0 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -65,7 +65,7 @@ LazyLogModule gMediaStreamGraphLog("MediaStreamGraph"); // NS_ReleaseOnMainThread(). This is based on our fix for M1348955 // et al. as demonstrated in TenFourFox issue 478. template -class ProxyReleaseEvent : public nsRunnable +class ProxyReleaseEvent : public Runnable { public: explicit ProxyReleaseEvent(already_AddRefed aDoomed) @@ -913,7 +913,7 @@ SetImageToBlackPixel(PlanarYCbCrImage* aImage) aImage->CopyData(data); } -class VideoFrameContainerInvalidateRunnable : public nsRunnable { +class VideoFrameContainerInvalidateRunnable : public Runnable { public: explicit VideoFrameContainerInvalidateRunnable(VideoFrameContainer* aVideoFrameContainer) : mVideoFrameContainer(aVideoFrameContainer) @@ -1613,7 +1613,7 @@ MediaStreamGraphImpl::ForceShutDown(ShutdownTicket* aShutdownTicket) namespace { -class MediaStreamGraphShutDownRunnable : public nsRunnable { +class MediaStreamGraphShutDownRunnable : public Runnable { public: explicit MediaStreamGraphShutDownRunnable(MediaStreamGraphImpl* aGraph) : mGraph(aGraph) @@ -1673,7 +1673,7 @@ private: RefPtr mGraph; }; -class MediaStreamGraphStableStateRunnable : public nsRunnable { +class MediaStreamGraphStableStateRunnable : public Runnable { public: explicit MediaStreamGraphStableStateRunnable(MediaStreamGraphImpl* aGraph, bool aSourceIsMSG) @@ -2611,7 +2611,7 @@ MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener) return; } - class NotifyRunnable final : public nsRunnable + class NotifyRunnable final : public Runnable { public: explicit NotifyRunnable(MediaStream* aStream) @@ -2631,7 +2631,7 @@ MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener) RefPtr mStream; }; - RefPtr runnable = new NotifyRunnable(this); + nsCOMPtr runnable = new NotifyRunnable(this); NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable.forget()))); } @@ -3503,7 +3503,7 @@ MediaStreamGraph::AddStream(MediaStream* aStream) graph->AppendMessage(MakeUnique(aStream)); } -class GraphStartedRunnable final : public nsRunnable +class GraphStartedRunnable final : public Runnable { public: GraphStartedRunnable(AudioNodeStream* aStream, MediaStreamGraph* aGraph) diff --git a/dom/media/TextTrackList.cpp b/dom/media/TextTrackList.cpp index a62b712817..eb402b80af 100644 --- a/dom/media/TextTrackList.cpp +++ b/dom/media/TextTrackList.cpp @@ -136,7 +136,7 @@ TextTrackList::DidSeek() } } -class TrackEventRunner final: public nsRunnable +class TrackEventRunner final: public Runnable { public: TrackEventRunner(TextTrackList* aList, nsIDOMEvent* aEvent) diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h index 3c1c590cef..55dca69a97 100644 --- a/dom/media/VideoUtils.h +++ b/dom/media/VideoUtils.h @@ -79,7 +79,7 @@ private: }; // Shuts down a thread asynchronously. -class ShutdownThreadEvent : public nsRunnable +class ShutdownThreadEvent : public Runnable { public: explicit ShutdownThreadEvent(nsIThread* aThread) : mThread(aThread) {} @@ -94,7 +94,7 @@ private: }; template -class DeleteObjectTask: public nsRunnable { +class DeleteObjectTask: public Runnable { public: explicit DeleteObjectTask(nsAutoPtr& aObject) : mObject(aObject) diff --git a/dom/media/android/AndroidMediaPluginHost.cpp b/dom/media/android/AndroidMediaPluginHost.cpp index 02f16bbc76..1a5f053663 100644 --- a/dom/media/android/AndroidMediaPluginHost.cpp +++ b/dom/media/android/AndroidMediaPluginHost.cpp @@ -41,7 +41,7 @@ static char* GetResource(Decoder *aDecoder) return static_cast(aDecoder->mResource); } -class GetIntPrefEvent : public nsRunnable { +class GetIntPrefEvent : public Runnable { public: GetIntPrefEvent(const char* aPref, int32_t* aResult) : mPref(aPref), mResult(aResult) {} diff --git a/dom/media/android/AndroidMediaResourceServer.cpp b/dom/media/android/AndroidMediaResourceServer.cpp index d4221817a6..2afffd626f 100644 --- a/dom/media/android/AndroidMediaResourceServer.cpp +++ b/dom/media/android/AndroidMediaResourceServer.cpp @@ -106,7 +106,7 @@ ReadCRLF (StreamType* aStream, nsLineBuffer * aBuffer, // protocol. It parses the headers and forwards data from the MediaResource // associated with the URL back to client. When the request is complete it will // shutdown the thread. -class ServeResourceEvent : public nsRunnable { +class ServeResourceEvent : public Runnable { private: // Reading from this reads the data sent from the client. nsCOMPtr mInput; diff --git a/dom/media/android/AndroidMediaResourceServer.h b/dom/media/android/AndroidMediaResourceServer.h index b13ecbf96e..68200f9c0f 100644 --- a/dom/media/android/AndroidMediaResourceServer.h +++ b/dom/media/android/AndroidMediaResourceServer.h @@ -37,7 +37,7 @@ class MediaResource; this is done by the Start() static method by synchronously dispatching to the main thread. */ -class AndroidMediaResourceServer : public nsRunnable +class AndroidMediaResourceServer : public Runnable { private: // Mutex protecting private members of AndroidMediaResourceServer. diff --git a/dom/media/gmp/GMPContentParent.cpp b/dom/media/gmp/GMPContentParent.cpp index 4b89dc7c53..e672f74955 100644 --- a/dom/media/gmp/GMPContentParent.cpp +++ b/dom/media/gmp/GMPContentParent.cpp @@ -47,7 +47,7 @@ GMPContentParent::~GMPContentParent() new DeleteTask(GetTransport())); } -class ReleaseGMPContentParent : public nsRunnable +class ReleaseGMPContentParent : public Runnable { public: explicit ReleaseGMPContentParent(GMPContentParent* aToRelease) diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp index a895986283..f1234eee37 100644 --- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -467,7 +467,7 @@ GMPParent::Shutdown() MOZ_ASSERT(mState == GMPStateNotLoaded); } -class NotifyGMPShutdownTask : public nsRunnable { +class NotifyGMPShutdownTask : public Runnable { public: explicit NotifyGMPShutdownTask(const nsAString& aNodeId) : mNodeId(aNodeId) @@ -976,7 +976,7 @@ GMPParent::RecvAsyncShutdownComplete() return true; } -class RunCreateContentParentCallbacks : public nsRunnable +class RunCreateContentParentCallbacks : public Runnable { public: explicit RunCreateContentParentCallbacks(GMPContentParent* aGMPContentParent) diff --git a/dom/media/gmp/GMPService.cpp b/dom/media/gmp/GMPService.cpp index 8a60403c84..48dffe4cb8 100644 --- a/dom/media/gmp/GMPService.cpp +++ b/dom/media/gmp/GMPService.cpp @@ -65,7 +65,7 @@ namespace gmp { static StaticRefPtr sSingletonService; -class GMPServiceCreateHelper final : public nsRunnable +class GMPServiceCreateHelper final : public mozilla::Runnable { RefPtr mService; diff --git a/dom/media/gmp/GMPServiceChild.cpp b/dom/media/gmp/GMPServiceChild.cpp index ffff8a897b..ef69535515 100644 --- a/dom/media/gmp/GMPServiceChild.cpp +++ b/dom/media/gmp/GMPServiceChild.cpp @@ -304,7 +304,7 @@ GMPServiceChild::GetAlreadyBridgedTo(nsTArray& aAlreadyBridgedT } } -class OpenPGMPServiceChild : public nsRunnable +class OpenPGMPServiceChild : public mozilla::Runnable { public: OpenPGMPServiceChild(UniquePtr&& aGMPServiceChild, diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index 183e394214..97bff89421 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -782,7 +782,7 @@ GeckoMediaPluginServiceParent::LoadFromEnvironment() return GenericPromise::All(thread, promises); } -class NotifyObserversTask final : public nsRunnable { +class NotifyObserversTask final : public mozilla::Runnable { public: explicit NotifyObserversTask(const char* aTopic, nsString aData = EmptyString()) : mTopic(aTopic) @@ -878,11 +878,6 @@ GeckoMediaPluginServiceParent::RemoveAndDeletePluginDirectory( aDefer)); } -class DummyRunnable : public nsRunnable { -public: - NS_IMETHOD Run() { return NS_OK; } -}; - NS_IMETHODIMP GeckoMediaPluginServiceParent::GetPluginVersionForAPI(const nsACString& aAPI, nsTArray* aTags, @@ -933,7 +928,7 @@ GeckoMediaPluginServiceParent::EnsurePluginsOnDiskScanned() // cause an event to be dispatched to which scans for plugins. We // dispatch a sync event to the GMP thread here in order to wait until // after the GMP thread has scanned any paths in MOZ_GMP_PATH. - nsresult rv = GMPDispatch(new DummyRunnable(), NS_DISPATCH_SYNC); + nsresult rv = GMPDispatch(new mozilla::Runnable(), NS_DISPATCH_SYNC); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(mScannedPluginOnDisk, "Should have scanned MOZ_GMP_PATH by now"); } @@ -1833,7 +1828,7 @@ GMPServiceParent::RecvGetGMPPluginVersionForAPI(const nsCString& aAPI, *aVersion)); } -class DeleteGMPServiceParent : public nsRunnable +class DeleteGMPServiceParent : public mozilla::Runnable { public: explicit DeleteGMPServiceParent(GMPServiceParent* aToDelete) @@ -1856,7 +1851,7 @@ GMPServiceParent::ActorDestroy(ActorDestroyReason aWhy) NS_DispatchToCurrentThread(new DeleteGMPServiceParent(this)); } -class OpenPGMPServiceParent : public nsRunnable +class OpenPGMPServiceParent : public mozilla::Runnable { public: OpenPGMPServiceParent(GMPServiceParent* aGMPServiceParent, diff --git a/dom/media/gmp/GMPServiceParent.h b/dom/media/gmp/GMPServiceParent.h index e912fa3b8e..5859f0ddb0 100644 --- a/dom/media/gmp/GMPServiceParent.h +++ b/dom/media/gmp/GMPServiceParent.h @@ -118,7 +118,7 @@ private: nsresult EnsurePluginsOnDiskScanned(); nsresult InitStorage(); - class PathRunnable : public nsRunnable + class PathRunnable : public Runnable { public: enum EOperation { diff --git a/dom/media/gtest/TestGMPCrossOrigin.cpp b/dom/media/gtest/TestGMPCrossOrigin.cpp index 326232523e..16a9f549e2 100644 --- a/dom/media/gtest/TestGMPCrossOrigin.cpp +++ b/dom/media/gtest/TestGMPCrossOrigin.cpp @@ -351,7 +351,7 @@ private: NS_IMPL_ISUPPORTS(GMPShutdownObserver, nsIRunnable, nsIObserver) -class NotifyObserversTask : public nsRunnable { +class NotifyObserversTask : public Runnable { public: explicit NotifyObserversTask(const char* aTopic) : mTopic(aTopic) @@ -621,7 +621,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback updates.AppendElement(aUpdate); CreateDecryptor(aOrigin, aTopLevelOrigin, aInPBMode, Move(updates)); } - class Updates : public nsRunnable + class Updates : public Runnable { public: Updates(GMPStorageTest* aRunner, nsTArray&& aUpdates) diff --git a/dom/media/gtest/TestMP4Demuxer.cpp b/dom/media/gtest/TestMP4Demuxer.cpp index 9d65f253e0..7fbcf94039 100644 --- a/dom/media/gtest/TestMP4Demuxer.cpp +++ b/dom/media/gtest/TestMP4Demuxer.cpp @@ -147,7 +147,7 @@ private: void DispatchTask(FunctionType aFun) { - RefPtr r = NS_NewRunnableFunction(aFun); + RefPtr r = NS_NewRunnableFunction(aFun); mTaskQueue->Dispatch(r.forget()); } diff --git a/dom/media/gtest/TestMediaFormatReader.cpp b/dom/media/gtest/TestMediaFormatReader.cpp index 95f720ba7d..0cebf9d0cc 100644 --- a/dom/media/gtest/TestMediaFormatReader.cpp +++ b/dom/media/gtest/TestMediaFormatReader.cpp @@ -128,7 +128,7 @@ public: template void RunTestAndWait(Function&& aFunction) { - RefPtr r = NS_NewRunnableFunction(Forward(aFunction)); + RefPtr r = NS_NewRunnableFunction(Forward(aFunction)); mTaskQueue->Dispatch(r.forget()); mTaskQueue->AwaitShutdownAndIdle(); } diff --git a/dom/media/gtest/TestMozPromise.cpp b/dom/media/gtest/TestMozPromise.cpp index 8a105b2caf..3bb51d21ea 100644 --- a/dom/media/gtest/TestMozPromise.cpp +++ b/dom/media/gtest/TestMozPromise.cpp @@ -34,7 +34,7 @@ private: RefPtr mTaskQueue; }; -class DelayedResolveOrReject : public nsRunnable +class DelayedResolveOrReject : public Runnable { public: DelayedResolveOrReject(TaskQueue* aTaskQueue, diff --git a/dom/media/imagecapture/CaptureTask.cpp b/dom/media/imagecapture/CaptureTask.cpp index d7a38023a0..7dc1b3dd1a 100644 --- a/dom/media/imagecapture/CaptureTask.cpp +++ b/dom/media/imagecapture/CaptureTask.cpp @@ -155,7 +155,7 @@ CaptureTask::PostTrackEndEvent() mImageGrabbedOrTrackEnd = true; // Got track end or finish event, stop the task. - class TrackEndRunnable : public nsRunnable + class TrackEndRunnable : public Runnable { public: explicit TrackEndRunnable(CaptureTask* aTask) diff --git a/dom/media/mediasink/DecodedStream.cpp b/dom/media/mediasink/DecodedStream.cpp index 73536719c6..1acd2779f8 100644 --- a/dom/media/mediasink/DecodedStream.cpp +++ b/dom/media/mediasink/DecodedStream.cpp @@ -270,7 +270,7 @@ DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo) mPlaying = true; ConnectListener(); - class R : public nsRunnable { + class R : public Runnable { typedef MozPromiseHolder Promise; public: R(PlaybackInfoInit&& aInit, Promise&& aPromise, OutputStreamManager* aManager) diff --git a/dom/media/mediasource/AsyncEventRunner.h b/dom/media/mediasource/AsyncEventRunner.h index c03afc594a..a1b6265f71 100644 --- a/dom/media/mediasource/AsyncEventRunner.h +++ b/dom/media/mediasource/AsyncEventRunner.h @@ -12,7 +12,7 @@ namespace mozilla { template -class AsyncEventRunner : public nsRunnable +class AsyncEventRunner : public Runnable { public: AsyncEventRunner(T* aTarget, const char* aName) diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index aef55fc0fe..f28577097b 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -988,9 +988,6 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) // 3. Set the need random access point flag on all track buffers to true. mVideoTracks.mNeedRandomAccessPoint = true; mAudioTracks.mNeedRandomAccessPoint = true; - - mVideoTracks.mLongestFrameDuration = mVideoTracks.mLastFrameDuration; - mAudioTracks.mLongestFrameDuration = mAudioTracks.mLastFrameDuration; } // 4. Let active track flag equal false. @@ -1377,18 +1374,15 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) TimeInterval targetWindow = mAppendWindow.mStart != TimeUnit::FromSeconds(0) ? mAppendWindow : TimeInterval(mAppendWindow.mStart, mAppendWindow.mEnd, - trackBuffer.mLongestFrameDuration.refOr(TimeUnit::FromMicroseconds(aSamples[0]->mDuration))); + trackBuffer.mLastFrameDuration.isSome() + ? trackBuffer.mLongestFrameDuration + : TimeUnit::FromMicroseconds(aSamples[0]->mDuration)); TimeIntervals samplesRange; uint32_t sizeNewSamples = 0; TrackBuffer samples; // array that will contain the frames to be added // to our track buffer. - // We assume that no frames are contiguous within a media segment and as such - // don't need to check for discontinuity except for the first frame and should - // a frame be ignored due to the target window. - bool needDiscontinuityCheck = true; - if (aSamples.Length()) { aTrackData.mLastParsedEndTime = TimeUnit(); } @@ -1434,24 +1428,29 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) // Step 3 is performed earlier or when a discontinuity has been detected. // 4. If timestampOffset is not 0, then run the following steps: + TimeUnit sampleTime = TimeUnit::FromMicroseconds(sample->mTime); + TimeUnit sampleTimecode = TimeUnit::FromMicroseconds(sample->mTimecode); + TimeUnit sampleDuration = TimeUnit::FromMicroseconds(sample->mDuration); + TimeUnit timestampOffset = mSourceBufferAttributes->GetTimestampOffset(); + TimeInterval sampleInterval = mSourceBufferAttributes->mGenerateTimestamps - ? TimeInterval(mSourceBufferAttributes->GetTimestampOffset(), - mSourceBufferAttributes->GetTimestampOffset() + TimeUnit::FromMicroseconds(sample->mDuration)) - : TimeInterval(TimeUnit::FromMicroseconds(sample->mTime) + mSourceBufferAttributes->GetTimestampOffset(), - TimeUnit::FromMicroseconds(sample->GetEndTime()) + mSourceBufferAttributes->GetTimestampOffset()); + ? TimeInterval(timestampOffset, timestampOffset + sampleDuration) + : TimeInterval(timestampOffset + sampleTime, + timestampOffset + sampleTime + sampleDuration); TimeUnit decodeTimestamp = mSourceBufferAttributes->mGenerateTimestamps - ? mSourceBufferAttributes->GetTimestampOffset() - : TimeUnit::FromMicroseconds(sample->mTimecode) + mSourceBufferAttributes->GetTimestampOffset(); + ? timestampOffset + : timestampOffset + sampleTimecode; // 6. If last decode timestamp for track buffer is set and decode timestamp is less than last decode timestamp: // OR // If last decode timestamp for track buffer is set and the difference between decode timestamp and last decode timestamp is greater than 2 times last frame duration: - if (needDiscontinuityCheck && trackBuffer.mLastDecodeTimestamp.isSome() && + if (trackBuffer.mLastDecodeTimestamp.isSome() && (decodeTimestamp < trackBuffer.mLastDecodeTimestamp.ref() || - decodeTimestamp - trackBuffer.mLastDecodeTimestamp.ref() > 2*trackBuffer.mLongestFrameDuration.ref())) { + (decodeTimestamp - trackBuffer.mLastDecodeTimestamp.ref() + > 2 * trackBuffer.mLongestFrameDuration))) { MSE_DEBUG("Discontinuity detected."); SourceBufferAppendMode appendMode = mSourceBufferAttributes->GetAppendMode(); @@ -1478,7 +1477,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) // steps again instead. // 3. If mode equals "sequence" and group start timestamp is set, then run the following steps: TimeUnit presentationTimestamp = mSourceBufferAttributes->mGenerateTimestamps - ? TimeUnit() : TimeUnit::FromMicroseconds(sample->mTime); + ? TimeUnit() : sampleTime; CheckSequenceDiscontinuity(presentationTimestamp); if (!sample->mKeyframe) { @@ -1487,19 +1486,18 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) if (appendMode == SourceBufferAppendMode::Sequence) { // mSourceBufferAttributes->GetTimestampOffset() was modified during CheckSequenceDiscontinuity. // We need to update our variables. + timestampOffset = mSourceBufferAttributes->GetTimestampOffset(); sampleInterval = mSourceBufferAttributes->mGenerateTimestamps - ? TimeInterval(mSourceBufferAttributes->GetTimestampOffset(), - mSourceBufferAttributes->GetTimestampOffset() + TimeUnit::FromMicroseconds(sample->mDuration)) - : TimeInterval(TimeUnit::FromMicroseconds(sample->mTime) + mSourceBufferAttributes->GetTimestampOffset(), - TimeUnit::FromMicroseconds(sample->GetEndTime()) + mSourceBufferAttributes->GetTimestampOffset()); + ? TimeInterval(timestampOffset, timestampOffset + sampleDuration) + : TimeInterval(timestampOffset + sampleTime, + timestampOffset + sampleTime + sampleDuration); decodeTimestamp = mSourceBufferAttributes->mGenerateTimestamps - ? mSourceBufferAttributes->GetTimestampOffset() - : TimeUnit::FromMicroseconds(sample->mTimecode) + mSourceBufferAttributes->GetTimestampOffset(); + ? timestampOffset + : timestampOffset + sampleTimecode; } trackBuffer.mNeedRandomAccessPoint = false; - needDiscontinuityCheck = false; } // 7. Let frame end timestamp equal the sum of presentation timestamp and frame duration. @@ -1518,7 +1516,6 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) sizeNewSamples = 0; } trackBuffer.mNeedRandomAccessPoint = true; - needDiscontinuityCheck = true; continue; } @@ -1531,18 +1528,17 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) // Steps 11,12,13,14, 15 and 16 will be done in one block in InsertFrames. - // 17. Set last decode timestamp for track buffer to decode timestamp. - trackBuffer.mLastDecodeTimestamp = - Some(TimeUnit::FromMicroseconds(sample->mTimecode)); - // 18. Set last frame duration for track buffer to frame duration. - trackBuffer.mLastFrameDuration = - Some(TimeUnit::FromMicroseconds(sample->mDuration)); - trackBuffer.mLongestFrameDuration = - Some(trackBuffer.mLongestFrameDuration.isNothing() - ? trackBuffer.mLastFrameDuration.ref() - : std::max(trackBuffer.mLastFrameDuration.ref(), - trackBuffer.mLongestFrameDuration.ref())); + trackBuffer.mLastFrameDuration.isSome() + ? sample->mKeyframe + ? sampleDuration + : std::max(sampleDuration, trackBuffer.mLongestFrameDuration) + : sampleDuration; + + // 17. Set last decode timestamp for track buffer to decode timestamp. + trackBuffer.mLastDecodeTimestamp = Some(decodeTimestamp); + // 18. Set last frame duration for track buffer to frame duration. + trackBuffer.mLastFrameDuration = Some(sampleDuration); // 19. If highest end timestamp for track buffer is unset or frame end timestamp is greater than highest end timestamp, then set highest end timestamp for track buffer to frame end timestamp. if (trackBuffer.mHighestEndTimestamp.isNothing() || @@ -1676,7 +1672,7 @@ TrackBuffersManager::InsertFrames(TrackBuffer& aSamples, // as fuzz is +/- value, giving an effective leeway of a full frame // length. TimeIntervals range(aIntervals); - range.SetFuzz(trackBuffer.mLongestFrameDuration.ref() / 2); + range.SetFuzz(trackBuffer.mLongestFrameDuration / 2); trackBuffer.mSanitizedBufferedRanges += range; } diff --git a/dom/media/mediasource/TrackBuffersManager.h b/dom/media/mediasource/TrackBuffersManager.h index f82f21158a..f05588c5b2 100644 --- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -268,8 +268,10 @@ private: // The variable is initially unset to indicate that no coded frames have // been appended yet. Maybe mHighestEndTimestamp; - // Longest frame duration seen in a coded frame group. - Maybe mLongestFrameDuration; + // Longest frame duration seen since last random access point. + // Only ever accessed when mLastDecodeTimestamp and mLastFrameDuration are + // set. + media::TimeUnit mLongestFrameDuration; // Need random access point flag variable that keeps track of whether the // track buffer is waiting for a random access point coded frame. // The variable is initially set to true to indicate that random access @@ -318,7 +320,6 @@ private: mHighestEndTimestamp.reset(); mNeedRandomAccessPoint = true; - mLongestFrameDuration.reset(); mNextInsertionIndex.reset(); } diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index 99636324b5..d8a8c38719 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -66,7 +66,7 @@ private: // the IO task dispatches a runnable to the main thread for parsing the // data. This goes on until all of the MP3 file has been parsed. -class MediaOmxReader::NotifyDataArrivedRunnable : public nsRunnable +class MediaOmxReader::NotifyDataArrivedRunnable : public Runnable { public: NotifyDataArrivedRunnable(MediaOmxReader* aOmxReader, diff --git a/dom/media/platforms/agnostic/BlankDecoderModule.cpp b/dom/media/platforms/agnostic/BlankDecoderModule.cpp index d19840dc49..bb3dfba4df 100644 --- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp +++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp @@ -43,7 +43,7 @@ public: return NS_OK; } - class OutputEvent : public nsRunnable { + class OutputEvent : public Runnable { public: OutputEvent(MediaRawData* aSample, MediaDataDecoderCallback* aCallback, diff --git a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h index 8083f08be7..4413a78d1b 100644 --- a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h +++ b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h @@ -15,7 +15,7 @@ namespace mozilla { -class InputTask : public nsRunnable { +class InputTask : public Runnable { public: InputTask(MediaDataDecoder* aDecoder, MediaRawData* aSample) diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index 34d363a429..86b456355e 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -149,7 +149,7 @@ WMFVideoMFTManager::GetMediaSubtypeGUID() }; } -class CreateDXVAManagerEvent : public nsRunnable { +class CreateDXVAManagerEvent : public Runnable { public: CreateDXVAManagerEvent(LayersBackend aBackend, nsCString& aFailureReason) : mBackend(aBackend) diff --git a/dom/media/systemservices/CamerasChild.cpp b/dom/media/systemservices/CamerasChild.cpp index 4d6a54f9d8..cb0e16047d 100644 --- a/dom/media/systemservices/CamerasChild.cpp +++ b/dom/media/systemservices/CamerasChild.cpp @@ -40,7 +40,7 @@ CamerasSingleton::~CamerasSingleton() { LOG(("~CamerasSingleton: %p", this)); } -class InitializeIPCThread : public nsRunnable +class InitializeIPCThread : public Runnable { public: InitializeIPCThread() @@ -484,9 +484,9 @@ Shutdown(void) child->ShutdownAll(); } -class ShutdownRunnable : public nsRunnable { +class ShutdownRunnable : public Runnable { public: - ShutdownRunnable(RefPtr aReplyEvent, + ShutdownRunnable(RefPtr aReplyEvent, nsIThread* aReplyThread) : mReplyEvent(aReplyEvent), mReplyThread(aReplyThread) {}; @@ -501,7 +501,7 @@ public: } private: - RefPtr mReplyEvent; + RefPtr mReplyEvent; nsIThread* mReplyThread; }; @@ -525,7 +525,7 @@ CamerasChild::ShutdownParent() if (CamerasSingleton::Thread()) { LOG(("Dispatching actor deletion")); // Delete the parent actor. - RefPtr deleteRunnable = + RefPtr deleteRunnable = // CamerasChild (this) will remain alive and is only deleted by the // IPC layer when SendAllDone returns. media::NewRunnableFrom([this]() -> nsresult { @@ -546,7 +546,7 @@ CamerasChild::ShutdownChild() LOG(("PBackground thread exists, dispatching close")); // Dispatch closing the IPC thread back to us when the // BackgroundChild is closed. - RefPtr event = + RefPtr event = new ThreadDestructor(CamerasSingleton::Thread()); RefPtr runnable = new ShutdownRunnable(event, NS_GetCurrentThread()); diff --git a/dom/media/systemservices/CamerasParent.cpp b/dom/media/systemservices/CamerasParent.cpp index d48c12938b..3dc7e9f21f 100644 --- a/dom/media/systemservices/CamerasParent.cpp +++ b/dom/media/systemservices/CamerasParent.cpp @@ -40,7 +40,7 @@ namespace camera { // called "VideoCapture". On Windows this is a thread with an event loop // suitable for UI access. -class FrameSizeChangeRunnable : public nsRunnable { +class FrameSizeChangeRunnable : public Runnable { public: FrameSizeChangeRunnable(CamerasParent *aParent, CaptureEngine capEngine, int cap_id, unsigned int aWidth, unsigned int aHeight) @@ -89,7 +89,7 @@ CallbackHelper::FrameSizeChange(unsigned int w, unsigned int h, return 0; } -class DeliverFrameRunnable : public nsRunnable { +class DeliverFrameRunnable : public Runnable { public: DeliverFrameRunnable(CamerasParent *aParent, CaptureEngine engine, @@ -165,7 +165,7 @@ CamerasParent::Observe(nsISupports *aSubject, } nsresult -CamerasParent::DispatchToVideoCaptureThread(nsRunnable *event) +CamerasParent::DispatchToVideoCaptureThread(Runnable *event) { // Don't try to dispatch if we're already on the right thread. // There's a potential deadlock because the mThreadMonitor is likely @@ -195,7 +195,7 @@ CamerasParent::StopVideoCapture() // from PBackground (when the Actor shuts down). // Shut down the WebRTC stack (on the capture thread) RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self]() -> nsresult { MonitorAutoLock lock(self->mThreadMonitor); self->CloseEngines(); @@ -220,7 +220,7 @@ CamerasParent::StopVideoCapture() if (self->mVideoCaptureThread) { base::Thread *thread = self->mVideoCaptureThread; self->mVideoCaptureThread = nullptr; - RefPtr threadShutdown = + RefPtr threadShutdown = media::NewRunnableFrom([thread]() -> nsresult { if (thread->IsRunning()) { thread->Stop(); @@ -480,7 +480,7 @@ CamerasParent::RecvNumberOfCaptureDevices(const int& aCapEngine) LOG((__PRETTY_FUNCTION__)); RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, aCapEngine]() -> nsresult { int num = -1; if (self->EnsureInitialized(aCapEngine)) { @@ -516,7 +516,7 @@ CamerasParent::RecvNumberOfCapabilities(const int& aCapEngine, LOG(("Getting caps for %s", unique_id.get())); RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, unique_id, aCapEngine]() -> nsresult { int num = -1; if (self->EnsureInitialized(aCapEngine)) { @@ -556,7 +556,7 @@ CamerasParent::RecvGetCaptureCapability(const int &aCapEngine, LOG(("RecvGetCaptureCapability: %s %d", unique_id.get(), num)); RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, unique_id, aCapEngine, num]() -> nsresult { webrtc::CaptureCapability webrtcCaps; int error = -1; @@ -604,7 +604,7 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine, LOG((__PRETTY_FUNCTION__)); RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, aListNumber]() -> nsresult { char deviceName[MediaEngineSource::kMaxDeviceNameLength]; char deviceUniqueId[MediaEngineSource::kMaxUniqueIdLength]; @@ -718,7 +718,7 @@ CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine, { LOG(("%s: Verifying permissions for %s", __PRETTY_FUNCTION__, aOrigin.get())); RefPtr self(this); - RefPtr mainthread_runnable = + RefPtr mainthread_runnable = media::NewRunnableFrom([self, aCapEngine, unique_id, aOrigin]() -> nsresult { // Verify whether the claimed origin has received permission // to use the camera, either persistently or this session (one shot). @@ -736,7 +736,7 @@ CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine, // After retrieving the permission (or not) on the main thread, // bounce to the WebRTC thread to allocate the device (or not), // then bounce back to the IPC thread for the reply to content. - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, allowed, aCapEngine, unique_id]() -> nsresult { int numdev = -1; int error = -1; @@ -787,7 +787,7 @@ CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine, LOG(("RecvReleaseCamera device nr %d", numdev)); RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, numdev]() -> nsresult { int error = self->ReleaseCaptureDevice(aCapEngine, numdev); RefPtr ipc_runnable = @@ -821,7 +821,7 @@ CamerasParent::RecvStartCapture(const int& aCapEngine, LOG((__PRETTY_FUNCTION__)); RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, capnum, ipcCaps]() -> nsresult { CallbackHelper** cbh; webrtc::ExternalRenderer* render; @@ -903,7 +903,7 @@ CamerasParent::RecvStopCapture(const int& aCapEngine, LOG((__PRETTY_FUNCTION__)); RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, capnum]() -> nsresult { self->StopCapture(aCapEngine, capnum); return NS_OK; @@ -968,7 +968,7 @@ CamerasParent::CamerasParent() LOG(("Spinning up WebRTC Cameras Thread")); RefPtr self(this); - RefPtr threadStart = + RefPtr threadStart = media::NewRunnableFrom([self]() -> nsresult { // Register thread shutdown observer nsCOMPtr obs = services::GetObserverService(); diff --git a/dom/media/systemservices/CamerasParent.h b/dom/media/systemservices/CamerasParent.h index 3d60007038..becdd435e6 100644 --- a/dom/media/systemservices/CamerasParent.h +++ b/dom/media/systemservices/CamerasParent.h @@ -129,7 +129,7 @@ protected: void CloseEngines(); void StopIPC(); void StopVideoCapture(); - nsresult DispatchToVideoCaptureThread(nsRunnable *event); + nsresult DispatchToVideoCaptureThread(Runnable *event); EngineHelper mEngines[CaptureEngine::MaxEngine]; nsTArray mCallbacks; diff --git a/dom/media/systemservices/CamerasUtils.h b/dom/media/systemservices/CamerasUtils.h index 5fb6ade212..dc4947ac85 100644 --- a/dom/media/systemservices/CamerasUtils.h +++ b/dom/media/systemservices/CamerasUtils.h @@ -18,7 +18,7 @@ namespace camera { nsresult SynchronouslyCreatePBackground(); -class ThreadDestructor : public nsRunnable +class ThreadDestructor : public Runnable { DISALLOW_COPY_AND_ASSIGN(ThreadDestructor); @@ -42,7 +42,7 @@ private: class RunnableTask : public Task { public: - explicit RunnableTask(nsRunnable* aRunnable) + explicit RunnableTask(Runnable* aRunnable) : mRunnable(aRunnable) {} void Run() override { @@ -51,7 +51,7 @@ public: private: ~RunnableTask() {} - RefPtr mRunnable; + RefPtr mRunnable; }; } diff --git a/dom/media/systemservices/LoadMonitor.cpp b/dom/media/systemservices/LoadMonitor.cpp index 0c496b9f3f..99457b9fd0 100644 --- a/dom/media/systemservices/LoadMonitor.cpp +++ b/dom/media/systemservices/LoadMonitor.cpp @@ -94,7 +94,7 @@ LoadMonitor::Observe(nsISupports* /* aSubject */, return NS_OK; } -class LoadMonitorAddObserver : public nsRunnable +class LoadMonitorAddObserver : public Runnable { public: explicit LoadMonitorAddObserver(RefPtr loadMonitor) @@ -119,7 +119,7 @@ private: RefPtr mLoadMonitor; }; -class LoadMonitorRemoveObserver : public nsRunnable +class LoadMonitorRemoveObserver : public Runnable { public: explicit LoadMonitorRemoveObserver(RefPtr loadMonitor) @@ -532,7 +532,7 @@ nsresult RTCLoadInfo::UpdateProcessLoad() { // Note: This class can't be in the anonymous namespace, because then we can't // declare it as a friend of LoadMonitor. -class LoadInfoCollectRunner : public nsRunnable +class LoadInfoCollectRunner : public Runnable { public: LoadInfoCollectRunner(RefPtr loadMonitor, diff --git a/dom/media/systemservices/MediaUtils.h b/dom/media/systemservices/MediaUtils.h index d6cdc0cc5c..b76ee30a61 100644 --- a/dom/media/systemservices/MediaUtils.h +++ b/dom/media/systemservices/MediaUtils.h @@ -146,14 +146,14 @@ private: UniquePtr mFunctors; }; -/* media::NewRunnableFrom() - Create an nsRunnable from a lambda. +/* media::NewRunnableFrom() - Create a Runnable from a lambda. * media::NewTaskFrom() - Create a Task from a lambda. * - * Passing variables (closures) to an async function is clunky with nsRunnable: + * Passing variables (closures) to an async function is clunky with Runnable: * * void Foo() * { - * class FooRunnable : public nsRunnable + * class FooRunnable : public Runnable * { * public: * FooRunnable(const Bar &aBar) : mBar(aBar) {} @@ -186,7 +186,7 @@ private: */ template -class LambdaRunnable : public nsRunnable +class LambdaRunnable : public Runnable { public: explicit LambdaRunnable(OnRunType&& aOnRun) : mOnRun(Move(aOnRun)) {} diff --git a/dom/media/webaudio/AlignedTArray.h b/dom/media/webaudio/AlignedTArray.h index 7631f11d22..2f6445882e 100644 --- a/dom/media/webaudio/AlignedTArray.h +++ b/dom/media/webaudio/AlignedTArray.h @@ -36,7 +36,7 @@ public: base_type::SetLength(newLen + sExtra); } - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool SetLength(size_type newLen, const mozilla::fallible_t&) { return base_type::SetLength(newLen + sExtra, mozilla::fallible); diff --git a/dom/media/webaudio/AnalyserNode.cpp b/dom/media/webaudio/AnalyserNode.cpp index a485a4ca38..9573751f54 100644 --- a/dom/media/webaudio/AnalyserNode.cpp +++ b/dom/media/webaudio/AnalyserNode.cpp @@ -26,7 +26,7 @@ NS_IMPL_ISUPPORTS_INHERITED0(AnalyserNode, AudioNode) class AnalyserNodeEngine final : public AudioNodeEngine { - class TransferBuffer final : public nsRunnable + class TransferBuffer final : public Runnable { public: TransferBuffer(AudioNodeStream* aStream, diff --git a/dom/media/webaudio/AudioBufferSourceNode.cpp b/dom/media/webaudio/AudioBufferSourceNode.cpp index c945f17858..87a6ecc4f8 100644 --- a/dom/media/webaudio/AudioBufferSourceNode.cpp +++ b/dom/media/webaudio/AudioBufferSourceNode.cpp @@ -756,7 +756,7 @@ AudioBufferSourceNode::NotifyMainThreadStreamFinished() { MOZ_ASSERT(mStream->IsFinished()); - class EndedEventDispatcher final : public nsRunnable + class EndedEventDispatcher final : public Runnable { public: explicit EndedEventDispatcher(AudioBufferSourceNode* aNode) diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 475a7b0020..001a46e473 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -743,7 +743,7 @@ StateChangeTask::Run() } /* This runnable allows to fire the "statechange" event */ -class OnStateChangeTask final : public nsRunnable +class OnStateChangeTask final : public Runnable { public: explicit OnStateChangeTask(AudioContext* aAudioContext) diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 5a1654f775..15870890af 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -91,7 +91,7 @@ private: /* This runnable allows the MSG to notify the main thread when audio is actually * flowing */ -class StateChangeTask final : public nsRunnable +class StateChangeTask final : public Runnable { public: /* This constructor should be used when this event is sent from the main diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index f2058ff30a..82a69d5e89 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -113,7 +113,7 @@ public: } - class OnCompleteTask final : public nsRunnable + class OnCompleteTask final : public Runnable { public: OnCompleteTask(AudioContext* aAudioContext, AudioBuffer* aRenderedBuffer) @@ -189,7 +189,7 @@ private: bool mBufferAllocated; }; -class InputMutedRunnable final : public nsRunnable +class InputMutedRunnable final : public Runnable { public: InputMutedRunnable(AudioNodeStream* aStream, diff --git a/dom/media/webaudio/AudioNode.cpp b/dom/media/webaudio/AudioNode.cpp index cd5cfffdf4..23bc8b0f9d 100644 --- a/dom/media/webaudio/AudioNode.cpp +++ b/dom/media/webaudio/AudioNode.cpp @@ -300,7 +300,7 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv) // ADDREF message to this (main) thread. Wait for a round trip before // releasing nodes, to give engines receiving sound now time to keep their // nodes alive. - class RunnableRelease final : public nsRunnable + class RunnableRelease final : public Runnable { public: explicit RunnableRelease(already_AddRefed aNode) diff --git a/dom/media/webaudio/DynamicsCompressorNode.cpp b/dom/media/webaudio/DynamicsCompressorNode.cpp index f9e86a6f3b..fa69503ee3 100644 --- a/dom/media/webaudio/DynamicsCompressorNode.cpp +++ b/dom/media/webaudio/DynamicsCompressorNode.cpp @@ -143,7 +143,7 @@ private: { MOZ_ASSERT(!NS_IsMainThread()); - class Command final : public nsRunnable + class Command final : public Runnable { public: Command(AudioNodeStream* aStream, float aReduction) diff --git a/dom/media/webaudio/MediaBufferDecoder.cpp b/dom/media/webaudio/MediaBufferDecoder.cpp index c3f19b4835..48ab297ebf 100644 --- a/dom/media/webaudio/MediaBufferDecoder.cpp +++ b/dom/media/webaudio/MediaBufferDecoder.cpp @@ -55,7 +55,7 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release) using namespace dom; -class ReportResultTask final : public nsRunnable +class ReportResultTask final : public Runnable { public: ReportResultTask(WebAudioDecodeJob& aDecodeJob, @@ -94,7 +94,7 @@ enum class PhaseEnum : int Done }; -class MediaDecodeTask final : public nsRunnable +class MediaDecodeTask final : public Runnable { public: MediaDecodeTask(const char* aContentType, uint8_t* aBuffer, diff --git a/dom/media/webaudio/OscillatorNode.cpp b/dom/media/webaudio/OscillatorNode.cpp index a68e6eaf93..14344b87f2 100644 --- a/dom/media/webaudio/OscillatorNode.cpp +++ b/dom/media/webaudio/OscillatorNode.cpp @@ -519,7 +519,7 @@ OscillatorNode::NotifyMainThreadStreamFinished() { MOZ_ASSERT(mStream->IsFinished()); - class EndedEventDispatcher final : public nsRunnable + class EndedEventDispatcher final : public Runnable { public: explicit EndedEventDispatcher(OscillatorNode* aNode) diff --git a/dom/media/webaudio/PlayingRefChangeHandler.h b/dom/media/webaudio/PlayingRefChangeHandler.h index 2ed42fafa2..700e8c0f32 100644 --- a/dom/media/webaudio/PlayingRefChangeHandler.h +++ b/dom/media/webaudio/PlayingRefChangeHandler.h @@ -13,7 +13,7 @@ namespace mozilla { namespace dom { -class PlayingRefChangeHandler final : public nsRunnable +class PlayingRefChangeHandler final : public Runnable { public: enum ChangeType { ADDREF, RELEASE }; diff --git a/dom/media/webaudio/ReportDecodeResultTask.h b/dom/media/webaudio/ReportDecodeResultTask.h index e0f0f7ec98..5d34f3438c 100644 --- a/dom/media/webaudio/ReportDecodeResultTask.h +++ b/dom/media/webaudio/ReportDecodeResultTask.h @@ -12,7 +12,7 @@ namespace mozilla { -class ReportDecodeResultTask final : public nsRunnable +class ReportDecodeResultTask final : public Runnable { public: ReportDecodeResultTask(DecodeJob& aDecodeJob, diff --git a/dom/media/webaudio/ScriptProcessorNode.cpp b/dom/media/webaudio/ScriptProcessorNode.cpp index ed4ec8eac2..5fff5da287 100644 --- a/dom/media/webaudio/ScriptProcessorNode.cpp +++ b/dom/media/webaudio/ScriptProcessorNode.cpp @@ -368,7 +368,7 @@ private: // Compute the playback time in the coordinate system of the destination double playbackTime = mDestination->StreamTimeToSeconds(playbackTick); - class Command final : public nsRunnable + class Command final : public Runnable { public: Command(AudioNodeStream* aStream, diff --git a/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp b/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp index 25185536ec..090e1b2172 100644 --- a/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp +++ b/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp @@ -107,7 +107,7 @@ size_t HRTFDatabaseLoader::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSize return amount; } -class HRTFDatabaseLoader::ProxyReleaseEvent final : public nsRunnable { +class HRTFDatabaseLoader::ProxyReleaseEvent final : public Runnable { public: explicit ProxyReleaseEvent(HRTFDatabaseLoader* loader) : mLoader(loader) {} NS_IMETHOD Run() override diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp index f1ce93cc97..4cbbb8ddc0 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp @@ -558,7 +558,7 @@ MediaEngineGonkVideoSource::OnUserError(UserContext aContext, nsresult aError) // A main thread runnable to send error code to all queued // MediaEnginePhotoCallbacks. - class TakePhotoError : public nsRunnable { + class TakePhotoError : public Runnable { public: TakePhotoError(nsTArray>& aCallbacks, nsresult aRv) @@ -600,7 +600,7 @@ MediaEngineGonkVideoSource::OnTakePictureComplete(const uint8_t* aData, uint32_t // Create a main thread runnable to generate a blob and call all current queued // MediaEnginePhotoCallbacks. - class GenerateBlobRunnable : public nsRunnable { + class GenerateBlobRunnable : public Runnable { public: GenerateBlobRunnable(nsTArray>& aCallbacks, const uint8_t* aData, diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.h b/dom/media/webrtc/MediaEngineTabVideoSource.h index 303387ca9f..d117553dc5 100644 --- a/dom/media/webrtc/MediaEngineTabVideoSource.h +++ b/dom/media/webrtc/MediaEngineTabVideoSource.h @@ -52,21 +52,21 @@ class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventList void Draw(); - class StartRunnable : public nsRunnable { + class StartRunnable : public Runnable { public: explicit StartRunnable(MediaEngineTabVideoSource *videoSource) : mVideoSource(videoSource) {} NS_IMETHOD Run(); RefPtr mVideoSource; }; - class StopRunnable : public nsRunnable { + class StopRunnable : public Runnable { public: explicit StopRunnable(MediaEngineTabVideoSource *videoSource) : mVideoSource(videoSource) {} NS_IMETHOD Run(); RefPtr mVideoSource; }; - class InitRunnable : public nsRunnable { + class InitRunnable : public Runnable { public: explicit InitRunnable(MediaEngineTabVideoSource *videoSource) : mVideoSource(videoSource) {} NS_IMETHOD Run(); diff --git a/dom/media/webspeech/recognition/PocketSphinxSpeechRecognitionService.cpp b/dom/media/webspeech/recognition/PocketSphinxSpeechRecognitionService.cpp index 5e02d613bb..7f679005af 100644 --- a/dom/media/webspeech/recognition/PocketSphinxSpeechRecognitionService.cpp +++ b/dom/media/webspeech/recognition/PocketSphinxSpeechRecognitionService.cpp @@ -30,7 +30,7 @@ namespace mozilla { using namespace dom; -class DecodeResultTask : public nsRunnable +class DecodeResultTask : public Runnable { public: DecodeResultTask(const nsString& hypstring, @@ -85,7 +85,7 @@ private: nsCOMPtr mWorkerThread; }; -class DecodeTask : public nsRunnable +class DecodeTask : public Runnable { public: DecodeTask(WeakPtr recogntion, diff --git a/dom/media/webspeech/recognition/SpeechRecognition.h b/dom/media/webspeech/recognition/SpeechRecognition.h index d4605599f3..297fe67e05 100644 --- a/dom/media/webspeech/recognition/SpeechRecognition.h +++ b/dom/media/webspeech/recognition/SpeechRecognition.h @@ -283,7 +283,7 @@ private: const char* GetName(SpeechEvent* aId); }; -class SpeechEvent : public nsRunnable +class SpeechEvent : public Runnable { public: SpeechEvent(SpeechRecognition* aRecognition, SpeechRecognition::EventType aType) diff --git a/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm index 7ccab6b51e..96d4b7c52b 100644 --- a/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm +++ b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm @@ -207,7 +207,7 @@ struct OSXVoice bool mIsDefault; }; -class RegisterVoicesRunnable final : public nsRunnable +class RegisterVoicesRunnable final : public Runnable { public: RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService, @@ -249,10 +249,13 @@ RegisterVoicesRunnable::Run() registry->SetDefaultVoice(voice.mUri, true); } } + + registry->NotifyVoicesChanged(); + return NS_OK; } -class EnumVoicesRunnable final : public nsRunnable +class EnumVoicesRunnable final : public Runnable { public: explicit EnumVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService) diff --git a/dom/media/webspeech/synth/ipc/PSpeechSynthesis.ipdl b/dom/media/webspeech/synth/ipc/PSpeechSynthesis.ipdl index c9f8554606..7b66034e4d 100644 --- a/dom/media/webspeech/synth/ipc/PSpeechSynthesis.ipdl +++ b/dom/media/webspeech/synth/ipc/PSpeechSynthesis.ipdl @@ -33,6 +33,8 @@ child: async IsSpeakingChanged(bool aIsSpeaking); + async NotifyVoicesChanged(); + parent: async __delete__(); diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp index 983e210db9..d1cb8bf0ed 100644 --- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp +++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp @@ -47,6 +47,13 @@ SpeechSynthesisChild::RecvIsSpeakingChanged(const bool& aIsSpeaking) return true; } +bool +SpeechSynthesisChild::RecvNotifyVoicesChanged() +{ + nsSynthVoiceRegistry::RecvNotifyVoicesChanged(); + return true; +} + PSpeechSynthesisRequestChild* SpeechSynthesisChild::AllocPSpeechSynthesisRequestChild(const nsString& aText, const nsString& aLang, diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h index 8b40319e39..01e9ffbdd7 100644 --- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h +++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h @@ -30,6 +30,8 @@ public: bool RecvIsSpeakingChanged(const bool& aIsSpeaking) override; + bool RecvNotifyVoicesChanged() override; + protected: SpeechSynthesisChild(); virtual ~SpeechSynthesisChild(); diff --git a/dom/media/webspeech/synth/moz.build b/dom/media/webspeech/synth/moz.build index e420172c92..34e7ecc17a 100644 --- a/dom/media/webspeech/synth/moz.build +++ b/dom/media/webspeech/synth/moz.build @@ -6,6 +6,7 @@ if CONFIG['MOZ_WEBSPEECH']: MOCHITEST_MANIFESTS += [ 'test/mochitest.ini', + 'test/startup/mochitest.ini', ] XPIDL_MODULE = 'dom_webspeechsynth' diff --git a/dom/media/webspeech/synth/nsISynthVoiceRegistry.idl b/dom/media/webspeech/synth/nsISynthVoiceRegistry.idl index af654f6978..cc0a5e1c63 100644 --- a/dom/media/webspeech/synth/nsISynthVoiceRegistry.idl +++ b/dom/media/webspeech/synth/nsISynthVoiceRegistry.idl @@ -7,7 +7,7 @@ interface nsISpeechService; -[scriptable, builtinclass, uuid(dac09c3a-156e-4025-a4ab-bc88b0ea92e7)] +[scriptable, builtinclass, uuid(5d7a0b38-77e5-4ee5-897c-ce5db9b85d44)] interface nsISynthVoiceRegistry : nsISupports { /** @@ -32,6 +32,12 @@ interface nsISynthVoiceRegistry : nsISupports */ void removeVoice(in nsISpeechService aService, in DOMString aUri); + /** + * Notify content of voice availability changes. This allows content + * to be notified of voice catalog changes in real time. + */ + void notifyVoicesChanged(); + /** * Set a voice as default. * diff --git a/dom/media/webspeech/synth/nsSpeechTask.cpp b/dom/media/webspeech/synth/nsSpeechTask.cpp index 7168f64cfc..9e4e821cf0 100644 --- a/dom/media/webspeech/synth/nsSpeechTask.cpp +++ b/dom/media/webspeech/synth/nsSpeechTask.cpp @@ -499,11 +499,17 @@ nsSpeechTask::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex) NS_IMETHODIMP nsSpeechTask::DispatchError(float aElapsedTime, uint32_t aCharIndex) { + LOG(LogLevel::Debug, ("nsSpeechTask::DispatchError")); + if (!mIndirectAudio) { NS_WARNING("Can't call DispatchError() from a direct audio speech service"); return NS_ERROR_FAILURE; } + if (!mPreCanceled) { + nsSynthVoiceRegistry::GetInstance()->SpeakNext(); + } + return DispatchErrorImpl(aElapsedTime, aCharIndex); } @@ -515,6 +521,10 @@ nsSpeechTask::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex) return NS_ERROR_NOT_AVAILABLE; } + if (mSpeechSynthesis) { + mSpeechSynthesis->OnEnd(this); + } + mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED; mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"), aCharIndex, aElapsedTime, diff --git a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp index f1d0e17ae9..6566d31be4 100644 --- a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp +++ b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp @@ -280,6 +280,17 @@ nsSynthVoiceRegistry::RecvIsSpeakingChanged(bool aIsSpeaking) gSynthVoiceRegistry->mIsSpeaking = aIsSpeaking; } +void +nsSynthVoiceRegistry::RecvNotifyVoicesChanged() +{ + // If we dont have a local instance of the registry yet, we don't care. + if(!gSynthVoiceRegistry) { + return; + } + + gSynthVoiceRegistry->NotifyVoicesChanged(); +} + NS_IMETHODIMP nsSynthVoiceRegistry::AddVoice(nsISpeechService* aService, const nsAString& aUri, @@ -350,6 +361,27 @@ nsSynthVoiceRegistry::RemoveVoice(nsISpeechService* aService, return NS_OK; } +NS_IMETHODIMP +nsSynthVoiceRegistry::NotifyVoicesChanged() +{ + if (XRE_IsParentProcess()) { + nsTArray ssplist; + GetAllSpeechSynthActors(ssplist); + + for (uint32_t i = 0; i < ssplist.Length(); ++i) + Unused << ssplist[i]->SendNotifyVoicesChanged(); + } + + nsCOMPtr obs = mozilla::services::GetObserverService(); + if(NS_WARN_IF(!(obs))) { + return NS_ERROR_NOT_AVAILABLE; + } + + obs->NotifyObservers(nullptr, "synth-voices-changed", nullptr); + + return NS_OK; +} + NS_IMETHODIMP nsSynthVoiceRegistry::SetDefaultVoice(const nsAString& aUri, bool aIsDefault) diff --git a/dom/media/webspeech/synth/nsSynthVoiceRegistry.h b/dom/media/webspeech/synth/nsSynthVoiceRegistry.h index 05885fe802..0a0672631a 100644 --- a/dom/media/webspeech/synth/nsSynthVoiceRegistry.h +++ b/dom/media/webspeech/synth/nsSynthVoiceRegistry.h @@ -64,6 +64,8 @@ public: static void RecvIsSpeakingChanged(bool aIsSpeaking); + static void RecvNotifyVoicesChanged(); + static void Shutdown(); private: diff --git a/dom/media/webspeech/synth/pico/nsPicoService.cpp b/dom/media/webspeech/synth/pico/nsPicoService.cpp index 95e5af234b..c68b4f853c 100644 --- a/dom/media/webspeech/synth/pico/nsPicoService.cpp +++ b/dom/media/webspeech/synth/pico/nsPicoService.cpp @@ -210,7 +210,7 @@ private: ~PicoVoice() {} }; -class PicoCallbackRunnable : public nsRunnable, +class PicoCallbackRunnable : public Runnable, public nsISpeechTaskCallback { friend class PicoSynthDataRunnable; @@ -261,9 +261,9 @@ private: RefPtr mService; }; -NS_IMPL_ISUPPORTS_INHERITED(PicoCallbackRunnable, nsRunnable, nsISpeechTaskCallback) +NS_IMPL_ISUPPORTS_INHERITED(PicoCallbackRunnable, Runnable, nsISpeechTaskCallback) -// nsRunnable +// Runnable NS_IMETHODIMP PicoCallbackRunnable::Run() @@ -342,7 +342,7 @@ void PicoCallbackRunnable::DispatchSynthDataRunnable( already_AddRefed&& aBuffer, size_t aBufferSize) { - class PicoSynthDataRunnable final : public nsRunnable + class PicoSynthDataRunnable final : public Runnable { public: PicoSynthDataRunnable(already_AddRefed& aBuffer, diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp index e1310f1fcb..bf39eb0e82 100644 --- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp @@ -416,7 +416,7 @@ SpeechDispatcherService::Setup() void SpeechDispatcherService::RegisterVoices() { - nsSynthVoiceRegistry* registry = nsSynthVoiceRegistry::GetInstance(); + RefPtr registry = nsSynthVoiceRegistry::GetInstance(); for (auto iter = mVoices.Iter(); !iter.Done(); iter.Next()) { RefPtr& voice = iter.Data(); @@ -434,6 +434,8 @@ SpeechDispatcherService::RegisterVoices() mInitThread = nullptr; mInitialized = true; + + registry->NotifyVoicesChanged(); } // nsIObserver diff --git a/dom/media/webspeech/synth/test/FakeSynthModule.cpp b/dom/media/webspeech/synth/test/FakeSynthModule.cpp index 46bf0437e2..5621ab78a8 100644 --- a/dom/media/webspeech/synth/test/FakeSynthModule.cpp +++ b/dom/media/webspeech/synth/test/FakeSynthModule.cpp @@ -32,7 +32,7 @@ static const mozilla::Module::ContractIDEntry kContracts[] = { }; static const mozilla::Module::CategoryEntry kCategories[] = { - { "profile-after-change", "Fake Speech Synth", FAKESYNTHSERVICE_CONTRACTID }, + { "speech-synth-started", "Fake Speech Synth", FAKESYNTHSERVICE_CONTRACTID }, { nullptr } }; diff --git a/dom/media/webspeech/synth/test/common.js b/dom/media/webspeech/synth/test/common.js index 404338407b..0ce9ec51b7 100644 --- a/dom/media/webspeech/synth/test/common.js +++ b/dom/media/webspeech/synth/test/common.js @@ -14,8 +14,6 @@ function synthTestQueue(aTestArgs, aEndFunc) { is(e.target, utterances.shift(), "Target matches utterances"); ok(!speechSynthesis.speaking, "speechSynthesis is not speaking."); - isnot(e.eventType, 'error', "Error in utterance"); - if (utterances.length) { ok(speechSynthesis.pending, "other utterances queued"); } else { @@ -38,10 +36,12 @@ function synthTestQueue(aTestArgs, aEndFunc) { u.addEventListener('end', onend_handler); u.addEventListener('error', onend_handler); - u.addEventListener( - 'error', function onerror_handler(e) { - ok(false, "Error in speech utterance '" + e.target.text + "'"); - }); + u.addEventListener('error', + (function (expectedError) { + return function onerror_handler(e) { + ok(expectedError, "Error in speech utterance '" + e.target.text + "'"); + }; + })(aTestArgs[i][1] ? aTestArgs[i][1].err : false)); utterances.push(u); win.speechSynthesis.speak(u); @@ -58,7 +58,28 @@ function loadFrame(frameId) { frame.contentWindow.document.title = frameId; resolve(frame); }); - frame1.src = 'data:text/html,' + encodeURI(''); + frame.src = 'data:text/html,' + encodeURI(''); + }); +} + +function waitForVoices(win) { + return new Promise(resolve => { + function resolver() { + if (win.speechSynthesis.getVoices().length) { + win.speechSynthesis.removeEventListener('voiceschanged', resolver); + resolve(); + } + } + + win.speechSynthesis.addEventListener('voiceschanged', resolver); + resolver(); + }); +} + +function loadSpeechTest(fileName, prefs, frameId="testFrame") { + loadFrame(frameId).then(frame => { + waitForVoices(frame.contentWindow).then( + () => document.getElementById("testFrame").src = fileName); }); } diff --git a/dom/media/webspeech/synth/test/file_speech_error.html b/dom/media/webspeech/synth/test/file_speech_error.html index a80f0cbf48..b98ec2fac0 100644 --- a/dom/media/webspeech/synth/test/file_speech_error.html +++ b/dom/media/webspeech/synth/test/file_speech_error.html @@ -28,7 +28,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1226015 function testFunc(done_cb) { var utterance = new SpeechSynthesisUtterance(); - utterance.lang = 'it-IT-error'; + utterance.lang = 'it-IT-failatstart'; speechSynthesis.speak(utterance); speechSynthesis.cancel(); diff --git a/dom/media/webspeech/synth/test/file_speech_queue.html b/dom/media/webspeech/synth/test/file_speech_queue.html index 12da780375..e308f35e59 100644 --- a/dom/media/webspeech/synth/test/file_speech_queue.html +++ b/dom/media/webspeech/synth/test/file_speech_queue.html @@ -30,9 +30,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444 var langUriMap = {}; for (var voice of speechSynthesis.getVoices()) { - if (voice.voiceURI.indexOf('urn:moz-tts:fake-direct') < 0) { - continue; - } langUriMap[voice.lang] = voice.voiceURI; ok(true, voice.lang + ' ' + voice.voiceURI + ' ' + voice.default); is(voice.default, voice.lang == 'en-JM', 'Only Jamaican voice should be default'); @@ -43,6 +40,7 @@ ok(langUriMap['en-GB'], 'No English-British voice'); ok(langUriMap['en-CA'], 'No English-Canadian voice'); ok(langUriMap['fr-CA'], 'No French-Canadian voice'); ok(langUriMap['es-MX'], 'No Spanish-Mexican voice'); +ok(langUriMap['it-IT-fail'], 'No Failing Italian voice'); function testFunc(done_cb) { synthTestQueue( @@ -53,6 +51,8 @@ function testFunc(done_cb) { { uri: langUriMap['fr-CA'], rate: 0.5, pitch: 0.75}], [{text: "How are you doing?", args: { lang: "en-GB" } }, { rate: 1, pitch: 1, uri: langUriMap['en-GB']}], + [{text: "Come stai?", args: { lang: "it-IT-fail" } }, + { rate: 1, pitch: 1, uri: langUriMap['it-IT-fail'], err: true }], [{text: "¡hasta mañana!", args: { lang: "es-MX" } }, { uri: langUriMap['es-MX'] }]], function () { diff --git a/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp b/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp index 0b72a4af5b..4e34e72008 100644 --- a/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp +++ b/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp @@ -31,7 +31,8 @@ enum VoiceFlags { eSuppressEvents = 1, eSuppressEnd = 2, - eFailAtStart = 4 + eFailAtStart = 4, + eFail = 8 }; struct VoiceDetails @@ -55,7 +56,8 @@ static const VoiceDetails sIndirectVoices[] = { {"urn:moz-tts:fake-indirect:zanetta", "Zanetta Farussi", "it-IT", false, 0}, {"urn:moz-tts:fake-indirect:margherita", "Margherita Durastanti", "it-IT-noevents-noend", false, eSuppressEvents | eSuppressEnd}, {"urn:moz-tts:fake-indirect:teresa", "Teresa Cornelys", "it-IT-noend", false, eSuppressEnd}, - {"urn:moz-tts:fake-indirect:cecilia", "Cecilia Bartoli", "it-IT-error", false, eFailAtStart}, + {"urn:moz-tts:fake-indirect:cecilia", "Cecilia Bartoli", "it-IT-failatstart", false, eFailAtStart}, + {"urn:moz-tts:fake-indirect:gottardo", "Gottardo Aldighieri", "it-IT-fail", false, eFail}, }; // FakeSynthCallback @@ -136,7 +138,7 @@ FakeDirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri, float aVolume, float aRate, float aPitch, nsISpeechTask* aTask) { - class Runnable final : public nsRunnable + class Runnable final : public mozilla::Runnable { public: Runnable(nsISpeechTask* aTask, const nsAString& aText) : @@ -199,7 +201,7 @@ FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri, float aVolume, float aRate, float aPitch, nsISpeechTask* aTask) { - class DispatchStart final : public nsRunnable + class DispatchStart final : public Runnable { public: explicit DispatchStart(nsISpeechTask* aTask) : @@ -218,7 +220,7 @@ FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri, nsCOMPtr mTask; }; - class DispatchEnd final : public nsRunnable + class DispatchEnd final : public Runnable { public: DispatchEnd(nsISpeechTask* aTask, const nsAString& aText) : @@ -238,6 +240,26 @@ FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri, nsString mText; }; + class DispatchError final : public Runnable + { + public: + DispatchError(nsISpeechTask* aTask, const nsAString& aText) : + mTask(aTask), mText(aText) + { + } + + NS_IMETHOD Run() override + { + mTask->DispatchError(mText.Length()/2, mText.Length()); + + return NS_OK; + } + + private: + nsCOMPtr mTask; + nsString mText; + }; + uint32_t flags = 0; for (uint32_t i = 0; i < ArrayLength(sIndirectVoices); i++) { if (aUri.EqualsASCII(sIndirectVoices[i].uri)) { @@ -246,8 +268,7 @@ FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri, } if (flags & eFailAtStart) { - aTask->DispatchError(0, 0); - return NS_OK; + return NS_ERROR_FAILURE; } RefPtr cb = new FakeSynthCallback( @@ -258,7 +279,10 @@ FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri, nsCOMPtr runnable = new DispatchStart(aTask); NS_DispatchToMainThread(runnable); - if ((flags & eSuppressEnd) == 0) { + if (flags & eFail) { + runnable = new DispatchError(aTask, aText); + NS_DispatchToMainThread(runnable); + } else if ((flags & eSuppressEnd) == 0) { runnable = new DispatchEnd(aTask, aText); NS_DispatchToMainThread(runnable); } @@ -294,7 +318,7 @@ nsFakeSynthServices::~nsFakeSynthServices() static void AddVoices(nsISpeechService* aService, const VoiceDetails* aVoices, uint32_t aLength) { - nsSynthVoiceRegistry* registry = nsSynthVoiceRegistry::GetInstance(); + RefPtr registry = nsSynthVoiceRegistry::GetInstance(); for (uint32_t i = 0; i < aLength; i++) { NS_ConvertUTF8toUTF16 name(aVoices[i].name); NS_ConvertUTF8toUTF16 uri(aVoices[i].uri); @@ -306,6 +330,8 @@ AddVoices(nsISpeechService* aService, const VoiceDetails* aVoices, uint32_t aLen registry->SetDefaultVoice(uri, true); } } + + registry->NotifyVoicesChanged(); } void @@ -325,12 +351,12 @@ nsFakeSynthServices::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { MOZ_ASSERT(NS_IsMainThread()); - if(NS_WARN_IF(!(!strcmp(aTopic, "profile-after-change")))) { + if(NS_WARN_IF(!(!strcmp(aTopic, "speech-synth-started")))) { return NS_ERROR_UNEXPECTED; } if (Preferences::GetBool("media.webspeech.synth.test")) { - Init(); + NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsFakeSynthServices::Init)); } return NS_OK; diff --git a/dom/media/webspeech/synth/test/startup/file_voiceschanged.html b/dom/media/webspeech/synth/test/startup/file_voiceschanged.html new file mode 100644 index 0000000000..6bb25462e4 --- /dev/null +++ b/dom/media/webspeech/synth/test/startup/file_voiceschanged.html @@ -0,0 +1,32 @@ + + + + + + Test for Bug 1254378: Web Speech API check all classes are present + + + + + + diff --git a/dom/media/webspeech/synth/test/startup/mochitest.ini b/dom/media/webspeech/synth/test/startup/mochitest.ini new file mode 100644 index 0000000000..7312a71eb3 --- /dev/null +++ b/dom/media/webspeech/synth/test/startup/mochitest.ini @@ -0,0 +1,7 @@ +[DEFAULT] +tags=msg +subsuite = media +support-files = + file_voiceschanged.html + +[test_voiceschanged.html] diff --git a/dom/media/webspeech/synth/test/startup/test_voiceschanged.html b/dom/media/webspeech/synth/test/startup/test_voiceschanged.html new file mode 100644 index 0000000000..079938c359 --- /dev/null +++ b/dom/media/webspeech/synth/test/startup/test_voiceschanged.html @@ -0,0 +1,32 @@ + + + + + + Test for Bug 1254378: Emit onvoiceschanged when voices first added + + + + +Mozilla Bug 1254378 +

+ + +
+
+
+ + diff --git a/dom/media/webspeech/synth/test/test_bfcache.html b/dom/media/webspeech/synth/test/test_bfcache.html index c7c147812b..8681def3f9 100644 --- a/dom/media/webspeech/synth/test/test_bfcache.html +++ b/dom/media/webspeech/synth/test/test_bfcache.html @@ -30,16 +30,14 @@ function onDone() { SimpleTest.finish(); } -function doTest() { - iframe = document.getElementById("testFrame"); - iframe.src = "file_bfcache_frame.html"; -} - SpecialPowers.pushPrefEnv({ set: [ ['media.webspeech.synth.enabled', true], ['media.webspeech.synth.force_global_queue', true], ['browser.sessionhistory.cache_subframes', true], - ['browser.sessionhistory.max_total_viewers', 10]] }, doTest()); + ['browser.sessionhistory.max_total_viewers', 10]] }, + function() { + loadSpeechTest("file_bfcache_frame.html"); + }); diff --git a/dom/media/webspeech/synth/test/test_global_queue.html b/dom/media/webspeech/synth/test/test_global_queue.html index 8e4093f58b..34d3a4ed3c 100644 --- a/dom/media/webspeech/synth/test/test_global_queue.html +++ b/dom/media/webspeech/synth/test/test_global_queue.html @@ -24,9 +24,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1188099 SimpleTest.waitForExplicitFinish(); -SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true], - ['media.webspeech.synth.force_global_queue', true]] }, - function() { document.getElementById("testFrame").src = "file_global_queue.html"; }); +SpecialPowers.pushPrefEnv( + { set: [['media.webspeech.synth.enabled', true], + ['media.webspeech.synth.force_global_queue', true]] }, + function() { loadSpeechTest("file_global_queue.html"); }); diff --git a/dom/media/webspeech/synth/test/test_global_queue_cancel.html b/dom/media/webspeech/synth/test/test_global_queue_cancel.html index f97382f629..4c5c116344 100644 --- a/dom/media/webspeech/synth/test/test_global_queue_cancel.html +++ b/dom/media/webspeech/synth/test/test_global_queue_cancel.html @@ -24,9 +24,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1188099 SimpleTest.waitForExplicitFinish(); -SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true], - ['media.webspeech.synth.force_global_queue', true]] }, - function() { document.getElementById("testFrame").src = "file_global_queue_cancel.html"; }); +SpecialPowers.pushPrefEnv( + { set: [['media.webspeech.synth.enabled', true], + ['media.webspeech.synth.force_global_queue', true]] }, + function() { loadSpeechTest("file_global_queue_cancel.html"); }); diff --git a/dom/media/webspeech/synth/test/test_global_queue_pause.html b/dom/media/webspeech/synth/test/test_global_queue_pause.html index 341d22b58d..f5ac1b98c6 100644 --- a/dom/media/webspeech/synth/test/test_global_queue_pause.html +++ b/dom/media/webspeech/synth/test/test_global_queue_pause.html @@ -24,9 +24,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1188099 SimpleTest.waitForExplicitFinish(); -SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true], - ['media.webspeech.synth.force_global_queue', true]] }, - function() { document.getElementById("testFrame").src = "file_global_queue_pause.html"; }); +SpecialPowers.pushPrefEnv( + { set: [['media.webspeech.synth.enabled', true], + ['media.webspeech.synth.force_global_queue', true]] }, + function() { loadSpeechTest("file_global_queue_pause.html"); }); diff --git a/dom/media/webspeech/synth/test/test_indirect_service_events.html b/dom/media/webspeech/synth/test/test_indirect_service_events.html index fe9caef982..d7f5ec4241 100644 --- a/dom/media/webspeech/synth/test/test_indirect_service_events.html +++ b/dom/media/webspeech/synth/test/test_indirect_service_events.html @@ -27,7 +27,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv( { set: [['media.webspeech.synth.enabled', true], ['media.webspeech.synth.force_global_queue', false]] }, - function() { document.getElementById("testFrame").src = "file_indirect_service_events.html"; }); + function() { loadSpeechTest("file_indirect_service_events.html"); }); diff --git a/dom/media/webspeech/synth/test/test_speech_cancel.html b/dom/media/webspeech/synth/test/test_speech_cancel.html index 0a927430b2..e7cf051ef1 100644 --- a/dom/media/webspeech/synth/test/test_speech_cancel.html +++ b/dom/media/webspeech/synth/test/test_speech_cancel.html @@ -27,7 +27,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv( { set: [['media.webspeech.synth.enabled', true], ['media.webspeech.synth.force_global_queue', false]] }, - function() { document.getElementById("testFrame").src = "file_speech_cancel.html"; }); + function() { loadSpeechTest("file_speech_cancel.html"); }); diff --git a/dom/media/webspeech/synth/test/test_speech_error.html b/dom/media/webspeech/synth/test/test_speech_error.html index 3a433d8cfb..c4bfdc6c45 100644 --- a/dom/media/webspeech/synth/test/test_speech_error.html +++ b/dom/media/webspeech/synth/test/test_speech_error.html @@ -27,7 +27,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv( { set: [['media.webspeech.synth.enabled', true], ['media.webspeech.synth.force_global_queue', false]] }, - function() { document.getElementById("testFrame").src = "file_speech_error.html"; }); + function() { loadSpeechTest("file_speech_error.html"); }); diff --git a/dom/media/webspeech/synth/test/test_speech_queue.html b/dom/media/webspeech/synth/test/test_speech_queue.html index 34fc0c2f08..ca652b243f 100644 --- a/dom/media/webspeech/synth/test/test_speech_queue.html +++ b/dom/media/webspeech/synth/test/test_speech_queue.html @@ -27,7 +27,9 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv( { set: [['media.webspeech.synth.enabled', true], ['media.webspeech.synth.force_global_queue', false]] }, - function() { document.getElementById("testFrame").src = "file_speech_queue.html"; }); + function() { + loadSpeechTest("file_speech_queue.html"); + }); diff --git a/dom/media/webspeech/synth/test/test_speech_simple.html b/dom/media/webspeech/synth/test/test_speech_simple.html index b8e0c4cc3b..2eb75af435 100644 --- a/dom/media/webspeech/synth/test/test_speech_simple.html +++ b/dom/media/webspeech/synth/test/test_speech_simple.html @@ -24,8 +24,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=650295 SimpleTest.waitForExplicitFinish(); -SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] }, - function() { document.getElementById("testFrame").src = "file_speech_simple.html"; }); +SpecialPowers.pushPrefEnv( + { set: [['media.webspeech.synth.enabled', true]] }, + function() { loadSpeechTest("file_speech_simple.html"); }); diff --git a/dom/media/webspeech/synth/windows/SapiService.cpp b/dom/media/webspeech/synth/windows/SapiService.cpp index c1325f4f92..52f06f311f 100644 --- a/dom/media/webspeech/synth/windows/SapiService.cpp +++ b/dom/media/webspeech/synth/windows/SapiService.cpp @@ -313,6 +313,8 @@ SapiService::RegisterVoices() mVoices.Put(uri, voiceToken); } + registry->NotifyVoicesChanged(); + return true; } diff --git a/dom/network/UDPSocket.cpp b/dom/network/UDPSocket.cpp index 60cbb53376..f12447a7d6 100644 --- a/dom/network/UDPSocket.cpp +++ b/dom/network/UDPSocket.cpp @@ -541,7 +541,7 @@ UDPSocket::Init(const nsString& aLocalAddress, return rv.StealNSResult(); } - class OpenSocketRunnable final : public nsRunnable + class OpenSocketRunnable final : public Runnable { public: explicit OpenSocketRunnable(UDPSocket* aSocket) : mSocket(aSocket) diff --git a/dom/notification/DesktopNotification.cpp b/dom/notification/DesktopNotification.cpp index 89c0538cf4..af3abdf092 100644 --- a/dom/notification/DesktopNotification.cpp +++ b/dom/notification/DesktopNotification.cpp @@ -27,7 +27,7 @@ namespace dom { * Simple Request */ class DesktopNotificationRequest : public nsIContentPermissionRequest - , public nsRunnable + , public Runnable { virtual ~DesktopNotificationRequest() { @@ -274,7 +274,7 @@ DesktopNotificationCenter::WrapObject(JSContext* aCx, JS::Handle aGiv /* DesktopNotificationRequest */ /* ------------------------------------------------------------------------ */ -NS_IMPL_ISUPPORTS_INHERITED(DesktopNotificationRequest, nsRunnable, +NS_IMPL_ISUPPORTS_INHERITED(DesktopNotificationRequest, Runnable, nsIContentPermissionRequest) NS_IMETHODIMP diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index e1737955e3..04fd542fc7 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -200,7 +200,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NotificationStorageCallback) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -class NotificationGetRunnable final : public nsRunnable +class NotificationGetRunnable final : public Runnable { const nsString mOrigin; const nsString mTag; @@ -310,7 +310,7 @@ public: } }; -class FocusWindowRunnable final : public nsRunnable +class FocusWindowRunnable final : public Runnable { nsMainThreadPtrHandle mWindow; public: @@ -520,7 +520,7 @@ public: } }; -class NotificationTask : public nsRunnable +class NotificationTask : public Runnable { public: enum NotificationAction { @@ -2165,7 +2165,7 @@ private: NS_IMPL_ISUPPORTS(WorkerGetCallback, nsINotificationStorageCallback) -class WorkerGetRunnable final : public nsRunnable +class WorkerGetRunnable final : public Runnable { RefPtr mPromiseProxy; const nsString mTag; diff --git a/dom/plugins/base/android/ANPAudio.cpp b/dom/plugins/base/android/ANPAudio.cpp index b23fdbcbe9..bc47e8999e 100644 --- a/dom/plugins/base/android/ANPAudio.cpp +++ b/dom/plugins/base/android/ANPAudio.cpp @@ -107,7 +107,7 @@ struct ANPAudioTrack { ANPAudioTrack() : lock("ANPAudioTrack") { } }; -class AudioRunnable : public nsRunnable +class AudioRunnable : public mozilla::Runnable { public: NS_DECL_NSIRUNNABLE diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index 2a814c2395..68b9d525dc 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -59,7 +59,7 @@ struct JSObjWrapperHasher } }; -namespace js { +namespace JS { template <> struct GCPolicy { static void trace(JSTracer* trc, nsJSObjWrapper** wrapper, const char* name) { @@ -68,7 +68,7 @@ struct GCPolicy { (*wrapper)->trace(trc); } }; -} // namespace js +} // namespace JS class NPObjWrapperHashEntry : public PLDHashEntryHdr { @@ -85,7 +85,7 @@ public: // when a plugin is torn down in case there's a leak in the plugin (we // don't want to leak the world just because a plugin leaks an // NPObject). -typedef js::GCHashMap JSObjWrapperTable; diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index 27296920a6..c50606608d 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -617,7 +617,7 @@ namespace { static char *gNPPException; -class nsPluginThreadRunnable : public nsRunnable, +class nsPluginThreadRunnable : public Runnable, public PRCList { public: diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 678da51f33..4967bc705a 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -65,7 +65,7 @@ using namespace mozilla::gl; typedef nsNPAPIPluginInstance::VideoInfo VideoInfo; -class PluginEventRunnable : public nsRunnable +class PluginEventRunnable : public Runnable { public: PluginEventRunnable(nsNPAPIPluginInstance* instance, ANPEvent* event) @@ -1639,7 +1639,7 @@ nsNPAPIPluginInstance::SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *c } } -class CarbonEventModelFailureEvent : public nsRunnable { +class CarbonEventModelFailureEvent : public Runnable { public: nsCOMPtr mContent; diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index f93ae92074..4a8c794259 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -1399,7 +1399,7 @@ nsPluginHost::GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPl return NS_ERROR_FAILURE; } -class nsPluginUnloadRunnable : public nsRunnable +class nsPluginUnloadRunnable : public Runnable { public: explicit nsPluginUnloadRunnable(uint32_t aPluginId) : mPluginId(aPluginId) {} @@ -4080,7 +4080,7 @@ nsPluginHost::DestroyRunningInstances(nsPluginTag* aPluginTag) // Runnable that does an async destroy of a plugin. -class nsPluginDestroyRunnable : public nsRunnable, +class nsPluginDestroyRunnable : public Runnable, public PRCList { public: diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index a7b5f3ad83..48878d017a 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -129,7 +129,7 @@ public: } }; -class AsyncPaintWaitEvent : public nsRunnable +class AsyncPaintWaitEvent : public Runnable { public: AsyncPaintWaitEvent(nsIContent* aContent, bool aFinished) : diff --git a/dom/plugins/base/nsPluginNativeWindowWin.cpp b/dom/plugins/base/nsPluginNativeWindowWin.cpp index 72fc011cfc..b81151775d 100644 --- a/dom/plugins/base/nsPluginNativeWindowWin.cpp +++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp @@ -46,7 +46,7 @@ typedef nsTWeakRef PluginWindowWeakRef; /** * PLEvent handling code */ -class PluginWindowEvent : public nsRunnable { +class PluginWindowEvent : public Runnable { public: PluginWindowEvent(); void Init(const PluginWindowWeakRef &ref, HWND hWnd, UINT msg, WPARAM wParam, @@ -159,7 +159,7 @@ static bool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsNPAPIPl return false; } -class nsDelayedPopupsEnabledEvent : public nsRunnable +class nsDelayedPopupsEnabledEvent : public Runnable { public: nsDelayedPopupsEnabledEvent(nsNPAPIPluginInstance *inst) diff --git a/dom/plugins/ipc/PluginHangUIParent.cpp b/dom/plugins/ipc/PluginHangUIParent.cpp index b379d59dc9..19b0a62b17 100644 --- a/dom/plugins/ipc/PluginHangUIParent.cpp +++ b/dom/plugins/ipc/PluginHangUIParent.cpp @@ -33,7 +33,7 @@ using std::string; using std::vector; namespace { -class nsPluginHangUITelemetry : public nsRunnable +class nsPluginHangUITelemetry : public mozilla::Runnable { public: nsPluginHangUITelemetry(int aResponseCode, int aDontAskCode, diff --git a/dom/plugins/ipc/PluginMessageUtils.cpp b/dom/plugins/ipc/PluginMessageUtils.cpp index 97d5aee386..5dcc4c4b5f 100644 --- a/dom/plugins/ipc/PluginMessageUtils.cpp +++ b/dom/plugins/ipc/PluginMessageUtils.cpp @@ -19,7 +19,7 @@ using mozilla::ipc::MessageChannel; namespace { -class DeferNPObjectReleaseRunnable : public nsRunnable +class DeferNPObjectReleaseRunnable : public mozilla::Runnable { public: DeferNPObjectReleaseRunnable(const NPNetscapeFuncs* f, NPObject* o) diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index c96df99c7a..57a3de81e8 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -54,7 +54,7 @@ using namespace workers; #ifndef SPIDERMONKEY_PROMISE // This class processes the promise's callbacks with promise's result. -class PromiseReactionJob final : public nsRunnable +class PromiseReactionJob final : public Runnable { public: PromiseReactionJob(Promise* aPromise, @@ -180,7 +180,7 @@ GetPromise(JSContext* aCx, JS::Handle aFunc) // Runnable to resolve thenables. // Equivalent to the specification's ResolvePromiseViaThenableTask. -class PromiseResolveThenableJob final : public nsRunnable +class PromiseResolveThenableJob final : public Runnable { public: PromiseResolveThenableJob(Promise* aPromise, diff --git a/dom/push/PushManager.cpp b/dom/push/PushManager.cpp index f4d7103139..5e49afe11d 100644 --- a/dom/push/PushManager.cpp +++ b/dom/push/PushManager.cpp @@ -262,7 +262,7 @@ private: NS_IMPL_ISUPPORTS(GetSubscriptionCallback, nsIPushSubscriptionCallback) -class GetSubscriptionRunnable final : public nsRunnable +class GetSubscriptionRunnable final : public Runnable { public: GetSubscriptionRunnable(PromiseWorkerProxy* aProxy, @@ -393,7 +393,7 @@ private: PushPermissionState mState; }; -class PermissionStateRunnable final : public nsRunnable +class PermissionStateRunnable final : public Runnable { public: explicit PermissionStateRunnable(PromiseWorkerProxy* aProxy) diff --git a/dom/push/PushSubscription.cpp b/dom/push/PushSubscription.cpp index 0834040df1..0d82709add 100644 --- a/dom/push/PushSubscription.cpp +++ b/dom/push/PushSubscription.cpp @@ -138,7 +138,7 @@ private: NS_IMPL_ISUPPORTS(WorkerUnsubscribeResultCallback, nsIUnsubscribeResultCallback) -class UnsubscribeRunnable final : public nsRunnable +class UnsubscribeRunnable final : public Runnable { public: UnsubscribeRunnable(PromiseWorkerProxy* aProxy, diff --git a/dom/quota/QuotaManager.cpp b/dom/quota/QuotaManager.cpp index 761d9cc276..86ad06923b 100644 --- a/dom/quota/QuotaManager.cpp +++ b/dom/quota/QuotaManager.cpp @@ -475,7 +475,7 @@ private: namespace { class CollectOriginsHelper final - : public nsRunnable + : public Runnable { uint64_t mMinSizeToBeFreed; @@ -506,7 +506,7 @@ private: }; class OriginOperationBase - : public nsRunnable + : public Runnable { protected: enum State { @@ -912,7 +912,7 @@ uint32_t gChunkSizeKB = kDefaultChunkSizeKB; bool gTestingEnabled = false; class StorageDirectoryHelper final - : public nsRunnable + : public Runnable { struct OriginProps; @@ -4500,7 +4500,7 @@ OriginOperationBase::DirectoryWork() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(NormalOriginOperationBase, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(NormalOriginOperationBase, Runnable) nsresult NormalOriginOperationBase::Open() diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index e9f8aef70c..0f7e3e113f 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -998,7 +998,7 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource, /** * Dispatched from the main thread to send reports for one CSP violation. */ -class CSPReportSenderRunnable final : public nsRunnable +class CSPReportSenderRunnable final : public Runnable { public: CSPReportSenderRunnable(nsISupports* aBlockedContentSource, diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 8f0315337f..53d57ec32c 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -544,19 +544,45 @@ nsContentSecurityManager::PerformSecurityCheck(nsIChannel* aChannel, } NS_IMETHODIMP -nsContentSecurityManager::IsURIPotentiallyTrustworthy(nsIURI* aURI, bool* aIsTrustWorthy) +nsContentSecurityManager::IsOriginPotentiallyTrustworthy(nsIPrincipal* aPrincipal, + bool* aIsTrustWorthy) { MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_ARG_POINTER(aURI); + NS_ENSURE_ARG_POINTER(aPrincipal); NS_ENSURE_ARG_POINTER(aIsTrustWorthy); + if (aPrincipal->GetIsSystemPrincipal()) { + *aIsTrustWorthy = true; + return NS_OK; + } + + // The following implements: + // https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy + *aIsTrustWorthy = false; + + if (aPrincipal->GetIsNullPrincipal()) { + return NS_OK; + } + + MOZ_ASSERT(aPrincipal->GetIsCodebasePrincipal(), + "Nobody is expected to call us with an nsIExpandedPrincipal"); + + nsCOMPtr uri; + aPrincipal->GetURI(getter_AddRefs(uri)); + nsAutoCString scheme; - nsresult rv = aURI->GetScheme(scheme); + nsresult rv = uri->GetScheme(scheme); if (NS_FAILED(rv)) { return NS_OK; } + // Blobs are expected to inherit their principal so we don't expect to have + // a codebase principal with scheme 'blob' here. We can't assert that though + // since someone could mess with a non-blob URI to give it that scheme. + NS_WARN_IF_FALSE(!scheme.EqualsLiteral("blob"), + "IsOriginPotentiallyTrustworthy ignoring blob scheme"); + // According to the specification, the user agent may choose to extend the // trust to other, vendor-specific URL schemes. We use this for "resource:", // which is technically a substituting protocol handler that is not limited to @@ -572,7 +598,7 @@ nsContentSecurityManager::IsURIPotentiallyTrustworthy(nsIURI* aURI, bool* aIsTru } nsAutoCString host; - rv = aURI->GetHost(host); + rv = uri->GetHost(host); if (NS_FAILED(rv)) { return NS_OK; } diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp index d9ffe29e93..6b523ac746 100644 --- a/dom/security/nsMixedContentBlocker.cpp +++ b/dom/security/nsMixedContentBlocker.cpp @@ -57,7 +57,7 @@ bool nsMixedContentBlocker::sBlockMixedDisplay = false; // Fired at the document that attempted to load mixed content. The UI could // handle this event, for example, by displaying an info bar that offers the // choice to reload the page with mixed content permitted. -class nsMixedContentEvent : public nsRunnable +class nsMixedContentEvent : public Runnable { public: nsMixedContentEvent(nsISupports *aContext, MixedContentTypes aType, bool aRootHasSecureConnection) diff --git a/dom/security/test/unit/test_isURIPotentiallyTrustworthy.js b/dom/security/test/unit/test_isOriginPotentiallyTrustworthy.js similarity index 70% rename from dom/security/test/unit/test_isURIPotentiallyTrustworthy.js rename to dom/security/test/unit/test_isOriginPotentiallyTrustworthy.js index a5946a42f3..de1834fbc8 100644 --- a/dom/security/test/unit/test_isURIPotentiallyTrustworthy.js +++ b/dom/security/test/unit/test_isOriginPotentiallyTrustworthy.js @@ -11,11 +11,15 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyServiceGetter(this, "gScriptSecurityManager", + "@mozilla.org/scriptsecuritymanager;1", + "nsIScriptSecurityManager"); + XPCOMUtils.defineLazyServiceGetter(this, "gContentSecurityManager", "@mozilla.org/contentsecuritymanager;1", "nsIContentSecurityManager"); -add_task(function* test_isURIPotentiallyTrustworthy() { +add_task(function* test_isOriginPotentiallyTrustworthy() { for (let [uriSpec, expectedResult] of [ ["http://example.com/", false], ["https://example.com/", true], @@ -27,7 +31,8 @@ add_task(function* test_isURIPotentiallyTrustworthy() { ["urn:generic", false], ]) { let uri = NetUtil.newURI(uriSpec); - Assert.equal(gContentSecurityManager.isURIPotentiallyTrustworthy(uri), + let principal = gScriptSecurityManager.getCodebasePrincipal(uri); + Assert.equal(gContentSecurityManager.isOriginPotentiallyTrustworthy(principal), expectedResult); } }); diff --git a/dom/security/test/unit/xpcshell.ini b/dom/security/test/unit/xpcshell.ini index fd7fedba59..b486b6483b 100644 --- a/dom/security/test/unit/xpcshell.ini +++ b/dom/security/test/unit/xpcshell.ini @@ -5,4 +5,4 @@ skip-if = toolkit == 'gonk' [test_csp_reports.js] skip-if = buildapp == 'mulet' -[test_isURIPotentiallyTrustworthy.js] +[test_isOriginPotentiallyTrustworthy.js] diff --git a/dom/smil/nsSMILTimedElement.cpp b/dom/smil/nsSMILTimedElement.cpp index d00ff04c06..0cb0a1f68a 100644 --- a/dom/smil/nsSMILTimedElement.cpp +++ b/dom/smil/nsSMILTimedElement.cpp @@ -78,7 +78,7 @@ nsSMILTimedElement::InstanceTimeComparator::LessThan( namespace { - class AsyncTimeEventRunner : public nsRunnable + class AsyncTimeEventRunner : public Runnable { protected: RefPtr mTarget; diff --git a/dom/storage/DOMStorage.cpp b/dom/storage/DOMStorage.cpp index 6bc4f8039e..064b483b9d 100644 --- a/dom/storage/DOMStorage.cpp +++ b/dom/storage/DOMStorage.cpp @@ -176,7 +176,7 @@ DOMStorage::Clear(ErrorResult& aRv) namespace { -class StorageNotifierRunnable : public nsRunnable +class StorageNotifierRunnable : public Runnable { public: StorageNotifierRunnable(nsISupports* aSubject, const char16_t* aType) diff --git a/dom/storage/DOMStorageCache.cpp b/dom/storage/DOMStorageCache.cpp index 06142148ce..fa39a7e129 100644 --- a/dom/storage/DOMStorageCache.cpp +++ b/dom/storage/DOMStorageCache.cpp @@ -666,7 +666,7 @@ DOMStorageUsage::DOMStorageUsage(const nsACString& aScope) namespace { -class LoadUsageRunnable : public nsRunnable +class LoadUsageRunnable : public Runnable { public: LoadUsageRunnable(int64_t* aUsage, const int64_t aDelta) diff --git a/dom/storage/DOMStorageIPC.cpp b/dom/storage/DOMStorageIPC.cpp index 4b13fc490a..21d129c1c4 100644 --- a/dom/storage/DOMStorageIPC.cpp +++ b/dom/storage/DOMStorageIPC.cpp @@ -291,7 +291,7 @@ DOMStorageDBParent::ReleaseIPDLReference() namespace { -class SendInitialChildDataRunnable : public nsRunnable +class SendInitialChildDataRunnable : public Runnable { public: explicit SendInitialChildDataRunnable(DOMStorageDBParent* aParent) @@ -612,7 +612,7 @@ DOMStorageDBParent::Observe(const char* aTopic, namespace { // Results must be sent back on the main thread -class LoadRunnable : public nsRunnable +class LoadRunnable : public Runnable { public: enum TaskType { @@ -715,7 +715,7 @@ DOMStorageDBParent::CacheParentBridge::LoadWait() namespace { -class UsageRunnable : public nsRunnable +class UsageRunnable : public Runnable { public: UsageRunnable(DOMStorageDBParent* aParent, const nsACString& aScope, const int64_t& aUsage) diff --git a/dom/system/nsDeviceSensors.cpp b/dom/system/nsDeviceSensors.cpp index 3b0a324a97..d071fd2249 100644 --- a/dom/system/nsDeviceSensors.cpp +++ b/dom/system/nsDeviceSensors.cpp @@ -137,7 +137,7 @@ NS_IMETHODIMP nsDeviceSensors::HasWindowListener(uint32_t aType, nsIDOMWindow *a return NS_OK; } -class DeviceSensorTestEvent : public nsRunnable +class DeviceSensorTestEvent : public Runnable { public: DeviceSensorTestEvent(nsDeviceSensors* aTarget, diff --git a/dom/u2f/U2F.cpp b/dom/u2f/U2F.cpp index 94158c2351..5892c3cdea 100644 --- a/dom/u2f/U2F.cpp +++ b/dom/u2f/U2F.cpp @@ -11,7 +11,6 @@ #include "mozilla/dom/U2FBinding.h" #include "mozilla/Preferences.h" #include "nsContentUtils.h" -#include "nsIEffectiveTLDService.h" #include "nsNetCID.h" #include "nsNSSComponent.h" #include "nsURLParsers.h" @@ -22,26 +21,11 @@ using mozilla::dom::ContentChild; namespace mozilla { namespace dom { -// These enumerations are defined in the FIDO U2F Javascript API under the -// interface "ErrorCode" as constant integers, and thus in the U2F.webidl file. -// Any changes to these must occur in both locations. -enum class ErrorCode { - OK = 0, - OTHER_ERROR = 1, - BAD_REQUEST = 2, - CONFIGURATION_UNSUPPORTED = 3, - DEVICE_INELIGIBLE = 4, - TIMEOUT = 5 -}; - #define PREF_U2F_SOFTTOKEN_ENABLED "security.webauth.u2f_enable_softtoken" #define PREF_U2F_USBTOKEN_ENABLED "security.webauth.u2f_enable_usbtoken" -const nsString U2F::FinishEnrollment = - NS_LITERAL_STRING("navigator.id.finishEnrollment"); - -const nsString U2F::GetAssertion = - NS_LITERAL_STRING("navigator.id.getAssertion"); +NS_NAMED_LITERAL_STRING(kFinishEnrollment, "navigator.id.finishEnrollment"); +NS_NAMED_LITERAL_STRING(kGetAssertion, "navigator.id.getAssertion"); NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(U2F) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY @@ -53,7 +37,603 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(U2F) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(U2F, mParent) -static mozilla::LazyLogModule gU2FLog("fido_u2f"); +static mozilla::LazyLogModule gU2FLog("webauth_u2f"); + +template +void +SendError(CB* aCallback, ErrorCode aErrorCode) +{ + Rsp response; + response.mErrorCode.Construct(static_cast(aErrorCode)); + + ErrorResult rv; + aCallback->Call(response, rv); + NS_WARN_IF(rv.Failed()); + // Useful exceptions already got reported. + rv.SuppressException(); +} + +static nsresult +AssembleClientData(const nsAString& aOrigin, const nsAString& aTyp, + const nsAString& aChallenge, CryptoBuffer& aClientData) +{ + ClientData clientDataObject; + clientDataObject.mTyp.Construct(aTyp); // "Typ" from the U2F specification + clientDataObject.mChallenge.Construct(aChallenge); + clientDataObject.mOrigin.Construct(aOrigin); + + nsAutoString json; + if (NS_WARN_IF(!clientDataObject.ToJSON(json))) { + return NS_ERROR_FAILURE; + } + + if (NS_WARN_IF(!aClientData.Assign(NS_ConvertUTF16toUTF8(json)))) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +static nsresult +NSSTokenIsCompatible(nsINSSU2FToken* aNSSToken, const nsString& aVersionString, + bool* aIsCompatible) +{ + MOZ_ASSERT(aIsCompatible); + + if (XRE_IsParentProcess()) { + MOZ_ASSERT(aNSSToken); + return aNSSToken->IsCompatibleVersion(aVersionString, aIsCompatible); + } + + ContentChild* cc = ContentChild::GetSingleton(); + MOZ_ASSERT(cc); + if (!cc->SendNSSU2FTokenIsCompatibleVersion(aVersionString, aIsCompatible)) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +static nsresult +NSSTokenIsRegistered(nsINSSU2FToken* aNSSToken, CryptoBuffer& aKeyHandle, + bool* aIsRegistered) +{ + MOZ_ASSERT(aIsRegistered); + + if (XRE_IsParentProcess()) { + MOZ_ASSERT(aNSSToken); + return aNSSToken->IsRegistered(aKeyHandle.Elements(), aKeyHandle.Length(), + aIsRegistered); + } + + ContentChild* cc = ContentChild::GetSingleton(); + MOZ_ASSERT(cc); + if (!cc->SendNSSU2FTokenIsRegistered(aKeyHandle, aIsRegistered)) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +static nsresult +NSSTokenSign(nsINSSU2FToken* aNSSToken, CryptoBuffer& aKeyHandle, + CryptoBuffer& aApplication, CryptoBuffer& aChallenge, + CryptoBuffer& aSignatureData) +{ + if (XRE_IsParentProcess()) { + MOZ_ASSERT(aNSSToken); + uint8_t* buffer; + uint32_t bufferlen; + nsresult rv = aNSSToken->Sign(aApplication.Elements(), aApplication.Length(), + aChallenge.Elements(), aChallenge.Length(), + aKeyHandle.Elements(), aKeyHandle.Length(), + &buffer, &bufferlen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + MOZ_ASSERT(buffer); + aSignatureData.Assign(buffer, bufferlen); + free(buffer); + return NS_OK; + } + + nsTArray signatureBuffer; + ContentChild* cc = ContentChild::GetSingleton(); + MOZ_ASSERT(cc); + if (!cc->SendNSSU2FTokenSign(aApplication, aChallenge, aKeyHandle, + &signatureBuffer)) { + return NS_ERROR_FAILURE; + } + + aSignatureData.Assign(signatureBuffer); + return NS_OK; +} + +static nsresult +NSSTokenRegister(nsINSSU2FToken* aNSSToken, CryptoBuffer& aApplication, + CryptoBuffer& aChallenge, CryptoBuffer& aRegistrationData) +{ + if (XRE_IsParentProcess()) { + MOZ_ASSERT(aNSSToken); + uint8_t* buffer; + uint32_t bufferlen; + nsresult rv; + rv = aNSSToken->Register(aApplication.Elements(), aApplication.Length(), + aChallenge.Elements(), aChallenge.Length(), + &buffer, &bufferlen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + MOZ_ASSERT(buffer); + aRegistrationData.Assign(buffer, bufferlen); + free(buffer); + return NS_OK; + } + + nsTArray registrationBuffer; + ContentChild* cc = ContentChild::GetSingleton(); + MOZ_ASSERT(cc); + if (!cc->SendNSSU2FTokenRegister(aApplication, aChallenge, + ®istrationBuffer)) { + return NS_ERROR_FAILURE; + } + + aRegistrationData.Assign(registrationBuffer); + return NS_OK; +} + +U2FTask::U2FTask(const nsAString& aOrigin, const nsAString& aAppId) + : mOrigin(aOrigin) + , mAppId(aAppId) +{} + +U2FTask::~U2FTask() +{} + +U2FRegisterTask::U2FRegisterTask(const nsAString& aOrigin, + const nsAString& aAppId, + const Sequence& aRegisterRequests, + const Sequence& aRegisteredKeys, + U2FRegisterCallback* aCallback, + const nsCOMPtr& aNSSToken) + : U2FTask(aOrigin, aAppId) + , mRegisterRequests(aRegisterRequests) + , mRegisteredKeys(aRegisteredKeys) + , mCallback(aCallback) + , mNSSToken(aNSSToken) +{} + +U2FRegisterTask::~U2FRegisterTask() +{ + nsNSSShutDownPreventionLock locker; + + if (isAlreadyShutDown()) { + return; + } + shutdown(calledFromObject); +} + +void +U2FRegisterTask::ReturnError(ErrorCode aCode) +{ + SendError(mCallback.get(), aCode); +} + +NS_IMETHODIMP +U2FRegisterTask::Run() +{ + nsNSSShutDownPreventionLock locker; + if (isAlreadyShutDown()) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + // TODO: Implement USB Tokens in Bug 1245527 + const bool softTokenEnabled = + Preferences::GetBool(PREF_U2F_SOFTTOKEN_ENABLED); + + for (size_t i = 0; i < mRegisteredKeys.Length(); ++i) { + RegisteredKey request(mRegisteredKeys[i]); + + // Check for required attributes + if (!(request.mKeyHandle.WasPassed() && + request.mVersion.WasPassed())) { + continue; + } + + // Do not permit an individual RegisteredKey to assert a different AppID + if (request.mAppId.WasPassed() && mAppId != request.mAppId.Value()) { + continue; + } + + // Decode the key handle + CryptoBuffer keyHandle; + nsresult rv = keyHandle.FromJwkBase64(request.mKeyHandle.Value()); + if (NS_WARN_IF(NS_FAILED(rv))) { + ReturnError(ErrorCode::BAD_REQUEST); + return NS_ERROR_FAILURE; + } + + // We ignore mTransports, as it is intended to be used for sorting the + // available devices by preference, but is not an exclusion factor. + + bool isCompatible = false; + bool isRegistered = false; + + // Determine if the provided keyHandle is registered at any device. If so, + // then we'll return DEVICE_INELIGIBLE to signify we're already registered. + if (softTokenEnabled) { + rv = NSSTokenIsCompatible(mNSSToken, request.mVersion.Value(), + &isCompatible); + if (NS_FAILED(rv)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + rv = NSSTokenIsRegistered(mNSSToken, keyHandle, &isRegistered); + if (NS_FAILED(rv)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + if (isCompatible && isRegistered) { + ReturnError(ErrorCode::DEVICE_INELIGIBLE); + return NS_OK; + } + } + } + + // Search the requests in order for the first some token can fulfill + for (size_t i = 0; i < mRegisterRequests.Length(); ++i) { + RegisterRequest request(mRegisterRequests[i]); + + // Check for equired attributes + if (!(request.mVersion.WasPassed() && + request.mChallenge.WasPassed())) { + continue; + } + + CryptoBuffer clientData; + nsresult rv = AssembleClientData(mOrigin, kFinishEnrollment, + request.mChallenge.Value(), + clientData); + if (NS_WARN_IF(NS_FAILED(rv))) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + // Hash the AppID and the ClientData into the AppParam and ChallengeParam + SECStatus srv; + nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId); + CryptoBuffer appParam; + CryptoBuffer challengeParam; + if (!appParam.SetLength(SHA256_LENGTH, fallible) || + !challengeParam.SetLength(SHA256_LENGTH, fallible)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(), + reinterpret_cast(cAppId.BeginReading()), + cAppId.Length()); + if (srv != SECSuccess) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(), + clientData.Elements(), clientData.Length()); + if (srv != SECSuccess) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + // Get the registration data from the token + CryptoBuffer regData; + bool registerSuccess = false; + bool isCompatible = false; + + if (!registerSuccess && softTokenEnabled) { + rv = NSSTokenIsCompatible(mNSSToken, request.mVersion.Value(), + &isCompatible); + if (NS_FAILED(rv)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + if (isCompatible) { + rv = NSSTokenRegister(mNSSToken, appParam, challengeParam, regData); + if (NS_FAILED(rv)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + registerSuccess = true; + } + } + + if (!registerSuccess) { + // Try another request + continue; + } + + // Assemble a response object to return + nsString clientDataBase64, registrationDataBase64; + nsresult rvClientData = + clientData.ToJwkBase64(clientDataBase64); + nsresult rvRegistrationData = + regData.ToJwkBase64(registrationDataBase64); + if (NS_WARN_IF(NS_FAILED(rvClientData)) || + NS_WARN_IF(NS_FAILED(rvRegistrationData))) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + RegisterResponse response; + response.mClientData.Construct(clientDataBase64); + response.mRegistrationData.Construct(registrationDataBase64); + response.mErrorCode.Construct(static_cast(ErrorCode::OK)); + + ErrorResult result; + mCallback->Call(response, result); + NS_WARN_IF(result.Failed()); + // Useful exceptions already got reported. + result.SuppressException(); + return NS_OK; + } + + // Nothing could satisfy + ReturnError(ErrorCode::BAD_REQUEST); + return NS_ERROR_FAILURE; +} + +U2FSignTask::U2FSignTask(const nsAString& aOrigin, + const nsAString& aAppId, + const nsAString& aChallenge, + const Sequence& aRegisteredKeys, + U2FSignCallback* aCallback, + const nsCOMPtr& aNSSToken) + : U2FTask(aOrigin, aAppId) + , mChallenge(aChallenge) + , mRegisteredKeys(aRegisteredKeys) + , mCallback(aCallback) + , mNSSToken(aNSSToken) +{} + +U2FSignTask::~U2FSignTask() +{ + nsNSSShutDownPreventionLock locker; + if (isAlreadyShutDown()) { + return; + } + shutdown(calledFromObject); +} + +void +U2FSignTask::ReturnError(ErrorCode aCode) +{ + SendError(mCallback.get(), aCode); +} + +NS_IMETHODIMP +U2FSignTask::Run() +{ + nsNSSShutDownPreventionLock locker; + if (isAlreadyShutDown()) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + // TODO: Implement USB Tokens in Bug 1245527 + const bool softTokenEnabled = + Preferences::GetBool(PREF_U2F_SOFTTOKEN_ENABLED); + + // Search the requests for one a token can fulfill + for (size_t i = 0; i < mRegisteredKeys.Length(); i += 1) { + RegisteredKey request(mRegisteredKeys[i]); + + // Check for required attributes + if (!(request.mVersion.WasPassed() && + request.mKeyHandle.WasPassed())) { + continue; + } + + // Do not permit an individual RegisteredKey to assert a different AppID + if (request.mAppId.WasPassed() && mAppId != request.mAppId.Value()) { + continue; + } + + // Assemble a clientData object + CryptoBuffer clientData; + nsresult rv = AssembleClientData(mOrigin, kGetAssertion, mChallenge, + clientData); + if (NS_WARN_IF(NS_FAILED(rv))) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + // Hash the AppID and the ClientData into the AppParam and ChallengeParam + SECStatus srv; + nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId); + CryptoBuffer appParam; + CryptoBuffer challengeParam; + if (!appParam.SetLength(SHA256_LENGTH, fallible) || + !challengeParam.SetLength(SHA256_LENGTH, fallible)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(), + reinterpret_cast(cAppId.BeginReading()), + cAppId.Length()); + if (srv != SECSuccess) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(), + clientData.Elements(), clientData.Length()); + if (srv != SECSuccess) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + // Decode the key handle + CryptoBuffer keyHandle; + rv = keyHandle.FromJwkBase64(request.mKeyHandle.Value()); + if (NS_WARN_IF(NS_FAILED(rv))) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + // Get the signature from the token + CryptoBuffer signatureData; + bool signSuccess = false; + + // We ignore mTransports, as it is intended to be used for sorting the + // available devices by preference, but is not an exclusion factor. + + if (!signSuccess && softTokenEnabled) { + bool isCompatible = false; + bool isRegistered = false; + + rv = NSSTokenIsCompatible(mNSSToken, request.mVersion.Value(), + &isCompatible); + if (NS_FAILED(rv)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + rv = NSSTokenIsRegistered(mNSSToken, keyHandle, &isRegistered); + if (NS_FAILED(rv)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + + if (isCompatible && isRegistered) { + rv = NSSTokenSign(mNSSToken, keyHandle, appParam, challengeParam, + signatureData); + if (NS_FAILED(rv)) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + signSuccess = true; + } + } + + if (!signSuccess) { + // Try another request + continue; + } + + // Assemble a response object to return + nsString clientDataBase64, signatureDataBase64; + nsresult rvClientData = + clientData.ToJwkBase64(clientDataBase64); + nsresult rvSignatureData = + signatureData.ToJwkBase64(signatureDataBase64); + if (NS_WARN_IF(NS_FAILED(rvClientData)) || + NS_WARN_IF(NS_FAILED(rvSignatureData))) { + ReturnError(ErrorCode::OTHER_ERROR); + return NS_ERROR_FAILURE; + } + SignResponse response; + response.mKeyHandle.Construct(request.mKeyHandle.Value()); + response.mClientData.Construct(clientDataBase64); + response.mSignatureData.Construct(signatureDataBase64); + response.mErrorCode.Construct(static_cast(ErrorCode::OK)); + + ErrorResult result; + mCallback->Call(response, result); + NS_WARN_IF(result.Failed()); + // Useful exceptions already got reported. + result.SuppressException(); + return NS_OK; + } + + // Nothing could satisfy + ReturnError(ErrorCode::DEVICE_INELIGIBLE); + return NS_ERROR_FAILURE; +} + +// EvaluateAppIDAndRunTask determines whether the supplied FIDO AppID is valid for +// the current FacetID, e.g., the current origin. +// See https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-appid-and-facets.html +// for a description of the algorithm. +static void +EvaluateAppIDAndRunTask(U2FTask* aTask) +{ + MOZ_ASSERT(aTask); + + nsCOMPtr urlParser = + do_GetService(NS_STDURLPARSER_CONTRACTID); + + MOZ_ASSERT(urlParser); + + uint32_t facetSchemePos; + int32_t facetSchemeLen; + uint32_t facetAuthPos; + int32_t facetAuthLen; + // Facet is the specification's way of referring to the web origin. + nsAutoCString facetUrl = NS_ConvertUTF16toUTF8(aTask->mOrigin); + nsresult rv = urlParser->ParseURL(facetUrl.get(), aTask->mOrigin.Length(), + &facetSchemePos, &facetSchemeLen, + &facetAuthPos, &facetAuthLen, + nullptr, nullptr); // ignore path + if (NS_WARN_IF(NS_FAILED(rv))) { + aTask->ReturnError(ErrorCode::BAD_REQUEST); + return; + } + + nsAutoCString facetScheme(Substring(facetUrl, facetSchemePos, facetSchemeLen)); + nsAutoCString facetAuth(Substring(facetUrl, facetAuthPos, facetAuthLen)); + + uint32_t appIdSchemePos; + int32_t appIdSchemeLen; + uint32_t appIdAuthPos; + int32_t appIdAuthLen; + // AppID is user-supplied. It's quite possible for this parse to fail. + nsAutoCString appIdUrl = NS_ConvertUTF16toUTF8(aTask->mAppId); + rv = urlParser->ParseURL(appIdUrl.get(), aTask->mAppId.Length(), + &appIdSchemePos, &appIdSchemeLen, + &appIdAuthPos, &appIdAuthLen, + nullptr, nullptr); // ignore path + if (NS_FAILED(rv)) { + aTask->ReturnError(ErrorCode::BAD_REQUEST); + return; + } + + nsAutoCString appIdScheme(Substring(appIdUrl, appIdSchemePos, appIdSchemeLen)); + nsAutoCString appIdAuth(Substring(appIdUrl, appIdAuthPos, appIdAuthLen)); + + // If the facetId (origin) is not HTTPS, reject + if (!facetScheme.LowerCaseEqualsLiteral("https")) { + aTask->ReturnError(ErrorCode::BAD_REQUEST); + return; + } + + // If the appId is empty or null, overwrite it with the facetId and accept + if (aTask->mAppId.IsEmpty() || aTask->mAppId.EqualsLiteral("null")) { + aTask->mAppId.Assign(aTask->mOrigin); + aTask->Run(); + return; + } + + // if the appId URL is not HTTPS, reject. + if (!appIdScheme.LowerCaseEqualsLiteral("https")) { + aTask->ReturnError(ErrorCode::BAD_REQUEST); + return; + } + + // If the facetId and the appId auths match, accept + if (facetAuth == appIdAuth) { + aTask->Run(); + return; + } + + // TODO(Bug 1244959) Implement the remaining algorithm. + aTask->ReturnError(ErrorCode::BAD_REQUEST); + return; +} U2F::U2F() {} @@ -91,6 +671,7 @@ U2F::Init(nsPIDOMWindow* aParent, ErrorResult& aRv) } if (NS_WARN_IF(mOrigin.IsEmpty())) { + aRv.Throw(NS_ERROR_FAILURE); return; } @@ -114,216 +695,6 @@ U2F::Init(nsPIDOMWindow* aParent, ErrorResult& aRv) } } -nsresult -U2F::NSSTokenIsCompatible(const nsString& aVersionString, bool* aIsCompatible) -{ - MOZ_ASSERT(aIsCompatible); - - if (XRE_IsParentProcess()) { - MOZ_ASSERT(mNSSToken); - return mNSSToken->IsCompatibleVersion(aVersionString, aIsCompatible); - } - - ContentChild* cc = ContentChild::GetSingleton(); - MOZ_ASSERT(cc); - if (!cc->SendNSSU2FTokenIsCompatibleVersion(aVersionString, aIsCompatible)) { - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -nsresult -U2F::NSSTokenIsRegistered(CryptoBuffer& aKeyHandle, bool* aIsRegistered) -{ - MOZ_ASSERT(aIsRegistered); - - if (XRE_IsParentProcess()) { - MOZ_ASSERT(mNSSToken); - return mNSSToken->IsRegistered(aKeyHandle.Elements(), aKeyHandle.Length(), - aIsRegistered); - } - - ContentChild* cc = ContentChild::GetSingleton(); - MOZ_ASSERT(cc); - if (!cc->SendNSSU2FTokenIsRegistered(aKeyHandle, aIsRegistered)) { - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -nsresult -U2F::NSSTokenRegister(CryptoBuffer& aApplication, CryptoBuffer& aChallenge, - CryptoBuffer& aRegistrationData) -{ - if (XRE_IsParentProcess()) { - MOZ_ASSERT(mNSSToken); - uint8_t* buffer; - uint32_t bufferlen; - nsresult rv; - rv = mNSSToken->Register(aApplication.Elements(), aApplication.Length(), - aChallenge.Elements(), aChallenge.Length(), - &buffer, &bufferlen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - MOZ_ASSERT(buffer); - aRegistrationData.Assign(buffer, bufferlen); - free(buffer); - return NS_OK; - } - - nsTArray registrationBuffer; - ContentChild* cc = ContentChild::GetSingleton(); - MOZ_ASSERT(cc); - if (!cc->SendNSSU2FTokenRegister(aApplication, aChallenge, - ®istrationBuffer)) { - return NS_ERROR_FAILURE; - } - - aRegistrationData.Assign(registrationBuffer); - return NS_OK; -} - -nsresult -U2F::NSSTokenSign(CryptoBuffer& aKeyHandle, CryptoBuffer& aApplication, - CryptoBuffer& aChallenge, CryptoBuffer& aSignatureData) -{ - if (XRE_IsParentProcess()) { - MOZ_ASSERT(mNSSToken); - uint8_t* buffer; - uint32_t bufferlen; - nsresult rv = mNSSToken->Sign(aApplication.Elements(), aApplication.Length(), - aChallenge.Elements(), aChallenge.Length(), - aKeyHandle.Elements(), aKeyHandle.Length(), - &buffer, &bufferlen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - MOZ_ASSERT(buffer); - aSignatureData.Assign(buffer, bufferlen); - free(buffer); - return NS_OK; - } - - nsTArray signatureBuffer; - ContentChild* cc = ContentChild::GetSingleton(); - MOZ_ASSERT(cc); - if (!cc->SendNSSU2FTokenSign(aApplication, aChallenge, aKeyHandle, - &signatureBuffer)) { - return NS_ERROR_FAILURE; - } - - aSignatureData.Assign(signatureBuffer); - return NS_OK; -} - -nsresult -U2F::AssembleClientData(const nsAString& aTyp, - const nsAString& aChallenge, - CryptoBuffer& aClientData) const -{ - ClientData clientDataObject; - clientDataObject.mTyp.Construct(aTyp); // "Typ" from the U2F specification - clientDataObject.mChallenge.Construct(aChallenge); - clientDataObject.mOrigin.Construct(mOrigin); - - nsAutoString json; - if (NS_WARN_IF(!clientDataObject.ToJSON(json))) { - return NS_ERROR_FAILURE; - } - - if (NS_WARN_IF(!aClientData.Assign(NS_ConvertUTF16toUTF8(json)))) { - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - -bool -U2F::ValidAppID(/* in/out */ nsString& aAppId) const -{ - nsCOMPtr urlParser = - do_GetService(NS_STDURLPARSER_CONTRACTID); - nsCOMPtr tldService = - do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); - - MOZ_ASSERT(urlParser); - MOZ_ASSERT(tldService); - - uint32_t facetSchemePos; - int32_t facetSchemeLen; - uint32_t facetAuthPos; - int32_t facetAuthLen; - // Facet is the specification's way of referring to the web origin. - nsAutoCString facetUrl = NS_ConvertUTF16toUTF8(mOrigin); - nsresult rv = urlParser->ParseURL(facetUrl.get(), mOrigin.Length(), - &facetSchemePos, &facetSchemeLen, - &facetAuthPos, &facetAuthLen, - nullptr, nullptr); // ignore path - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - - nsAutoCString facetScheme(Substring(facetUrl, facetSchemePos, facetSchemeLen)); - nsAutoCString facetAuth(Substring(facetUrl, facetAuthPos, facetAuthLen)); - - uint32_t appIdSchemePos; - int32_t appIdSchemeLen; - uint32_t appIdAuthPos; - int32_t appIdAuthLen; - nsAutoCString appIdUrl = NS_ConvertUTF16toUTF8(aAppId); - rv = urlParser->ParseURL(appIdUrl.get(), aAppId.Length(), - &appIdSchemePos, &appIdSchemeLen, - &appIdAuthPos, &appIdAuthLen, - nullptr, nullptr); // ignore path - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - - nsAutoCString appIdScheme(Substring(appIdUrl, appIdSchemePos, appIdSchemeLen)); - nsAutoCString appIdAuth(Substring(appIdUrl, appIdAuthPos, appIdAuthLen)); - - // If the facetId (origin) is not HTTPS, reject - if (!facetScheme.LowerCaseEqualsLiteral("https")) { - return false; - } - - // If the appId is empty or null, overwrite it with the facetId and accept - if (aAppId.IsEmpty() || aAppId.EqualsLiteral("null")) { - aAppId.Assign(mOrigin); - return true; - } - - // if the appId URL is not HTTPS, reject. - if (!appIdScheme.LowerCaseEqualsLiteral("https")) { - return false; - } - - // If the facetId and the appId auths match, accept - if (facetAuth == appIdAuth) { - return true; - } - - // TODO(Bug 1244959) Implement the remaining algorithm. - return false; -} - -template -void -SendError(CB& aCallback, ErrorCode aErrorCode) -{ - Rsp response; - response.mErrorCode.Construct(static_cast(aErrorCode)); - - ErrorResult rv; - aCallback.Call(response, rv); - NS_WARN_IF(rv.Failed()); - // Useful exceptions already got reported. - rv.SuppressException(); -} - void U2F::Register(const nsAString& aAppId, const Sequence& aRegisterRequests, @@ -332,204 +703,13 @@ U2F::Register(const nsAString& aAppId, const Optional>& opt_aTimeoutSeconds, ErrorResult& aRv) { - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } + RefPtr registerTask = new U2FRegisterTask(mOrigin, aAppId, + aRegisterRequests, + aRegisteredKeys, + &aCallback, + mNSSToken); - const bool softTokenEnabled = - Preferences::GetBool(PREF_U2F_SOFTTOKEN_ENABLED); - - const bool usbTokenEnabled = - Preferences::GetBool(PREF_U2F_USBTOKEN_ENABLED); - - nsAutoString appId(aAppId); - - // Verify the global appId first. - if (!ValidAppID(appId)) { - SendError(aCallback, - ErrorCode::BAD_REQUEST); - return; - } - - for (size_t i = 0; i < aRegisteredKeys.Length(); ++i) { - RegisteredKey request(aRegisteredKeys[i]); - - // Check for required attributes - if (!(request.mKeyHandle.WasPassed() && - request.mVersion.WasPassed())) { - continue; - } - - // Verify the appId for this Registered Key, if set - if (request.mAppId.WasPassed() && - !ValidAppID(request.mAppId.Value())) { - continue; - } - - // Decode the key handle - CryptoBuffer keyHandle; - nsresult rv = keyHandle.FromJwkBase64(request.mKeyHandle.Value()); - if (NS_WARN_IF(NS_FAILED(rv))) { - SendError(aCallback, - ErrorCode::BAD_REQUEST); - return; - } - - // We ignore mTransports, as it is intended to be used for sorting the - // available devices by preference, but is not an exclusion factor. - - bool isCompatible = false; - bool isRegistered = false; - - // Determine if the provided keyHandle is registered at any device. If so, - // then we'll return DEVICE_INELIGIBLE to signify we're already registered. - if (usbTokenEnabled && - mUSBToken.IsCompatibleVersion(request.mVersion.Value()) && - mUSBToken.IsRegistered(keyHandle)) { - SendError(aCallback, - ErrorCode::DEVICE_INELIGIBLE); - return; - } - if (softTokenEnabled) { - rv = NSSTokenIsCompatible(request.mVersion.Value(), &isCompatible); - if (NS_FAILED(rv)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - rv = NSSTokenIsRegistered(keyHandle, &isRegistered); - if (NS_FAILED(rv)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - if (isCompatible && isRegistered) { - SendError(aCallback, - ErrorCode::DEVICE_INELIGIBLE); - return; - } - } - } - - // Search the requests in order for the first some token can fulfill - for (size_t i = 0; i < aRegisterRequests.Length(); ++i) { - RegisterRequest request(aRegisterRequests[i]); - - // Check for equired attributes - if (!(request.mVersion.WasPassed() && - request.mChallenge.WasPassed())) { - continue; - } - - CryptoBuffer clientData; - nsresult rv = AssembleClientData(FinishEnrollment, - request.mChallenge.Value(), - clientData); - if (NS_WARN_IF(NS_FAILED(rv))) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - // Hash the AppID and the ClientData into the AppParam and ChallengeParam - SECStatus srv; - nsCString cAppId = NS_ConvertUTF16toUTF8(appId); - CryptoBuffer appParam; - CryptoBuffer challengeParam; - if (!appParam.SetLength(SHA256_LENGTH, fallible) || - !challengeParam.SetLength(SHA256_LENGTH, fallible)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(), - reinterpret_cast(cAppId.BeginReading()), - cAppId.Length()); - if (srv != SECSuccess) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(), - clientData.Elements(), clientData.Length()); - if (srv != SECSuccess) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - // Get the registration data from the token - CryptoBuffer registrationData; - bool registerSuccess = false; - bool isCompatible = false; - if (usbTokenEnabled) { - // TODO: Implement in Bug 1245527 - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - if (!registerSuccess && softTokenEnabled) { - rv = NSSTokenIsCompatible(request.mVersion.Value(), &isCompatible); - if (NS_FAILED(rv)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - if (isCompatible) { - rv = NSSTokenRegister(appParam, challengeParam, registrationData); - if (NS_FAILED(rv)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - registerSuccess = true; - } - } - - if (!registerSuccess) { - // Try another request - continue; - } - - // Assemble a response object to return - nsString clientDataBase64, registrationDataBase64; - nsresult rvClientData = - clientData.ToJwkBase64(clientDataBase64); - nsresult rvRegistrationData = - registrationData.ToJwkBase64(registrationDataBase64); - if (NS_WARN_IF(NS_FAILED(rvClientData)) || - NS_WARN_IF(NS_FAILED(rvRegistrationData))) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - RegisterResponse response; - response.mClientData.Construct(clientDataBase64); - response.mRegistrationData.Construct(registrationDataBase64); - response.mErrorCode.Construct(static_cast(ErrorCode::OK)); - - ErrorResult result; - aCallback.Call(response, result); - NS_WARN_IF(result.Failed()); - // Useful exceptions already got reported. - result.SuppressException(); - return; - } - - // Nothing could satisfy - SendError(aCallback, - ErrorCode::BAD_REQUEST); - return; + EvaluateAppIDAndRunTask(registerTask); } void @@ -540,175 +720,11 @@ U2F::Sign(const nsAString& aAppId, const Optional>& opt_aTimeoutSeconds, ErrorResult& aRv) { - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } + RefPtr signTask = new U2FSignTask(mOrigin, aAppId, aChallenge, + aRegisteredKeys, &aCallback, + mNSSToken); - const bool softTokenEnabled = - Preferences::GetBool(PREF_U2F_SOFTTOKEN_ENABLED); - - const bool usbTokenEnabled = - Preferences::GetBool(PREF_U2F_USBTOKEN_ENABLED); - - nsAutoString appId(aAppId); - - // Verify the global appId first. - if (!ValidAppID(appId)) { - SendError(aCallback, - ErrorCode::BAD_REQUEST); - return; - } - - // Search the requests for one a token can fulfill - for (size_t i = 0; i < aRegisteredKeys.Length(); i += 1) { - RegisteredKey request(aRegisteredKeys[i]); - - // Check for required attributes - if (!(request.mVersion.WasPassed() && - request.mKeyHandle.WasPassed())) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - continue; - } - - // Allow an individual RegisteredKey to assert a different AppID - nsAutoString regKeyAppId(appId); - if (request.mAppId.WasPassed()) { - regKeyAppId.Assign(request.mAppId.Value()); - if (!ValidAppID(regKeyAppId)) { - continue; - } - } - - // Assemble a clientData object - CryptoBuffer clientData; - nsresult rv = AssembleClientData(GetAssertion, aChallenge, clientData); - if (NS_WARN_IF(NS_FAILED(rv))) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - // Hash the AppID and the ClientData into the AppParam and ChallengeParam - SECStatus srv; - nsCString cAppId = NS_ConvertUTF16toUTF8(regKeyAppId); - CryptoBuffer appParam; - CryptoBuffer challengeParam; - if (!appParam.SetLength(SHA256_LENGTH, fallible) || - !challengeParam.SetLength(SHA256_LENGTH, fallible)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(), - reinterpret_cast(cAppId.BeginReading()), - cAppId.Length()); - if (srv != SECSuccess) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(), - clientData.Elements(), clientData.Length()); - if (srv != SECSuccess) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - // Decode the key handle - CryptoBuffer keyHandle; - rv = keyHandle.FromJwkBase64(request.mKeyHandle.Value()); - if (NS_WARN_IF(NS_FAILED(rv))) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - // Get the signature from the token - CryptoBuffer signatureData; - bool signSuccess = false; - - // We ignore mTransports, as it is intended to be used for sorting the - // available devices by preference, but is not an exclusion factor. - - if (usbTokenEnabled && - mUSBToken.IsCompatibleVersion(request.mVersion.Value())) { - // TODO: Implement in Bug 1245527 - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - if (!signSuccess && softTokenEnabled) { - bool isCompatible = false; - bool isRegistered = false; - - rv = NSSTokenIsCompatible(request.mVersion.Value(), &isCompatible); - if (NS_FAILED(rv)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - rv = NSSTokenIsRegistered(keyHandle, &isRegistered); - if (NS_FAILED(rv)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - - if (isCompatible && isRegistered) { - rv = NSSTokenSign(keyHandle, appParam, challengeParam, signatureData); - if (NS_FAILED(rv)) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - signSuccess = true; - } - } - - if (!signSuccess) { - // Try another request - continue; - } - - // Assemble a response object to return - nsString clientDataBase64, signatureDataBase64; - nsresult rvClientData = - clientData.ToJwkBase64(clientDataBase64); - nsresult rvSignatureData = - signatureData.ToJwkBase64(signatureDataBase64); - if (NS_WARN_IF(NS_FAILED(rvClientData)) || - NS_WARN_IF(NS_FAILED(rvSignatureData))) { - SendError(aCallback, - ErrorCode::OTHER_ERROR); - return; - } - SignResponse response; - response.mKeyHandle.Construct(request.mKeyHandle.Value()); - response.mClientData.Construct(clientDataBase64); - response.mSignatureData.Construct(signatureDataBase64); - response.mErrorCode.Construct(static_cast(ErrorCode::OK)); - - ErrorResult result; - aCallback.Call(response, result); - NS_WARN_IF(result.Failed()); - // Useful exceptions already got reported. - result.SuppressException(); - return; - } - - // Nothing could satisfy - SendError(aCallback, - ErrorCode::DEVICE_INELIGIBLE); - return; + EvaluateAppIDAndRunTask(signTask); } } // namespace dom diff --git a/dom/u2f/U2F.h b/dom/u2f/U2F.h index 87a6622321..a47b16c8f7 100644 --- a/dom/u2f/U2F.h +++ b/dom/u2f/U2F.h @@ -28,11 +28,87 @@ struct RegisteredKey; class U2FRegisterCallback; class U2FSignCallback; -} // namespace dom -} // namespace mozilla +// These enumerations are defined in the FIDO U2F Javascript API under the +// interface "ErrorCode" as constant integers, and thus in the U2F.webidl file. +// Any changes to these must occur in both locations. +enum class ErrorCode { + OK = 0, + OTHER_ERROR = 1, + BAD_REQUEST = 2, + CONFIGURATION_UNSUPPORTED = 3, + DEVICE_INELIGIBLE = 4, + TIMEOUT = 5 +}; -namespace mozilla { -namespace dom { +class U2FTask : public Runnable +{ +public: + U2FTask(const nsAString& aOrigin, + const nsAString& aAppId); + + nsString mOrigin; + nsString mAppId; + + virtual + void ReturnError(ErrorCode code) = 0; + +protected: + virtual ~U2FTask(); +}; + +class U2FRegisterTask final : public nsNSSShutDownObject, + public U2FTask +{ +public: + U2FRegisterTask(const nsAString& aOrigin, + const nsAString& aAppId, + const Sequence& aRegisterRequests, + const Sequence& aRegisteredKeys, + U2FRegisterCallback* aCallback, + const nsCOMPtr& aNSSToken); + + // No NSS resources to release. + virtual + void virtualDestroyNSSReference() override {}; + + void ReturnError(ErrorCode code) override; + + NS_DECL_NSIRUNNABLE +private: + ~U2FRegisterTask(); + + Sequence mRegisterRequests; + Sequence mRegisteredKeys; + RefPtr mCallback; + nsCOMPtr mNSSToken; +}; + +class U2FSignTask final : public nsNSSShutDownObject, + public U2FTask +{ +public: + U2FSignTask(const nsAString& aOrigin, + const nsAString& aAppId, + const nsAString& aChallenge, + const Sequence& aRegisteredKeys, + U2FSignCallback* aCallback, + const nsCOMPtr& aNSSToken); + + // No NSS resources to release. + virtual + void virtualDestroyNSSReference() override {}; + + void ReturnError(ErrorCode code) override; + + NS_DECL_NSIRUNNABLE +private: + ~U2FSignTask(); + + nsString mChallenge; + Sequence mRegisteredKeys; + RefPtr mCallback; + nsCOMPtr mNSSToken; +}; class U2F final : public nsISupports, public nsWrapperCache, @@ -82,37 +158,7 @@ private: USBToken mUSBToken; nsCOMPtr mNSSToken; - static const nsString FinishEnrollment; - static const nsString GetAssertion; - ~U2F(); - - nsresult - AssembleClientData(const nsAString& aTyp, - const nsAString& aChallenge, - CryptoBuffer& aClientData) const; - - // ValidAppID determines whether the supplied FIDO AppID is valid for - // the current FacetID, e.g., the current origin. If the supplied - // aAppId param is null or empty, it will be filled in per the algorithm. - // See https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-appid-and-facets.html - // for a description of the algorithm. - bool - ValidAppID(/* in/out */ nsString& aAppId) const; - - nsresult - NSSTokenIsCompatible(const nsString& versionString, bool* isCompatible); - - nsresult - NSSTokenIsRegistered(CryptoBuffer& keyHandle, bool* isRegistered); - - nsresult - NSSTokenRegister(CryptoBuffer& application, CryptoBuffer& challenge, - CryptoBuffer& registrationData); - - nsresult - NSSTokenSign(CryptoBuffer& keyHandle, CryptoBuffer& application, - CryptoBuffer& challenge, CryptoBuffer& signatureData); }; } // namespace dom diff --git a/dom/u2f/tests/facet/facetList-good b/dom/u2f/tests/facet/facetList-good deleted file mode 100644 index e141988b77..0000000000 --- a/dom/u2f/tests/facet/facetList-good +++ /dev/null @@ -1,8 +0,0 @@ -{ - "trustedFacets" : [{ - "version": { "major": 1, "minor" : 0 }, - "ids": [ - "https://fido.example.com" - ] - }] -} \ No newline at end of file diff --git a/dom/u2f/tests/facet/facetList-good^headers^ b/dom/u2f/tests/facet/facetList-good^headers^ deleted file mode 100644 index a12b2b7e42..0000000000 --- a/dom/u2f/tests/facet/facetList-good^headers^ +++ /dev/null @@ -1 +0,0 @@ -Content-Type: application/fido.trusted-apps+json \ No newline at end of file diff --git a/dom/u2f/tests/facet/facetList-invalid_format b/dom/u2f/tests/facet/facetList-invalid_format deleted file mode 100644 index a11c9d5e51..0000000000 --- a/dom/u2f/tests/facet/facetList-invalid_format +++ /dev/null @@ -1,6 +0,0 @@ -# This file isn't actually JSON, so it shouldn't successfully parse. -{ - "trustedFacets" : [{ - "version": { "major": 1, "minor" : 0 }, - },{}] -} \ No newline at end of file diff --git a/dom/u2f/tests/facet/facetList-invalid_format^headers^ b/dom/u2f/tests/facet/facetList-invalid_format^headers^ deleted file mode 100644 index a12b2b7e42..0000000000 --- a/dom/u2f/tests/facet/facetList-invalid_format^headers^ +++ /dev/null @@ -1 +0,0 @@ -Content-Type: application/fido.trusted-apps+json \ No newline at end of file diff --git a/dom/u2f/tests/facet/facetList-no_overlap b/dom/u2f/tests/facet/facetList-no_overlap deleted file mode 100644 index 7ed2a3b9c5..0000000000 --- a/dom/u2f/tests/facet/facetList-no_overlap +++ /dev/null @@ -1,9 +0,0 @@ -{ - "trustedFacets" : [{ - "version": { "major": 1, "minor" : 0 }, - "ids": [ - "https://example.net", - "http://www.example.com" - ] - }] -} \ No newline at end of file diff --git a/dom/u2f/tests/facet/facetList-no_overlap^headers^ b/dom/u2f/tests/facet/facetList-no_overlap^headers^ deleted file mode 100644 index a12b2b7e42..0000000000 --- a/dom/u2f/tests/facet/facetList-no_overlap^headers^ +++ /dev/null @@ -1 +0,0 @@ -Content-Type: application/fido.trusted-apps+json \ No newline at end of file diff --git a/dom/u2f/tests/facet/facetList.txt b/dom/u2f/tests/facet/facetList.txt deleted file mode 100644 index e141988b77..0000000000 --- a/dom/u2f/tests/facet/facetList.txt +++ /dev/null @@ -1,8 +0,0 @@ -{ - "trustedFacets" : [{ - "version": { "major": 1, "minor" : 0 }, - "ids": [ - "https://fido.example.com" - ] - }] -} \ No newline at end of file diff --git a/dom/u2f/tests/mochitest.ini b/dom/u2f/tests/mochitest.ini index a39e92eb75..f278f5dc08 100644 --- a/dom/u2f/tests/mochitest.ini +++ b/dom/u2f/tests/mochitest.ini @@ -5,16 +5,8 @@ support-files = test_frame_appid_facet.html test_frame_register.html test_frame_register_sign.html - test_frame_appid_facet_remoteload.html test_frame_appid_facet_insecure.html test_frame_appid_facet_subdomain.html - facet/facetList.txt - facet/facetList-good - facet/facetList-good^headers^ - facet/facetList-no_overlap - facet/facetList-no_overlap^headers^ - facet/facetList-invalid_format - facet/facetList-invalid_format^headers^ pkijs/common.js pkijs/asn1.js pkijs/x509_schema.js diff --git a/dom/u2f/tests/test_frame.html b/dom/u2f/tests/test_frame.html index 7740c37b84..70d6884a7b 100644 --- a/dom/u2f/tests/test_frame.html +++ b/dom/u2f/tests/test_frame.html @@ -26,7 +26,6 @@ function() { "https://example.com/tests/dom/u2f/tests/test_frame_register_sign.html", "http://mochi.test:8888/tests/dom/u2f/tests/test_frame_appid_facet_insecure.html", "https://example.com/tests/dom/u2f/tests/test_frame_appid_facet.html", - "https://example.com/tests/dom/u2f/tests/test_frame_appid_facet_remoteload.html", "https://test1.example.com/tests/dom/u2f/tests/test_frame_appid_facet_subdomain.html" ]; diff --git a/dom/u2f/tests/test_frame_appid_facet_remoteload.html b/dom/u2f/tests/test_frame_appid_facet_remoteload.html deleted file mode 100644 index b3ba3921de..0000000000 --- a/dom/u2f/tests/test_frame_appid_facet_remoteload.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - -

Test for Remote AppId Load behavior for FIDO Universal Second Factor

- - - diff --git a/dom/u2f/tests/test_frame_register_sign.html b/dom/u2f/tests/test_frame_register_sign.html index fd46e67385..e0cf4cb1c0 100644 --- a/dom/u2f/tests/test_frame_register_sign.html +++ b/dom/u2f/tests/test_frame_register_sign.html @@ -82,9 +82,9 @@ function() { var clientDataJSON = ""; base64ToBytesUrlSafe(regResponse.clientData).map(x => clientDataJSON += String.fromCharCode(x)); var clientData = JSON.parse(clientDataJSON); - local_is(clientData.typ, "navigator.id.finishEnrollment", "Data type matches"); - local_is(clientData.challenge, state.regRequest.challenge, "Register challenge matches"); - local_is(clientData.origin, window.location.origin, "Origins are the same"); + local_is(clientData.typ, "navigator.id.finishEnrollment", "Register - Data type matches"); + local_is(clientData.challenge, state.regRequest.challenge, "Register - Challenge matches"); + local_is(clientData.origin, window.location.origin, "Register - Origins are the same"); // Verify the signature from the attestation certificate deriveAppAndChallengeParam(state.appId, string2buffer(clientDataJSON)) @@ -161,9 +161,9 @@ function() { var clientDataJSON = ""; base64ToBytesUrlSafe(signResponse.clientData).map(x => clientDataJSON += String.fromCharCode(x)); var clientData = JSON.parse(clientDataJSON); - local_is(clientData.typ, "navigator.id.getAssertion", "Data type matches"); - local_is(clientData.challenge, state.signChallenge, "Sign challenge matches"); - local_is(clientData.origin, window.location.origin, "Origins are the same"); + local_is(clientData.typ, "navigator.id.getAssertion", "Sign - Data type matches"); + local_is(clientData.challenge, state.signChallenge, "Sign - Challenge matches"); + local_is(clientData.origin, window.location.origin, "Sign - Origins are the same"); // Parse the signature data var signatureData = base64ToBytesUrlSafe(signResponse.signatureData); diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 49fabef01b..9e89f951c9 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -13,6 +13,7 @@ * https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html * https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html * http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html + * https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object */ interface ApplicationCache; @@ -418,6 +419,11 @@ partial interface Window { readonly attribute Console console; }; +// https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object +partial interface Window { + readonly attribute boolean isSecureContext; +}; + #ifdef HAVE_SIDEBAR // Mozilla extension partial interface Window { diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 9e5bf4604c..e1c5214af4 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -585,7 +585,7 @@ InterruptCallback(JSContext* aCx) return worker->InterruptCallback(aCx); } -class LogViolationDetailsRunnable final : public nsRunnable +class LogViolationDetailsRunnable final : public Runnable { WorkerPrivate* mWorkerPrivate; nsCOMPtr mSyncLoopTarget; @@ -1035,13 +1035,13 @@ private: } }; -class WorkerThreadPrimaryRunnable final : public nsRunnable +class WorkerThreadPrimaryRunnable final : public Runnable { WorkerPrivate* mWorkerPrivate; RefPtr mThread; JSRuntime* mParentRuntime; - class FinishedRunnable final : public nsRunnable + class FinishedRunnable final : public Runnable { RefPtr mThread; @@ -2594,7 +2594,7 @@ RuntimeService::JSVersionChanged(const char* /* aPrefName */, void* /* aClosure options.behaviors().setVersion(useLatest ? JSVERSION_LATEST : JSVERSION_DEFAULT); } -NS_IMPL_ISUPPORTS_INHERITED0(LogViolationDetailsRunnable, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(LogViolationDetailsRunnable, Runnable) NS_IMETHODIMP LogViolationDetailsRunnable::Run() @@ -2622,7 +2622,7 @@ LogViolationDetailsRunnable::Run() NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback) -NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, Runnable) NS_IMETHODIMP WorkerThreadPrimaryRunnable::Run() @@ -2775,7 +2775,7 @@ WorkerThreadPrimaryRunnable::SynchronouslyCreatePBackground() } NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable, - nsRunnable) + Runnable) NS_IMETHODIMP WorkerThreadPrimaryRunnable::FinishedRunnable::Run() diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 7dd46cc1d8..1dc85d8fe9 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -1632,7 +1632,7 @@ CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCont return NS_OK; } -class ChannelGetterRunnable final : public nsRunnable +class ChannelGetterRunnable final : public Runnable { WorkerPrivate* mParentWorker; nsCOMPtr mSyncLoopTarget; diff --git a/dom/workers/ServiceWorkerClient.cpp b/dom/workers/ServiceWorkerClient.cpp index 9493785039..a40b7792b0 100644 --- a/dom/workers/ServiceWorkerClient.cpp +++ b/dom/workers/ServiceWorkerClient.cpp @@ -83,7 +83,7 @@ ServiceWorkerClient::WrapObject(JSContext* aCx, JS::Handle aGivenProt namespace { class ServiceWorkerClientPostMessageRunnable final - : public nsRunnable + : public Runnable , public StructuredCloneHolder { uint64_t mWindowId; diff --git a/dom/workers/ServiceWorkerClients.cpp b/dom/workers/ServiceWorkerClients.cpp index 47bae64cb1..0f6ee4287c 100644 --- a/dom/workers/ServiceWorkerClients.cpp +++ b/dom/workers/ServiceWorkerClients.cpp @@ -60,7 +60,7 @@ ServiceWorkerClients::WrapObject(JSContext* aCx, JS::Handle aGivenPro namespace { -class GetRunnable final : public nsRunnable +class GetRunnable final : public Runnable { class ResolvePromiseWorkerRunnable final : public WorkerRunnable { @@ -142,7 +142,7 @@ public: } }; -class MatchAllRunnable final : public nsRunnable +class MatchAllRunnable final : public Runnable { class ResolvePromiseWorkerRunnable final : public WorkerRunnable { @@ -256,7 +256,7 @@ public: } }; -class ClaimRunnable final : public nsRunnable +class ClaimRunnable final : public Runnable { RefPtr mPromiseProxy; nsCString mScope; @@ -469,7 +469,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebProgressListener) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END -class OpenWindowRunnable final : public nsRunnable +class OpenWindowRunnable final : public Runnable { RefPtr mPromiseProxy; nsString mUrl; diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index 6e61ac0356..72aab12b26 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -156,7 +156,7 @@ FetchEvent::Constructor(const GlobalObject& aGlobal, namespace { -class FinishResponse final : public nsRunnable +class FinishResponse final : public Runnable { nsMainThreadPtrHandle mChannel; RefPtr mInternalResponse; diff --git a/dom/workers/ServiceWorkerEvents.h b/dom/workers/ServiceWorkerEvents.h index 5c8c5d41a1..09e00237d8 100644 --- a/dom/workers/ServiceWorkerEvents.h +++ b/dom/workers/ServiceWorkerEvents.h @@ -38,7 +38,7 @@ struct PushEventInit; BEGIN_WORKERS_NAMESPACE -class CancelChannelRunnable final : public nsRunnable +class CancelChannelRunnable final : public Runnable { nsMainThreadPtrHandle mChannel; const nsresult mStatus; diff --git a/dom/workers/ServiceWorkerInfo.cpp b/dom/workers/ServiceWorkerInfo.cpp index 265d519c33..832a96a531 100644 --- a/dom/workers/ServiceWorkerInfo.cpp +++ b/dom/workers/ServiceWorkerInfo.cpp @@ -81,7 +81,7 @@ ServiceWorkerInfo::RemoveWorker(ServiceWorker* aWorker) namespace { -class ChangeStateUpdater final : public nsRunnable +class ChangeStateUpdater final : public Runnable { public: ChangeStateUpdater(const nsTArray& aInstances, diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index 9a1ee542bc..1715fed700 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -190,7 +190,7 @@ PopulateRegistrationData(nsIPrincipal* aPrincipal, return NS_OK; } -class TeardownRunnable final : public nsRunnable +class TeardownRunnable final : public Runnable { public: explicit TeardownRunnable(ServiceWorkerManagerChild* aActor) @@ -405,7 +405,7 @@ GetRequiredScopeStringPrefix(nsIURI* aScriptURI, nsACString& aPrefix, return NS_OK; } -class PropagateSoftUpdateRunnable final : public nsRunnable +class PropagateSoftUpdateRunnable final : public Runnable { public: PropagateSoftUpdateRunnable(const OriginAttributes& aOriginAttributes, @@ -433,7 +433,7 @@ private: const nsString mScope; }; -class PropagateUnregisterRunnable final : public nsRunnable +class PropagateUnregisterRunnable final : public Runnable { public: PropagateUnregisterRunnable(nsIPrincipal* aPrincipal, @@ -470,7 +470,7 @@ private: const nsString mScope; }; -class RemoveRunnable final : public nsRunnable +class RemoveRunnable final : public Runnable { public: explicit RemoveRunnable(const nsACString& aHost) @@ -494,7 +494,7 @@ private: const nsCString mHost; }; -class PropagateRemoveRunnable final : public nsRunnable +class PropagateRemoveRunnable final : public Runnable { public: explicit PropagateRemoveRunnable(const nsACString& aHost) @@ -518,7 +518,7 @@ private: const nsCString mHost; }; -class PropagateRemoveAllRunnable final : public nsRunnable +class PropagateRemoveAllRunnable final : public Runnable { public: PropagateRemoveAllRunnable() @@ -555,7 +555,7 @@ IsFromAuthenticatedOrigin(nsIDocument* aDoc) } while (doc && !nsContentUtils::IsChromeDoc(doc)) { - bool trustworthyURI = false; + bool trustworthyOrigin = false; // The origin of the document may be different from the document URI // itself. Check the principal, not the document URI itself. @@ -565,15 +565,8 @@ IsFromAuthenticatedOrigin(nsIDocument* aDoc) // principal inside the loop. MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(documentPrincipal)); - // Pass the principal as a URI to the security manager - nsCOMPtr uri; - documentPrincipal->GetURI(getter_AddRefs(uri)); - if (NS_WARN_IF(!uri)) { - return false; - } - - csm->IsURIPotentiallyTrustworthy(uri, &trustworthyURI); - if (!trustworthyURI) { + csm->IsOriginPotentiallyTrustworthy(documentPrincipal, &trustworthyOrigin); + if (!trustworthyOrigin) { return false; } @@ -654,7 +647,7 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow, return NS_ERROR_DOM_SECURITY_ERR; } - // The IsURIPotentiallyTrustworthy() check allows file:// and possibly other + // The IsOriginPotentiallyTrustworthy() check allows file:// and possibly other // URI schemes. We need to explicitly only allows http and https schemes. // Note, we just use the aScriptURI here for the check since its already // been verified as same origin with the document principal. This also @@ -739,7 +732,7 @@ ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable) /* * Implements the async aspects of the getRegistrations algorithm. */ -class GetRegistrationsRunnable final : public nsRunnable +class GetRegistrationsRunnable final : public Runnable { nsCOMPtr mWindow; RefPtr mPromise; @@ -854,7 +847,7 @@ ServiceWorkerManager::GetRegistrations(nsIDOMWindow* aWindow, /* * Implements the async aspects of the getRegistration algorithm. */ -class GetRegistrationRunnable final : public nsRunnable +class GetRegistrationRunnable final : public Runnable { nsCOMPtr mWindow; RefPtr mPromise; @@ -956,7 +949,7 @@ ServiceWorkerManager::GetRegistration(nsIDOMWindow* aWindow, return NS_DispatchToCurrentThread(runnable); } -class GetReadyPromiseRunnable final : public nsRunnable +class GetReadyPromiseRunnable final : public Runnable { nsCOMPtr mWindow; RefPtr mPromise; @@ -2175,7 +2168,7 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow, namespace { -class ContinueDispatchFetchEventRunnable : public nsRunnable +class ContinueDispatchFetchEventRunnable : public Runnable { RefPtr mServiceWorkerPrivate; nsCOMPtr mChannel; diff --git a/dom/workers/ServiceWorkerManagerParent.cpp b/dom/workers/ServiceWorkerManagerParent.cpp index 8ded04c0b5..6c4ebf2416 100644 --- a/dom/workers/ServiceWorkerManagerParent.cpp +++ b/dom/workers/ServiceWorkerManagerParent.cpp @@ -25,7 +25,7 @@ namespace { uint64_t sServiceWorkerManagerParentID = 0; -class RegisterServiceWorkerCallback final : public nsRunnable +class RegisterServiceWorkerCallback final : public Runnable { public: RegisterServiceWorkerCallback(const ServiceWorkerRegistrationData& aData, @@ -63,7 +63,7 @@ private: const uint64_t mParentID; }; -class UnregisterServiceWorkerCallback final : public nsRunnable +class UnregisterServiceWorkerCallback final : public Runnable { public: UnregisterServiceWorkerCallback(const PrincipalInfo& aPrincipalInfo, @@ -106,12 +106,12 @@ private: uint64_t mParentID; }; -class CheckPrincipalWithCallbackRunnable final : public nsRunnable +class CheckPrincipalWithCallbackRunnable final : public Runnable { public: CheckPrincipalWithCallbackRunnable(already_AddRefed aParent, const PrincipalInfo& aPrincipalInfo, - nsRunnable* aCallback) + Runnable* aCallback) : mContentParent(aParent) , mPrincipalInfo(aPrincipalInfo) , mCallback(aCallback) @@ -146,7 +146,7 @@ public: private: RefPtr mContentParent; PrincipalInfo mPrincipalInfo; - RefPtr mCallback; + RefPtr mCallback; nsCOMPtr mBackgroundThread; }; diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp index 7c3584e512..f03266cf02 100644 --- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -234,7 +234,7 @@ public: NS_IMPL_ISUPPORTS0(KeepAliveHandler) -class RegistrationUpdateRunnable : public nsRunnable +class RegistrationUpdateRunnable : public Runnable { nsMainThreadPtrHandle mRegistration; const bool mNeedTimeCheck; @@ -1272,7 +1272,7 @@ public: private: ~FetchEventRunnable() {} - class ResumeRequest final : public nsRunnable { + class ResumeRequest final : public Runnable { nsMainThreadPtrHandle mChannel; public: explicit ResumeRequest(nsMainThreadPtrHandle& aChannel) diff --git a/dom/workers/ServiceWorkerPrivate.h b/dom/workers/ServiceWorkerPrivate.h index 512b29df38..181961e65c 100644 --- a/dom/workers/ServiceWorkerPrivate.h +++ b/dom/workers/ServiceWorkerPrivate.h @@ -21,7 +21,7 @@ class ServiceWorkerInfo; class ServiceWorkerRegistrationInfo; class KeepAliveToken; -class LifeCycleEventCallback : public nsRunnable +class LifeCycleEventCallback : public Runnable { public: // Called on the worker thread. diff --git a/dom/workers/ServiceWorkerRegistrar.cpp b/dom/workers/ServiceWorkerRegistrar.cpp index 822ee48002..b3808fd0a4 100644 --- a/dom/workers/ServiceWorkerRegistrar.cpp +++ b/dom/workers/ServiceWorkerRegistrar.cpp @@ -1,3 +1,4 @@ + /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public @@ -440,7 +441,7 @@ ServiceWorkerRegistrar::DeleteData() } } -class ServiceWorkerRegistrarSaveDataRunnable final : public nsRunnable +class ServiceWorkerRegistrarSaveDataRunnable final : public Runnable { public: ServiceWorkerRegistrarSaveDataRunnable() @@ -457,7 +458,7 @@ public: service->SaveData(); - RefPtr runnable = + RefPtr runnable = NS_NewRunnableMethod(service, &ServiceWorkerRegistrar::DataSaved); nsresult rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -481,7 +482,7 @@ ServiceWorkerRegistrar::ScheduleSaveData() do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); MOZ_ASSERT(target, "Must have stream transport service"); - RefPtr runnable = + RefPtr runnable = new ServiceWorkerRegistrarSaveDataRunnable(); nsresult rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -531,7 +532,7 @@ ServiceWorkerRegistrar::MaybeScheduleShutdownCompleted() return; } - RefPtr runnable = + RefPtr runnable = NS_NewRunnableMethod(this, &ServiceWorkerRegistrar::ShutdownCompleted); nsresult rv = NS_DispatchToMainThread(runnable); if (NS_WARN_IF(NS_FAILED(rv))) { diff --git a/dom/workers/ServiceWorkerRegistration.cpp b/dom/workers/ServiceWorkerRegistration.cpp index 02f9c5c835..f87e63d10c 100644 --- a/dom/workers/ServiceWorkerRegistration.cpp +++ b/dom/workers/ServiceWorkerRegistration.cpp @@ -396,7 +396,7 @@ public: } }; -class UpdateRunnable final : public nsRunnable +class UpdateRunnable final : public Runnable { public: UpdateRunnable(PromiseWorkerProxy* aPromiseProxy, @@ -564,7 +564,7 @@ NS_IMPL_ISUPPORTS(WorkerUnregisterCallback, nsIServiceWorkerUnregisterCallback); * If the worker goes away, we still continue to unregister, but we don't try to * resolve the worker Promise (which doesn't exist by that point). */ -class StartUnregisterRunnable final : public nsRunnable +class StartUnregisterRunnable final : public Runnable { RefPtr mPromiseWorkerProxy; const nsString mScope; @@ -1014,7 +1014,7 @@ ServiceWorkerRegistrationWorkerThread::Unregister(ErrorResult& aRv) return promise.forget(); } -class StartListeningRunnable final : public nsRunnable +class StartListeningRunnable final : public Runnable { RefPtr mListener; public: @@ -1050,7 +1050,7 @@ ServiceWorkerRegistrationWorkerThread::InitListener() MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); } -class AsyncStopListeningRunnable final : public nsRunnable +class AsyncStopListeningRunnable final : public Runnable { RefPtr mListener; public: diff --git a/dom/workers/ServiceWorkerWindowClient.cpp b/dom/workers/ServiceWorkerWindowClient.cpp index 8b036f412b..2122a2468f 100644 --- a/dom/workers/ServiceWorkerWindowClient.cpp +++ b/dom/workers/ServiceWorkerWindowClient.cpp @@ -72,7 +72,7 @@ public: } }; -class ClientFocusRunnable final : public nsRunnable +class ClientFocusRunnable final : public Runnable { uint64_t mWindowId; RefPtr mPromiseProxy; diff --git a/dom/workers/URL.cpp b/dom/workers/URL.cpp index 55eee1ef86..13f2f481ed 100644 --- a/dom/workers/URL.cpp +++ b/dom/workers/URL.cpp @@ -283,7 +283,7 @@ public: } }; -class TeardownURLRunnable : public nsRunnable +class TeardownURLRunnable : public Runnable { public: explicit TeardownURLRunnable(URLProxy* aURLProxy) diff --git a/dom/workers/WorkerDebuggerManager.cpp b/dom/workers/WorkerDebuggerManager.cpp index c0b83255b2..dfd7e5acc3 100644 --- a/dom/workers/WorkerDebuggerManager.cpp +++ b/dom/workers/WorkerDebuggerManager.cpp @@ -16,7 +16,7 @@ USING_WORKERS_NAMESPACE namespace { -class RegisterDebuggerMainThreadRunnable final : public nsRunnable +class RegisterDebuggerMainThreadRunnable final : public mozilla::Runnable { WorkerPrivate* mWorkerPrivate; bool mNotifyListeners; @@ -43,7 +43,7 @@ private: } }; -class UnregisterDebuggerMainThreadRunnable final : public nsRunnable +class UnregisterDebuggerMainThreadRunnable final : public mozilla::Runnable { WorkerPrivate* mWorkerPrivate; diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 275fdff553..4efd3ce5bb 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -330,7 +330,7 @@ LogErrorToConsole(const nsAString& aMessage, fflush(stderr); } -class MainThreadReleaseRunnable final : public nsRunnable +class MainThreadReleaseRunnable final : public Runnable { nsTArray> mDoomed; nsCOMPtr mLoadGroupToCancel; @@ -414,7 +414,7 @@ private: } }; -class TopLevelWorkerFinishedRunnable final : public nsRunnable +class TopLevelWorkerFinishedRunnable final : public Runnable { WorkerPrivate* mFinishedWorker; @@ -1725,9 +1725,9 @@ PRThreadFromThread(nsIThread* aThread) } /* anonymous namespace */ -NS_IMPL_ISUPPORTS_INHERITED0(MainThreadReleaseRunnable, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(MainThreadReleaseRunnable, Runnable) -NS_IMPL_ISUPPORTS_INHERITED0(TopLevelWorkerFinishedRunnable, nsRunnable) +NS_IMPL_ISUPPORTS_INHERITED0(TopLevelWorkerFinishedRunnable, Runnable) TimerThreadEventTarget::TimerThreadEventTarget(WorkerPrivate* aWorkerPrivate, WorkerRunnable* aWorkerRunnable) @@ -3597,7 +3597,7 @@ WorkerPrivateParent::AssertInnerWindowIsCorrect() const #endif -class PostDebuggerMessageRunnable final : public nsRunnable +class PostDebuggerMessageRunnable final : public Runnable { WorkerDebugger *mDebugger; nsString mMessage; @@ -3623,7 +3623,7 @@ private: } }; -class ReportDebuggerErrorRunnable final : public nsRunnable +class ReportDebuggerErrorRunnable final : public Runnable { WorkerDebugger *mDebugger; nsString mFilename; diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp index 7f6b5386b5..8a00e62eeb 100644 --- a/dom/workers/WorkerRunnable.cpp +++ b/dom/workers/WorkerRunnable.cpp @@ -500,7 +500,7 @@ StopSyncLoopRunnable::WorkerRun(JSContext* aCx, mSyncLoopTarget.swap(syncLoopTarget); if (!mResult) { - MaybeSetException(aCx); + MaybeSetException(); } aWorkerPrivate->StopSyncLoop(syncLoopTarget, mResult); diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h index a8ca309ebb..412aeb4b2a 100644 --- a/dom/workers/WorkerRunnable.h +++ b/dom/workers/WorkerRunnable.h @@ -286,10 +286,14 @@ protected: virtual ~StopSyncLoopRunnable() { } - // Called on the worker thread to set an exception on the context if mResult - // is false. Override if you need an exception. + // Called on the worker thread, in WorkerRun, right before stopping the + // syncloop to set an exception (however subclasses want to handle that) if + // mResult is false. Note that overrides of this method must NOT set an + // actual exception on the JSContext; they may only set some state that will + // get turned into an exception once the syncloop actually terminates and + // control is returned to whoever was spinning the syncloop. virtual void - MaybeSetException(JSContext* aCx) + MaybeSetException() { } private: @@ -420,7 +424,7 @@ protected: // dispatch the tasks from the worker thread to the main thread. // // Note that the derived class must override MainThreadRun. -class WorkerMainThreadRunnable : public nsRunnable +class WorkerMainThreadRunnable : public Runnable { protected: WorkerPrivate* mWorkerPrivate; diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index 2430d04b0b..77b79c0885 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -585,7 +585,7 @@ public: } }; -class WorkerScopeSkipWaitingRunnable final : public nsRunnable +class WorkerScopeSkipWaitingRunnable final : public Runnable { RefPtr mPromiseProxy; nsCString mScope; diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 7e2ff0bfd2..687fbefe80 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -186,7 +186,7 @@ private: } }; -class WorkerThreadProxySyncRunnable : public nsRunnable +class WorkerThreadProxySyncRunnable : public Runnable { protected: WorkerPrivate* mWorkerPrivate; @@ -194,18 +194,26 @@ protected: nsCOMPtr mSyncLoopTarget; private: + // mRv is set on the worker thread by the constructor. Must not be touched on + // the main thread, except for copying the reference to the ResponseRunnable. + ErrorResult& mRv; + class ResponseRunnable final: public MainThreadStopSyncLoopRunnable { RefPtr mProxy; nsresult mErrorCode; + // mRv is set on the main thread by the constructor. Must not be touched on + // the main thread otherwise. + ErrorResult& mRv; public: ResponseRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - nsresult aErrorCode) + nsresult aErrorCode, ErrorResult& aRv) : MainThreadStopSyncLoopRunnable(aWorkerPrivate, aProxy->GetEventTarget(), NS_SUCCEEDED(aErrorCode)), - mProxy(aProxy), mErrorCode(aErrorCode) + mProxy(aProxy), mErrorCode(aErrorCode), mRv(aRv) { + AssertIsOnMainThread(); MOZ_ASSERT(aProxy); } @@ -214,26 +222,26 @@ private: { } virtual void - MaybeSetException(JSContext* aCx) override + MaybeSetException() override { + mWorkerPrivate->AssertIsOnWorkerThread(); MOZ_ASSERT(NS_FAILED(mErrorCode)); - Throw(aCx, mErrorCode); + mRv.Throw(mErrorCode); } }; public: - WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) - : mWorkerPrivate(aWorkerPrivate), mProxy(aProxy) + WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, + ErrorResult& aRv) + : mWorkerPrivate(aWorkerPrivate), mProxy(aProxy), mRv(aRv) { MOZ_ASSERT(aWorkerPrivate); MOZ_ASSERT(aProxy); aWorkerPrivate->AssertIsOnWorkerThread(); } - NS_DECL_ISUPPORTS_INHERITED - - bool + void Dispatch() { mWorkerPrivate->AssertIsOnWorkerThread(); @@ -242,10 +250,13 @@ public: mSyncLoopTarget = syncLoop.EventTarget(); if (NS_FAILED(NS_DispatchToMainThread(this))) { - return false; + MOZ_CRASH("How can this not work? No good will come of this"); } - return syncLoop.Run(); + DebugOnly ok = syncLoop.Run(); + // If !ok, then our ResponseRunnable had a failing nsresult and should have + // stashed it in mRv. + MOZ_ASSERT_IF(!ok, mRv.Failed()); } protected: @@ -269,8 +280,8 @@ class SendRunnable final public: SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - const nsAString& aStringBody) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) + const nsAString& aStringBody, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv) , StructuredCloneHolder(CloningSupported, TransferringNotSupported, SameProcessDifferentThread) , mStringBody(aStringBody) @@ -409,7 +420,7 @@ private: } }; -class AsyncTeardownRunnable final : public nsRunnable +class AsyncTeardownRunnable final : public Runnable { RefPtr mProxy; @@ -420,8 +431,6 @@ public: MOZ_ASSERT(aProxy); } - NS_DECL_ISUPPORTS_INHERITED - private: ~AsyncTeardownRunnable() { } @@ -440,7 +449,7 @@ private: } }; -class LoadStartDetectionRunnable final : public nsRunnable, +class LoadStartDetectionRunnable final : public Runnable, public nsIDOMEventListener { WorkerPrivate* mWorkerPrivate; @@ -598,8 +607,9 @@ private: class SyncTeardownRunnable final : public WorkerThreadProxySyncRunnable { public: - SyncTeardownRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) + SyncTeardownRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, + ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv) { } private: @@ -622,8 +632,8 @@ class SetBackgroundRequestRunnable final : public: SetBackgroundRequestRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - bool aValue) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mValue(aValue) + bool aValue, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), mValue(aValue) { } private: @@ -644,8 +654,8 @@ class SetWithCredentialsRunnable final : public: SetWithCredentialsRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - bool aValue) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mValue(aValue) + bool aValue, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), mValue(aValue) { } private: @@ -665,8 +675,8 @@ class SetResponseTypeRunnable final : public WorkerThreadProxySyncRunnable public: SetResponseTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - const nsAString& aResponseType) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), + const nsAString& aResponseType, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), mResponseType(aResponseType) { } @@ -698,8 +708,9 @@ class SetTimeoutRunnable final : public WorkerThreadProxySyncRunnable public: SetTimeoutRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - uint32_t aTimeout) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mTimeout(aTimeout) + uint32_t aTimeout, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), + mTimeout(aTimeout) { } private: @@ -716,8 +727,8 @@ private: class AbortRunnable final : public WorkerThreadProxySyncRunnable { public: - AbortRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) + AbortRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv) { } private: @@ -735,8 +746,8 @@ class GetAllResponseHeadersRunnable final : public: GetAllResponseHeadersRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - nsCString& aResponseHeaders) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), + nsCString& aResponseHeaders, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), mResponseHeaders(aResponseHeaders) { } @@ -759,8 +770,10 @@ class GetResponseHeaderRunnable final : public WorkerThreadProxySyncRunnable public: GetResponseHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - const nsACString& aHeader, nsCString& aValue) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mHeader(aHeader), + const nsACString& aHeader, nsCString& aValue, + ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), + mHeader(aHeader), mValue(aValue) { } @@ -793,8 +806,9 @@ public: const Optional& aUser, const Optional& aPassword, bool aBackgroundRequest, bool aWithCredentials, - uint32_t aTimeout) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMethod(aMethod), + uint32_t aTimeout, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), + mMethod(aMethod), mURL(aURL), mBackgroundRequest(aBackgroundRequest), mWithCredentials(aWithCredentials), mTimeout(aTimeout) { @@ -835,8 +849,10 @@ class SetRequestHeaderRunnable final : public WorkerThreadProxySyncRunnable public: SetRequestHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - const nsACString& aHeader, const nsACString& aValue) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mHeader(aHeader), + const nsACString& aHeader, const nsACString& aValue, + ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), + mHeader(aHeader), mValue(aValue) { } @@ -857,8 +873,9 @@ class OverrideMimeTypeRunnable final : public WorkerThreadProxySyncRunnable public: OverrideMimeTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - const nsAString& aMimeType) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMimeType(aMimeType) + const nsAString& aMimeType, ErrorResult& aRv) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy, aRv), + mMimeType(aMimeType) { } private: @@ -1115,11 +1132,7 @@ Proxy::HandleEvent(nsIDOMEvent* aEvent) return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadProxySyncRunnable, nsRunnable) - -NS_IMPL_ISUPPORTS_INHERITED0(AsyncTeardownRunnable, nsRunnable) - -NS_IMPL_ISUPPORTS_INHERITED(LoadStartDetectionRunnable, nsRunnable, +NS_IMPL_ISUPPORTS_INHERITED(LoadStartDetectionRunnable, Runnable, nsIDOMEventListener) NS_IMETHODIMP @@ -1443,7 +1456,7 @@ WorkerThreadProxySyncRunnable::Run() nsresult rv = MainThreadRun(); RefPtr response = - new ResponseRunnable(mWorkerPrivate, mProxy, rv); + new ResponseRunnable(mWorkerPrivate, mProxy, rv, mRv); if (!response->Dispatch()) { MOZ_ASSERT(false, "Failed to dispatch response!"); } @@ -1558,7 +1571,7 @@ SendRunnable::MainThreadRun() // Send() has been already called. if (mProxy->mWorkerPrivate) { - return NS_ERROR_FAILURE; + return NS_ERROR_DOM_INVALID_STATE_ERR; } mProxy->mWorkerPrivate = mWorkerPrivate; @@ -1695,11 +1708,13 @@ XMLHttpRequest::ReleaseProxy(ReleaseType aType) } // We need to make a sync call here. + ErrorResult forAsssertionsOnly; RefPtr runnable = - new SyncTeardownRunnable(mWorkerPrivate, mProxy); + new SyncTeardownRunnable(mWorkerPrivate, mProxy, forAsssertionsOnly); mProxy = nullptr; - if (!runnable->Dispatch()) { + runnable->Dispatch(); + if (forAsssertionsOnly.Failed()) { NS_ERROR("Failed to dispatch teardown runnable!"); } } @@ -1875,13 +1890,13 @@ XMLHttpRequest::SendInternal(SendRunnable* aRunnable, aRunnable->SetSyncLoopTarget(syncLoopTarget); aRunnable->SetHaveUploadListeners(hasUploadListeners); - if (!aRunnable->Dispatch()) { + aRunnable->Dispatch(); + if (aRv.Failed()) { // Dispatch() may have spun the event loop and we may have already unrooted. // If so we don't want autoUnpin to try again. if (!mRooted) { autoUnpin.Clear(); } - aRv.Throw(NS_ERROR_FAILURE); return; } @@ -1893,7 +1908,12 @@ XMLHttpRequest::SendInternal(SendRunnable* aRunnable, autoUnpin.Clear(); - if (!autoSyncLoop->Run()) { + // Don't clobber an existing exception that we may have thrown on aRv + // already... though can there really be one? In any case, it seems to me + // that this autoSyncLoop->Run() can never fail, since the StopSyncLoop call + // for it will come from ProxyCompleteRunnable and that always passes true for + // the second arg. + if (!autoSyncLoop->Run() && !aRv.Failed()) { aRv.Throw(NS_ERROR_FAILURE); } } @@ -1938,15 +1958,15 @@ XMLHttpRequest::Open(const nsACString& aMethod, const nsAString& aUrl, RefPtr runnable = new OpenRunnable(mWorkerPrivate, mProxy, aMethod, aUrl, aUser, aPassword, mBackgroundRequest, mWithCredentials, - mTimeout); + mTimeout, aRv); ++mProxy->mOpenCount; - if (!runnable->Dispatch()) { + runnable->Dispatch(); + if (aRv.Failed()) { if (mProxy && !--mProxy->mOpenCount) { ReleaseProxy(); } - aRv.Throw(NS_ERROR_FAILURE); return; } @@ -1977,11 +1997,8 @@ XMLHttpRequest::SetRequestHeader(const nsACString& aHeader, } RefPtr runnable = - new SetRequestHeaderRunnable(mWorkerPrivate, mProxy, aHeader, aValue); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } + new SetRequestHeaderRunnable(mWorkerPrivate, mProxy, aHeader, aValue, aRv); + runnable->Dispatch(); } void @@ -2003,11 +2020,8 @@ XMLHttpRequest::SetTimeout(uint32_t aTimeout, ErrorResult& aRv) } RefPtr runnable = - new SetTimeoutRunnable(mWorkerPrivate, mProxy, aTimeout); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } + new SetTimeoutRunnable(mWorkerPrivate, mProxy, aTimeout, aRv); + runnable->Dispatch(); } void @@ -2029,11 +2043,9 @@ XMLHttpRequest::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv) } RefPtr runnable = - new SetWithCredentialsRunnable(mWorkerPrivate, mProxy, aWithCredentials); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } + new SetWithCredentialsRunnable(mWorkerPrivate, mProxy, aWithCredentials, + aRv); + runnable->Dispatch(); } void @@ -2057,11 +2069,8 @@ XMLHttpRequest::SetMozBackgroundRequest(bool aBackgroundRequest, RefPtr runnable = new SetBackgroundRequestRunnable(mWorkerPrivate, mProxy, - aBackgroundRequest); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } + aBackgroundRequest, aRv); + runnable->Dispatch(); } XMLHttpRequestUpload* @@ -2102,7 +2111,7 @@ XMLHttpRequest::Send(ErrorResult& aRv) } RefPtr sendRunnable = - new SendRunnable(mWorkerPrivate, mProxy, NullString()); + new SendRunnable(mWorkerPrivate, mProxy, NullString(), aRv); // Nothing to clone. SendInternal(sendRunnable, aRv); @@ -2124,7 +2133,7 @@ XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv) } RefPtr sendRunnable = - new SendRunnable(mWorkerPrivate, mProxy, aBody); + new SendRunnable(mWorkerPrivate, mProxy, aBody, aRv); // Nothing to clone. SendInternal(sendRunnable, aRv); @@ -2164,7 +2173,7 @@ XMLHttpRequest::Send(JS::Handle aBody, ErrorResult& aRv) } RefPtr sendRunnable = - new SendRunnable(mWorkerPrivate, mProxy, EmptyString()); + new SendRunnable(mWorkerPrivate, mProxy, EmptyString(), aRv); sendRunnable->Write(cx, valToClone, aRv); if (NS_WARN_IF(aRv.Failed())) { @@ -2205,7 +2214,7 @@ XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv) } RefPtr sendRunnable = - new SendRunnable(mWorkerPrivate, mProxy, EmptyString()); + new SendRunnable(mWorkerPrivate, mProxy, EmptyString(), aRv); sendRunnable->Write(cx, value, aRv); if (NS_WARN_IF(aRv.Failed())) { @@ -2238,7 +2247,7 @@ XMLHttpRequest::Send(FormData& aBody, ErrorResult& aRv) } RefPtr sendRunnable = - new SendRunnable(mWorkerPrivate, mProxy, EmptyString()); + new SendRunnable(mWorkerPrivate, mProxy, EmptyString(), aRv); sendRunnable->Write(cx, value, aRv); if (NS_WARN_IF(aRv.Failed())) { @@ -2287,13 +2296,17 @@ XMLHttpRequest::Abort(ErrorResult& aRv) return; } + if (mStateData.mReadyState == 4) { + // No one did anything to us while we fired abort events, so reset our state + // to "unsent" + mStateData.mReadyState = 0; + } + mProxy->mOuterEventStreamId++; - RefPtr runnable = new AbortRunnable(mWorkerPrivate, mProxy); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } + RefPtr runnable = + new AbortRunnable(mWorkerPrivate, mProxy, aRv); + runnable->Dispatch(); } void @@ -2315,9 +2328,9 @@ XMLHttpRequest::GetResponseHeader(const nsACString& aHeader, nsCString responseHeader; RefPtr runnable = new GetResponseHeaderRunnable(mWorkerPrivate, mProxy, aHeader, - responseHeader); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); + responseHeader, aRv); + runnable->Dispatch(); + if (aRv.Failed()) { return; } aResponseHeader = responseHeader; @@ -2341,9 +2354,10 @@ XMLHttpRequest::GetAllResponseHeaders(nsACString& aResponseHeaders, nsCString responseHeaders; RefPtr runnable = - new GetAllResponseHeadersRunnable(mWorkerPrivate, mProxy, responseHeaders); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); + new GetAllResponseHeadersRunnable(mWorkerPrivate, mProxy, responseHeaders, + aRv); + runnable->Dispatch(); + if (aRv.Failed()) { return; } @@ -2373,11 +2387,9 @@ XMLHttpRequest::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv) } RefPtr runnable = - new OverrideMimeTypeRunnable(mWorkerPrivate, mProxy, aMimeType); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } + new OverrideMimeTypeRunnable(mWorkerPrivate, mProxy, aMimeType, + aRv); + runnable->Dispatch(); } void @@ -2408,9 +2420,9 @@ XMLHttpRequest::SetResponseType(XMLHttpRequestResponseType aResponseType, ConvertResponseTypeToString(aResponseType, responseType); RefPtr runnable = - new SetResponseTypeRunnable(mWorkerPrivate, mProxy, responseType); - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); + new SetResponseTypeRunnable(mWorkerPrivate, mProxy, responseType, aRv); + runnable->Dispatch(); + if (aRv.Failed()) { return; } diff --git a/dom/xbl/nsXBLMaybeCompiled.h b/dom/xbl/nsXBLMaybeCompiled.h index 63c1b24ce6..b3b56da143 100644 --- a/dom/xbl/nsXBLMaybeCompiled.h +++ b/dom/xbl/nsXBLMaybeCompiled.h @@ -83,7 +83,7 @@ private: }; /* Add support for JS::Heap. */ -namespace js { +namespace JS { template struct GCPolicy> @@ -91,6 +91,10 @@ struct GCPolicy> static nsXBLMaybeCompiled initial() { return nsXBLMaybeCompiled(); } }; +} // namespace JS + +namespace js { + template struct BarrierMethods> { diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp index 462e34eaeb..d29fc6046e 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -546,7 +546,7 @@ txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName, return mVariables.add(varName, var); } -class nsTransformBlockerEvent : public nsRunnable { +class nsTransformBlockerEvent : public mozilla::Runnable { public: RefPtr mProcessor; diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp index 692ed7f198..0b7aede9a6 100644 --- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -34,6 +34,7 @@ #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsIDocument.h" #include "nsLayoutStylesheetCache.h" +#include "mozilla/ClearOnShutdown.h" #include "mozilla/EventListenerManager.h" #include "mozilla/EventStateManager.h" #include "mozilla/EventStates.h" @@ -808,7 +809,7 @@ IsInFeedSubscribeLine(nsXULElement* aElement) } #endif -class XULInContentErrorReporter : public nsRunnable +class XULInContentErrorReporter : public Runnable { public: explicit XULInContentErrorReporter(nsIDocument* aDocument) : mDocument(aDocument) {} @@ -1962,7 +1963,7 @@ nsXULElement::SetTitlebarColor(nscolor aColor, bool aActive) } } -class SetDrawInTitleBarEvent : public nsRunnable +class SetDrawInTitleBarEvent : public Runnable { public: SetDrawInTitleBarEvent(nsIWidget* aWidget, bool aState) @@ -2018,7 +2019,7 @@ nsXULElement::UpdateBrightTitlebarForeground(nsIDocument* aDoc) } } -class MarginSetter : public nsRunnable +class MarginSetter : public Runnable { public: explicit MarginSetter(nsIWidget* aWidget) : @@ -2709,20 +2710,46 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput, return rv; } -class NotifyOffThreadScriptCompletedRunnable : public nsRunnable +class NotifyOffThreadScriptCompletedRunnable : public Runnable { - RefPtr mReceiver; + // An array of all outstanding script receivers. All reference counting of + // these objects happens on the main thread. When we return to the main + // thread from script compilation we make sure our receiver is still in + // this array (still alive) before proceeding. This array is cleared during + // shutdown, potentially before all outstanding script compilations have + // finished. We do not need to worry about pointer replay here, because + // a) we should not be starting script compilation after clearing this + // array and b) in all other cases the receiver will still be alive. + static StaticAutoPtr>> sReceivers; + static bool sSetupClearOnShutdown; + + nsIOffThreadScriptReceiver* mReceiver; void *mToken; public: - NotifyOffThreadScriptCompletedRunnable(already_AddRefed aReceiver, + NotifyOffThreadScriptCompletedRunnable(nsIOffThreadScriptReceiver* aReceiver, void *aToken) : mReceiver(aReceiver), mToken(aToken) {} + static void NoteReceiver(nsIOffThreadScriptReceiver* aReceiver) { + if (!sSetupClearOnShutdown) { + ClearOnShutdown(&sReceivers); + sSetupClearOnShutdown = true; + sReceivers = new nsTArray>(); + } + + // If we ever crash here, it's because we tried to lazy compile script + // too late in shutdown. + sReceivers->AppendElement(aReceiver); + } + NS_DECL_NSIRUNNABLE }; +StaticAutoPtr>> NotifyOffThreadScriptCompletedRunnable::sReceivers; +bool NotifyOffThreadScriptCompletedRunnable::sSetupClearOnShutdown = false; + NS_IMETHODIMP NotifyOffThreadScriptCompletedRunnable::Run() { @@ -2740,7 +2767,17 @@ NotifyOffThreadScriptCompletedRunnable::Run() script = JS::FinishOffThreadScript(cx, JS_GetRuntime(cx), mToken); } - return mReceiver->OnScriptCompileComplete(script, script ? NS_OK : NS_ERROR_FAILURE); + if (!sReceivers) { + // We've already shut down. + return NS_OK; + } + + auto index = sReceivers->IndexOf(mReceiver); + MOZ_RELEASE_ASSERT(index != sReceivers->NoIndex); + nsCOMPtr receiver = (*sReceivers)[index].forget(); + sReceivers->RemoveElementAt(index); + + return receiver->OnScriptCompileComplete(script, script ? NS_OK : NS_ERROR_FAILURE); } static void @@ -2750,8 +2787,7 @@ OffThreadScriptReceiverCallback(void *aToken, void *aCallbackData) // may be invoked off the main thread. nsIOffThreadScriptReceiver* aReceiver = static_cast(aCallbackData); RefPtr notify = - new NotifyOffThreadScriptCompletedRunnable( - already_AddRefed(aReceiver), aToken); + new NotifyOffThreadScriptCompletedRunnable(aReceiver, aToken); NS_DispatchToMainThread(notify); } @@ -2793,8 +2829,7 @@ nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf, static_cast(aOffThreadReceiver))) { return NS_ERROR_OUT_OF_MEMORY; } - // This reference will be consumed by the NotifyOffThreadScriptCompletedRunnable. - NS_ADDREF(aOffThreadReceiver); + NotifyOffThreadScriptCompletedRunnable::NoteReceiver(aOffThreadReceiver); } else { JS::Rooted script(cx); if (!JS::Compile(cx, options, aSrcBuf, &script)) diff --git a/editor/composer/nsEditorSpellCheck.cpp b/editor/composer/nsEditorSpellCheck.cpp index 88b36cb580..3917b48c7b 100644 --- a/editor/composer/nsEditorSpellCheck.cpp +++ b/editor/composer/nsEditorSpellCheck.cpp @@ -296,7 +296,7 @@ nsEditorSpellCheck::CanSpellCheck(bool* _retval) } // Instances of this class can be used as either runnables or RAII helpers. -class CallbackCaller final : public nsRunnable +class CallbackCaller final : public Runnable { public: explicit CallbackCaller(nsIEditorSpellCheckCallback* aCallback) diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index 77a4b2f70a..118595e51b 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -1758,7 +1758,7 @@ nsEditor::RemoveEditorObserver(nsIEditorObserver *aObserver) return NS_OK; } -class EditorInputEventDispatcher : public nsRunnable +class EditorInputEventDispatcher : public Runnable { public: EditorInputEventDispatcher(nsEditor* aEditor, diff --git a/extensions/gio/nsGIOProtocolHandler.cpp b/extensions/gio/nsGIOProtocolHandler.cpp index b5ae992efa..1ccece1fac 100644 --- a/extensions/gio/nsGIOProtocolHandler.cpp +++ b/extensions/gio/nsGIOProtocolHandler.cpp @@ -542,7 +542,7 @@ nsGIOInputStream::DoRead(char *aBuf, uint32_t aCount, uint32_t *aCountRead) /** * This class is used to implement SetContentTypeOfChannel. */ -class nsGIOSetContentTypeEvent : public nsRunnable +class nsGIOSetContentTypeEvent : public mozilla::Runnable { public: nsGIOSetContentTypeEvent(nsIChannel *channel, const char *contentType) diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/extensions/spellcheck/src/mozInlineSpellChecker.cpp index 2e7e5b6ede..a9ffc804e3 100644 --- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -472,7 +472,7 @@ mozInlineSpellStatus::PositionToCollapsedRange(nsIDOMDocument* aDocument, // mozInlineSpellResume -class mozInlineSpellResume : public nsRunnable +class mozInlineSpellResume : public Runnable { public: mozInlineSpellResume(const mozInlineSpellStatus& aStatus, diff --git a/extensions/spellcheck/src/mozPersonalDictionary.cpp b/extensions/spellcheck/src/mozPersonalDictionary.cpp index 6cd870e31d..efaf143565 100644 --- a/extensions/spellcheck/src/mozPersonalDictionary.cpp +++ b/extensions/spellcheck/src/mozPersonalDictionary.cpp @@ -53,7 +53,7 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION(mozPersonalDictionary, mEncoder) -class mozPersonalDictionaryLoader final : public nsRunnable +class mozPersonalDictionaryLoader final : public mozilla::Runnable { public: explicit mozPersonalDictionaryLoader(mozPersonalDictionary *dict) : mDict(dict) @@ -74,7 +74,7 @@ private: RefPtr mDict; }; -class mozPersonalDictionarySave final : public nsRunnable +class mozPersonalDictionarySave final : public mozilla::Runnable { public: explicit mozPersonalDictionarySave(mozPersonalDictionary *aDict, diff --git a/gfx/2d/BaseRect.h b/gfx/2d/BaseRect.h index ecb1ce295e..ec68556718 100644 --- a/gfx/2d/BaseRect.h +++ b/gfx/2d/BaseRect.h @@ -107,7 +107,7 @@ struct BaseRect { // (including edges) of *this and aRect. If there are no points in that // intersection, returns an empty rectangle with x/y set to the std::max of the x/y // of *this and aRect. - MOZ_WARN_UNUSED_RESULT Sub Intersect(const Sub& aRect) const + MOZ_MUST_USE Sub Intersect(const Sub& aRect) const { Sub result; result.x = std::max(x, aRect.x); @@ -135,7 +135,7 @@ struct BaseRect { // this and aRect2. // Thus, empty input rectangles are ignored. // If both rectangles are empty, returns this. - MOZ_WARN_UNUSED_RESULT Sub Union(const Sub& aRect) const + MOZ_MUST_USE Sub Union(const Sub& aRect) const { if (IsEmpty()) { return aRect; @@ -148,7 +148,7 @@ struct BaseRect { // Returns the smallest rectangle that contains both the points (including // edges) of both aRect1 and aRect2. // Thus, empty input rectangles are allowed to affect the result. - MOZ_WARN_UNUSED_RESULT Sub UnionEdges(const Sub& aRect) const + MOZ_MUST_USE Sub UnionEdges(const Sub& aRect) const { Sub result; result.x = std::min(x, aRect.x); @@ -526,7 +526,7 @@ struct BaseRect { * Clamp aPoint to this rectangle. It is allowed to end up on any * edge of the rectangle. */ - MOZ_WARN_UNUSED_RESULT Point ClampPoint(const Point& aPoint) const + MOZ_MUST_USE Point ClampPoint(const Point& aPoint) const { return Point(std::max(x, std::min(XMost(), aPoint.x)), std::max(y, std::min(YMost(), aPoint.y))); @@ -537,7 +537,7 @@ struct BaseRect { * aRect then the dimensions that don't fit will be shrunk so that they * do fit. The resulting rect is returned. */ - MOZ_WARN_UNUSED_RESULT Sub MoveInsideAndClamp(const Sub& aRect) const + MOZ_MUST_USE Sub MoveInsideAndClamp(const Sub& aRect) const { Sub rect(std::max(aRect.x, x), std::max(aRect.y, y), diff --git a/gfx/layers/AsyncCanvasRenderer.cpp b/gfx/layers/AsyncCanvasRenderer.cpp index b25d60c15a..4375026fdd 100644 --- a/gfx/layers/AsyncCanvasRenderer.cpp +++ b/gfx/layers/AsyncCanvasRenderer.cpp @@ -44,7 +44,7 @@ AsyncCanvasRenderer::~AsyncCanvasRenderer() void AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() { - class Runnable final : public nsRunnable + class Runnable final : public mozilla::Runnable { public: explicit Runnable(AsyncCanvasRenderer* aRenderer) @@ -69,7 +69,7 @@ AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() RefPtr mRenderer; }; - RefPtr runnable = new Runnable(this); + nsCOMPtr runnable = new Runnable(this); nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { NS_WARNING("Failed to dispatch a runnable to the main-thread."); @@ -79,7 +79,7 @@ AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() void AsyncCanvasRenderer::NotifyElementAboutInvalidation() { - class Runnable final : public nsRunnable + class Runnable final : public mozilla::Runnable { public: explicit Runnable(AsyncCanvasRenderer* aRenderer) @@ -104,7 +104,7 @@ AsyncCanvasRenderer::NotifyElementAboutInvalidation() RefPtr mRenderer; }; - RefPtr runnable = new Runnable(this); + nsCOMPtr runnable = new Runnable(this); nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { NS_WARNING("Failed to dispatch a runnable to the main-thread."); diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index 6e7dcedaa3..8ad993d19c 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -56,7 +56,7 @@ public: /** * The XPCOM event that will do the actual release on the main thread. */ - class SurfaceReleaser : public nsRunnable { + class SurfaceReleaser : public mozilla::Runnable { public: explicit SurfaceReleaser(RawRef aRef) : mRef(aRef) {} NS_IMETHOD Run() { @@ -94,7 +94,7 @@ public: /** * The XPCOM event that will do the actual release on the creation thread. */ - class SurfaceReleaser : public nsRunnable { + class SurfaceReleaser : public mozilla::Runnable { public: explicit SurfaceReleaser(RawRef aRef) : mRef(aRef) {} NS_IMETHOD Run() { diff --git a/gfx/layers/LayerScope.cpp b/gfx/layers/LayerScope.cpp index 67158d9e30..abcd14a223 100644 --- a/gfx/layers/LayerScope.cpp +++ b/gfx/layers/LayerScope.cpp @@ -342,7 +342,7 @@ public: } private: friend class CreateServerSocketRunnable; - class CreateServerSocketRunnable : public nsRunnable + class CreateServerSocketRunnable : public Runnable { public: explicit CreateServerSocketRunnable(LayerScopeManager *aLayerScopeManager) diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index e68ad44c3f..7cf0b7aff7 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -332,7 +332,7 @@ APZCCallbackHelper::InitializeRootDisplayport(nsIPresShell* aPresShell) } } -class AcknowledgeScrollUpdateEvent : public nsRunnable +class AcknowledgeScrollUpdateEvent : public Runnable { typedef mozilla::layers::FrameMetrics::ViewID ViewID; @@ -343,7 +343,7 @@ public: { } - NS_IMETHOD Run() { + NS_IMETHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId); diff --git a/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h index 3e1e620d4e..dae1b6081b 100644 --- a/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h +++ b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h @@ -39,7 +39,7 @@ struct HelperForMainThreadDestruction }; template -struct DeleteOnMainThreadTask: public nsRunnable +struct DeleteOnMainThreadTask : public Runnable { T* mToDelete; explicit DeleteOnMainThreadTask(T* aToDelete) : mToDelete(aToDelete) {} diff --git a/gfx/src/gfxCrashReporterUtils.cpp b/gfx/src/gfxCrashReporterUtils.cpp index de7060d0e2..42647ccc60 100644 --- a/gfx/src/gfxCrashReporterUtils.cpp +++ b/gfx/src/gfxCrashReporterUtils.cpp @@ -65,7 +65,7 @@ ObserverToDestroyFeaturesAlreadyReported::Observe(nsISupports* aSubject, return NS_OK; } -class RegisterObserverRunnable : public nsRunnable { +class RegisterObserverRunnable : public Runnable { public: NS_IMETHOD Run() override { // LeakLog made me do this. Basically, I just wanted gFeaturesAlreadyReported to be a static nsTArray, diff --git a/gfx/src/nsPoint.h b/gfx/src/nsPoint.h index ac6a9e1f31..b377eb5a56 100644 --- a/gfx/src/nsPoint.h +++ b/gfx/src/nsPoint.h @@ -35,12 +35,12 @@ struct nsPoint : public mozilla::gfx::BasePoint { * @param aFromAPP the APP to scale from * @param aToAPP the APP to scale to */ - MOZ_WARN_UNUSED_RESULT inline nsPoint + MOZ_MUST_USE inline nsPoint ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const; - MOZ_WARN_UNUSED_RESULT inline nsPoint + MOZ_MUST_USE inline nsPoint RemoveResolution(const float resolution) const; - MOZ_WARN_UNUSED_RESULT inline nsPoint + MOZ_MUST_USE inline nsPoint ApplyResolution(const float resolution) const; }; diff --git a/gfx/src/nsRect.h b/gfx/src/nsRect.h index 22481774d0..178ab0b1f1 100644 --- a/gfx/src/nsRect.h +++ b/gfx/src/nsRect.h @@ -56,7 +56,7 @@ struct nsRect : // overflowing nscoord values in the 'width' and 'height' fields by // clamping the width and height values to nscoord_MAX if necessary. - MOZ_WARN_UNUSED_RESULT nsRect SaturatingUnion(const nsRect& aRect) const + MOZ_MUST_USE nsRect SaturatingUnion(const nsRect& aRect) const { if (IsEmpty()) { return aRect; @@ -67,7 +67,7 @@ struct nsRect : } } - MOZ_WARN_UNUSED_RESULT nsRect SaturatingUnionEdges(const nsRect& aRect) const + MOZ_MUST_USE nsRect SaturatingUnionEdges(const nsRect& aRect) const { #ifdef NS_COORD_IS_FLOAT return UnionEdges(aRect); @@ -102,7 +102,7 @@ struct nsRect : #ifndef NS_COORD_IS_FLOAT // Make all nsRect Union methods be saturating. - MOZ_WARN_UNUSED_RESULT nsRect UnionEdges(const nsRect& aRect) const + MOZ_MUST_USE nsRect UnionEdges(const nsRect& aRect) const { return SaturatingUnionEdges(aRect); } @@ -110,7 +110,7 @@ struct nsRect : { *this = aRect1.UnionEdges(aRect2); } - MOZ_WARN_UNUSED_RESULT nsRect Union(const nsRect& aRect) const + MOZ_MUST_USE nsRect Union(const nsRect& aRect) const { return SaturatingUnion(aRect); } @@ -138,32 +138,32 @@ struct nsRect : * @param aToAPP the APP to scale to * @note this can turn an empty rectangle into a non-empty rectangle */ - MOZ_WARN_UNUSED_RESULT inline nsRect + MOZ_MUST_USE inline nsRect ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const; - MOZ_WARN_UNUSED_RESULT inline nsRect + MOZ_MUST_USE inline nsRect ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const; - MOZ_WARN_UNUSED_RESULT inline mozilla::gfx::IntRect + MOZ_MUST_USE inline mozilla::gfx::IntRect ScaleToNearestPixels(float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const; - MOZ_WARN_UNUSED_RESULT inline mozilla::gfx::IntRect + MOZ_MUST_USE inline mozilla::gfx::IntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const; // Note: this can turn an empty rectangle into a non-empty rectangle - MOZ_WARN_UNUSED_RESULT inline mozilla::gfx::IntRect + MOZ_MUST_USE inline mozilla::gfx::IntRect ScaleToOutsidePixels(float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const; // Note: this can turn an empty rectangle into a non-empty rectangle - MOZ_WARN_UNUSED_RESULT inline mozilla::gfx::IntRect + MOZ_MUST_USE inline mozilla::gfx::IntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const; - MOZ_WARN_UNUSED_RESULT inline mozilla::gfx::IntRect + MOZ_MUST_USE inline mozilla::gfx::IntRect ScaleToInsidePixels(float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const; - MOZ_WARN_UNUSED_RESULT inline mozilla::gfx::IntRect + MOZ_MUST_USE inline mozilla::gfx::IntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const; // This is here only to keep IPDL-generated code happy. DO NOT USE. @@ -172,7 +172,7 @@ struct nsRect : return IsEqualEdges(aRect); } - MOZ_WARN_UNUSED_RESULT inline nsRect RemoveResolution(const float aResolution) const; + MOZ_MUST_USE inline nsRect RemoveResolution(const float aResolution) const; }; /* diff --git a/gfx/src/nsRegion.h b/gfx/src/nsRegion.h index 88dc02af8a..6f9f7fc8e3 100644 --- a/gfx/src/nsRegion.h +++ b/gfx/src/nsRegion.h @@ -297,9 +297,9 @@ public: * @param aToAPP the APP to scale to * @note this can turn an empty region into a non-empty region */ - MOZ_WARN_UNUSED_RESULT nsRegion + MOZ_MUST_USE nsRegion ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const; - MOZ_WARN_UNUSED_RESULT nsRegion + MOZ_MUST_USE nsRegion ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const; nsRegion& ScaleRoundOut(float aXScale, float aYScale); nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale); diff --git a/gfx/src/nsSize.h b/gfx/src/nsSize.h index 578cbaa195..f27c478f96 100644 --- a/gfx/src/nsSize.h +++ b/gfx/src/nsSize.h @@ -30,7 +30,7 @@ struct nsSize : public mozilla::gfx::BaseSize { * @param aFromAPP the APP to scale from * @param aToAPP the APP to scale to */ - MOZ_WARN_UNUSED_RESULT inline nsSize + MOZ_MUST_USE inline nsSize ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const; }; diff --git a/gfx/thebes/gfxFontInfoLoader.cpp b/gfx/thebes/gfxFontInfoLoader.cpp index d1c398c4d2..a53c96369b 100644 --- a/gfx/thebes/gfxFontInfoLoader.cpp +++ b/gfx/thebes/gfxFontInfoLoader.cpp @@ -39,7 +39,7 @@ FontInfoData::Load() mLoadTime = TimeStamp::Now() - start; } -class FontInfoLoadCompleteEvent : public nsRunnable { +class FontInfoLoadCompleteEvent : public Runnable { virtual ~FontInfoLoadCompleteEvent() {} NS_DECL_ISUPPORTS_INHERITED @@ -53,7 +53,7 @@ class FontInfoLoadCompleteEvent : public nsRunnable { RefPtr mFontInfo; }; -class AsyncFontInfoLoader : public nsRunnable { +class AsyncFontInfoLoader : public Runnable { virtual ~AsyncFontInfoLoader() {} NS_DECL_ISUPPORTS_INHERITED @@ -70,7 +70,7 @@ class AsyncFontInfoLoader : public nsRunnable { RefPtr mCompleteEvent; }; -class ShutdownThreadEvent : public nsRunnable { +class ShutdownThreadEvent : public Runnable { virtual ~ShutdownThreadEvent() {} NS_DECL_ISUPPORTS_INHERITED @@ -83,7 +83,7 @@ class ShutdownThreadEvent : public nsRunnable { nsCOMPtr mThread; }; -NS_IMPL_ISUPPORTS_INHERITED0(ShutdownThreadEvent, nsRunnable); +NS_IMPL_ISUPPORTS_INHERITED0(ShutdownThreadEvent, Runnable); // runs on main thread after async font info loading is done nsresult @@ -97,7 +97,7 @@ FontInfoLoadCompleteEvent::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(FontInfoLoadCompleteEvent, nsRunnable); +NS_IMPL_ISUPPORTS_INHERITED0(FontInfoLoadCompleteEvent, Runnable); // runs on separate thread nsresult @@ -112,7 +112,7 @@ AsyncFontInfoLoader::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(AsyncFontInfoLoader, nsRunnable); +NS_IMPL_ISUPPORTS_INHERITED0(AsyncFontInfoLoader, Runnable); NS_IMPL_ISUPPORTS(gfxFontInfoLoader::ShutdownObserver, nsIObserver) diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 2984b80ff5..0753f49429 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -298,7 +298,7 @@ void CrashStatsLogForwarder::UpdateCrashReport() } } -class LogForwarderEvent : public nsRunnable +class LogForwarderEvent : public Runnable { virtual ~LogForwarderEvent() {} @@ -317,7 +317,7 @@ protected: nsCString mMessage; }; -NS_IMPL_ISUPPORTS_INHERITED0(LogForwarderEvent, nsRunnable); +NS_IMPL_ISUPPORTS_INHERITED0(LogForwarderEvent, Runnable); void CrashStatsLogForwarder::Log(const std::string& aString) { @@ -340,7 +340,7 @@ void CrashStatsLogForwarder::Log(const std::string& aString) } } -class CrashTelemetryEvent : public nsRunnable +class CrashTelemetryEvent : public Runnable { virtual ~CrashTelemetryEvent() {} @@ -358,7 +358,7 @@ protected: uint32_t mReason; }; -NS_IMPL_ISUPPORTS_INHERITED0(CrashTelemetryEvent, nsRunnable); +NS_IMPL_ISUPPORTS_INHERITED0(CrashTelemetryEvent, Runnable); void CrashStatsLogForwarder::CrashAction(LogReason aReason) diff --git a/image/DecodePool.cpp b/image/DecodePool.cpp index 2bef9777fa..259ad06642 100644 --- a/image/DecodePool.cpp +++ b/image/DecodePool.cpp @@ -36,7 +36,7 @@ namespace image { // Helper runnables. /////////////////////////////////////////////////////////////////////////////// -class NotifyProgressWorker : public nsRunnable +class NotifyProgressWorker : public Runnable { public: /** @@ -79,7 +79,7 @@ private: const SurfaceFlags mSurfaceFlags; }; -class NotifyDecodeCompleteWorker : public nsRunnable +class NotifyDecodeCompleteWorker : public Runnable { public: /** @@ -111,7 +111,7 @@ private: #ifdef MOZ_NUWA_PROCESS -class RegisterDecodeIOThreadWithNuwaRunnable : public nsRunnable +class RegisterDecodeIOThreadWithNuwaRunnable : public Runnable { public: NS_IMETHOD Run() @@ -260,7 +260,7 @@ private: bool mShuttingDown; }; -class DecodePoolWorker : public nsRunnable +class DecodePoolWorker : public Runnable { public: explicit DecodePoolWorker(DecodePoolImpl* aImpl) : mImpl(aImpl) { } diff --git a/image/DrawResult.h b/image/DrawResult.h index dd7fdec1ef..8240ede26b 100644 --- a/image/DrawResult.h +++ b/image/DrawResult.h @@ -45,7 +45,7 @@ namespace image { * * BAD_ARGS: We failed to draw because bad arguments were passed to draw(). */ -enum class MOZ_MUST_USE DrawResult : uint8_t +enum class MOZ_MUST_USE_TYPE DrawResult : uint8_t { SUCCESS, INCOMPLETE, diff --git a/image/ProgressTracker.cpp b/image/ProgressTracker.cpp index d17eaa535a..7b5b22864c 100644 --- a/image/ProgressTracker.cpp +++ b/image/ProgressTracker.cpp @@ -113,7 +113,7 @@ ProgressTracker::GetImageStatus() const } // A helper class to allow us to call SyncNotify asynchronously. -class AsyncNotifyRunnable : public nsRunnable +class AsyncNotifyRunnable : public Runnable { public: AsyncNotifyRunnable(ProgressTracker* aTracker, @@ -193,7 +193,7 @@ ProgressTracker::Notify(IProgressObserver* aObserver) // A helper class to allow us to call SyncNotify asynchronously for a given, // fixed, state. -class AsyncNotifyCurrentStateRunnable : public nsRunnable +class AsyncNotifyCurrentStateRunnable : public Runnable { public: AsyncNotifyCurrentStateRunnable(ProgressTracker* aProgressTracker, diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index d2d77504d7..caf4f19663 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -770,7 +770,7 @@ RasterImage::CollectSizeOfSurfaces(nsTArray& aCounters, } } -class OnAddedFrameRunnable : public nsRunnable +class OnAddedFrameRunnable : public Runnable { public: OnAddedFrameRunnable(RasterImage* aImage, diff --git a/image/RasterImage.h b/image/RasterImage.h index 375d5e7e9c..03972be900 100644 --- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -430,7 +430,7 @@ private: // data // Error handling. void DoError(); - class HandleErrorWorker : public nsRunnable + class HandleErrorWorker : public Runnable { public: /** diff --git a/image/imgFrame.cpp b/image/imgFrame.cpp index 7736011bde..54d67dce97 100644 --- a/image/imgFrame.cpp +++ b/image/imgFrame.cpp @@ -816,7 +816,7 @@ imgFrame::AssertImageDataLocked() const #endif } -class UnlockImageDataRunnable : public nsRunnable +class UnlockImageDataRunnable : public Runnable { public: explicit UnlockImageDataRunnable(imgFrame* aTarget) diff --git a/image/imgRequest.cpp b/image/imgRequest.cpp index 00e406457b..7607e312a6 100644 --- a/image/imgRequest.cpp +++ b/image/imgRequest.cpp @@ -308,7 +308,7 @@ imgRequest::CancelAndAbort(nsresult aStatus) } } -class imgRequestMainThreadCancel : public nsRunnable +class imgRequestMainThreadCancel : public Runnable { public: imgRequestMainThreadCancel(imgRequest* aImgRequest, nsresult aStatus) @@ -358,7 +358,7 @@ imgRequest::ContinueCancel(nsresult aStatus) } } -class imgRequestMainThreadEvict : public nsRunnable +class imgRequestMainThreadEvict : public Runnable { public: explicit imgRequestMainThreadEvict(imgRequest* aImgRequest) @@ -992,7 +992,7 @@ PrepareForNewPart(nsIRequest* aRequest, nsIInputStream* aInStr, uint32_t aCount, return result; } -class FinishPreparingForNewPartRunnable final : public nsRunnable +class FinishPreparingForNewPartRunnable final : public Runnable { public: FinishPreparingForNewPartRunnable(imgRequest* aImgRequest, diff --git a/image/imgRequestProxy.h b/image/imgRequestProxy.h index dd61fbb808..558b7eaaf7 100644 --- a/image/imgRequestProxy.h +++ b/image/imgRequestProxy.h @@ -138,7 +138,7 @@ protected: class imgCancelRunnable; friend class imgCancelRunnable; - class imgCancelRunnable : public nsRunnable + class imgCancelRunnable : public mozilla::Runnable { public: imgCancelRunnable(imgRequestProxy* owner, nsresult status) diff --git a/image/test/gtest/TestDecodeToSurface.cpp b/image/test/gtest/TestDecodeToSurface.cpp index 70ce27e07f..81e60e63d7 100644 --- a/image/test/gtest/TestDecodeToSurface.cpp +++ b/image/test/gtest/TestDecodeToSurface.cpp @@ -32,7 +32,7 @@ TEST(ImageDecodeToSurface, ImageModuleAvailable) EXPECT_TRUE(imgTools != nullptr); } -class DecodeToSurfaceRunnable : public nsRunnable +class DecodeToSurfaceRunnable : public Runnable { public: DecodeToSurfaceRunnable(RefPtr& aSurface, diff --git a/intl/uconv/nsIUnicodeDecoder.h b/intl/uconv/nsIUnicodeDecoder.h index 319b60990b..36a46759b5 100644 --- a/intl/uconv/nsIUnicodeDecoder.h +++ b/intl/uconv/nsIUnicodeDecoder.h @@ -110,9 +110,9 @@ public: * NS_ERROR_OUT_OF_MEMORY if OOM * NS_OK is all we have is an approximation */ - MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char* aSrc, - int32_t aSrcLength, - int32_t* aDestLength) = 0; + MOZ_MUST_USE NS_IMETHOD GetMaxLength(const char* aSrc, + int32_t aSrcLength, + int32_t* aDestLength) = 0; /** * Resets the charset converter so it may be recycled for a completely diff --git a/intl/uconv/nsIUnicodeEncoder.h b/intl/uconv/nsIUnicodeEncoder.h index a364519276..e704a21955 100644 --- a/intl/uconv/nsIUnicodeEncoder.h +++ b/intl/uconv/nsIUnicodeEncoder.h @@ -135,9 +135,9 @@ public: * NS_ERROR_OUT_OF_MEMORY if OOM * NS_OK if all we have is an approximation */ - MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char16_t* aSrc, - int32_t aSrcLength, - int32_t* aDestLength) = 0; + MOZ_MUST_USE NS_IMETHOD GetMaxLength(const char16_t* aSrc, + int32_t aSrcLength, + int32_t* aDestLength) = 0; /** * Resets the charset converter so it may be recycled for a completely diff --git a/intl/uconv/nsReplacementToUnicode.h b/intl/uconv/nsReplacementToUnicode.h index b5b96c7e9d..fd19e8892f 100644 --- a/intl/uconv/nsReplacementToUnicode.h +++ b/intl/uconv/nsReplacementToUnicode.h @@ -24,9 +24,9 @@ public: char16_t* aDest, int32_t* aDestLength) override; - MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char* aSrc, - int32_t aSrcLength, - int32_t* aDestLength) override; + MOZ_MUST_USE NS_IMETHOD GetMaxLength(const char* aSrc, + int32_t aSrcLength, + int32_t* aDestLength) override; NS_IMETHOD Reset() override; diff --git a/intl/uconv/nsUTF8ToUnicode.h b/intl/uconv/nsUTF8ToUnicode.h index 40a3a30305..d80fa18992 100644 --- a/intl/uconv/nsUTF8ToUnicode.h +++ b/intl/uconv/nsUTF8ToUnicode.h @@ -49,9 +49,9 @@ protected: //-------------------------------------------------------------------- // Subclassing of nsDecoderSupport class [declaration] - MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char* aSrc, - int32_t aSrcLength, - int32_t* aDestLength) override; + MOZ_MUST_USE NS_IMETHOD GetMaxLength(const char* aSrc, + int32_t aSrcLength, + int32_t* aDestLength) override; //-------------------------------------------------------------------- // Subclassing of nsBasicDecoderSupport class [declaration] diff --git a/intl/uconv/nsUnicodeToUTF8.h b/intl/uconv/nsUnicodeToUTF8.h index d08d0bd1b2..410bde2813 100644 --- a/intl/uconv/nsUnicodeToUTF8.h +++ b/intl/uconv/nsUnicodeToUTF8.h @@ -48,9 +48,9 @@ public: NS_IMETHOD Finish(char* aDest, int32_t* aDestLength) override; - MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char16_t* aSrc, - int32_t aSrcLength, - int32_t* aDestLength) override; + MOZ_MUST_USE NS_IMETHOD GetMaxLength(const char16_t* aSrc, + int32_t aSrcLength, + int32_t* aDestLength) override; NS_IMETHOD Reset() override {mHighSurrogate = 0; return NS_OK;} diff --git a/intl/uconv/ucvlatin/nsUTF16ToUnicode.h b/intl/uconv/ucvlatin/nsUTF16ToUnicode.h index 8f05d32ea2..227fb412f4 100644 --- a/intl/uconv/ucvlatin/nsUTF16ToUnicode.h +++ b/intl/uconv/ucvlatin/nsUTF16ToUnicode.h @@ -24,9 +24,9 @@ public: //-------------------------------------------------------------------- // Subclassing of nsDecoderSupport class [declaration] - MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char* aSrc, - int32_t aSrcLength, - int32_t* aDestLength) override; + MOZ_MUST_USE NS_IMETHOD GetMaxLength(const char* aSrc, + int32_t aSrcLength, + int32_t* aDestLength) override; NS_IMETHOD Reset() override; protected: diff --git a/intl/uconv/ucvlatin/nsUnicodeToUTF16.h b/intl/uconv/ucvlatin/nsUnicodeToUTF16.h index 427b9fc8d6..d7a4451e44 100644 --- a/intl/uconv/ucvlatin/nsUnicodeToUTF16.h +++ b/intl/uconv/ucvlatin/nsUnicodeToUTF16.h @@ -19,9 +19,9 @@ public: NS_IMETHOD Convert(const char16_t* aSrc, int32_t* aSrcLength, char* aDest, int32_t* aDestLength); - MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char16_t* aSrc, - int32_t aSrcLength, - int32_t* aDestLength); + MOZ_MUST_USE NS_IMETHOD GetMaxLength(const char16_t* aSrc, + int32_t aSrcLength, + int32_t* aDestLength); NS_IMETHOD Finish(char* aDest, int32_t* aDestLength); NS_IMETHOD Reset(); NS_IMETHOD SetOutputErrorBehavior(int32_t aBehavior, diff --git a/intl/uconv/ucvtw/nsUnicodeToBIG5.h b/intl/uconv/ucvtw/nsUnicodeToBIG5.h index 714b2b9025..51e2c0928e 100644 --- a/intl/uconv/ucvtw/nsUnicodeToBIG5.h +++ b/intl/uconv/ucvtw/nsUnicodeToBIG5.h @@ -29,9 +29,9 @@ public: NS_IMETHOD Finish(char* aDest, int32_t* aDestLength) override; - MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char16_t* aSrc, - int32_t aSrcLength, - int32_t* aDestLength) override; + MOZ_MUST_USE NS_IMETHOD GetMaxLength(const char16_t* aSrc, + int32_t aSrcLength, + int32_t* aDestLength) override; NS_IMETHOD Reset() override; diff --git a/ipc/chromium/src/base/pickle.cc b/ipc/chromium/src/base/pickle.cc index cf0a653638..209d25133a 100644 --- a/ipc/chromium/src/base/pickle.cc +++ b/ipc/chromium/src/base/pickle.cc @@ -147,10 +147,7 @@ Pickle::Pickle(const Pickle& other) capacity_(0), variable_buffer_offset_(other.variable_buffer_offset_) { uint32_t payload_size = header_size_ + other.header_->payload_size; - bool resized = Resize(payload_size); - if (!resized) { - NS_ABORT_OOM(payload_size); - } + Resize(payload_size); memcpy(header_, other.header_, payload_size); } @@ -175,10 +172,7 @@ Pickle& Pickle::operator=(const Pickle& other) { header_ = NULL; header_size_ = other.header_size_; } - bool resized = Resize(other.header_size_ + other.header_->payload_size); - if (!resized) { - NS_ABORT_OOM(other.header_size_ + other.header_->payload_size); - } + Resize(other.header_size_ + other.header_->payload_size); memcpy(header_, other.header_, header_size_ + other.header_->payload_size); variable_buffer_offset_ = other.variable_buffer_offset_; return *this; @@ -437,6 +431,9 @@ bool Pickle::ReadWString(void** iter, std::wstring* result) const { int len; if (!ReadLength(iter, &len)) return false; + // Avoid integer multiplication overflow. + if (len > INT_MAX / static_cast(sizeof(wchar_t))) + return false; if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t))) return false; @@ -447,24 +444,6 @@ bool Pickle::ReadWString(void** iter, std::wstring* result) const { return true; } -bool Pickle::ReadString16(void** iter, string16* result) const { - DCHECK(iter); - if (!*iter) - *iter = const_cast(payload()); - - int len; - if (!ReadLength(iter, &len)) - return false; - if (!IteratorHasRoomFor(*iter, len)) - return false; - - char16* chars = reinterpret_cast(*iter); - result->assign(chars, len); - - UpdateIter(iter, len * sizeof(char16)); - return true; -} - bool Pickle::ReadBytes(void** iter, const char** data, int length, uint32_t alignment) const { DCHECK(iter); @@ -520,8 +499,9 @@ char* Pickle::BeginWrite(uint32_t length, uint32_t alignment) { uint32_t new_size = offset + padding + AlignInt(length); uint32_t needed_size = header_size_ + new_size; - if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) - return NULL; + if (needed_size > capacity_) { + Resize(std::max(capacity_ * 2, needed_size)); + } DCHECK(intptr_t(header_) % alignment == 0); @@ -590,14 +570,6 @@ bool Pickle::WriteWString(const std::wstring& value) { static_cast(value.size() * sizeof(wchar_t))); } -bool Pickle::WriteString16(const string16& value) { - if (!WriteInt(static_cast(value.size()))) - return false; - - return WriteBytes(value.data(), - static_cast(value.size()) * sizeof(char16)); -} - bool Pickle::WriteData(const char* data, int length) { return WriteInt(length) && WriteBytes(data, length); } @@ -639,16 +611,13 @@ void Pickle::TrimWriteData(int new_length) { *cur_length = new_length; } -bool Pickle::Resize(uint32_t new_capacity) { +void Pickle::Resize(uint32_t new_capacity) { new_capacity = ConstantAligner::align(new_capacity); - void* p = realloc(header_, new_capacity); - if (!p) - return false; + void* p = moz_xrealloc(header_, new_capacity); header_ = reinterpret_cast(p); capacity_ = new_capacity; - return true; } // static diff --git a/ipc/chromium/src/base/pickle.h b/ipc/chromium/src/base/pickle.h index ce0712ae2b..1df477d069 100644 --- a/ipc/chromium/src/base/pickle.h +++ b/ipc/chromium/src/base/pickle.h @@ -81,31 +81,30 @@ class Pickle { // the Pickle, initialize *iter to NULL. If successful, these methods return // true. Otherwise, false is returned to indicate that the result could not // be extracted. - MOZ_WARN_UNUSED_RESULT bool ReadBool(void** iter, bool* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadInt16(void** iter, int16_t* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadUInt16(void** iter, uint16_t* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadShort(void** iter, short* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadInt(void** iter, int* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadLong(void** iter, long* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadULong(void** iter, unsigned long* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadSize(void** iter, size_t* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadInt32(void** iter, int32_t* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadUInt32(void** iter, uint32_t* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadInt64(void** iter, int64_t* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadUInt64(void** iter, uint64_t* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadDouble(void** iter, double* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadIntPtr(void** iter, intptr_t* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadUnsignedChar(void** iter, unsigned char* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadString(void** iter, std::string* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadWString(void** iter, std::wstring* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadString16(void** iter, string16* result) const; - MOZ_WARN_UNUSED_RESULT bool ReadData(void** iter, const char** data, int* length) const; - MOZ_WARN_UNUSED_RESULT bool ReadBytes(void** iter, const char** data, int length, + MOZ_MUST_USE bool ReadBool(void** iter, bool* result) const; + MOZ_MUST_USE bool ReadInt16(void** iter, int16_t* result) const; + MOZ_MUST_USE bool ReadUInt16(void** iter, uint16_t* result) const; + MOZ_MUST_USE bool ReadShort(void** iter, short* result) const; + MOZ_MUST_USE bool ReadInt(void** iter, int* result) const; + MOZ_MUST_USE bool ReadLong(void** iter, long* result) const; + MOZ_MUST_USE bool ReadULong(void** iter, unsigned long* result) const; + MOZ_MUST_USE bool ReadSize(void** iter, size_t* result) const; + MOZ_MUST_USE bool ReadInt32(void** iter, int32_t* result) const; + MOZ_MUST_USE bool ReadUInt32(void** iter, uint32_t* result) const; + MOZ_MUST_USE bool ReadInt64(void** iter, int64_t* result) const; + MOZ_MUST_USE bool ReadUInt64(void** iter, uint64_t* result) const; + MOZ_MUST_USE bool ReadDouble(void** iter, double* result) const; + MOZ_MUST_USE bool ReadIntPtr(void** iter, intptr_t* result) const; + MOZ_MUST_USE bool ReadUnsignedChar(void** iter, unsigned char* result) const; + MOZ_MUST_USE bool ReadString(void** iter, std::string* result) const; + MOZ_MUST_USE bool ReadWString(void** iter, std::wstring* result) const; + MOZ_MUST_USE bool ReadData(void** iter, const char** data, int* length) const; + MOZ_MUST_USE bool ReadBytes(void** iter, const char** data, int length, uint32_t alignment = sizeof(memberAlignmentType)) const; // Safer version of ReadInt() checks for the result not being negative. // Use it for reading the object sizes. - MOZ_WARN_UNUSED_RESULT bool ReadLength(void** iter, int* result) const; + MOZ_MUST_USE bool ReadLength(void** iter, int* result) const; // Methods for adding to the payload of the Pickle. These values are // appended to the end of the Pickle's payload. When reading values from a @@ -163,7 +162,6 @@ class Pickle { } bool WriteString(const std::string& value); bool WriteWString(const std::wstring& value); - bool WriteString16(const string16& value); bool WriteData(const char* data, int length); bool WriteBytes(const void* data, int data_len, uint32_t alignment = sizeof(memberAlignmentType)); @@ -261,7 +259,7 @@ class Pickle { // the header: new_capacity = sizeof(Header) + desired_payload_capacity. // A realloc() failure will cause a Resize failure... and caller should check // the return result for true (i.e., successful resizing). - bool Resize(uint32_t new_capacity); + void Resize(uint32_t new_capacity); // Round 'bytes' up to the next multiple of 'alignment'. 'alignment' must be // a power of 2. diff --git a/ipc/glue/BackgroundImpl.cpp b/ipc/glue/BackgroundImpl.cpp index 9fd213e65e..00645a535d 100644 --- a/ipc/glue/BackgroundImpl.cpp +++ b/ipc/glue/BackgroundImpl.cpp @@ -495,8 +495,7 @@ private: } }; -class ParentImpl::RequestMessageLoopRunnable final : - public nsRunnable +class ParentImpl::RequestMessageLoopRunnable final : public Runnable { nsCOMPtr mTargetThread; MessageLoop* mMessageLoop; @@ -510,8 +509,6 @@ public: MOZ_ASSERT(aTargetThread); } - NS_DECL_ISUPPORTS_INHERITED - private: ~RequestMessageLoopRunnable() { } @@ -519,7 +516,7 @@ private: NS_DECL_NSIRUNNABLE }; -class ParentImpl::ShutdownBackgroundThreadRunnable final : public nsRunnable +class ParentImpl::ShutdownBackgroundThreadRunnable final : public Runnable { public: ShutdownBackgroundThreadRunnable() @@ -528,8 +525,6 @@ public: AssertIsOnMainThread(); } - NS_DECL_ISUPPORTS_INHERITED - private: ~ShutdownBackgroundThreadRunnable() { } @@ -537,7 +532,7 @@ private: NS_DECL_NSIRUNNABLE }; -class ParentImpl::ForceCloseBackgroundActorsRunnable final : public nsRunnable +class ParentImpl::ForceCloseBackgroundActorsRunnable final : public Runnable { nsTArray* mActorArray; @@ -550,8 +545,6 @@ public: MOZ_ASSERT(aActorArray); } - NS_DECL_ISUPPORTS_INHERITED - private: ~ForceCloseBackgroundActorsRunnable() { } @@ -559,7 +552,7 @@ private: NS_DECL_NSIRUNNABLE }; -class ParentImpl::CreateCallbackRunnable final : public nsRunnable +class ParentImpl::CreateCallbackRunnable final : public Runnable { RefPtr mCallback; @@ -572,8 +565,6 @@ public: MOZ_ASSERT(aCallback); } - NS_DECL_ISUPPORTS_INHERITED - private: ~CreateCallbackRunnable() { } @@ -581,7 +572,7 @@ private: NS_DECL_NSIRUNNABLE }; -class ParentImpl::ConnectActorRunnable final : public nsRunnable +class ParentImpl::ConnectActorRunnable final : public Runnable { RefPtr mActor; Transport* mTransport; @@ -603,8 +594,6 @@ public: MOZ_ASSERT(aLiveActorArray); } - NS_DECL_ISUPPORTS_INHERITED - private: ~ConnectActorRunnable() { @@ -652,7 +641,7 @@ private: } }; -class ChildImpl::CreateActorRunnable final : public nsRunnable +class ChildImpl::CreateActorRunnable final : public Runnable { nsCOMPtr mEventTarget; @@ -663,8 +652,6 @@ public: MOZ_ASSERT(mEventTarget); } - NS_DECL_ISUPPORTS_INHERITED - private: ~CreateActorRunnable() { } @@ -716,7 +703,7 @@ protected: nsresult Cancel() override; }; -class ChildImpl::FailedCreateCallbackRunnable final : public nsRunnable +class ChildImpl::FailedCreateCallbackRunnable final : public Runnable { public: FailedCreateCallbackRunnable() @@ -724,8 +711,6 @@ public: // May be created on any thread! } - NS_DECL_ISUPPORTS_INHERITED - protected: virtual ~FailedCreateCallbackRunnable() { } @@ -733,7 +718,7 @@ protected: NS_DECL_NSIRUNNABLE }; -class ChildImpl::OpenChildProcessActorRunnable final : public nsRunnable +class ChildImpl::OpenChildProcessActorRunnable final : public Runnable { RefPtr mActor; nsAutoPtr mTransport; @@ -751,8 +736,6 @@ public: MOZ_ASSERT(aTransport); } - NS_DECL_ISUPPORTS_INHERITED - private: ~OpenChildProcessActorRunnable() { @@ -765,7 +748,7 @@ private: NS_DECL_NSIRUNNABLE }; -class ChildImpl::OpenMainProcessActorRunnable final : public nsRunnable +class ChildImpl::OpenMainProcessActorRunnable final : public Runnable { RefPtr mActor; RefPtr mParentActor; @@ -783,8 +766,6 @@ public: MOZ_ASSERT(aParentMessageLoop); } - NS_DECL_ISUPPORTS_INHERITED - private: ~OpenMainProcessActorRunnable() { } @@ -1410,9 +1391,6 @@ ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::RequestMessageLoopRunnable, - nsRunnable) - NS_IMETHODIMP ParentImpl::RequestMessageLoopRunnable::Run() { @@ -1479,9 +1457,6 @@ ParentImpl::RequestMessageLoopRunnable::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ShutdownBackgroundThreadRunnable, - nsRunnable) - NS_IMETHODIMP ParentImpl::ShutdownBackgroundThreadRunnable::Run() { @@ -1497,9 +1472,6 @@ ParentImpl::ShutdownBackgroundThreadRunnable::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ForceCloseBackgroundActorsRunnable, - nsRunnable) - NS_IMETHODIMP ParentImpl::ForceCloseBackgroundActorsRunnable::Run() { @@ -1528,8 +1500,6 @@ ParentImpl::ForceCloseBackgroundActorsRunnable::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::CreateCallbackRunnable, nsRunnable) - NS_IMETHODIMP ParentImpl::CreateCallbackRunnable::Run() { @@ -1548,8 +1518,6 @@ ParentImpl::CreateCallbackRunnable::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ConnectActorRunnable, nsRunnable) - NS_IMETHODIMP ParentImpl::ConnectActorRunnable::Run() { @@ -1847,9 +1815,6 @@ ChildImpl::AlreadyCreatedCallbackRunnable::Cancel() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::FailedCreateCallbackRunnable, - nsRunnable); - NS_IMETHODIMP ChildImpl::FailedCreateCallbackRunnable::Run() { @@ -1865,9 +1830,6 @@ ChildImpl::FailedCreateCallbackRunnable::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenChildProcessActorRunnable, - nsRunnable); - NS_IMETHODIMP ChildImpl::OpenChildProcessActorRunnable::Run() { @@ -1918,9 +1880,6 @@ ChildImpl::OpenChildProcessActorRunnable::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenMainProcessActorRunnable, - nsRunnable); - NS_IMETHODIMP ChildImpl::OpenMainProcessActorRunnable::Run() { @@ -1984,8 +1943,6 @@ ChildImpl::OpenMainProcessActorRunnable::Run() return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateActorRunnable, nsRunnable) - NS_IMETHODIMP ChildImpl::CreateActorRunnable::Run() { diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index 5eb697214c..7f47640d2a 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -330,7 +330,7 @@ BackgroundParentImpl::DeallocPCamerasParent(camera::PCamerasParent *aActor) namespace { -class InitUDPSocketParentCallback final : public nsRunnable +class InitUDPSocketParentCallback final : public Runnable { public: InitUDPSocketParentCallback(UDPSocketParent* aActor, @@ -443,7 +443,7 @@ struct MOZ_STACK_CLASS NullifyContentParentRAII RefPtr& mContentParent; }; -class CheckPrincipalRunnable final : public nsRunnable +class CheckPrincipalRunnable final : public Runnable { public: CheckPrincipalRunnable(already_AddRefed aParent, @@ -496,7 +496,7 @@ private: nsCString mOrigin; }; -class CheckPermissionRunnable final : public nsRunnable +class CheckPermissionRunnable final : public Runnable { public: CheckPermissionRunnable(already_AddRefed aParent, diff --git a/ipc/ipdl/ipdl/cxx/cgen.py b/ipc/ipdl/ipdl/cxx/cgen.py index c3582c6164..3c6677a4c8 100644 --- a/ipc/ipdl/ipdl/cxx/cgen.py +++ b/ipc/ipdl/ipdl/cxx/cgen.py @@ -185,7 +185,7 @@ class CxxCodeGen(CodePrinter, Visitor): self.printdent() if md.warn_unused: - self.write('MOZ_WARN_UNUSED_RESULT ') + self.write('MOZ_MUST_USE ') if md.inline: self.write('inline ') if md.never_inline: diff --git a/js/ipc/JavaScriptBase.h b/js/ipc/JavaScriptBase.h index bc62db0e90..2248a83668 100644 --- a/js/ipc/JavaScriptBase.h +++ b/js/ipc/JavaScriptBase.h @@ -99,6 +99,11 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base bool RecvGetPrototype(const uint64_t& objId, ReturnStatus* rs, ObjectOrNullVariant* result) { return Answer::RecvGetPrototype(ObjectId::deserialize(objId), rs, result); } + bool RecvGetPrototypeIfOrdinary(const uint64_t& objId, ReturnStatus* rs, bool* isOrdinary, + ObjectOrNullVariant* result) + { + return Answer::RecvGetPrototypeIfOrdinary(ObjectId::deserialize(objId), rs, isOrdinary, result); + } bool RecvRegExpToShared(const uint64_t& objId, ReturnStatus* rs, nsString* source, uint32_t* flags) { return Answer::RecvRegExpToShared(ObjectId::deserialize(objId), rs, source, flags); } @@ -190,6 +195,11 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base bool SendGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result) { return Base::SendGetPrototype(objId.serialize(), rs, result); } + bool SendGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary, + ObjectOrNullVariant* result) + { + return Base::SendGetPrototypeIfOrdinary(objId.serialize(), rs, isOrdinary, result); + } bool SendRegExpToShared(const ObjectId& objId, ReturnStatus* rs, nsString* source, uint32_t* flags) { diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp index aa19bc2bfd..ffc374e80e 100644 --- a/js/ipc/JavaScriptShared.cpp +++ b/js/ipc/JavaScriptShared.cpp @@ -83,16 +83,6 @@ IdToObjectMap::empty() const return table_.empty(); } -ObjectToIdMap::ObjectToIdMap(JSRuntime* rt) - : rt_(rt) -{ -} - -ObjectToIdMap::~ObjectToIdMap() -{ - JS_ClearAllPostBarrierCallbacks(rt_); -} - bool ObjectToIdMap::init() { @@ -145,9 +135,7 @@ bool JavaScriptShared::sStackLoggingEnabled; JavaScriptShared::JavaScriptShared(JSRuntime* rt) : rt_(rt), refcount_(1), - nextSerialNumber_(1), - unwaivedObjectIds_(rt), - waivedObjectIds_(rt) + nextSerialNumber_(1) { if (!sLoggingInitialized) { sLoggingInitialized = true; diff --git a/js/ipc/JavaScriptShared.h b/js/ipc/JavaScriptShared.h index 01803bd530..3a6f8e3686 100644 --- a/js/ipc/JavaScriptShared.h +++ b/js/ipc/JavaScriptShared.h @@ -109,12 +109,9 @@ class IdToObjectMap class ObjectToIdMap { using Hasher = js::MovableCellHasher>; - using Table = js::GCHashMap, ObjectId, Hasher, js::SystemAllocPolicy>; + using Table = JS::GCHashMap, ObjectId, Hasher, js::SystemAllocPolicy>; public: - explicit ObjectToIdMap(JSRuntime* rt); - ~ObjectToIdMap(); - bool init(); void trace(JSTracer* trc); void sweep(); @@ -125,7 +122,6 @@ class ObjectToIdMap void clear(); private: - JSRuntime* rt_; Table table_; }; diff --git a/js/ipc/PJavaScript.ipdl b/js/ipc/PJavaScript.ipdl index 05b028e3ce..667fedf717 100644 --- a/js/ipc/PJavaScript.ipdl +++ b/js/ipc/PJavaScript.ipdl @@ -42,6 +42,7 @@ both: prio(high) sync IsArray(uint64_t objId) returns (ReturnStatus rs, uint32_t ans); prio(high) sync ClassName(uint64_t objId) returns (nsCString name); prio(high) sync GetPrototype(uint64_t objId) returns (ReturnStatus rs, ObjectOrNullVariant result); + prio(high) sync GetPrototypeIfOrdinary(uint64_t objId) returns (ReturnStatus rs, bool isOrdinary, ObjectOrNullVariant result); prio(high) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags); prio(high) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, JSIDVariant[] ids); diff --git a/js/ipc/WrapperAnswer.cpp b/js/ipc/WrapperAnswer.cpp index 07be205c86..223e73f905 100644 --- a/js/ipc/WrapperAnswer.cpp +++ b/js/ipc/WrapperAnswer.cpp @@ -585,6 +585,34 @@ WrapperAnswer::RecvGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectO return ok(rs); } +bool +WrapperAnswer::RecvGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary, + ObjectOrNullVariant* result) +{ + *result = NullVariant(); + *isOrdinary = false; + + AutoJSAPI jsapi; + if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects()))) + return false; + JSContext* cx = jsapi.cx(); + + RootedObject obj(cx, findObjectById(cx, objId)); + if (!obj) + return fail(jsapi, rs); + + JS::RootedObject proto(cx); + if (!JS_GetPrototypeIfOrdinary(cx, obj, isOrdinary, &proto)) + return fail(jsapi, rs); + + if (!toObjectOrNullVariant(cx, proto, result)) + return fail(jsapi, rs); + + LOG("getPrototypeIfOrdinary(%s)", ReceiverObj(objId)); + + return ok(rs); +} + bool WrapperAnswer::RecvRegExpToShared(const ObjectId& objId, ReturnStatus* rs, nsString* source, uint32_t* flags) diff --git a/js/ipc/WrapperAnswer.h b/js/ipc/WrapperAnswer.h index 7edfb87703..23f7239503 100644 --- a/js/ipc/WrapperAnswer.h +++ b/js/ipc/WrapperAnswer.h @@ -56,6 +56,8 @@ class WrapperAnswer : public virtual JavaScriptShared bool RecvIsArray(const ObjectId& objId, ReturnStatus* rs, uint32_t* ans); bool RecvClassName(const ObjectId& objId, nsCString* result); bool RecvGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result); + bool RecvGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary, + ObjectOrNullVariant* result); bool RecvRegExpToShared(const ObjectId& objId, ReturnStatus* rs, nsString* source, uint32_t* flags); bool RecvGetPropertyKeys(const ObjectId& objId, const uint32_t& flags, diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index 2040da932b..6031916e59 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -15,7 +15,8 @@ #include "CPOWTimer.h" #include "WrapperFactory.h" -#include "nsIRemoteTagService.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDOMDocument.h" using namespace js; using namespace JS; @@ -136,6 +137,8 @@ class CPOWProxyHandler : public BaseProxyHandler virtual bool isCallable(JSObject* obj) const override; virtual bool isConstructor(JSObject* obj) const override; virtual bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; static const char family; static const CPOWProxyHandler singleton; @@ -827,6 +830,34 @@ WrapperOwner::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObjec return true; } +bool +CPOWProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject objp) const +{ + FORWARD(getPrototypeIfOrdinary, (cx, proxy, isOrdinary, objp)); +} + +bool +WrapperOwner::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject objp) +{ + ObjectId objId = idOf(proxy); + + ObjectOrNullVariant val; + ReturnStatus status; + if (!SendGetPrototypeIfOrdinary(objId, &status, isOrdinary, &val)) + return ipcfail(cx); + + LOG_STACK(); + + if (!ok(cx, status)) + return false; + + objp.set(fromObjectOrNullVariant(cx, val)); + + return true; +} + bool CPOWProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const { @@ -1066,23 +1097,33 @@ WrapperOwner::ok(JSContext* cx, const ReturnStatus& status, ObjectOpResult& resu return result.succeed(); } +// CPOWs can have a tag string attached to them, originating in the local +// process from this function. It's sent with the CPOW to the remote process, +// where it can be fetched with Components.utils.getCrossProcessWrapperTag. +static nsCString +GetRemoteObjectTag(JS::Handle obj) +{ + if (nsCOMPtr supports = xpc::UnwrapReflectorToISupports(obj)) { + nsCOMPtr treeItem(do_QueryInterface(supports)); + if (treeItem) + return NS_LITERAL_CSTRING("ContentDocShellTreeItem"); + + nsCOMPtr doc(do_QueryInterface(supports)); + if (doc) + return NS_LITERAL_CSTRING("ContentDocument"); + } + + return NS_LITERAL_CSTRING("generic"); +} + static RemoteObject MakeRemoteObject(JSContext* cx, ObjectId id, HandleObject obj) { - nsCString objectTag; - - nsCOMPtr service = - do_GetService("@mozilla.org/addons/remote-tag-service;1"); - if (service) { - RootedValue objVal(cx, ObjectValue(*obj)); - service->GetRemoteObjectTag(objVal, objectTag); - } - return RemoteObject(id.serialize(), JS::IsCallable(obj), JS::IsConstructor(obj), dom::IsDOMObject(obj), - objectTag); + GetRemoteObjectTag(obj)); } bool @@ -1146,7 +1187,8 @@ WrapperOwner::fromRemoteObjectVariant(JSContext* cx, RemoteObject objVar) RootedObject junkScope(cx, xpc::PrivilegedJunkScope()); JSAutoCompartment ac(cx, junkScope); RootedValue v(cx, UndefinedValue()); - // We need to setLazyProto for the getPrototype hook. + // We need to setLazyProto for the getPrototype/getPrototypeIfOrdinary + // hooks. ProxyOptions options; options.setLazyProto(true); obj = NewProxyObject(cx, diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index ab5de8f2c1..4f0a8f266c 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -58,6 +58,8 @@ class WrapperOwner : public virtual JavaScriptShared bool isArray(JSContext* cx, JS::HandleObject proxy, JS::IsArrayAnswer* answer); const char* className(JSContext* cx, JS::HandleObject proxy); bool getPrototype(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleObject protop); + bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject proxy, bool* isOrdinary, + JS::MutableHandleObject protop); bool regexp_toShared(JSContext* cx, JS::HandleObject proxy, js::RegExpGuard* g); @@ -147,6 +149,8 @@ class WrapperOwner : public virtual JavaScriptShared uint32_t* answer) = 0; virtual bool SendClassName(const ObjectId& objId, nsCString* result) = 0; virtual bool SendGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result) = 0; + virtual bool SendGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary, + ObjectOrNullVariant* result) = 0; virtual bool SendRegExpToShared(const ObjectId& objId, ReturnStatus* rs, nsString* source, uint32_t* flags) = 0; diff --git a/js/public/Class.h b/js/public/Class.h index 1f1a8a7d0e..3f2555186a 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -960,7 +960,7 @@ enum ESClassValue { }; /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */ -inline bool +bool Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); #ifdef DEBUG diff --git a/js/public/Debug.h b/js/public/Debug.h index 5b40b55c65..f9585d4b95 100644 --- a/js/public/Debug.h +++ b/js/public/Debug.h @@ -150,7 +150,7 @@ class Builder { // A rooted reference to our value. PersistentRooted value; - BuiltThing(JSContext* cx, Builder& owner_, T value_ = js::GCPolicy::initial()) + BuiltThing(JSContext* cx, Builder& owner_, T value_ = GCPolicy::initial()) : owner(owner_), value(cx, value_) { owner.assertBuilt(value_); diff --git a/js/public/GCHashTable.h b/js/public/GCHashTable.h index 103ba2a95c..cf79bdc07c 100644 --- a/js/public/GCHashTable.h +++ b/js/public/GCHashTable.h @@ -13,7 +13,7 @@ #include "js/SweepingAPI.h" #include "js/TracingAPI.h" -namespace js { +namespace JS { // Define a reasonable default GC policy for GC-aware Maps. template @@ -49,12 +49,12 @@ struct DefaultMapSweepPolicy { // sweeping, currently it requires an explicit call to .sweep(). template , - typename AllocPolicy = TempAllocPolicy, + typename HashPolicy = js::DefaultHasher, + typename AllocPolicy = js::TempAllocPolicy, typename MapSweepPolicy = DefaultMapSweepPolicy> -class GCHashMap : public HashMap +class GCHashMap : public js::HashMap { - using Base = HashMap; + using Base = js::HashMap; public: explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} @@ -92,6 +92,10 @@ class GCHashMap : public HashMap GCHashMap& operator=(const GCHashMap& hm) = delete; }; +} // namespace JS + +namespace js { + // HashMap that supports rekeying. // // If your keys are pointers to something like JSObject that can be tenured or @@ -101,10 +105,10 @@ template , typename AllocPolicy = TempAllocPolicy, - typename MapSweepPolicy = DefaultMapSweepPolicy> -class GCRekeyableHashMap : public GCHashMap + typename MapSweepPolicy = JS::DefaultMapSweepPolicy> +class GCRekeyableHashMap : public JS::GCHashMap { - using Base = GCHashMap; + using Base = JS::GCHashMap; public: explicit GCRekeyableHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} @@ -133,7 +137,7 @@ class GCRekeyableHashMap : public GCHashMap class GCHashMapOperations { - using Map = GCHashMap; + using Map = JS::GCHashMap; using Lookup = typename Map::Lookup; using Ptr = typename Map::Ptr; using Range = typename Map::Range; @@ -163,7 +167,7 @@ template class MutableGCHashMapOperations : public GCHashMapOperations { - using Map = GCHashMap; + using Map = JS::GCHashMap; using Lookup = typename Map::Lookup; using Ptr = typename Map::Ptr; using Range = typename Map::Range; @@ -208,25 +212,29 @@ class MutableGCHashMapOperations }; template -class RootedBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> +class RootedBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> {}; template -class MutableHandleBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> +class MutableHandleBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> {}; template -class HandleBase> - : public GCHashMapOperations>, A,B,C,D,E> +class HandleBase> + : public GCHashMapOperations>, A,B,C,D,E> {}; template -class WeakCacheBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> +class WeakCacheBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> {}; +} // namespace js + +namespace JS { + // A GCHashSet is a HashSet with an additional trace method that knows // be traced to be kept alive will generally want to use this GCHashSet // specializeation in lieu of HashSet. @@ -241,11 +249,11 @@ class WeakCacheBase> // function properly it must either be used with Rooted or barriered and traced // manually. template , - typename AllocPolicy = TempAllocPolicy> -class GCHashSet : public HashSet + typename HashPolicy = js::DefaultHasher, + typename AllocPolicy = js::TempAllocPolicy> +class GCHashSet : public js::HashSet { - using Base = HashSet; + using Base = js::HashSet; public: explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {} @@ -280,10 +288,14 @@ class GCHashSet : public HashSet GCHashSet& operator=(const GCHashSet& hs) = delete; }; +} // namespace JS + +namespace js { + template class GCHashSetOperations { - using Set = GCHashSet; + using Set = JS::GCHashSet; using Lookup = typename Set::Lookup; using Ptr = typename Set::Ptr; using Range = typename Set::Range; @@ -314,7 +326,7 @@ template class MutableGCHashSetOperations : public GCHashSetOperations { - using Set = GCHashSet; + using Set = JS::GCHashSet; using Lookup = typename Set::Lookup; using Ptr = typename Set::Ptr; using Range = typename Set::Range; @@ -359,26 +371,26 @@ class MutableGCHashSetOperations }; template -class RootedBase> - : public MutableGCHashSetOperations>, T, HP, AP> +class RootedBase> + : public MutableGCHashSetOperations>, T, HP, AP> { }; template -class MutableHandleBase> - : public MutableGCHashSetOperations>, T, HP, AP> +class MutableHandleBase> + : public MutableGCHashSetOperations>, T, HP, AP> { }; template -class HandleBase> - : public GCHashSetOperations>, T, HP, AP> +class HandleBase> + : public GCHashSetOperations>, T, HP, AP> { }; template -class WeakCacheBase> - : public MutableGCHashSetOperations>, T, HP, AP> +class WeakCacheBase> + : public MutableGCHashSetOperations>, T, HP, AP> { }; diff --git a/js/public/GCPolicyAPI.h b/js/public/GCPolicyAPI.h index 3e1c86316d..1ca473dcb8 100644 --- a/js/public/GCPolicyAPI.h +++ b/js/public/GCPolicyAPI.h @@ -53,7 +53,7 @@ namespace JS { class Symbol; } -namespace js { +namespace JS { // Defines a policy for container types with non-GC, i.e. C storage. This // policy dispatches to the underlying struct for GC interactions. @@ -113,10 +113,10 @@ template struct GCPolicy> { static void trace(JSTracer* trc, JS::Heap* thingp, const char* name) { - JS::TraceEdge(trc, thingp, name); + TraceEdge(trc, thingp, name); } static bool needsSweep(JS::Heap* thingp) { - return gc::EdgeNeedsSweep(thingp); + return js::gc::EdgeNeedsSweep(thingp); } }; @@ -133,6 +133,6 @@ struct GCPolicy> } }; -} // namespace js +} // namespace JS #endif // GCPolicyAPI_h diff --git a/js/public/GCVariant.h b/js/public/GCVariant.h index 29eda9144f..ae5598d9be 100644 --- a/js/public/GCVariant.h +++ b/js/public/GCVariant.h @@ -13,7 +13,7 @@ #include "js/RootingAPI.h" #include "js/TracingAPI.h" -namespace js { +namespace JS { // These template specializations allow Variant to be used inside GC wrappers. // @@ -120,10 +120,14 @@ struct GCPolicy> } }; +} // namespace JS + +namespace js { + template class GCVariantOperations { - using Impl = detail::GCVariantImplementation; + using Impl = JS::detail::GCVariantImplementation; using Variant = mozilla::Variant; const Variant& variant() const { return static_cast(this)->get(); } @@ -150,7 +154,7 @@ template class MutableGCVariantOperations : public GCVariantOperations { - using Impl = detail::GCVariantImplementation; + using Impl = JS::detail::GCVariantImplementation; using Variant = mozilla::Variant; const Variant& variant() const { return static_cast(this)->get(); } diff --git a/js/public/GCVector.h b/js/public/GCVector.h index 53c05976e4..097df72e0e 100644 --- a/js/public/GCVector.h +++ b/js/public/GCVector.h @@ -14,7 +14,7 @@ #include "js/TracingAPI.h" #include "js/Vector.h" -namespace js { +namespace JS { // A GCVector is a Vector with an additional trace method that knows how // to visit all of the items stored in the Vector. For vectors that contain GC @@ -32,7 +32,7 @@ namespace js { // it must either be used with Rooted, or barriered and traced manually. template + typename AllocPolicy = js::TempAllocPolicy> class GCVector { mozilla::Vector vector; @@ -126,10 +126,14 @@ class GCVector } }; +} // namespace JS + +namespace js { + template class GCVectorOperations { - using Vec = GCVector; + using Vec = JS::GCVector; const Vec& vec() const { return static_cast(this)->get(); } public: @@ -150,7 +154,7 @@ template class MutableGCVectorOperations : public GCVectorOperations { - using Vec = GCVector; + using Vec = JS::GCVector; const Vec& vec() const { return static_cast(this)->get(); } Vec& vec() { return static_cast(this)->get(); } @@ -214,23 +218,23 @@ class MutableGCVectorOperations }; template -class RootedBase> - : public MutableGCVectorOperations>, T,N,AP> +class RootedBase> + : public MutableGCVectorOperations>, T,N,AP> {}; template -class MutableHandleBase> - : public MutableGCVectorOperations>, T,N,AP> +class MutableHandleBase> + : public MutableGCVectorOperations>, T,N,AP> {}; template -class HandleBase> - : public GCVectorOperations>, T,N,AP> +class HandleBase> + : public GCVectorOperations>, T,N,AP> {}; template -class PersistentRootedBase> - : public MutableGCVectorOperations>, T,N,AP> +class PersistentRootedBase> + : public MutableGCVectorOperations>, T,N,AP> {}; } // namespace js diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 57f84e5abe..56653e885e 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -77,8 +77,8 @@ class HashMap // HashMap construction is fallible (due to OOM); thus the user must call // init after constructing a HashMap and check the return value. explicit HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {} - MOZ_WARN_UNUSED_RESULT bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } + MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } + bool initialized() const { return impl.initialized(); } // Return whether the given lookup value is present in the map. E.g.: // @@ -140,19 +140,19 @@ class HashMap } template - MOZ_WARN_UNUSED_RESULT bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { return impl.add(p, mozilla::Forward(k), mozilla::Forward(v)); } template - MOZ_WARN_UNUSED_RESULT bool add(AddPtr& p, KeyInput&& k) { + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { return impl.add(p, mozilla::Forward(k), Value()); } template - MOZ_WARN_UNUSED_RESULT bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { return impl.relookupOrAdd(p, k, mozilla::Forward(k), mozilla::Forward(v)); @@ -223,7 +223,7 @@ class HashMap // Overwrite existing value with v. Return false on oom. template - MOZ_WARN_UNUSED_RESULT bool put(KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { AddPtr p = lookupForAdd(k); if (p) { p->value() = mozilla::Forward(v); @@ -234,7 +234,7 @@ class HashMap // Like put, but assert that the given key is not already present. template - MOZ_WARN_UNUSED_RESULT bool putNew(KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { return impl.putNew(k, mozilla::Forward(k), mozilla::Forward(v)); } @@ -331,8 +331,8 @@ class HashSet // HashSet construction is fallible (due to OOM); thus the user must call // init after constructing a HashSet and check the return value. explicit HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {} - MOZ_WARN_UNUSED_RESULT bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } + MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } + bool initialized() const { return impl.initialized(); } // Return whether the given lookup value is present in the map. E.g.: // @@ -389,12 +389,12 @@ class HashSet AddPtr lookupForAdd(const Lookup& l) const { return impl.lookupForAdd(l); } template - MOZ_WARN_UNUSED_RESULT bool add(AddPtr& p, U&& u) { + MOZ_MUST_USE bool add(AddPtr& p, U&& u) { return impl.add(p, mozilla::Forward(u)); } template - MOZ_WARN_UNUSED_RESULT bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { return impl.relookupOrAdd(p, l, mozilla::Forward(u)); } @@ -463,19 +463,19 @@ class HashSet // Add |u| if it is not present already. Return false on oom. template - MOZ_WARN_UNUSED_RESULT bool put(U&& u) { + MOZ_MUST_USE bool put(U&& u) { AddPtr p = lookupForAdd(u); return p ? true : add(p, mozilla::Forward(u)); } // Like put, but assert that the given key is not already present. template - MOZ_WARN_UNUSED_RESULT bool putNew(U&& u) { + MOZ_MUST_USE bool putNew(U&& u) { return impl.putNew(u, mozilla::Forward(u)); } template - MOZ_WARN_UNUSED_RESULT bool putNew(const Lookup& l, U&& u) { + MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { return impl.putNew(l, mozilla::Forward(u)); } @@ -1193,7 +1193,7 @@ class HashTable : private AllocPolicy #endif {} - MOZ_WARN_UNUSED_RESULT bool init(uint32_t length) + MOZ_MUST_USE bool init(uint32_t length) { MOZ_ASSERT(!initialized()); @@ -1689,7 +1689,7 @@ class HashTable : private AllocPolicy } template - MOZ_WARN_UNUSED_RESULT bool add(AddPtr& p, Args&&... args) + MOZ_MUST_USE bool add(AddPtr& p, Args&&... args) { mozilla::ReentrancyGuard g(*this); MOZ_ASSERT(table); @@ -1738,7 +1738,7 @@ class HashTable : private AllocPolicy // Note: |l| may be alias arguments in |args|, so this function must take // care not to use |l| after moving |args|. template - MOZ_WARN_UNUSED_RESULT bool putNew(const Lookup& l, Args&&... args) + MOZ_MUST_USE bool putNew(const Lookup& l, Args&&... args) { if (!this->checkSimulatedOOM()) return false; @@ -1753,7 +1753,7 @@ class HashTable : private AllocPolicy // Note: |l| may be a reference to a piece of |u|, so this function // must take care not to use |l| after moving |u|. template - MOZ_WARN_UNUSED_RESULT bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) { #ifdef JS_DEBUG p.generation = generation(); diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index b411a26138..658d284618 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -114,6 +114,8 @@ struct Zone JSTracer* const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|. public: + js::RootLists roots; + bool needsIncrementalBarrier_; Zone(JSRuntime* runtime, JSTracer* barrierTracerArg) @@ -392,6 +394,9 @@ GCThingIsMarkedGray(GCCellPtr thing) return js::gc::detail::CellIsMarkedGray(thing.asCell()); } +extern JS_PUBLIC_API(JS::TraceKind) +GCThingTraceKind(void* thing); + } /* namespace JS */ namespace js { diff --git a/js/public/Id.h b/js/public/Id.h index 7e3e2b2e8a..a761b05ee4 100644 --- a/js/public/Id.h +++ b/js/public/Id.h @@ -170,6 +170,19 @@ extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY; extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE; extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE; +namespace JS { + +template <> +struct GCPolicy +{ + static jsid initial() { return JSID_VOID; } + static void trace(JSTracer* trc, jsid* idp, const char* name) { + js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); + } +}; + +} // namespace JS + namespace js { template <> @@ -184,15 +197,6 @@ struct DefaultHasher } }; -template <> -struct GCPolicy -{ - static jsid initial() { return JSID_VOID; } - static void trace(JSTracer* trc, jsid* idp, const char* name) { - js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); - } -}; - template <> struct BarrierMethods { diff --git a/js/public/Proxy.h b/js/public/Proxy.h index 1939c4849d..9470b70e8d 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -270,7 +270,9 @@ class JS_FRIEND_API(BaseProxyHandler) virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const; - /* Non-standard but conceptual kin to {g,s}etPrototype, so lives here. */ + /* Non-standard but conceptual kin to {g,s}etPrototype, so these live here. */ + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const; virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const; virtual bool preventExtensions(JSContext* cx, HandleObject proxy, @@ -381,6 +383,8 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler MutableHandleObject protop) const override; virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override; virtual bool preventExtensions(JSContext* cx, HandleObject proxy, diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 00ab9691d6..3b947372f0 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -222,7 +222,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase Heap() { static_assert(sizeof(T) == sizeof(Heap), "Heap must be binary compatible with T."); - init(js::GCPolicy::initial()); + init(GCPolicy::initial()); } explicit Heap(T p) { init(p); } @@ -235,7 +235,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase explicit Heap(const Heap& p) { init(p.ptr); } ~Heap() { - post(ptr, js::GCPolicy::initial()); + post(ptr, GCPolicy::initial()); } DECLARE_POINTER_CONSTREF_OPS(T); @@ -259,7 +259,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase private: void init(T newPtr) { ptr = newPtr; - post(js::GCPolicy::initial(), ptr); + post(GCPolicy::initial(), ptr); } void set(T newPtr) { @@ -600,7 +600,7 @@ class DispatchWrapper public: template MOZ_IMPLICIT DispatchWrapper(U&& initial) - : tracer(&GCPolicy::trace), + : tracer(&JS::GCPolicy::trace), storage(mozilla::Forward(initial)) { } @@ -641,8 +641,14 @@ class MOZ_RAII Rooted : public js::RootedBase *stack = reinterpret_cast*>(this); } - js::RootLists& rootLists(js::ContextFriendFields* cx) { return cx->roots; } - js::RootLists& rootLists(JSContext* cx) { return js::ContextFriendFields::get(cx)->roots; } + js::RootLists& rootLists(js::ContextFriendFields* cx) { + return rootLists(reinterpret_cast(cx)); + } + js::RootLists& rootLists(JSContext* cx) { + if (JS::Zone* zone = js::GetContextZone(cx)) + return JS::shadow::Zone::asShadowZone(zone)->roots; + return rootLists(js::GetRuntime(cx)); + } js::RootLists& rootLists(js::PerThreadDataFriendFields* pt) { return pt->roots; } js::RootLists& rootLists(JSRuntime* rt) { return js::PerThreadDataFriendFields::getMainThread(rt)->roots; @@ -651,7 +657,7 @@ class MOZ_RAII Rooted : public js::RootedBase public: template explicit Rooted(const RootingContext& cx) - : ptr(js::GCPolicy::initial()) + : ptr(GCPolicy::initial()) { registerWithRootLists(rootLists(cx)); } @@ -756,7 +762,7 @@ class MOZ_RAII FakeRooted : public RootedBase { public: template - explicit FakeRooted(CX* cx) : ptr(GCPolicy::initial()) {} + explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy::initial()) {} template FakeRooted(CX* cx, T initial) : ptr(initial) {} @@ -970,11 +976,11 @@ class PersistentRooted : public js::PersistentRootedBase, } public: - PersistentRooted() : ptr(js::GCPolicy::initial()) {} + PersistentRooted() : ptr(GCPolicy::initial()) {} template explicit PersistentRooted(const RootingContext& cx) - : ptr(js::GCPolicy::initial()) + : ptr(GCPolicy::initial()) { registerWithRootLists(rootLists(cx)); } @@ -1007,7 +1013,7 @@ class PersistentRooted : public js::PersistentRootedBase, template void init(const RootingContext& cx) { - init(cx, js::GCPolicy::initial()); + init(cx, GCPolicy::initial()); } template @@ -1018,7 +1024,7 @@ class PersistentRooted : public js::PersistentRootedBase, void reset() { if (initialized()) { - set(js::GCPolicy::initial()); + set(GCPolicy::initial()); ListBase::remove(); } } diff --git a/js/public/SweepingAPI.h b/js/public/SweepingAPI.h index f730f64e1e..2c5fadbbe9 100644 --- a/js/public/SweepingAPI.h +++ b/js/public/SweepingAPI.h @@ -45,7 +45,7 @@ class WeakCache : public js::WeakCacheBase, WeakCache(Zone* zone, U&& initial) : cache(mozilla::Forward(initial)) { - sweeper = js::GCPolicy::sweep; + sweeper = GCPolicy::sweep; shadow::RegisterWeakCache(zone, reinterpret_cast*>(this)); } WeakCache(WeakCache&& other) diff --git a/js/public/Utility.h b/js/public/Utility.h index 3575ed43fb..fa666c37e1 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -35,22 +35,6 @@ namespace mozilla {} /* The private JS engine namespace. */ namespace js {} -/* - * Patterns used by SpiderMonkey to overwrite unused memory. If you are - * accessing an object with one of these pattern, you probably have a dangling - * pointer. - */ -#define JS_FRESH_NURSERY_PATTERN 0x2F -#define JS_SWEPT_NURSERY_PATTERN 0x2B -#define JS_ALLOCATED_NURSERY_PATTERN 0x2D -#define JS_FRESH_TENURED_PATTERN 0x4F -#define JS_MOVED_TENURED_PATTERN 0x49 -#define JS_SWEPT_TENURED_PATTERN 0x4B -#define JS_ALLOCATED_TENURED_PATTERN 0x4D -#define JS_EMPTY_STOREBUFFER_PATTERN 0x1B -#define JS_SWEPT_CODE_PATTERN 0x3B -#define JS_SWEPT_FRAME_PATTERN 0x5B - #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT") #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF") @@ -360,7 +344,7 @@ namespace js { * instances of type |T|. Return false if the calculation overflowed. */ template -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool CalculateAllocSize(size_t numElems, size_t* bytesOut) { *bytesOut = numElems * sizeof(T); @@ -373,7 +357,7 @@ CalculateAllocSize(size_t numElems, size_t* bytesOut) * false if the calculation overflowed. */ template -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut) { *bytesOut = sizeof(T) + numExtra * sizeof(Extra); diff --git a/js/public/Value.h b/js/public/Value.h index 7e564a1bc2..9f0a90a554 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -76,8 +76,9 @@ JS_ENUM_HEADER(JSValueType, uint8_t) JSVAL_TYPE_MAGIC = 0x04, JSVAL_TYPE_STRING = 0x05, JSVAL_TYPE_SYMBOL = 0x06, - JSVAL_TYPE_NULL = 0x07, - JSVAL_TYPE_OBJECT = 0x08, + JSVAL_TYPE_PRIVATE_GCTHING = 0x07, + JSVAL_TYPE_NULL = 0x08, + JSVAL_TYPE_OBJECT = 0x0c, /* These never appear in a jsval; they are only provided as an out-of-band value. */ JSVAL_TYPE_UNKNOWN = 0x20, @@ -100,7 +101,8 @@ JS_ENUM_HEADER(JSValueTag, uint32_t) JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, - JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT + JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), @@ -119,7 +121,8 @@ JS_ENUM_HEADER(JSValueTag, uint32_t) JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, - JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT + JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), @@ -127,15 +130,16 @@ static_assert(sizeof(JSValueTag) == sizeof(uint32_t), JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) { - JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), - JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) + JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), + JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT) } JS_ENUM_FOOTER(JSValueShiftedTag); static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), @@ -163,8 +167,9 @@ typedef uint8_t JSValueType; #define JSVAL_TYPE_MAGIC ((uint8_t)0x04) #define JSVAL_TYPE_STRING ((uint8_t)0x05) #define JSVAL_TYPE_SYMBOL ((uint8_t)0x06) -#define JSVAL_TYPE_NULL ((uint8_t)0x07) -#define JSVAL_TYPE_OBJECT ((uint8_t)0x08) +#define JSVAL_TYPE_PRIVATE_GCTHING ((uint8_t)0x07) +#define JSVAL_TYPE_NULL ((uint8_t)0x08) +#define JSVAL_TYPE_OBJECT ((uint8_t)0x0c) #define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20) #if defined(JS_NUNBOX32) @@ -179,6 +184,7 @@ typedef uint32_t JSValueTag; #define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) #define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) #define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) +#define JSVAL_TAG_PRIVATE_GCTHING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING)) #elif defined(JS_PUNBOX64) @@ -192,17 +198,19 @@ typedef uint32_t JSValueTag; #define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) #define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) #define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) +#define JSVAL_TAG_PRIVATE_GCTHING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING) typedef uint64_t JSValueShiftedTag; -#define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) -#define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_SYMBOL (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) +#define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_SYMBOL (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_PRIVATE_GCTHING (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT) #endif /* JS_PUNBOX64 */ #endif /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ @@ -632,6 +640,29 @@ JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) return l.s.payload.ptr; } +static inline jsval_layout +PRIVATE_GCTHING_TO_JSVAL_IMPL(js::gc::Cell* cell) +{ + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String, + "Private GC thing Values must not be strings. Make a StringValue instead."); + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol, + "Private GC thing Values must not be symbols. Make a SymbolValue instead."); + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object, + "Private GC thing Values must not be objects. Make an ObjectValue instead."); + + jsval_layout l; + MOZ_ASSERT(uintptr_t(cell) > 0x1000); + l.s.tag = JSVAL_TAG_PRIVATE_GCTHING; + l.s.payload.cell = cell; + return l; +} + +static inline bool +JSVAL_IS_PRIVATE_GCTHING_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_PRIVATE_GCTHING; +} + static inline bool JSVAL_IS_GCTHING_IMPL(jsval_layout l) { @@ -654,6 +685,8 @@ JSVAL_TRACE_KIND_IMPL(jsval_layout l) "Value type tags must correspond with JS::TraceKinds."); static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), "Value type tags must correspond with JS::TraceKinds."); + if (MOZ_UNLIKELY(JSVAL_IS_PRIVATE_GCTHING_IMPL(l))) + return (uint32_t)JS::GCThingTraceKind(JSVAL_TO_GCTHING_IMPL(l)); return l.s.tag & 0x03; } @@ -872,6 +905,12 @@ JSVAL_IS_NULL_IMPL(jsval_layout l) return l.asBits == JSVAL_SHIFTED_TAG_NULL; } +static inline bool +JSVAL_IS_PRIVATE_GCTHING_IMPL(jsval_layout l) +{ + return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_PRIVATE_GCTHING; +} + static inline bool JSVAL_IS_GCTHING_IMPL(jsval_layout l) { @@ -895,6 +934,8 @@ JSVAL_TRACE_KIND_IMPL(jsval_layout l) "Value type tags must correspond with JS::TraceKinds."); static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), "Value type tags must correspond with JS::TraceKinds."); + if (MOZ_UNLIKELY(JSVAL_IS_PRIVATE_GCTHING_IMPL(l))) + return (uint32_t)JS::GCThingTraceKind(JSVAL_TO_GCTHING_IMPL(l)); return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) & 0x03; } @@ -916,6 +957,24 @@ JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) return (void*)(l.asBits << 1); } +static inline jsval_layout +PRIVATE_GCTHING_TO_JSVAL_IMPL(js::gc::Cell* cell) +{ + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String, + "Private GC thing Values must not be strings. Make a StringValue instead."); + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol, + "Private GC thing Values must not be symbols. Make a SymbolValue instead."); + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object, + "Private GC thing Values must not be objects. Make an ObjectValue instead."); + + jsval_layout l; + uint64_t cellBits = (uint64_t)cell; + MOZ_ASSERT(uintptr_t(cellBits) > 0x1000); + MOZ_ASSERT((cellBits >> JSVAL_TAG_SHIFT) == 0); + l.asBits = cellBits | JSVAL_SHIFTED_TAG_PRIVATE_GCTHING; + return l; +} + static inline bool JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) { @@ -1341,6 +1400,23 @@ class Value return uint32_t(toInt32()); } + /* + * Private GC Thing API + * + * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit + * payload as private GC things. Such Values are considered isMarkable() + * and isGCThing(), and as such, automatically marked. Their traceKind() + * is gotten via their cells. + */ + + void setPrivateGCThing(js::gc::Cell* cell) { + data = PRIVATE_GCTHING_TO_JSVAL_IMPL(cell); + } + + bool isPrivateGCThing() const { + return JSVAL_IS_PRIVATE_GCTHING_IMPL(data); + } + /* * An unmarked value is just a void* cast as a Value. Thus, the Value is * not safe for GC and must not be marked. This API avoids raw casts @@ -1683,6 +1759,14 @@ PrivateUint32Value(uint32_t ui) return v; } +static inline Value +PrivateGCThingValue(js::gc::Cell* cell) +{ + Value v; + v.setPrivateGCThing(cell); + return v; +} + inline bool SameType(const Value& lhs, const Value& rhs) { @@ -1695,19 +1779,20 @@ SameType(const Value& lhs, const Value& rhs) namespace JS { JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next); -} // namespace JS - -namespace js { template <> struct GCPolicy { - static JS::Value initial() { return JS::UndefinedValue(); } - static void trace(JSTracer* trc, JS::Value* v, const char* name) { + static Value initial() { return UndefinedValue(); } + static void trace(JSTracer* trc, Value* v, const char* name) { js::UnsafeTraceManuallyBarrieredEdge(trc, v, name); } }; +} // namespace JS + +namespace js { + template <> struct BarrierMethods { @@ -1800,6 +1885,7 @@ class MutableValueOperations : public ValueOperations void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); } void setObject(JSObject& obj) { this->value().setObject(obj); } void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); } + void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); } }; /* @@ -1828,6 +1914,7 @@ class HeapBase : public ValueOperations > void setString(JSString* str) { setBarriered(JS::StringValue(str)); } void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); } void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); } + void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); } bool setNumber(uint32_t ui) { if (ui > JSVAL_INT_MAX) { @@ -1889,6 +1976,8 @@ DispatchTyped(F f, const JS::Value& val, Args&&... args) return f(&val.toObject(), mozilla::Forward(args)...); if (val.isSymbol()) return f(val.toSymbol(), mozilla::Forward(args)...); + if (MOZ_UNLIKELY(val.isPrivateGCThing())) + return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward(args)...); MOZ_ASSERT(!val.isMarkable()); return F::defaultValue(val); } diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index 81df88516e..15bc32c47b 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -13,6 +13,7 @@ // These includes are needed these for some typedefs (e.g. HandleValue) and // functions (e.g. NullValue())... #include "js/CallNonGenericMethod.h" +#include "js/GCHashTable.h" #include "js/GCVector.h" #include "js/TypeDecls.h" #include "js/Value.h" @@ -36,9 +37,9 @@ typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; typedef AutoVectorRooter AutoVector; -using ValueVector = js::GCVector; -using IdVector = js::GCVector; -using ScriptVector = js::GCVector; +using ValueVector = JS::GCVector; +using IdVector = JS::GCVector; +using ScriptVector = JS::GCVector; template class AutoVectorRooter; template class AutoHashMapRooter; @@ -94,6 +95,10 @@ using JS::ScriptVector; using JS::AutoHashMapRooter; using JS::AutoHashSetRooter; +using JS::GCVector; +using JS::GCHashMap; +using JS::GCHashSet; + using JS::CallArgs; using JS::CallNonGenericMethod; using JS::CallReceiver; diff --git a/js/src/asmjs/AsmJS.cpp b/js/src/asmjs/AsmJS.cpp index b41b7568c7..9d136d9bc0 100644 --- a/js/src/asmjs/AsmJS.cpp +++ b/js/src/asmjs/AsmJS.cpp @@ -392,6 +392,9 @@ class js::AsmJSModule final : public Module virtual const char16_t* displayURL() const override { return scriptSource()->hasDisplayURL() ? scriptSource()->displayURL() : nullptr; } + virtual ScriptSource* maybeScriptSource() const override { + return scriptSource(); + } uint32_t minHeapLength() const { return module_->minHeapLength; } uint32_t numFFIs() const { return module_->numFFIs; } @@ -741,8 +744,8 @@ FunctionObject(ParseNode* fn) static inline PropertyName* FunctionName(ParseNode* fn) { - if (JSAtom* atom = FunctionObject(fn)->atom()) - return atom->asPropertyName(); + if (JSAtom* name = FunctionObject(fn)->name()) + return name->asPropertyName(); return nullptr; } @@ -1811,7 +1814,7 @@ class MOZ_STACK_CLASS ModuleValidator MOZ_ASSERT(type == Type::canonicalize(Type::lit(lit))); uint32_t index; - if (!mg_.allocateGlobalVar(type.canonicalToValType(), isConst, &index)) + if (!mg_.allocateGlobal(type.canonicalToValType(), isConst, &index)) return false; Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable; @@ -1828,7 +1831,7 @@ class MOZ_STACK_CLASS ModuleValidator AsmJSGlobal g(AsmJSGlobal::Variable, nullptr); g.pod.u.var.initKind_ = AsmJSGlobal::InitConstant; g.pod.u.var.u.val_ = lit.value(); - g.pod.u.var.globalDataOffset_ = mg_.globalVar(index).globalDataOffset; + g.pod.u.var.globalDataOffset_ = mg_.global(index).globalDataOffset; return module_->globals.append(g); } bool addGlobalVarImport(PropertyName* var, PropertyName* field, Type type, bool isConst) { @@ -1836,7 +1839,7 @@ class MOZ_STACK_CLASS ModuleValidator uint32_t index; ValType valType = type.canonicalToValType(); - if (!mg_.allocateGlobalVar(valType, isConst, &index)) + if (!mg_.allocateGlobal(valType, isConst, &index)) return false; Global::Which which = isConst ? Global::ConstantImport : Global::Variable; @@ -1851,7 +1854,7 @@ class MOZ_STACK_CLASS ModuleValidator AsmJSGlobal g(AsmJSGlobal::Variable, field); g.pod.u.var.initKind_ = AsmJSGlobal::InitImport; g.pod.u.var.u.importType_ = valType; - g.pod.u.var.globalDataOffset_ = mg_.globalVar(index).globalDataOffset; + g.pod.u.var.globalDataOffset_ = mg_.global(index).globalDataOffset; return module_->globals.append(g); } bool addArrayView(PropertyName* var, Scalar::Type vt, PropertyName* maybeField) { @@ -2550,13 +2553,13 @@ SimdToExpr(SimdType type, SimdOperation op) case SimdOperation::Fn_greaterThan: return Expr::I32x4greaterThanU; case SimdOperation::Fn_greaterThanOrEqual: return Expr::I32x4greaterThanOrEqualU; case SimdOperation::Fn_fromFloat32x4: return Expr::I32x4fromFloat32x4U; - case SimdOperation::Fn_fromInt32x4Bits: return Expr::Id; + case SimdOperation::Fn_fromInt32x4Bits: return Expr::Limit; default: break; } MOZ_FALLTHROUGH; case SimdType::Int32x4: { // Bitcasts Uint32x4 <--> Int32x4 become noops. - if (op == SimdOperation::Fn_fromUint32x4Bits) return Expr::Id; + if (op == SimdOperation::Fn_fromUint32x4Bits) return Expr::Limit; ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32CASE) break; } @@ -2699,8 +2702,8 @@ class MOZ_STACK_CLASS FunctionValidator MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf); MOZ_ASSERT(absolute < blockDepth_); return encoder().writeExpr(expr) && - encoder().writeVarU32(blockDepth_ - 1 - absolute) && - encoder().writeExpr(Expr::Nop); + encoder().writeVarU32(0) && // break arity + encoder().writeVarU32(blockDepth_ - 1 - absolute); } void removeLabel(PropertyName* label, LabelMap* map) { LabelMap::Ptr p = map->lookup(label); @@ -2709,16 +2712,16 @@ class MOZ_STACK_CLASS FunctionValidator } public: - bool pushBreakableBlock(uint32_t numStmts) { + bool pushBreakableBlock() { return encoder().writeExpr(Expr::Block) && - encoder().writeVarU32(numStmts) && breakableStack_.append(blockDepth_++); } - void popBreakableBlock() { + bool popBreakableBlock() { JS_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_); + return encoder().writeExpr(Expr::End); } - bool pushUnbreakableBlock(uint32_t numStmts, const NameVector* labels = nullptr) { + bool pushUnbreakableBlock(const NameVector* labels = nullptr) { if (labels) { for (PropertyName* label : *labels) { if (!breakLabels_.putNew(label, blockDepth_)) @@ -2726,35 +2729,49 @@ class MOZ_STACK_CLASS FunctionValidator } } blockDepth_++; - return encoder().writeExpr(Expr::Block) && - encoder().writeVarU32(numStmts); + return encoder().writeExpr(Expr::Block); } - void popUnbreakableBlock(const NameVector* labels = nullptr) { + bool popUnbreakableBlock(const NameVector* labels = nullptr) { if (labels) { for (PropertyName* label : *labels) removeLabel(label, &breakLabels_); } --blockDepth_; + return encoder().writeExpr(Expr::End); } - bool pushContinuableBlock(uint32_t numStmts) { + bool pushContinuableBlock() { return encoder().writeExpr(Expr::Block) && - encoder().writeVarU32(numStmts) && continuableStack_.append(blockDepth_++); } - void popContinuableBlock() { + bool popContinuableBlock() { JS_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_); + return encoder().writeExpr(Expr::End); } - bool pushLoop(uint32_t numStmts) { + bool pushLoop() { return encoder().writeExpr(Expr::Loop) && - encoder().writeVarU32(numStmts) && breakableStack_.append(blockDepth_++) && continuableStack_.append(blockDepth_++); } - void popLoop() { + bool popLoop() { JS_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_); JS_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_); + return encoder().writeExpr(Expr::End); + } + + bool pushIf() { + ++blockDepth_; + return encoder().writeExpr(Expr::If); + } + bool switchToElse() { + MOZ_ASSERT(blockDepth_ > 0); + return encoder().writeExpr(Expr::Else); + } + bool popIf() { + MOZ_ASSERT(blockDepth_ > 0); + --blockDepth_; + return encoder().writeExpr(Expr::End); } bool writeBreakIf() { @@ -2814,11 +2831,11 @@ class MOZ_STACK_CLASS FunctionValidator Encoder& encoder() { return *encoder_; } - MOZ_WARN_UNUSED_RESULT bool writeInt32Lit(int32_t i32) { + MOZ_MUST_USE bool writeInt32Lit(int32_t i32) { return encoder().writeExpr(Expr::I32Const) && encoder().writeVarS32(i32); } - MOZ_WARN_UNUSED_RESULT bool writeConstExpr(NumLit lit) { + MOZ_MUST_USE bool writeConstExpr(NumLit lit) { switch (lit.which()) { case NumLit::Fixnum: case NumLit::NegativeInt: @@ -2846,16 +2863,18 @@ class MOZ_STACK_CLASS FunctionValidator } MOZ_CRASH("unexpected literal type"); } - MOZ_WARN_UNUSED_RESULT bool writeCall(ParseNode* pn, Expr op) { + MOZ_MUST_USE bool writeCall(ParseNode* pn, Expr op) { return encoder().writeExpr(op) && fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); } - MOZ_WARN_UNUSED_RESULT bool patchableCall(ParseNode* pn, size_t* offset) { - return encoder().writePatchableOneByteExpr(offset) && - fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); + MOZ_MUST_USE bool prepareCall(ParseNode* pn) { + return fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); } - MOZ_WARN_UNUSED_RESULT bool writeSimdOp(SimdType simdType, SimdOperation op) { - return encoder().writeExpr(SimdToExpr(simdType, op)); + MOZ_MUST_USE bool writeSimdOp(SimdType simdType, SimdOperation op) { + Expr expr = SimdToExpr(simdType, op); + if (expr == Expr::Limit) + return true; + return encoder().writeExpr(expr); } }; @@ -3536,12 +3555,12 @@ CheckVariables(FunctionValidator& f, ParseNode** stmtIter) NumLit lit = inits[i]; if (lit.isZeroBits()) continue; + if (!f.writeConstExpr(lit)) + return false; if (!f.encoder().writeExpr(Expr::SetLocal)) return false; if (!f.encoder().writeVarU32(firstVar + i)) return false; - if (!f.writeConstExpr(lit)) - return false; } *stmtIter = stmt; @@ -3619,10 +3638,8 @@ static const bool NoSimd = false; static bool CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr, - bool isSimd, Scalar::Type* viewType, int32_t* mask) + bool isSimd, Scalar::Type* viewType) { - *mask = 0; - if (!viewName->isKind(PNK_NAME)) return f.fail(viewName, "base of array access must be a typed array view name"); @@ -3639,14 +3656,13 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr if (!f.m().tryConstantAccess(byteOffset, width)) return f.fail(indexExpr, "constant index out of range"); - *mask = NoMask; return f.writeInt32Lit(byteOffset); } // Mask off the low bits to account for the clearing effect of a right shift // followed by the left shift implicit in the array access. E.g., H32[i>>2] // loses the low two bits. - *mask = ~(TypedArrayElemSize(*viewType) - 1); + int32_t mask = ~(TypedArrayElemSize(*viewType) - 1); if (indexExpr->isKind(PNK_RSH)) { ParseNode* shiftAmountNode = BitwiseRight(indexExpr); @@ -3673,7 +3689,7 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr if (TypedArrayShift(*viewType) != 0) return f.fail(indexExpr, "index expression isn't shifted; must be an Int8/Uint8 access"); - MOZ_ASSERT(*mask == NoMask); + MOZ_ASSERT(mask == NoMask); ParseNode* pointerNode = indexExpr; @@ -3690,6 +3706,13 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr } } + // Don't generate the mask op if there is no need for it which could happen for + // a shift of zero or a SIMD access. + if (mask != NoMask) { + return f.writeInt32Lit(mask) && + f.encoder().writeExpr(Expr::I32And); + } + return true; } @@ -3697,35 +3720,22 @@ static bool CheckAndPrepareArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr, bool isSimd, Scalar::Type* viewType) { - size_t flagsAt; - if (!f.encoder().writePatchableFixedU8(&flagsAt)) + return CheckArrayAccess(f, viewName, indexExpr, isSimd, viewType); +} + +static bool +WriteArrayAccessFlags(FunctionValidator& f, Scalar::Type viewType) +{ + // asm.js only has naturally-aligned accesses. + size_t align = TypedArrayElemSize(viewType); + MOZ_ASSERT(IsPowerOfTwo(align)); + if (!f.encoder().writeFixedU8(CeilingLog2(align))) return false; // asm.js doesn't have constant offsets, so just encode a 0. if (!f.encoder().writeVarU32(0)) return false; - size_t prepareAt; - if (!f.encoder().writePatchableOneByteExpr(&prepareAt)) - return false; - - int32_t mask; - if (!CheckArrayAccess(f, viewName, indexExpr, isSimd, viewType, &mask)) - return false; - - // asm.js only has naturally-aligned accesses. - size_t align = TypedArrayElemSize(*viewType); - MOZ_ASSERT(IsPowerOfTwo(align)); - f.encoder().patchFixedU8(flagsAt, CeilingLog2(align)); - - // Don't generate the mask op if there is no need for it which could happen for - // a shift of zero or a SIMD access. - if (mask != NoMask) { - f.encoder().patchOneByteExpr(prepareAt, Expr::I32And); - return f.writeInt32Lit(mask); - } - - f.encoder().patchOneByteExpr(prepareAt, Expr::Id); return true; } @@ -3734,22 +3744,18 @@ CheckLoadArray(FunctionValidator& f, ParseNode* elem, Type* type) { Scalar::Type viewType; - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - if (!CheckAndPrepareArrayAccess(f, ElemBase(elem), ElemIndex(elem), NoSimd, &viewType)) return false; switch (viewType) { - case Scalar::Int8: f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Load8S); break; - case Scalar::Uint8: f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Load8U); break; - case Scalar::Int16: f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Load16S); break; - case Scalar::Uint16: f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Load16U); break; + case Scalar::Int8: if (!f.encoder().writeExpr(Expr::I32Load8S)) return false; break; + case Scalar::Uint8: if (!f.encoder().writeExpr(Expr::I32Load8U)) return false; break; + case Scalar::Int16: if (!f.encoder().writeExpr(Expr::I32Load16S)) return false; break; + case Scalar::Uint16: if (!f.encoder().writeExpr(Expr::I32Load16U)) return false; break; case Scalar::Uint32: - case Scalar::Int32: f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Load); break; - case Scalar::Float32: f.encoder().patchOneByteExpr(opcodeAt, Expr::F32Load); break; - case Scalar::Float64: f.encoder().patchOneByteExpr(opcodeAt, Expr::F64Load); break; + case Scalar::Int32: if (!f.encoder().writeExpr(Expr::I32Load)) return false; break; + case Scalar::Float32: if (!f.encoder().writeExpr(Expr::F32Load)) return false; break; + case Scalar::Float64: if (!f.encoder().writeExpr(Expr::F64Load)) return false; break; default: MOZ_CRASH("unexpected scalar type"); } @@ -3771,16 +3777,15 @@ CheckLoadArray(FunctionValidator& f, ParseNode* elem, Type* type) default: MOZ_CRASH("Unexpected array type"); } + if (!WriteArrayAccessFlags(f, viewType)) + return false; + return true; } static bool CheckStoreArray(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type) { - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Scalar::Type viewType; if (!CheckAndPrepareArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), NoSimd, &viewType)) return false; @@ -3814,31 +3819,43 @@ CheckStoreArray(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type switch (viewType) { case Scalar::Int8: case Scalar::Uint8: - f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Store8); + if (!f.encoder().writeExpr(Expr::I32Store8)) + return false; break; case Scalar::Int16: case Scalar::Uint16: - f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Store16); + if (!f.encoder().writeExpr(Expr::I32Store16)) + return false; break; case Scalar::Int32: case Scalar::Uint32: - f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Store); + if (!f.encoder().writeExpr(Expr::I32Store)) + return false; break; case Scalar::Float32: - if (rhsType.isFloatish()) - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32Store); - else - f.encoder().patchOneByteExpr(opcodeAt, Expr::F64StoreF32); + if (rhsType.isFloatish()) { + if (!f.encoder().writeExpr(Expr::F32Store)) + return false; + } else { + if (!f.encoder().writeExpr(Expr::F64StoreF32)) + return false; + } break; case Scalar::Float64: - if (rhsType.isFloatish()) - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32StoreF64); - else - f.encoder().patchOneByteExpr(opcodeAt, Expr::F64Store); + if (rhsType.isFloatish()) { + if (!f.encoder().writeExpr(Expr::F32StoreF64)) + return false; + } else { + if (!f.encoder().writeExpr(Expr::F64Store)) + return false; + } break; default: MOZ_CRASH("unexpected scalar type"); } + if (!WriteArrayAccessFlags(f, viewType)) + return false; + *type = rhsType; return true; } @@ -3849,15 +3866,15 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type RootedPropertyName name(f.cx(), lhs->name()); if (const FunctionValidator::Local* lhsVar = f.lookupLocal(name)) { + Type rhsType; + if (!CheckExpr(f, rhs, &rhsType)) + return false; + if (!f.encoder().writeExpr(Expr::SetLocal)) return false; if (!f.encoder().writeVarU32(lhsVar->slot)) return false; - Type rhsType; - if (!CheckExpr(f, rhs, &rhsType)) - return false; - if (!(rhsType <= lhsVar->type)) { return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), lhsVar->type.toChars()); @@ -3870,11 +3887,6 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type if (global->which() != ModuleValidator::Global::Variable) return f.failName(lhs, "'%s' is not a mutable variable", name); - if (!f.encoder().writeExpr(Expr::StoreGlobal)) - return false; - if (!f.encoder().writeVarU32(global->varOrConstIndex())) - return false; - Type rhsType; if (!CheckExpr(f, rhs, &rhsType)) return false; @@ -3882,6 +3894,11 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type Type globType = global->varOrConstType(); if (!(rhsType <= globType)) return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), globType.toChars()); + if (!f.encoder().writeExpr(Expr::StoreGlobal)) + return false; + if (!f.encoder().writeVarU32(global->varOrConstIndex())) + return false; + *type = rhsType; return true; } @@ -3915,9 +3932,6 @@ CheckMathIMul(FunctionValidator& f, ParseNode* call, Type* type) ParseNode* lhs = CallArgList(call); ParseNode* rhs = NextNode(lhs); - if (!f.encoder().writeExpr(Expr::I32Mul)) - return false; - Type lhsType; if (!CheckExpr(f, lhs, &lhsType)) return false; @@ -3932,7 +3946,7 @@ CheckMathIMul(FunctionValidator& f, ParseNode* call, Type* type) return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars()); *type = Type::Signed; - return true; + return f.encoder().writeExpr(Expr::I32Mul); } static bool @@ -3941,9 +3955,6 @@ CheckMathClz32(FunctionValidator& f, ParseNode* call, Type* type) if (CallArgListLength(call) != 1) return f.fail(call, "Math.clz32 must be passed 1 argument"); - if (!f.encoder().writeExpr(Expr::I32Clz)) - return false; - ParseNode* arg = CallArgList(call); Type argType; @@ -3954,7 +3965,7 @@ CheckMathClz32(FunctionValidator& f, ParseNode* call, Type* type) return f.failf(arg, "%s is not a subtype of intish", argType.toChars()); *type = Type::Fixnum; - return true; + return f.encoder().writeExpr(Expr::I32Clz); } static bool @@ -3965,30 +3976,23 @@ CheckMathAbs(FunctionValidator& f, ParseNode* call, Type* type) ParseNode* arg = CallArgList(call); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Type argType; if (!CheckExpr(f, arg, &argType)) return false; if (argType.isSigned()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Abs); *type = Type::Unsigned; - return true; + return f.encoder().writeExpr(Expr::I32Abs); } if (argType.isMaybeDouble()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F64Abs); *type = Type::Double; - return true; + return f.encoder().writeExpr(Expr::F64Abs); } if (argType.isMaybeFloat()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32Abs); *type = Type::Floatish; - return true; + return f.encoder().writeExpr(Expr::F32Abs); } return f.failf(call, "%s is not a subtype of signed, float? or double?", argType.toChars()); @@ -4002,24 +4006,18 @@ CheckMathSqrt(FunctionValidator& f, ParseNode* call, Type* type) ParseNode* arg = CallArgList(call); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Type argType; if (!CheckExpr(f, arg, &argType)) return false; if (argType.isMaybeDouble()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F64Sqrt); *type = Type::Double; - return true; + return f.encoder().writeExpr(Expr::F64Sqrt); } if (argType.isMaybeFloat()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32Sqrt); *type = Type::Floatish; - return true; + return f.encoder().writeExpr(Expr::F32Sqrt); } return f.failf(call, "%s is neither a subtype of double? nor float?", argType.toChars()); @@ -4031,10 +4029,6 @@ CheckMathMinMax(FunctionValidator& f, ParseNode* callNode, bool isMax, Type* typ if (CallArgListLength(callNode) < 2) return f.fail(callNode, "Math.min/max must be passed at least 2 arguments"); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - ParseNode* firstArg = CallArgList(callNode); Type firstType; if (!CheckExpr(f, firstArg, &firstType)) @@ -4057,19 +4051,18 @@ CheckMathMinMax(FunctionValidator& f, ParseNode* callNode, bool isMax, Type* typ return f.failf(firstArg, "%s is not a subtype of double?, float? or signed", firstType.toChars()); } - f.encoder().patchOneByteExpr(opcodeAt, expr); unsigned numArgs = CallArgListLength(callNode); ParseNode* nextArg = NextNode(firstArg); for (unsigned i = 1; i < numArgs; i++, nextArg = NextNode(nextArg)) { - if (i != numArgs - 1 && !f.encoder().writeExpr(expr)) - return false; - Type nextType; if (!CheckExpr(f, nextArg, &nextType)) return false; if (!(nextType <= firstType)) return f.failf(nextArg, "%s is not a subtype of %s", nextType.toChars(), firstType.toChars()); + + if (!f.encoder().writeExpr(expr)) + return false; } return true; @@ -4105,10 +4098,10 @@ CheckSharedArrayAtomicAccess(FunctionValidator& f, ParseNode* viewName, ParseNod } static bool -WriteAtomicOperator(FunctionValidator& f, Expr opcode, size_t* viewTypeAt) +WriteAtomicOperator(FunctionValidator& f, Expr opcode, Scalar::Type viewType) { return f.encoder().writeExpr(opcode) && - f.encoder().writePatchableFixedU8(viewTypeAt); + f.encoder().writeFixedU8(viewType); } static bool @@ -4120,15 +4113,15 @@ CheckAtomicsLoad(FunctionValidator& f, ParseNode* call, Type* type) ParseNode* arrayArg = CallArgList(call); ParseNode* indexArg = NextNode(arrayArg); - size_t viewTypeAt; - if (!WriteAtomicOperator(f, Expr::I32AtomicsLoad, &viewTypeAt)) - return false; - Scalar::Type viewType; if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - f.encoder().patchFixedU8(viewTypeAt, uint8_t(viewType)); + if (!WriteAtomicOperator(f, Expr::I32AtomicsLoad, viewType)) + return false; + + if (!WriteArrayAccessFlags(f, viewType)) + return false; *type = Type::Int; return true; @@ -4144,14 +4137,6 @@ CheckAtomicsStore(FunctionValidator& f, ParseNode* call, Type* type) ParseNode* indexArg = NextNode(arrayArg); ParseNode* valueArg = NextNode(indexArg); - size_t viewTypeAt; - if (!WriteAtomicOperator(f, Expr::I32AtomicsStore, &viewTypeAt)) - return false; - - Scalar::Type viewType; - if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) - return false; - Type rhsType; if (!CheckExpr(f, valueArg, &rhsType)) return false; @@ -4159,7 +4144,15 @@ CheckAtomicsStore(FunctionValidator& f, ParseNode* call, Type* type) if (!rhsType.isIntish()) return f.failf(arrayArg, "%s is not a subtype of intish", rhsType.toChars()); - f.encoder().patchFixedU8(viewTypeAt, uint8_t(viewType)); + Scalar::Type viewType; + if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) + return false; + + if (!WriteAtomicOperator(f, Expr::I32AtomicsStore, viewType)) + return false; + + if (!WriteArrayAccessFlags(f, viewType)) + return false; *type = rhsType; return true; @@ -4175,16 +4168,6 @@ CheckAtomicsBinop(FunctionValidator& f, ParseNode* call, Type* type, AtomicOp op ParseNode* indexArg = NextNode(arrayArg); ParseNode* valueArg = NextNode(indexArg); - size_t viewTypeAt; - if (!WriteAtomicOperator(f, Expr::I32AtomicsBinOp, &viewTypeAt)) - return false; - if (!f.encoder().writeFixedU8(uint8_t(op))) - return false; - - Scalar::Type viewType; - if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) - return false; - Type valueArgType; if (!CheckExpr(f, valueArg, &valueArgType)) return false; @@ -4192,7 +4175,17 @@ CheckAtomicsBinop(FunctionValidator& f, ParseNode* call, Type* type, AtomicOp op if (!valueArgType.isIntish()) return f.failf(valueArg, "%s is not a subtype of intish", valueArgType.toChars()); - f.encoder().patchFixedU8(viewTypeAt, uint8_t(viewType)); + Scalar::Type viewType; + if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) + return false; + + if (!WriteAtomicOperator(f, Expr::I32AtomicsBinOp, viewType)) + return false; + if (!f.encoder().writeFixedU8(uint8_t(op))) + return false; + + if (!WriteArrayAccessFlags(f, viewType)) + return false; *type = Type::Int; return true; @@ -4225,14 +4218,6 @@ CheckAtomicsCompareExchange(FunctionValidator& f, ParseNode* call, Type* type) ParseNode* oldValueArg = NextNode(indexArg); ParseNode* newValueArg = NextNode(oldValueArg); - size_t viewTypeAt; - if (!WriteAtomicOperator(f, Expr::I32AtomicsCompareExchange, &viewTypeAt)) - return false; - - Scalar::Type viewType; - if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) - return false; - Type oldValueArgType; if (!CheckExpr(f, oldValueArg, &oldValueArgType)) return false; @@ -4247,7 +4232,15 @@ CheckAtomicsCompareExchange(FunctionValidator& f, ParseNode* call, Type* type) if (!newValueArgType.isIntish()) return f.failf(newValueArg, "%s is not a subtype of intish", newValueArgType.toChars()); - f.encoder().patchFixedU8(viewTypeAt, uint8_t(viewType)); + Scalar::Type viewType; + if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) + return false; + + if (!WriteAtomicOperator(f, Expr::I32AtomicsCompareExchange, viewType)) + return false; + + if (!WriteArrayAccessFlags(f, viewType)) + return false; *type = Type::Int; return true; @@ -4263,14 +4256,6 @@ CheckAtomicsExchange(FunctionValidator& f, ParseNode* call, Type* type) ParseNode* indexArg = NextNode(arrayArg); ParseNode* valueArg = NextNode(indexArg); - size_t viewTypeAt; - if (!WriteAtomicOperator(f, Expr::I32AtomicsExchange, &viewTypeAt)) - return false; - - Scalar::Type viewType; - if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) - return false; - Type valueArgType; if (!CheckExpr(f, valueArg, &valueArgType)) return false; @@ -4278,7 +4263,15 @@ CheckAtomicsExchange(FunctionValidator& f, ParseNode* call, Type* type) if (!valueArgType.isIntish()) return f.failf(arrayArg, "%s is not a subtype of intish", valueArgType.toChars()); - f.encoder().patchFixedU8(viewTypeAt, uint8_t(viewType)); + Scalar::Type viewType; + if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) + return false; + + if (!WriteAtomicOperator(f, Expr::I32AtomicsExchange, viewType)) + return false; + + if (!WriteArrayAccessFlags(f, viewType)) + return false; *type = Type::Int; return true; @@ -4394,24 +4387,28 @@ CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calle { MOZ_ASSERT(ret.isCanonical()); - if (!f.writeCall(callNode, Expr::Call)) - return false; - - // Function's index, to find out the function's entry - size_t funcIndexAt; - if (!f.encoder().writePatchableVarU32(&funcIndexAt)) - return false; - ValTypeVector args; if (!CheckCallArgs(f, callNode, &args)) return false; + uint32_t arity = args.length(); Sig sig(Move(args), ret.canonicalToExprType()); + ModuleValidator::Func* callee; if (!CheckFunctionSignature(f.m(), callNode, Move(sig), calleeName, &callee)) return false; - f.encoder().patchVarU32(funcIndexAt, callee->index()); + if (!f.writeCall(callNode, Expr::Call)) + return false; + + // Call arity + if (!f.encoder().writeVarU32(arity)) + return false; + + // Function's index, to find out the function's entry + if (!f.encoder().writeVarU32(callee->index())) + return false; + *type = Type::ret(ret); return true; } @@ -4472,15 +4469,6 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, Type ret, Type* type if (!IsLiteralInt(f.m(), maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1)) return f.fail(maskNode, "function-pointer table index mask value must be a power of two minus 1"); - // Opcode - if (!f.writeCall(callNode, Expr::CallIndirect)) - return false; - - // Call signature - size_t sigIndexAt; - if (!f.encoder().writePatchableVarU32(&sigIndexAt)) - return false; - Type indexType; if (!CheckExpr(f, indexNode, &indexType)) return false; @@ -4492,13 +4480,23 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, Type ret, Type* type if (!CheckCallArgs(f, callNode, &args)) return false; + uint32_t arity = args.length(); Sig sig(Move(args), ret.canonicalToExprType()); uint32_t tableIndex; if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(sig), mask, &tableIndex)) return false; - f.encoder().patchVarU32(sigIndexAt, f.m().funcPtrTable(tableIndex).sigIndex()); + if (!f.writeCall(callNode, Expr::CallIndirect)) + return false; + + // Call arity + if (!f.encoder().writeVarU32(arity)) + return false; + + // Call signature + if (!f.encoder().writeVarU32(f.m().funcPtrTable(tableIndex).sigIndex())) + return false; *type = Type::ret(ret); return true; @@ -4524,50 +4522,43 @@ CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, Type if (ret.isSimd()) return f.fail(callNode, "FFI calls can't return SIMD values"); - // Opcode - if (!f.writeCall(callNode, Expr::CallImport)) - return false; - - // Import index - size_t importIndexAt; - if (!f.encoder().writePatchableVarU32(&importIndexAt)) - return false; - ValTypeVector args; if (!CheckCallArgs(f, callNode, &args)) return false; + uint32_t arity = args.length(); Sig sig(Move(args), ret.canonicalToExprType()); + uint32_t importIndex; if (!f.m().declareImport(calleeName, Move(sig), ffiIndex, &importIndex)) return false; - f.encoder().patchVarU32(importIndexAt, importIndex); + if (!f.writeCall(callNode, Expr::CallImport)) + return false; + + // Call arity + if (!f.encoder().writeVarU32(arity)) + return false; + + // Import index + if (!f.encoder().writeVarU32(importIndex)) + return false; *type = Type::ret(ret); return true; } static bool -CheckFloatCoercionArg(FunctionValidator& f, ParseNode* inputNode, Type inputType, - size_t opcodeAt) +CheckFloatCoercionArg(FunctionValidator& f, ParseNode* inputNode, Type inputType) { - if (inputType.isMaybeDouble()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32DemoteF64); + if (inputType.isMaybeDouble()) + return f.encoder().writeExpr(Expr::F32DemoteF64); + if (inputType.isSigned()) + return f.encoder().writeExpr(Expr::F32ConvertSI32); + if (inputType.isUnsigned()) + return f.encoder().writeExpr(Expr::F32ConvertUI32); + if (inputType.isFloatish()) return true; - } - if (inputType.isSigned()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32ConvertSI32); - return true; - } - if (inputType.isUnsigned()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32ConvertUI32); - return true; - } - if (inputType.isFloatish()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::Id); - return true; - } return f.failf(inputNode, "%s is not a subtype of signed, unsigned, double? or floatish", inputType.toChars()); @@ -4584,21 +4575,16 @@ CheckCoercionArg(FunctionValidator& f, ParseNode* arg, Type expected, Type* type if (arg->isKind(PNK_CALL)) return CheckCoercedCall(f, arg, expected, type); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Type argType; if (!CheckExpr(f, arg, &argType)) return false; if (expected.isFloat()) { - if (!CheckFloatCoercionArg(f, arg, argType, opcodeAt)) + if (!CheckFloatCoercionArg(f, arg, argType)) return false; } else if (expected.isSimd()) { if (!(argType <= expected)) return f.fail(arg, "argument to SIMD coercion isn't from the correct SIMD type"); - f.encoder().patchOneByteExpr(opcodeAt, Expr::Id); } else { MOZ_CRASH("not call coercions"); } @@ -4657,8 +4643,7 @@ CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltin if (actualArity != arity) return f.failf(callNode, "call passed %u arguments, expected %u", actualArity, arity); - size_t opcodeAt; - if (!f.patchableCall(callNode, &opcodeAt)) + if (!f.prepareCall(callNode)) return false; Type firstType; @@ -4673,11 +4658,6 @@ CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltin if (!opIsDouble && f32 == Expr::Unreachable) return f.fail(callNode, "math builtin cannot be used as float"); - if (opIsDouble) - f.encoder().patchOneByteExpr(opcodeAt, f64); - else - f.encoder().patchOneByteExpr(opcodeAt, f32); - if (arity == 2) { Type secondType; argNode = NextNode(argNode); @@ -4690,6 +4670,14 @@ CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltin return f.fail(argNode, "both arguments to math builtin call should be the same type"); } + if (opIsDouble) { + if (!f.encoder().writeExpr(f64)) + return false; + } else { + if (!f.encoder().writeExpr(f32)) + return false; + } + *type = opIsDouble ? Type::Double : Type::Floatish; return true; } @@ -4719,31 +4707,6 @@ CheckSimdCallArgs(FunctionValidator& f, ParseNode* call, unsigned expectedArity, return true; } -template -static bool -CheckSimdCallArgsPatchable(FunctionValidator& f, ParseNode* call, unsigned expectedArity, - const CheckArgOp& checkArg) -{ - unsigned numArgs = CallArgListLength(call); - if (numArgs != expectedArity) - return f.failf(call, "expected %u arguments to SIMD call, got %u", expectedArity, numArgs); - - ParseNode* arg = CallArgList(call); - for (size_t i = 0; i < numArgs; i++, arg = NextNode(arg)) { - MOZ_ASSERT(!!arg); - Type argType; - size_t patchAt; - if (!f.encoder().writePatchableOneByteExpr(&patchAt)) - return false; - if (!CheckExpr(f, arg, &argType)) - return false; - if (!checkArg(f, arg, i, argType, patchAt)) - return false; - } - - return true; -} - class CheckArgIsSubtypeOf { @@ -4788,8 +4751,7 @@ class CheckSimdScalarArgs : simdType_(simdType), formalType_(SimdToCoercedScalarType(simdType)) {} - bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType, - size_t patchAt) const + bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const { if (!(actualType <= formalType_)) { // As a special case, accept doublelit arguments to float32x4 ops by @@ -4801,15 +4763,9 @@ class CheckSimdScalarArgs } // We emitted a double literal and actually want a float32. - MOZ_ASSERT(patchAt != size_t(-1)); - f.encoder().patchOneByteExpr(patchAt, Expr::F32DemoteF64); - return true; + return f.encoder().writeExpr(Expr::F32DemoteF64); } - if (patchAt == size_t(-1)) - return true; - - f.encoder().patchOneByteExpr(patchAt, Expr::Id); return true; } }; @@ -4845,36 +4801,6 @@ class CheckSimdVectorScalarArgs public: explicit CheckSimdVectorScalarArgs(SimdType t) : formalSimdType_(t) {} - bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType, - size_t patchAt = -1) const - { - MOZ_ASSERT(argIndex < 2); - if (argIndex == 0) { - // First argument is the vector - if (!(actualType <= Type(formalSimdType_))) { - return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(), - Type(formalSimdType_).toChars()); - } - - if (patchAt == size_t(-1)) - return true; - - f.encoder().patchOneByteExpr(patchAt, Expr::Id); - return true; - } - - // Second argument is the scalar - return CheckSimdScalarArgs(formalSimdType_)(f, arg, argIndex, actualType, patchAt); - } -}; - -class CheckSimdExtractLaneArgs -{ - SimdType formalSimdType_; - - public: - explicit CheckSimdExtractLaneArgs(SimdType t) : formalSimdType_(t) {} - bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const { MOZ_ASSERT(argIndex < 2); @@ -4884,53 +4810,12 @@ class CheckSimdExtractLaneArgs return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(), Type(formalSimdType_).toChars()); } + return true; } - uint32_t laneIndex; - // Second argument is the lane < vector length - if (!IsLiteralOrConstInt(f, arg, &laneIndex)) - return f.failf(arg, "lane selector should be a constant integer literal"); - if (laneIndex >= GetSimdLanes(formalSimdType_)) - return f.failf(arg, "lane selector should be in bounds"); - return true; - } -}; - -class CheckSimdReplaceLaneArgs -{ - SimdType formalSimdType_; - - public: - explicit CheckSimdReplaceLaneArgs(SimdType t) : formalSimdType_(t) {} - - bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType, - size_t patchAt) const - { - MOZ_ASSERT(argIndex < 3); - uint32_t u32; - switch (argIndex) { - case 0: - // First argument is the vector - if (!(actualType <= Type(formalSimdType_))) { - return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(), - Type(formalSimdType_).toChars()); - } - f.encoder().patchOneByteExpr(patchAt, Expr::Id); - return true; - case 1: - // Second argument is the lane (< vector length). - if (!IsLiteralOrConstInt(f, arg, &u32)) - return f.failf(arg, "lane selector should be a constant integer literal"); - if (u32 >= GetSimdLanes(formalSimdType_)) - return f.failf(arg, "lane selector should be in bounds"); - f.encoder().patchOneByteExpr(patchAt, Expr::Id); - return true; - case 2: - // Third argument is the scalar - return CheckSimdScalarArgs(formalSimdType_)(f, arg, argIndex, actualType, patchAt); - } - return false; + // Second argument is the scalar + return CheckSimdScalarArgs(formalSimdType_)(f, arg, argIndex, actualType); } }; @@ -4940,10 +4825,10 @@ static bool CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, Type* type) { - if (!f.writeSimdOp(opType, op)) - return false; if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType))) return false; + if (!f.writeSimdOp(opType, op)) + return false; *type = opType; return true; } @@ -4952,10 +4837,10 @@ static bool CheckSimdBinaryShift(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, Type *type) { - if (!f.writeSimdOp(opType, op)) - return false; if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType))) return false; + if (!f.writeSimdOp(opType, op)) + return false; *type = opType; return true; } @@ -4964,10 +4849,10 @@ static bool CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, Type *type) { - if (!f.writeSimdOp(opType, op)) - return false; if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType))) return false; + if (!f.writeSimdOp(opType, op)) + return false; *type = GetBooleanSimdType(opType); return true; } @@ -4976,10 +4861,10 @@ static bool CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, Type* type) { - if (!f.writeSimdOp(opType, op)) - return false; if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType))) return false; + if (!f.writeSimdOp(opType, op)) + return false; *type = opType; return true; } @@ -4987,8 +4872,6 @@ CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOper static bool CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) { - if (!f.writeSimdOp(opType, SimdOperation::Fn_extractLane)) - return false; switch (opType) { case SimdType::Int32x4: *type = Type::Signed; break; case SimdType::Uint32x4: *type = Type::Unsigned; break; @@ -4996,15 +4879,84 @@ CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Typ case SimdType::Bool32x4: *type = Type::Int; break; default: MOZ_CRASH("unhandled simd type"); } - return CheckSimdCallArgs(f, call, 2, CheckSimdExtractLaneArgs(opType)); + + unsigned numArgs = CallArgListLength(call); + if (numArgs != 2) + return f.failf(call, "expected 2 arguments to SIMD extract, got %u", numArgs); + + ParseNode* arg = CallArgList(call); + + // First argument is the vector + Type vecType; + if (!CheckExpr(f, arg, &vecType)) + return false; + if (!(vecType <= Type(opType))) { + return f.failf(arg, "%s is not a subtype of %s", vecType.toChars(), + Type(opType).toChars()); + } + + arg = NextNode(arg); + + // Second argument is the lane < vector length + uint32_t lane; + if (!IsLiteralOrConstInt(f, arg, &lane)) + return f.failf(arg, "lane selector should be a constant integer literal"); + if (lane >= GetSimdLanes(opType)) + return f.failf(arg, "lane selector should be in bounds"); + + if (!f.writeSimdOp(opType, SimdOperation::Fn_extractLane)) + return false; + if (!f.encoder().writeVarU32(lane)) + return false; + return true; } static bool CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) { + unsigned numArgs = CallArgListLength(call); + if (numArgs != 3) + return f.failf(call, "expected 2 arguments to SIMD replace, got %u", numArgs); + + ParseNode* arg = CallArgList(call); + + // First argument is the vector + Type vecType; + if (!CheckExpr(f, arg, &vecType)) + return false; + if (!(vecType <= Type(opType))) { + return f.failf(arg, "%s is not a subtype of %s", vecType.toChars(), + Type(opType).toChars()); + } + + arg = NextNode(arg); + + // Second argument is the lane < vector length + uint32_t lane; + if (!IsLiteralOrConstInt(f, arg, &lane)) + return f.failf(arg, "lane selector should be a constant integer literal"); + if (lane >= GetSimdLanes(opType)) + return f.failf(arg, "lane selector should be in bounds"); + + arg = NextNode(arg); + + // Third argument is the scalar + Type scalarType; + if (!CheckExpr(f, arg, &scalarType)) + return false; + if (!(scalarType <= SimdToCoercedScalarType(opType))) { + if (opType == SimdType::Float32x4 && scalarType.isDoubleLit()) { + if (!f.encoder().writeExpr(Expr::F32DemoteF64)) + return false; + } else { + return f.failf(arg, "%s is not the correct type to replace an element of %s", + scalarType.toChars(), vecType.toChars()); + } + } + if (!f.writeSimdOp(opType, SimdOperation::Fn_replaceLane)) return false; - if (!CheckSimdCallArgsPatchable(f, call, 3, CheckSimdReplaceLaneArgs(opType))) + if (!f.encoder().writeVarU32(lane)) return false; *type = opType; return true; @@ -5019,10 +4971,10 @@ static bool CheckSimdCast(FunctionValidator& f, ParseNode* call, SimdType fromType, SimdType toType, SimdOperation op, Type* type) { - if (!f.writeSimdOp(toType, op)) - return false; if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(fromType))) return false; + if (!f.writeSimdOp(toType, op)) + return false; *type = toType; return true; } @@ -5050,9 +5002,6 @@ CheckSimdSwizzle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t if (numArgs != 5) return f.failf(call, "expected 5 arguments to SIMD swizzle, got %u", numArgs); - if (!f.writeSimdOp(opType, SimdOperation::Fn_swizzle)) - return false; - Type retType = opType; ParseNode* vec = CallArgList(call); Type vecType; @@ -5061,6 +5010,9 @@ CheckSimdSwizzle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t if (!(vecType <= retType)) return f.failf(vec, "%s is not a subtype of %s", vecType.toChars(), retType.toChars()); + if (!f.writeSimdOp(opType, SimdOperation::Fn_swizzle)) + return false; + int32_t lanes[4]; if (!CheckSimdShuffleSelectors(f, NextNode(vec), lanes, 4)) return false; @@ -5081,9 +5033,6 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t if (numArgs != 6) return f.failf(call, "expected 6 arguments to SIMD shuffle, got %u", numArgs); - if (!f.writeSimdOp(opType, SimdOperation::Fn_shuffle)) - return false; - Type retType = opType; ParseNode* arg = CallArgList(call); for (unsigned i = 0; i < 2; i++, arg = NextNode(arg)) { @@ -5094,6 +5043,9 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t return f.failf(arg, "%s is not a subtype of %s", type.toChars(), retType.toChars()); } + if (!f.writeSimdOp(opType, SimdOperation::Fn_shuffle)) + return false; + int32_t lanes[4]; if (!CheckSimdShuffleSelectors(f, arg, lanes, 8)) return false; @@ -5108,7 +5060,7 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t } static bool -CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call) +CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, Scalar::Type* viewType) { ParseNode* view = CallArgList(call); if (!view->isKind(PNK_NAME)) @@ -5116,11 +5068,10 @@ CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call) ParseNode* indexExpr = NextNode(view); - Scalar::Type viewType; - if (!CheckAndPrepareArrayAccess(f, view, indexExpr, YesSimd, &viewType)) + if (!CheckAndPrepareArrayAccess(f, view, indexExpr, YesSimd, viewType)) return false; - if (viewType != Scalar::Uint8) + if (*viewType != Scalar::Uint8) return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument"); return true; @@ -5134,10 +5085,14 @@ CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperat if (numArgs != 2) return f.failf(call, "expected 2 arguments to SIMD load, got %u", numArgs); + Scalar::Type viewType; + if (!CheckSimdLoadStoreArgs(f, call, &viewType)) + return false; + if (!f.writeSimdOp(opType, op)) return false; - if (!CheckSimdLoadStoreArgs(f, call)) + if (!WriteArrayAccessFlags(f, viewType)) return false; *type = opType; @@ -5152,10 +5107,8 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera if (numArgs != 3) return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs); - if (!f.writeSimdOp(opType, op)) - return false; - - if (!CheckSimdLoadStoreArgs(f, call)) + Scalar::Type viewType; + if (!CheckSimdLoadStoreArgs(f, call, &viewType)) return false; Type retType = opType; @@ -5164,6 +5117,12 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera if (!CheckExpr(f, vecExpr, &vecType)) return false; + if (!f.writeSimdOp(opType, op)) + return false; + + if (!WriteArrayAccessFlags(f, viewType)) + return false; + if (!(vecType <= retType)) return f.failf(vecExpr, "%s is not a subtype of %s", vecType.toChars(), retType.toChars()); @@ -5174,10 +5133,10 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera static bool CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) { - if (!f.writeSimdOp(opType, SimdOperation::Fn_select)) - return false; if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType))) return false; + if (!f.writeSimdOp(opType, SimdOperation::Fn_select)) + return false; *type = opType; return true; } @@ -5185,10 +5144,10 @@ CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* ty static bool CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) { - if (!f.writeSimdOp(opType, SimdOperation::Fn_allTrue)) - return false; if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType))) return false; + if (!f.writeSimdOp(opType, SimdOperation::Fn_allTrue)) + return false; *type = Type::Int; return true; } @@ -5196,10 +5155,10 @@ CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t static bool CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) { - if (!f.writeSimdOp(opType, SimdOperation::Fn_anyTrue)) - return false; if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType))) return false; + if (!f.writeSimdOp(opType, SimdOperation::Fn_anyTrue)) + return false; *type = Type::Int; return true; } @@ -5217,9 +5176,9 @@ CheckSimdCheck(FunctionValidator& f, ParseNode* call, SimdType opType, Type* typ static bool CheckSimdSplat(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) { - if (!f.writeSimdOp(opType, SimdOperation::Fn_splat)) + if (!CheckSimdCallArgs(f, call, 1, CheckSimdScalarArgs(opType))) return false; - if (!CheckSimdCallArgsPatchable(f, call, 1, CheckSimdScalarArgs(opType))) + if (!f.writeSimdOp(opType, SimdOperation::Fn_splat)) return false; *type = opType; return true; @@ -5319,11 +5278,11 @@ CheckSimdCtorCall(FunctionValidator& f, ParseNode* call, const ModuleValidator:: MOZ_ASSERT(call->isKind(PNK_CALL)); SimdType simdType = global->simdCtorType(); - if (!f.writeSimdOp(simdType, SimdOperation::Constructor)) + unsigned length = GetSimdLanes(simdType); + if (!CheckSimdCallArgs(f, call, length, CheckSimdScalarArgs(simdType))) return false; - unsigned length = GetSimdLanes(simdType); - if (!CheckSimdCallArgsPatchable(f, call, length, CheckSimdScalarArgs(simdType))) + if (!f.writeSimdOp(simdType, SimdOperation::Constructor)) return false; *type = simdType; @@ -5354,43 +5313,44 @@ CheckUncoercedCall(FunctionValidator& f, ParseNode* expr, Type* type) } static bool -CoerceResult(FunctionValidator& f, ParseNode* expr, Type expected, Type actual, size_t patchAt, +CoerceResult(FunctionValidator& f, ParseNode* expr, Type expected, Type actual, Type* type) { MOZ_ASSERT(expected.isCanonical()); // At this point, the bytecode resembles this: - // | patchAt | the thing we wanted to coerce | current position |> + // | the thing we wanted to coerce | current position |> switch (expected.which()) { case Type::Void: - f.encoder().patchOneByteExpr(patchAt, Expr::Id); break; case Type::Int: if (!actual.isIntish()) return f.failf(expr, "%s is not a subtype of intish", actual.toChars()); - f.encoder().patchOneByteExpr(patchAt, Expr::Id); break; case Type::Float: - if (!CheckFloatCoercionArg(f, expr, actual, patchAt)) + if (!CheckFloatCoercionArg(f, expr, actual)) return false; break; case Type::Double: - if (actual.isMaybeDouble()) - f.encoder().patchOneByteExpr(patchAt, Expr::Id); - else if (actual.isMaybeFloat()) - f.encoder().patchOneByteExpr(patchAt, Expr::F64PromoteF32); - else if (actual.isSigned()) - f.encoder().patchOneByteExpr(patchAt, Expr::F64ConvertSI32); - else if (actual.isUnsigned()) - f.encoder().patchOneByteExpr(patchAt, Expr::F64ConvertUI32); - else + if (actual.isMaybeDouble()) { + // No conversion necessary. + } else if (actual.isMaybeFloat()) { + if (!f.encoder().writeExpr(Expr::F64PromoteF32)) + return false; + } else if (actual.isSigned()) { + if (!f.encoder().writeExpr(Expr::F64ConvertSI32)) + return false; + } else if (actual.isUnsigned()) { + if (!f.encoder().writeExpr(Expr::F64ConvertUI32)) + return false; + } else { return f.failf(expr, "%s is not a subtype of double?, float?, signed or unsigned", actual.toChars()); + } break; default: MOZ_ASSERT(expected.isSimd(), "Incomplete switch"); if (actual != expected) return f.failf(expr, "got type %s, expected %s", actual.toChars(), expected.toChars()); - f.encoder().patchOneByteExpr(patchAt, Expr::Id); break; } @@ -5402,13 +5362,10 @@ static bool CheckCoercedMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltinFunction func, Type ret, Type* type) { - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; Type actual; if (!CheckMathBuiltinCall(f, callNode, func, &actual)) return false; - return CoerceResult(f, callNode, ret, actual, opcodeAt, type); + return CoerceResult(f, callNode, ret, actual, type); } static bool @@ -5417,10 +5374,6 @@ CheckCoercedSimdCall(FunctionValidator& f, ParseNode* call, const ModuleValidato { MOZ_ASSERT(ret.isCanonical()); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Type actual; if (global->isSimdCtor()) { if (!CheckSimdCtorCall(f, call, global, &actual)) @@ -5432,7 +5385,7 @@ CheckCoercedSimdCall(FunctionValidator& f, ParseNode* call, const ModuleValidato return false; } - return CoerceResult(f, call, ret, actual, opcodeAt, type); + return CoerceResult(f, call, ret, actual, type); } static bool @@ -5441,13 +5394,10 @@ CheckCoercedAtomicsBuiltinCall(FunctionValidator& f, ParseNode* callNode, { MOZ_ASSERT(ret.isCanonical()); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; Type actual; if (!CheckAtomicsBuiltinCall(f, callNode, func, &actual)) return false; - return CoerceResult(f, callNode, ret, actual, opcodeAt, type); + return CoerceResult(f, callNode, ret, actual, type); } static bool @@ -5458,13 +5408,10 @@ CheckCoercedCall(FunctionValidator& f, ParseNode* call, Type ret, Type* type) JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); if (IsNumericLiteral(f.m(), call)) { - size_t coerceOp; - if (!f.encoder().writePatchableOneByteExpr(&coerceOp)) - return false; NumLit lit = ExtractNumericLiteral(f.m(), call); if (!f.writeConstExpr(lit)) return false; - return CoerceResult(f, call, ret, Type::lit(lit), coerceOp, type); + return CoerceResult(f, call, ret, Type::lit(lit), type); } ParseNode* callee = CallCallee(call); @@ -5512,15 +5459,11 @@ CheckPos(FunctionValidator& f, ParseNode* pos, Type* type) if (operand->isKind(PNK_CALL)) return CheckCoercedCall(f, operand, Type::Double, type); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Type actual; if (!CheckExpr(f, operand, &actual)) return false; - return CoerceResult(f, operand, Type::Double, actual, opcodeAt, type); + return CoerceResult(f, operand, Type::Double, actual, type); } static bool @@ -5529,9 +5472,6 @@ CheckNot(FunctionValidator& f, ParseNode* expr, Type* type) MOZ_ASSERT(expr->isKind(PNK_NOT)); ParseNode* operand = UnaryKid(expr); - if (!f.encoder().writeExpr(Expr::I32Eqz)) - return false; - Type operandType; if (!CheckExpr(f, operand, &operandType)) return false; @@ -5540,7 +5480,7 @@ CheckNot(FunctionValidator& f, ParseNode* expr, Type* type) return f.failf(operand, "%s is not a subtype of int", operandType.toChars()); *type = Type::Int; - return true; + return f.encoder().writeExpr(Expr::I32Eqz); } static bool @@ -5549,30 +5489,23 @@ CheckNeg(FunctionValidator& f, ParseNode* expr, Type* type) MOZ_ASSERT(expr->isKind(PNK_NEG)); ParseNode* operand = UnaryKid(expr); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Type operandType; if (!CheckExpr(f, operand, &operandType)) return false; if (operandType.isInt()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Neg); *type = Type::Intish; - return true; + return f.encoder().writeExpr(Expr::I32Neg); } if (operandType.isMaybeDouble()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F64Neg); *type = Type::Double; - return true; + return f.encoder().writeExpr(Expr::F64Neg); } if (operandType.isMaybeFloat()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32Neg); *type = Type::Floatish; - return true; + return f.encoder().writeExpr(Expr::F32Neg); } return f.failf(operand, "%s is not a subtype of int, float? or double?", operandType.toChars()); @@ -5584,25 +5517,19 @@ CheckCoerceToInt(FunctionValidator& f, ParseNode* expr, Type* type) MOZ_ASSERT(expr->isKind(PNK_BITNOT)); ParseNode* operand = UnaryKid(expr); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Type operandType; if (!CheckExpr(f, operand, &operandType)) return false; if (operandType.isMaybeDouble() || operandType.isMaybeFloat()) { - Expr opcode = operandType.isMaybeDouble() ? Expr::I32TruncSF64 : Expr::I32TruncSF32; - f.encoder().patchOneByteExpr(opcodeAt, opcode); *type = Type::Signed; - return true; + Expr opcode = operandType.isMaybeDouble() ? Expr::I32TruncSF64 : Expr::I32TruncSF32; + return f.encoder().writeExpr(opcode); } if (!operandType.isIntish()) return f.failf(operand, "%s is not a subtype of double?, float? or intish", operandType.toChars()); - f.encoder().patchOneByteExpr(opcodeAt, Expr::Id); *type = Type::Signed; return true; } @@ -5616,9 +5543,6 @@ CheckBitNot(FunctionValidator& f, ParseNode* neg, Type* type) if (operand->isKind(PNK_BITNOT)) return CheckCoerceToInt(f, operand, type); - if (!f.encoder().writeExpr(Expr::I32BitNot)) - return false; - Type operandType; if (!CheckExpr(f, operand, &operandType)) return false; @@ -5626,6 +5550,9 @@ CheckBitNot(FunctionValidator& f, ParseNode* neg, Type* type) if (!operandType.isIntish()) return f.failf(operand, "%s is not a subtype of intish", operandType.toChars()); + if (!f.encoder().writeExpr(Expr::I32BitNot)) + return false; + *type = Type::Signed; return true; } @@ -5643,8 +5570,6 @@ CheckComma(FunctionValidator& f, ParseNode* comma, Type* type) // contain breaks and continues and nested control flow structures. if (!f.encoder().writeExpr(Expr::Block)) return false; - if (!f.encoder().writeVarU32(ListLength(comma))) - return false; ParseNode* pn = operands; for (; NextNode(pn); pn = NextNode(pn)) { @@ -5652,7 +5577,10 @@ CheckComma(FunctionValidator& f, ParseNode* comma, Type* type) return false; } - return CheckExpr(f, pn, type); + if (!CheckExpr(f, pn, type)) + return false; + + return f.encoder().writeExpr(Expr::End); } static bool @@ -5660,9 +5588,6 @@ CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type) { MOZ_ASSERT(ternary->isKind(PNK_CONDITIONAL)); - if (!f.encoder().writeExpr(Expr::IfElse)) - return false; - ParseNode* cond = TernaryKid1(ternary); ParseNode* thenExpr = TernaryKid2(ternary); ParseNode* elseExpr = TernaryKid3(ternary); @@ -5674,10 +5599,16 @@ CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type) if (!condType.isInt()) return f.failf(cond, "%s is not a subtype of int", condType.toChars()); + if (!f.pushIf()) + return false; + Type thenType; if (!CheckExpr(f, thenExpr, &thenType)) return false; + if (!f.switchToElse()) + return false; + Type elseType; if (!CheckExpr(f, elseExpr, &elseType)) return false; @@ -5696,6 +5627,9 @@ CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type) thenType.toChars(), elseType.toChars()); } + if (!f.popIf()) + return false; + return true; } @@ -5733,10 +5667,6 @@ CheckMultiply(FunctionValidator& f, ParseNode* star, Type* type) ParseNode* lhs = MultiplyLeft(star); ParseNode* rhs = MultiplyRight(star); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - Type lhsType; if (!CheckExpr(f, lhs, &lhsType)) return false; @@ -5748,21 +5678,18 @@ CheckMultiply(FunctionValidator& f, ParseNode* star, Type* type) if (lhsType.isInt() && rhsType.isInt()) { if (!IsValidIntMultiplyConstant(f.m(), lhs) && !IsValidIntMultiplyConstant(f.m(), rhs)) return f.fail(star, "one arg to int multiply must be a small (-2^20, 2^20) int literal"); - f.encoder().patchOneByteExpr(opcodeAt, Expr::I32Mul); *type = Type::Intish; - return true; + return f.encoder().writeExpr(Expr::I32Mul); } if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F64Mul); *type = Type::Double; - return true; + return f.encoder().writeExpr(Expr::F64Mul); } if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32Mul); *type = Type::Floatish; - return true; + return f.encoder().writeExpr(Expr::F32Mul); } return f.fail(star, "multiply operands must be both int, both double? or both float?"); @@ -5780,10 +5707,6 @@ CheckAddOrSub(FunctionValidator& f, ParseNode* expr, Type* type, unsigned* numAd Type lhsType, rhsType; unsigned lhsNumAddOrSub, rhsNumAddOrSub; - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - if (lhs->isKind(PNK_ADD) || lhs->isKind(PNK_SUB)) { if (!CheckAddOrSub(f, lhs, &lhsType, &lhsNumAddOrSub)) return false; @@ -5811,13 +5734,16 @@ CheckAddOrSub(FunctionValidator& f, ParseNode* expr, Type* type, unsigned* numAd return f.fail(expr, "too many + or - without intervening coercion"); if (lhsType.isInt() && rhsType.isInt()) { - f.encoder().patchOneByteExpr(opcodeAt, expr->isKind(PNK_ADD) ? Expr::I32Add : Expr::I32Sub); + if (!f.encoder().writeExpr(expr->isKind(PNK_ADD) ? Expr::I32Add : Expr::I32Sub)) + return false; *type = Type::Intish; } else if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) { - f.encoder().patchOneByteExpr(opcodeAt, expr->isKind(PNK_ADD) ? Expr::F64Add : Expr::F64Sub); + if (!f.encoder().writeExpr(expr->isKind(PNK_ADD) ? Expr::F64Add : Expr::F64Sub)) + return false; *type = Type::Double; } else if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) { - f.encoder().patchOneByteExpr(opcodeAt, expr->isKind(PNK_ADD) ? Expr::F32Add : Expr::F32Sub); + if (!f.encoder().writeExpr(expr->isKind(PNK_ADD) ? Expr::F32Add : Expr::F32Sub)) + return false; *type = Type::Floatish; } else { return f.failf(expr, "operands to + or - must both be int, float? or double?, got %s and %s", @@ -5834,10 +5760,6 @@ CheckDivOrMod(FunctionValidator& f, ParseNode* expr, Type* type) { MOZ_ASSERT(expr->isKind(PNK_DIV) || expr->isKind(PNK_MOD)); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - ParseNode* lhs = DivOrModLeft(expr); ParseNode* rhs = DivOrModRight(expr); @@ -5848,30 +5770,26 @@ CheckDivOrMod(FunctionValidator& f, ParseNode* expr, Type* type) return false; if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) { - f.encoder().patchOneByteExpr(opcodeAt, expr->isKind(PNK_DIV) ? Expr::F64Div : Expr::F64Mod); *type = Type::Double; - return true; + return f.encoder().writeExpr(expr->isKind(PNK_DIV) ? Expr::F64Div : Expr::F64Mod); } if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) { + *type = Type::Floatish; if (expr->isKind(PNK_DIV)) - f.encoder().patchOneByteExpr(opcodeAt, Expr::F32Div); + return f.encoder().writeExpr(Expr::F32Div); else return f.fail(expr, "modulo cannot receive float arguments"); - *type = Type::Floatish; - return true; } if (lhsType.isSigned() && rhsType.isSigned()) { - f.encoder().patchOneByteExpr(opcodeAt, expr->isKind(PNK_DIV) ? Expr::I32DivS : Expr::I32RemS); *type = Type::Intish; - return true; + return f.encoder().writeExpr(expr->isKind(PNK_DIV) ? Expr::I32DivS : Expr::I32RemS); } if (lhsType.isUnsigned() && rhsType.isUnsigned()) { - f.encoder().patchOneByteExpr(opcodeAt, expr->isKind(PNK_DIV) ? Expr::I32DivU : Expr::I32RemU); *type = Type::Intish; - return true; + return f.encoder().writeExpr(expr->isKind(PNK_DIV) ? Expr::I32DivU : Expr::I32RemU); } return f.failf(expr, "arguments to / or %% must both be double?, float?, signed, or unsigned; " @@ -5884,10 +5802,6 @@ CheckComparison(FunctionValidator& f, ParseNode* comp, Type* type) MOZ_ASSERT(comp->isKind(PNK_LT) || comp->isKind(PNK_LE) || comp->isKind(PNK_GT) || comp->isKind(PNK_GE) || comp->isKind(PNK_EQ) || comp->isKind(PNK_NE)); - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; - ParseNode* lhs = ComparisonLeft(comp); ParseNode* rhs = ComparisonRight(comp); @@ -5951,9 +5865,8 @@ CheckComparison(FunctionValidator& f, ParseNode* comp, Type* type) MOZ_CRASH("unexpected type"); } - f.encoder().patchOneByteExpr(opcodeAt, stmt); *type = Type::Int; - return true; + return f.encoder().writeExpr(stmt); } static bool @@ -5996,16 +5909,6 @@ CheckBitwise(FunctionValidator& f, ParseNode* bitwise, Type* type) return true; } - switch (bitwise->getKind()) { - case PNK_BITOR: if (!f.encoder().writeExpr(Expr::I32Or)) return false; break; - case PNK_BITAND: if (!f.encoder().writeExpr(Expr::I32And)) return false; break; - case PNK_BITXOR: if (!f.encoder().writeExpr(Expr::I32Xor)) return false; break; - case PNK_LSH: if (!f.encoder().writeExpr(Expr::I32Shl)) return false; break; - case PNK_RSH: if (!f.encoder().writeExpr(Expr::I32ShrS)) return false; break; - case PNK_URSH: if (!f.encoder().writeExpr(Expr::I32ShrU)) return false; break; - default: MOZ_CRASH("not a bitwise op"); - } - Type lhsType; if (!CheckExpr(f, lhs, &lhsType)) return false; @@ -6019,6 +5922,16 @@ CheckBitwise(FunctionValidator& f, ParseNode* bitwise, Type* type) if (!rhsType.isIntish()) return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars()); + switch (bitwise->getKind()) { + case PNK_BITOR: if (!f.encoder().writeExpr(Expr::I32Or)) return false; break; + case PNK_BITAND: if (!f.encoder().writeExpr(Expr::I32And)) return false; break; + case PNK_BITXOR: if (!f.encoder().writeExpr(Expr::I32Xor)) return false; break; + case PNK_LSH: if (!f.encoder().writeExpr(Expr::I32Shl)) return false; break; + case PNK_RSH: if (!f.encoder().writeExpr(Expr::I32ShrS)) return false; break; + case PNK_URSH: if (!f.encoder().writeExpr(Expr::I32ShrU)) return false; break; + default: MOZ_CRASH("not a bitwise op"); + } + return true; } @@ -6087,7 +6000,7 @@ CheckExprStatement(FunctionValidator& f, ParseNode* exprStmt) MOZ_ASSERT(exprStmt->isKind(PNK_SEMI)); ParseNode* expr = UnaryKid(exprStmt); if (!expr) - return f.encoder().writeExpr(Expr::Nop); + return true; return CheckAsExprStatement(f, expr); } @@ -6095,22 +6008,8 @@ static bool CheckLoopConditionOnEntry(FunctionValidator& f, ParseNode* cond) { uint32_t maybeLit; - - // TODO: will not need to generate nop when blocks switch from - // number-of-statements immediate to end marker. if (IsLiteralInt(f.m(), cond, &maybeLit) && maybeLit) - return f.encoder().writeExpr(Expr::Nop); - - // brIf (i32.eq 0 $f) $out - if (!f.writeBreakIf()) - return false; - - // TODO change this to i32.eqz - // i32.eq 0 $f - if (!f.encoder().writeExpr(Expr::I32Eq)) - return false; - if (!f.writeInt32Lit(0)) - return false; + return true; Type condType; if (!CheckExpr(f, cond, &condType)) @@ -6118,6 +6017,17 @@ CheckLoopConditionOnEntry(FunctionValidator& f, ParseNode* cond) if (!condType.isInt()) return f.failf(cond, "%s is not a subtype of int", condType.toChars()); + // TODO change this to i32.eqz + // i32.eq 0 $f + if (!f.writeInt32Lit(0)) + return false; + if (!f.encoder().writeExpr(Expr::I32Eq)) + return false; + + // brIf (i32.eq 0 $f) $out + if (!f.writeBreakIf()) + return false; + return true; } @@ -6137,7 +6047,7 @@ CheckWhile(FunctionValidator& f, ParseNode* whileStmt, const NameVector* labels if (labels && !f.addLabels(*labels, 0, 1)) return false; - if (!f.pushLoop(/* numStmts = */ 3)) + if (!f.pushLoop()) return false; if (!CheckLoopConditionOnEntry(f, cond)) @@ -6147,7 +6057,8 @@ CheckWhile(FunctionValidator& f, ParseNode* whileStmt, const NameVector* labels if (!f.writeContinue()) return false; - f.popLoop(); + if (!f.popLoop()) + return false; if (labels) f.removeLabels(*labels); return true; @@ -6182,14 +6093,14 @@ CheckFor(FunctionValidator& f, ParseNode* forStmt, const NameVector* labels = nu if (labels && !f.addLabels(*labels, 1, 3)) return false; - if (!f.pushUnbreakableBlock(/* numStmts = */ 1 + !!maybeInit)) + if (!f.pushUnbreakableBlock()) return false; if (maybeInit && !CheckAsExprStatement(f, maybeInit)) return false; { - if (!f.pushLoop(/* numStmts = */ 2 + !!maybeCond + !!maybeInc)) + if (!f.pushLoop()) return false; if (maybeCond && !CheckLoopConditionOnEntry(f, maybeCond)) @@ -6197,11 +6108,12 @@ CheckFor(FunctionValidator& f, ParseNode* forStmt, const NameVector* labels = nu { // Continuing in the body should just break out to the increment. - if (!f.pushContinuableBlock(1)) + if (!f.pushContinuableBlock()) return false; if (!CheckStatement(f, body)) return false; - f.popContinuableBlock(); + if (!f.popContinuableBlock()) + return false; } if (maybeInc && !CheckAsExprStatement(f, maybeInc)) @@ -6209,10 +6121,12 @@ CheckFor(FunctionValidator& f, ParseNode* forStmt, const NameVector* labels = nu if (!f.writeContinue()) return false; - f.popLoop(); + if (!f.popLoop()) + return false; } - f.popUnbreakableBlock(); + if (!f.popUnbreakableBlock()) + return false; if (labels) f.removeLabels(*labels); @@ -6237,28 +6151,30 @@ CheckDoWhile(FunctionValidator& f, ParseNode* whileStmt, const NameVector* label if (labels && !f.addLabels(*labels, 0, 2)) return false; - if (!f.pushLoop(2 /* numStmts = #body + br_if */)) + if (!f.pushLoop()) return false; { // An unlabeled continue in the body should break out to the condition. - if (!f.pushContinuableBlock(1)) + if (!f.pushContinuableBlock()) return false; if (!CheckStatement(f, body)) return false; - f.popContinuableBlock(); + if (!f.popContinuableBlock()) + return false; } - if (!f.writeContinueIf()) - return false; - Type condType; if (!CheckExpr(f, cond, &condType)) return false; if (!condType.isInt()) return f.failf(cond, "%s is not a subtype of int", condType.toChars()); - f.popLoop(); + if (!f.writeContinueIf()) + return false; + + if (!f.popLoop()) + return false; if (labels) f.removeLabels(*labels); return true; @@ -6292,24 +6208,23 @@ CheckLabel(FunctionValidator& f, ParseNode* labeledStmt) break; } - if (!f.pushUnbreakableBlock(1, &labels)) + if (!f.pushUnbreakableBlock(&labels)) return false; if (!CheckStatement(f, innermost)) return false; - f.popUnbreakableBlock(&labels); + if (!f.popUnbreakableBlock(&labels)) + return false; return true; } static bool CheckIf(FunctionValidator& f, ParseNode* ifStmt) { - recurse: - size_t opcodeAt; - if (!f.encoder().writePatchableOneByteExpr(&opcodeAt)) - return false; + uint32_t numIfEnd = 1; + recurse: MOZ_ASSERT(ifStmt->isKind(PNK_IF)); ParseNode* cond = TernaryKid1(ifStmt); ParseNode* thenStmt = TernaryKid2(ifStmt); @@ -6321,16 +6236,21 @@ CheckIf(FunctionValidator& f, ParseNode* ifStmt) if (!condType.isInt()) return f.failf(cond, "%s is not a subtype of int", condType.toChars()); + if (!f.pushIf()) + return false; + if (!CheckStatement(f, thenStmt)) return false; - if (!elseStmt) { - f.encoder().patchOneByteExpr(opcodeAt, Expr::If); - } else { - f.encoder().patchOneByteExpr(opcodeAt, Expr::IfElse); + if (elseStmt) { + if (!f.switchToElse()) + return false; if (elseStmt->isKind(PNK_IF)) { ifStmt = elseStmt; + ++numIfEnd; + if (numIfEnd == 0) + return false; goto recurse; } @@ -6338,6 +6258,11 @@ CheckIf(FunctionValidator& f, ParseNode* ifStmt) return false; } + for (uint32_t i = 0; i != numIfEnd; ++i) { + if (!f.popIf()) + return false; + } + return true; } @@ -6480,26 +6405,44 @@ CheckSwitch(FunctionValidator& f, ParseNode* switchStmt) } // Open the wrapping breakable default block. - if (!f.pushBreakableBlock(2)) + if (!f.pushBreakableBlock()) return false; // Open all the case blocks. for (uint32_t i = 0; i < numCases; i++) { - if (!f.pushUnbreakableBlock(2)) + if (!f.pushUnbreakableBlock()) return false; } // Open the br_table block. - if (!f.pushUnbreakableBlock(1)) + if (!f.pushUnbreakableBlock()) return false; // The default block is the last one. uint32_t defaultDepth = numCases; + // Subtract lowest case value, so that all the cases start from 0. + if (low) { + if (!CheckSwitchExpr(f, switchExpr)) + return false; + if (!f.writeInt32Lit(low)) + return false; + if (!f.encoder().writeExpr(Expr::I32Sub)) + return false; + } else { + if (!CheckSwitchExpr(f, switchExpr)) + return false; + } + // Start the br_table block. if (!f.encoder().writeExpr(Expr::BrTable)) return false; + // The br_table arity. + if (!f.encoder().writeVarU32(0)) + return false; + + // Write the number of cases (tableLength - 1 + 1 (default)). // Write the number of cases (tableLength - 1 + 1 (default)). if (!f.encoder().writeVarU32(tableLength)) return false; @@ -6516,40 +6459,26 @@ CheckSwitch(FunctionValidator& f, ParseNode* switchStmt) if (!f.encoder().writeFixedU32(defaultDepth)) return false; - // Subtract lowest case value, so that all the cases start from 0. - if (low) { - if (!f.encoder().writeExpr(Expr::I32Sub)) - return false; - if (!CheckSwitchExpr(f, switchExpr)) - return false; - if (!f.writeInt32Lit(low)) - return false; - } else { - if (!CheckSwitchExpr(f, switchExpr)) - return false; - } - // Our br_table is done. Close its block, write the cases down in order. - f.popUnbreakableBlock(); + if (!f.popUnbreakableBlock()) + return false; for (; stmt && !IsDefaultCase(stmt); stmt = NextNode(stmt)) { if (!CheckStatement(f, CaseBody(stmt))) return false; - f.popUnbreakableBlock(); + if (!f.popUnbreakableBlock()) + return false; } // Write the default block. if (stmt && IsDefaultCase(stmt)) { if (!CheckStatement(f, CaseBody(stmt))) return false; - } else { - // TODO no need to write this nop once we go postorder. - if (!f.encoder().writeExpr(Expr::Nop)) - return false; } // Close the wrapping block. - f.popBreakableBlock(); + if (!f.popBreakableBlock()) + return false; return true; } @@ -6574,20 +6503,28 @@ CheckReturn(FunctionValidator& f, ParseNode* returnStmt) { ParseNode* expr = ReturnExpr(returnStmt); + if (!expr) { + if (!CheckReturnType(f, returnStmt, Type::Void)) + return false; + } else { + Type type; + if (!CheckExpr(f, expr, &type)) + return false; + + if (!type.isReturnType()) + return f.failf(expr, "%s is not a valid return type", type.toChars()); + + if (!CheckReturnType(f, expr, Type::canonicalize(type))) + return false; + } + if (!f.encoder().writeExpr(Expr::Return)) return false; - if (!expr) - return CheckReturnType(f, returnStmt, Type::Void); - - Type type; - if (!CheckExpr(f, expr, &type)) + if (!f.encoder().writeVarU32(expr ? 1 : 0)) return false; - if (!type.isReturnType()) - return f.failf(expr, "%s is not a valid return type", type.toChars()); - - return CheckReturnType(f, expr, Type::canonicalize(type)); + return true; } static bool @@ -6595,8 +6532,7 @@ CheckStatementList(FunctionValidator& f, ParseNode* stmtList, const NameVector* { MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST)); - uint32_t numStmts = ListLength(stmtList); - if (!f.pushUnbreakableBlock(numStmts, labels)) + if (!f.pushUnbreakableBlock(labels)) return false; for (ParseNode* stmt = ListHead(stmtList); stmt; stmt = NextNode(stmt)) { @@ -6604,7 +6540,8 @@ CheckStatementList(FunctionValidator& f, ParseNode* stmtList, const NameVector* return false; } - f.popUnbreakableBlock(labels); + if (!f.popUnbreakableBlock(labels)) + return false; return true; } @@ -7520,8 +7457,7 @@ DynamicallyLinkModule(JSContext* cx, const CallArgs& args, HandleisExceptionPending()) return false; @@ -7630,7 +7566,7 @@ LinkAsmJS(JSContext* cx, unsigned argc, JS::Value* vp) if (!DynamicallyLinkModule(cx, args, moduleObj, &exportObj)) { // Linking failed, so reparse the entire asm.js module from scratch to // get normal interpreted bytecode which we can simply Invoke. Very slow. - RootedPropertyName name(cx, fun->name()); + RootedAtom name(cx, fun->name()); return HandleDynamicLinkFailure(cx, args, *module, name); } @@ -7641,7 +7577,7 @@ LinkAsmJS(JSContext* cx, unsigned argc, JS::Value* vp) static JSFunction* NewModuleFunction(ExclusiveContext* cx, JSFunction* origFun, HandleObject moduleObj) { - RootedPropertyName name(cx, origFun->name()); + RootedAtom name(cx, origFun->name()); JSFunction::Flags flags = origFun->isLambda() ? JSFunction::ASMJS_LAMBDA_CTOR : JSFunction::ASMJS_CTOR; @@ -8431,7 +8367,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda if (!out.append("function ")) return nullptr; - if (fun->atom() && !out.append(fun->atom())) + if (fun->name() && !out.append(fun->name())) return nullptr; bool haveSource = source->hasSourceData(); @@ -8505,8 +8441,8 @@ js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun) if (!haveSource) { // asm.js functions can't be anonymous - MOZ_ASSERT(fun->atom()); - if (!out.append(fun->atom())) + MOZ_ASSERT(fun->name()); + if (!out.append(fun->name())) return nullptr; if (!out.append("() {\n [sourceless code]\n}")) return nullptr; diff --git a/js/src/asmjs/Wasm.cpp b/js/src/asmjs/Wasm.cpp index 67ffb091fd..ce1807fd57 100644 --- a/js/src/asmjs/Wasm.cpp +++ b/js/src/asmjs/Wasm.cpp @@ -22,6 +22,7 @@ #include "jsprf.h" +#include "asmjs/WasmBinaryIterator.h" #include "asmjs/WasmGenerator.h" #include "vm/ArrayBufferObject.h" #include "vm/Debugger.h" @@ -61,105 +62,64 @@ Fail(JSContext* cx, Decoder& d, const char* str) return false; } -/*****************************************************************************/ -// wasm validation type lattice - -// ExprType::Limit is an out-of-band value and has no wasm-semantic meaning. For -// the purpose of recursive validation, we use this value to represent the type -// of branch/return instructions that don't actually return to the parent -// expression and can thus be used in any context. -static const ExprType AnyType = ExprType::Limit; - -static ExprType -Unify(ExprType one, ExprType two) -{ - if (one == AnyType) - return two; - if (two == AnyType) - return one; - if (one == two) - return one; - return ExprType::Void; -} - static bool IsI64Implemented() { #ifdef JS_CPU_X64 - return true; + return true; #else - return false; + return false; #endif } -class FunctionDecoder +namespace { + +class ValidatingPolicy : public ExprIterPolicy { JSContext* cx_; - Decoder& d_; - ModuleGenerator& mg_; - FunctionGenerator& fg_; - uint32_t funcIndex_; - const ValTypeVector& locals_; - Vector blocks_; public: - FunctionDecoder(JSContext* cx, Decoder& d, ModuleGenerator& mg, FunctionGenerator& fg, - uint32_t funcIndex, const ValTypeVector& locals) - : cx_(cx), d_(d), mg_(mg), fg_(fg), funcIndex_(funcIndex), locals_(locals), blocks_(cx) - {} - JSContext* cx() const { return cx_; } - Decoder& d() const { return d_; } - ModuleGenerator& mg() const { return mg_; } - FunctionGenerator& fg() const { return fg_; } - uint32_t funcIndex() const { return funcIndex_; } - const ValTypeVector& locals() const { return locals_; } - const DeclaredSig& sig() const { return mg_.funcSig(funcIndex_); } + // Validation is what we're all about here. + static const bool Validate = true; - bool fail(const char* str) { - return Fail(cx_, d_, str); + // Fail by printing a message, using the contains JSContext. + bool fail(const char* str, Decoder& d) { + return Fail(cx_, d, str); } + + explicit ValidatingPolicy(JSContext* cx) : cx_(cx) {} +}; + +typedef ExprIter ValidatingExprIter; + +class FunctionDecoder +{ + const ModuleGenerator& mg_; + ValidatingExprIter iter_; + const ValTypeVector& locals_; + const DeclaredSig& sig_; + + public: + FunctionDecoder(JSContext* cx, const ModuleGenerator& mg, Decoder& d, + uint32_t funcIndex, const ValTypeVector& locals) + : mg_(mg), + iter_(ValidatingPolicy(cx), d), + locals_(locals), + sig_(mg.funcSig(funcIndex)) + {} + const ModuleGenerator& mg() const { return mg_; } + ValidatingExprIter& iter() { return iter_; } + const ValTypeVector& locals() const { return locals_; } + const DeclaredSig& sig() const { return sig_; } + bool checkI64Support() { if (!IsI64Implemented()) - return fail("i64 NYI on this platform"); - return true; - } - - MOZ_WARN_UNUSED_RESULT bool pushBlock() { - return blocks_.append(AnyType); - } - ExprType popBlock() { - return blocks_.popCopy(); - } - MOZ_WARN_UNUSED_RESULT bool branchWithType(uint32_t depth, ExprType type) { - if (depth >= blocks_.length()) - return false; - uint32_t absolute = blocks_.length() - 1 - depth; - blocks_[absolute] = Unify(blocks_[absolute], type); + return iter().notYetImplemented("i64 NYI on this platform"); return true; } }; -static bool -CheckType(FunctionDecoder& f, ExprType actual, ValType expected) -{ - if (actual == AnyType || actual == ToExprType(expected)) - return true; - - UniqueChars error(JS_smprintf("type mismatch: expression has type %s but expected %s", - ToCString(actual), ToCString(expected))); - if (!error) - return false; - - return f.fail(error.get()); -} - -static bool -CheckType(FunctionDecoder& f, ExprType actual, ExprType expected) -{ - MOZ_ASSERT(expected != AnyType); - return expected == ExprType::Void || - CheckType(f, actual, NonVoidToValType(expected)); -} +} // end anonymous namespace static bool CheckValType(JSContext* cx, Decoder& d, ValType type) @@ -184,537 +144,169 @@ CheckValType(JSContext* cx, Decoder& d, ValType type) } static bool -CheckExprType(JSContext* cx, Decoder& d, ExprType type) +DecodeCallArgs(FunctionDecoder& f, uint32_t arity, const Sig& sig) { - return type == ExprType::Void || - CheckValType(cx, d, NonVoidToValType(type)); -} + if (arity != sig.args().length()) + return f.iter().fail("call arity out of range"); -static bool -DecodeExpr(FunctionDecoder& f, ExprType* type); - -static bool -DecodeNop(FunctionDecoder& f, ExprType* type) -{ - *type = ExprType::Void; - return true; -} - -static bool -DecodeUnreachable(FunctionDecoder& f, ExprType* type) -{ - *type = AnyType; - return true; -} - -static bool -DecodeCallWithSig(FunctionDecoder& f, const Sig& sig, ExprType* type) -{ - for (ValType argType : sig.args()) { - ExprType exprType; - if (!DecodeExpr(f, &exprType)) - return false; - - if (!CheckType(f, exprType, argType)) + const ValTypeVector& args = sig.args(); + uint32_t numArgs = args.length(); + for (size_t i = 0; i < numArgs; ++i) { + ValType argType = args[i]; + if (!f.iter().readCallArg(argType, numArgs, i, nullptr)) return false; } - *type = sig.ret(); - return true; + return f.iter().readCallArgsEnd(numArgs); } static bool -DecodeCall(FunctionDecoder& f, ExprType* type) +DecodeCallReturn(FunctionDecoder& f, const Sig& sig) { - uint32_t funcIndex; - if (!f.d().readVarU32(&funcIndex)) - return f.fail("unable to read import index"); - - if (funcIndex >= f.mg().numFuncSigs()) - return f.fail("callee index out of range"); - - return DecodeCallWithSig(f, f.mg().funcSig(funcIndex), type); + return f.iter().readCallReturn(sig.ret()); } static bool -DecodeCallImport(FunctionDecoder& f, ExprType* type) +DecodeCall(FunctionDecoder& f) { - uint32_t importIndex; - if (!f.d().readVarU32(&importIndex)) - return f.fail("unable to read import index"); + uint32_t calleeIndex; + uint32_t arity; + if (!f.iter().readCall(&calleeIndex, &arity)) + return false; - if (importIndex >= f.mg().numImports()) - return f.fail("import index out of range"); + if (calleeIndex >= f.mg().numFuncSigs()) + return f.iter().fail("callee index out of range"); - return DecodeCallWithSig(f, *f.mg().import(importIndex).sig, type); + const Sig& sig = f.mg().funcSig(calleeIndex); + return DecodeCallArgs(f, arity, sig) && + DecodeCallReturn(f, sig); } static bool -DecodeCallIndirect(FunctionDecoder& f, ExprType* type) +DecodeCallIndirect(FunctionDecoder& f) { uint32_t sigIndex; - if (!f.d().readVarU32(&sigIndex)) - return f.fail("unable to read indirect call signature index"); + uint32_t arity; + if (!f.iter().readCallIndirect(&sigIndex, &arity)) + return false; if (sigIndex >= f.mg().numSigs()) - return f.fail("signature index out of range"); + return f.iter().fail("signature index out of range"); - ExprType indexType; - if (!DecodeExpr(f, &indexType)) + const Sig& sig = f.mg().sig(sigIndex); + if (!DecodeCallArgs(f, arity, sig)) return false; - if (!CheckType(f, indexType, ValType::I32)) + if (!f.iter().readCallIndirectCallee(nullptr)) return false; - return DecodeCallWithSig(f, f.mg().sig(sigIndex), type); + return DecodeCallReturn(f, sig); } static bool -DecodeConstI32(FunctionDecoder& f, ExprType* type) +DecodeCallImport(FunctionDecoder& f) { - int32_t _; - if (!f.d().readVarS32(&_)) - return f.fail("unable to read i32.const immediate"); + uint32_t importIndex; + uint32_t arity; + if (!f.iter().readCallImport(&importIndex, &arity)) + return false; - *type = ExprType::I32; - return true; + if (importIndex >= f.mg().numImports()) + return f.iter().fail("import index out of range"); + + const Sig& sig = *f.mg().import(importIndex).sig; + return DecodeCallArgs(f, arity, sig) && + DecodeCallReturn(f, sig); } static bool -DecodeConstI64(FunctionDecoder& f, ExprType* type) -{ - int64_t _; - if (!f.d().readVarS64(&_)) - return f.fail("unable to read i64.const immediate"); - - *type = ExprType::I64; - return true; -} - -static bool -DecodeConstF32(FunctionDecoder& f, ExprType* type) -{ - float value; - if (!f.d().readFixedF32(&value)) - return f.fail("unable to read f32.const immediate"); - - if (IsNaN(value)) { - const float jsNaN = (float)JS::GenericNaN(); - if (memcmp(&value, &jsNaN, sizeof(value)) != 0) - return f.fail("NYI: NaN literals with custom payloads"); - } - - *type = ExprType::F32; - return true; -} - -static bool -DecodeConstF64(FunctionDecoder& f, ExprType* type) -{ - double value; - if (!f.d().readFixedF64(&value)) - return f.fail("unable to read f64.const immediate"); - - if (IsNaN(value)) { - const double jsNaN = JS::GenericNaN(); - if (memcmp(&value, &jsNaN, sizeof(value)) != 0) - return f.fail("NYI: NaN literals with custom payloads"); - } - - *type = ExprType::F64; - return true; -} - -static bool -DecodeGetLocal(FunctionDecoder& f, ExprType* type) -{ - uint32_t localIndex; - if (!f.d().readVarU32(&localIndex)) - return f.fail("unable to read get_local index"); - - if (localIndex >= f.locals().length()) - return f.fail("get_local index out of range"); - - *type = ToExprType(f.locals()[localIndex]); - return true; -} - -static bool -DecodeSetLocal(FunctionDecoder& f, ExprType* type) -{ - uint32_t localIndex; - if (!f.d().readVarU32(&localIndex)) - return f.fail("unable to read set_local index"); - - if (localIndex >= f.locals().length()) - return f.fail("set_local index out of range"); - - *type = ToExprType(f.locals()[localIndex]); - - ExprType rhsType; - if (!DecodeExpr(f, &rhsType)) - return false; - - return CheckType(f, rhsType, *type); -} - -static bool -DecodeBlock(FunctionDecoder& f, bool isLoop, ExprType* type) -{ - if (!f.pushBlock()) - return f.fail("nesting overflow"); - - if (isLoop) { - if (!f.pushBlock()) - return f.fail("nesting overflow"); - } - - uint32_t numExprs; - if (!f.d().readVarU32(&numExprs)) - return f.fail("unable to read block's number of expressions"); - - ExprType exprType = ExprType::Void; - - for (uint32_t i = 0; i < numExprs; i++) { - if (!DecodeExpr(f, &exprType)) - return false; - } - - if (isLoop) - f.popBlock(); - - ExprType branchType = f.popBlock(); - *type = Unify(branchType, exprType); - return true; -} - -static bool -DecodeUnaryOperator(FunctionDecoder& f, ValType argType, ExprType *type) -{ - ExprType actual; - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, argType)) - return false; - - *type = ToExprType(argType); - return true; -} - -static bool -DecodeBinaryOperator(FunctionDecoder& f, ValType argType, ExprType* type) -{ - ExprType actual; - - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, argType)) - return false; - - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, argType)) - return false; - - *type = ToExprType(argType); - return true; -} - -static bool -DecodeComparisonOperator(FunctionDecoder& f, ValType argType, ExprType* type) -{ - ExprType actual; - - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, argType)) - return false; - - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, argType)) - return false; - - *type = ExprType::I32; - return true; -} - -static bool -DecodeConversionOperator(FunctionDecoder& f, ValType to, ValType argType, ExprType* type) -{ - ExprType actual; - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, argType)) - return false; - - *type = ToExprType(to); - return true; -} - -static bool -DecodeSelect(FunctionDecoder& f, ExprType* type) -{ - ExprType trueType; - if (!DecodeExpr(f, &trueType)) - return false; - - if (trueType == ExprType::I64 && !f.checkI64Support()) - return false; - - ExprType falseType; - if (!DecodeExpr(f, &falseType)) - return false; - - ExprType condType; - if (!DecodeExpr(f, &condType)) - return false; - - if (!CheckType(f, condType, ValType::I32)) - return false; - - *type = Unify(trueType, falseType); - return true; -} - -static bool -DecodeIfElse(FunctionDecoder& f, bool hasElse, ExprType* type) -{ - ExprType condType; - if (!DecodeExpr(f, &condType)) - return false; - - if (!CheckType(f, condType, ValType::I32)) - return false; - - ExprType thenType; - if (!DecodeExpr(f, &thenType)) - return false; - - if (hasElse) { - ExprType elseType; - if (!DecodeExpr(f, &elseType)) - return false; - - *type = Unify(thenType, elseType); - } else { - *type = ExprType::Void; - } - - return true; -} - -static bool -DecodeLoadStoreAddress(FunctionDecoder &f, unsigned width) -{ - uint32_t flags; - if (!f.d().readVarU32(&flags)) - return f.fail("expected memory access flags"); - - uint32_t alignLog2 = flags; - if (alignLog2 >= 32 || (1u << alignLog2) > width) - return f.fail("greater than natural alignment"); - - uint32_t offset; - if (!f.d().readVarU32(&offset)) - return f.fail("expected memory access offset"); - - ExprType baseType; - if (!DecodeExpr(f, &baseType)) - return false; - - return CheckType(f, baseType, ExprType::I32); -} - -static bool -DecodeLoad(FunctionDecoder& f, unsigned width, ValType loadType, ExprType* type) -{ - if (!DecodeLoadStoreAddress(f, width)) - return false; - - *type = ToExprType(loadType); - return true; -} - -static bool -DecodeStore(FunctionDecoder& f, unsigned width, ValType storeType, ExprType* type) -{ - if (!DecodeLoadStoreAddress(f, width)) - return false; - - ExprType actual; - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, storeType)) - return false; - - *type = ToExprType(storeType); - return true; -} - -static bool -DecodeBranch(FunctionDecoder& f, Expr expr, ExprType* type) -{ - MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf); - - uint32_t relativeDepth; - if (!f.d().readVarU32(&relativeDepth)) - return f.fail("expected relative depth"); - - ExprType brType; - if (!DecodeExpr(f, &brType)) - return f.fail("expected branch value"); - - if (!f.branchWithType(relativeDepth, brType)) - return f.fail("branch depth exceeds current nesting level"); - - if (expr == Expr::BrIf) { - ExprType actual; - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, ValType::I32)) - return false; - - *type = ExprType::Void; - } else { - *type = AnyType; - } - - return true; -} - -static bool -DecodeBrTable(FunctionDecoder& f, ExprType* type) +DecodeBrTable(FunctionDecoder& f) { uint32_t tableLength; - if (!f.d().readVarU32(&tableLength)) + ExprType type; + if (!f.iter().readBrTable(&tableLength, &type, nullptr, nullptr)) return false; - if (tableLength > MaxBrTableElems) - return f.fail("too many br_table entries"); - - for (uint32_t i = 0; i < tableLength; i++) { - uint32_t depth; - if (!f.d().readFixedU32(&depth)) - return f.fail("missing br_table entry"); - - if (!f.branchWithType(depth, ExprType::Void)) - return f.fail("branch depth exceeds current nesting level"); - } - - uint32_t defaultDepth; - if (!f.d().readFixedU32(&defaultDepth)) - return f.fail("expected default relative depth"); - - if (!f.branchWithType(defaultDepth, ExprType::Void)) - return f.fail("branch depth exceeds current nesting level"); - - ExprType actual; - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, ExprType::I32)) - return false; - - *type = AnyType; - return true; -} - -static bool -DecodeReturn(FunctionDecoder& f, ExprType* type) -{ - if (f.sig().ret() != ExprType::Void) { - ExprType actual; - if (!DecodeExpr(f, &actual)) - return false; - - if (!CheckType(f, actual, f.sig().ret())) + uint32_t depth; + for (size_t i = 0, e = tableLength; i < e; ++i) { + if (!f.iter().readBrTableEntry(type, &depth)) return false; } - *type = AnyType; - return true; + // Read the default label. + return f.iter().readBrTableEntry(type, &depth); } static bool -DecodeExpr(FunctionDecoder& f, ExprType* type) +DecodeExpr(FunctionDecoder& f) { - JS_CHECK_RECURSION(f.cx(), return false); - Expr expr; - if (!f.d().readExpr(&expr)) - return f.fail("unable to read expression"); + if (!f.iter().readExpr(&expr)) + return false; switch (expr) { case Expr::Nop: - return DecodeNop(f, type); + return f.iter().readNullary(); case Expr::Call: - return DecodeCall(f, type); - case Expr::CallImport: - return DecodeCallImport(f, type); + return DecodeCall(f); case Expr::CallIndirect: - return DecodeCallIndirect(f, type); + return DecodeCallIndirect(f); + case Expr::CallImport: + return DecodeCallImport(f); case Expr::I32Const: - return DecodeConstI32(f, type); + return f.iter().readI32Const(nullptr); case Expr::I64Const: - return f.checkI64Support() && DecodeConstI64(f, type); + return f.checkI64Support() && + f.iter().readI64Const(nullptr); case Expr::F32Const: - return DecodeConstF32(f, type); + return f.iter().readF32Const(nullptr); case Expr::F64Const: - return DecodeConstF64(f, type); + return f.iter().readF64Const(nullptr); case Expr::GetLocal: - return DecodeGetLocal(f, type); + return f.iter().readGetLocal(f.locals(), nullptr); case Expr::SetLocal: - return DecodeSetLocal(f, type); + return f.iter().readSetLocal(f.locals(), nullptr, nullptr); case Expr::Select: - return DecodeSelect(f, type); + return f.iter().readSelect(nullptr, nullptr, nullptr, nullptr); case Expr::Block: - return DecodeBlock(f, /* isLoop */ false, type); + return f.iter().readBlock(); case Expr::Loop: - return DecodeBlock(f, /* isLoop */ true, type); + return f.iter().readLoop(); case Expr::If: - return DecodeIfElse(f, /* hasElse */ false, type); - case Expr::IfElse: - return DecodeIfElse(f, /* hasElse */ true, type); + return f.iter().readIf(nullptr); + case Expr::Else: + return f.iter().readElse(nullptr, nullptr); + case Expr::End: + return f.iter().readEnd(nullptr, nullptr, nullptr); case Expr::I32Clz: case Expr::I32Ctz: case Expr::I32Popcnt: - case Expr::I32Eqz: - return DecodeUnaryOperator(f, ValType::I32, type); + return f.iter().readUnary(ValType::I32, nullptr); case Expr::I64Clz: case Expr::I64Ctz: case Expr::I64Popcnt: - case Expr::I64Eqz: - return f.fail("NYI: i64") && - DecodeUnaryOperator(f, ValType::I64, type); + return f.iter().notYetImplemented("i64") && + f.iter().readUnary(ValType::I64, nullptr); case Expr::F32Abs: case Expr::F32Neg: case Expr::F32Ceil: case Expr::F32Floor: case Expr::F32Sqrt: - return DecodeUnaryOperator(f, ValType::F32, type); + return f.iter().readUnary(ValType::F32, nullptr); case Expr::F32Trunc: - return f.fail("NYI: trunc"); + return f.iter().notYetImplemented("trunc"); case Expr::F32Nearest: - return f.fail("NYI: nearest"); + return f.iter().notYetImplemented("nearest"); case Expr::F64Abs: case Expr::F64Neg: case Expr::F64Ceil: case Expr::F64Floor: case Expr::F64Sqrt: - return DecodeUnaryOperator(f, ValType::F64, type); + return f.iter().readUnary(ValType::F64, nullptr); case Expr::F64Trunc: - return f.fail("NYI: trunc"); + return f.iter().notYetImplemented("trunc"); case Expr::F64Nearest: - return f.fail("NYI: nearest"); + return f.iter().notYetImplemented("nearest"); case Expr::I32Add: case Expr::I32Sub: case Expr::I32Mul: @@ -728,10 +320,9 @@ DecodeExpr(FunctionDecoder& f, ExprType* type) case Expr::I32Shl: case Expr::I32ShrS: case Expr::I32ShrU: - return DecodeBinaryOperator(f, ValType::I32, type); case Expr::I32Rotl: case Expr::I32Rotr: - return f.fail("NYI: rotate"); + return f.iter().readBinary(ValType::I32, nullptr, nullptr); case Expr::I64Add: case Expr::I64Sub: case Expr::I64Mul: @@ -745,28 +336,28 @@ DecodeExpr(FunctionDecoder& f, ExprType* type) case Expr::I64Shl: case Expr::I64ShrS: case Expr::I64ShrU: - return f.checkI64Support() && DecodeBinaryOperator(f, ValType::I64, type); case Expr::I64Rotl: case Expr::I64Rotr: - return f.fail("NYI: rotate"); + return f.checkI64Support() && + f.iter().readBinary(ValType::I64, nullptr, nullptr); case Expr::F32Add: case Expr::F32Sub: case Expr::F32Mul: case Expr::F32Div: case Expr::F32Min: case Expr::F32Max: - return DecodeBinaryOperator(f, ValType::F32, type); + return f.iter().readBinary(ValType::F32, nullptr, nullptr); case Expr::F32CopySign: - return f.fail("NYI: copysign"); + return f.iter().notYetImplemented("copysign"); case Expr::F64Add: case Expr::F64Sub: case Expr::F64Mul: case Expr::F64Div: case Expr::F64Min: case Expr::F64Max: - return DecodeBinaryOperator(f, ValType::F64, type); + return f.iter().readBinary(ValType::F64, nullptr, nullptr); case Expr::F64CopySign: - return f.fail("NYI: copysign"); + return f.iter().notYetImplemented("copysign"); case Expr::I32Eq: case Expr::I32Ne: case Expr::I32LtS: @@ -777,7 +368,7 @@ DecodeExpr(FunctionDecoder& f, ExprType* type) case Expr::I32GtU: case Expr::I32GeS: case Expr::I32GeU: - return DecodeComparisonOperator(f, ValType::I32, type); + return f.iter().readComparison(ValType::I32, nullptr, nullptr); case Expr::I64Eq: case Expr::I64Ne: case Expr::I64LtS: @@ -788,130 +379,144 @@ DecodeExpr(FunctionDecoder& f, ExprType* type) case Expr::I64GtU: case Expr::I64GeS: case Expr::I64GeU: - return f.checkI64Support() && DecodeComparisonOperator(f, ValType::I64, type); + return f.checkI64Support() && + f.iter().readComparison(ValType::I64, nullptr, nullptr); case Expr::F32Eq: case Expr::F32Ne: case Expr::F32Lt: case Expr::F32Le: case Expr::F32Gt: case Expr::F32Ge: - return DecodeComparisonOperator(f, ValType::F32, type); + return f.iter().readComparison(ValType::F32, nullptr, nullptr); case Expr::F64Eq: case Expr::F64Ne: case Expr::F64Lt: case Expr::F64Le: case Expr::F64Gt: case Expr::F64Ge: - return DecodeComparisonOperator(f, ValType::F64, type); + return f.iter().readComparison(ValType::F64, nullptr, nullptr); + case Expr::I32Eqz: + return f.iter().readConversion(ValType::I32, ValType::I32, nullptr); + case Expr::I64Eqz: + return f.checkI64Support() && + f.iter().readConversion(ValType::I64, ValType::I32, nullptr); case Expr::I32WrapI64: return f.checkI64Support() && - DecodeConversionOperator(f, ValType::I32, ValType::I64, type); + f.iter().readConversion(ValType::I64, ValType::I32, nullptr); case Expr::I32TruncSF32: case Expr::I32TruncUF32: case Expr::I32ReinterpretF32: - return DecodeConversionOperator(f, ValType::I32, ValType::F32, type); + return f.iter().readConversion(ValType::F32, ValType::I32, nullptr); case Expr::I32TruncSF64: case Expr::I32TruncUF64: - return DecodeConversionOperator(f, ValType::I32, ValType::F64, type); + return f.iter().readConversion(ValType::F64, ValType::I32, nullptr); case Expr::I64ExtendSI32: case Expr::I64ExtendUI32: return f.checkI64Support() && - DecodeConversionOperator(f, ValType::I64, ValType::I32, type); + f.iter().readConversion(ValType::I32, ValType::I64, nullptr); case Expr::I64TruncSF32: case Expr::I64TruncUF32: return f.checkI64Support() && - DecodeConversionOperator(f, ValType::I64, ValType::F32, type); + f.iter().readConversion(ValType::F32, ValType::I64, nullptr); case Expr::I64TruncSF64: case Expr::I64TruncUF64: case Expr::I64ReinterpretF64: return f.checkI64Support() && - DecodeConversionOperator(f, ValType::I64, ValType::F64, type); + f.iter().readConversion(ValType::F64, ValType::I64, nullptr); case Expr::F32ConvertSI32: case Expr::F32ConvertUI32: case Expr::F32ReinterpretI32: - return DecodeConversionOperator(f, ValType::F32, ValType::I32, type); + return f.iter().readConversion(ValType::I32, ValType::F32, nullptr); case Expr::F32ConvertSI64: case Expr::F32ConvertUI64: return f.checkI64Support() && - DecodeConversionOperator(f, ValType::F32, ValType::I64, type); + f.iter().readConversion(ValType::I64, ValType::F32, nullptr); case Expr::F32DemoteF64: - return DecodeConversionOperator(f, ValType::F32, ValType::F64, type); + return f.iter().readConversion(ValType::F64, ValType::F32, nullptr); case Expr::F64ConvertSI32: case Expr::F64ConvertUI32: - return DecodeConversionOperator(f, ValType::F64, ValType::I32, type); + return f.iter().readConversion(ValType::I32, ValType::F64, nullptr); case Expr::F64ConvertSI64: case Expr::F64ConvertUI64: case Expr::F64ReinterpretI64: return f.checkI64Support() && - DecodeConversionOperator(f, ValType::F64, ValType::I64, type); + f.iter().readConversion(ValType::I64, ValType::F64, nullptr); case Expr::F64PromoteF32: - return DecodeConversionOperator(f, ValType::F64, ValType::F32, type); + return f.iter().readConversion(ValType::F32, ValType::F64, nullptr); case Expr::I32Load8S: case Expr::I32Load8U: - return DecodeLoad(f, 1, ValType::I32, type); + return f.iter().readLoad(ValType::I32, 1, nullptr); case Expr::I32Load16S: case Expr::I32Load16U: - return DecodeLoad(f, 2, ValType::I32, type); + return f.iter().readLoad(ValType::I32, 2, nullptr); case Expr::I32Load: - return DecodeLoad(f, 4, ValType::I32, type); - case Expr::I64Load: + return f.iter().readLoad(ValType::I32, 4, nullptr); case Expr::I64Load8S: case Expr::I64Load8U: + return f.iter().notYetImplemented("i64") && + f.iter().readLoad(ValType::I64, 1, nullptr); case Expr::I64Load16S: case Expr::I64Load16U: + return f.iter().notYetImplemented("i64") && + f.iter().readLoad(ValType::I64, 2, nullptr); case Expr::I64Load32S: case Expr::I64Load32U: - return f.fail("NYI: i64") && - DecodeLoad(f, 0, ValType::I64, type); + return f.iter().notYetImplemented("i64") && + f.iter().readLoad(ValType::I64, 4, nullptr); + case Expr::I64Load: + return f.iter().notYetImplemented("i64"); case Expr::F32Load: - return DecodeLoad(f, 4, ValType::F32, type); + return f.iter().readLoad(ValType::F32, 4, nullptr); case Expr::F64Load: - return DecodeLoad(f, 8, ValType::F64, type); + return f.iter().readLoad(ValType::F64, 8, nullptr); case Expr::I32Store8: - return DecodeStore(f, 1, ValType::I32, type); + return f.iter().readStore(ValType::I32, 1, nullptr, nullptr); case Expr::I32Store16: - return DecodeStore(f, 2, ValType::I32, type); + return f.iter().readStore(ValType::I32, 2, nullptr, nullptr); case Expr::I32Store: - return DecodeStore(f, 4, ValType::I32, type); - case Expr::I64Store: + return f.iter().readStore(ValType::I32, 4, nullptr, nullptr); case Expr::I64Store8: + return f.iter().notYetImplemented("i64") && + f.iter().readStore(ValType::I64, 1, nullptr, nullptr); case Expr::I64Store16: + return f.iter().notYetImplemented("i64") && + f.iter().readStore(ValType::I64, 2, nullptr, nullptr); case Expr::I64Store32: - return f.fail("NYI: i64") && - DecodeStore(f, 0, ValType::I64, type); + return f.iter().notYetImplemented("i64") && + f.iter().readStore(ValType::I64, 4, nullptr, nullptr); + case Expr::I64Store: + return f.iter().notYetImplemented("i64"); case Expr::F32Store: - return DecodeStore(f, 4, ValType::F32, type); + return f.iter().readStore(ValType::F32, 4, nullptr, nullptr); case Expr::F64Store: - return DecodeStore(f, 8, ValType::F64, type); + return f.iter().readStore(ValType::F64, 8, nullptr, nullptr); case Expr::Br: - return DecodeBranch(f, expr, type); + return f.iter().readBr(nullptr, nullptr, nullptr); case Expr::BrIf: - return DecodeBranch(f, expr, type); + return f.iter().readBrIf(nullptr, nullptr, nullptr, nullptr); case Expr::BrTable: - return DecodeBrTable(f, type); + return DecodeBrTable(f); case Expr::Return: - return DecodeReturn(f, type); + return f.iter().readReturn(nullptr); case Expr::Unreachable: - return DecodeUnreachable(f, type); + return f.iter().readUnreachable(); default: // Note: it's important not to remove this default since readExpr() // can return Expr values for which there is no enumerator. break; } - return f.fail("bad expression code"); + return f.iter().unrecognizedOpcode(expr); } /*****************************************************************************/ // wasm decoding and generation -typedef HashSet SigSet; - static bool -DecodeSignatures(JSContext* cx, Decoder& d, ModuleGeneratorData* init) +DecodeTypeSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init) { - uint32_t sectionStart; - if (!d.startSection(SignaturesId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!d.startSection(TypeSectionId, §ionStart, §ionSize)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -928,25 +533,18 @@ DecodeSignatures(JSContext* cx, Decoder& d, ModuleGeneratorData* init) if (!init->sigToTable.resize(numSigs)) return false; - SigSet dupSet(cx); - if (!dupSet.init()) - return false; - for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) { + uint32_t form; + if (!d.readVarU32(&form) || form != uint32_t(TypeConstructor::Function)) + return Fail(cx, d, "expected function form"); + uint32_t numArgs; if (!d.readVarU32(&numArgs)) - return Fail(cx, d, "bad number of signature args"); + return Fail(cx, d, "bad number of function args"); if (numArgs > MaxArgsPerFunc) return Fail(cx, d, "too many arguments in signature"); - ExprType result; - if (!d.readExprType(&result)) - return Fail(cx, d, "bad expression type"); - - if (!CheckExprType(cx, d, result)) - return false; - ValTypeVector args; if (!args.resize(numArgs)) return false; @@ -959,17 +557,30 @@ DecodeSignatures(JSContext* cx, Decoder& d, ModuleGeneratorData* init) return false; } + uint32_t numRets; + if (!d.readVarU32(&numRets)) + return Fail(cx, d, "bad number of function returns"); + + if (numRets > 1) + return Fail(cx, d, "too many returns in signature"); + + ExprType result = ExprType::Void; + + if (numRets == 1) { + ValType type; + if (!d.readValType(&type)) + return Fail(cx, d, "bad expression type"); + + if (!CheckValType(cx, d, type)) + return false; + + result = ToExprType(type); + } + init->sigs[sigIndex] = Sig(Move(args), result); - - SigSet::AddPtr p = dupSet.lookupForAdd(init->sigs[sigIndex]); - if (p) - return Fail(cx, d, "duplicate signature"); - - if (!dupSet.add(p, &init->sigs[sigIndex])) - return false; } - if (!d.finishSection(sectionStart)) + if (!d.finishSection(sectionStart, sectionSize)) return Fail(cx, d, "decls section byte size mismatch"); return true; @@ -991,10 +602,10 @@ DecodeSignatureIndex(JSContext* cx, Decoder& d, const ModuleGeneratorData& init, } static bool -DecodeFunctionSignatures(JSContext* cx, Decoder& d, ModuleGeneratorData* init) +DecodeFunctionSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init) { - uint32_t sectionStart; - if (!d.startSection(FunctionSignaturesId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!d.startSection(FunctionSectionId, §ionStart, §ionSize)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1014,17 +625,17 @@ DecodeFunctionSignatures(JSContext* cx, Decoder& d, ModuleGeneratorData* init) return false; } - if (!d.finishSection(sectionStart)) + if (!d.finishSection(sectionStart, sectionSize)) return Fail(cx, d, "decls section byte size mismatch"); return true; } static bool -DecodeFunctionTable(JSContext* cx, Decoder& d, ModuleGeneratorData* init) +DecodeTableSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init) { - uint32_t sectionStart; - if (!d.startSection(FunctionTableId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!d.startSection(TableSectionId, §ionStart, §ionSize)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1050,7 +661,7 @@ DecodeFunctionTable(JSContext* cx, Decoder& d, ModuleGeneratorData* init) elems[i] = funcIndex; } - if (!d.finishSection(sectionStart)) + if (!d.finishSection(sectionStart, sectionSize)) return Fail(cx, d, "table section byte size mismatch"); // Convert the single (heterogeneous) indirect function table into an @@ -1142,10 +753,10 @@ DecodeImport(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVec } static bool -DecodeImportTable(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames) +DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames) { - uint32_t sectionStart; - if (!d.startSection(ImportTableId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!d.startSection(ImportSectionId, §ionStart, §ionSize)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1162,17 +773,17 @@ DecodeImportTable(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNa return false; } - if (!d.finishSection(sectionStart)) + if (!d.finishSection(sectionStart, sectionSize)) return Fail(cx, d, "import section byte size mismatch"); return true; } static bool -DecodeMemory(JSContext* cx, Decoder& d, ModuleGenerator& mg, MutableHandle heap) +DecodeMemorySection(JSContext* cx, Decoder& d, ModuleGenerator& mg, MutableHandle heap) { - uint32_t sectionStart; - if (!d.startSection(MemoryId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!d.startSection(MemorySectionId, §ionStart, §ionSize)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1205,7 +816,7 @@ DecodeMemory(JSContext* cx, Decoder& d, ModuleGenerator& mg, MutableHandle heap) +DecodeDataSection(JSContext* cx, Decoder& d, Handle heap) { - uint32_t sectionStart; - if (!d.startSection(DataSegmentsId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!d.startSection(DataSectionId, §ionStart, §ionSize)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1438,7 +1050,7 @@ DecodeDataSegments(JSContext* cx, Decoder& d, Handle heap) prevEnd = dstOffset + numBytes; } - if (!d.finishSection(sectionStart)) + if (!d.finishSection(sectionStart, sectionSize)) return Fail(cx, d, "data section byte size mismatch"); return true; @@ -1462,32 +1074,32 @@ DecodeModule(JSContext* cx, UniqueChars file, const uint8_t* bytes, uint32_t len if (!init) return false; - if (!DecodeSignatures(cx, d, init.get())) + if (!DecodeTypeSection(cx, d, init.get())) return false; - if (!DecodeImportTable(cx, d, init.get(), importNames)) + if (!DecodeImportSection(cx, d, init.get(), importNames)) return false; - if (!DecodeFunctionSignatures(cx, d, init.get())) + if (!DecodeFunctionSection(cx, d, init.get())) return false; - if (!DecodeFunctionTable(cx, d, init.get())) + if (!DecodeTableSection(cx, d, init.get())) return false; ModuleGenerator mg(cx); if (!mg.init(Move(init), Move(file))) return false; - if (!DecodeMemory(cx, d, mg, heap)) + if (!DecodeMemorySection(cx, d, mg, heap)) return false; - if (!DecodeExportTable(cx, d, mg)) + if (!DecodeExportSection(cx, d, mg)) return false; - if (!DecodeFunctionBodies(cx, d, mg)) + if (!DecodeCodeSection(cx, d, mg)) return false; - if (!DecodeDataSegments(cx, d, heap)) + if (!DecodeDataSection(cx, d, heap)) return false; CacheableCharsVector funcNames; @@ -1750,4 +1362,3 @@ js::InitWasmClass(JSContext* cx, HandleObject global) global->as().setConstructor(JSProto_Wasm, ObjectValue(*Wasm)); return Wasm; } - diff --git a/js/src/asmjs/WasmBinary.h b/js/src/asmjs/WasmBinary.h index b5a5416fdb..3d5bf90163 100644 --- a/js/src/asmjs/WasmBinary.h +++ b/js/src/asmjs/WasmBinary.h @@ -25,22 +25,19 @@ namespace js { namespace wasm { static const uint32_t MagicNumber = 0x6d736100; // "\0asm" -static const uint32_t EncodingVersion = 0xa; +static const uint32_t EncodingVersion = 0x0b; -static const char SignaturesId[] = "signatures"; -static const char ImportTableId[] = "import_table"; -static const char FunctionSignaturesId[] = "function_signatures"; -static const char FunctionTableId[] = "function_table"; -static const char MemoryId[] = "memory"; -static const char ExportTableId[] = "export_table"; -static const char FunctionBodiesId[] = "function_bodies"; -static const char DataSegmentsId[] = "data_segments"; +static const char TypeSectionId[] = "type"; +static const char ImportSectionId[] = "import"; +static const char FunctionSectionId[] = "function"; +static const char TableSectionId[] = "table"; +static const char MemorySectionId[] = "memory"; +static const char ExportSectionId[] = "export"; +static const char CodeSectionId[] = "code"; +static const char DataSectionId[] = "data"; enum class ValType { - // 0x00 is reserved for ExprType::Void in the binary encoding. See comment - // below about ExprType going away. - I32 = 0x01, I64 = 0x02, F32 = 0x03, @@ -57,6 +54,11 @@ enum class ValType Limit }; +enum class TypeConstructor +{ + Function = 0x40 +}; + enum class Expr { // Control flow operators @@ -64,24 +66,25 @@ enum class Expr Block = 0x01, Loop = 0x02, If = 0x03, - IfElse = 0x04, + Else = 0x04, Select = 0x05, Br = 0x06, BrIf = 0x07, BrTable = 0x08, - Return = 0x14, - Unreachable = 0x15, + Return = 0x09, + Unreachable = 0x0a, + End = 0x0f, // Basic operators - I32Const = 0x0a, - I64Const = 0x0b, - F64Const = 0x0c, - F32Const = 0x0d, - GetLocal = 0x0e, - SetLocal = 0x0f, - Call = 0x12, - CallIndirect = 0x13, - CallImport = 0x1f, + I32Const = 0x10, + I64Const = 0x11, + F64Const = 0x12, + F32Const = 0x13, + GetLocal = 0x14, + SetLocal = 0x15, + Call = 0x16, + CallIndirect = 0x17, + CallImport = 0x18, // Memory-related operators I32Load8S = 0x20, @@ -107,7 +110,7 @@ enum class Expr I64Store = 0x34, F32Store = 0x35, F64Store = 0x36, - MemorySize = 0x3b, + CurrentMemory = 0x3b, GrowMemory = 0x39, // i32 operators @@ -252,8 +255,7 @@ enum class Expr // compiling asm.js and are rejected by wasm validation. // asm.js-specific operators - Id = 0xc0, - LoadGlobal, + LoadGlobal = 0xc0, StoreGlobal, I32Min, I32Max, @@ -343,12 +345,12 @@ class Encoder Bytes& bytes_; template - MOZ_WARN_UNUSED_RESULT bool write(const T& v) { + MOZ_MUST_USE bool write(const T& v) { return bytes_.append(reinterpret_cast(&v), sizeof(T)); } template - MOZ_WARN_UNUSED_RESULT bool writeVarU(UInt i) { + MOZ_MUST_USE bool writeVarU(UInt i) { do { uint8_t byte = i & 0x7f; i >>= 7; @@ -361,7 +363,7 @@ class Encoder } template - MOZ_WARN_UNUSED_RESULT bool writeVarS(SInt i) { + MOZ_MUST_USE bool writeVarS(SInt i) { bool done; do { uint8_t byte = i & 0x7f; @@ -413,48 +415,44 @@ class Encoder // Fixed-size encoding operations simply copy the literal bytes (without // attempting to align). - MOZ_WARN_UNUSED_RESULT bool writeFixedU8(uint8_t i) { + MOZ_MUST_USE bool writeFixedU8(uint8_t i) { return write(i); } - MOZ_WARN_UNUSED_RESULT bool writeFixedU32(uint32_t i) { + MOZ_MUST_USE bool writeFixedU32(uint32_t i) { return write(i); } - MOZ_WARN_UNUSED_RESULT bool writeFixedF32(float f) { + MOZ_MUST_USE bool writeFixedF32(float f) { return write(f); } - MOZ_WARN_UNUSED_RESULT bool writeFixedF64(double d) { + MOZ_MUST_USE bool writeFixedF64(double d) { return write(d); } - MOZ_WARN_UNUSED_RESULT bool writeFixedI32x4(const I32x4& i32x4) { + MOZ_MUST_USE bool writeFixedI32x4(const I32x4& i32x4) { return write(i32x4); } - MOZ_WARN_UNUSED_RESULT bool writeFixedF32x4(const F32x4& f32x4) { + MOZ_MUST_USE bool writeFixedF32x4(const F32x4& f32x4) { return write(f32x4); } // Variable-length encodings that all use LEB128. - MOZ_WARN_UNUSED_RESULT bool writeVarU32(uint32_t i) { + MOZ_MUST_USE bool writeVarU32(uint32_t i) { return writeVarU(i); } - MOZ_WARN_UNUSED_RESULT bool writeVarS32(int32_t i) { + MOZ_MUST_USE bool writeVarS32(int32_t i) { return writeVarS(i); } - MOZ_WARN_UNUSED_RESULT bool writeVarU64(uint64_t i) { + MOZ_MUST_USE bool writeVarU64(uint64_t i) { return writeVarU(i); } - MOZ_WARN_UNUSED_RESULT bool writeVarS64(int64_t i) { + MOZ_MUST_USE bool writeVarS64(int64_t i) { return writeVarS(i); } - MOZ_WARN_UNUSED_RESULT bool writeValType(ValType type) { + MOZ_MUST_USE bool writeValType(ValType type) { static_assert(size_t(ValType::Limit) <= INT8_MAX, "fits"); return writeFixedU8(size_t(type)); } - MOZ_WARN_UNUSED_RESULT bool writeExprType(ExprType type) { - static_assert(size_t(ExprType::Limit) <= INT8_MAX, "fits"); - return writeFixedU8(uint8_t(type)); - } - MOZ_WARN_UNUSED_RESULT bool writeExpr(Expr expr) { + MOZ_MUST_USE bool writeExpr(Expr expr) { static_assert(size_t(Expr::Limit) <= ExprLimit, "fits"); if (size_t(expr) < UINT8_MAX) return writeFixedU8(uint8_t(expr)); @@ -464,16 +462,7 @@ class Encoder // Variable-length encodings that allow back-patching. - MOZ_WARN_UNUSED_RESULT bool writePatchableFixedU8(size_t* offset) { - *offset = bytes_.length(); - return bytes_.append(0xff); - } - void patchFixedU8(size_t offset, uint8_t i) { - MOZ_ASSERT(bytes_[offset] == 0xff); - bytes_[offset] = i; - } - - MOZ_WARN_UNUSED_RESULT bool writePatchableVarU32(size_t* offset) { + MOZ_MUST_USE bool writePatchableVarU32(size_t* offset) { *offset = bytes_.length(); return writeVarU32(UINT32_MAX); } @@ -481,20 +470,10 @@ class Encoder return patchVarU32(offset, patchBits, UINT32_MAX); } - MOZ_WARN_UNUSED_RESULT bool writePatchableOneByteExpr(size_t* offset) { - *offset = bytes_.length(); - return writeFixedU8(0xff); - } - void patchOneByteExpr(size_t offset, Expr expr) { - MOZ_ASSERT(size_t(expr) < UINT8_MAX); - MOZ_ASSERT(bytes_[offset] == 0xff); - bytes_[offset] = uint8_t(expr); - } - // Byte ranges start with an LEB128 length followed by an arbitrary sequence // of bytes. When used for strings, bytes are to be interpreted as utf8. - MOZ_WARN_UNUSED_RESULT bool writeBytes(const void* bytes, uint32_t numBytes) { + MOZ_MUST_USE bool writeBytes(const void* bytes, uint32_t numBytes) { return writeVarU32(numBytes) && bytes_.append(reinterpret_cast(bytes), numBytes); } @@ -506,12 +485,12 @@ class Encoder // after the section length is the string id of the section. template - MOZ_WARN_UNUSED_RESULT bool startSection(const char (&id)[IdSizeWith0], size_t* offset) { + MOZ_MUST_USE bool startSection(const char (&id)[IdSizeWith0], size_t* offset) { static const size_t IdSize = IdSizeWith0 - 1; MOZ_ASSERT(id[IdSize] == '\0'); - return writePatchableVarU32(offset) && - writeVarU32(IdSize) && - bytes_.append(reinterpret_cast(id), IdSize); + return writeVarU32(IdSize) && + bytes_.append(reinterpret_cast(id), IdSize) && + writePatchableVarU32(offset); } void finishSection(size_t offset) { return patchVarU32(offset, bytes_.length() - offset - varU32ByteLength(offset)); @@ -529,7 +508,7 @@ class Decoder const uint8_t* cur_; template - MOZ_WARN_UNUSED_RESULT bool read(T* out) { + MOZ_MUST_USE bool read(T* out) { if (bytesRemain() < sizeof(T)) return false; memcpy((void*)out, cur_, sizeof(T)); @@ -547,7 +526,7 @@ class Decoder } template - MOZ_WARN_UNUSED_RESULT bool readVarU(UInt* out) { + MOZ_MUST_USE bool readVarU(UInt* out) { const unsigned numBits = sizeof(UInt) * CHAR_BIT; const unsigned remainderBits = numBits % 7; const unsigned numBitsInSevens = numBits - remainderBits; @@ -571,7 +550,7 @@ class Decoder } template - MOZ_WARN_UNUSED_RESULT bool readVarS(SInt* out) { + MOZ_MUST_USE bool readVarS(SInt* out) { const unsigned numBits = sizeof(SInt) * CHAR_BIT; const unsigned remainderBits = numBits % 7; const unsigned numBitsInSevens = numBits - remainderBits; @@ -634,40 +613,40 @@ class Decoder // Fixed-size encoding operations simply copy the literal bytes (without // attempting to align). - MOZ_WARN_UNUSED_RESULT bool readFixedU8(uint8_t* i) { + MOZ_MUST_USE bool readFixedU8(uint8_t* i) { return read(i); } - MOZ_WARN_UNUSED_RESULT bool readFixedU32(uint32_t* u) { + MOZ_MUST_USE bool readFixedU32(uint32_t* u) { return read(u); } - MOZ_WARN_UNUSED_RESULT bool readFixedF32(float* f) { + MOZ_MUST_USE bool readFixedF32(float* f) { return read(f); } - MOZ_WARN_UNUSED_RESULT bool readFixedF64(double* d) { + MOZ_MUST_USE bool readFixedF64(double* d) { return read(d); } - MOZ_WARN_UNUSED_RESULT bool readFixedI32x4(I32x4* i32x4) { + MOZ_MUST_USE bool readFixedI32x4(I32x4* i32x4) { return read(i32x4); } - MOZ_WARN_UNUSED_RESULT bool readFixedF32x4(F32x4* f32x4) { + MOZ_MUST_USE bool readFixedF32x4(F32x4* f32x4) { return read(f32x4); } // Variable-length encodings that all use LEB128. - MOZ_WARN_UNUSED_RESULT bool readVarU32(uint32_t* out) { + MOZ_MUST_USE bool readVarU32(uint32_t* out) { return readVarU(out); } - MOZ_WARN_UNUSED_RESULT bool readVarS32(int32_t* out) { + MOZ_MUST_USE bool readVarS32(int32_t* out) { return readVarS(out); } - MOZ_WARN_UNUSED_RESULT bool readVarU64(uint64_t* out) { + MOZ_MUST_USE bool readVarU64(uint64_t* out) { return readVarU(out); } - MOZ_WARN_UNUSED_RESULT bool readVarS64(int64_t* out) { + MOZ_MUST_USE bool readVarS64(int64_t* out) { return readVarS(out); } - MOZ_WARN_UNUSED_RESULT bool readValType(ValType* type) { + MOZ_MUST_USE bool readValType(ValType* type) { static_assert(uint8_t(ValType::Limit) <= INT8_MAX, "fits"); uint8_t u8; if (!readFixedU8(&u8)) @@ -675,15 +654,7 @@ class Decoder *type = (ValType)u8; return true; } - MOZ_WARN_UNUSED_RESULT bool readExprType(ExprType* type) { - static_assert(uint8_t(ExprType::Limit) <= INT8_MAX, "fits"); - uint8_t u8; - if (!readFixedU8(&u8)) - return false; - *type = (ExprType)u8; - return true; - } - MOZ_WARN_UNUSED_RESULT bool readExpr(Expr* expr) { + MOZ_MUST_USE bool readExpr(Expr* expr) { static_assert(size_t(Expr::Limit) <= ExprLimit, "fits"); uint8_t u8; if (!readFixedU8(&u8)) @@ -702,7 +673,7 @@ class Decoder // See writeBytes comment. - MOZ_WARN_UNUSED_RESULT bool readBytes(Bytes* bytes) { + MOZ_MUST_USE bool readBytes(Bytes* bytes) { uint32_t numBytes; if (!readVarU32(&numBytes)) return false; @@ -714,7 +685,7 @@ class Decoder cur_ += numBytes; return true; } - MOZ_WARN_UNUSED_RESULT bool readBytesRaw(uint32_t numBytes, const uint8_t** bytes) { + MOZ_MUST_USE bool readBytesRaw(uint32_t numBytes, const uint8_t** bytes) { if (bytes) *bytes = cur_; if (bytesRemain() < numBytes) @@ -728,15 +699,11 @@ class Decoder static const uint32_t NotStarted = UINT32_MAX; template - MOZ_WARN_UNUSED_RESULT bool startSection(const char (&id)[IdSizeWith0], uint32_t* startOffset) { + MOZ_MUST_USE bool startSection(const char (&id)[IdSizeWith0], uint32_t* startOffset, + uint32_t* size) { static const size_t IdSize = IdSizeWith0 - 1; MOZ_ASSERT(id[IdSize] == '\0'); const uint8_t* before = cur_; - uint32_t size; - if (!readVarU32(&size)) - goto backup; - if (bytesRemain() < size) - return false; uint32_t idSize; if (!readVarU32(&idSize)) goto backup; @@ -745,32 +712,29 @@ class Decoder if (idSize != IdSize || !!memcmp(cur_, id, IdSize)) goto backup; cur_ += IdSize; - *startOffset = before - beg_; + if (!readVarU32(size)) + goto backup; + if (bytesRemain() < *size) + return false; + *startOffset = cur_ - beg_; return true; backup: cur_ = before; *startOffset = NotStarted; return true; } - MOZ_WARN_UNUSED_RESULT bool finishSection(uint32_t startOffset) { - uint32_t currentOffset = cur_ - beg_; - cur_ = beg_ + startOffset; - uint32_t size = uncheckedReadVarU32(); - uint32_t afterSize = cur_ - beg_; - cur_ = beg_ + currentOffset; - return size == (currentOffset - afterSize); + MOZ_MUST_USE bool finishSection(uint32_t startOffset, uint32_t size) { + return size == (cur_ - beg_) - startOffset; } - MOZ_WARN_UNUSED_RESULT bool skipSection() { - uint32_t size; - if (!readVarU32(&size) || bytesRemain() < size) - return false; - const uint8_t* begin = cur_; + MOZ_MUST_USE bool skipSection() { uint32_t idSize; if (!readVarU32(&idSize) || bytesRemain() < idSize) return false; - if (uint32_t(cur_ - begin) > size) + cur_ += idSize; + uint32_t size; + if (!readVarU32(&size) || bytesRemain() < size) return false; - cur_ = begin + size; + cur_ += size; return true; } @@ -834,12 +798,15 @@ class Decoder ? Expr(u8) : Expr(uncheckedReadFixedU8() + UINT8_MAX); } - Expr uncheckedPeekExpr() { - static_assert(size_t(Expr::Limit) <= ExprLimit, "fits"); - uint8_t u8 = cur_[0]; - return u8 != UINT8_MAX - ? Expr(u8) - : Expr(cur_[1] + UINT8_MAX); + void uncheckedReadFixedI32x4(I32x4* i32x4) { + struct T { I32x4 v; }; + T t = uncheckedRead(); + memcpy(i32x4, &t, sizeof(t)); + } + void uncheckedReadFixedF32x4(F32x4* f32x4) { + struct T { F32x4 v; }; + T t = uncheckedRead(); + memcpy(f32x4, &t, sizeof(t)); } }; diff --git a/js/src/asmjs/WasmBinaryIterator.cpp b/js/src/asmjs/WasmBinaryIterator.cpp new file mode 100644 index 0000000000..39915ccbcb --- /dev/null +++ b/js/src/asmjs/WasmBinaryIterator.cpp @@ -0,0 +1,368 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * + * Copyright 2015 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "asmjs/WasmBinaryIterator.h" + +using namespace js; +using namespace js::jit; +using namespace js::wasm; + +#ifdef DEBUG +ExprKind +wasm::Classify(Expr expr) +{ + switch (expr) { + case Expr::Block: + return ExprKind::Block; + case Expr::Loop: + return ExprKind::Loop; + case Expr::Unreachable: + return ExprKind::Unreachable; + case Expr::I32Const: + return ExprKind::I32; + case Expr::I64Const: + return ExprKind::I64; + case Expr::F32Const: + return ExprKind::F32; + case Expr::F64Const: + return ExprKind::F64; + case Expr::I32x4Const: + return ExprKind::I32x4; + case Expr::B32x4Const: + return ExprKind::B32x4; + case Expr::F32x4Const: + return ExprKind::F32x4; + case Expr::Br: + return ExprKind::Br; + case Expr::BrIf: + return ExprKind::BrIf; + case Expr::BrTable: + return ExprKind::BrTable; + case Expr::Nop: + return ExprKind::Nullary; + case Expr::I32Clz: + case Expr::I32Ctz: + case Expr::I32Popcnt: + case Expr::I64Clz: + case Expr::I64Ctz: + case Expr::I64Popcnt: + case Expr::I64Eqz: + case Expr::F32Abs: + case Expr::F32Neg: + case Expr::F32Ceil: + case Expr::F32Floor: + case Expr::F32Sqrt: + case Expr::F64Abs: + case Expr::F64Neg: + case Expr::F64Ceil: + case Expr::F64Floor: + case Expr::F64Sqrt: + case Expr::I32BitNot: + case Expr::I32Abs: + case Expr::F64Sin: + case Expr::F64Cos: + case Expr::F64Tan: + case Expr::F64Asin: + case Expr::F64Acos: + case Expr::F64Atan: + case Expr::F64Exp: + case Expr::F64Log: + case Expr::I32Neg: + case Expr::I32x4neg: + case Expr::I32x4not: + case Expr::F32x4neg: + case Expr::F32x4sqrt: + case Expr::F32x4abs: + case Expr::F32x4reciprocalApproximation: + case Expr::F32x4reciprocalSqrtApproximation: + case Expr::B32x4not: + return ExprKind::Unary; + case Expr::I32Add: + case Expr::I32Sub: + case Expr::I32Mul: + case Expr::I32DivS: + case Expr::I32DivU: + case Expr::I32RemS: + case Expr::I32RemU: + case Expr::I32And: + case Expr::I32Or: + case Expr::I32Xor: + case Expr::I32Shl: + case Expr::I32ShrS: + case Expr::I32ShrU: + case Expr::I32Rotl: + case Expr::I32Rotr: + case Expr::I64Add: + case Expr::I64Sub: + case Expr::I64Mul: + case Expr::I64DivS: + case Expr::I64DivU: + case Expr::I64RemS: + case Expr::I64RemU: + case Expr::I64And: + case Expr::I64Or: + case Expr::I64Xor: + case Expr::I64Shl: + case Expr::I64ShrS: + case Expr::I64ShrU: + case Expr::I64Rotl: + case Expr::I64Rotr: + case Expr::F32Add: + case Expr::F32Sub: + case Expr::F32Mul: + case Expr::F32Div: + case Expr::F32Min: + case Expr::F32Max: + case Expr::F32CopySign: + case Expr::F64Add: + case Expr::F64Sub: + case Expr::F64Mul: + case Expr::F64Div: + case Expr::F64Min: + case Expr::F64Max: + case Expr::F64CopySign: + case Expr::I32Min: + case Expr::I32Max: + case Expr::F64Mod: + case Expr::F64Pow: + case Expr::F64Atan2: + case Expr::I32x4add: + case Expr::I32x4sub: + case Expr::I32x4mul: + case Expr::I32x4and: + case Expr::I32x4or: + case Expr::I32x4xor: + case Expr::F32x4add: + case Expr::F32x4sub: + case Expr::F32x4mul: + case Expr::F32x4div: + case Expr::F32x4min: + case Expr::F32x4max: + case Expr::F32x4minNum: + case Expr::F32x4maxNum: + case Expr::B32x4and: + case Expr::B32x4or: + case Expr::B32x4xor: + return ExprKind::Binary; + case Expr::I32Eq: + case Expr::I32Ne: + case Expr::I32LtS: + case Expr::I32LtU: + case Expr::I32LeS: + case Expr::I32LeU: + case Expr::I32GtS: + case Expr::I32GtU: + case Expr::I32GeS: + case Expr::I32GeU: + case Expr::I64Eq: + case Expr::I64Ne: + case Expr::I64LtS: + case Expr::I64LtU: + case Expr::I64LeS: + case Expr::I64LeU: + case Expr::I64GtS: + case Expr::I64GtU: + case Expr::I64GeS: + case Expr::I64GeU: + case Expr::F32Eq: + case Expr::F32Ne: + case Expr::F32Lt: + case Expr::F32Le: + case Expr::F32Gt: + case Expr::F32Ge: + case Expr::F64Eq: + case Expr::F64Ne: + case Expr::F64Lt: + case Expr::F64Le: + case Expr::F64Gt: + case Expr::F64Ge: + return ExprKind::Comparison; + case Expr::I32Eqz: + case Expr::I32WrapI64: + case Expr::I32TruncSF32: + case Expr::I32TruncUF32: + case Expr::I32ReinterpretF32: + case Expr::I32TruncSF64: + case Expr::I32TruncUF64: + case Expr::I64ExtendSI32: + case Expr::I64ExtendUI32: + case Expr::I64TruncSF32: + case Expr::I64TruncUF32: + case Expr::I64TruncSF64: + case Expr::I64TruncUF64: + case Expr::I64ReinterpretF64: + case Expr::F32ConvertSI32: + case Expr::F32ConvertUI32: + case Expr::F32ReinterpretI32: + case Expr::F32ConvertSI64: + case Expr::F32ConvertUI64: + case Expr::F32DemoteF64: + case Expr::F64ConvertSI32: + case Expr::F64ConvertUI32: + case Expr::F64ConvertSI64: + case Expr::F64ConvertUI64: + case Expr::F64ReinterpretI64: + case Expr::F64PromoteF32: + case Expr::I32x4fromFloat32x4: + case Expr::I32x4fromFloat32x4U: + case Expr::F32x4fromInt32x4: + case Expr::F32x4fromUint32x4: + case Expr::I32x4fromFloat32x4Bits: + case Expr::F32x4fromInt32x4Bits: + case Expr::F32x4fromUint32x4Bits: + return ExprKind::Conversion; + case Expr::I32Load8S: + case Expr::I32Load8U: + case Expr::I32Load16S: + case Expr::I32Load16U: + case Expr::I64Load8S: + case Expr::I64Load8U: + case Expr::I64Load16S: + case Expr::I64Load16U: + case Expr::I64Load32S: + case Expr::I64Load32U: + case Expr::I32Load: + case Expr::I64Load: + case Expr::F32Load: + case Expr::F64Load: + case Expr::I32x4load: + case Expr::I32x4load1: + case Expr::I32x4load2: + case Expr::I32x4load3: + case Expr::F32x4load: + case Expr::F32x4load1: + case Expr::F32x4load2: + case Expr::F32x4load3: + return ExprKind::Load; + case Expr::I32Store8: + case Expr::I32Store16: + case Expr::I64Store8: + case Expr::I64Store16: + case Expr::I64Store32: + case Expr::I32Store: + case Expr::I64Store: + case Expr::F32Store: + case Expr::F64Store: + case Expr::F32StoreF64: + case Expr::F64StoreF32: + case Expr::I32x4store: + case Expr::I32x4store1: + case Expr::I32x4store2: + case Expr::I32x4store3: + case Expr::F32x4store: + case Expr::F32x4store1: + case Expr::F32x4store2: + case Expr::F32x4store3: + return ExprKind::Store; + case Expr::Select: + return ExprKind::Select; + case Expr::GetLocal: + case Expr::LoadGlobal: + return ExprKind::GetVar; + case Expr::SetLocal: + case Expr::StoreGlobal: + return ExprKind::SetVar; + case Expr::Call: + return ExprKind::Call; + case Expr::CallIndirect: + return ExprKind::CallIndirect; + case Expr::CallImport: + return ExprKind::CallImport; + case Expr::Return: + case Expr::Limit: + // Accept Limit, for use in decoding the end of a function after the body. + return ExprKind::Return; + case Expr::If: + return ExprKind::If; + case Expr::Else: + return ExprKind::Else; + case Expr::End: + return ExprKind::End; + case Expr::I32AtomicsLoad: + return ExprKind::AtomicLoad; + case Expr::I32AtomicsStore: + return ExprKind::AtomicStore; + case Expr::I32AtomicsBinOp: + return ExprKind::AtomicBinOp; + case Expr::I32AtomicsCompareExchange: + return ExprKind::AtomicCompareExchange; + case Expr::I32AtomicsExchange: + return ExprKind::AtomicExchange; + case Expr::I32x4extractLane: + case Expr::F32x4extractLane: + case Expr::B32x4extractLane: + return ExprKind::ExtractLane; + case Expr::I32x4replaceLane: + case Expr::F32x4replaceLane: + case Expr::B32x4replaceLane: + return ExprKind::ReplaceLane; + case Expr::I32x4swizzle: + case Expr::F32x4swizzle: + return ExprKind::Swizzle; + case Expr::I32x4shuffle: + case Expr::F32x4shuffle: + return ExprKind::Shuffle; + case Expr::I32x4splat: + case Expr::F32x4splat: + case Expr::B32x4splat: + case Expr::I32x4check: + case Expr::F32x4check: + case Expr::B32x4check: + return ExprKind::Splat; + case Expr::I32x4select: + case Expr::F32x4select: + return ExprKind::SimdSelect; + case Expr::I32x4Constructor: + case Expr::F32x4Constructor: + case Expr::B32x4Constructor: + return ExprKind::SimdCtor; + case Expr::B32x4anyTrue: + case Expr::B32x4allTrue: + return ExprKind::SimdBooleanReduction; + case Expr::I32x4shiftLeftByScalar: + case Expr::I32x4shiftRightByScalar: + case Expr::I32x4shiftRightByScalarU: + return ExprKind::SimdShiftByScalar; + case Expr::I32x4equal: + case Expr::I32x4notEqual: + case Expr::I32x4greaterThan: + case Expr::I32x4greaterThanOrEqual: + case Expr::I32x4lessThan: + case Expr::I32x4lessThanOrEqual: + case Expr::I32x4greaterThanU: + case Expr::I32x4greaterThanOrEqualU: + case Expr::I32x4lessThanU: + case Expr::I32x4lessThanOrEqualU: + case Expr::F32x4equal: + case Expr::F32x4notEqual: + case Expr::F32x4greaterThan: + case Expr::F32x4greaterThanOrEqual: + case Expr::F32x4lessThan: + case Expr::F32x4lessThanOrEqual: + return ExprKind::SimdComparison; + case Expr::CurrentMemory: + case Expr::GrowMemory: + case Expr::F32Trunc: + case Expr::F32Nearest: + case Expr::F64Trunc: + case Expr::F64Nearest: + break; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unimplemented opcode"); +} +#endif diff --git a/js/src/asmjs/WasmBinaryIterator.h b/js/src/asmjs/WasmBinaryIterator.h new file mode 100644 index 0000000000..0cebb23135 --- /dev/null +++ b/js/src/asmjs/WasmBinaryIterator.h @@ -0,0 +1,1781 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * + * Copyright 2016 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_binary_iterator_h +#define wasm_binary_iterator_h + +#include "mozilla/Poison.h" + +#include "jsprf.h" + +#include "asmjs/WasmTypes.h" +#include "jit/AtomicOp.h" + +namespace js { +namespace wasm { + +// The kind of a control-flow stack item. +enum class LabelKind : uint8_t { Block, Loop, Then, Else }; + +#ifdef DEBUG +// Families of opcodes that share a signature and validation logic. +enum class ExprKind { + Block, + Loop, + Unreachable, + I32, + I64, + F32, + F64, + I32x4, + B32x4, + F32x4, + Br, + BrIf, + BrTable, + Nullary, + Unary, + Binary, + Comparison, + Conversion, + Load, + Store, + Select, + GetVar, + SetVar, + Call, + CallIndirect, + CallImport, + Return, + If, + Else, + End, + AtomicLoad, + AtomicStore, + AtomicBinOp, + AtomicCompareExchange, + AtomicExchange, + ExtractLane, + ReplaceLane, + Swizzle, + Shuffle, + Splat, + SimdSelect, + SimdCtor, + SimdBooleanReduction, + SimdShiftByScalar, + SimdComparison, +}; + +// Return the ExprKind for a given Expr. This is used for sanity-checking that +// API users use the correct read function for a given Expr. +ExprKind +Classify(Expr expr); +#endif + +// Common fields for linear memory access. +template +struct LinearMemoryAddress +{ + Value base; + uint32_t offset; + uint32_t align; + + LinearMemoryAddress() + {} + LinearMemoryAddress(Value base, uint32_t offset, uint32_t align) + : base(base), offset(offset), align(align) + {} +}; + +struct Nothing {}; + +template +class ControlStackEntry +{ + LabelKind kind_; + ExprType type_; + size_t valueStackStart_; + ControlItem controlItem_; + + public: + ControlStackEntry(LabelKind kind, size_t valueStackStart) + : kind_(kind), type_(AnyType), valueStackStart_(valueStackStart) + {} + + LabelKind kind() const { return kind_; } + size_t valueStackStart() const { return valueStackStart_; } + const ExprType& type() const { return type_; } + ExprType& type() { return type_; } + ControlItem& controlItem() { return controlItem_; } +}; + +// Specialization for when there is no additional data needed. +template <> +class ControlStackEntry +{ + LabelKind kind_; + ExprType type_; + size_t valueStackStart_; + + public: + ControlStackEntry(LabelKind kind, size_t valueStackStart) + : kind_(kind), type_(AnyType), valueStackStart_(valueStackStart) + {} + + LabelKind kind() const { return kind_; } + size_t valueStackStart() const { return valueStackStart_; } + const ExprType& type() const { return type_; } + ExprType& type() { return type_; } + Nothing controlItem() { return Nothing(); } +}; + +template +class TypeAndValue +{ + ExprType type_; + Value value_; + + public: + TypeAndValue() = default; + explicit TypeAndValue(ExprType type) + : type_(type) + {} + TypeAndValue(ExprType type, Value value) + : type_(type), value_(value) + {} + ExprType type() const { + return type_; + } + Value value() const { + return value_; + } + void setValue(Value value) { + value_ = value; + } +}; + +// Specialization for when there is no additional data needed. +template <> +struct TypeAndValue +{ + ExprType type_; + + public: + TypeAndValue() {} + explicit TypeAndValue(ExprType type) : type_(type) {} + + TypeAndValue(ExprType type, Nothing value) + : type_(type) + {} + + ExprType type() const { return type_; } + Nothing value() const { return Nothing(); } + void setValue(Nothing value) {} +}; + +// A policy class for configuring ExprIter. Clients can use this as a +// base class, and override the behavior as needed. +struct ExprIterPolicy +{ + // Should the iterator perform validation, such as type checking and + // validity checking? + static const bool Validate = false; + + // Should the iterator produce output values? + static const bool Output = false; + + // This function is called to report failures. + static bool fail(const char*, Decoder&) { + MOZ_CRASH("unexpected validation failure"); + return false; + } + + // These members allow clients to add additional information to the value + // and control stacks, respectively. Using Nothing means that no additional + // field is added. + typedef Nothing Value; + typedef Nothing ControlItem; +}; + +// An iterator over the bytes of a function body. It performs validation +// (if Policy::Validate is true) and unpacks the data into a usable form. +// +// The MOZ_STACK_CLASS attribute here is because of the use of DebugOnly. +// There's otherwise nothing inherent in this class which would require +// it to be used on the stack. +template +class MOZ_STACK_CLASS ExprIter : private Policy +{ + static const bool Validate = Policy::Validate; + static const bool Output = Policy::Output; + typedef typename Policy::Value Value; + typedef typename Policy::ControlItem ControlItem; + + Decoder& d_; + + Vector, 0, SystemAllocPolicy> valueStack_; + Vector, 0, SystemAllocPolicy> controlStack_; + + DebugOnly expr_; + + MOZ_MUST_USE bool readFixedU8(uint8_t* out) { + if (Validate) + return d_.readFixedU8(out); + *out = d_.uncheckedReadFixedU8(); + return true; + } + MOZ_MUST_USE bool readFixedU32(uint32_t* out) { + if (Validate) + return d_.readFixedU32(out); + *out = d_.uncheckedReadFixedU32(); + return true; + } + MOZ_MUST_USE bool readVarS32(int32_t* out) { + if (Validate) + return d_.readVarS32(out); + *out = d_.uncheckedReadVarS32(); + return true; + } + MOZ_MUST_USE bool readVarU32(uint32_t* out) { + if (Validate) + return d_.readVarU32(out); + *out = d_.uncheckedReadVarU32(); + return true; + } + MOZ_MUST_USE bool readVarS64(int64_t* out) { + if (Validate) + return d_.readVarS64(out); + *out = d_.uncheckedReadVarS64(); + return true; + } + MOZ_MUST_USE bool readVarU64(uint64_t* out) { + if (Validate) + return d_.readVarU64(out); + *out = d_.uncheckedReadVarU64(); + return true; + } + MOZ_MUST_USE bool readFixedF32(float* out) { + if (Validate) + return d_.readFixedF32(out); + *out = d_.uncheckedReadFixedF32(); + return true; + } + MOZ_MUST_USE bool readFixedF64(double* out) { + if (Validate) + return d_.readFixedF64(out); + *out = d_.uncheckedReadFixedF64(); + return true; + } + MOZ_MUST_USE bool readFixedI32x4(I32x4* out) { + if (Validate) + return d_.readFixedI32x4(out); + d_.uncheckedReadFixedI32x4(out); + return true; + } + MOZ_MUST_USE bool readFixedF32x4(F32x4* out) { + if (Validate) + return d_.readFixedF32x4(out); + d_.uncheckedReadFixedF32x4(out); + return true; + } + + MOZ_MUST_USE bool readAtomicViewType(Scalar::Type* viewType) { + uint8_t x; + if (!readFixedU8(&x)) + return false; + if (Validate && x >= Scalar::MaxTypedArrayViewType) + return fail("invalid atomic view type"); + *viewType = Scalar::Type(x); + return true; + } + + MOZ_MUST_USE bool readAtomicBinOpOp(jit::AtomicOp* op) { + uint8_t x; + if (!readFixedU8(&x)) + return false; + if (Validate) { + switch (x) { + case jit::AtomicFetchAddOp: + case jit::AtomicFetchSubOp: + case jit::AtomicFetchAndOp: + case jit::AtomicFetchOrOp: + case jit::AtomicFetchXorOp: + break; + default: + return fail("unrecognized atomic binop"); + } + } + *op = jit::AtomicOp(x); + return true; + } + + MOZ_MUST_USE bool typeMismatch(ExprType actual, ExprType expected) MOZ_COLD; + MOZ_MUST_USE bool checkType(ExprType actual, ExprType expected); + MOZ_MUST_USE bool readFunctionReturnValue(ExprType ret); + MOZ_MUST_USE bool checkBranch(uint32_t relativeDepth, ExprType type); + MOZ_MUST_USE bool pushControl(LabelKind kind); + MOZ_MUST_USE bool popControl(LabelKind* kind, ExprType* type, Value* value); + MOZ_MUST_USE bool popControlAfterCheck(LabelKind* kind, ExprType* type, Value* value); + MOZ_MUST_USE bool push(ExprType t) { return valueStack_.emplaceBack(t); } + MOZ_MUST_USE bool push(TypeAndValue tv) { return valueStack_.append(tv); } + + MOZ_MUST_USE bool readLinearMemoryAddress(uint32_t byteSize, LinearMemoryAddress* addr); + + void infallibleCheckSuccessor(ControlStackEntry& controlItem, ExprType type); + void infalliblePush(ExprType t) { valueStack_.infallibleEmplaceBack(t); } + void infalliblePush(TypeAndValue tv) { valueStack_.infallibleAppend(tv); } + + // Test whether reading the top of the value stack is currently valid. + MOZ_MUST_USE bool checkTop() { + if (Validate && valueStack_.length() <= controlStack_.back().valueStackStart()) + return fail("popping value from outside block"); + return true; + } + + // Pop the top of the value stack. + MOZ_MUST_USE bool pop(TypeAndValue* tv) { + if (!checkTop()) + return false; + *tv = valueStack_.popCopy(); + return true; + } + + // Pop the top of the value stack and check that it has the given type. + MOZ_MUST_USE bool popWithType(ExprType expectedType, Value* value) { + if (!checkTop()) + return false; + TypeAndValue tv = valueStack_.popCopy(); + if (!checkType(tv.type(), expectedType)) + return false; + if (Output) + *value = tv.value(); + return true; + } + + // Read the top of the value stack (without popping it). + MOZ_MUST_USE bool top(TypeAndValue* tv) { + if (!checkTop()) + return false; + *tv = valueStack_.back(); + return true; + } + + // Read the top of the value stack (without popping it) and check that it + // has the given type. + MOZ_MUST_USE bool topWithType(ExprType expectedType, Value* value) { + if (!checkTop()) + return false; + TypeAndValue& tv = valueStack_.back(); + if (!checkType(tv.type(), expectedType)) + return false; + if (Output) + *value = tv.value(); + return true; + } + + // Read the value stack entry at depth |index|. + bool peek(uint32_t index, TypeAndValue* tv) { + if (Validate && valueStack_.length() - controlStack_.back().valueStackStart() <= index) + return fail("peeking at value from outside block"); + *tv = valueStack_[valueStack_.length() - index]; + return true; + } + + public: + ExprIter(Policy policy, Decoder& decoder) + : Policy(policy), d_(decoder) + { + expr_ = Expr::Limit; + } + + // Return the decoding byte offset. + uint32_t currentOffset() const { return d_.currentOffset(); } + + // Test whether the iterator has reached the end of the buffer. + bool done() const { return d_.done(); } + + // Report a general failure. + MOZ_MUST_USE bool fail(const char* msg) MOZ_COLD; + + // Report an unimplemented feature. + MOZ_MUST_USE bool notYetImplemented(const char* what) MOZ_COLD; + + // Report an unrecognized opcode. + MOZ_MUST_USE bool unrecognizedOpcode(Expr expr) MOZ_COLD; + + // ------------------------------------------------------------------------ + // Decoding and validation interface. + + MOZ_MUST_USE bool readExpr(Expr* expr); + MOZ_MUST_USE bool readFunctionStart(); + MOZ_MUST_USE bool readFunctionEnd(ExprType ret, Value* value); + MOZ_MUST_USE bool readReturn(Value* value); + MOZ_MUST_USE bool readBlock(); + MOZ_MUST_USE bool readLoop(); + MOZ_MUST_USE bool readIf(Value* condition); + MOZ_MUST_USE bool readElse(ExprType* thenType, Value* thenValue); + MOZ_MUST_USE bool readEnd(LabelKind* kind, ExprType* type, Value* value); + MOZ_MUST_USE bool readBr(uint32_t* relativeDepth, ExprType* type, Value* value); + MOZ_MUST_USE bool readBrIf(uint32_t* relativeDepth, ExprType* type, + Value* value, Value* condition); + MOZ_MUST_USE bool readBrTable(uint32_t* tableLength, ExprType* type, + Value* value, Value* index); + MOZ_MUST_USE bool readBrTableEntry(ExprType type, uint32_t* depth); + MOZ_MUST_USE bool readUnreachable(); + MOZ_MUST_USE bool readUnary(ValType operandType, Value* input); + MOZ_MUST_USE bool readConversion(ValType operandType, ValType resultType, Value* input); + MOZ_MUST_USE bool readBinary(ValType operandType, Value* lhs, Value* rhs); + MOZ_MUST_USE bool readComparison(ValType operandType, Value* lhs, Value* rhs); + MOZ_MUST_USE bool readLoad(ValType resultType, uint32_t byteSize, + LinearMemoryAddress* addr); + MOZ_MUST_USE bool readStore(ValType resultType, uint32_t byteSize, + LinearMemoryAddress* addr, Value* value); + MOZ_MUST_USE bool readNullary(); + MOZ_MUST_USE bool readSelect(ExprType* type, + Value* trueValue, Value* falseValue, Value* condition); + MOZ_MUST_USE bool readGetLocal(const ValTypeVector& locals, uint32_t* id); + MOZ_MUST_USE bool readSetLocal(const ValTypeVector& locals, uint32_t* id, Value* value); + MOZ_MUST_USE bool readGetGlobal(const GlobalDescVector& globals, uint32_t* id); + MOZ_MUST_USE bool readSetGlobal(const GlobalDescVector& globals, uint32_t* id, Value* value); + MOZ_MUST_USE bool readI32Const(int32_t* i32); + MOZ_MUST_USE bool readI64Const(int64_t* i64); + MOZ_MUST_USE bool readF32Const(float* f32); + MOZ_MUST_USE bool readF64Const(double* f64); + MOZ_MUST_USE bool readI32x4Const(I32x4* i32x4); + MOZ_MUST_USE bool readF32x4Const(F32x4* f32x4); + MOZ_MUST_USE bool readB32x4Const(I32x4* i32x4); + MOZ_MUST_USE bool readCall(uint32_t* calleeIndex, uint32_t* arity); + MOZ_MUST_USE bool readCallIndirect(uint32_t* sigIndex, uint32_t* arity); + MOZ_MUST_USE bool readCallImport(uint32_t* importIndex, uint32_t* arity); + MOZ_MUST_USE bool readCallArg(ValType type, uint32_t numArgs, uint32_t argIndex, Value* arg); + MOZ_MUST_USE bool readCallArgsEnd(uint32_t numArgs); + MOZ_MUST_USE bool readCallIndirectCallee(Value* callee); + MOZ_MUST_USE bool readCallReturn(ExprType ret); + MOZ_MUST_USE bool readAtomicLoad(LinearMemoryAddress* addr, + Scalar::Type* viewType); + MOZ_MUST_USE bool readAtomicStore(LinearMemoryAddress* addr, + Scalar::Type* viewType, + Value* value); + MOZ_MUST_USE bool readAtomicBinOp(LinearMemoryAddress* addr, + Scalar::Type* viewType, + jit::AtomicOp* op, + Value* value); + MOZ_MUST_USE bool readAtomicCompareExchange(LinearMemoryAddress* addr, + Scalar::Type* viewType, + Value* oldValue, + Value* newValue); + MOZ_MUST_USE bool readAtomicExchange(LinearMemoryAddress* addr, + Scalar::Type* viewType, + Value* newValue); + MOZ_MUST_USE bool readSimdComparison(ValType simdType, Value* lhs, + Value* rhs); + MOZ_MUST_USE bool readSimdShiftByScalar(ValType simdType, Value* lhs, + Value* rhs); + MOZ_MUST_USE bool readSimdBooleanReduction(ValType simdType, Value* input); + MOZ_MUST_USE bool readExtractLane(ValType simdType, jit::SimdLane* lane, + Value* vector); + MOZ_MUST_USE bool readReplaceLane(ValType simdType, jit::SimdLane* lane, + Value* vector, Value* scalar); + MOZ_MUST_USE bool readSplat(ValType simdType, Value* scalar); + MOZ_MUST_USE bool readSwizzle(ValType simdType, uint8_t (* lanes)[4], Value* vector); + MOZ_MUST_USE bool readShuffle(ValType simdType, uint8_t (* lanes)[4], + Value* lhs, Value* rhs); + MOZ_MUST_USE bool readSimdSelect(ValType simdType, Value* trueValue, + Value* falseValue, + Value* condition); + MOZ_MUST_USE bool readSimdCtor(); + MOZ_MUST_USE bool readSimdCtorArg(ValType elementType, uint32_t numElements, uint32_t argIndex, Value* arg); + MOZ_MUST_USE bool readSimdCtorArgsEnd(uint32_t numElements); + MOZ_MUST_USE bool readSimdCtorReturn(ValType simdType); + + // ------------------------------------------------------------------------ + // Stack management. + + // Set the result value of the current top-of-value-stack expression. + void setResult(Value value) { + valueStack_.back().setValue(value); + } + + // Return the result value of the current top-of-value-stack expression. + Value getResult() { + return valueStack_.back().value(); + } + + // Return a reference to the top of the control stack. + ControlItem& controlItem() { + return controlStack_.back().controlItem(); + } +}; + +template +inline bool +ExprIter::typeMismatch(ExprType actual, ExprType expected) +{ + UniqueChars error(JS_smprintf("type mismatch: expression has type %s but expected %s", + ToCString(actual), ToCString(expected))); + if (!error) + return false; + + return fail(error.get()); +} + +template +inline MOZ_MUST_USE bool +ExprIter::checkType(ExprType actual, ExprType expected) +{ + if (!Validate) { + MOZ_ASSERT(actual == AnyType || actual == expected, "type mismatch"); + return true; + } + + if (MOZ_LIKELY(actual == AnyType || actual == expected)) + return true; + + return typeMismatch(actual, expected); +} + +template +inline bool +ExprIter::notYetImplemented(const char* what) +{ + UniqueChars error(JS_smprintf("not yet implemented: %s", what)); + if (!error) + return false; + + return fail(error.get()); +} + +template +inline bool +ExprIter::unrecognizedOpcode(Expr expr) +{ + UniqueChars error(JS_smprintf("unrecognized opcode: %x", uint32_t(expr))); + if (!error) + return false; + + return fail(error.get()); +} + +template +inline bool +ExprIter::fail(const char* msg) { + return Policy::fail(msg, d_); +} + +template +inline bool +ExprIter::readExpr(Expr* expr) +{ + if (Validate) { + if (MOZ_UNLIKELY(!d_.readExpr(expr))) + return fail("unable to read opcode"); + } else { + *expr = d_.uncheckedReadExpr(); + } + + expr_ = *expr; + + return true; +} + +template +inline bool +ExprIter::readFunctionStart() +{ + MOZ_ASSERT(valueStack_.empty()); + MOZ_ASSERT(controlStack_.empty()); + MOZ_ASSERT(Expr(expr_) == Expr::Limit); + + return pushControl(LabelKind::Block); +} + +template +inline bool +ExprIter::readFunctionEnd(ExprType ret, Value* value) +{ + expr_ = Expr::Limit; + + if (Validate) { + MOZ_ASSERT(controlStack_.length() > 0); + if (controlStack_.length() != 1) + return fail("unbalanced function body control flow"); + } else { + MOZ_ASSERT(controlStack_.length() == 1); + } + + ExprType type; + LabelKind kind; + if (!popControlAfterCheck(&kind, &type, value)) + return false; + + MOZ_ASSERT(kind == LabelKind::Block); + MOZ_ASSERT(valueStack_.length() == 1); + + if (!IsVoid(ret)) { + if (!checkType(type, ret)) + return false; + } + + return true; +} + +template +inline bool +ExprIter::readReturn(Value* value) +{ + ControlStackEntry& controlItem = controlStack_[0]; + MOZ_ASSERT(controlItem.kind() == LabelKind::Block); + MOZ_ASSERT(Classify(expr_) == ExprKind::Return); + + uint32_t arity; + if (!readVarU32(&arity)) + return fail("failed to read return arity"); + if (arity > 1) + return fail("return arity too big"); + + TypeAndValue tv; + if (arity) { + if (!pop(&tv)) + return false; + } else { + tv = TypeAndValue(ExprType::Void); + } + + infallibleCheckSuccessor(controlItem, tv.type()); + + if (!push(AnyType)) + return false; + + if (Output) + *value = tv.value(); + + return true; +} + +template +inline void +ExprIter::infallibleCheckSuccessor(ControlStackEntry& controlItem, + ExprType type) +{ + controlItem.type() = Unify(controlItem.type(), type); +} + +template +inline bool +ExprIter::checkBranch(uint32_t relativeDepth, ExprType type) +{ + // FIXME: Don't allow branching to the function-body block for now. + if (Validate && relativeDepth >= controlStack_.length() - 1) + return fail("branch depth exceeds current nesting level"); + + ControlStackEntry& controlItem = + controlStack_[controlStack_.length() - 1 - relativeDepth]; + + if (controlItem.kind() != LabelKind::Loop) + infallibleCheckSuccessor(controlItem, type); + + return true; +} + +template +inline bool +ExprIter::pushControl(LabelKind kind) +{ + size_t length = valueStack_.length(); + + // Push a void value at the start of every control region, in case the + // region is empty. + if (!push(ExprType::Void)) + return false; + + return controlStack_.emplaceBack(kind, length); +} + +template +inline bool +ExprIter::popControl(LabelKind* kind, ExprType* type, Value* value) +{ + MOZ_ASSERT(controlStack_.length() > 0); + if (controlStack_.length() <= 1) + return fail("unbalanced function body control flow"); + + return popControlAfterCheck(kind, type, value); +} + +template +inline bool +ExprIter::popControlAfterCheck(LabelKind* kind, ExprType* type, Value* value) +{ + TypeAndValue tv; + if (!pop(&tv)) + return false; + + if (Output) + *value = tv.value(); + + ControlStackEntry controlItem = controlStack_.popCopy(); + *kind = controlItem.kind(); + + infallibleCheckSuccessor(controlItem, tv.type()); + + *type = controlItem.type(); + + // Clear out the value stack up to the start of the block/loop. + valueStack_.shrinkTo(controlItem.valueStackStart()); + + infalliblePush(controlItem.type()); + return true; +} + +template +inline bool +ExprIter::readBlock() +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Block); + + return pushControl(LabelKind::Block); +} + +template +inline bool +ExprIter::readLoop() +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Loop); + + return pushControl(LabelKind::Block) && + pushControl(LabelKind::Loop); +} + +template +inline bool +ExprIter::readIf(Value* condition) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::If); + + if (!popWithType(ExprType::I32, condition)) + return false; + + return pushControl(LabelKind::Then); +} + +template +inline bool +ExprIter::readElse(ExprType* thenType, Value* thenValue) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Else); + + ExprType type; + LabelKind kind; + if (!popControl(&kind, &type, thenValue)) + return false; + + if (Validate && kind != LabelKind::Then) + return fail("else can only be used within an if"); + + // Pop and discard the old then value for now. + TypeAndValue tv; + if (!pop(&tv)) + return false; + + if (!pushControl(LabelKind::Else)) + return false; + + // Initialize the else block's type with the then block's type, so that + // the two get unified. + ControlStackEntry& controlItem = controlStack_.back(); + controlItem.type() = type; + + if (Output) + *thenType = type; + + return true; +} + +template +inline bool +ExprIter::readEnd(LabelKind* kind, ExprType* type, Value* value) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::End); + + LabelKind validateKind; + ExprType validateType; + if (!popControl(&validateKind, &validateType, value)) + return false; + + switch (validateKind) { + case LabelKind::Block: + break; + case LabelKind::Loop: { + // Note: Propose a spec change: loops don't implicitly have an end label. + + if (Output) + setResult(*value); + + LabelKind blockKind; + if (!popControl(&blockKind, &validateType, value)) + return false; + + MOZ_ASSERT(blockKind == LabelKind::Block); + break; + } + case LabelKind::Then: + valueStack_.back() = TypeAndValue(ExprType::Void); + if (Output) + *type = ExprType::Void; + break; + case LabelKind::Else: + break; + } + + if (Output) { + *kind = validateKind; + *type = validateType; + } + + return true; +} + +template +inline bool +ExprIter::readBr(uint32_t* relativeDepth, ExprType* type, Value* value) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Br); + + uint32_t arity; + if (!readVarU32(&arity)) + return fail("unable to read br arity"); + if (arity > 1) + return fail("br arity too big"); + + uint32_t validateRelativeDepth; + if (!readVarU32(&validateRelativeDepth)) + return fail("unable to read br depth"); + + TypeAndValue tv; + if (arity) { + if (!pop(&tv)) + return false; + } else { + tv = TypeAndValue(ExprType::Void); + } + + if (!checkBranch(validateRelativeDepth, tv.type())) + return false; + + if (!push(AnyType)) + return false; + + if (Output) { + *relativeDepth = validateRelativeDepth; + *type = tv.type(); + *value = tv.value(); + } + + return true; +} + +template +inline bool +ExprIter::readBrIf(uint32_t* relativeDepth, ExprType* type, Value* value, Value* condition) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::BrIf); + + uint32_t arity; + if (!readVarU32(&arity)) + return fail("unable to read br_if arity"); + if (arity > 1) + return fail("br_if arity too big"); + + uint32_t validateRelativeDepth; + if (!readVarU32(&validateRelativeDepth)) + return fail("unable to read br_if depth"); + + if (!popWithType(ExprType::I32, condition)) + return false; + + TypeAndValue tv; + if (arity) { + if (!top(&tv)) + return false; + } else { + tv = TypeAndValue(ExprType::Void); + if (!push(tv)) + return false; + } + + if (!checkBranch(validateRelativeDepth, tv.type())) + return false; + + if (Output) { + *relativeDepth = validateRelativeDepth; + *type = tv.type(); + *value = tv.value(); + } + + return true; +} + +template +inline bool +ExprIter::readBrTable(uint32_t* tableLength, ExprType* type, + Value* value, Value* index) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::BrTable); + + if (!popWithType(ExprType::I32, index)) + return false; + + uint32_t arity; + if (!readVarU32(&arity)) + return fail("unable to read br_table arity"); + if (arity > 1) + return fail("br_table arity too big"); + + TypeAndValue tv; + if (arity) { + if (!top(&tv)) + return false; + } else { + tv = TypeAndValue(ExprType::Void); + if (!push(tv)) + return false; + } + *type = tv.type(); + if (Output) + *value = tv.value(); + + if (!readVarU32(tableLength)) + return fail("unable to read br_table table length"); + + return true; +} + +template +inline bool +ExprIter::readBrTableEntry(ExprType type, uint32_t* depth) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::BrTable); + + return readFixedU32(depth) && + checkBranch(*depth, type); +} + +template +inline bool +ExprIter::readUnreachable() +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Unreachable); + + return push(AnyType); +} + +template +inline bool +ExprIter::readUnary(ValType operandType, Value* input) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Unary); + + if (!popWithType(ToExprType(operandType), input)) + return false; + + infalliblePush(ToExprType(operandType)); + + return true; +} + +template +inline bool +ExprIter::readConversion(ValType operandType, ValType resultType, Value* input) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Conversion); + + if (!popWithType(ToExprType(operandType), input)) + return false; + + infalliblePush(ToExprType(resultType)); + + return true; +} + +template +inline bool +ExprIter::readBinary(ValType operandType, Value* lhs, Value* rhs) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Binary); + + if (!popWithType(ToExprType(operandType), rhs)) + return false; + + if (!popWithType(ToExprType(operandType), lhs)) + return false; + + infalliblePush(ToExprType(operandType)); + + return true; +} + +template +inline bool +ExprIter::readComparison(ValType operandType, Value* lhs, Value* rhs) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Comparison); + + if (!popWithType(ToExprType(operandType), rhs)) + return false; + + if (!popWithType(ToExprType(operandType), lhs)) + return false; + + infalliblePush(ExprType::I32); + + return true; +} + +template +inline bool +ExprIter::readLinearMemoryAddress(uint32_t byteSize, LinearMemoryAddress* addr) +{ + Value unused; + if (!popWithType(ExprType::I32, Output ? &addr->base : &unused)) + return false; + + uint8_t alignLog2; + if (!readFixedU8(&alignLog2)) + return fail("unable to read load alignment"); + if (Validate && (alignLog2 >= 32 || (uint32_t(1) << alignLog2) > byteSize)) + return fail("greater than natural alignment"); + if (Output) + addr->align = uint32_t(1) << alignLog2; + + uint32_t unusedOffset; + if (!readVarU32(Output ? &addr->offset : &unusedOffset)) + return fail("unable to read load offset"); + + return true; +} + +template +inline bool +ExprIter::readLoad(ValType resultType, uint32_t byteSize, + LinearMemoryAddress* addr) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Load); + + if (!readLinearMemoryAddress(byteSize, addr)) + return false; + + infalliblePush(ToExprType(resultType)); + + return true; +} + +template +inline bool +ExprIter::readStore(ValType resultType, uint32_t byteSize, + LinearMemoryAddress* addr, Value* value) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Store); + + if (!popWithType(ToExprType(resultType), value)) + return false; + + if (!readLinearMemoryAddress(byteSize, addr)) + return false; + + infalliblePush(TypeAndValue(ToExprType(resultType), Output ? *value : Value())); + + return true; +} + +template +inline bool +ExprIter::readNullary() +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Nullary); + + return push(ExprType::Void); +} + +template +inline bool +ExprIter::readSelect(ExprType* type, Value* trueValue, Value* falseValue, Value* condition) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Select); + + if (!popWithType(ExprType::I32, condition)) + return false; + + TypeAndValue false_; + if (!pop(&false_)) + return false; + + TypeAndValue true_; + if (!pop(&true_)) + return false; + + ExprType resultType = Unify(true_.type(), false_.type()); + infalliblePush(resultType); + + if (Output) { + *type = resultType; + *trueValue = true_.value(); + *falseValue = false_.value(); + } + + return true; +} + +template +inline bool +ExprIter::readGetLocal(const ValTypeVector& locals, uint32_t* id) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::GetVar); + + uint32_t validateId; + if (!readVarU32(&validateId)) + return false; + + if (Validate && validateId >= locals.length()) + return fail("get_local index out of range"); + + if (!push(ToExprType(locals[validateId]))) + return false; + + if (Output) + *id = validateId; + + return true; +} + +template +inline bool +ExprIter::readSetLocal(const ValTypeVector& locals, uint32_t* id, Value* value) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SetVar); + + uint32_t validateId; + if (!readVarU32(&validateId)) + return false; + + if (Validate && validateId >= locals.length()) + return fail("set_local index out of range"); + + if (!topWithType(ToExprType(locals[validateId]), value)) + return false; + + if (Output) + *id = validateId; + + return true; +} + +template +inline bool +ExprIter::readGetGlobal(const GlobalDescVector& globals, uint32_t* id) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::GetVar); + + uint32_t validateId; + if (!readVarU32(&validateId)) + return false; + + if (Validate && validateId >= globals.length()) + return fail("get_global index out of range"); + + if (!push(ToExprType(globals[validateId].type))) + return false; + + if (Output) + *id = validateId; + + return true; +} + +template +inline bool +ExprIter::readSetGlobal(const GlobalDescVector& globals, uint32_t* id, Value* value) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SetVar); + + uint32_t validateId; + if (!readVarU32(&validateId)) + return false; + + if (Validate && validateId >= globals.length()) + return fail("set_global index out of range"); + + if (!topWithType(ToExprType(globals[validateId].type), value)) + return false; + + if (Output) + *id = validateId; + + return true; +} + +template +inline MOZ_MUST_USE bool +ExprIter::readI32Const(int32_t* i32) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::I32); + + int32_t unused; + return readVarS32(Output ? i32 : &unused) && + push(ExprType::I32); +} + +template +inline MOZ_MUST_USE bool +ExprIter::readI64Const(int64_t* i64) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::I64); + + int64_t unused; + return readVarS64(Output ? i64 : &unused) && + push(ExprType::I64); +} + +template +inline MOZ_MUST_USE bool +ExprIter::readF32Const(float* f32) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::F32); + + float validateF32; + if (!readFixedF32(Output ? f32 : &validateF32)) + return false; + + if (Validate && mozilla::IsNaN(Output ? *f32 : validateF32)) { + const float jsNaN = (float)JS::GenericNaN(); + if (memcmp(Output ? f32 : &validateF32, &jsNaN, sizeof(*f32)) != 0) + return notYetImplemented("NaN literals with custom payloads"); + } + + return push(ExprType::F32); +} + +template +inline MOZ_MUST_USE bool +ExprIter::readF64Const(double* f64) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::F64); + + double validateF64; + if (!readFixedF64(Output ? f64 : &validateF64)) + return false; + + if (Validate && mozilla::IsNaN(Output ? *f64 : validateF64)) { + const double jsNaN = JS::GenericNaN(); + if (memcmp(Output ? f64 : &validateF64, &jsNaN, sizeof(*f64)) != 0) + return notYetImplemented("NaN literals with custom payloads"); + } + + return push(ExprType::F64); +} + +template +inline MOZ_MUST_USE bool +ExprIter::readI32x4Const(I32x4* i32x4) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::I32x4); + + I32x4 unused; + return readFixedI32x4(Output ? i32x4 : &unused) && + push(ExprType::I32x4); +} + +template +inline MOZ_MUST_USE bool +ExprIter::readF32x4Const(F32x4* f32x4) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::F32x4); + + F32x4 unused; + return readFixedF32x4(Output ? f32x4 : &unused) && + push(ExprType::F32x4); +} + +template +inline MOZ_MUST_USE bool +ExprIter::readB32x4Const(I32x4* i32x4) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::B32x4); + + I32x4 unused; + return readFixedI32x4(Output ? i32x4 : &unused) && + push(ExprType::B32x4); +} + +template +inline bool +ExprIter::readCall(uint32_t* calleeIndex, uint32_t* arity) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Call); + + if (!readVarU32(arity)) + return fail("unable to read call arity"); + + if (!readVarU32(calleeIndex)) + return fail("unable to read call function index"); + + return true; +} + +template +inline bool +ExprIter::readCallIndirect(uint32_t* sigIndex, uint32_t* arity) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::CallIndirect); + + if (!readVarU32(arity)) + return fail("unable to read call_indirect arity"); + + if (!readVarU32(sigIndex)) + return fail("unable to read call_indirect signature index"); + + return true; +} + +template +inline bool +ExprIter::readCallImport(uint32_t* importIndex, uint32_t* arity) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::CallImport); + + if (!readVarU32(arity)) + return fail("unable to read call_import arity"); + + if (!readVarU32(importIndex)) + return fail("unable to read call_import import index"); + + return true; +} + +template +inline bool +ExprIter::readCallArg(ValType type, uint32_t numArgs, uint32_t argIndex, Value* arg) +{ + TypeAndValue tv; + if (!peek(numArgs - argIndex, &tv)) + return false; + if (!checkType(tv.type(), ToExprType(type))) + return false; + + if (Output) + *arg = tv.value(); + + return true; +} + +template +inline bool +ExprIter::readCallArgsEnd(uint32_t numArgs) +{ + MOZ_ASSERT(numArgs <= valueStack_.length()); + + valueStack_.shrinkBy(numArgs); + return true; +} + +template +inline bool +ExprIter::readCallIndirectCallee(Value* callee) +{ + return popWithType(ExprType::I32, callee); +} + +template +inline bool +ExprIter::readCallReturn(ExprType ret) +{ + return push(ret); +} + +template +inline bool +ExprIter::readAtomicLoad(LinearMemoryAddress* addr, Scalar::Type* viewType) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::AtomicLoad); + + Scalar::Type validateViewType; + if (!readAtomicViewType(&validateViewType)) + return false; + + uint32_t byteSize = Scalar::byteSize(validateViewType); + if (!readLinearMemoryAddress(byteSize, addr)) + return false; + + infalliblePush(ExprType::I32); + + if (Output) + *viewType = validateViewType; + + return true; +} + +template +inline bool +ExprIter::readAtomicStore(LinearMemoryAddress* addr, + Scalar::Type* viewType, Value* value) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::AtomicStore); + + Scalar::Type validateViewType; + if (!readAtomicViewType(&validateViewType)) + return false; + + uint32_t byteSize = Scalar::byteSize(validateViewType); + if (!readLinearMemoryAddress(byteSize, addr)) + return false; + + if (!popWithType(ExprType::I32, value)) + return false; + + infalliblePush(ExprType::I32); + + if (Output) + *viewType = validateViewType; + + return true; +} + +template +inline bool +ExprIter::readAtomicBinOp(LinearMemoryAddress* addr, Scalar::Type* viewType, + jit::AtomicOp* op, Value* value) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::AtomicBinOp); + + Scalar::Type validateViewType; + if (!readAtomicViewType(&validateViewType)) + return false; + + if (!readAtomicBinOpOp(op)) + return false; + + uint32_t byteSize = Scalar::byteSize(validateViewType); + if (!readLinearMemoryAddress(byteSize, addr)) + return false; + + if (!popWithType(ExprType::I32, value)) + return false; + + infalliblePush(ExprType::I32); + + if (Output) + *viewType = validateViewType; + + return true; +} + +template +inline bool +ExprIter::readAtomicCompareExchange(LinearMemoryAddress* addr, + Scalar::Type* viewType, + Value* oldValue, Value* newValue) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::AtomicCompareExchange); + + Scalar::Type validateViewType; + if (!readAtomicViewType(&validateViewType)) + return false; + + uint32_t byteSize = Scalar::byteSize(validateViewType); + if (!readLinearMemoryAddress(byteSize, addr)) + return false; + + if (!popWithType(ExprType::I32, newValue)) + return false; + + if (!popWithType(ExprType::I32, oldValue)) + return false; + + infalliblePush(ExprType::I32); + + if (Output) + *viewType = validateViewType; + + return true; +} + +template +inline bool +ExprIter::readAtomicExchange(LinearMemoryAddress* addr, + Scalar::Type* viewType, + Value* value) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::AtomicExchange); + + Scalar::Type validateViewType; + if (!readAtomicViewType(&validateViewType)) + return false; + + uint32_t byteSize = Scalar::byteSize(validateViewType); + if (!readLinearMemoryAddress(byteSize, addr)) + return false; + + if (!popWithType(ExprType::I32, value)) + return false; + + infalliblePush(ExprType::I32); + + if (Output) + *viewType = validateViewType; + + return true; +} + +template +inline bool +ExprIter::readSimdComparison(ValType simdType, Value* lhs, Value* rhs) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SimdComparison); + + if (!popWithType(ToExprType(simdType), rhs)) + return false; + + if (!popWithType(ToExprType(simdType), lhs)) + return false; + + infalliblePush(ToExprType(SimdBoolType(simdType))); + + return true; +} + +template +inline bool +ExprIter::readSimdShiftByScalar(ValType simdType, Value* lhs, Value* rhs) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SimdShiftByScalar); + + if (!popWithType(ExprType::I32, rhs)) + return false; + + if (!popWithType(ToExprType(simdType), lhs)) + return false; + + infalliblePush(ToExprType(simdType)); + + return true; +} + +template +inline bool +ExprIter::readSimdBooleanReduction(ValType simdType, Value* input) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SimdBooleanReduction); + + if (!popWithType(ToExprType(simdType), input)) + return false; + + infalliblePush(ExprType::I32); + + return true; +} + +template +inline bool +ExprIter::readExtractLane(ValType simdType, jit::SimdLane* lane, Value* vector) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::ExtractLane); + + uint32_t laneBits; + if (!readVarU32(&laneBits)) + return false; + if (Validate && laneBits >= NumSimdElements(simdType)) + return fail("simd lane out of bounds for simd type"); + if (Output) + *lane = jit::SimdLane(laneBits); + + if (!popWithType(ToExprType(simdType), vector)) + return false; + + infalliblePush(ToExprType(SimdElementType(simdType))); + + return true; +} + +template +inline bool +ExprIter::readReplaceLane(ValType simdType, jit::SimdLane* lane, Value* vector, + Value* scalar) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::ReplaceLane); + + uint32_t laneBits; + if (!readVarU32(&laneBits)) + return false; + if (Validate && laneBits >= NumSimdElements(simdType)) + return fail("simd lane out of bounds for simd type"); + if (Output) + *lane = jit::SimdLane(laneBits); + + if (!popWithType(ToExprType(SimdElementType(simdType)), scalar)) + return false; + + if (!popWithType(ToExprType(simdType), vector)) + return false; + + infalliblePush(ToExprType(simdType)); + + return true; +} + +template +inline bool +ExprIter::readSplat(ValType simdType, Value* scalar) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Splat); + + if (!popWithType(ToExprType(SimdElementType(simdType)), scalar)) + return false; + + infalliblePush(ToExprType(simdType)); + + return true; +} + +template +inline bool +ExprIter::readSwizzle(ValType simdType, uint8_t (* lanes)[4], Value* vector) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Swizzle); + + uint32_t numSimdLanes = NumSimdElements(simdType); + MOZ_ASSERT(numSimdLanes <= mozilla::ArrayLength(*lanes)); + for (uint32_t i = 0; i < numSimdLanes; ++i) { + uint8_t validateLane; + if (!readFixedU8(Output ? &(*lanes)[i] : &validateLane)) + return false; + if (Validate && (Output ? (*lanes)[i] : validateLane) >= numSimdLanes) + return fail("swizzle index out of bounds"); + } + + if (!popWithType(ToExprType(simdType), vector)) + return false; + + infalliblePush(ToExprType(simdType)); + + return true; +} + +template +inline bool +ExprIter::readShuffle(ValType simdType, uint8_t (* lanes)[4], Value* lhs, Value* rhs) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::Shuffle); + + uint32_t numSimdLanes = NumSimdElements(simdType); + MOZ_ASSERT(numSimdLanes <= mozilla::ArrayLength(*lanes)); + for (uint32_t i = 0; i < numSimdLanes; ++i) { + uint8_t validateLane; + if (!readFixedU8(Output ? &(*lanes)[i] : &validateLane)) + return false; + if (Validate && (Output ? (*lanes)[i] : validateLane) >= numSimdLanes * 2) + return fail("shuffle index out of bounds"); + } + + if (!popWithType(ToExprType(simdType), rhs)) + return false; + + if (!popWithType(ToExprType(simdType), lhs)) + return false; + + infalliblePush(ToExprType(simdType)); + + return true; +} + +template +inline bool +ExprIter::readSimdSelect(ValType simdType, Value* trueValue, Value* falseValue, + Value* condition) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SimdSelect); + + if (!popWithType(ToExprType(simdType), falseValue)) + return false; + if (!popWithType(ToExprType(simdType), trueValue)) + return false; + if (!popWithType(ToExprType(SimdBoolType(simdType)), condition)) + return false; + + infalliblePush(ToExprType(simdType)); + + return true; +} + +template +inline bool +ExprIter::readSimdCtor() +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SimdCtor); + + return true; +} + +template +inline bool +ExprIter::readSimdCtorArg(ValType elementType, uint32_t numElements, uint32_t index, + Value* arg) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SimdCtor); + + TypeAndValue tv; + if (!peek(numElements - index, &tv)) + return false; + if (!checkType(tv.type(), ToExprType(elementType))) + return false; + + *arg = tv.value(); + return true; +} + +template +inline bool +ExprIter::readSimdCtorArgsEnd(uint32_t numElements) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SimdCtor); + MOZ_ASSERT(numElements <= valueStack_.length()); + + valueStack_.shrinkBy(numElements); + return true; +} + +template +inline bool +ExprIter::readSimdCtorReturn(ValType simdType) +{ + MOZ_ASSERT(Classify(expr_) == ExprKind::SimdCtor); + + return push(ToExprType(simdType)); +} + +} // namespace wasm +} // namespace js + +namespace mozilla { + +// Specialize IsPod for the Nothing specializations. +template<> struct IsPod> : TrueType {}; +template<> struct IsPod> : TrueType {}; + +} // namespace mozilla + +#endif // wasm_iterator_h diff --git a/js/src/asmjs/WasmBinaryToText.cpp b/js/src/asmjs/WasmBinaryToText.cpp index 379a988160..6a29b753b6 100644 --- a/js/src/asmjs/WasmBinaryToText.cpp +++ b/js/src/asmjs/WasmBinaryToText.cpp @@ -913,6 +913,14 @@ RenderBrTable(WasmRenderContext& c) if (!c.buffer.append(" ")) return false; + // Value + if (!RenderExpr(c)) + return false; + + if (!c.buffer.append(" ")) + return false; + + // Index if (!RenderExpr(c)) return false; @@ -1000,7 +1008,7 @@ RenderExpr(WasmRenderContext& c) return RenderLoop(c); case Expr::If: return RenderIfElse(c, false); - case Expr::IfElse: + case Expr::Else: return RenderIfElse(c, true); case Expr::I32Clz: case Expr::I32Ctz: @@ -1251,10 +1259,10 @@ RenderSignature(WasmRenderContext& c, const DeclaredSig& sig, bool varAssignment } static bool -RenderSignatures(WasmRenderContext& c) +RenderTypeSection(WasmRenderContext& c) { - uint32_t sectionStart; - if (!c.d.startSection(SignaturesId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!c.d.startSection(TypeSectionId, §ionStart, §ionSize)) return RenderFail(c, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1267,6 +1275,10 @@ RenderSignatures(WasmRenderContext& c) return false; for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) { + uint32_t form; + if (!c.d.readVarU32(&form) || form != uint32_t(TypeConstructor::Function)) + return RenderFail(c, "expected function form"); + uint32_t numArgs; if (!c.d.readVarU32(&numArgs)) return RenderFail(c, "bad number of signature args"); @@ -1275,10 +1287,6 @@ RenderSignatures(WasmRenderContext& c) if (!args.resize(numArgs)) return false; - ExprType result; - if (!c.d.readExprType(&result)) - return RenderFail(c, "bad expression type"); - for (uint32_t i = 0; i < numArgs; i++) { ValType arg; if (!c.d.readValType(&arg)) @@ -1286,6 +1294,23 @@ RenderSignatures(WasmRenderContext& c) args[i] = arg; } + uint32_t numRets; + if (!c.d.readVarU32(&numRets)) + return RenderFail(c, "bad number of function returns"); + + if (numRets > 1) + return RenderFail(c, "too many returns in signature"); + + ExprType result = ExprType::Void; + + if (numRets == 1) { + ValType type; + if (!c.d.readValType(&type)) + return RenderFail(c, "bad expression type"); + + result = ToExprType(type); + } + c.signatures[sigIndex] = Sig(Move(args), result); if (!RenderIndent(c)) @@ -1302,17 +1327,17 @@ RenderSignatures(WasmRenderContext& c) return false; } - if (!c.d.finishSection(sectionStart)) + if (!c.d.finishSection(sectionStart, sectionSize)) return RenderFail(c, "decls section byte size mismatch"); return true; } static bool -RenderFunctionSignatures(WasmRenderContext& c) +RenderFunctionSection(WasmRenderContext& c) { - uint32_t sectionStart; - if (!c.d.startSection(FunctionSignaturesId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!c.d.startSection(FunctionSectionId, §ionStart, §ionSize)) return RenderFail(c, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1331,17 +1356,17 @@ RenderFunctionSignatures(WasmRenderContext& c) c.funcSigs[i] = sigIndex; } - if (!c.d.finishSection(sectionStart)) + if (!c.d.finishSection(sectionStart, sectionSize)) return RenderFail(c, "decls section byte size mismatch"); return true; } static bool -RenderFunctionTable(WasmRenderContext& c) +RenderTableSection(WasmRenderContext& c) { - uint32_t sectionStart; - if (!c.d.startSection(FunctionTableId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!c.d.startSection(TableSectionId, §ionStart, §ionSize)) return RenderFail(c, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1366,7 +1391,7 @@ RenderFunctionTable(WasmRenderContext& c) if (!c.buffer.append(")")) return false; - if (!c.d.finishSection(sectionStart)) + if (!c.d.finishSection(sectionStart, sectionSize)) return RenderFail(c, "table section byte size mismatch"); return true; @@ -1423,10 +1448,10 @@ RenderImport(WasmRenderContext& c, uint32_t importIndex) static bool -RenderImportTable(WasmRenderContext& c) +RenderImportSection(WasmRenderContext& c) { - uint32_t sectionStart; - if (!c.d.startSection(ImportTableId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!c.d.startSection(ImportSectionId, §ionStart, §ionSize)) return RenderFail(c, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1443,20 +1468,20 @@ RenderImportTable(WasmRenderContext& c) return false; } - if (!c.d.finishSection(sectionStart)) + if (!c.d.finishSection(sectionStart, sectionSize)) return RenderFail(c, "import section byte size mismatch"); return true; } static bool -RenderMemory(WasmRenderContext& c, uint32_t* memInitial, uint32_t* memMax) +RenderMemorySection(WasmRenderContext& c, uint32_t* memInitial, uint32_t* memMax) { *memInitial = 0; *memMax = 0; - uint32_t sectionStart; - if (!c.d.startSection(MemoryId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!c.d.startSection(MemorySectionId, §ionStart, §ionSize)) return RenderFail(c, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1475,7 +1500,7 @@ RenderMemory(WasmRenderContext& c, uint32_t* memInitial, uint32_t* memMax) if (!c.d.readFixedU8(&exported)) return RenderFail(c, "expected exported byte"); - if (!c.d.finishSection(sectionStart)) + if (!c.d.finishSection(sectionStart, sectionSize)) return RenderFail(c, "memory section byte size mismatch"); if (exported && !c.buffer.append("(export \"memory\" memory)")) @@ -1528,10 +1553,10 @@ RenderFunctionExport(WasmRenderContext& c) } static bool -RenderExportTable(WasmRenderContext& c) +RenderExportSection(WasmRenderContext& c) { - uint32_t sectionStart; - if (!c.d.startSection(ExportTableId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!c.d.startSection(ExportSectionId, §ionStart, §ionSize)) return RenderFail(c, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; @@ -1545,7 +1570,7 @@ RenderExportTable(WasmRenderContext& c) return false; } - if (!c.d.finishSection(sectionStart)) + if (!c.d.finishSection(sectionStart, sectionSize)) return RenderFail(c, "export section byte size mismatch"); return true; @@ -1612,10 +1637,10 @@ RenderFunctionBody(WasmRenderContext& c, uint32_t funcIndex, uint32_t paramsNum) } static bool -RenderFunctionBodies(WasmRenderContext& c) +RenderCodeSection(WasmRenderContext& c) { - uint32_t sectionStart; - if (!c.d.startSection(FunctionBodiesId, §ionStart)) + uint32_t sectionStart, sectionSize; + if (!c.d.startSection(CodeSectionId, §ionStart, §ionSize)) return RenderFail(c, "failed to start section"); if (sectionStart == Decoder::NotStarted) @@ -1656,7 +1681,7 @@ RenderFunctionBodies(WasmRenderContext& c) return false; } - if (!c.d.finishSection(sectionStart)) + if (!c.d.finishSection(sectionStart, sectionSize)) return RenderFail(c, "function section byte size mismatch"); return true; @@ -1664,7 +1689,7 @@ RenderFunctionBodies(WasmRenderContext& c) static bool -RenderDataSegments(WasmRenderContext& c, uint32_t memInitial, uint32_t memMax) +RenderDataSection(WasmRenderContext& c, uint32_t memInitial, uint32_t memMax) { if (!RenderIndent(c)) return false; @@ -1681,7 +1706,8 @@ RenderDataSegments(WasmRenderContext& c, uint32_t memInitial, uint32_t memMax) c.indent++; uint32_t sectionStart; - if (!c.d.startSection(DataSegmentsId, §ionStart)) + uint32_t sectionSize; + if (!c.d.startSection(DataSectionId, §ionStart, §ionSize)) return RenderFail(c, "failed to start section"); if (sectionStart == Decoder::NotStarted) { if (!c.buffer.append(")\n")) @@ -1723,7 +1749,7 @@ RenderDataSegments(WasmRenderContext& c, uint32_t memInitial, uint32_t memMax) return false; } - if (!c.d.finishSection(sectionStart)) + if (!c.d.finishSection(sectionStart, sectionSize)) return RenderFail(c, "data section byte size mismatch"); c.indent--; @@ -1748,29 +1774,29 @@ RenderModule(WasmRenderContext& c) c.indent++; - if (!RenderSignatures(c)) + if (!RenderTypeSection(c)) return false; - if (!RenderImportTable(c)) + if (!RenderImportSection(c)) return false; - if (!RenderFunctionSignatures(c)) + if (!RenderFunctionSection(c)) return false; - if (!RenderFunctionTable(c)) + if (!RenderTableSection(c)) return false; uint32_t memInitial, memMax; - if (!RenderMemory(c, &memInitial, &memMax)) + if (!RenderMemorySection(c, &memInitial, &memMax)) return false; - if (!RenderExportTable(c)) + if (!RenderExportSection(c)) return false; - if (!RenderFunctionBodies(c)) + if (!RenderCodeSection(c)) return false; - if (!RenderDataSegments(c, memInitial, memMax)) + if (!RenderDataSection(c, memInitial, memMax)) return false; c.indent--; @@ -1791,7 +1817,11 @@ wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuf WasmRenderContext c(cx, d, buffer); - if (!RenderModule(c)) { + if (!c.buffer.append("Binary-to-text is temporarily unavailable\n")) + return false; + + // FIXME: Implement binary-to-text and re-enable this. + if (0 && !RenderModule(c)) { if (!cx->isExceptionPending()) ReportOutOfMemory(cx); return false; diff --git a/js/src/asmjs/WasmGenerator.cpp b/js/src/asmjs/WasmGenerator.cpp index 855456835b..b2cf87fec9 100644 --- a/js/src/asmjs/WasmGenerator.cpp +++ b/js/src/asmjs/WasmGenerator.cpp @@ -20,6 +20,7 @@ #include "mozilla/EnumeratedRange.h" +#include "asmjs/WasmIonCompile.h" #include "asmjs/WasmStubs.h" #include "jit/MacroAssembler-inl.h" @@ -54,7 +55,8 @@ ModuleGenerator::ModuleGenerator(ExclusiveContext* cx) tasks_(cx), freeTasks_(cx), activeFunc_(nullptr), - finishedFuncs_(false) + startedFuncDefs_(false), + finishedFuncDefs_(false) { MOZ_ASSERT(IsCompilingAsmJS()); } @@ -563,9 +565,9 @@ ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* g } bool -ModuleGenerator::allocateGlobalVar(ValType type, bool isConst, uint32_t* index) +ModuleGenerator::allocateGlobal(ValType type, bool isConst, uint32_t* index) { - MOZ_ASSERT(!startedFuncDefs()); + MOZ_ASSERT(!startedFuncDefs_); unsigned width = 0; switch (type) { case ValType::I32: @@ -591,7 +593,7 @@ ModuleGenerator::allocateGlobalVar(ValType type, bool isConst, uint32_t* index) return false; *index = shared_->globals.length(); - return shared_->globals.append(AsmJSGlobalVariable(ToExprType(type), offset, isConst)); + return shared_->globals.append(GlobalDesc(type, offset, isConst)); } void @@ -731,10 +733,8 @@ ModuleGenerator::addMemoryExport(UniqueChars fieldName) bool ModuleGenerator::startFuncDefs() { - MOZ_ASSERT(!startedFuncDefs()); - threadView_ = MakeUnique(*shared_); - if (!threadView_) - return false; + MOZ_ASSERT(!startedFuncDefs_); + MOZ_ASSERT(!finishedFuncDefs_); uint32_t numTasks; if (ParallelCompilationEnabled(cx_) && @@ -759,23 +759,24 @@ ModuleGenerator::startFuncDefs() return false; JSRuntime* rt = cx_->compartment()->runtimeFromAnyThread(); for (size_t i = 0; i < numTasks; i++) - tasks_.infallibleEmplaceBack(rt, *threadView_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE); + tasks_.infallibleEmplaceBack(rt, *shared_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE); if (!freeTasks_.reserve(numTasks)) return false; for (size_t i = 0; i < numTasks; i++) freeTasks_.infallibleAppend(&tasks_[i]); - MOZ_ASSERT(startedFuncDefs()); + startedFuncDefs_ = true; + MOZ_ASSERT(!finishedFuncDefs_); return true; } bool ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg) { - MOZ_ASSERT(startedFuncDefs()); + MOZ_ASSERT(startedFuncDefs_); MOZ_ASSERT(!activeFunc_); - MOZ_ASSERT(!finishedFuncs_); + MOZ_ASSERT(!finishedFuncDefs_); if (freeTasks_.empty() && !finishOutstandingTask()) return false; @@ -827,9 +828,9 @@ ModuleGenerator::finishFuncDef(uint32_t funcIndex, unsigned generateTime, Functi bool ModuleGenerator::finishFuncDefs() { - MOZ_ASSERT(startedFuncDefs()); + MOZ_ASSERT(startedFuncDefs_); MOZ_ASSERT(!activeFunc_); - MOZ_ASSERT(!finishedFuncs_); + MOZ_ASSERT(!finishedFuncDefs_); while (outstanding_ > 0) { if (!finishOutstandingTask()) @@ -840,7 +841,7 @@ ModuleGenerator::finishFuncDefs() MOZ_ASSERT(funcIsDefined(funcIndex)); module_->functionBytes = masm_.size(); - finishedFuncs_ = true; + finishedFuncDefs_ = true; return true; } @@ -883,7 +884,7 @@ ModuleGenerator::finish(CacheableCharsVector&& prettyFuncNames, SlowFunctionVector* slowFuncs) { MOZ_ASSERT(!activeFunc_); - MOZ_ASSERT(finishedFuncs_); + MOZ_ASSERT(finishedFuncDefs_); UniqueStaticLinkData link = MakeUnique(); if (!link) diff --git a/js/src/asmjs/WasmGenerator.h b/js/src/asmjs/WasmGenerator.h index 31cb12f9a3..dc83723b55 100644 --- a/js/src/asmjs/WasmGenerator.h +++ b/js/src/asmjs/WasmGenerator.h @@ -20,7 +20,6 @@ #define wasm_generator_h #include "asmjs/WasmBinary.h" -#include "asmjs/WasmIonCompile.h" #include "asmjs/WasmModule.h" #include "jit/MacroAssembler.h" @@ -47,12 +46,11 @@ struct SlowFunction typedef Vector SlowFunctionVector; // The ModuleGeneratorData holds all the state shared between the -// ModuleGenerator and ModuleGeneratorThreadView. The ModuleGeneratorData -// is encapsulated by ModuleGenerator/ModuleGeneratorThreadView classes which -// present a race-free interface to the code in each thread assuming any given -// element is initialized by the ModuleGenerator thread before an index to that -// element is written to Bytes sent to a ModuleGeneratorThreadView thread. -// Once created, the Vectors are never resized. +// ModuleGenerator thread and background compile threads. The background +// threads are given a read-only view of the ModuleGeneratorData and the +// ModuleGenerator is careful to initialize, and never subsequently mutate, +// any given datum before being read by a background thread. In particular, +// once created, the Vectors are never resized. struct TableModuleGeneratorData { @@ -82,18 +80,6 @@ struct ImportModuleGeneratorData typedef Vector ImportModuleGeneratorDataVector; -struct AsmJSGlobalVariable -{ - ExprType type; - unsigned globalDataOffset; - bool isConst; - AsmJSGlobalVariable(ExprType type, unsigned offset, bool isConst) - : type(type), globalDataOffset(offset), isConst(isConst) - {} -}; - -typedef Vector AsmJSGlobalVariableVector; - struct ModuleGeneratorData { CompileArgs args; @@ -105,7 +91,7 @@ struct ModuleGeneratorData TableModuleGeneratorDataVector sigToTable; DeclaredSigPtrVector funcSigs; ImportModuleGeneratorDataVector imports; - AsmJSGlobalVariableVector globals; + GlobalDescVector globals; uint32_t funcSigIndex(uint32_t funcIndex) const { return funcSigs[funcIndex] - sigs.begin(); @@ -118,51 +104,6 @@ struct ModuleGeneratorData typedef UniquePtr UniqueModuleGeneratorData; -// The ModuleGeneratorThreadView class presents a restricted, read-only view of -// the shared state needed by helper threads. There is only one -// ModuleGeneratorThreadView object owned by ModuleGenerator and referenced by -// all compile tasks. - -class ModuleGeneratorThreadView -{ - const ModuleGeneratorData& shared_; - - public: - explicit ModuleGeneratorThreadView(const ModuleGeneratorData& shared) - : shared_(shared) - {} - CompileArgs args() const { - return shared_.args; - } - bool isAsmJS() const { - return shared_.kind == ModuleKind::AsmJS; - } - uint32_t numTableElems() const { - MOZ_ASSERT(!isAsmJS()); - return shared_.numTableElems; - } - uint32_t minHeapLength() const { - return shared_.minHeapLength; - } - const DeclaredSig& sig(uint32_t sigIndex) const { - return shared_.sigs[sigIndex]; - } - const TableModuleGeneratorData& sigToTable(uint32_t sigIndex) const { - return shared_.sigToTable[sigIndex]; - } - const DeclaredSig& funcSig(uint32_t funcIndex) const { - MOZ_ASSERT(shared_.funcSigs[funcIndex]); - return *shared_.funcSigs[funcIndex]; - } - const ImportModuleGeneratorData& import(uint32_t importIndex) const { - MOZ_ASSERT(shared_.imports[importIndex].sig); - return shared_.imports[importIndex]; - } - const AsmJSGlobalVariable& globalVar(uint32_t globalIndex) const { - return shared_.globals[globalIndex]; - } -}; - // A ModuleGenerator encapsulates the creation of a wasm module. During the // lifetime of a ModuleGenerator, a sequence of FunctionGenerators are created // and destroyed to compile the individual function bodies. After generating all @@ -171,7 +112,6 @@ class ModuleGeneratorThreadView class MOZ_STACK_CLASS ModuleGenerator { - typedef UniquePtr UniqueModuleGeneratorThreadView; typedef HashMap FuncIndexMap; ExclusiveContext* cx_; @@ -197,13 +137,13 @@ class MOZ_STACK_CLASS ModuleGenerator // Parallel compilation bool parallel_; uint32_t outstanding_; - UniqueModuleGeneratorThreadView threadView_; Vector tasks_; Vector freeTasks_; // Assertions - FunctionGenerator* activeFunc_; - bool finishedFuncs_; + DebugOnly activeFunc_; + DebugOnly startedFuncDefs_; + DebugOnly finishedFuncDefs_; bool finishOutstandingTask(); bool funcIsDefined(uint32_t funcIndex) const; @@ -213,7 +153,6 @@ class MOZ_STACK_CLASS ModuleGenerator bool finishCodegen(StaticLinkData* link); bool finishStaticLinkData(uint8_t* code, uint32_t codeBytes, StaticLinkData* link); bool addImport(const Sig& sig, uint32_t globalDataOffset); - bool startedFuncDefs() const { return !!threadView_; } bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset); public: @@ -238,6 +177,10 @@ class MOZ_STACK_CLASS ModuleGenerator uint32_t numFuncSigs() const { return module_->numFuncs; } const DeclaredSig& funcSig(uint32_t funcIndex) const; + // Globals: + bool allocateGlobal(ValType type, bool isConst, uint32_t* index); + const GlobalDesc& global(unsigned index) const { return shared_->globals[index]; } + // Imports: uint32_t numImports() const; const ImportModuleGeneratorData& import(uint32_t index) const; @@ -264,10 +207,6 @@ class MOZ_STACK_CLASS ModuleGenerator void initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices); void bumpMinHeapLength(uint32_t newMinHeapLength); - // asm.js global variables: - bool allocateGlobalVar(ValType type, bool isConst, uint32_t* index); - const AsmJSGlobalVariable& globalVar(unsigned index) const { return shared_->globals[index]; } - // Return a ModuleData object which may be used to construct a Module, the // StaticLinkData required to call Module::staticallyLink, and the list of // functions that took a long time to compile. diff --git a/js/src/asmjs/WasmIonCompile.cpp b/js/src/asmjs/WasmIonCompile.cpp index ad8c7c52ba..7cadc86d96 100644 --- a/js/src/asmjs/WasmIonCompile.cpp +++ b/js/src/asmjs/WasmIonCompile.cpp @@ -18,6 +18,7 @@ #include "asmjs/WasmIonCompile.h" +#include "asmjs/WasmBinaryIterator.h" #include "asmjs/WasmGenerator.h" #include "jit/CodeGenerator.h" @@ -29,8 +30,24 @@ using namespace js::wasm; using mozilla::DebugOnly; using mozilla::Maybe; +namespace { + typedef Vector BlockVector; +struct IonCompilePolicy : ExprIterPolicy +{ + // Producing output is what we're all about here. + static const bool Output = true; + + // We store SSA definitions in the value stack. + typedef MDefinition* Value; + + // We store loop headers and then/else blocks in the control flow stack. + typedef MBasicBlock* ControlItem; +}; + +typedef ExprIter IonExprIter; + // Encapsulates the compilation of a single function in an asm.js module. The // function compiler handles the creation and final backend compilation of the // MIR graph. @@ -55,8 +72,8 @@ class FunctionCompiler private: typedef Vector CallVector; - ModuleGeneratorThreadView& mg_; - Decoder& decoder_; + const ModuleGeneratorData& mg_; + IonExprIter iter_; const FuncBytes& func_; const ValTypeVector& locals_; size_t lastReadCallSite_; @@ -77,14 +94,14 @@ class FunctionCompiler FuncCompileResults& compileResults_; public: - FunctionCompiler(ModuleGeneratorThreadView& mg, + FunctionCompiler(const ModuleGeneratorData& mg, Decoder& decoder, const FuncBytes& func, const ValTypeVector& locals, MIRGenerator& mirGen, FuncCompileResults& compileResults) : mg_(mg), - decoder_(decoder), + iter_(IonCompilePolicy(), decoder), func_(func), locals_(locals), lastReadCallSite_(0), @@ -99,7 +116,8 @@ class FunctionCompiler compileResults_(compileResults) {} - ModuleGeneratorThreadView& mg() const { return mg_; } + const ModuleGeneratorData& mg() const { return mg_; } + IonExprIter& iter() { return iter_; } TempAllocator& alloc() const { return alloc_; } MacroAssembler& masm() const { return compileResults_.masm(); } const Sig& sig() const { return func_.sig(); } @@ -127,26 +145,26 @@ class FunctionCompiler MInstruction* ins = nullptr; switch (locals_[i]) { case ValType::I32: - ins = MConstant::NewAsmJS(alloc(), Int32Value(0), MIRType_Int32); + ins = MConstant::NewAsmJS(alloc(), Int32Value(0), MIRType::Int32); break; case ValType::I64: ins = MConstant::NewInt64(alloc(), 0); break; case ValType::F32: - ins = MConstant::NewAsmJS(alloc(), Float32Value(0.f), MIRType_Float32); + ins = MConstant::NewAsmJS(alloc(), Float32Value(0.f), MIRType::Float32); break; case ValType::F64: - ins = MConstant::NewAsmJS(alloc(), DoubleValue(0.0), MIRType_Double); + ins = MConstant::NewAsmJS(alloc(), DoubleValue(0.0), MIRType::Double); break; case ValType::I32x4: - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType_Int32x4); + ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType::Int32x4); break; case ValType::F32x4: - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0.f), MIRType_Float32x4); + ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0.f), MIRType::Float32x4); break; case ValType::B32x4: // Bool32x4 uses the same data layout as Int32x4. - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType_Bool32x4); + ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType::Bool32x4); break; case ValType::Limit: MOZ_CRASH("Limit"); @@ -176,7 +194,7 @@ class FunctionCompiler } #endif MOZ_ASSERT(inDeadCode()); - MOZ_ASSERT(decoder_.done(), "all bytes must be consumed"); + MOZ_ASSERT(done(), "all bytes must be consumed"); MOZ_ASSERT(func_.callSiteLineNums().length() == lastReadCallSite_); } @@ -193,7 +211,7 @@ class FunctionCompiler return curBlock_->getSlot(info().localSlot(slot)); } - ValType localType(unsigned slot) const { return locals_[slot]; } + const ValTypeVector& locals() const { return locals_; } /***************************** Code generation (after local scope setup) */ @@ -376,7 +394,7 @@ class FunctionCompiler if (inDeadCode()) return nullptr; - MSimdAllTrue* ins = MSimdAllTrue::New(alloc(), boolVector, MIRType_Int32); + MSimdAllTrue* ins = MSimdAllTrue::New(alloc(), boolVector, MIRType::Int32); curBlock_->add(ins); return ins; } @@ -386,7 +404,7 @@ class FunctionCompiler if (inDeadCode()) return nullptr; - MSimdAnyTrue* ins = MSimdAnyTrue::New(alloc(), boolVector, MIRType_Int32); + MSimdAnyTrue* ins = MSimdAnyTrue::New(alloc(), boolVector, MIRType::Int32); curBlock_->add(ins); return ins; } @@ -508,11 +526,11 @@ class FunctionCompiler return ins; } - MDefinition* reinterpret(MDefinition* op, MIRType to) + MDefinition* rotate(MDefinition* input, MDefinition* count, MIRType type, bool left) { if (inDeadCode()) return nullptr; - auto* ins = MAsmReinterpret::New(alloc(), op, to); + auto* ins = MRotate::NewAsmJS(alloc(), input, count, type, left); curBlock_->add(ins); return ins; } @@ -543,8 +561,7 @@ class FunctionCompiler curBlock_->setSlot(info().localSlot(slot), def); } - MDefinition* loadHeap(MDefinition* base, - const MAsmJSHeapAccess& access) + MDefinition* loadHeap(MDefinition* base, const MAsmJSHeapAccess& access) { if (inDeadCode()) return nullptr; @@ -665,7 +682,7 @@ class FunctionCompiler void addInterruptCheck() { - if (mg_.args().useSignalHandlersForInterrupt) + if (mg_.args.useSignalHandlersForInterrupt) return; if (inDeadCode()) @@ -847,11 +864,11 @@ class FunctionCompiler } MAsmJSLoadFuncPtr* ptrFun; - if (mg().isAsmJS()) { + if (mg().kind == ModuleKind::AsmJS) { MOZ_ASSERT(IsPowerOfTwo(length)); MConstant* mask = MConstant::New(alloc(), Int32Value(length - 1)); curBlock_->add(mask); - MBitAnd* maskedIndex = MBitAnd::NewAsmJS(alloc(), index, mask, MIRType_Int32); + MBitAnd* maskedIndex = MBitAnd::NewAsmJS(alloc(), index, mask, MIRType::Int32); curBlock_->add(maskedIndex); ptrFun = MAsmJSLoadFuncPtr::New(alloc(), maskedIndex, globalDataOffset); curBlock_->add(ptrFun); @@ -861,10 +878,10 @@ class FunctionCompiler // However, these signatures may still be called (it is not a validation error) // so we instead have a flag alwaysThrow which throws an exception instead of loading // the function pointer from the (non-existant) array. - MOZ_ASSERT(!length || length == mg_.numTableElems()); + MOZ_ASSERT(!length || length == mg_.numTableElems); bool alwaysThrow = !length; - ptrFun = MAsmJSLoadFuncPtr::New(alloc(), index, mg_.numTableElems(), alwaysThrow, + ptrFun = MAsmJSLoadFuncPtr::New(alloc(), index, mg_.numTableElems, alwaysThrow, globalDataOffset); curBlock_->add(ptrFun); } @@ -924,32 +941,6 @@ class FunctionCompiler curBlock_ = nullptr; } - bool branchAndStartThen(MDefinition* cond, MBasicBlock** thenBlock, MBasicBlock** elseBlock) - { - if (inDeadCode()) - return true; - - bool hasThenBlock = *thenBlock != nullptr; - bool hasElseBlock = *elseBlock != nullptr; - - if (!hasThenBlock && !newBlock(curBlock_, thenBlock)) - return false; - if (!hasElseBlock && !newBlock(curBlock_, elseBlock)) - return false; - - curBlock_->end(MTest::New(alloc(), cond, *thenBlock, *elseBlock)); - - // Only add as a predecessor if newBlock hasn't been called (as it does it for us) - if (hasThenBlock && !(*thenBlock)->addPredecessor(alloc(), curBlock_)) - return false; - if (hasElseBlock && !(*elseBlock)->addPredecessor(alloc(), curBlock_)) - return false; - - curBlock_ = *thenBlock; - mirGraph().moveBlockToEnd(curBlock_); - return true; - } - private: static bool hasPushed(MBasicBlock* block) { @@ -970,7 +961,7 @@ class FunctionCompiler if (inDeadCode()) return; MOZ_ASSERT(!hasPushed(curBlock_)); - if (def && def->type() != MIRType_None) + if (def && def->type() != MIRType::None) curBlock_->push(def); } @@ -979,7 +970,7 @@ class FunctionCompiler if (!hasPushed(curBlock_)) return nullptr; MDefinition* def = curBlock_->pop(); - MOZ_ASSERT(def->type() != MIRType_Value); + MOZ_ASSERT(def->type() != MIRType::Value); return def; } @@ -1013,52 +1004,93 @@ class FunctionCompiler } } - bool joinIf(MBasicBlock* joinBlock, BlockVector* blocks, MDefinition** def) - { - MOZ_ASSERT_IF(curBlock_, blocks->back() == curBlock_); - curBlock_ = joinBlock; - return joinIfElse(nullptr, blocks, def); - } - - void switchToElse(MBasicBlock* elseBlock) - { - if (!elseBlock) - return; - curBlock_ = elseBlock; - mirGraph().moveBlockToEnd(curBlock_); - } - - bool addJoinPredecessor(MDefinition* def, BlockVector* blocks) + private: + void addJoinPredecessor(MDefinition* def, MBasicBlock** joinPred) { + *joinPred = curBlock_; if (inDeadCode()) - return true; + return; pushDef(def); - return blocks->append(curBlock_); } - bool joinIfElse(MDefinition* elseDef, BlockVector* blocks, MDefinition** def) + public: + bool branchAndStartThen(MDefinition* cond, MBasicBlock** elseBlock) { - if (!addJoinPredecessor(elseDef, blocks)) - return false; - - auto getBlock = [&](size_t i) -> MBasicBlock* { return (*blocks)[i]; }; - ensurePushInvariants(getBlock, blocks->length()); - - if (blocks->empty()) { - *def = nullptr; - return true; - } - - MBasicBlock* join; - if (!goToNewBlock((*blocks)[0], &join)) - return false; - for (size_t i = 1; i < blocks->length(); i++) { - if (!goToExistingBlock((*blocks)[i], join)) + if (inDeadCode()) { + *elseBlock = nullptr; + } else { + MBasicBlock* thenBlock; + if (!newBlock(curBlock_, &thenBlock)) return false; + if (!newBlock(curBlock_, elseBlock)) + return false; + + curBlock_->end(MTest::New(alloc(), cond, thenBlock, *elseBlock)); + + curBlock_ = thenBlock; + mirGraph().moveBlockToEnd(curBlock_); + } + + return startBlock(); + } + + bool switchToElse(MBasicBlock* elseBlock, MBasicBlock** thenJoinPred) + { + MDefinition* ifDef; + if (!finishBlock(&ifDef)) + return false; + + if (!elseBlock) { + *thenJoinPred = nullptr; + } else { + addJoinPredecessor(ifDef, thenJoinPred); + + curBlock_ = elseBlock; + mirGraph().moveBlockToEnd(curBlock_); + } + + return startBlock(); + } + + bool joinIfElse(MBasicBlock* thenJoinPred, MDefinition** def) + { + MDefinition* elseDef; + if (!finishBlock(&elseDef)) + return false; + + if (!thenJoinPred && inDeadCode()) { + *def = nullptr; + } else { + MBasicBlock* elseJoinPred; + addJoinPredecessor(elseDef, &elseJoinPred); + + mozilla::Array blocks; + size_t numJoinPreds = 0; + if (thenJoinPred) + blocks[numJoinPreds++] = thenJoinPred; + if (elseJoinPred) + blocks[numJoinPreds++] = elseJoinPred; + + auto getBlock = [&](size_t i) -> MBasicBlock* { return blocks[i]; }; + ensurePushInvariants(getBlock, numJoinPreds); + + if (numJoinPreds == 0) { + *def = nullptr; + return true; + } + + MBasicBlock* join; + if (!goToNewBlock(blocks[0], &join)) + return false; + for (size_t i = 1; i < numJoinPreds; ++i) { + if (!goToExistingBlock(blocks[i], join)) + return false; + } + + curBlock_ = join; + *def = popDefIfPushed(); } - curBlock_ = join; - *def = popDefIfPushed(); return true; } @@ -1262,7 +1294,8 @@ class FunctionCompiler return true; } - bool brTable(MDefinition* expr, uint32_t defaultDepth, const Uint32Vector& depths) + bool brTable(MDefinition* expr, uint32_t defaultDepth, const Uint32Vector& depths, + MDefinition* maybeValue) { if (inDeadCode()) return true; @@ -1306,6 +1339,8 @@ class FunctionCompiler return false; } + pushDef(maybeValue); + curBlock_->end(table); curBlock_ = nullptr; @@ -1314,38 +1349,13 @@ class FunctionCompiler /************************************************************ DECODING ***/ - uint8_t readU8() { return decoder_.uncheckedReadFixedU8(); } - uint32_t readU32() { return decoder_.uncheckedReadFixedU32(); } - uint32_t readVarS32() { return decoder_.uncheckedReadVarS32(); } - uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); } - uint64_t readVarU64() { return decoder_.uncheckedReadVarU64(); } - uint64_t readVarS64() { return decoder_.uncheckedReadVarS64(); } - float readF32() { return decoder_.uncheckedReadFixedF32(); } - double readF64() { return decoder_.uncheckedReadFixedF64(); } - Expr readExpr() { return decoder_.uncheckedReadExpr(); } - Expr peakExpr() { return decoder_.uncheckedPeekExpr(); } - - SimdConstant readI32X4() { - I32x4 i32x4; - JS_ALWAYS_TRUE(decoder_.readFixedI32x4(&i32x4)); - return SimdConstant::CreateX4(i32x4); - } - SimdConstant readF32X4() { - F32x4 f32x4; - JS_ALWAYS_TRUE(decoder_.readFixedF32x4(&f32x4)); - return SimdConstant::CreateX4(f32x4); - } - - uint32_t currentOffset() const { - return decoder_.currentOffset(); - } uint32_t readCallSiteLineOrBytecode(uint32_t callOffset) { if (!func_.callSiteLineNums().empty()) return func_.callSiteLineNums()[lastReadCallSite_++]; return callOffset; } - bool done() const { return decoder_.done(); } + bool done() const { return iter_.done(); } /*************************************************************************/ private: @@ -1428,99 +1438,620 @@ class FunctionCompiler } }; +} // end anonymous namespace + static bool -EmitLiteral(FunctionCompiler& f, ValType type, MDefinition** def) +EmitBlock(FunctionCompiler& f) { - switch (type) { - case ValType::I32: { - int32_t val = f.readVarS32(); - *def = f.constant(Int32Value(val), MIRType_Int32); - return true; - } - case ValType::I64: { - int64_t val = f.readVarS64(); - *def = f.constant(val); - return true; - } - case ValType::F32: { - float val = f.readF32(); - *def = f.constant(Float32Value(val), MIRType_Float32); - return true; - } - case ValType::F64: { - double val = f.readF64(); - *def = f.constant(DoubleValue(val), MIRType_Double); - return true; - } - case ValType::I32x4: { - SimdConstant lit(f.readI32X4()); - *def = f.constant(lit, MIRType_Int32x4); - return true; - } - case ValType::F32x4: { - SimdConstant lit(f.readF32X4()); - *def = f.constant(lit, MIRType_Float32x4); - return true; - } - case ValType::B32x4: { - // Boolean vectors are stored as an Int vector with -1 / 0 lanes. - SimdConstant lit(f.readI32X4()); - *def = f.constant(lit, MIRType_Bool32x4); - return true; - } - case ValType::Limit: + return f.iter().readBlock() && + f.startBlock(); +} + +static bool +EmitLoop(FunctionCompiler& f) +{ + if (!f.iter().readLoop()) + return false; + + MBasicBlock *loopHeader; + if (!f.startLoop(&loopHeader)) + return false; + + f.addInterruptCheck(); + + f.iter().controlItem() = loopHeader; + return true; +} + +static bool +EmitIf(FunctionCompiler& f) +{ + MDefinition* condition; + if (!f.iter().readIf(&condition)) + return false; + + MBasicBlock* elseBlock; + if (!f.branchAndStartThen(condition, &elseBlock)) + return false; + + f.iter().controlItem() = elseBlock; + return true; +} + +static bool +EmitElse(FunctionCompiler& f) +{ + MBasicBlock *block = f.iter().controlItem(); + + ExprType thenType; + MDefinition* thenValue; + if (!f.iter().readElse(&thenType, &thenValue)) + return false; + + if (!IsVoid(thenType)) + f.pushDef(thenValue); + + if (!f.switchToElse(block, &f.iter().controlItem())) + return false; + + return true; +} + +static bool +EmitEnd(FunctionCompiler& f) +{ + MBasicBlock *block = f.iter().controlItem(); + + LabelKind kind; + ExprType type; + MDefinition* value; + if (!f.iter().readEnd(&kind, &type, &value)) + return false; + + if (!IsVoid(type)) + f.pushDef(value); + + MDefinition* def; + switch (kind) { + case LabelKind::Block: + if (!f.finishBlock(&def)) + return false; + break; + case LabelKind::Loop: + if (!f.closeLoop(block, &def)) + return false; + break; + case LabelKind::Then: + // If we didn't see an Else, create a trivial else block so that we create + // a diamond anyway, to preserve Ion invariants. + if (!f.switchToElse(block, &block)) + return false; + + if (!f.joinIfElse(block, &def)) + return false; + break; + case LabelKind::Else: + if (!f.joinIfElse(block, &def)) + return false; break; } - MOZ_CRASH("unexpected literal type"); -} -static bool -EmitGetLocal(FunctionCompiler& f, MDefinition** def) -{ - uint32_t slot = f.readVarU32(); - *def = f.getLocalDef(slot); + f.iter().setResult(def); return true; } static bool -EmitLoadGlobal(FunctionCompiler& f, MDefinition** def) +EmitBr(FunctionCompiler& f) { - uint32_t index = f.readVarU32(); - const AsmJSGlobalVariable& global = f.mg().globalVar(index); - *def = f.loadGlobalVar(global.globalDataOffset, global.isConst, ToMIRType(global.type)); - return true; -} - -static bool EmitExpr(FunctionCompiler&, MDefinition**); - -static bool -EmitHeapAddress(FunctionCompiler& f, MDefinition** base, MAsmJSHeapAccess* access) -{ - uint32_t alignLog2 = f.readVarU32(); - access->setAlign(1 << alignLog2); - - uint32_t offset = f.readVarU32(); - access->setOffset(offset); - - if (!EmitExpr(f, base)) + uint32_t relativeDepth; + ExprType type; + MDefinition* value; + if (!f.iter().readBr(&relativeDepth, &type, &value)) return false; - if (f.mg().isAsmJS()) { - MOZ_ASSERT(offset == 0 && "asm.js validation does not produce load/store offsets"); + if (IsVoid(type)) { + if (!f.br(relativeDepth, nullptr)) + return false; + } else { + if (!f.br(relativeDepth, value)) + return false; + } + + return true; +} + +static bool +EmitBrIf(FunctionCompiler& f) +{ + uint32_t relativeDepth; + ExprType type; + MDefinition* value; + MDefinition* condition; + if (!f.iter().readBrIf(&relativeDepth, &type, &value, &condition)) + return false; + + if (IsVoid(type)) { + if (!f.brIf(relativeDepth, nullptr, condition)) + return false; + } else { + if (!f.brIf(relativeDepth, value, condition)) + return false; + } + + return true; +} + +static bool +EmitBrTable(FunctionCompiler& f) +{ + uint32_t tableLength; + ExprType type; + MDefinition* value; + MDefinition* index; + if (!f.iter().readBrTable(&tableLength, &type, &value, &index)) + return false; + + Uint32Vector depths; + if (!depths.reserve(tableLength)) + return false; + + uint32_t depth; + for (size_t i = 0; i < tableLength; ++i) { + if (!f.iter().readBrTableEntry(type, &depth)) + return false; + depths.infallibleAppend(depth); + } + + // Read the default label. + if (!f.iter().readBrTableEntry(type, &depth)) + return false; + + MDefinition* maybeValue = IsVoid(type) ? nullptr : value; + + if (tableLength == 0) + return f.br(depth, maybeValue); + + return f.brTable(index, depth, depths, maybeValue); +} + +static bool +EmitReturn(FunctionCompiler& f) +{ + MDefinition* value; + if (!f.iter().readReturn(&value)) + return false; + + if (IsVoid(f.sig().ret())) { + f.returnVoid(); return true; } + f.returnExpr(value); + return true; +} + +static bool +EmitCallArgs(FunctionCompiler& f, const Sig& sig, FunctionCompiler::Call* ionCall) +{ + if (!f.startCallArgs(ionCall)) + return false; + + MDefinition* arg; + const ValTypeVector& args = sig.args(); + uint32_t numArgs = args.length(); + for (size_t i = 0; i < numArgs; ++i) { + ValType argType = args[i]; + if (!f.iter().readCallArg(argType, numArgs, i, &arg)) + return false; + if (!f.passArg(arg, argType, ionCall)) + return false; + } + + if (!f.iter().readCallArgsEnd(numArgs)) + return false; + + f.finishCallArgs(ionCall); + return true; +} + +static bool +EmitCall(FunctionCompiler& f, uint32_t callOffset) +{ + uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); + + uint32_t calleeIndex; + uint32_t arity; + if (!f.iter().readCall(&calleeIndex, &arity)) + return false; + + const Sig& sig = *f.mg().funcSigs[calleeIndex]; + + FunctionCompiler::Call ionCall(f, lineOrBytecode); + if (!EmitCallArgs(f, sig, &ionCall)) + return false; + + if (!f.iter().readCallReturn(sig.ret())) + return false; + + MDefinition* def; + if (!f.internalCall(sig, calleeIndex, ionCall, &def)) + return false; + + if (IsVoid(sig.ret())) + return true; + + f.iter().setResult(def); + return true; +} + +static bool +EmitCallIndirect(FunctionCompiler& f, uint32_t callOffset) +{ + uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); + + uint32_t sigIndex; + uint32_t arity; + if (!f.iter().readCallIndirect(&sigIndex, &arity)) + return false; + + const Sig& sig = f.mg().sigs[sigIndex]; + + FunctionCompiler::Call ionCall(f, lineOrBytecode); + if (!EmitCallArgs(f, sig, &ionCall)) + return false; + + MDefinition* callee; + if (!f.iter().readCallIndirectCallee(&callee)) + return false; + + if (!f.iter().readCallReturn(sig.ret())) + return false; + + MDefinition* def; + const TableModuleGeneratorData& table = f.mg().sigToTable[sigIndex]; + if (!f.funcPtrCall(sig, table.numElems, table.globalDataOffset, callee, ionCall, &def)) + return false; + + if (IsVoid(sig.ret())) + return true; + + f.iter().setResult(def); + return true; +} + +static bool +EmitCallImport(FunctionCompiler& f, uint32_t callOffset) +{ + uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); + + uint32_t importIndex; + uint32_t arity; + if (!f.iter().readCallImport(&importIndex, &arity)) + return false; + + const ImportModuleGeneratorData& import = f.mg().imports[importIndex]; + const Sig& sig = *import.sig; + + FunctionCompiler::Call ionCall(f, lineOrBytecode); + if (!EmitCallArgs(f, sig, &ionCall)) + return false; + + if (!f.iter().readCallReturn(sig.ret())) + return false; + + MDefinition* def; + if (!f.ffiCall(import.globalDataOffset, ionCall, sig.ret(), &def)) + return false; + + if (IsVoid(sig.ret())) + return true; + + f.iter().setResult(def); + return true; +} + +static bool +EmitGetLocal(FunctionCompiler& f) +{ + uint32_t id; + if (!f.iter().readGetLocal(f.locals(), &id)) + return false; + + f.iter().setResult(f.getLocalDef(id)); + return true; +} + +static bool +EmitSetLocal(FunctionCompiler& f) +{ + uint32_t id; + MDefinition* value; + if (!f.iter().readSetLocal(f.locals(), &id, &value)) + return false; + + f.assign(id, value); + return true; +} + +static bool +EmitGetGlobal(FunctionCompiler& f) +{ + uint32_t id; + if (!f.iter().readGetGlobal(f.mg().globals, &id)) + return false; + + const GlobalDesc& global = f.mg().globals[id]; + f.iter().setResult(f.loadGlobalVar(global.globalDataOffset, global.isConst, + ToMIRType(global.type))); + return true; +} + +static bool +EmitSetGlobal(FunctionCompiler& f) +{ + uint32_t id; + MDefinition* value; + if (!f.iter().readSetGlobal(f.mg().globals, &id, &value)) + return false; + + const GlobalDesc& global = f.mg().globals[id]; + f.storeGlobalVar(global.globalDataOffset, value); + return true; +} + +template +static bool +EmitUnary(FunctionCompiler& f, ValType operandType) +{ + MDefinition* input; + if (!f.iter().readUnary(operandType, &input)) + return false; + + f.iter().setResult(f.unary(input)); + return true; +} + +template +static bool +EmitConversion(FunctionCompiler& f, ValType operandType, ValType resultType) +{ + MDefinition* input; + if (!f.iter().readConversion(operandType, resultType, &input)) + return false; + + f.iter().setResult(f.unary(input)); + return true; +} + +template +static bool +EmitUnaryWithType(FunctionCompiler& f, ValType operandType, MIRType mirType) +{ + MDefinition* input; + if (!f.iter().readUnary(operandType, &input)) + return false; + + f.iter().setResult(f.unary(input, mirType)); + return true; +} + +template +static bool +EmitConversionWithType(FunctionCompiler& f, + ValType operandType, ValType resultType, MIRType mirType) +{ + MDefinition* input; + if (!f.iter().readConversion(operandType, resultType, &input)) + return false; + + f.iter().setResult(f.unary(input, mirType)); + return true; +} + +static bool +EmitTruncate(FunctionCompiler& f, ValType operandType, ValType resultType, + bool isUnsigned) +{ + MDefinition* input; + if (!f.iter().readConversion(operandType, resultType, &input)) + return false; + + if (resultType == ValType::I32) { + if (f.mg().kind == ModuleKind::AsmJS) + f.iter().setResult(f.truncate(input, isUnsigned)); + else + f.iter().setResult(f.truncate(input, isUnsigned)); + } else { + MOZ_ASSERT(resultType == ValType::I64); + MOZ_ASSERT(f.mg().kind == ModuleKind::Wasm); + f.iter().setResult(f.truncate(input, isUnsigned)); + } + return true; +} + +static bool +EmitExtendI32(FunctionCompiler& f, bool isUnsigned) +{ + MDefinition* input; + if (!f.iter().readConversion(ValType::I32, ValType::I64, &input)) + return false; + + f.iter().setResult(f.extendI32(input, isUnsigned)); + return true; +} + +static bool +EmitConvertI64ToFloatingPoint(FunctionCompiler& f, + ValType resultType, MIRType mirType, bool isUnsigned) +{ + MDefinition* input; + if (!f.iter().readConversion(ValType::I64, resultType, &input)) + return false; + + f.iter().setResult(f.convertI64ToFloatingPoint(input, mirType, isUnsigned)); + return true; +} + +static bool +EmitReinterpret(FunctionCompiler& f, ValType resultType, ValType operandType, MIRType mirType) +{ + MDefinition* input; + if (!f.iter().readConversion(operandType, resultType, &input)) + return false; + + f.iter().setResult(f.unary(input, mirType)); + return true; +} + +template +static bool +EmitBinary(FunctionCompiler& f, ValType type, MIRType mirType) +{ + MDefinition* lhs; + MDefinition* rhs; + if (!f.iter().readBinary(type, &lhs, &rhs)) + return false; + + f.iter().setResult(f.binary(lhs, rhs, mirType)); + return true; +} + +static bool +EmitRotate(FunctionCompiler& f, ValType type, bool isLeftRotation) +{ + MDefinition* lhs; + MDefinition* rhs; + if (!f.iter().readBinary(type, &lhs, &rhs)) + return false; + + MDefinition* result = f.rotate(lhs, rhs, ToMIRType(type), isLeftRotation); + f.iter().setResult(result); + return true; +} + +template +static bool +EmitBitwise(FunctionCompiler& f, ValType operandType) +{ + MDefinition* input; + if (!f.iter().readUnary(operandType, &input)) + return false; + + f.iter().setResult(f.bitwise(input)); + return true; +} + +template +static bool +EmitBitwise(FunctionCompiler& f, ValType operandType, MIRType mirType) +{ + MDefinition* lhs; + MDefinition* rhs; + if (!f.iter().readBinary(operandType, &lhs, &rhs)) + return false; + + f.iter().setResult(f.bitwise(lhs, rhs, mirType)); + return true; +} + +static bool +EmitMul(FunctionCompiler& f, ValType operandType, MIRType mirType) +{ + MDefinition* lhs; + MDefinition* rhs; + if (!f.iter().readBinary(operandType, &lhs, &rhs)) + return false; + + f.iter().setResult(f.mul(lhs, rhs, mirType, + mirType == MIRType::Int32 ? MMul::Integer : MMul::Normal)); + return true; +} + +static bool +EmitDiv(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isUnsigned) +{ + MDefinition* lhs; + MDefinition* rhs; + if (!f.iter().readBinary(operandType, &lhs, &rhs)) + return false; + + f.iter().setResult(f.div(lhs, rhs, mirType, isUnsigned)); + return true; +} + +static bool +EmitRem(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isUnsigned) +{ + MDefinition* lhs; + MDefinition* rhs; + if (!f.iter().readBinary(operandType, &lhs, &rhs)) + return false; + + f.iter().setResult(f.mod(lhs, rhs, mirType, isUnsigned)); + return true; +} + +static bool +EmitMinMax(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isMax) +{ + MDefinition* lhs; + MDefinition* rhs; + if (!f.iter().readBinary(operandType, &lhs, &rhs)) + return false; + + f.iter().setResult(f.minMax(lhs, rhs, mirType, isMax)); + return true; +} + +static bool +EmitComparison(FunctionCompiler& f, + ValType operandType, JSOp compareOp, MCompare::CompareType compareType) +{ + MDefinition* lhs; + MDefinition* rhs; + if (!f.iter().readComparison(operandType, &lhs, &rhs)) + return false; + + f.iter().setResult(f.compare(lhs, rhs, compareOp, compareType)); + return true; +} + +static bool +EmitSelect(FunctionCompiler& f) +{ + ExprType type; + MDefinition* trueValue; + MDefinition* falseValue; + MDefinition* condition; + if (!f.iter().readSelect(&type, &trueValue, &falseValue, &condition)) + return false; + + if (!IsVoid(type)) + f.iter().setResult(f.select(trueValue, falseValue, condition)); + + return true; +} + +enum class IsAtomic { + No = false, + Yes = true +}; + +static bool +SetHeapAccessOffset(FunctionCompiler& f, uint32_t offset, MAsmJSHeapAccess* access, MDefinition** base, + IsAtomic atomic = IsAtomic::No) +{ // TODO Remove this after implementing non-wraparound offset semantics. - uint32_t endOffset = access->endOffset(); + uint32_t endOffset = offset + access->byteSize(); if (endOffset < offset) return false; - bool accessNeedsBoundsCheck = true; + // Assume worst case. - bool atomicAccess = true; - if (endOffset > f.mirGen().foldableOffsetRange(accessNeedsBoundsCheck, atomicAccess)) { - MDefinition* rhs = f.constant(Int32Value(offset), MIRType_Int32); - *base = f.binary(*base, rhs, MIRType_Int32); - offset = 0; + if (endOffset > f.mirGen().foldableOffsetRange(/* bounds check */ true, bool(atomic))) { + MDefinition* rhs = f.constant(Int32Value(offset), MIRType::Int32); + *base = f.binary(*base, rhs, MIRType::Int32); + access->setOffset(0); + } else { access->setOffset(offset); } @@ -1528,335 +2059,230 @@ EmitHeapAddress(FunctionCompiler& f, MDefinition** base, MAsmJSHeapAccess* acces } static bool -EmitLoad(FunctionCompiler& f, Scalar::Type viewType, MDefinition** def) +EmitLoad(FunctionCompiler& f, ValType type, Scalar::Type viewType) { - MDefinition* base; - MAsmJSHeapAccess access(viewType); - if (!EmitHeapAddress(f, &base, &access)) + LinearMemoryAddress addr; + if (!f.iter().readLoad(type, Scalar::byteSize(viewType), &addr)) return false; - *def = f.loadHeap(base, access); + + MAsmJSHeapAccess access(viewType); + access.setAlign(addr.align); + + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base)) + return false; + + f.iter().setResult(f.loadHeap(base, access)); return true; } static bool -EmitStore(FunctionCompiler& f, Scalar::Type viewType, MDefinition** def) +EmitStore(FunctionCompiler& f, ValType resultType, Scalar::Type viewType) { - MDefinition* base; - MAsmJSHeapAccess access(viewType); - if (!EmitHeapAddress(f, &base, &access)) + LinearMemoryAddress addr; + MDefinition* value; + if (!f.iter().readStore(resultType, Scalar::byteSize(viewType), &addr, &value)) return false; - MDefinition* rhs = nullptr; - switch (viewType) { - case Scalar::Int8: - case Scalar::Int16: - case Scalar::Int32: - if (!EmitExpr(f, &rhs)) - return false; - break; - case Scalar::Float32: - if (!EmitExpr(f, &rhs)) - return false; - break; - case Scalar::Float64: - if (!EmitExpr(f, &rhs)) - return false; - break; - default: MOZ_CRASH("unexpected scalar type"); - } + MAsmJSHeapAccess access(viewType); + access.setAlign(addr.align); - f.storeHeap(base, access, rhs); - *def = rhs; + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base)) + return false; + + f.storeHeap(base, access, value); return true; } static bool -EmitStoreWithCoercion(FunctionCompiler& f, Scalar::Type rhsType, Scalar::Type viewType, - MDefinition **def) +EmitStoreWithCoercion(FunctionCompiler& f, ValType resultType, Scalar::Type viewType) { - MDefinition* base; - MAsmJSHeapAccess access(viewType); - if (!EmitHeapAddress(f, &base, &access)) + LinearMemoryAddress addr; + MDefinition* value; + if (!f.iter().readStore(resultType, Scalar::byteSize(viewType), &addr, &value)) return false; - MDefinition* rhs = nullptr; - MDefinition* coerced = nullptr; - if (rhsType == Scalar::Float32 && viewType == Scalar::Float64) { - if (!EmitExpr(f, &rhs)) - return false; - coerced = f.unary(rhs); - } else if (rhsType == Scalar::Float64 && viewType == Scalar::Float32) { - if (!EmitExpr(f, &rhs)) - return false; - coerced = f.unary(rhs); - } else { + if (resultType == ValType::F32 && viewType == Scalar::Float64) + value = f.unary(value); + else if (resultType == ValType::F64 && viewType == Scalar::Float32) + value = f.unary(value); + else MOZ_CRASH("unexpected coerced store"); - } - f.storeHeap(base, access, coerced); - *def = rhs; - return true; -} + MAsmJSHeapAccess access(viewType); + access.setAlign(addr.align); -static bool -EmitSetLocal(FunctionCompiler& f, MDefinition** def) -{ - uint32_t slot = f.readVarU32(); - MDefinition* expr; - if (!EmitExpr(f, &expr)) + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base)) return false; - f.assign(slot, expr); - *def = expr; + + f.storeHeap(base, access, value); return true; } static bool -EmitStoreGlobal(FunctionCompiler& f, MDefinition**def) +EmitUnaryMathBuiltinCall(FunctionCompiler& f, uint32_t callOffset, SymbolicAddress callee, + ValType operandType) { - uint32_t index = f.readVarU32(); - const AsmJSGlobalVariable& global = f.mg().globalVar(index); - MDefinition* expr; - if (!EmitExpr(f, &expr)) + uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); + + FunctionCompiler::Call call(f, lineOrBytecode); + if (!f.startCallArgs(&call)) return false; - f.storeGlobalVar(global.globalDataOffset, expr); - *def = expr; + + MDefinition* input; + if (!f.iter().readUnary(operandType, &input)) + return false; + + if (!f.passArg(input, operandType, &call)) + return false; + + f.finishCallArgs(&call); + + MDefinition* def; + if (!f.builtinCall(callee, call, operandType, &def)) + return false; + + f.iter().setResult(def); return true; } -typedef bool IsMax; - static bool -EmitMathMinMax(FunctionCompiler& f, ValType type, bool isMax, MDefinition** def) +EmitBinaryMathBuiltinCall(FunctionCompiler& f, uint32_t callOffset, SymbolicAddress callee, + ValType operandType) { + uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); + + FunctionCompiler::Call call(f, lineOrBytecode); + if (!f.startCallArgs(&call)) + return false; + MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; MDefinition* rhs; - if (!EmitExpr(f, &rhs)) + if (!f.iter().readBinary(operandType, &lhs, &rhs)) return false; - MIRType mirType = ToMIRType(type); - *def = f.minMax(lhs, rhs, mirType, isMax); + + if (!f.passArg(lhs, operandType, &call)) + return false; + + if (!f.passArg(rhs, operandType, &call)) + return false; + + f.finishCallArgs(&call); + + MDefinition* def; + if (!f.builtinCall(callee, call, operandType, &def)) + return false; + + f.iter().setResult(def); return true; } static bool -EmitAtomicsLoad(FunctionCompiler& f, MDefinition** def) +EmitAtomicsLoad(FunctionCompiler& f) { - Scalar::Type viewType = Scalar::Type(f.readU8()); + LinearMemoryAddress addr; + Scalar::Type viewType; + if (!f.iter().readAtomicLoad(&addr, &viewType)) + return false; - MDefinition* base; MAsmJSHeapAccess access(viewType, 0, MembarBeforeLoad, MembarAfterLoad); - if (!EmitHeapAddress(f, &base, &access)) + access.setAlign(addr.align); + + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base, IsAtomic::Yes)) return false; - *def = f.atomicLoadHeap(base, access); + f.iter().setResult(f.atomicLoadHeap(base, access)); return true; } static bool -EmitAtomicsStore(FunctionCompiler& f, MDefinition** def) +EmitAtomicsStore(FunctionCompiler& f) { - Scalar::Type viewType = Scalar::Type(f.readU8()); + LinearMemoryAddress addr; + Scalar::Type viewType; + MDefinition* value; + if (!f.iter().readAtomicStore(&addr, &viewType, &value)) + return false; - MDefinition* base; MAsmJSHeapAccess access(viewType, 0, MembarBeforeStore, MembarAfterStore); - if (!EmitHeapAddress(f, &base, &access)) + access.setAlign(addr.align); + + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base, IsAtomic::Yes)) return false; - MDefinition* value; - if (!EmitExpr(f, &value)) - return false; f.atomicStoreHeap(base, access, value); - *def = value; + f.iter().setResult(value); return true; } static bool -EmitAtomicsBinOp(FunctionCompiler& f, MDefinition** def) +EmitAtomicsBinOp(FunctionCompiler& f) { - Scalar::Type viewType = Scalar::Type(f.readU8()); - js::jit::AtomicOp op = js::jit::AtomicOp(f.readU8()); - - MDefinition* base; - MAsmJSHeapAccess access(viewType); - if (!EmitHeapAddress(f, &base, &access)) - return false; - + LinearMemoryAddress addr; + Scalar::Type viewType; + jit::AtomicOp op; MDefinition* value; - if (!EmitExpr(f, &value)) + if (!f.iter().readAtomicBinOp(&addr, &viewType, &op, &value)) return false; - *def = f.atomicBinopHeap(op, base, access, value); + + MAsmJSHeapAccess access(viewType); + access.setAlign(addr.align); + + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base, IsAtomic::Yes)) + return false; + + f.iter().setResult(f.atomicBinopHeap(op, base, access, value)); return true; } static bool -EmitAtomicsCompareExchange(FunctionCompiler& f, MDefinition** def) +EmitAtomicsCompareExchange(FunctionCompiler& f) { - Scalar::Type viewType = Scalar::Type(f.readU8()); - - MDefinition* base; - MAsmJSHeapAccess access(viewType); - if (!EmitHeapAddress(f, &base, &access)) - return false; - + LinearMemoryAddress addr; + Scalar::Type viewType; MDefinition* oldValue; - if (!EmitExpr(f, &oldValue)) - return false; MDefinition* newValue; - if (!EmitExpr(f, &newValue)) + if (!f.iter().readAtomicCompareExchange(&addr, &viewType, &oldValue, &newValue)) return false; - *def = f.atomicCompareExchangeHeap(base, access, oldValue, newValue); - return true; -} -static bool -EmitAtomicsExchange(FunctionCompiler& f, MDefinition** def) -{ - Scalar::Type viewType = Scalar::Type(f.readU8()); - - MDefinition* base; MAsmJSHeapAccess access(viewType); - if (!EmitHeapAddress(f, &base, &access)) + access.setAlign(addr.align); + + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base, IsAtomic::Yes)) return false; + f.iter().setResult(f.atomicCompareExchangeHeap(base, access, oldValue, newValue)); + return true; +} + +static bool +EmitAtomicsExchange(FunctionCompiler& f) +{ + LinearMemoryAddress addr; + Scalar::Type viewType; MDefinition* value; - if (!EmitExpr(f, &value)) + if (!f.iter().readAtomicExchange(&addr, &viewType, &value)) return false; - *def = f.atomicExchangeHeap(base, access, value); + + MAsmJSHeapAccess access(viewType); + access.setAlign(addr.align); + + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base, IsAtomic::Yes)) + return false; + + f.iter().setResult(f.atomicExchangeHeap(base, access, value)); return true; } static bool -EmitCallArgs(FunctionCompiler& f, const Sig& sig, FunctionCompiler::Call* call) -{ - if (!f.startCallArgs(call)) - return false; - for (ValType argType : sig.args()) { - MDefinition* arg; - if (!EmitExpr(f, &arg)) - return false; - if (!f.passArg(arg, argType, call)) - return false; - } - f.finishCallArgs(call); - return true; -} - -static bool -EmitCall(FunctionCompiler& f, uint32_t callOffset, MDefinition** def) -{ - uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); - uint32_t funcIndex = f.readVarU32(); - - const Sig& sig = f.mg().funcSig(funcIndex); - - FunctionCompiler::Call call(f, lineOrBytecode); - if (!EmitCallArgs(f, sig, &call)) - return false; - - return f.internalCall(sig, funcIndex, call, def); -} - -static bool -EmitCallIndirect(FunctionCompiler& f, uint32_t callOffset, MDefinition** def) -{ - uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); - uint32_t sigIndex = f.readVarU32(); - - const Sig& sig = f.mg().sig(sigIndex); - - MDefinition* index; - if (!EmitExpr(f, &index)) - return false; - - FunctionCompiler::Call call(f, lineOrBytecode); - if (!EmitCallArgs(f, sig, &call)) - return false; - - const TableModuleGeneratorData& table = f.mg().sigToTable(sigIndex); - return f.funcPtrCall(sig, table.numElems, table.globalDataOffset, index, call, def); -} - -static bool -EmitCallImport(FunctionCompiler& f, uint32_t callOffset, MDefinition** def) -{ - uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); - uint32_t importIndex = f.readVarU32(); - - const ImportModuleGeneratorData& import = f.mg().import(importIndex); - const Sig& sig = *import.sig; - - FunctionCompiler::Call call(f, lineOrBytecode); - if (!EmitCallArgs(f, sig, &call)) - return false; - - return f.ffiCall(import.globalDataOffset, call, sig.ret(), def); -} - -static bool -EmitF32MathBuiltinCall(FunctionCompiler& f, uint32_t callOffset, Expr f32, MDefinition** def) -{ - MOZ_ASSERT(f32 == Expr::F32Ceil || f32 == Expr::F32Floor); - - uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); - - FunctionCompiler::Call call(f, lineOrBytecode); - if (!f.startCallArgs(&call)) - return false; - - MDefinition* firstArg; - if (!EmitExpr(f, &firstArg) || !f.passArg(firstArg, ValType::F32, &call)) - return false; - - f.finishCallArgs(&call); - - SymbolicAddress callee = f32 == Expr::F32Ceil ? SymbolicAddress::CeilF : SymbolicAddress::FloorF; - return f.builtinCall(callee, call, ValType::F32, def); -} - -static bool -EmitF64MathBuiltinCall(FunctionCompiler& f, uint32_t callOffset, Expr f64, MDefinition** def) -{ - uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); - - FunctionCompiler::Call call(f, lineOrBytecode); - if (!f.startCallArgs(&call)) - return false; - - MDefinition* firstArg; - if (!EmitExpr(f, &firstArg) || !f.passArg(firstArg, ValType::F64, &call)) - return false; - - if (f64 == Expr::F64Pow || f64 == Expr::F64Atan2) { - MDefinition* secondArg; - if (!EmitExpr(f, &secondArg) || !f.passArg(secondArg, ValType::F64, &call)) - return false; - } - - SymbolicAddress callee; - switch (f64) { - case Expr::F64Ceil: callee = SymbolicAddress::CeilD; break; - case Expr::F64Floor: callee = SymbolicAddress::FloorD; break; - case Expr::F64Sin: callee = SymbolicAddress::SinD; break; - case Expr::F64Cos: callee = SymbolicAddress::CosD; break; - case Expr::F64Tan: callee = SymbolicAddress::TanD; break; - case Expr::F64Asin: callee = SymbolicAddress::ASinD; break; - case Expr::F64Acos: callee = SymbolicAddress::ACosD; break; - case Expr::F64Atan: callee = SymbolicAddress::ATanD; break; - case Expr::F64Exp: callee = SymbolicAddress::ExpD; break; - case Expr::F64Log: callee = SymbolicAddress::LogD; break; - case Expr::F64Pow: callee = SymbolicAddress::PowD; break; - case Expr::F64Atan2: callee = SymbolicAddress::ATan2D; break; - default: MOZ_CRASH("unexpected double math builtin callee"); - } - - f.finishCallArgs(&call); - - return f.builtinCall(callee, call, ValType::F64, def); -} - -static bool -EmitSimdUnary(FunctionCompiler& f, ValType type, SimdOperation simdOp, MDefinition** def) +EmitSimdUnary(FunctionCompiler& f, ValType type, SimdOperation simdOp) { MSimdUnaryArith::Operation op; switch (simdOp) { @@ -1881,51 +2307,50 @@ EmitSimdUnary(FunctionCompiler& f, ValType type, SimdOperation simdOp, MDefiniti default: MOZ_CRASH("not a simd unary arithmetic operation"); } - MDefinition* in; - if (!EmitExpr(f, &in)) + + MDefinition* input; + if (!f.iter().readUnary(type, &input)) return false; - *def = f.unarySimd(in, op, ToMIRType(type)); + + f.iter().setResult(f.unarySimd(input, op, ToMIRType(type))); return true; } template inline bool -EmitSimdBinary(FunctionCompiler& f, ValType type, OpKind op, MDefinition** def) +EmitSimdBinary(FunctionCompiler& f, ValType type, OpKind op) { MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; MDefinition* rhs; - if (!EmitExpr(f, &rhs)) + if (!f.iter().readBinary(type, &lhs, &rhs)) return false; - *def = f.binarySimd(lhs, rhs, op, ToMIRType(type)); + + f.iter().setResult(f.binarySimd(lhs, rhs, op, ToMIRType(type))); return true; } static bool -EmitSimdBinaryComp(FunctionCompiler& f, MSimdBinaryComp::Operation op, SimdSign sign, - MDefinition** def) +EmitSimdBinaryComp(FunctionCompiler& f, ValType operandType, MSimdBinaryComp::Operation op, + SimdSign sign) { MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; MDefinition* rhs; - if (!EmitExpr(f, &rhs)) + if (!f.iter().readSimdComparison(operandType, &lhs, &rhs)) return false; - *def = f.binarySimdComp(lhs, rhs, op, sign); + + f.iter().setResult(f.binarySimdComp(lhs, rhs, op, sign)); return true; } static bool -EmitSimdShift(FunctionCompiler& f, MSimdShift::Operation op, MDefinition** def) +EmitSimdShift(FunctionCompiler& f, ValType operandType, MSimdShift::Operation op) { MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; MDefinition* rhs; - if (!EmitExpr(f, &rhs)) + if (!f.iter().readSimdShiftByScalar(operandType, &lhs, &rhs)) return false; - *def = f.binarySimd(lhs, rhs, op); + + f.iter().setResult(f.binarySimd(lhs, rhs, op)); return true; } @@ -1946,128 +2371,89 @@ SimdToLaneType(ValType type) } static bool -EmitExtractLane(FunctionCompiler& f, ValType type, SimdSign sign, MDefinition** def) +EmitExtractLane(FunctionCompiler& f, ValType operandType, SimdSign sign) { - MDefinition* vec; - if (!EmitExpr(f, &vec)) + jit::SimdLane lane; + MDefinition* vector; + if (!f.iter().readExtractLane(operandType, &lane, &vector)) return false; - MDefinition* laneDef; - if (!EmitExpr(f, &laneDef)) - return false; - - if (!laneDef) { - *def = nullptr; - return true; - } - - MOZ_ASSERT(laneDef->isConstant()); - int32_t laneLit = laneDef->toConstant()->toInt32(); - MOZ_ASSERT(laneLit < 4); - SimdLane lane = SimdLane(laneLit); - - *def = f.extractSimdElement(lane, vec, ToMIRType(SimdToLaneType(type)), sign); + f.iter().setResult(f.extractSimdElement(lane, vector, + ToMIRType(SimdToLaneType(operandType)), sign)); return true; } // Emit an I32 expression and then convert it to a boolean SIMD lane value, i.e. -1 or 0. -static bool -EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def) +static MDefinition* +EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition* i32) { - MDefinition* i32; - if (!EmitExpr(f, &i32)) - return false; - // Now compute !i32 - 1 to force the value range into {0, -1}. + // Compute !i32 - 1 to force the value range into {0, -1}. MDefinition* noti32 = f.unary(i32); - *def = f.binary(noti32, f.constant(Int32Value(1), MIRType_Int32), MIRType_Int32); - return true; + return f.binary(noti32, f.constant(Int32Value(1), MIRType::Int32), MIRType::Int32); } static bool -EmitSimdReplaceLane(FunctionCompiler& f, ValType simdType, MDefinition** def) +EmitSimdReplaceLane(FunctionCompiler& f, ValType simdType) { + if (IsSimdBoolType(simdType)) + f.iter().setResult(EmitSimdBooleanLaneExpr(f, f.iter().getResult())); + + jit::SimdLane lane; MDefinition* vector; - if (!EmitExpr(f, &vector)) - return false; - - MDefinition* laneDef; - if (!EmitExpr(f, &laneDef)) - return false; - - SimdLane lane; - if (laneDef) { - MOZ_ASSERT(laneDef->isConstant()); - int32_t laneLit = laneDef->toConstant()->toInt32(); - MOZ_ASSERT(laneLit < 4); - lane = SimdLane(laneLit); - } else { - lane = SimdLane(-1); - } - MDefinition* scalar; - if (IsSimdBoolType(simdType)) { - if (!EmitSimdBooleanLaneExpr(f, &scalar)) - return false; - } else { - if (!EmitExpr(f, &scalar)) - return false; - } - *def = f.insertElementSimd(vector, scalar, lane, ToMIRType(simdType)); + if (!f.iter().readReplaceLane(simdType, &lane, &vector, &scalar)) + return false; + + f.iter().setResult(f.insertElementSimd(vector, scalar, lane, ToMIRType(simdType))); return true; } inline bool -EmitSimdBitcast(FunctionCompiler& f, ValType fromType, ValType toType, MDefinition** def) +EmitSimdBitcast(FunctionCompiler& f, ValType fromType, ValType toType) { - MDefinition* in; - if (!EmitExpr(f, &in)) + MDefinition* input; + if (!f.iter().readConversion(fromType, toType, &input)) return false; - *def = f.bitcastSimd(in, ToMIRType(fromType), ToMIRType(toType)); + + f.iter().setResult(f.bitcastSimd(input, ToMIRType(fromType), ToMIRType(toType))); return true; } inline bool -EmitSimdConvert(FunctionCompiler& f, ValType fromType, ValType toType, SimdSign sign, - MDefinition** def) +EmitSimdConvert(FunctionCompiler& f, ValType fromType, ValType toType, SimdSign sign) { - MDefinition* in; - if (!EmitExpr(f, &in)) + MDefinition* input; + if (!f.iter().readConversion(fromType, toType, &input)) return false; - *def = f.convertSimd(in, ToMIRType(fromType), ToMIRType(toType), sign); + + f.iter().setResult(f.convertSimd(input, ToMIRType(fromType), ToMIRType(toType), sign)); return true; } static bool -EmitSimdSwizzle(FunctionCompiler& f, ValType type, MDefinition** def) +EmitSimdSwizzle(FunctionCompiler& f, ValType simdType) { - MDefinition* in; - if (!EmitExpr(f, &in)) - return false; - uint8_t lanes[4]; - for (unsigned i = 0; i < 4; i++) - lanes[i] = f.readU8(); + MDefinition* vector; + if (!f.iter().readSwizzle(simdType, &lanes, &vector)) + return false; - *def = f.swizzleSimd(in, lanes[0], lanes[1], lanes[2], lanes[3], ToMIRType(type)); + f.iter().setResult(f.swizzleSimd(vector, lanes[0], lanes[1], lanes[2], lanes[3], + ToMIRType(simdType))); return true; } static bool -EmitSimdShuffle(FunctionCompiler& f, ValType type, MDefinition** def) +EmitSimdShuffle(FunctionCompiler& f, ValType simdType) { + uint8_t lanes[4]; MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; - MDefinition* rhs; - if (!EmitExpr(f, &rhs)) + if (!f.iter().readShuffle(simdType, &lanes, &lhs, &rhs)) return false; - uint8_t lanes[4]; - for (unsigned i = 0; i < 4; i++) - lanes[i] = f.readU8(); - - *def = f.shuffleSimd(lhs, rhs, lanes[0], lanes[1], lanes[2], lanes[3], ToMIRType(type)); + f.iter().setResult(f.shuffleSimd(lhs, rhs, lanes[0], lanes[1], lanes[2], lanes[3], + ToMIRType(simdType))); return true; } @@ -2083,126 +2469,147 @@ SimdExprTypeToViewType(ValType type, unsigned* defaultNumElems) } static bool -EmitSimdLoad(FunctionCompiler& f, ValType type, unsigned numElems, MDefinition** def) +EmitSimdLoad(FunctionCompiler& f, ValType resultType, unsigned numElems) { unsigned defaultNumElems; - Scalar::Type viewType = SimdExprTypeToViewType(type, &defaultNumElems); + Scalar::Type viewType = SimdExprTypeToViewType(resultType, &defaultNumElems); if (!numElems) numElems = defaultNumElems; - MDefinition* base; - MAsmJSHeapAccess access(viewType, numElems); - if (!EmitHeapAddress(f, &base, &access)) + LinearMemoryAddress addr; + if (!f.iter().readLoad(resultType, Scalar::byteSize(viewType), &addr)) return false; - *def = f.loadSimdHeap(base, access); + MAsmJSHeapAccess access(viewType, numElems); + access.setAlign(addr.align); + + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base)) + return false; + + f.iter().setResult(f.loadSimdHeap(base, access)); return true; } static bool -EmitSimdStore(FunctionCompiler& f, ValType type, unsigned numElems, MDefinition** def) +EmitSimdStore(FunctionCompiler& f, ValType resultType, unsigned numElems) { unsigned defaultNumElems; - Scalar::Type viewType = SimdExprTypeToViewType(type, &defaultNumElems); + Scalar::Type viewType = SimdExprTypeToViewType(resultType, &defaultNumElems); if (!numElems) numElems = defaultNumElems; - MDefinition* base; + LinearMemoryAddress addr; + MDefinition* value; + if (!f.iter().readStore(resultType, Scalar::byteSize(viewType), &addr, &value)) + return false; + MAsmJSHeapAccess access(viewType, numElems); - if (!EmitHeapAddress(f, &base, &access)) + access.setAlign(addr.align); + + MDefinition* base = addr.base; + if (!SetHeapAccessOffset(f, addr.offset, &access, &base)) return false; - MDefinition* vec; - if (!EmitExpr(f, &vec)) - return false; - - f.storeSimdHeap(base, access, vec); - *def = vec; + f.storeSimdHeap(base, access, value); return true; } static bool -EmitSimdSelect(FunctionCompiler& f, ValType type, MDefinition** def) +EmitSimdSelect(FunctionCompiler& f, ValType simdType) { - MDefinition* mask; - MDefinition* defs[2]; - - // The mask is a boolean vector for elementwise select. - if (!EmitExpr(f, &mask)) + MDefinition* trueValue; + MDefinition* falseValue; + MDefinition* condition; + if (!f.iter().readSimdSelect(simdType, &trueValue, &falseValue, &condition)) return false; - if (!EmitExpr(f, &defs[0]) || !EmitExpr(f, &defs[1])) - return false; - *def = f.selectSimd(mask, defs[0], defs[1], ToMIRType(type)); + f.iter().setResult(f.selectSimd(condition, trueValue, falseValue, + ToMIRType(simdType))); return true; } static bool -EmitSimdAllTrue(FunctionCompiler& f, MDefinition** def) +EmitSimdAllTrue(FunctionCompiler& f, ValType operandType) { - MDefinition* in; - if (!EmitExpr(f, &in)) + MDefinition* input; + if (!f.iter().readSimdBooleanReduction(operandType, &input)) return false; - *def = f.simdAllTrue(in); + + f.iter().setResult(f.simdAllTrue(input)); return true; } static bool -EmitSimdAnyTrue(FunctionCompiler& f, MDefinition** def) +EmitSimdAnyTrue(FunctionCompiler& f, ValType operandType) { - MDefinition* in; - if (!EmitExpr(f, &in)) + MDefinition* input; + if (!f.iter().readSimdBooleanReduction(operandType, &input)) return false; - *def = f.simdAnyTrue(in); + + f.iter().setResult(f.simdAnyTrue(input)); return true; } static bool -EmitSimdSplat(FunctionCompiler& f, ValType type, MDefinition** def) +EmitSimdSplat(FunctionCompiler& f, ValType simdType) { - MDefinition* in; - if (IsSimdBoolType(type)) { - if (!EmitSimdBooleanLaneExpr(f, &in)) - return false; - } else { - if (!EmitExpr(f, &in)) - return false; - } - *def = f.splatSimd(in, ToMIRType(type)); + if (IsSimdBoolType(simdType)) + f.iter().setResult(EmitSimdBooleanLaneExpr(f, f.iter().getResult())); + + MDefinition* input; + if (!f.iter().readSplat(simdType, &input)) + return false; + + f.iter().setResult(f.splatSimd(input, ToMIRType(simdType))); return true; } static bool -EmitSimdCtor(FunctionCompiler& f, ValType type, MDefinition** def) +EmitSimdCtor(FunctionCompiler& f, ValType type) { + if (!f.iter().readSimdCtor()) + return false; + switch (type) { case ValType::I32x4: { MDefinition* args[4]; for (unsigned i = 0; i < 4; i++) { - if (!EmitExpr(f, &args[i])) + if (!f.iter().readSimdCtorArg(ValType::I32, 4, i, &args[i])) return false; } - *def = f.constructSimd(args[0], args[1], args[2], args[3], MIRType_Int32x4); + if (!f.iter().readSimdCtorArgsEnd(4) || !f.iter().readSimdCtorReturn(type)) + return false; + f.iter().setResult(f.constructSimd(args[0], args[1], args[2], args[3], + MIRType::Int32x4)); return true; } case ValType::F32x4: { MDefinition* args[4]; for (unsigned i = 0; i < 4; i++) { - if (!EmitExpr(f, &args[i])) + if (!f.iter().readSimdCtorArg(ValType::F32, 4, i, &args[i])) return false; } - *def = f.constructSimd(args[0], args[1], args[2], args[3], MIRType_Float32x4); + if (!f.iter().readSimdCtorArgsEnd(4) || !f.iter().readSimdCtorReturn(type)) + return false; + f.iter().setResult(f.constructSimd(args[0], args[1], args[2], args[3], + MIRType::Float32x4)); return true; } case ValType::B32x4: { MDefinition* args[4]; for (unsigned i = 0; i < 4; i++) { - if (!EmitSimdBooleanLaneExpr(f, &args[i])) + MDefinition* i32; + if (!f.iter().readSimdCtorArg(ValType::I32, 4, i, &i32)) return false; + args[i] = EmitSimdBooleanLaneExpr(f, i32); } - *def = f.constructSimd(args[0], args[1], args[2], args[3], MIRType_Bool32x4); + if (!f.iter().readSimdCtorArgsEnd(4) || !f.iter().readSimdCtorReturn(type)) + return false; + f.iter().setResult(f.constructSimd(args[0], args[1], args[2], args[3], + MIRType::Bool32x4)); return true; } case ValType::I32: @@ -2215,386 +2622,86 @@ EmitSimdCtor(FunctionCompiler& f, ValType type, MDefinition** def) MOZ_CRASH("unexpected SIMD type"); } -template static bool -EmitUnary(FunctionCompiler& f, MDefinition** def) -{ - MDefinition* in; - if (!EmitExpr(f, &in)) - return false; - *def = f.unary(in); - return true; -} - -template -static bool -EmitUnaryWithType(FunctionCompiler& f, ValType type, MDefinition** def) -{ - MDefinition* in; - if (!EmitExpr(f, &in)) - return false; - *def = f.unary(in, ToMIRType(type)); - return true; -} - -static bool -EmitMultiply(FunctionCompiler& f, ValType type, MDefinition** def) -{ - MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; - MDefinition* rhs; - if (!EmitExpr(f, &rhs)) - return false; - MIRType mirType = ToMIRType(type); - *def = f.mul(lhs, rhs, mirType, mirType == MIRType_Int32 ? MMul::Integer : MMul::Normal); - return true; -} - -static bool -EmitSelect(FunctionCompiler& f, MDefinition** def) -{ - MDefinition* trueExpr; - if (!EmitExpr(f, &trueExpr)) - return false; - - MDefinition* falseExpr; - if (!EmitExpr(f, &falseExpr)) - return false; - - MDefinition* condExpr; - if (!EmitExpr(f, &condExpr)) - return false; - - if (trueExpr && falseExpr && - trueExpr->type() == falseExpr->type() && - trueExpr->type() != MIRType_None) - { - *def = f.select(trueExpr, falseExpr, condExpr); - } else { - *def = nullptr; - } - - return true; -} - -typedef bool IsAdd; - -static bool -EmitAddOrSub(FunctionCompiler& f, ValType type, bool isAdd, MDefinition** def) -{ - MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; - MDefinition* rhs; - if (!EmitExpr(f, &rhs)) - return false; - MIRType mirType = ToMIRType(type); - *def = isAdd ? f.binary(lhs, rhs, mirType) : f.binary(lhs, rhs, mirType); - return true; -} - -typedef bool IsUnsigned; -typedef bool IsDiv; - -static bool -EmitDivOrMod(FunctionCompiler& f, ValType type, bool isDiv, bool isUnsigned, MDefinition** def) -{ - MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; - MDefinition* rhs; - if (!EmitExpr(f, &rhs)) - return false; - *def = isDiv - ? f.div(lhs, rhs, ToMIRType(type), isUnsigned) - : f.mod(lhs, rhs, ToMIRType(type), isUnsigned); - return true; -} - -static bool -EmitDivOrMod(FunctionCompiler& f, ValType type, bool isDiv, MDefinition** def) -{ - MOZ_ASSERT(type != ValType::I32 && type != ValType::I64, - "int div or mod must indicate signedness"); - return EmitDivOrMod(f, type, isDiv, false, def); -} - -static bool -EmitComparison(FunctionCompiler& f, Expr expr, MDefinition** def) -{ - MDefinition *lhs, *rhs; - MCompare::CompareType compareType; - switch (expr) { - case Expr::I32Eq: - case Expr::I32Ne: - case Expr::I32LeS: - case Expr::I32LtS: - case Expr::I32LeU: - case Expr::I32LtU: - case Expr::I32GeS: - case Expr::I32GtS: - case Expr::I32GeU: - case Expr::I32GtU: - if (!EmitExpr(f, &lhs) || !EmitExpr(f, &rhs)) - return false; - - switch (expr) { - case Expr::I32LeS: case Expr::I32LtS: case Expr::I32GeS: case Expr::I32GtS: - case Expr::I32Eq: case Expr::I32Ne: - compareType = MCompare::Compare_Int32; break; - case Expr::I32GeU: case Expr::I32GtU: case Expr::I32LeU: case Expr::I32LtU: - compareType = MCompare::Compare_UInt32; break; - default: MOZ_CRASH("impossibru opcode"); - } - break; - case Expr::I64Eq: - case Expr::I64Ne: - case Expr::I64LeS: - case Expr::I64LtS: - case Expr::I64LeU: - case Expr::I64LtU: - case Expr::I64GeS: - case Expr::I64GtS: - case Expr::I64GeU: - case Expr::I64GtU: - if (!EmitExpr(f, &lhs) || !EmitExpr(f, &rhs)) - return false; - switch (expr) { - case Expr::I64LeS: case Expr::I64LtS: case Expr::I64GeS: case Expr::I64GtS: - case Expr::I64Eq: case Expr::I64Ne: - compareType = MCompare::Compare_Int64; - break; - case Expr::I64GeU: case Expr::I64GtU: case Expr::I64LeU: case Expr::I64LtU: - compareType = MCompare::Compare_UInt64; - break; - default: - MOZ_CRASH("unexpected opcode"); - } - break; - case Expr::F32Eq: - case Expr::F32Ne: - case Expr::F32Le: - case Expr::F32Lt: - case Expr::F32Ge: - case Expr::F32Gt: - if (!EmitExpr(f, &lhs) || !EmitExpr(f, &rhs)) - return false; - compareType = MCompare::Compare_Float32; - break; - case Expr::F64Eq: - case Expr::F64Ne: - case Expr::F64Le: - case Expr::F64Lt: - case Expr::F64Ge: - case Expr::F64Gt: - if (!EmitExpr(f, &lhs) || !EmitExpr(f, &rhs)) - return false; - compareType = MCompare::Compare_Double; - break; - default: MOZ_CRASH("unexpected comparison opcode"); - } - - JSOp compareOp; - switch (expr) { - case Expr::I32Eq: - case Expr::I64Eq: - case Expr::F32Eq: - case Expr::F64Eq: - compareOp = JSOP_EQ; - break; - case Expr::I32Ne: - case Expr::I64Ne: - case Expr::F32Ne: - case Expr::F64Ne: - compareOp = JSOP_NE; - break; - case Expr::I32LeS: - case Expr::I32LeU: - case Expr::I64LeS: - case Expr::I64LeU: - case Expr::F32Le: - case Expr::F64Le: - compareOp = JSOP_LE; - break; - case Expr::I32LtS: - case Expr::I32LtU: - case Expr::I64LtS: - case Expr::I64LtU: - case Expr::F32Lt: - case Expr::F64Lt: - compareOp = JSOP_LT; - break; - case Expr::I32GeS: - case Expr::I32GeU: - case Expr::I64GeS: - case Expr::I64GeU: - case Expr::F32Ge: - case Expr::F64Ge: - compareOp = JSOP_GE; - break; - case Expr::I32GtS: - case Expr::I32GtU: - case Expr::I64GtS: - case Expr::I64GtU: - case Expr::F32Gt: - case Expr::F64Gt: - compareOp = JSOP_GT; - break; - default: MOZ_CRASH("unexpected comparison opcode"); - } - - *def = f.compare(lhs, rhs, compareOp, compareType); - return true; -} - -template -static bool -EmitBitwise(FunctionCompiler& f, ValType type, MDefinition** def) -{ - MDefinition* lhs; - if (!EmitExpr(f, &lhs)) - return false; - MDefinition* rhs; - if (!EmitExpr(f, &rhs)) - return false; - MIRType mirType = ToMIRType(type); - *def = f.bitwise(lhs, rhs, mirType); - return true; -} - -static bool -EmitBitwiseNot(FunctionCompiler& f, MDefinition** def) -{ - MDefinition* in; - if (!EmitExpr(f, &in)) - return false; - *def = f.bitwise(in); - return true; -} - -static bool -EmitExtendI32(FunctionCompiler& f, bool isUnsigned, MDefinition** def) -{ - MDefinition* in; - if (!EmitExpr(f, &in)) - return false; - *def = f.extendI32(in, isUnsigned); - return true; -} - -template -static bool -EmitTruncate(FunctionCompiler& f, bool isUnsigned, MDefinition** def) -{ - MDefinition* in; - if (!EmitExpr(f, &in)) - return false; - *def = f.truncate(in, isUnsigned); - return true; -} - -static bool -EmitConvertI64ToFloatingPoint(FunctionCompiler& f, ValType type, bool isUnsigned, - MDefinition** def) -{ - MDefinition* in; - if (!EmitExpr(f, &in)) - return false; - *def = f.convertI64ToFloatingPoint(in, ToMIRType(type), isUnsigned); - return true; -} - -static bool -EmitReinterpret(FunctionCompiler& f, ValType to, MDefinition** def) -{ - MDefinition* in; - if (!EmitExpr(f, &in)) - return false; - *def = f.reinterpret(in, ToMIRType(to)); - return true; -} - -static bool -EmitSimdOp(FunctionCompiler& f, ValType type, SimdOperation op, SimdSign sign, MDefinition** def) +EmitSimdOp(FunctionCompiler& f, ValType type, SimdOperation op, SimdSign sign) { switch (op) { case SimdOperation::Constructor: - return EmitSimdCtor(f, type, def); + return EmitSimdCtor(f, type); case SimdOperation::Fn_extractLane: - return EmitExtractLane(f, type, sign, def); + return EmitExtractLane(f, type, sign); case SimdOperation::Fn_replaceLane: - return EmitSimdReplaceLane(f, type, def); + return EmitSimdReplaceLane(f, type); case SimdOperation::Fn_check: MOZ_CRASH("only used in asm.js' type system"); case SimdOperation::Fn_splat: - return EmitSimdSplat(f, type, def); + return EmitSimdSplat(f, type); case SimdOperation::Fn_select: - return EmitSimdSelect(f, type, def); + return EmitSimdSelect(f, type); case SimdOperation::Fn_swizzle: - return EmitSimdSwizzle(f, type, def); + return EmitSimdSwizzle(f, type); case SimdOperation::Fn_shuffle: - return EmitSimdShuffle(f, type, def); + return EmitSimdShuffle(f, type); case SimdOperation::Fn_load: - return EmitSimdLoad(f, type, 0, def); + return EmitSimdLoad(f, type, 0); case SimdOperation::Fn_load1: - return EmitSimdLoad(f, type, 1, def); + return EmitSimdLoad(f, type, 1); case SimdOperation::Fn_load2: - return EmitSimdLoad(f, type, 2, def); + return EmitSimdLoad(f, type, 2); case SimdOperation::Fn_load3: - return EmitSimdLoad(f, type, 3, def); + return EmitSimdLoad(f, type, 3); case SimdOperation::Fn_store: - return EmitSimdStore(f, type, 0, def); + return EmitSimdStore(f, type, 0); case SimdOperation::Fn_store1: - return EmitSimdStore(f, type, 1, def); + return EmitSimdStore(f, type, 1); case SimdOperation::Fn_store2: - return EmitSimdStore(f, type, 2, def); + return EmitSimdStore(f, type, 2); case SimdOperation::Fn_store3: - return EmitSimdStore(f, type, 3, def); + return EmitSimdStore(f, type, 3); case SimdOperation::Fn_allTrue: - return EmitSimdAllTrue(f, def); + return EmitSimdAllTrue(f, type); case SimdOperation::Fn_anyTrue: - return EmitSimdAnyTrue(f, def); + return EmitSimdAnyTrue(f, type); case SimdOperation::Fn_abs: case SimdOperation::Fn_neg: case SimdOperation::Fn_not: case SimdOperation::Fn_sqrt: case SimdOperation::Fn_reciprocalApproximation: case SimdOperation::Fn_reciprocalSqrtApproximation: - return EmitSimdUnary(f, type, op, def); + return EmitSimdUnary(f, type, op); case SimdOperation::Fn_shiftLeftByScalar: - return EmitSimdShift(f, MSimdShift::lsh, def); + return EmitSimdShift(f, type, MSimdShift::lsh); case SimdOperation::Fn_shiftRightByScalar: - return EmitSimdShift(f, MSimdShift::rshForSign(sign), def); + return EmitSimdShift(f, type, MSimdShift::rshForSign(sign)); #define _CASE(OP) \ case SimdOperation::Fn_##OP: \ - return EmitSimdBinaryComp(f, MSimdBinaryComp::OP, sign, def); + return EmitSimdBinaryComp(f, type, MSimdBinaryComp::OP, sign); FOREACH_COMP_SIMD_OP(_CASE) #undef _CASE case SimdOperation::Fn_and: - return EmitSimdBinary(f, type, MSimdBinaryBitwise::and_, def); + return EmitSimdBinary(f, type, MSimdBinaryBitwise::and_); case SimdOperation::Fn_or: - return EmitSimdBinary(f, type, MSimdBinaryBitwise::or_, def); + return EmitSimdBinary(f, type, MSimdBinaryBitwise::or_); case SimdOperation::Fn_xor: - return EmitSimdBinary(f, type, MSimdBinaryBitwise::xor_, def); + return EmitSimdBinary(f, type, MSimdBinaryBitwise::xor_); #define _CASE(OP) \ case SimdOperation::Fn_##OP: \ - return EmitSimdBinary(f, type, MSimdBinaryArith::Op_##OP, def); + return EmitSimdBinary(f, type, MSimdBinaryArith::Op_##OP); FOREACH_NUMERIC_SIMD_BINOP(_CASE) FOREACH_FLOAT_SIMD_BINOP(_CASE) #undef _CASE case SimdOperation::Fn_fromFloat32x4: - return EmitSimdConvert(f, ValType::F32x4, type, sign, def); + return EmitSimdConvert(f, ValType::F32x4, type, sign); case SimdOperation::Fn_fromInt32x4: - return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Signed, def); + return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Signed); case SimdOperation::Fn_fromUint32x4: - return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Unsigned, def); + return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Unsigned); case SimdOperation::Fn_fromInt32x4Bits: case SimdOperation::Fn_fromUint32x4Bits: - return EmitSimdBitcast(f, ValType::I32x4, type, def); + return EmitSimdBitcast(f, ValType::I32x4, type); case SimdOperation::Fn_fromFloat32x4Bits: case SimdOperation::Fn_fromInt8x16Bits: - return EmitSimdBitcast(f, ValType::F32x4, type, def); + return EmitSimdBitcast(f, ValType::F32x4, type); case SimdOperation::Fn_fromInt16x8Bits: case SimdOperation::Fn_fromUint8x16Bits: case SimdOperation::Fn_fromUint16x8Bits: @@ -2605,488 +2712,394 @@ EmitSimdOp(FunctionCompiler& f, ValType type, SimdOperation op, SimdSign sign, M } static bool -EmitLoop(FunctionCompiler& f, MDefinition** def) -{ - MBasicBlock* loopHeader; - if (!f.startLoop(&loopHeader)) - return false; - - f.addInterruptCheck(); - - if (uint32_t numStmts = f.readVarU32()) { - for (uint32_t i = 0; i < numStmts - 1; i++) { - MDefinition* _; - if (!EmitExpr(f, &_)) - return false; - } - MDefinition* last = nullptr; - if (!EmitExpr(f, &last)) - return false; - f.pushDef(last); - } - - return f.closeLoop(loopHeader, def); -} - -static bool -EmitIfElse(FunctionCompiler& f, Expr op, MDefinition** def) -{ - MOZ_ASSERT(op == Expr::If || op == Expr::IfElse); - - // Handle if/else-if chains using iteration instead of recursion. This - // avoids blowing the C stack quota for long if/else-if chains and also - // creates fewer MBasicBlocks at join points (by creating one join block - // for the entire if/else-if chain). - BlockVector blocks; - - recurse: - MDefinition* condition; - if (!EmitExpr(f, &condition)) - return false; - - MBasicBlock* thenBlock = nullptr; - MBasicBlock* elseOrJoinBlock = nullptr; - if (!f.branchAndStartThen(condition, &thenBlock, &elseOrJoinBlock)) - return false; - - MDefinition* ifDef; - if (!EmitExpr(f, &ifDef)) - return false; - - if (!f.addJoinPredecessor(ifDef, &blocks)) - return false; - - if (op == Expr::If) - return f.joinIf(elseOrJoinBlock, &blocks, def); - - f.switchToElse(elseOrJoinBlock); - - Expr nextStmt = f.peakExpr(); - if (nextStmt == Expr::If || nextStmt == Expr::IfElse) { - JS_ALWAYS_TRUE(f.readExpr() == nextStmt); - op = nextStmt; - goto recurse; - } - - MDefinition* elseDef; - if (!EmitExpr(f, &elseDef)) - return false; - - return f.joinIfElse(elseDef, &blocks, def); -} - -static bool -EmitBrTable(FunctionCompiler& f, MDefinition** def) -{ - uint32_t numCases = f.readVarU32(); - - Uint32Vector depths; - if (!depths.resize(numCases)) - return false; - - for (size_t i = 0; i < numCases; i++) - depths[i] = f.readU32(); - - uint32_t defaultDepth = f.readU32(); - - MDefinition* index; - if (!EmitExpr(f, &index)) - return false; - - *def = nullptr; - - // Empty table - if (!numCases) - return f.br(defaultDepth, nullptr); - - return f.brTable(index, defaultDepth, depths); -} - -static bool -EmitReturn(FunctionCompiler& f, MDefinition** def) -{ - ExprType ret = f.sig().ret(); - - if (IsVoid(ret)) { - *def = nullptr; - f.returnVoid(); - return true; - } - - MDefinition* retVal; - if (!EmitExpr(f, &retVal)) - return false; - - f.returnExpr(retVal); - - *def = nullptr; - return true; -} - -static bool -EmitUnreachable(FunctionCompiler& f, MDefinition** def) -{ - *def = nullptr; - f.unreachableTrap(); - return true; -} - -static bool -EmitBlock(FunctionCompiler& f, MDefinition** def) -{ - if (!f.startBlock()) - return false; - if (uint32_t numStmts = f.readVarU32()) { - for (uint32_t i = 0; i < numStmts - 1; i++) { - MDefinition* _ = nullptr; - if (!EmitExpr(f, &_)) - return false; - } - MDefinition* last = nullptr; - if (!EmitExpr(f, &last)) - return false; - f.pushDef(last); - } - return f.finishBlock(def); -} - -static bool -EmitBranch(FunctionCompiler& f, Expr op, MDefinition** def) -{ - MOZ_ASSERT(op == Expr::Br || op == Expr::BrIf); - - uint32_t relativeDepth = f.readVarU32(); - - MDefinition* maybeValue = nullptr; - if (!EmitExpr(f, &maybeValue)) - return false; - - if (op == Expr::Br) { - if (!f.br(relativeDepth, maybeValue)) - return false; - } else { - MDefinition* condition; - if (!EmitExpr(f, &condition)) - return false; - - if (!f.brIf(relativeDepth, maybeValue, condition)) - return false; - } - - *def = nullptr; - return true; -} - -static bool -EmitExpr(FunctionCompiler& f, MDefinition** def) +EmitExpr(FunctionCompiler& f) { if (!f.mirGen().ensureBallast()) return false; - uint32_t exprOffset = f.currentOffset(); + uint32_t exprOffset = f.iter().currentOffset(); - switch (Expr op = f.readExpr()) { + Expr expr; + if (!f.iter().readExpr(&expr)) + return false; + + switch (expr) { // Control opcodes case Expr::Nop: - *def = nullptr; - return true; - case Expr::Id: - return EmitExpr(f, def); + return f.iter().readNullary(); case Expr::Block: - return EmitBlock(f, def); - case Expr::If: - case Expr::IfElse: - return EmitIfElse(f, op, def); + return EmitBlock(f); case Expr::Loop: - return EmitLoop(f, def); + return EmitLoop(f); + case Expr::If: + return EmitIf(f); + case Expr::Else: + return EmitElse(f); + case Expr::End: + return EmitEnd(f); case Expr::Br: + return EmitBr(f); case Expr::BrIf: - return EmitBranch(f, op, def); + return EmitBrIf(f); case Expr::BrTable: - return EmitBrTable(f, def); + return EmitBrTable(f); case Expr::Return: - return EmitReturn(f, def); + return EmitReturn(f); case Expr::Unreachable: - return EmitUnreachable(f, def); + if (!f.iter().readUnreachable()) + return false; + f.unreachableTrap(); + return true; // Calls case Expr::Call: - return EmitCall(f, exprOffset, def); + return EmitCall(f, exprOffset); case Expr::CallIndirect: - return EmitCallIndirect(f, exprOffset, def); + return EmitCallIndirect(f, exprOffset); case Expr::CallImport: - return EmitCallImport(f, exprOffset, def); + return EmitCallImport(f, exprOffset); // Locals and globals case Expr::GetLocal: - return EmitGetLocal(f, def); + return EmitGetLocal(f); case Expr::SetLocal: - return EmitSetLocal(f, def); + return EmitSetLocal(f); case Expr::LoadGlobal: - return EmitLoadGlobal(f, def); + return EmitGetGlobal(f); case Expr::StoreGlobal: - return EmitStoreGlobal(f, def); + return EmitSetGlobal(f); // Select case Expr::Select: - return EmitSelect(f, def); + return EmitSelect(f); // I32 - case Expr::I32Const: - return EmitLiteral(f, ValType::I32, def); + case Expr::I32Const: { + int32_t i32; + if (!f.iter().readI32Const(&i32)) + return false; + + f.iter().setResult(f.constant(Int32Value(i32), MIRType::Int32)); + return true; + } case Expr::I32Add: - return EmitAddOrSub(f, ValType::I32, IsAdd(true), def); + return EmitBinary(f, ValType::I32, MIRType::Int32); case Expr::I32Sub: - return EmitAddOrSub(f, ValType::I32, IsAdd(false), def); + return EmitBinary(f, ValType::I32, MIRType::Int32); case Expr::I32Mul: - return EmitMultiply(f, ValType::I32, def); + return EmitMul(f, ValType::I32, MIRType::Int32); case Expr::I32DivS: case Expr::I32DivU: - return EmitDivOrMod(f, ValType::I32, IsDiv(true), IsUnsigned(op == Expr::I32DivU), def); + return EmitDiv(f, ValType::I32, MIRType::Int32, expr == Expr::I32DivU); case Expr::I32RemS: case Expr::I32RemU: - return EmitDivOrMod(f, ValType::I32, IsDiv(false), IsUnsigned(op == Expr::I32RemU), def); + return EmitRem(f, ValType::I32, MIRType::Int32, expr == Expr::I32RemU); case Expr::I32Min: - return EmitMathMinMax(f, ValType::I32, IsMax(false), def); case Expr::I32Max: - return EmitMathMinMax(f, ValType::I32, IsMax(true), def); + return EmitMinMax(f, ValType::I32, MIRType::Int32, expr == Expr::I32Max); case Expr::I32Eqz: - return EmitUnary(f, def); + return EmitConversion(f, ValType::I32, ValType::I32); case Expr::I32TruncSF32: case Expr::I32TruncUF32: - return EmitUnary(f, def); + return EmitTruncate(f, ValType::F32, ValType::I32, expr == Expr::I32TruncUF32); case Expr::I32TruncSF64: case Expr::I32TruncUF64: - return EmitUnary(f, def); + return EmitTruncate(f, ValType::F64, ValType::I32, expr == Expr::I32TruncUF64); case Expr::I32WrapI64: - return EmitUnary(f, def); - case Expr::I32Clz: - return EmitUnary(f, def); - case Expr::I32Ctz: - return EmitUnary(f, def); - case Expr::I32Popcnt: - return EmitUnary(f, def); - case Expr::I32Abs: - return EmitUnaryWithType(f, ValType::I32, def); - case Expr::I32Neg: - return EmitUnaryWithType(f, ValType::I32, def); - case Expr::I32Or: - return EmitBitwise(f, ValType::I32, def); - case Expr::I32And: - return EmitBitwise(f, ValType::I32, def); - case Expr::I32Xor: - return EmitBitwise(f, ValType::I32, def); - case Expr::I32Shl: - return EmitBitwise(f, ValType::I32, def); - case Expr::I32ShrS: - return EmitBitwise(f, ValType::I32, def); - case Expr::I32ShrU: - return EmitBitwise(f, ValType::I32, def); - case Expr::I32BitNot: - return EmitBitwiseNot(f, def); - case Expr::I32Load8S: - return EmitLoad(f, Scalar::Int8, def); - case Expr::I32Load8U: - return EmitLoad(f, Scalar::Uint8, def); - case Expr::I32Load16S: - return EmitLoad(f, Scalar::Int16, def); - case Expr::I32Load16U: - return EmitLoad(f, Scalar::Uint16, def); - case Expr::I32Load: - return EmitLoad(f, Scalar::Int32, def); - case Expr::I32Store8: - return EmitStore(f, Scalar::Int8, def); - case Expr::I32Store16: - return EmitStore(f, Scalar::Int16, def); - case Expr::I32Store: - return EmitStore(f, Scalar::Int32, def); - case Expr::I32Eq: - case Expr::I32Ne: - case Expr::I32LtS: - case Expr::I32LeS: - case Expr::I32GtS: - case Expr::I32GeS: - case Expr::I32LtU: - case Expr::I32LeU: - case Expr::I32GtU: - case Expr::I32GeU: - case Expr::I64Eq: - case Expr::I64Ne: - case Expr::I64LtS: - case Expr::I64LeS: - case Expr::I64LtU: - case Expr::I64LeU: - case Expr::I64GtS: - case Expr::I64GeS: - case Expr::I64GtU: - case Expr::I64GeU: - case Expr::F32Eq: - case Expr::F32Ne: - case Expr::F32Lt: - case Expr::F32Le: - case Expr::F32Gt: - case Expr::F32Ge: - case Expr::F64Eq: - case Expr::F64Ne: - case Expr::F64Lt: - case Expr::F64Le: - case Expr::F64Gt: - case Expr::F64Ge: - return EmitComparison(f, op, def); + return EmitConversion(f, ValType::I64, ValType::I32); case Expr::I32ReinterpretF32: - return EmitReinterpret(f, ValType::I32, def); + return EmitReinterpret(f, ValType::I32, ValType::F32, MIRType::Int32); + case Expr::I32Clz: + return EmitUnary(f, ValType::I32); + case Expr::I32Ctz: + return EmitUnary(f, ValType::I32); + case Expr::I32Popcnt: + return EmitUnary(f, ValType::I32); + case Expr::I32Abs: + return EmitUnaryWithType(f, ValType::I32, MIRType::Int32); + case Expr::I32Neg: + return EmitUnaryWithType(f, ValType::I32, MIRType::Int32); + case Expr::I32Or: + return EmitBitwise(f, ValType::I32, MIRType::Int32); + case Expr::I32And: + return EmitBitwise(f, ValType::I32, MIRType::Int32); + case Expr::I32Xor: + return EmitBitwise(f, ValType::I32, MIRType::Int32); + case Expr::I32Shl: + return EmitBitwise(f, ValType::I32, MIRType::Int32); + case Expr::I32ShrS: + return EmitBitwise(f, ValType::I32, MIRType::Int32); + case Expr::I32ShrU: + return EmitBitwise(f, ValType::I32, MIRType::Int32); + case Expr::I32BitNot: + return EmitBitwise(f, ValType::I32); + case Expr::I32Load8S: + return EmitLoad(f, ValType::I32, Scalar::Int8); + case Expr::I32Load8U: + return EmitLoad(f, ValType::I32, Scalar::Uint8); + case Expr::I32Load16S: + return EmitLoad(f, ValType::I32, Scalar::Int16); + case Expr::I32Load16U: + return EmitLoad(f, ValType::I32, Scalar::Uint16); + case Expr::I32Load: + return EmitLoad(f, ValType::I32, Scalar::Int32); + case Expr::I32Store8: + return EmitStore(f, ValType::I32, Scalar::Int8); + case Expr::I32Store16: + return EmitStore(f, ValType::I32, Scalar::Int16); + case Expr::I32Store: + return EmitStore(f, ValType::I32, Scalar::Int32); + case Expr::I32Rotr: + case Expr::I32Rotl: + return EmitRotate(f, ValType::I32, expr == Expr::I32Rotl); // I64 - case Expr::I64Const: - return EmitLiteral(f, ValType::I64, def); - case Expr::I64ExtendSI32: - case Expr::I64ExtendUI32: - return EmitExtendI32(f, IsUnsigned(op == Expr::I64ExtendUI32), def); - case Expr::I64TruncSF32: - case Expr::I64TruncUF32: - return EmitTruncate(f, IsUnsigned(op == Expr::I64TruncUF32), def); - case Expr::I64TruncSF64: - case Expr::I64TruncUF64: - return EmitTruncate(f, IsUnsigned(op == Expr::I64TruncUF64), def); - case Expr::I64Or: - return EmitBitwise(f, ValType::I64, def); - case Expr::I64And: - return EmitBitwise(f, ValType::I64, def); - case Expr::I64Xor: - return EmitBitwise(f, ValType::I64, def); - case Expr::I64Shl: - return EmitBitwise(f, ValType::I64, def); - case Expr::I64ShrS: - return EmitBitwise(f, ValType::I64, def); - case Expr::I64ShrU: - return EmitBitwise(f, ValType::I64, def); + case Expr::I64Const: { + int64_t i64; + if (!f.iter().readI64Const(&i64)) + return false; + + f.iter().setResult(f.constant(i64)); + return true; + } case Expr::I64Add: - return EmitAddOrSub(f, ValType::I64, IsAdd(true), def); + return EmitBinary(f, ValType::I64, MIRType::Int64); case Expr::I64Sub: - return EmitAddOrSub(f, ValType::I64, IsAdd(false), def); + return EmitBinary(f, ValType::I64, MIRType::Int64); case Expr::I64Mul: - return EmitMultiply(f, ValType::I64, def); + return EmitMul(f, ValType::I64, MIRType::Int64); case Expr::I64DivS: case Expr::I64DivU: - return EmitDivOrMod(f, ValType::I64, IsDiv(true), IsUnsigned(op == Expr::I64DivU), def); + return EmitDiv(f, ValType::I64, MIRType::Int64, expr == Expr::I64DivU); case Expr::I64RemS: case Expr::I64RemU: - return EmitDivOrMod(f, ValType::I64, IsDiv(false), IsUnsigned(op == Expr::I64RemU), def); + return EmitRem(f, ValType::I64, MIRType::Int64, expr == Expr::I64RemU); + case Expr::I64TruncSF32: + case Expr::I64TruncUF32: + return EmitTruncate(f, ValType::F32, ValType::I64, expr == Expr::I64TruncUF32); + case Expr::I64TruncSF64: + case Expr::I64TruncUF64: + return EmitTruncate(f, ValType::F64, ValType::I64, expr == Expr::I64TruncUF64); + case Expr::I64ExtendSI32: + case Expr::I64ExtendUI32: + return EmitExtendI32(f, expr == Expr::I64ExtendUI32); case Expr::I64ReinterpretF64: - return EmitReinterpret(f, ValType::I64, def); + return EmitReinterpret(f, ValType::I64, ValType::F64, MIRType::Int64); + case Expr::I64Or: + return EmitBitwise(f, ValType::I64, MIRType::Int64); + case Expr::I64And: + return EmitBitwise(f, ValType::I64, MIRType::Int64); + case Expr::I64Xor: + return EmitBitwise(f, ValType::I64, MIRType::Int64); + case Expr::I64Shl: + return EmitBitwise(f, ValType::I64, MIRType::Int64); + case Expr::I64ShrS: + return EmitBitwise(f, ValType::I64, MIRType::Int64); + case Expr::I64ShrU: + return EmitBitwise(f, ValType::I64, MIRType::Int64); + case Expr::I64Rotr: + case Expr::I64Rotl: + return EmitRotate(f, ValType::I64, expr == Expr::I64Rotl); // F32 - case Expr::F32Const: - return EmitLiteral(f, ValType::F32, def); + case Expr::F32Const: { + float f32; + if (!f.iter().readF32Const(&f32)) + return false; + + f.iter().setResult(f.constant(Float32Value(f32), MIRType::Float32)); + return true; + } case Expr::F32Add: - return EmitAddOrSub(f, ValType::F32, IsAdd(true), def); + return EmitBinary(f, ValType::F32, MIRType::Float32); case Expr::F32Sub: - return EmitAddOrSub(f, ValType::F32, IsAdd(false), def); + return EmitBinary(f, ValType::F32, MIRType::Float32); case Expr::F32Mul: - return EmitMultiply(f, ValType::F32, def); + return EmitMul(f, ValType::F32, MIRType::Float32); case Expr::F32Div: - return EmitDivOrMod(f, ValType::F32, IsDiv(true), def); + return EmitDiv(f, ValType::F32, MIRType::Float32, /* isUnsigned = */ false); case Expr::F32Min: - return EmitMathMinMax(f, ValType::F32, IsMax(false), def); case Expr::F32Max: - return EmitMathMinMax(f, ValType::F32, IsMax(true), def); + return EmitMinMax(f, ValType::F32, MIRType::Float32, expr == Expr::F32Max); case Expr::F32Neg: - return EmitUnaryWithType(f, ValType::F32, def); + return EmitUnaryWithType(f, ValType::F32, MIRType::Float32); case Expr::F32Abs: - return EmitUnaryWithType(f, ValType::F32, def); + return EmitUnaryWithType(f, ValType::F32, MIRType::Float32); case Expr::F32Sqrt: - return EmitUnaryWithType(f, ValType::F32, def); + return EmitUnaryWithType(f, ValType::F32, MIRType::Float32); case Expr::F32Ceil: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::CeilF, ValType::F32); case Expr::F32Floor: - return EmitF32MathBuiltinCall(f, exprOffset, op, def); + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::FloorF, ValType::F32); case Expr::F32DemoteF64: - return EmitUnary(f, def); + return EmitConversion(f, ValType::F64, ValType::F32); case Expr::F32ConvertSI32: - return EmitUnary(f, def); + return EmitConversion(f, ValType::I32, ValType::F32); case Expr::F32ConvertUI32: - return EmitUnary(f, def); + return EmitConversion(f, ValType::I32, ValType::F32); case Expr::F32ConvertSI64: case Expr::F32ConvertUI64: - return EmitConvertI64ToFloatingPoint(f, ValType::F32, - IsUnsigned(op == Expr::F32ConvertUI64), def); + return EmitConvertI64ToFloatingPoint(f, ValType::F32, MIRType::Float32, + expr == Expr::F32ConvertUI64); + case Expr::F32ReinterpretI32: + return EmitReinterpret(f, ValType::F32, ValType::I32, MIRType::Float32); case Expr::F32Load: - return EmitLoad(f, Scalar::Float32, def); + return EmitLoad(f, ValType::F32, Scalar::Float32); case Expr::F32Store: - return EmitStore(f, Scalar::Float32, def); + return EmitStore(f, ValType::F32, Scalar::Float32); case Expr::F32StoreF64: - return EmitStoreWithCoercion(f, Scalar::Float32, Scalar::Float64, def); - case Expr::F32ReinterpretI32: - return EmitReinterpret(f, ValType::F32, def); + return EmitStoreWithCoercion(f, ValType::F32, Scalar::Float64); // F64 - case Expr::F64Const: - return EmitLiteral(f, ValType::F64, def); + case Expr::F64Const: { + double f64; + if (!f.iter().readF64Const(&f64)) + return false; + + f.iter().setResult(f.constant(DoubleValue(f64), MIRType::Double)); + return true; + } case Expr::F64Add: - return EmitAddOrSub(f, ValType::F64, IsAdd(true), def); + return EmitBinary(f, ValType::F64, MIRType::Double); case Expr::F64Sub: - return EmitAddOrSub(f, ValType::F64, IsAdd(false), def); + return EmitBinary(f, ValType::F64, MIRType::Double); case Expr::F64Mul: - return EmitMultiply(f, ValType::F64, def); + return EmitMul(f, ValType::F64, MIRType::Double); case Expr::F64Div: - return EmitDivOrMod(f, ValType::F64, IsDiv(true), def); + return EmitDiv(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false); case Expr::F64Mod: - return EmitDivOrMod(f, ValType::F64, IsDiv(false), def); + return EmitRem(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false); case Expr::F64Min: - return EmitMathMinMax(f, ValType::F64, IsMax(false), def); case Expr::F64Max: - return EmitMathMinMax(f, ValType::F64, IsMax(true), def); + return EmitMinMax(f, ValType::F64, MIRType::Double, expr == Expr::F64Max); case Expr::F64Neg: - return EmitUnaryWithType(f, ValType::F64, def); + return EmitUnaryWithType(f, ValType::F64, MIRType::Double); case Expr::F64Abs: - return EmitUnaryWithType(f, ValType::F64, def); + return EmitUnaryWithType(f, ValType::F64, MIRType::Double); case Expr::F64Sqrt: - return EmitUnaryWithType(f, ValType::F64, def); + return EmitUnaryWithType(f, ValType::F64, MIRType::Double); case Expr::F64Ceil: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::CeilD, ValType::F64); case Expr::F64Floor: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::FloorD, + ValType::F64); case Expr::F64Sin: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::SinD, ValType::F64); case Expr::F64Cos: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::CosD, ValType::F64); case Expr::F64Tan: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::TanD, ValType::F64); case Expr::F64Asin: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::ASinD, ValType::F64); case Expr::F64Acos: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::ACosD, ValType::F64); case Expr::F64Atan: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::ATanD, ValType::F64); case Expr::F64Exp: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::ExpD, ValType::F64); case Expr::F64Log: + return EmitUnaryMathBuiltinCall(f, exprOffset, SymbolicAddress::LogD, ValType::F64); case Expr::F64Pow: + return EmitBinaryMathBuiltinCall(f, exprOffset, SymbolicAddress::PowD, ValType::F64); case Expr::F64Atan2: - return EmitF64MathBuiltinCall(f, exprOffset, op, def); + return EmitBinaryMathBuiltinCall(f, exprOffset, SymbolicAddress::ATan2D, + ValType::F64); case Expr::F64PromoteF32: - return EmitUnary(f, def); + return EmitConversion(f, ValType::F32, ValType::F64); case Expr::F64ConvertSI32: - return EmitUnary(f, def); + return EmitConversion(f, ValType::I32, ValType::F64); case Expr::F64ConvertUI32: - return EmitUnary(f, def); + return EmitConversion(f, ValType::I32, ValType::F64); case Expr::F64ConvertSI64: case Expr::F64ConvertUI64: - return EmitConvertI64ToFloatingPoint(f, ValType::F64, - IsUnsigned(op == Expr::F64ConvertUI64), def); + return EmitConvertI64ToFloatingPoint(f, ValType::F64, MIRType::Double, + expr == Expr::F64ConvertUI64); case Expr::F64Load: - return EmitLoad(f, Scalar::Float64, def); + return EmitLoad(f, ValType::F64, Scalar::Float64); case Expr::F64Store: - return EmitStore(f, Scalar::Float64, def); + return EmitStore(f, ValType::F64, Scalar::Float64); case Expr::F64StoreF32: - return EmitStoreWithCoercion(f, Scalar::Float64, Scalar::Float32, def); + return EmitStoreWithCoercion(f, ValType::F64, Scalar::Float32); case Expr::F64ReinterpretI64: - return EmitReinterpret(f, ValType::F64, def); + return EmitReinterpret(f, ValType::F64, ValType::I64, MIRType::Double); + + // Comparisons + case Expr::I32Eq: + return EmitComparison(f, ValType::I32, JSOP_EQ, MCompare::Compare_Int32); + case Expr::I32Ne: + return EmitComparison(f, ValType::I32, JSOP_NE, MCompare::Compare_Int32); + case Expr::I32LtS: + return EmitComparison(f, ValType::I32, JSOP_LT, MCompare::Compare_Int32); + case Expr::I32LeS: + return EmitComparison(f, ValType::I32, JSOP_LE, MCompare::Compare_Int32); + case Expr::I32GtS: + return EmitComparison(f, ValType::I32, JSOP_GT, MCompare::Compare_Int32); + case Expr::I32GeS: + return EmitComparison(f, ValType::I32, JSOP_GE, MCompare::Compare_Int32); + case Expr::I32LtU: + return EmitComparison(f, ValType::I32, JSOP_LT, MCompare::Compare_UInt32); + case Expr::I32LeU: + return EmitComparison(f, ValType::I32, JSOP_LE, MCompare::Compare_UInt32); + case Expr::I32GtU: + return EmitComparison(f, ValType::I32, JSOP_GT, MCompare::Compare_UInt32); + case Expr::I32GeU: + return EmitComparison(f, ValType::I32, JSOP_GE, MCompare::Compare_UInt32); + case Expr::I64Eq: + return EmitComparison(f, ValType::I64, JSOP_EQ, MCompare::Compare_Int64); + case Expr::I64Ne: + return EmitComparison(f, ValType::I64, JSOP_NE, MCompare::Compare_Int64); + case Expr::I64LtS: + return EmitComparison(f, ValType::I64, JSOP_LT, MCompare::Compare_Int64); + case Expr::I64LeS: + return EmitComparison(f, ValType::I64, JSOP_LE, MCompare::Compare_Int64); + case Expr::I64GtS: + return EmitComparison(f, ValType::I64, JSOP_GT, MCompare::Compare_Int64); + case Expr::I64GeS: + return EmitComparison(f, ValType::I64, JSOP_GE, MCompare::Compare_Int64); + case Expr::I64LtU: + return EmitComparison(f, ValType::I64, JSOP_LT, MCompare::Compare_UInt64); + case Expr::I64LeU: + return EmitComparison(f, ValType::I64, JSOP_LE, MCompare::Compare_UInt64); + case Expr::I64GtU: + return EmitComparison(f, ValType::I64, JSOP_GT, MCompare::Compare_UInt64); + case Expr::I64GeU: + return EmitComparison(f, ValType::I64, JSOP_GE, MCompare::Compare_UInt64); + case Expr::F32Eq: + return EmitComparison(f, ValType::F32, JSOP_EQ, MCompare::Compare_Float32); + case Expr::F32Ne: + return EmitComparison(f, ValType::F32, JSOP_NE, MCompare::Compare_Float32); + case Expr::F32Lt: + return EmitComparison(f, ValType::F32, JSOP_LT, MCompare::Compare_Float32); + case Expr::F32Le: + return EmitComparison(f, ValType::F32, JSOP_LE, MCompare::Compare_Float32); + case Expr::F32Gt: + return EmitComparison(f, ValType::F32, JSOP_GT, MCompare::Compare_Float32); + case Expr::F32Ge: + return EmitComparison(f, ValType::F32, JSOP_GE, MCompare::Compare_Float32); + case Expr::F64Eq: + return EmitComparison(f, ValType::F64, JSOP_EQ, MCompare::Compare_Double); + case Expr::F64Ne: + return EmitComparison(f, ValType::F64, JSOP_NE, MCompare::Compare_Double); + case Expr::F64Lt: + return EmitComparison(f, ValType::F64, JSOP_LT, MCompare::Compare_Double); + case Expr::F64Le: + return EmitComparison(f, ValType::F64, JSOP_LE, MCompare::Compare_Double); + case Expr::F64Gt: + return EmitComparison(f, ValType::F64, JSOP_GT, MCompare::Compare_Double); + case Expr::F64Ge: + return EmitComparison(f, ValType::F64, JSOP_GE, MCompare::Compare_Double); // SIMD #define CASE(TYPE, OP, SIGN) \ case Expr::TYPE##OP: \ - return EmitSimdOp(f, ValType::TYPE, SimdOperation::Fn_##OP, SIGN, def); + return EmitSimdOp(f, ValType::TYPE, SimdOperation::Fn_##OP, SIGN); #define I32CASE(OP) CASE(I32x4, OP, SimdSign::Signed) #define F32CASE(OP) CASE(F32x4, OP, SimdSign::NotApplicable) #define B32CASE(OP) CASE(B32x4, OP, SimdSign::NotApplicable) #define ENUMERATE(TYPE, FORALL, DO) \ - case Expr::TYPE##Const: \ - return EmitLiteral(f, ValType::TYPE, def); \ case Expr::TYPE##Constructor: \ - return EmitSimdOp(f, ValType::TYPE, SimdOperation::Constructor, \ - SimdSign::NotApplicable, def); \ + return EmitSimdOp(f, ValType::TYPE, SimdOperation::Constructor, SimdSign::NotApplicable); \ FORALL(DO) ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32CASE) @@ -3099,36 +3112,56 @@ EmitExpr(FunctionCompiler& f, MDefinition** def) #undef B32CASE #undef ENUMERATE + case Expr::I32x4Const: { + I32x4 i32x4; + if (!f.iter().readI32x4Const(&i32x4)) + return false; + + f.iter().setResult(f.constant(SimdConstant::CreateX4(i32x4), MIRType::Int32x4)); + return true; + } + case Expr::F32x4Const: { + F32x4 f32x4; + if (!f.iter().readF32x4Const(&f32x4)) + return false; + + f.iter().setResult(f.constant(SimdConstant::CreateX4(f32x4), MIRType::Float32x4)); + return true; + } + case Expr::B32x4Const: { + I32x4 i32x4; + if (!f.iter().readB32x4Const(&i32x4)) + return false; + + f.iter().setResult(f.constant(SimdConstant::CreateX4(i32x4), MIRType::Bool32x4)); + return true; + } + // SIMD unsigned integer operations. case Expr::I32x4shiftRightByScalarU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_shiftRightByScalar, - SimdSign::Unsigned, def); + return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned); case Expr::I32x4lessThanU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThan, SimdSign::Unsigned, def); + return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThan, SimdSign::Unsigned); case Expr::I32x4lessThanOrEqualU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThanOrEqual, - SimdSign::Unsigned, def); + return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned); case Expr::I32x4greaterThanU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThan, SimdSign::Unsigned, - def); + return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThan, SimdSign::Unsigned); case Expr::I32x4greaterThanOrEqualU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThanOrEqual, - SimdSign::Unsigned, def); + return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned); case Expr::I32x4fromFloat32x4U: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_fromFloat32x4, - SimdSign::Unsigned, def); + return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_fromFloat32x4, SimdSign::Unsigned); // Atomics - case Expr::I32AtomicsCompareExchange: - return EmitAtomicsCompareExchange(f, def); - case Expr::I32AtomicsExchange: - return EmitAtomicsExchange(f, def); case Expr::I32AtomicsLoad: - return EmitAtomicsLoad(f, def); + return EmitAtomicsLoad(f); case Expr::I32AtomicsStore: - return EmitAtomicsStore(f, def); + return EmitAtomicsStore(f); case Expr::I32AtomicsBinOp: - return EmitAtomicsBinOp(f, def); + return EmitAtomicsBinOp(f); + case Expr::I32AtomicsCompareExchange: + return EmitAtomicsCompareExchange(f); + case Expr::I32AtomicsExchange: + return EmitAtomicsExchange(f); // Future opcodes case Expr::F32CopySign: @@ -3152,14 +3185,9 @@ EmitExpr(FunctionCompiler& f, MDefinition** def) case Expr::I64Ctz: case Expr::I64Popcnt: case Expr::I64Eqz: - case Expr::I32Rotr: - case Expr::I32Rotl: - case Expr::I64Rotr: - case Expr::I64Rotl: - case Expr::MemorySize: + case Expr::CurrentMemory: case Expr::GrowMemory: MOZ_CRASH("NYI"); - break; case Expr::Limit:; } @@ -3192,8 +3220,8 @@ wasm::IonCompileFunction(IonCompileTask* task) CompileInfo compileInfo(locals.length()); MIRGenerator mir(nullptr, options, &results.alloc(), &graph, &compileInfo, IonOptimizations.get(OptimizationLevel::AsmJS)); - mir.initUsesSignalHandlersForAsmJSOOB(task->mg().args().useSignalHandlersForOOB); - mir.initMinAsmJSHeapLength(task->mg().minHeapLength()); + mir.initUsesSignalHandlersForAsmJSOOB(task->mg().args.useSignalHandlersForOOB); + mir.initMinAsmJSHeapLength(task->mg().minHeapLength); // Build MIR graph { @@ -3201,16 +3229,21 @@ wasm::IonCompileFunction(IonCompileTask* task) if (!f.init()) return false; - MDefinition* last; + if (!f.iter().readFunctionStart()) + return false; + while (!f.done()) { - if (!EmitExpr(f, &last)) + if (!EmitExpr(f)) return false; } + MDefinition* value; + if (!f.iter().readFunctionEnd(f.sig().ret(), &value)) + return false; if (IsVoid(f.sig().ret())) f.returnVoid(); else - f.returnExpr(last); + f.returnExpr(value); f.finish(); } diff --git a/js/src/asmjs/WasmIonCompile.h b/js/src/asmjs/WasmIonCompile.h index 7e91f2042e..f5eff686c3 100644 --- a/js/src/asmjs/WasmIonCompile.h +++ b/js/src/asmjs/WasmIonCompile.h @@ -25,7 +25,7 @@ namespace js { namespace wasm { -class ModuleGeneratorThreadView; +struct ModuleGeneratorData; typedef Vector MIRTypeVector; typedef jit::ABIArgIter ABIArgMIRTypeIter; @@ -108,7 +108,7 @@ class FuncCompileResults class IonCompileTask { JSRuntime* const runtime_; - ModuleGeneratorThreadView& mg_; + const ModuleGeneratorData& mg_; LifoAlloc lifo_; UniqueFuncBytes func_; Maybe results_; @@ -117,7 +117,7 @@ class IonCompileTask IonCompileTask& operator=(const IonCompileTask&) = delete; public: - IonCompileTask(JSRuntime* rt, ModuleGeneratorThreadView& mg, size_t defaultChunkSize) + IonCompileTask(JSRuntime* rt, const ModuleGeneratorData& mg, size_t defaultChunkSize) : runtime_(rt), mg_(mg), lifo_(defaultChunkSize), func_(nullptr) {} JSRuntime* runtime() const { @@ -126,7 +126,7 @@ class IonCompileTask LifoAlloc& lifo() { return lifo_; } - ModuleGeneratorThreadView& mg() const { + const ModuleGeneratorData& mg() const { return mg_; } void init(UniqueFuncBytes func) { diff --git a/js/src/asmjs/WasmModule.h b/js/src/asmjs/WasmModule.h index 9cf19d1fd4..7036767fa4 100644 --- a/js/src/asmjs/WasmModule.h +++ b/js/src/asmjs/WasmModule.h @@ -501,7 +501,7 @@ class Module : public mozilla::LinkedListElement void specializeToHeap(ArrayBufferObjectMaybeShared* heap); void despecializeFromHeap(ArrayBufferObjectMaybeShared* heap); bool sendCodeRangesToProfiler(JSContext* cx); - MOZ_WARN_UNUSED_RESULT bool setProfilingEnabled(JSContext* cx, bool enabled); + MOZ_MUST_USE bool setProfilingEnabled(JSContext* cx, bool enabled); ImportExit& importToExit(const Import& import); friend class js::WasmActivation; @@ -552,6 +552,7 @@ class Module : public mozilla::LinkedListElement const AsmJSModule& asAsmJS() const { MOZ_ASSERT(isAsmJS()); return *(const AsmJSModule*)this; } virtual bool mutedErrors() const; virtual const char16_t* displayURL() const; + virtual ScriptSource* maybeScriptSource() const { return nullptr; } // The range [0, functionBytes) is a subrange of [0, codeBytes) that // contains only function body code, not the stub code. This distinction is diff --git a/js/src/asmjs/WasmSignalHandlers.cpp b/js/src/asmjs/WasmSignalHandlers.cpp index 2eaa6f7a5e..88858a99b9 100644 --- a/js/src/asmjs/WasmSignalHandlers.cpp +++ b/js/src/asmjs/WasmSignalHandlers.cpp @@ -670,8 +670,7 @@ EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddre uint32_t wrappedOffset = uint32_t(unwrappedOffset); size_t size = access.size(); MOZ_RELEASE_ASSERT(wrappedOffset + size > wrappedOffset); - bool inBounds = wrappedOffset < module.heapLength() && - wrappedOffset + size < module.heapLength(); + bool inBounds = wrappedOffset + size < module.heapLength(); // If this is storing Z of an XYZ, check whether X is also in bounds, so // that we don't store anything before throwing. diff --git a/js/src/asmjs/WasmStubs.cpp b/js/src/asmjs/WasmStubs.cpp index 66f4701219..0019b1cfed 100644 --- a/js/src/asmjs/WasmStubs.cpp +++ b/js/src/asmjs/WasmStubs.cpp @@ -20,6 +20,8 @@ #include "mozilla/ArrayUtils.h" +#include "asmjs/WasmIonCompile.h" + #include "jit/MacroAssembler-inl.h" using namespace js; @@ -166,12 +168,12 @@ wasm::GenerateEntry(MacroAssembler& masm, unsigned target, const Sig& sig, bool unsigned argOffset = iter.index() * Module::SizeOfEntryArg; Address src(argv, argOffset); MIRType type = iter.mirType(); - MOZ_ASSERT_IF(type == MIRType_Int64, JitOptions.wasmTestMode); + MOZ_ASSERT_IF(type == MIRType::Int64, JitOptions.wasmTestMode); switch (iter->kind()) { case ABIArg::GPR: - if (type == MIRType_Int32) + if (type == MIRType::Int32) masm.load32(src, iter->gpr()); - else if (type == MIRType_Int64) + else if (type == MIRType::Int64) masm.load64(src, iter->gpr64()); break; #ifdef JS_CODEGEN_REGISTER_PAIR @@ -183,17 +185,17 @@ wasm::GenerateEntry(MacroAssembler& masm, unsigned target, const Sig& sig, bool static_assert(Module::SizeOfEntryArg >= jit::Simd128DataSize, "EntryArg must be big enough to store SIMD values"); switch (type) { - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: masm.loadUnalignedInt32x4(src, iter->fpu()); break; - case MIRType_Float32x4: + case MIRType::Float32x4: masm.loadUnalignedFloat32x4(src, iter->fpu()); break; - case MIRType_Double: + case MIRType::Double: masm.loadDouble(src, iter->fpu()); break; - case MIRType_Float32: + case MIRType::Float32: masm.loadFloat32(src, iter->fpu()); break; default: @@ -204,29 +206,29 @@ wasm::GenerateEntry(MacroAssembler& masm, unsigned target, const Sig& sig, bool } case ABIArg::Stack: switch (type) { - case MIRType_Int32: + case MIRType::Int32: masm.load32(src, scratch); masm.storePtr(scratch, Address(masm.getStackPointer(), iter->offsetFromArgBase())); break; - case MIRType_Int64: + case MIRType::Int64: masm.load64(src, scratch64); masm.store64(scratch64, Address(masm.getStackPointer(), iter->offsetFromArgBase())); break; - case MIRType_Double: + case MIRType::Double: masm.loadDouble(src, ScratchDoubleReg); masm.storeDouble(ScratchDoubleReg, Address(masm.getStackPointer(), iter->offsetFromArgBase())); break; - case MIRType_Float32: + case MIRType::Float32: masm.loadFloat32(src, ScratchFloat32Reg); masm.storeFloat32(ScratchFloat32Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase())); break; - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: masm.loadUnalignedInt32x4(src, ScratchSimd128Reg); masm.storeAlignedInt32x4(ScratchSimd128Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase())); break; - case MIRType_Float32x4: + case MIRType::Float32x4: masm.loadUnalignedFloat32x4(src, ScratchSimd128Reg); masm.storeAlignedFloat32x4(ScratchSimd128Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase())); @@ -303,16 +305,16 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO Address dstAddr(masm.getStackPointer(), argOffset + i.index() * sizeof(Value)); MIRType type = i.mirType(); - MOZ_ASSERT_IF(type == MIRType_Int64, JitOptions.wasmTestMode); + MOZ_ASSERT_IF(type == MIRType::Int64, JitOptions.wasmTestMode); switch (i->kind()) { case ABIArg::GPR: - if (type == MIRType_Int32) { + if (type == MIRType::Int32) { if (toValue) masm.storeValue(JSVAL_TYPE_INT32, i->gpr(), dstAddr); else masm.store32(i->gpr(), dstAddr); - } else if (type == MIRType_Int64) { + } else if (type == MIRType::Int64) { // We can't box int64 into Values (yet). if (toValue) masm.breakpoint(); @@ -331,7 +333,7 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO MOZ_ASSERT(IsFloatingPointType(type)); FloatRegister srcReg = i->fpu(); if (toValue) { - if (type == MIRType_Float32) { + if (type == MIRType::Float32) { masm.convertFloat32ToDouble(i->fpu(), ScratchDoubleReg); srcReg = ScratchDoubleReg; } @@ -341,14 +343,14 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO break; } case ABIArg::Stack: - if (type == MIRType_Int32) { + if (type == MIRType::Int32) { Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase()); masm.load32(src, scratch); if (toValue) masm.storeValue(JSVAL_TYPE_INT32, scratch, dstAddr); else masm.store32(scratch, dstAddr); - } else if (type == MIRType_Int64) { + } else if (type == MIRType::Int64) { // We can't box int64 into Values (yet). if (toValue) { masm.breakpoint(); @@ -361,7 +363,7 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO MOZ_ASSERT(IsFloatingPointType(type)); Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase()); if (toValue) { - if (type == MIRType_Float32) { + if (type == MIRType::Float32) { masm.loadFloat32(src, ScratchFloat32Reg); masm.convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg); } else { @@ -389,9 +391,9 @@ wasm::GenerateInterpExit(MacroAssembler& masm, const Import& import, uint32_t im masm.setFramePushed(0); // Argument types for InvokeImport_*: - static const MIRType typeArray[] = { MIRType_Pointer, // ImportExit - MIRType_Int32, // argc - MIRType_Pointer }; // argv + static const MIRType typeArray[] = { MIRType::Pointer, // ImportExit + MIRType::Int32, // argc + MIRType::Pointer }; // argv MIRTypeVector invokeArgTypes; MOZ_ALWAYS_TRUE(invokeArgTypes.append(typeArray, ArrayLength(typeArray))); @@ -745,7 +747,7 @@ wasm::GenerateJitExit(MacroAssembler& masm, const Import& import, bool usesHeap) // Coercion calls use the following stack layout (sp grows to the left): // | args | padding | Value argv[1] | padding | exit AsmJSFrame | MIRTypeVector coerceArgTypes; - JS_ALWAYS_TRUE(coerceArgTypes.append(MIRType_Pointer)); + JS_ALWAYS_TRUE(coerceArgTypes.append(MIRType::Pointer)); unsigned offsetToCoerceArgv = AlignBytes(StackArgBytes(coerceArgTypes), sizeof(Value)); MOZ_ASSERT(nativeFramePushed >= offsetToCoerceArgv + sizeof(Value)); AssertStackAlignment(masm, ABIStackAlignment); @@ -901,6 +903,10 @@ wasm::GenerateJumpTarget(MacroAssembler& masm, JumpTarget target) return GenerateErrorStub(masm, SymbolicAddress::BadIndirectCall); case JumpTarget::UnreachableTrap: return GenerateErrorStub(masm, SymbolicAddress::UnreachableTrap); + case JumpTarget::InvalidConversionToIntegerTrap: + return GenerateErrorStub(masm, SymbolicAddress::InvalidConversionToIntegerTrap); + case JumpTarget::IntegerOverflowTrap: + return GenerateErrorStub(masm, SymbolicAddress::IntegerOverflowTrap); case JumpTarget::Throw: return GenerateThrow(masm); case JumpTarget::Limit: diff --git a/js/src/asmjs/WasmTextToBinary.cpp b/js/src/asmjs/WasmTextToBinary.cpp index 4c744dfa24..2770fb9745 100644 --- a/js/src/asmjs/WasmTextToBinary.cpp +++ b/js/src/asmjs/WasmTextToBinary.cpp @@ -305,8 +305,8 @@ class WasmAstBlock : public WasmAstExpr public: static const WasmAstExprKind Kind = WasmAstExprKind::Block; - explicit WasmAstBlock(Expr expr, WasmName breakName, WasmName continueName, - WasmAstExprVector&& exprs) + explicit WasmAstBlock(Expr expr, WasmName breakName, + WasmName continueName, WasmAstExprVector&& exprs) : WasmAstExpr(Kind), expr_(expr), breakName_(breakName), @@ -471,18 +471,22 @@ class WasmAstBranchTable : public WasmAstExpr WasmAstExpr& index_; WasmRef default_; WasmRefVector table_; + WasmAstExpr* value_; public: static const WasmAstExprKind Kind = WasmAstExprKind::BranchTable; - explicit WasmAstBranchTable(WasmAstExpr& index, WasmRef def, WasmRefVector&& table) + explicit WasmAstBranchTable(WasmAstExpr& index, WasmRef def, WasmRefVector&& table, + WasmAstExpr* maybeValue) : WasmAstExpr(Kind), index_(index), default_(def), - table_(Move(table)) + table_(Move(table)), + value_(maybeValue) {} WasmAstExpr& index() const { return index_; } WasmRef& def() { return default_; } WasmRefVector& table() { return table_; } + WasmAstExpr* maybeValue() { return value_; } }; class WasmAstFunc : public WasmAstNode @@ -1004,7 +1008,7 @@ IsWasmLetter(char16_t c) static bool IsNameAfterDollar(char16_t c) { - return IsWasmLetter(c) || IsWasmDigit(c) || c == '_' || c == '$' || c == '-'; + return IsWasmLetter(c) || IsWasmDigit(c) || c == '_' || c == '$' || c == '-' || c == '.'; } static bool @@ -2800,7 +2804,17 @@ ParseBranchTable(WasmParseContext& c, WasmToken brTable) if (!index) return nullptr; - return new(c.lifo) WasmAstBranchTable(*index, def, Move(table)); + WasmAstExpr* value = nullptr; + if (c.ts.getIf(WasmToken::OpenParen)) { + value = index; + index = ParseExprInsideParens(c); + if (!index) + return nullptr; + if (!c.ts.match(WasmToken::CloseParen, c.error)) + return nullptr; + } + + return new(c.lifo) WasmAstBranchTable(*index, def, Move(table), value); } static WasmAstExpr* @@ -3481,9 +3495,18 @@ ResolveConversionOperator(Resolver& r, WasmAstConversionOperator& b) static bool ResolveIfElse(Resolver& r, WasmAstIf& i) { - return ResolveExpr(r, i.cond()) && - ResolveExpr(r, i.thenBranch()) && - (!i.hasElse() || ResolveExpr(r, i.elseBranch())); + if (!ResolveExpr(r, i.cond())) + return false; + if (!r.pushTarget(WasmName())) + return false; + if (!ResolveExpr(r, i.thenBranch())) + return false; + if (i.hasElse()) { + if (!ResolveExpr(r, i.elseBranch())) + return false; + } + r.popTarget(WasmName()); + return true; } static bool @@ -3654,14 +3677,15 @@ EncodeBlock(Encoder& e, WasmAstBlock& b) return false; size_t numExprs = b.exprs().length(); - if (!e.writeVarU32(numExprs)) - return false; for (size_t i = 0; i < numExprs; i++) { if (!EncodeExpr(e, *b.exprs()[i])) return false; } + if (!e.writeExpr(Expr::End)) + return false; + return true; } @@ -3670,20 +3694,27 @@ EncodeBranch(Encoder& e, WasmAstBranch& br) { MOZ_ASSERT(br.expr() == Expr::Br || br.expr() == Expr::BrIf); - if (!e.writeExpr(br.expr())) - return false; - - if (!e.writeVarU32(br.target().index())) - return false; - - if (br.maybeValue() ? !EncodeExpr(e, *br.maybeValue()) : !e.writeExpr(Expr::Nop)) - return false; + uint32_t arity = 0; + if (br.maybeValue()) { + arity = 1; + if (!EncodeExpr(e, *br.maybeValue())) + return false; + } if (br.expr() == Expr::BrIf) { if (!EncodeExpr(e, br.cond())) return false; } + if (!e.writeExpr(br.expr())) + return false; + + if (!e.writeVarU32(arity)) + return false; + + if (!e.writeVarU32(br.target().index())) + return false; + return true; } @@ -3701,13 +3732,16 @@ EncodeArgs(Encoder& e, const WasmAstExprVector& args) static bool EncodeCall(Encoder& e, WasmAstCall& c) { + if (!EncodeArgs(e, c.args())) + return false; + if (!e.writeExpr(c.expr())) return false; - if (!e.writeVarU32(c.func().index())) + if (!e.writeVarU32(c.args().length())) return false; - if (!EncodeArgs(e, c.args())) + if (!e.writeVarU32(c.func().index())) return false; return true; @@ -3716,18 +3750,21 @@ EncodeCall(Encoder& e, WasmAstCall& c) static bool EncodeCallIndirect(Encoder& e, WasmAstCallIndirect& c) { - if (!e.writeExpr(Expr::CallIndirect)) - return false; - - if (!e.writeVarU32(c.sig().index())) - return false; - if (!EncodeExpr(e, *c.index())) return false; if (!EncodeArgs(e, c.args())) return false; + if (!e.writeExpr(Expr::CallIndirect)) + return false; + + if (!e.writeVarU32(c.args().length())) + return false; + + if (!e.writeVarU32(c.sig().index())) + return false; + return true; } @@ -3763,95 +3800,130 @@ EncodeGetLocal(Encoder& e, WasmAstGetLocal& gl) static bool EncodeSetLocal(Encoder& e, WasmAstSetLocal& sl) { - return e.writeExpr(Expr::SetLocal) && - e.writeVarU32(sl.local().index()) && - EncodeExpr(e, sl.value()); + return EncodeExpr(e, sl.value()) && + e.writeExpr(Expr::SetLocal) && + e.writeVarU32(sl.local().index()); } static bool EncodeUnaryOperator(Encoder& e, WasmAstUnaryOperator& b) { - return e.writeExpr(b.expr()) && - EncodeExpr(e, *b.op()); + return EncodeExpr(e, *b.op()) && + e.writeExpr(b.expr()); } static bool EncodeBinaryOperator(Encoder& e, WasmAstBinaryOperator& b) { - return e.writeExpr(b.expr()) && - EncodeExpr(e, *b.lhs()) && - EncodeExpr(e, *b.rhs()); + return EncodeExpr(e, *b.lhs()) && + EncodeExpr(e, *b.rhs()) && + e.writeExpr(b.expr()); } static bool EncodeTernaryOperator(Encoder& e, WasmAstTernaryOperator& b) { - return e.writeExpr(b.expr()) && - EncodeExpr(e, *b.op0()) && + return EncodeExpr(e, *b.op0()) && EncodeExpr(e, *b.op1()) && - EncodeExpr(e, *b.op2()); + EncodeExpr(e, *b.op2()) && + e.writeExpr(b.expr()); } static bool EncodeComparisonOperator(Encoder& e, WasmAstComparisonOperator& b) { - return e.writeExpr(b.expr()) && - EncodeExpr(e, *b.lhs()) && - EncodeExpr(e, *b.rhs()); + return EncodeExpr(e, *b.lhs()) && + EncodeExpr(e, *b.rhs()) && + e.writeExpr(b.expr()); } static bool EncodeConversionOperator(Encoder& e, WasmAstConversionOperator& b) { - return e.writeExpr(b.expr()) && - EncodeExpr(e, *b.op()); + return EncodeExpr(e, *b.op()) && + e.writeExpr(b.expr()); } static bool EmitIf(Encoder& e, WasmAstIf& i) { - return e.writeExpr(i.hasElse() ? Expr::IfElse : Expr::If) && - EncodeExpr(e, i.cond()) && + return EncodeExpr(e, i.cond()) && + e.writeExpr(Expr::If) && EncodeExpr(e, i.thenBranch()) && - (!i.hasElse() || EncodeExpr(e, i.elseBranch())); + (!i.hasElse() || + (e.writeExpr(Expr::Else) && + EncodeExpr(e, i.elseBranch()))) && + e.writeExpr(Expr::End); } static bool EncodeLoadStoreAddress(Encoder &e, const WasmAstLoadStoreAddress &address) +{ + return EncodeExpr(e, address.base()); +} + +static bool +EncodeLoadStoreFlags(Encoder &e, const WasmAstLoadStoreAddress &address) { return e.writeVarU32(address.flags()) && - e.writeVarU32(address.offset()) && - EncodeExpr(e, address.base()); + e.writeVarU32(address.offset()); } static bool EncodeLoad(Encoder& e, WasmAstLoad& l) { - return e.writeExpr(l.expr()) && - EncodeLoadStoreAddress(e, l.address()); + return EncodeLoadStoreAddress(e, l.address()) && + e.writeExpr(l.expr()) && + EncodeLoadStoreFlags(e, l.address()); } static bool EncodeStore(Encoder& e, WasmAstStore& s) { - return e.writeExpr(s.expr()) && - EncodeLoadStoreAddress(e, s.address()) && - EncodeExpr(e, s.value()); + return EncodeLoadStoreAddress(e, s.address()) && + EncodeExpr(e, s.value()) && + e.writeExpr(s.expr()) && + EncodeLoadStoreFlags(e, s.address()); } static bool EncodeReturn(Encoder& e, WasmAstReturn& r) { - return e.writeExpr(Expr::Return) && - (!r.maybeExpr() || EncodeExpr(e, *r.maybeExpr())); + uint32_t arity = 0; + if (r.maybeExpr()) { + arity = 1; + if (!EncodeExpr(e, *r.maybeExpr())) + return false; + } + + if (!e.writeExpr(Expr::Return)) + return false; + + if (!e.writeVarU32(arity)) + return false; + + return true; } static bool EncodeBranchTable(Encoder& e, WasmAstBranchTable& bt) { + uint32_t arity = 0; + if (bt.maybeValue()) { + arity = 1; + if (!EncodeExpr(e, *bt.maybeValue())) + return false; + } + + if (!EncodeExpr(e, bt.index())) + return false; + if (!e.writeExpr(Expr::BrTable)) return false; + if (!e.writeVarU32(arity)) + return false; + if (!e.writeVarU32(bt.table().length())) return false; @@ -3863,7 +3935,7 @@ EncodeBranchTable(Encoder& e, WasmAstBranchTable& bt) if (!e.writeFixedU32(bt.def().index())) return false; - return EncodeExpr(e, bt.index()); + return true; } static bool @@ -3916,29 +3988,37 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr) // wasm AST binary serialization static bool -EncodeSignatures(Encoder& e, WasmAstModule& module) +EncodeTypeSection(Encoder& e, WasmAstModule& module) { if (module.sigs().empty()) return true; size_t offset; - if (!e.startSection(SignaturesId, &offset)) + if (!e.startSection(TypeSectionId, &offset)) return false; if (!e.writeVarU32(module.sigs().length())) return false; for (WasmAstSig* sig : module.sigs()) { - if (!e.writeVarU32(sig->args().length())) + if (!e.writeVarU32(uint32_t(TypeConstructor::Function))) return false; - if (!e.writeExprType(sig->ret())) + if (!e.writeVarU32(sig->args().length())) return false; for (ValType t : sig->args()) { if (!e.writeValType(t)) return false; } + + if (!e.writeVarU32(!IsVoid(sig->ret()))) + return false; + + if (!IsVoid(sig->ret())) { + if (!e.writeValType(NonVoidToValType(sig->ret()))) + return false; + } } e.finishSection(offset); @@ -3946,13 +4026,13 @@ EncodeSignatures(Encoder& e, WasmAstModule& module) } static bool -EncodeFunctionSignatures(Encoder& e, WasmAstModule& module) +EncodeFunctionSection(Encoder& e, WasmAstModule& module) { if (module.funcs().empty()) return true; size_t offset; - if (!e.startSection(FunctionSignaturesId, &offset)) + if (!e.startSection(FunctionSectionId, &offset)) return false; if (!e.writeVarU32(module.funcs().length())) @@ -3991,13 +4071,13 @@ EncodeImport(Encoder& e, WasmAstImport& imp) } static bool -EncodeImportTable(Encoder& e, WasmAstModule& module) +EncodeImportSection(Encoder& e, WasmAstModule& module) { if (module.imports().empty()) return true; size_t offset; - if (!e.startSection(ImportTableId, &offset)) + if (!e.startSection(ImportSectionId, &offset)) return false; if (!e.writeVarU32(module.imports().length())) @@ -4013,13 +4093,13 @@ EncodeImportTable(Encoder& e, WasmAstModule& module) } static bool -EncodeMemory(Encoder& e, WasmAstModule& module) +EncodeMemorySection(Encoder& e, WasmAstModule& module) { if (!module.maybeMemory()) return true; size_t offset; - if (!e.startSection(MemoryId, &offset)) + if (!e.startSection(MemorySectionId, &offset)) return false; WasmAstMemory& memory = *module.maybeMemory(); @@ -4059,7 +4139,7 @@ EncodeFunctionExport(Encoder& e, WasmAstExport& exp) } static bool -EncodeExportTable(Encoder& e, WasmAstModule& module) +EncodeExportSection(Encoder& e, WasmAstModule& module) { uint32_t numFuncExports = 0; for (WasmAstExport* exp : module.exports()) { @@ -4071,7 +4151,7 @@ EncodeExportTable(Encoder& e, WasmAstModule& module) return true; size_t offset; - if (!e.startSection(ExportTableId, &offset)) + if (!e.startSection(ExportSectionId, &offset)) return false; if (!e.writeVarU32(numFuncExports)) @@ -4093,13 +4173,13 @@ EncodeExportTable(Encoder& e, WasmAstModule& module) } static bool -EncodeFunctionTable(Encoder& e, WasmAstModule& module) +EncodeTableSection(Encoder& e, WasmAstModule& module) { if (!module.maybeTable()) return true; size_t offset; - if (!e.startSection(FunctionTableId, &offset)) + if (!e.startSection(TableSectionId, &offset)) return false; if (!e.writeVarU32(module.maybeTable()->elems().length())) @@ -4139,13 +4219,13 @@ EncodeFunctionBody(Encoder& e, WasmAstFunc& func) } static bool -EncodeFunctionBodies(Encoder& e, WasmAstModule& module) +EncodeCodeSection(Encoder& e, WasmAstModule& module) { if (module.funcs().empty()) return true; size_t offset; - if (!e.startSection(FunctionBodiesId, &offset)) + if (!e.startSection(CodeSectionId, &offset)) return false; if (!e.writeVarU32(module.funcs().length())) @@ -4187,7 +4267,7 @@ EncodeDataSegment(Encoder& e, WasmAstSegment& segment) } static bool -EncodeDataSegments(Encoder& e, WasmAstModule& module) +EncodeDataSection(Encoder& e, WasmAstModule& module) { if (!module.maybeMemory() || module.maybeMemory()->segments().empty()) return true; @@ -4195,7 +4275,7 @@ EncodeDataSegments(Encoder& e, WasmAstModule& module) const WasmAstSegmentVector& segments = module.maybeMemory()->segments(); size_t offset; - if (!e.startSection(DataSegmentsId, &offset)) + if (!e.startSection(DataSectionId, &offset)) return false; if (!e.writeVarU32(segments.length())) @@ -4221,28 +4301,28 @@ EncodeModule(WasmAstModule& module, Bytes* bytes) if (!e.writeFixedU32(EncodingVersion)) return false; - if (!EncodeSignatures(e, module)) + if (!EncodeTypeSection(e, module)) return false; - if (!EncodeImportTable(e, module)) + if (!EncodeImportSection(e, module)) return false; - if (!EncodeFunctionSignatures(e, module)) + if (!EncodeFunctionSection(e, module)) return false; - if (!EncodeFunctionTable(e, module)) + if (!EncodeTableSection(e, module)) return false; - if (!EncodeMemory(e, module)) + if (!EncodeMemorySection(e, module)) return false; - if (!EncodeExportTable(e, module)) + if (!EncodeExportSection(e, module)) return false; - if (!EncodeFunctionBodies(e, module)) + if (!EncodeCodeSection(e, module)) return false; - if (!EncodeDataSegments(e, module)) + if (!EncodeDataSection(e, module)) return false; return true; diff --git a/js/src/asmjs/WasmTypes.cpp b/js/src/asmjs/WasmTypes.cpp index 610653626b..c293212141 100644 --- a/js/src/asmjs/WasmTypes.cpp +++ b/js/src/asmjs/WasmTypes.cpp @@ -86,6 +86,20 @@ UnreachableTrap() JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_UNREACHABLE); } +static void +IntegerOverflowTrap() +{ + JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_INTEGER_OVERFLOW); +} + +static void +InvalidConversionToIntegerTrap() +{ + JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_INVALID_CONVERSION); +} + static int32_t CoerceInPlace_ToInt32(MutableHandleValue val) { @@ -238,6 +252,10 @@ wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx) return FuncCast(BadIndirectCall, Args_General0); case SymbolicAddress::UnreachableTrap: return FuncCast(UnreachableTrap, Args_General0); + case SymbolicAddress::IntegerOverflowTrap: + return FuncCast(IntegerOverflowTrap, Args_General0); + case SymbolicAddress::InvalidConversionToIntegerTrap: + return FuncCast(InvalidConversionToIntegerTrap, Args_General0); case SymbolicAddress::HandleExecutionInterrupt: return FuncCast(WasmHandleExecutionInterrupt, Args_General0); case SymbolicAddress::InvokeImport_Void: diff --git a/js/src/asmjs/WasmTypes.h b/js/src/asmjs/WasmTypes.h index 4b2546ac4e..8f90f06053 100644 --- a/js/src/asmjs/WasmTypes.h +++ b/js/src/asmjs/WasmTypes.h @@ -39,6 +39,7 @@ class PropertyName; namespace wasm { +using mozilla::DebugOnly; using mozilla::EnumeratedArray; using mozilla::Maybe; using mozilla::Move; @@ -48,6 +49,24 @@ typedef Vector Uint32Vector; // ValType/ExprType utilities +// ExprType::Limit is an out-of-band value and has no wasm-semantic meaning. For +// the purpose of recursive validation, we use this value to represent the type +// of branch/return instructions that don't actually return to the parent +// expression and can thus be used in any context. +const ExprType AnyType = ExprType::Limit; + +inline ExprType +Unify(ExprType a, ExprType b) +{ + if (a == AnyType) + return b; + if (b == AnyType) + return a; + if (a == b) + return a; + return ExprType::Void; +} + static inline bool IsVoid(ExprType et) { @@ -73,6 +92,50 @@ IsSimdType(ValType vt) return vt == ValType::I32x4 || vt == ValType::F32x4 || vt == ValType::B32x4; } +static inline uint32_t +NumSimdElements(ValType vt) +{ + MOZ_ASSERT(IsSimdType(vt)); + switch (vt) { + case ValType::I32x4: + case ValType::F32x4: + case ValType::B32x4: + return 4; + default: + MOZ_CRASH("Unhandled SIMD type"); + } +} + +static inline ValType +SimdElementType(ValType vt) +{ + MOZ_ASSERT(IsSimdType(vt)); + switch (vt) { + case ValType::I32x4: + return ValType::I32; + case ValType::F32x4: + return ValType::F32; + case ValType::B32x4: + return ValType::I32; + default: + MOZ_CRASH("Unhandled SIMD type"); + } +} + +static inline ValType +SimdBoolType(ValType vt) +{ + MOZ_ASSERT(IsSimdType(vt)); + switch (vt) { + case ValType::I32x4: + case ValType::F32x4: + case ValType::B32x4: + return ValType::B32x4; + default: + MOZ_CRASH("Unhandled SIMD type"); + } +} + static inline bool IsSimdType(ExprType et) { @@ -89,13 +152,13 @@ static inline jit::MIRType ToMIRType(ValType vt) { switch (vt) { - case ValType::I32: return jit::MIRType_Int32; - case ValType::I64: return jit::MIRType_Int64; - case ValType::F32: return jit::MIRType_Float32; - case ValType::F64: return jit::MIRType_Double; - case ValType::I32x4: return jit::MIRType_Int32x4; - case ValType::F32x4: return jit::MIRType_Float32x4; - case ValType::B32x4: return jit::MIRType_Bool32x4; + case ValType::I32: return jit::MIRType::Int32; + case ValType::I64: return jit::MIRType::Int64; + case ValType::F32: return jit::MIRType::Float32; + case ValType::F64: return jit::MIRType::Double; + case ValType::I32x4: return jit::MIRType::Int32x4; + case ValType::F32x4: return jit::MIRType::Float32x4; + case ValType::B32x4: return jit::MIRType::Bool32x4; case ValType::Limit: break; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type"); @@ -104,7 +167,7 @@ ToMIRType(ValType vt) static inline jit::MIRType ToMIRType(ExprType et) { - return IsVoid(et) ? jit::MIRType_None : ToMIRType(ValType(et)); + return IsVoid(et) ? jit::MIRType::None : ToMIRType(ValType(et)); } static inline const char* @@ -233,6 +296,21 @@ struct SigHashPolicy static bool match(const Sig* lhs, Lookup rhs) { return *lhs == rhs; } }; +// A GlobalDesc describes a single global variable. Currently, globals are only +// exposed through asm.js. + +struct GlobalDesc +{ + ValType type; + unsigned globalDataOffset; + bool isConst; + GlobalDesc(ValType type, unsigned offset, bool isConst) + : type(type), globalDataOffset(offset), isConst(isConst) + {} +}; + +typedef Vector GlobalDescVector; + // A "declared" signature is a Sig object that is created and owned by the // ModuleGenerator. These signature objects are read-only and have the same // lifetime as the ModuleGenerator. This type is useful since some uses of Sig @@ -536,6 +614,8 @@ enum class SymbolicAddress OnImpreciseConversion, BadIndirectCall, UnreachableTrap, + IntegerOverflowTrap, + InvalidConversionToIntegerTrap, HandleExecutionInterrupt, InvokeImport_Void, InvokeImport_I32, @@ -565,6 +645,8 @@ enum class JumpTarget ConversionError, BadIndirectCall, UnreachableTrap, + IntegerOverflowTrap, + InvalidConversionToIntegerTrap, Throw, Limit }; diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 739bef6720..9f3a2227f4 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -1118,9 +1118,7 @@ const JSFunctionSpec AtomicsMethods[] = { JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor), JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree), JS_FN("wait", atomics_wait, 4,0), - JS_FN("futexWait", atomics_wait, 4,0), JS_FN("wake", atomics_wake, 3,0), - JS_FN("futexWake", atomics_wake, 3,0), JS_FS_END }; diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h index 82e5272bfc..17dc8cc1c2 100644 --- a/js/src/builtin/AtomicsObject.h +++ b/js/src/builtin/AtomicsObject.h @@ -118,7 +118,7 @@ public: // interrupt handler WaitingInterrupted, // We are waiting, but have been interrupted // and are running the interrupt handler - Woken // Woken by a script call to futexWake + Woken // Woken by a script call to Atomics.wake }; // Condition variable that this runtime will wait on. diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 29b3940832..522340f323 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -410,15 +410,15 @@ WriteBarrierPost(JSRuntime* rt, ValueSet* set, const Value& key) bool MapObject::getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj, - JS::AutoValueVector* entries) + JS::MutableHandle> entries) { ValueMap* map = obj->as().getData(); if (!map) return false; for (ValueMap::Range r = map->all(); !r.empty(); r.popFront()) { - if (!entries->append(r.front().key.get()) || - !entries->append(r.front().value)) + if (!entries.append(r.front().key.get()) || + !entries.append(r.front().value)) { return false; } @@ -1075,14 +1075,14 @@ SetObject::initClass(JSContext* cx, JSObject* obj) bool -SetObject::keys(JSContext* cx, HandleObject obj, JS::AutoValueVector* keys) +SetObject::keys(JSContext* cx, HandleObject obj, JS::MutableHandle> keys) { ValueSet* set = obj->as().getData(); if (!set) return false; for (ValueSet::Range r = set->all(); !r.empty(); r.popFront()) { - if (!keys->append(r.front().get())) + if (!keys.append(r.front().get())) return false; } diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h index 90cd096cd0..5eeeb02ebe 100644 --- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -89,7 +89,7 @@ class MapObject : public NativeObject { static const Class class_; static bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj, - JS::AutoValueVector* entries); + JS::MutableHandle> entries); static bool entries(JSContext* cx, unsigned argc, Value* vp); static bool has(JSContext* cx, unsigned argc, Value* vp); static MapObject* create(JSContext* cx, HandleObject proto = nullptr); @@ -178,7 +178,7 @@ class SetObject : public NativeObject { static JSObject* initClass(JSContext* cx, JSObject* obj); static const Class class_; - static bool keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys); + static bool keys(JSContext *cx, HandleObject obj, JS::MutableHandle> keys); static bool values(JSContext *cx, unsigned argc, Value *vp); static bool add(JSContext *cx, HandleObject obj, HandleValue key); static bool has(JSContext *cx, unsigned argc, Value *vp); diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 28141fb274..38460cf53b 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -356,6 +356,15 @@ ModuleNamespaceObject::ProxyHandler::setPrototype(JSContext* cx, HandleObject pr return result.failCantSetProto(); } +bool +ModuleNamespaceObject::ProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, + bool* isOrdinary, + MutableHandleObject protop) const +{ + *isOrdinary = false; + return true; +} + bool ModuleNamespaceObject::ProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const @@ -1108,7 +1117,7 @@ ModuleBuilder::processExport(frontend::ParseNode* pn) case PNK_FUNCTION: { RootedFunction func(cx_, kid->pn_funbox->function()); - RootedAtom localName(cx_, func->atom()); + RootedAtom localName(cx_, func->name()); RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); if (!appendExportEntry(exportName, localName)) return false; diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index 0d2c2e436e..f3e53c3e00 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -165,6 +165,8 @@ class ModuleNamespaceObject : public ProxyObject MutableHandleObject protop) const override; bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const override; + bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override; diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 37c2badffb..6badd0f0ef 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -222,7 +222,7 @@ PromiseObject::getID() * its dependent promise is. */ bool -PromiseObject::dependentPromises(JSContext* cx, AutoValueVector& values) +PromiseObject::dependentPromises(JSContext* cx, MutableHandle> values) { RootedValue rejectReactionsVal(cx, getReservedSlot(PROMISE_REJECT_REACTIONS_SLOT)); RootedObject rejectReactions(cx, rejectReactionsVal.toObjectOrNull()); diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index 1dc30629f8..eefd44c544 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -54,7 +54,7 @@ class PromiseObject : public NativeObject MOZ_ASSERT(state() != JS::PromiseState::Pending); return resolutionTime() - allocationTime(); } - bool dependentPromises(JSContext* cx, AutoValueVector& values); + bool dependentPromises(JSContext* cx, MutableHandle> values); double getID(); }; diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 88dbd74921..d1a5990dda 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3470,7 +3470,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) #endif RootedValue id(cx); - RootedAtom funcAtom(cx, func->atom()); + RootedAtom funcAtom(cx, func->name()); if (!optIdentifier(funcAtom, nullptr, &id)) return false; diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 0a22a1536d..5ec36bed24 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -1190,7 +1190,7 @@ GetParen(JSLinearString* matched, JS::Value capture, JSSubString* out) template static bool InterpretDollar(JSLinearString* matched, JSLinearString* string, size_t position, size_t tailPos, - AutoValueVector& captures, JSLinearString* replacement, + MutableHandle> captures, JSLinearString* replacement, const CharT* replacementBegin, const CharT* currentDollar, const CharT* replacementEnd, JSSubString* out, size_t* skip) @@ -1265,7 +1265,7 @@ InterpretDollar(JSLinearString* matched, JSLinearString* string, size_t position template static bool FindReplaceLengthString(JSContext* cx, HandleLinearString matched, HandleLinearString string, - size_t position, size_t tailPos, AutoValueVector& captures, + size_t position, size_t tailPos, MutableHandle> captures, HandleLinearString replacement, size_t firstDollarIndex, size_t* sizep) { CheckedInt replen = replacement->length(); @@ -1304,7 +1304,7 @@ FindReplaceLengthString(JSContext* cx, HandleLinearString matched, HandleLinearS static bool FindReplaceLength(JSContext* cx, HandleLinearString matched, HandleLinearString string, - size_t position, size_t tailPos, AutoValueVector& captures, + size_t position, size_t tailPos, MutableHandle> captures, HandleLinearString replacement, size_t firstDollarIndex, size_t* sizep) { return replacement->hasLatin1Chars() @@ -1322,7 +1322,7 @@ FindReplaceLength(JSContext* cx, HandleLinearString matched, HandleLinearString template static void DoReplace(HandleLinearString matched, HandleLinearString string, - size_t position, size_t tailPos, AutoValueVector& captures, + size_t position, size_t tailPos, MutableHandle> captures, HandleLinearString replacement, size_t firstDollarIndex, StringBuffer &sb) { JS::AutoCheckCannotGC nogc; @@ -1378,7 +1378,7 @@ js::RegExpGetSubstitution(JSContext* cx, HandleLinearString matched, HandleLinea if (!GetLengthProperty(cx, capturesObj, &nCaptures)) return false; - AutoValueVector captures(cx); + Rooted> captures(cx, GCVector(cx)); if (!captures.reserve(nCaptures)) return false; @@ -1414,7 +1414,7 @@ js::RegExpGetSubstitution(JSContext* cx, HandleLinearString matched, HandleLinea // Step 11. size_t reserveLength; - if (!FindReplaceLength(cx, matched, string, position, tailPos, captures, replacement, + if (!FindReplaceLength(cx, matched, string, position, tailPos, &captures, replacement, firstDollarIndex, &reserveLength)) { return false; @@ -1430,10 +1430,10 @@ js::RegExpGetSubstitution(JSContext* cx, HandleLinearString matched, HandleLinea return false; if (replacement->hasLatin1Chars()) { - DoReplace(matched, string, position, tailPos, captures, + DoReplace(matched, string, position, tailPos, &captures, replacement, firstDollarIndex, result); } else { - DoReplace(matched, string, position, tailPos, captures, + DoReplace(matched, string, position, tailPos, &captures, replacement, firstDollarIndex, result); } @@ -1446,6 +1446,58 @@ js::RegExpGetSubstitution(JSContext* cx, HandleLinearString matched, HandleLinea return true; } +bool +js::GetFirstDollarIndex(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + RootedString str(cx, args[0].toString()); + + int32_t index = -1; + if (!GetFirstDollarIndexRaw(cx, str, &index)) + return false; + + args.rval().setInt32(index); + return true; +} + +template +static MOZ_ALWAYS_INLINE int +GetFirstDollarIndexImpl(const TextChar* text, uint32_t textLen) +{ + const TextChar* end = text + textLen; + for (const TextChar* c = text; c != end; ++c) { + if (*c == '$') + return c - text; + } + return -1; +} + +int32_t +js::GetFirstDollarIndexRawFlat(JSLinearString* text) +{ + uint32_t len = text->length(); + // Should be handled in different path. + MOZ_ASSERT(len != 0); + + JS::AutoCheckCannotGC nogc; + if (text->hasLatin1Chars()) + return GetFirstDollarIndexImpl(text->latin1Chars(nogc), len); + + return GetFirstDollarIndexImpl(text->twoByteChars(nogc), len); +} + +bool +js::GetFirstDollarIndexRaw(JSContext* cx, HandleString str, int32_t* index) +{ + JSLinearString* text = str->ensureLinear(cx); + if (!text) + return false; + + *index = GetFirstDollarIndexRawFlat(text); + return true; +} + bool js::RegExpPrototypeOptimizable(JSContext* cx, unsigned argc, Value* vp) { diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index 07f983ed35..80d88e104b 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -130,6 +130,15 @@ RegExpGetSubstitution(JSContext* cx, HandleLinearString matched, HandleLinearStr size_t position, HandleObject capturesObj, HandleLinearString replacement, size_t firstDollarIndex, MutableHandleValue rval); +extern bool +GetFirstDollarIndex(JSContext* cx, unsigned argc, Value* vp); + +extern bool +GetFirstDollarIndexRaw(JSContext* cx, HandleString str, int32_t* index); + +extern int32_t +GetFirstDollarIndexRawFlat(JSLinearString* text); + // RegExp ClassSpec members used in RegExpObject.cpp. extern bool regexp_construct(JSContext* cx, unsigned argc, Value* vp); diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js index ad1da27737..d3a6ac583f 100644 --- a/js/src/builtin/RegExp.js +++ b/js/src/builtin/RegExp.js @@ -190,7 +190,7 @@ function RegExpReplace(string, replaceValue) { // A single character string may contain "$", but that cannot be a // substitution. if (replaceValue.length > 1) - firstDollarIndex = callFunction(std_String_indexOf, replaceValue, "$"); + firstDollarIndex = GetFirstDollarIndex(replaceValue); } // Step 7. diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 97be0563c5..a451ae9328 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2503,7 +2503,7 @@ struct FindPathHandler { typedef JS::ubi::BreadthFirst Traversal; FindPathHandler(JSContext*cx, JS::ubi::Node start, JS::ubi::Node target, - AutoValueVector& nodes, Vector& edges) + MutableHandle> nodes, Vector& edges) : cx(cx), start(start), target(target), foundPath(false), nodes(nodes), edges(edges) { } @@ -2572,7 +2572,7 @@ struct FindPathHandler { // - edges[i] is the name of the edge from nodes[i] to nodes[i-1]. // - edges[0] is the name of the edge from nodes[0] to the target. // - The last node, nodes[n-1], is the start node. - AutoValueVector& nodes; + MutableHandle> nodes; Vector& edges; }; @@ -2605,7 +2605,7 @@ FindPath(JSContext* cx, unsigned argc, Value* vp) return false; } - AutoValueVector nodes(cx); + Rooted> nodes(cx, GCVector(cx)); Vector edges(cx); { @@ -2615,7 +2615,7 @@ FindPath(JSContext* cx, unsigned argc, Value* vp) JS::ubi::Node start(args[0]), target(args[1]); - heaptools::FindPathHandler handler(cx, start, target, nodes, edges); + heaptools::FindPathHandler handler(cx, start, target, &nodes, edges); heaptools::FindPathHandler::Traversal traversal(cx->runtime(), handler, autoCannotGC); if (!traversal.init() || !traversal.addStart(start)) return false; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index d1a4311b1b..67875ac590 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -644,8 +644,10 @@ ArrayMetaTypeDescr::create(JSContext* cx, if (!CreateTraceList(cx, obj)) return nullptr; - if (!cx->zone()->typeDescrObjects.put(obj)) + if (!cx->zone()->typeDescrObjects.put(obj)) { + ReportOutOfMemory(cx); return nullptr; + } return obj; } @@ -691,12 +693,16 @@ ArrayMetaTypeDescr::construct(JSContext* cx, unsigned argc, Value* vp) // Construct a canonical string `new ArrayType(, N)`: StringBuffer contents(cx); - contents.append("new ArrayType("); - contents.append(&elementType->stringRepr()); - contents.append(", "); + if (!contents.append("new ArrayType(")) + return false; + if (!contents.append(&elementType->stringRepr())) + return false; + if (!contents.append(", ")) + return false; if (!NumberValueToStringBuffer(cx, NumberValue(length), contents)) return false; - contents.append(")"); + if (!contents.append(")")) + return false; RootedAtom stringRepr(cx, contents.finishAtom()); if (!stringRepr) return false; @@ -799,10 +805,8 @@ StructMetaTypeDescr::create(JSContext* cx, if (!userFieldTypes) return nullptr; - if (!stringBuffer.append("new StructType({")) { - ReportOutOfMemory(cx); + if (!stringBuffer.append("new StructType({")) return nullptr; - } RootedValue fieldTypeVal(cx); RootedId id(cx); @@ -830,14 +834,10 @@ StructMetaTypeDescr::create(JSContext* cx, // Collect field name and type object RootedValue fieldName(cx, IdToValue(id)); - if (!fieldNames.append(fieldName)) { - ReportOutOfMemory(cx); + if (!fieldNames.append(fieldName)) return nullptr; - } - if (!fieldTypeObjs.append(ObjectValue(*fieldType))) { - ReportOutOfMemory(cx); + if (!fieldTypeObjs.append(ObjectValue(*fieldType))) return nullptr; - } // userFieldTypes[id] = typeObj if (!DefineProperty(cx, userFieldTypes, id, fieldTypeObjs[i], nullptr, nullptr, @@ -847,22 +847,14 @@ StructMetaTypeDescr::create(JSContext* cx, } // Append "f:Type" to the string repr - if (i > 0 && !stringBuffer.append(", ")) { - ReportOutOfMemory(cx); + if (i > 0 && !stringBuffer.append(", ")) return nullptr; - } - if (!stringBuffer.append(JSID_TO_ATOM(id))) { - ReportOutOfMemory(cx); + if (!stringBuffer.append(JSID_TO_ATOM(id))) return nullptr; - } - if (!stringBuffer.append(": ")) { - ReportOutOfMemory(cx); + if (!stringBuffer.append(": ")) return nullptr; - } - if (!stringBuffer.append(&fieldType->stringRepr())) { - ReportOutOfMemory(cx); + if (!stringBuffer.append(&fieldType->stringRepr())) return nullptr; - } // Offset of this field is the current total size adjusted for // the field's alignment. @@ -873,10 +865,8 @@ StructMetaTypeDescr::create(JSContext* cx, return nullptr; } MOZ_ASSERT(offset.value() >= 0); - if (!fieldOffsets.append(Int32Value(offset.value()))) { - ReportOutOfMemory(cx); + if (!fieldOffsets.append(Int32Value(offset.value()))) return nullptr; - } // userFieldOffsets[id] = offset RootedValue offsetValue(cx, Int32Value(offset.value())); @@ -903,10 +893,9 @@ StructMetaTypeDescr::create(JSContext* cx, } // Complete string representation. - if (!stringBuffer.append("})")) { - ReportOutOfMemory(cx); + if (!stringBuffer.append("})")) return nullptr; - } + RootedAtom stringRepr(cx, stringBuffer.finishAtom()); if (!stringRepr) return nullptr; @@ -1003,6 +992,7 @@ StructMetaTypeDescr::create(JSContext* cx, if (!cx->zone()->typeDescrObjects.put(descr) || !cx->zone()->typeDescrObjects.put(fieldTypeVec)) { + ReportOutOfMemory(cx); return nullptr; } @@ -1172,8 +1162,10 @@ DefineSimpleTypeDescr(JSContext* cx, if (!CreateTraceList(cx, descr)) return false; - if (!cx->zone()->typeDescrObjects.put(descr)) + if (!cx->zone()->typeDescrObjects.put(descr)) { + ReportOutOfMemory(cx); return false; + } return true; } @@ -1618,11 +1610,7 @@ OutlineTypedObject::obj_trace(JSTracer* trc, JSObject* object) if (!typedObj.owner_) return; - // When this is called for compacting GC, the related objects we touch here - // may not have had their slots updated yet. Note that this does not apply - // to generational GC because these objects (type descriptors and - // prototypes) are never allocated in the nursery. - TypeDescr& descr = *MaybeForwarded(&typedObj.typeDescr()); + TypeDescr& descr = typedObj.typeDescr(); // Mark the owner, watching in case it is moved by the tracer. JSObject* oldOwner = typedObj.owner_; @@ -2138,11 +2126,7 @@ InlineTypedObject::obj_trace(JSTracer* trc, JSObject* object) if (typedObj.is()) return; - // When this is called for compacting GC, the related objects we touch here - // may not have had their slots updated yet. - TypeDescr& descr = *MaybeForwarded(&typedObj.typeDescr()); - - descr.traceInstances(trc, typedObj.inlineTypedMem(), 1); + typedObj.typeDescr().traceInstances(trc, typedObj.inlineTypedMem(), 1); } /* static */ void diff --git a/js/src/devtools/gc-ubench/benchmarks/largeArrayPropertyAndElements.js b/js/src/devtools/gc-ubench/benchmarks/largeArrayPropertyAndElements.js new file mode 100644 index 0000000000..36ae04971b --- /dev/null +++ b/js/src/devtools/gc-ubench/benchmarks/largeArrayPropertyAndElements.js @@ -0,0 +1,34 @@ +window.tests.set('largeArrayPropertyAndElements', (function() { + var garbage; + var index; + + return { + description: "Large array with both properties and elements", + + load: n => { + garbage = new Array(n); + garbage.fill(null); + index = 0; + }, + + unload: () => { + garbage = null; + index = 0; + }, + + defaultGarbageTotal: "100K", + defaultGarbagePerFrame: "30K", + + makeGarbage: n => { + for (var i = 0; i < n; i++) { + index++; + index %= garbage.length; + + var obj = {}; + garbage[index] = obj; + garbage["key-" + index] = obj; + } + } + }; + +}())); diff --git a/js/src/devtools/gc-ubench/index.html b/js/src/devtools/gc-ubench/index.html index 3b2ae90768..d5ab2a0839 100644 --- a/js/src/devtools/gc-ubench/index.html +++ b/js/src/devtools/gc-ubench/index.html @@ -14,6 +14,7 @@ + diff --git a/js/src/ds/Fifo.h b/js/src/ds/Fifo.h index bc9eb7a24d..84851ac947 100644 --- a/js/src/ds/Fifo.h +++ b/js/src/ds/Fifo.h @@ -95,7 +95,7 @@ class Fifo // Push an element to the back of the queue. This method can take either a // |const T&| or a |T&&|. template - bool pushBack(U&& u) { + MOZ_MUST_USE bool pushBack(U&& u) { if (!rear_.append(mozilla::Forward(u))) return false; if (!fixup()) { @@ -107,7 +107,7 @@ class Fifo // Construct a T in-place at the back of the queue. template - bool emplaceBack(Args&&... args) { + MOZ_MUST_USE bool emplaceBack(Args&&... args) { if (!rear_.emplaceBack(mozilla::Forward(args)...)) return false; if (!fixup()) { @@ -128,7 +128,7 @@ class Fifo } // Remove the front element from the queue. - bool popFront() { + MOZ_MUST_USE bool popFront() { MOZ_ASSERT(!empty()); T t(mozilla::Move(front())); front_.popBack(); diff --git a/js/src/ds/IdValuePair.h b/js/src/ds/IdValuePair.h index 203beb2799..1b79bf2aeb 100644 --- a/js/src/ds/IdValuePair.h +++ b/js/src/ds/IdValuePair.h @@ -37,7 +37,7 @@ struct IdValuePair } }; -using IdValueVector = GCVector; +using IdValueVector = JS::GCVector; } /* namespace js */ diff --git a/js/src/ds/InlineMap.h b/js/src/ds/InlineMap.h index 1d0502a474..310aed150a 100644 --- a/js/src/ds/InlineMap.h +++ b/js/src/ds/InlineMap.h @@ -56,7 +56,7 @@ class InlineMap return inlNext > InlineElems; } - bool switchToMap() { + MOZ_MUST_USE bool switchToMap() { MOZ_ASSERT(inlNext == InlineElems); if (map.initialized()) { @@ -80,7 +80,7 @@ class InlineMap } MOZ_NEVER_INLINE - bool switchAndAdd(const K& key, const V& value) { + MOZ_MUST_USE bool switchAndAdd(const K& key, const V& value) { if (!switchToMap()) return false; @@ -252,7 +252,7 @@ class InlineMap } MOZ_ALWAYS_INLINE - bool add(AddPtr& p, const K& key, const V& value) { + MOZ_MUST_USE bool add(AddPtr& p, const K& key, const V& value) { MOZ_ASSERT(!p); MOZ_ASSERT(keyNonZero(key)); @@ -277,7 +277,7 @@ class InlineMap } MOZ_ALWAYS_INLINE - bool put(const K& key, const V& value) { + MOZ_MUST_USE bool put(const K& key, const V& value) { AddPtr p = lookupForAdd(key); if (p) { p.value() = value; diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index e196ee077b..8c6544a0b2 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -299,7 +299,7 @@ class LifoAlloc // allocation requests, not necessarily contiguous. Note that this does // not guarantee a successful single allocation of N bytes. MOZ_ALWAYS_INLINE - bool ensureUnusedApproximate(size_t n) { + MOZ_MUST_USE bool ensureUnusedApproximate(size_t n) { size_t total = 0; for (BumpChunk* chunk = latest; chunk; chunk = chunk->next()) { total += chunk->unused(); @@ -583,7 +583,7 @@ class LifoAllocPolicy } void reportAllocOverflow() const { } - bool checkSimulatedOOM() const { + MOZ_MUST_USE bool checkSimulatedOOM() const { return fb == Infallible || !js::oom::ShouldFailWithOOM(); } }; diff --git a/js/src/ds/OrderedHashTable.h b/js/src/ds/OrderedHashTable.h index 616cf6bbbd..6a066bd409 100644 --- a/js/src/ds/OrderedHashTable.h +++ b/js/src/ds/OrderedHashTable.h @@ -83,7 +83,7 @@ class OrderedHashTable explicit OrderedHashTable(AllocPolicy& ap) : hashTable(nullptr), data(nullptr), dataLength(0), ranges(nullptr), alloc(ap) {} - bool init() { + MOZ_MUST_USE bool init() { MOZ_ASSERT(!hashTable, "init must be called at most once"); uint32_t buckets = initialBuckets(); @@ -150,7 +150,7 @@ class OrderedHashTable * means the element was not added to the table. */ template - bool put(ElementInput&& element) { + MOZ_MUST_USE bool put(ElementInput&& element) { HashNumber h = prepareHash(Ops::getKey(element)); if (Data* e = lookup(Ops::getKey(element), h)) { e->element = Forward(element); @@ -221,7 +221,7 @@ class OrderedHashTable * particular, those Ranges are still live and will see any entries added * after a successful clear(). */ - bool clear() { + MOZ_MUST_USE bool clear() { if (dataLength != 0) { Data** oldHashTable = hashTable; Data* oldData = data; @@ -627,7 +627,7 @@ class OrderedHashTable * empty elements in data[0:dataLength]. On allocation failure, this * leaves everything as it was and returns false. */ - bool rehash(uint32_t newHashShift) { + MOZ_MUST_USE bool rehash(uint32_t newHashShift) { // If the size of the table is not changing, rehash in place to avoid // allocating memory. if (newHashShift == hashShift) { @@ -740,17 +740,17 @@ class OrderedHashMap typedef typename Impl::Range Range; explicit OrderedHashMap(AllocPolicy ap = AllocPolicy()) : impl(ap) {} - MOZ_WARN_UNUSED_RESULT bool init() { return impl.init(); } + MOZ_MUST_USE bool init() { return impl.init(); } uint32_t count() const { return impl.count(); } bool has(const Key& key) const { return impl.has(key); } Range all() { return impl.all(); } const Entry* get(const Key& key) const { return impl.get(key); } Entry* get(const Key& key) { return impl.get(key); } bool remove(const Key& key, bool* foundp) { return impl.remove(key, foundp); } - MOZ_WARN_UNUSED_RESULT bool clear() { return impl.clear(); } + MOZ_MUST_USE bool clear() { return impl.clear(); } template - MOZ_WARN_UNUSED_RESULT bool put(const Key& key, V&& value) { + MOZ_MUST_USE bool put(const Key& key, V&& value) { return impl.put(Entry(key, Forward(value))); } @@ -792,13 +792,13 @@ class OrderedHashSet typedef typename Impl::Range Range; explicit OrderedHashSet(AllocPolicy ap = AllocPolicy()) : impl(ap) {} - MOZ_WARN_UNUSED_RESULT bool init() { return impl.init(); } + MOZ_MUST_USE bool init() { return impl.init(); } uint32_t count() const { return impl.count(); } bool has(const T& value) const { return impl.has(value); } Range all() { return impl.all(); } - MOZ_WARN_UNUSED_RESULT bool put(const T& value) { return impl.put(value); } + MOZ_MUST_USE bool put(const T& value) { return impl.put(value); } bool remove(const T& value, bool* foundp) { return impl.remove(value, foundp); } - MOZ_WARN_UNUSED_RESULT bool clear() { return impl.clear(); } + MOZ_MUST_USE bool clear() { return impl.clear(); } void rekeyOneEntry(const T& current, const T& newKey) { return impl.rekeyOneEntry(current, newKey, newKey); diff --git a/js/src/ds/PriorityQueue.h b/js/src/ds/PriorityQueue.h index 5a571a6966..549e44e926 100644 --- a/js/src/ds/PriorityQueue.h +++ b/js/src/ds/PriorityQueue.h @@ -35,7 +35,7 @@ class PriorityQueue : heap(ap) {} - bool reserve(size_t capacity) { + MOZ_MUST_USE bool reserve(size_t capacity) { return heap.reserve(capacity); } @@ -57,7 +57,7 @@ class PriorityQueue return highest; } - bool insert(const T& v) { + MOZ_MUST_USE bool insert(const T& v) { if (!heap.append(v)) return false; siftUp(heap.length() - 1); diff --git a/js/src/ds/Sort.h b/js/src/ds/Sort.h index 9ccadc7054..e5870a3501 100644 --- a/js/src/ds/Sort.h +++ b/js/src/ds/Sort.h @@ -78,7 +78,7 @@ MergeArrayRuns(T* dst, const T* src, size_t run1, size_t run2, Comparator c) * arbitrary. */ template -bool +MOZ_MUST_USE bool MergeSort(T* array, size_t nelems, T* scratch, Comparator c) { const size_t INS_SORT_LIMIT = 3; diff --git a/js/src/ds/TraceableFifo.h b/js/src/ds/TraceableFifo.h index 3176e3e3ea..5899c6799b 100644 --- a/js/src/ds/TraceableFifo.h +++ b/js/src/ds/TraceableFifo.h @@ -46,9 +46,9 @@ class TraceableFifo : public js::Fifo void trace(JSTracer* trc) { for (size_t i = 0; i < this->front_.length(); ++i) - GCPolicy::trace(trc, &this->front_[i], "fifo element"); + JS::GCPolicy::trace(trc, &this->front_[i], "fifo element"); for (size_t i = 0; i < this->rear_.length(); ++i) - GCPolicy::trace(trc, &this->rear_[i], "fifo element"); + JS::GCPolicy::trace(trc, &this->rear_[i], "fifo element"); } }; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c8c91873f6..d33b0abc51 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1584,7 +1584,7 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn) // Look up for name in function and block scopes. if (ssi.type() == StaticScopeIter::Function) { RootedScript funScript(cx, ssi.funScript()); - if (funScript->funHasExtensibleScope() || ssi.fun().atom() == pn->pn_atom) + if (funScript->funHasExtensibleScope() || ssi.fun().name() == pn->pn_atom) return false; // Skip the current function, since we're trying to convert a @@ -1853,7 +1853,7 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn) return true; MOZ_ASSERT(fun->isLambda()); - MOZ_ASSERT(pn->pn_atom == fun->atom()); + MOZ_ASSERT(pn->pn_atom == fun->name()); /* * Leave pn->isOp(JSOP_GETNAME) if this->fun needs a CallObject to @@ -6538,7 +6538,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) } else if (sc->isFunctionBox()) { #ifdef DEBUG BindingIter bi(script); - while (bi->name() != fun->atom()) + while (bi->name() != fun->name()) bi++; MOZ_ASSERT(bi->kind() == Binding::VARIABLE || bi->kind() == Binding::CONSTANT || bi->kind() == Binding::ARGUMENT); @@ -6554,7 +6554,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) return false; } else { RootedModuleObject module(cx, sc->asModuleBox()->module()); - RootedAtom name(cx, fun->atom()); + RootedAtom name(cx, fun->name()); if (!module->noteFunctionDeclaration(cx, name, fun)) return false; } diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 74f558c69d..80909a4276 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -866,11 +866,11 @@ class FullParseHandler MOZ_ASSERT(pn->isArity(PN_LIST)); pn->pn_xflags |= flag; } - MOZ_WARN_UNUSED_RESULT ParseNode* parenthesize(ParseNode* pn) { + MOZ_MUST_USE ParseNode* parenthesize(ParseNode* pn) { pn->setInParens(true); return pn; } - MOZ_WARN_UNUSED_RESULT ParseNode* setLikelyIIFE(ParseNode* pn) { + MOZ_MUST_USE ParseNode* setLikelyIIFE(ParseNode* pn) { return parenthesize(pn); } void setPrologue(ParseNode* pn) { diff --git a/js/src/frontend/ParseNode-inl.h b/js/src/frontend/ParseNode-inl.h index d7f43d69ec..395d09b5b9 100644 --- a/js/src/frontend/ParseNode-inl.h +++ b/js/src/frontend/ParseNode-inl.h @@ -18,7 +18,7 @@ inline PropertyName* ParseNode::name() const { MOZ_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME)); - JSAtom* atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->atom() : pn_atom; + JSAtom* atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->name() : pn_atom; return atom->asPropertyName(); } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5f8536f0f2..2a6ec97ed0 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -945,8 +945,7 @@ Parser::reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum) { JSAutoByteString name; - JSAtom* atom = pc->sc->asFunctionBox()->function()->atom(); - if (atom) { + if (JSAtom* atom = pc->sc->asFunctionBox()->function()->name()) { if (!AtomToPrintableString(context, atom, &name)) return false; } else { @@ -1998,6 +1997,25 @@ Parser::leaveFunction(Node fn, ParseContextfunction(), outerpc); } +template +JSAtom* +Parser::prefixAccessorName(PropertyType propType, HandleAtom propAtom) +{ + RootedAtom prefix(context); + if (propType == PropertyType::Setter || propType == PropertyType::SetterNoExpressionClosure) { + prefix = context->names().setPrefix; + } else { + MOZ_ASSERT(propType == PropertyType::Getter || propType == PropertyType::GetterNoExpressionClosure); + prefix = context->names().getPrefix; + } + + RootedString str(context, ConcatStrings(context, prefix, propAtom)); + if (!str) + return nullptr; + + return AtomizeString(context, str); +} + /* * defineArg is called for both the arguments of a regular function definition * and the arguments specified by the Function constructor. @@ -2401,7 +2419,7 @@ Parser::bindLexicalFunctionName(HandlePropertyName funName, template <> bool -Parser::checkFunctionDefinition(HandlePropertyName funName, +Parser::checkFunctionDefinition(HandleAtom funAtom, ParseNode** pn_, FunctionSyntaxKind kind, bool* pbodyProcessed, ParseNode** assignmentForAnnexBOut) @@ -2410,6 +2428,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, *pbodyProcessed = false; if (kind == Statement) { + RootedPropertyName funName(context, funAtom->asPropertyName()); MOZ_ASSERT(assignmentForAnnexBOut); *assignmentForAnnexBOut = nullptr; @@ -2654,7 +2673,7 @@ Parser::addFreeVariablesFromLazyFunction(JSFunction* fun, template <> bool -Parser::checkFunctionDefinition(HandlePropertyName funName, +Parser::checkFunctionDefinition(HandleAtom funAtom, Node* pn, FunctionSyntaxKind kind, bool* pbodyProcessed, Node* assignmentForAnnexBOut) @@ -2665,6 +2684,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, bool bodyLevel = pc->atBodyLevel(); if (kind == Statement) { + RootedPropertyName funName(context, funAtom->asPropertyName()); *assignmentForAnnexBOut = null(); if (!bodyLevel) { @@ -2776,7 +2796,7 @@ Parser::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node Parser::functionDef(InHandling inHandling, YieldHandling yieldHandling, - HandlePropertyName funName, FunctionSyntaxKind kind, + HandleAtom funName, FunctionSyntaxKind kind, GeneratorKind generatorKind, InvokedPrediction invoked, Node* assignmentForAnnexBOut) { @@ -3192,10 +3212,10 @@ Parser::functionArgsAndBodyGeneric(InHandling inHandling, if (!body) return false; - if ((kind != Method && !IsConstructorKind(kind)) && fun->name() && - !checkStrictBinding(fun->name(), pn)) - { - return false; + if ((kind != Method && !IsConstructorKind(kind)) && fun->name()) { + RootedPropertyName propertyName(context, fun->name()->asPropertyName()); + if (!checkStrictBinding(propertyName, pn)) + return false; } if (bodyType == StatementListBody) { @@ -5694,7 +5714,7 @@ Parser::exportDeclaration() if (!kid) return null(); - if (!checkExportedName(kid->pn_funbox->function()->atom())) + if (!checkExportedName(kid->pn_funbox->function()->name())) return null(); break; @@ -7225,21 +7245,23 @@ Parser::classDefinition(YieldHandling yieldHandling, // FIXME: Implement ES6 function "name" property semantics // (bug 883377). - RootedPropertyName funName(context); + RootedAtom funName(context); switch (propType) { case PropertyType::GetterNoExpressionClosure: case PropertyType::SetterNoExpressionClosure: - funName = nullptr; + if (!tokenStream.isCurrentTokenType(TOK_RB)) { + funName = prefixAccessorName(propType, propAtom); + if (!funName) + return null(); + } break; case PropertyType::Constructor: case PropertyType::DerivedConstructor: funName = name; break; default: - if (tokenStream.isCurrentTokenType(TOK_NAME)) - funName = tokenStream.currentName(); - else - funName = nullptr; + if (!tokenStream.isCurrentTokenType(TOK_RB)) + funName = propAtom; } ParseNode* fn = methodDefinition(yieldHandling, propType, funName); if (!fn) @@ -9367,18 +9389,17 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* } else { // FIXME: Implement ES6 function "name" property semantics // (bug 883377). - RootedPropertyName funName(context); - switch (propType) { - case PropertyType::Getter: - case PropertyType::Setter: - funName = nullptr; - break; - default: - if (tokenStream.isCurrentTokenType(TOK_NAME)) - funName = tokenStream.currentName(); - else - funName = nullptr; + RootedAtom funName(context); + if (!tokenStream.isCurrentTokenType(TOK_RB)) { + funName = propAtom; + + if (propType == PropertyType::Getter || propType == PropertyType::Setter) { + funName = prefixAccessorName(propType, propAtom); + if (!funName) + return null(); + } } + Node fn = methodDefinition(yieldHandling, propType, funName); if (!fn) return null(); @@ -9405,7 +9426,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* template typename ParseHandler::Node Parser::methodDefinition(YieldHandling yieldHandling, PropertyType propType, - HandlePropertyName funName) + HandleAtom funName) { FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index e56386ddda..79521ef3cf 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -875,8 +875,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter bool tryNewTarget(Node& newTarget); bool checkAndMarkSuperScope(); - Node methodDefinition(YieldHandling yieldHandling, PropertyType propType, - HandlePropertyName funName); + Node methodDefinition(YieldHandling yieldHandling, PropertyType propType, HandleAtom funName); /* * Additional JS parsers. @@ -884,7 +883,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn, bool* hasRest); - Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name, + Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandleAtom name, FunctionSyntaxKind kind, GeneratorKind generatorKind, InvokedPrediction invoked = PredictUninvoked, Node* assignmentForAnnexBOut = nullptr); @@ -952,7 +951,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter bool makeDefIntoUse(Definition* dn, Node pn, HandleAtom atom); bool bindLexicalFunctionName(HandlePropertyName funName, ParseNode* pn); bool bindBodyLevelFunctionName(HandlePropertyName funName, ParseNode** pn); - bool checkFunctionDefinition(HandlePropertyName funName, Node* pn, FunctionSyntaxKind kind, + bool checkFunctionDefinition(HandleAtom funAtom, Node* pn, FunctionSyntaxKind kind, bool* pbodyProcessed, Node* assignmentForAnnexBOut); bool finishFunctionDefinition(Node pn, FunctionBox* funbox, Node body); bool addFreeVariablesFromLazyFunction(JSFunction* fun, ParseContext* pc); @@ -1059,6 +1058,8 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter bool leaveFunction(Node fn, ParseContext* outerpc, FunctionSyntaxKind kind = Expression); + JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom); + TokenPos pos() const { return tokenStream.currentToken().pos; } bool asmJS(Node list); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 4aeb122c71..2de4394167 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -502,7 +502,7 @@ class SyntaxParseHandler void setBlockId(Node pn, unsigned blockid) {} void setFlag(Node pn, unsigned flag) {} void setListFlag(Node pn, unsigned flag) {} - MOZ_WARN_UNUSED_RESULT Node parenthesize(Node node) { + MOZ_MUST_USE Node parenthesize(Node node) { // A number of nodes have different behavior upon parenthesization, but // only in some circumstances. Convert these nodes to special // parenthesized forms. @@ -531,7 +531,7 @@ class SyntaxParseHandler // to the unparenthesized form: return |node| unchanged. return node; } - MOZ_WARN_UNUSED_RESULT Node setLikelyIIFE(Node pn) { + MOZ_MUST_USE Node setLikelyIIFE(Node pn) { return pn; // Remain in syntax-parse mode. } void setPrologue(Node pn) {} diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp index 2f2fc85669..a2cb308909 100644 --- a/js/src/gc/Barrier.cpp +++ b/js/src/gc/Barrier.cpp @@ -80,9 +80,13 @@ ReadBarrierFunctor::operator()(T* t) { InternalBarrierMethods::readBarrier(t); } -template void ReadBarrierFunctor::operator()(JS::Symbol*); -template void ReadBarrierFunctor::operator()(JSObject*); -template void ReadBarrierFunctor::operator()(JSString*); + +// All GC things may be held in a Value, either publicly or as a private GC +// thing. +#define JS_EXPAND_DEF(name, type, _) \ +template void ReadBarrierFunctor::operator()(type*); +JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); +#undef JS_EXPAND_DEF template template @@ -91,9 +95,14 @@ PreBarrierFunctor::operator()(T* t) { InternalBarrierMethods::preBarrier(t); } -template void PreBarrierFunctor::operator()(JS::Symbol*); -template void PreBarrierFunctor::operator()(JSObject*); -template void PreBarrierFunctor::operator()(JSString*); + +// All GC things may be held in a Value, either publicly or as a private GC +// thing. +#define JS_EXPAND_DEF(name, type, _) \ +template void PreBarrierFunctor::operator()(type*); +JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); +#undef JS_EXPAND_DEF + template void PreBarrierFunctor::operator()(JS::Symbol*); template void PreBarrierFunctor::operator()(JSString*); diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index d822bab65e..70c6628507 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -261,7 +261,7 @@ struct InternalBarrierMethods static void readBarrier(T* v) { T::readBarrier(v); } }; -template struct PreBarrierFunctor : VoidDefaultAdaptor { +template struct PreBarrierFunctor : public VoidDefaultAdaptor { template void operator()(T* t); }; @@ -379,7 +379,7 @@ template class PreBarriered : public WriteBarrieredBase { public: - PreBarriered() : WriteBarrieredBase(GCPolicy::initial()) {} + PreBarriered() : WriteBarrieredBase(JS::GCPolicy::initial()) {} /* * Allow implicit construction for use in generic contexts, such as DebuggerWeakMap::markKeys. */ @@ -424,12 +424,12 @@ template class HeapPtr : public WriteBarrieredBase { public: - HeapPtr() : WriteBarrieredBase(GCPolicy::initial()) {} + HeapPtr() : WriteBarrieredBase(JS::GCPolicy::initial()) {} explicit HeapPtr(T v) : WriteBarrieredBase(v) { - this->post(GCPolicy::initial(), v); + this->post(JS::GCPolicy::initial(), v); } explicit HeapPtr(const HeapPtr& v) : WriteBarrieredBase(v) { - this->post(GCPolicy::initial(), v); + this->post(JS::GCPolicy::initial(), v); } #ifdef DEBUG ~HeapPtr() { @@ -441,7 +441,7 @@ class HeapPtr : public WriteBarrieredBase void init(T v) { this->value = v; - this->post(GCPolicy::initial(), v); + this->post(JS::GCPolicy::initial(), v); } DECLARE_POINTER_ASSIGN_OPS(HeapPtr, T); @@ -494,11 +494,11 @@ template class RelocatablePtr : public WriteBarrieredBase { public: - RelocatablePtr() : WriteBarrieredBase(GCPolicy::initial()) {} + RelocatablePtr() : WriteBarrieredBase(JS::GCPolicy::initial()) {} // Implicitly adding barriers is a reasonable default. MOZ_IMPLICIT RelocatablePtr(const T& v) : WriteBarrieredBase(v) { - this->post(GCPolicy::initial(), this->value); + this->post(JS::GCPolicy::initial(), this->value); } /* @@ -508,17 +508,17 @@ class RelocatablePtr : public WriteBarrieredBase * simply omit the rvalue variant. */ MOZ_IMPLICIT RelocatablePtr(const RelocatablePtr& v) : WriteBarrieredBase(v) { - this->post(GCPolicy::initial(), this->value); + this->post(JS::GCPolicy::initial(), this->value); } ~RelocatablePtr() { this->pre(); - this->post(this->value, GCPolicy::initial()); + this->post(this->value, JS::GCPolicy::initial()); } void init(T v) { this->value = v; - this->post(GCPolicy::initial(), this->value); + this->post(JS::GCPolicy::initial(), this->value); } DECLARE_POINTER_ASSIGN_OPS(RelocatablePtr, T); @@ -573,16 +573,16 @@ template class ReadBarriered : public ReadBarrieredBase { public: - ReadBarriered() : ReadBarrieredBase(GCPolicy::initial()) {} + ReadBarriered() : ReadBarrieredBase(JS::GCPolicy::initial()) {} // It is okay to add barriers implicitly. MOZ_IMPLICIT ReadBarriered(const T& v) : ReadBarrieredBase(v) { - this->post(GCPolicy::initial(), v); + this->post(JS::GCPolicy::initial(), v); } // Copy is creating a new edge, so we must read barrier the source edge. explicit ReadBarriered(const ReadBarriered& v) : ReadBarrieredBase(v) { - this->post(GCPolicy::initial(), v.get()); + this->post(JS::GCPolicy::initial(), v.get()); } // Move retains the lifetime status of the source edge, so does not fire @@ -590,11 +590,11 @@ class ReadBarriered : public ReadBarrieredBase ReadBarriered(ReadBarriered&& v) : ReadBarrieredBase(mozilla::Forward>(v)) { - this->post(GCPolicy::initial(), v.value); + this->post(JS::GCPolicy::initial(), v.value); } ~ReadBarriered() { - this->post(this->value, GCPolicy::initial()); + this->post(this->value, JS::GCPolicy::initial()); } ReadBarriered& operator=(const ReadBarriered& v) { @@ -606,7 +606,7 @@ class ReadBarriered : public ReadBarrieredBase const T get() const { if (!InternalBarrierMethods::isMarkable(this->value)) - return GCPolicy::initial(); + return JS::GCPolicy::initial(); this->read(); return this->value; } diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h index b9bf028d3a..228f9e92d1 100644 --- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -128,6 +128,7 @@ struct MovingTracer : JS::CallbackTracer void onStringEdge(JSString** stringp) override; void onScriptEdge(JSScript** scriptp) override; void onLazyScriptEdge(LazyScript** lazyp) override; + void onBaseShapeEdge(BaseShape** basep) override; void onChild(const JS::GCCellPtr& thing) override { MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell())); } diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 2dada9b2e7..d7e84703b6 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -8,6 +8,7 @@ #define gc_GCRuntime_h #include "mozilla/Atomics.h" +#include "mozilla/EnumSet.h" #include "jsfriendapi.h" #include "jsgc.h" @@ -577,6 +578,8 @@ class ChainedIter typedef HashMap, SystemAllocPolicy> RootedValueMap; +using AllocKinds = mozilla::EnumSet; + class GCRuntime { public: @@ -611,7 +614,6 @@ class GCRuntime gcstats::AutoPhase ap(stats, gcstats::PHASE_EVICT_NURSERY); minorGCImpl(reason, nullptr); } - void clearPostBarrierCallbacks(); bool gcIfRequested(JSContext* cx = nullptr); void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason); void startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0); @@ -970,6 +972,7 @@ class GCRuntime bool relocateArenas(Zone* zone, JS::gcreason::Reason reason, Arena*& relocatedListOut, SliceBudget& sliceBudget); void updateTypeDescrObjects(MovingTracer* trc, Zone* zone); + void updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, size_t bgTaskCount); void updateAllCellPointers(MovingTracer* trc, Zone* zone); void updatePointersToRelocatedCells(Zone* zone); void protectAndHoldArenas(Arena* arenaList); @@ -1173,7 +1176,7 @@ class GCRuntime bool sweepingTypes; unsigned finalizePhase; JS::Zone* sweepZone; - unsigned sweepKindIndex; + AllocKind sweepKind; bool abortSweepAfterCurrentGroup; /* diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index d839505898..7be1c6f3ba 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -126,10 +126,10 @@ IsThingPoisoned(T* thing) JS_SWEPT_NURSERY_PATTERN, JS_ALLOCATED_NURSERY_PATTERN, JS_FRESH_TENURED_PATTERN, + JS_MOVED_TENURED_PATTERN, JS_SWEPT_TENURED_PATTERN, JS_ALLOCATED_TENURED_PATTERN, - JS_SWEPT_CODE_PATTERN, - JS_SWEPT_FRAME_PATTERN + JS_SWEPT_CODE_PATTERN }; const int numPoisonBytes = sizeof(poisonBytes) / sizeof(poisonBytes[0]); uint32_t* p = reinterpret_cast(reinterpret_cast(thing) + 1); @@ -2032,7 +2032,7 @@ template struct TenuringTraversalFunctor : public IdentityDefaultAdaptor { template S operator()(T* t, TenuringTracer* trc) { trc->traverse(&t); - return js::gc::RewrapTaggedPointer::wrap(t); + return js::gc::RewrapTaggedPointer::wrap(t); } }; @@ -2102,6 +2102,9 @@ js::gc::StoreBuffer::WholeCellEdges::trace(TenuringTracer& mover) const JS::TraceKind kind = edge->getTraceKind(); if (kind == JS::TraceKind::Object) { JSObject *object = static_cast(edge); + if (object->is()) + object->as().clearInWholeCellBuffer(); + mover.traceObject(object); // Additionally trace the expando object attached to any unboxed plain @@ -2435,7 +2438,7 @@ template struct IsMarkedFunctor : public IdentityDefaultAdaptor { template S operator()(T* t, bool* rv) { *rv = IsMarkedInternal(&t); - return js::gc::RewrapTaggedPointer::wrap(t); + return js::gc::RewrapTaggedPointer::wrap(t); } }; @@ -2494,7 +2497,7 @@ template struct IsAboutToBeFinalizedFunctor : public IdentityDefaultAdaptor { template S operator()(T* t, bool* rv) { *rv = IsAboutToBeFinalizedInternal(&t); - return js::gc::RewrapTaggedPointer::wrap(t); + return js::gc::RewrapTaggedPointer::wrap(t); } }; diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index f6e1aa5e10..15da5346b8 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -420,14 +420,34 @@ template struct RewrapTaggedPointer{}; #define DECLARE_REWRAP(S, T, method, prefix) \ template <> struct RewrapTaggedPointer { \ - static S wrap(T thing) { return method ( prefix thing ); } \ + static S wrap(T* thing) { return method ( prefix thing ); } \ } -DECLARE_REWRAP(JS::Value, JSObject*, JS::ObjectOrNullValue, ); -DECLARE_REWRAP(JS::Value, JSString*, JS::StringValue, ); -DECLARE_REWRAP(JS::Value, JS::Symbol*, JS::SymbolValue, ); -DECLARE_REWRAP(jsid, JSString*, NON_INTEGER_ATOM_TO_JSID, (JSAtom*)); -DECLARE_REWRAP(jsid, JS::Symbol*, SYMBOL_TO_JSID, ); -DECLARE_REWRAP(js::TaggedProto, JSObject*, js::TaggedProto, ); +DECLARE_REWRAP(JS::Value, JSObject, JS::ObjectOrNullValue, ); +DECLARE_REWRAP(JS::Value, JSString, JS::StringValue, ); +DECLARE_REWRAP(JS::Value, JS::Symbol, JS::SymbolValue, ); +DECLARE_REWRAP(jsid, JSString, NON_INTEGER_ATOM_TO_JSID, (JSAtom*)); +DECLARE_REWRAP(jsid, JS::Symbol, SYMBOL_TO_JSID, ); +DECLARE_REWRAP(js::TaggedProto, JSObject, js::TaggedProto, ); +#undef DECLARE_REWRAP + +template +struct IsPrivateGCThingInValue + : public mozilla::EnableIf::value && + !mozilla::IsBaseOf::value && + !mozilla::IsBaseOf::value && + !mozilla::IsBaseOf::value, T> +{ + static_assert(!mozilla::IsSame::value && !mozilla::IsSame::value, + "T must not be Cell or TenuredCell"); +}; + +template +struct RewrapTaggedPointer +{ + static Value wrap(typename IsPrivateGCThingInValue::Type* thing) { + return JS::PrivateGCThingValue(thing); + } +}; } /* namespace gc */ diff --git a/js/src/gc/Policy.h b/js/src/gc/Policy.h index b5a94389ce..d30fe6f125 100644 --- a/js/src/gc/Policy.h +++ b/js/src/gc/Policy.h @@ -134,33 +134,38 @@ struct InternalGCPointerPolicy { TraceManuallyBarrieredEdge(trc, vp, name); } }; + +} // namespace js + +namespace JS { + #define DEFINE_INTERNAL_GC_POLICY(type) \ - template <> struct GCPolicy : public InternalGCPointerPolicy {}; + template <> struct GCPolicy : public js::InternalGCPointerPolicy {}; FOR_EACH_INTERNAL_GC_POINTER_TYPE(DEFINE_INTERNAL_GC_POLICY) #undef DEFINE_INTERNAL_GC_POLICY template -struct GCPolicy> +struct GCPolicy> { - static void trace(JSTracer* trc, RelocatablePtr* thingp, const char* name) { - TraceEdge(trc, thingp, name); + static void trace(JSTracer* trc, js::RelocatablePtr* thingp, const char* name) { + js::TraceEdge(trc, thingp, name); } - static bool needsSweep(RelocatablePtr* thingp) { - return gc::IsAboutToBeFinalized(thingp); + static bool needsSweep(js::RelocatablePtr* thingp) { + return js::gc::IsAboutToBeFinalized(thingp); } }; template -struct GCPolicy> +struct GCPolicy> { - static void trace(JSTracer* trc, ReadBarriered* thingp, const char* name) { - TraceEdge(trc, thingp, name); + static void trace(JSTracer* trc, js::ReadBarriered* thingp, const char* name) { + js::TraceEdge(trc, thingp, name); } - static bool needsSweep(ReadBarriered* thingp) { - return gc::IsAboutToBeFinalized(thingp); + static bool needsSweep(js::ReadBarriered* thingp) { + return js::gc::IsAboutToBeFinalized(thingp); } }; -} // namespace js +} // namespace JS #endif // gc_Policy_h diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index bab858ad02..7b9933ef03 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -82,8 +82,8 @@ JS_FOR_EACH_TRACEKIND(MARK_ROOTS) static void MarkExactStackRoots(JSRuntime* rt, JSTracer* trc) { - for (ContextIter cx(rt); !cx.done(); cx.next()) - cx->roots.traceStackRoots(trc); + for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) + zone->roots.traceStackRoots(trc); rt->mainThread.roots.traceStackRoots(trc); } @@ -113,8 +113,6 @@ JS_FOR_EACH_TRACEKIND(MARK_ROOTS) static void MarkPersistentRooted(JSRuntime* rt, JSTracer* trc) { - for (ContextIter cx(rt); !cx.done(); cx.next()) - cx->roots.tracePersistentRoots(trc); rt->mainThread.roots.tracePersistentRoots(trc); } diff --git a/js/src/gc/Rooting.h b/js/src/gc/Rooting.h index d558c2386d..95ccdda88a 100644 --- a/js/src/gc/Rooting.h +++ b/js/src/gc/Rooting.h @@ -56,10 +56,10 @@ typedef JS::Rooted RootedPlainObject; typedef JS::Rooted RootedSavedFrame; typedef JS::Rooted RootedScriptSource; -typedef GCVector FunctionVector; -typedef GCVector PropertyNameVector; -typedef GCVector ShapeVector; -typedef GCVector StringVector; +typedef JS::GCVector FunctionVector; +typedef JS::GCVector PropertyNameVector; +typedef JS::GCVector ShapeVector; +typedef JS::GCVector StringVector; } /* namespace js */ diff --git a/js/src/gc/StoreBuffer-inl.h b/js/src/gc/StoreBuffer-inl.h new file mode 100644 index 0000000000..640645c878 --- /dev/null +++ b/js/src/gc/StoreBuffer-inl.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef gc_StoreBuffer_inl_h +#define gc_StoreBuffer_inl_h + +namespace js { +namespace gc { + +inline void +StoreBuffer::putWholeCell(Cell* cell) +{ + MOZ_ASSERT(cell->isTenured()); + + if (cell->getTraceKind() == JS::TraceKind::Object) { + JSObject *obj = static_cast(cell); + if (obj->is()) + obj->as().setInWholeCellBuffer(); + } + + put(bufferWholeCell, WholeCellEdges(cell)); +} + +} // namespace gc +} // namespace js + +#endif // gc_StoreBuffer_inl_h diff --git a/js/src/gc/StoreBuffer.h b/js/src/gc/StoreBuffer.h index fe524073c9..9f26de05fb 100644 --- a/js/src/gc/StoreBuffer.h +++ b/js/src/gc/StoreBuffer.h @@ -357,23 +357,6 @@ class StoreBuffer typedef PointerEdgeHasher Hasher; }; - template - struct CallbackRef : public BufferableRef - { - typedef void (*TraceCallback)(JSTracer* trc, Key* key, void* data); - - CallbackRef(TraceCallback cb, Key* k, void* d) : callback(cb), key(k), data(d) {} - - virtual void trace(JSTracer* trc) { - callback(trc, key, data); - } - - private: - TraceCallback callback; - Key* key; - void* data; - }; - template void unput(Buffer& buffer, const Edge& edge) { MOZ_ASSERT(!JS::shadow::Runtime::asShadowRuntime(runtime_)->isHeapBusy()); @@ -445,21 +428,12 @@ class StoreBuffer else put(bufferSlot, edge); } - void putWholeCell(Cell* cell) { - MOZ_ASSERT(cell->isTenured()); - put(bufferWholeCell, WholeCellEdges(cell)); - } + inline void putWholeCell(Cell* cell); /* Insert an entry into the generic buffer. */ template void putGeneric(const T& t) { put(bufferGeneric, t);} - /* Insert or update a callback entry. */ - template - void putCallback(void (*callback)(JSTracer* trc, Key* key, void* data), Key* key, void* data) { - put(bufferGeneric, CallbackRef(callback, key, data)); - } - void setShouldCancelIonCompilations() { cancelIonCompilations_ = true; } @@ -474,10 +448,6 @@ class StoreBuffer /* For use by our owned buffers and for testing. */ void setAboutToOverflow(); - bool hasPostBarrierCallbacks() { - return !bufferGeneric.isEmpty(); - } - void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::GCSizes* sizes); }; diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index f564d2ae9b..d8fb179b65 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -59,7 +59,7 @@ JS_FOR_EACH_TRACEKIND(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS); template struct DoCallbackFunctor : public IdentityDefaultAdaptor { template S operator()(T* t, JS::CallbackTracer* trc, const char* name) { - return js::gc::RewrapTaggedPointer::wrap(DoCallback(trc, &t, name)); + return js::gc::RewrapTaggedPointer::wrap(DoCallback(trc, &t, name)); } }; diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 7c6cfd7867..22791a0065 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -127,7 +127,7 @@ struct Zone : public JS::shadow::Zone, { explicit Zone(JSRuntime* rt); ~Zone(); - MOZ_WARN_UNUSED_RESULT bool init(bool isSystem); + MOZ_MUST_USE bool init(bool isSystem); void findOutgoingEdges(js::gc::ComponentFinder& finder); @@ -151,7 +151,7 @@ struct Zone : public JS::shadow::Zone, bool isTooMuchMalloc() const { return gcMallocBytes <= 0; } void onTooMuchMalloc(); - MOZ_WARN_UNUSED_RESULT void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, + MOZ_MUST_USE void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) { if (!js::CurrentThreadCanAccessRuntime(runtime_)) return nullptr; @@ -380,7 +380,7 @@ struct Zone : public JS::shadow::Zone, } // Creates a HashNumber based on getUniqueId. Returns false on OOM. - MOZ_WARN_UNUSED_RESULT bool getHashCode(js::gc::Cell* cell, js::HashNumber* hashp) { + MOZ_MUST_USE bool getHashCode(js::gc::Cell* cell, js::HashNumber* hashp) { uint64_t uid; if (!getUniqueId(cell, &uid)) return false; @@ -390,7 +390,7 @@ struct Zone : public JS::shadow::Zone, // Puts an existing UID in |uidp|, or creates a new UID for this Cell and // puts that into |uidp|. Returns false on OOM. - MOZ_WARN_UNUSED_RESULT bool getUniqueId(js::gc::Cell* cell, uint64_t* uidp) { + MOZ_MUST_USE bool getUniqueId(js::gc::Cell* cell, uint64_t* uidp) { MOZ_ASSERT(uidp); MOZ_ASSERT(js::CurrentThreadCanAccessZone(this)); @@ -425,7 +425,7 @@ struct Zone : public JS::shadow::Zone, } // Return true if this cell has a UID associated with it. - MOZ_WARN_UNUSED_RESULT bool hasUniqueId(js::gc::Cell* cell) { + MOZ_MUST_USE bool hasUniqueId(js::gc::Cell* cell) { MOZ_ASSERT(js::CurrentThreadCanAccessZone(this)); return uniqueIds_.has(cell); } diff --git a/js/src/irregexp/RegExpEngine.h b/js/src/irregexp/RegExpEngine.h index 1ecb04c43f..2fa911e257 100644 --- a/js/src/irregexp/RegExpEngine.h +++ b/js/src/irregexp/RegExpEngine.h @@ -130,7 +130,7 @@ FOR_EACH_REG_EXP_TREE_TYPE(FORWARD_DECLARE) // InfallibleVector is like Vector, but all its methods are infallible (they // crash on OOM). We use this class instead of Vector to avoid a ton of -// MOZ_WARN_UNUSED_RESULT warnings in irregexp code (imported from V8). +// MOZ_MUST_USE warnings in irregexp code (imported from V8). template class InfallibleVector { diff --git a/js/src/jit-test/lib/wasm.js b/js/src/jit-test/lib/wasm.js index 9bd0044f52..da568f4013 100644 --- a/js/src/jit-test/lib/wasm.js +++ b/js/src/jit-test/lib/wasm.js @@ -16,6 +16,18 @@ function hasI64() { return getBuildConfiguration().x64; } +function jsify(wasmVal) { + if (wasmVal === 'nan') + return NaN; + if (wasmVal === 'infinity') + return Infinity; + if (wasmVal === '-infinity') + return Infinity; + if (wasmVal === '-0') + return -0; + return wasmVal; +} + // Assert that the expected value is equal to the int64 value, as passed by // Baldr with --wasm-extra-tests {low: int32, high: int32}. // - if the expected value is in the int32 range, it can be just a number. diff --git a/js/src/jit-test/tests/TypedObject/bug1265690.js b/js/src/jit-test/tests/TypedObject/bug1265690.js new file mode 100644 index 0000000000..7e20a2ed12 --- /dev/null +++ b/js/src/jit-test/tests/TypedObject/bug1265690.js @@ -0,0 +1,14 @@ +if (!('oomTest' in this) || !this.hasOwnProperty("TypedObject")) + quit(); +lfCodeBuffer = ` + ArrayType = TypedObject.ArrayType; + var StructType = TypedObject.StructType; + float32 = TypedObject.float32; + Point = new ArrayType(float32, 3); + var Line = new StructType({ Point }); + new ArrayType(Line, 3); +`; +loadFile(lfCodeBuffer); +function loadFile(lfVarx) { + oomTest(function() { eval(lfVarx) }); +} diff --git a/js/src/jit-test/tests/arrays/std_Array-prototype.js b/js/src/jit-test/tests/arrays/std_Array-prototype.js new file mode 100644 index 0000000000..89ebde5d00 --- /dev/null +++ b/js/src/jit-test/tests/arrays/std_Array-prototype.js @@ -0,0 +1,6 @@ +Object.prototype.prototype = {}; +assertEq(Object.getPrototypeOf([].concat()), Array.prototype); +assertEq(Object.getPrototypeOf([].map(x => x)), Array.prototype); +assertEq(Object.getPrototypeOf([].filter(x => x)), Array.prototype); +assertEq(Object.getPrototypeOf([].slice()), Array.prototype); +assertEq(Object.getPrototypeOf([].splice()), Array.prototype); diff --git a/js/src/jit-test/tests/asm.js/testBug1219098.js b/js/src/jit-test/tests/asm.js/testBug1219098.js new file mode 100644 index 0000000000..1573ec460c --- /dev/null +++ b/js/src/jit-test/tests/asm.js/testBug1219098.js @@ -0,0 +1,14 @@ +load(libdir + "asm.js"); + +var bigScript = ` + function wee() { return 42 } + function asmModule() { 'use asm'; function f() { return 43 } return f} +` + ' '.repeat(10 * 1024 * 1024); + +eval(bigScript); + +if (isAsmJSCompilationAvailable()) + assertEq(isAsmJSModule(asmModule), true); + +assertEq(wee(), 42); +assertEq(eval('(' + wee.toSource() + ')')(), 42); diff --git a/js/src/jit-test/tests/asm.js/testExpressions.js b/js/src/jit-test/tests/asm.js/testExpressions.js index 991a495ab6..52b03cfcc3 100644 --- a/js/src/jit-test/tests/asm.js/testExpressions.js +++ b/js/src/jit-test/tests/asm.js/testExpressions.js @@ -56,6 +56,14 @@ assertEq(f(-1), (1048575*-1)|0); assertEq(f(INT32_MIN), (1048575*INT32_MIN)|0); assertEq(f(INT32_MAX), (1048575*INT32_MAX)|0); +var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=0; j=~i; return j|0 } return f")); +assertEq(f(0), ~0); +assertEq(f(3), ~3); +assertEq(f(-3), ~-3); +assertEq(f(INT32_MAX), ~INT32_MAX); +assertEq(f(INT32_MIN), ~INT32_MIN); +assertEq(f(UINT32_MAX), ~UINT32_MAX); + var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=+i; var j=0; j=~~i; return j|0 } return f")); assertEq(f(0), 0); assertEq(f(3.5), 3); diff --git a/js/src/jit-test/tests/basic/function-tosource-getset.js b/js/src/jit-test/tests/basic/function-tosource-getset.js index a42ca903d3..36c6d010e7 100644 --- a/js/src/jit-test/tests/basic/function-tosource-getset.js +++ b/js/src/jit-test/tests/basic/function-tosource-getset.js @@ -1,7 +1,7 @@ var o = {get prop() a + b, set prop(x) a + b}; var prop = Object.getOwnPropertyDescriptor(o, "prop"); -assertEq(prop.get.toString(), "function () a + b"); -assertEq(prop.get.toSource(), "(function () a + b)"); -assertEq(prop.set.toString(), "function (x) a + b"); -assertEq(prop.set.toSource(), "(function (x) a + b)"); +assertEq(prop.get.toString(), "function get prop() a + b"); +assertEq(prop.get.toSource(), "(function get prop() a + b)"); +assertEq(prop.set.toString(), "function set prop(x) a + b"); +assertEq(prop.set.toSource(), "(function set prop(x) a + b)"); assertEq(o.toSource(), "({get prop () a + b, set prop (x) a + b})"); diff --git a/js/src/jit-test/tests/parser/bug-1264568.js b/js/src/jit-test/tests/parser/bug-1264568.js new file mode 100644 index 0000000000..086a04aa94 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1264568.js @@ -0,0 +1,6 @@ +// |jit-test| error: SyntaxError +f = (function(stdlib, foreign, heap) { + "use asm"; + ({ "0" + () + { eval } diff --git a/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js b/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js index c78a1392b3..d665486803 100644 --- a/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js +++ b/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js @@ -20,11 +20,11 @@ cold_and_warm(entry1, { function: entry1 }, [ "entry1" ]); var getx = { get x() { } }; cold_and_warm(Object.getOwnPropertyDescriptor(getx, 'x').get, - { object: getx, property: 'x' }, [ "getx.x" ]); + { object: getx, property: 'x' }, [ "get x" ]); var sety = { set y(v) { } }; cold_and_warm(Object.getOwnPropertyDescriptor(sety, 'y').set, - { object: sety, property: 'y', value: 'glerk' }, [ "sety.y" ]); + { object: sety, property: 'y', value: 'glerk' }, [ "set y" ]); cold_and_warm(Object.prototype.toString, { ToString: {} }, []); diff --git a/js/src/jit-test/tests/wasm/basic-control-flow.js b/js/src/jit-test/tests/wasm/basic-control-flow.js index 733d32a4f2..b7d124b2ad 100644 --- a/js/src/jit-test/tests/wasm/basic-control-flow.js +++ b/js/src/jit-test/tests/wasm/basic-control-flow.js @@ -273,7 +273,7 @@ assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br 0)) assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br 0 (f32.const 42)))))'), TypeError, mismatchError("f32", "i32")); assertErrorMessage(() => wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))))) (export "" 0))`), TypeError, mismatchError("void", "i32")); -assertErrorMessage(() => wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (br 0 (f32.const 42)))) (export "" 0))`), TypeError, mismatchError("void", "i32")); +assertErrorMessage(() => wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (br 0 (f32.const 42)))) (export "" 0))`), TypeError, mismatchError("f32", "i32")); assertEq(wasmEvalText('(module (func (result i32) (block (br 0 (i32.const 42)) (i32.const 13))) (export "" 0))')(), 42); @@ -282,6 +282,10 @@ assertEq(wasmEvalText('(module (func) (func (block (br_if 0 (call 0) (i32.const var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (i32.const 43))) (export "" 0))`); assertEq(f(0), 43); +assertEq(f(1), 43); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 1 (i32.const 42))) (i32.const 43))) (export "" 0))`); +assertEq(f(0), 43); assertEq(f(1), 42); var f = wasmEvalText(`(module (func (result i32) (param i32) (block (br_if 0 (i32.const 42) (get_local 0)) (i32.const 43))) (export "" 0))`); @@ -290,6 +294,10 @@ assertEq(f(1), 42); var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (br 0 (i32.const 43)))) (export "" 0))`); assertEq(f(0), 43); +assertEq(f(1), 43); + +var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 1 (i32.const 42))) (br 0 (i32.const 43)))) (export "" 0))`); +assertEq(f(0), 43); assertEq(f(1), 42); var f = wasmEvalText(`(module (func (result i32) (param i32) (block (br_if 0 (i32.const 42) (get_local 0)) (br 0 (i32.const 43)))) (export "" 0))`); @@ -298,6 +306,10 @@ assertEq(f(1), 42); var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (if (get_local 0) (br 0 (i32.const 99))) (i32.const -1)))) (export "" 0))`); assertEq(f(0), 0); +assertEq(f(1), 0); + +var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (if (get_local 0) (br 1 (i32.const 99))) (i32.const -1)))) (export "" 0))`); +assertEq(f(0), 0); assertEq(f(1), 100); var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (br_if 0 (i32.const 99) (get_local 0)) (i32.const -1)))) (export "" 0))`); @@ -514,6 +526,45 @@ assertEq(f(1), 0); assertEq(f(2), 2); assertEq(f(3), -1); +// br_table with values +assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br_table 0 (i32.const 0)))))'), TypeError, mismatchError("void", "i32")); +assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br_table 0 (f32.const 0) (i32.const 0)))))'), TypeError, mismatchError("f32", "i32")); + +assertErrorMessage(() => wasmEvalText(`(module + (func + (result i32) + (block $outer + (block $inner + (br_table $outer $inner (f32.const 13.37) (i32.const 1)) + ) + (br $outer (i32.const 42)) + ) + ) +(export "" 0))`), TypeError, mismatchError("void", "i32")); + +assertEq(wasmEvalText(`(module (func (result i32) (block $default (br_table $default (i32.const 42) (i32.const 1)))) (export "" 0))`)(), 42); + +var f = wasmEvalText(`(module (func (param i32) (result i32) + (i32.add + (block $1 + (block $0 + (block $default + (br_table $0 $1 $default (get_local 0) (get_local 0)) + ) + (set_local 0 (i32.mul (i32.const 2) (get_local 0))) + ) + (set_local 0 (i32.add (i32.const 4) (get_local 0))) + ) + (i32.const 1) + ) + ) (export "" 0))`); + +assertEq(f(0), 5); +assertEq(f(1), 2); +assertEq(f(2), 9); +assertEq(f(3), 11); +assertEq(f(4), 13); + // ---------------------------------------------------------------------------- // unreachable diff --git a/js/src/jit-test/tests/wasm/basic-conversion.js b/js/src/jit-test/tests/wasm/basic-conversion.js index a4afcc9f1a..10e1bebf3a 100644 --- a/js/src/jit-test/tests/wasm/basic-conversion.js +++ b/js/src/jit-test/tests/wasm/basic-conversion.js @@ -22,7 +22,7 @@ function testConversion(resultType, opcode, paramType, op, expect) { assertEq(wasmEvalText('(module (func (param ' + paramType + ') (result ' + resultType + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))) (export "" 0))')(op), expect); } - let formerWasmExtraTests = getJitCompilerOptions()['wasm.test-mode']; + let formerTestMode = getJitCompilerOptions()['wasm.test-mode']; setJitCompilerOption('wasm.test-mode', 1); for (var bad of ['i32', 'f32', 'f64', 'i64']) { if (bad === 'i64' && !hasI64()) @@ -44,7 +44,25 @@ function testConversion(resultType, opcode, paramType, op, expect) { ); } } - setJitCompilerOption('wasm.test-mode', formerWasmExtraTests); + setJitCompilerOption('wasm.test-mode', formerTestMode); +} + +function testTrap(resultType, opcode, paramType, op, expect) { + if (resultType === 'i64' && !hasI64()) + return; + + let func = wasmEvalText(`(module + (func + (param ${paramType}) + (result ${resultType}) + (${resultType}.${opcode}/${paramType} (get_local 0)) + ) + (export "" 0) + )`); + + let expectedError = op === 'nan' ? /invalid conversion to integer/ : /integer overflow/; + + assertErrorMessage(() => func(jsify(op)), Error, expectedError); } if (hasI64()) { @@ -160,30 +178,29 @@ if (hasI64()) { testConversion('i64', 'trunc_u', 'f32', 4294967296, "0x100000000"); testConversion('i64', 'trunc_u', 'f32', 18446742974197923840.0, "0xffffff0000000000"); - // TODO: these should trap. - testConversion('i64', 'trunc_s', 'f64', 9223372036854775808.0, "0x8000000000000000"); - testConversion('i64', 'trunc_s', 'f64', -9223372036854777856.0, "0x8000000000000000"); - testConversion('i64', 'trunc_s', 'f64', "nan", "0x8000000000000000"); - testConversion('i64', 'trunc_s', 'f64', "infinity", "0x8000000000000000"); - testConversion('i64', 'trunc_s', 'f64', "-infinity", "0x8000000000000000"); + testTrap('i64', 'trunc_s', 'f64', 9223372036854776000.0); + testTrap('i64', 'trunc_s', 'f64', -9223372036854778000.0); + testTrap('i64', 'trunc_s', 'f64', "nan"); + testTrap('i64', 'trunc_s', 'f64', "infinity"); + testTrap('i64', 'trunc_s', 'f64', "-infinity"); - testConversion('i64', 'trunc_u', 'f64', -1, "0x8000000000000000"); - testConversion('i64', 'trunc_u', 'f64', 18446744073709551616.0, "0x8000000000000000"); - testConversion('i64', 'trunc_u', 'f64', "nan", "0x8000000000000000"); - testConversion('i64', 'trunc_u', 'f64', "infinity", "0x8000000000000000"); - testConversion('i64', 'trunc_u', 'f64', "-infinity", "0x8000000000000000"); + testTrap('i64', 'trunc_u', 'f64', -1); + testTrap('i64', 'trunc_u', 'f64', 18446744073709551616.0); + testTrap('i64', 'trunc_u', 'f64', "nan"); + testTrap('i64', 'trunc_u', 'f64', "infinity"); + testTrap('i64', 'trunc_u', 'f64', "-infinity"); - testConversion('i64', 'trunc_s', 'f32', 9223372036854775808.0, "0x8000000000000000"); - testConversion('i64', 'trunc_s', 'f32', -9223372036854777856.0, "0x8000000000000000"); - testConversion('i64', 'trunc_s', 'f32', "nan", "0x8000000000000000"); - testConversion('i64', 'trunc_s', 'f32', "infinity", "0x8000000000000000"); - testConversion('i64', 'trunc_s', 'f32', "-infinity", "0x8000000000000000"); + testTrap('i64', 'trunc_s', 'f32', 9223372036854776000.0); + testTrap('i64', 'trunc_s', 'f32', -9223372586610630000.0); + testTrap('i64', 'trunc_s', 'f32', "nan"); + testTrap('i64', 'trunc_s', 'f32', "infinity"); + testTrap('i64', 'trunc_s', 'f32', "-infinity"); - testConversion('i64', 'trunc_u', 'f32', 18446744073709551616.0, "0x8000000000000000"); - testConversion('i64', 'trunc_u', 'f32', -1, "0x8000000000000000"); - testConversion('i64', 'trunc_u', 'f32', "nan", "0x8000000000000000"); - testConversion('i64', 'trunc_u', 'f32', "infinity", "0x8000000000000000"); - testConversion('i64', 'trunc_u', 'f32', "-infinity", "0x8000000000000000"); + testTrap('i64', 'trunc_u', 'f32', 18446744073709551616.0); + testTrap('i64', 'trunc_u', 'f32', -1); + testTrap('i64', 'trunc_u', 'f32', "nan"); + testTrap('i64', 'trunc_u', 'f32', "infinity"); + testTrap('i64', 'trunc_u', 'f32', "-infinity"); testConversion('i64', 'reinterpret', 'f64', 40.09999999999968, "0x40440ccccccccca0"); testConversion('f64', 'reinterpret', 'i64', "0x40440ccccccccca0", 40.09999999999968); @@ -193,7 +210,7 @@ if (hasI64()) { // Sleeper test: once i64 works on more platforms, remove this if-else. try { testConversion('i32', 'wrap', 'i64', 4294967336, 40); - assertEq(0, 1); + throw new Error('hasI64() in wasm.js needs an update!'); } catch(e) { assertEq(e.toString().indexOf("NYI on this platform") >= 0, true); } diff --git a/js/src/jit-test/tests/wasm/basic-memory.js b/js/src/jit-test/tests/wasm/basic-memory.js index c9f9489783..cbf083f7f8 100644 --- a/js/src/jit-test/tests/wasm/basic-memory.js +++ b/js/src/jit-test/tests/wasm/basic-memory.js @@ -94,7 +94,7 @@ testLoad('i32', '16_u', 16, 0, 0, 0xf1f0); // When these tests fail, uncomment the load/store tests below. function testLoadNYI(ext) { - assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.load${ext} (i32.const 0))))`), TypeError, /NYI/); + assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.load${ext} (i32.const 0))))`), TypeError, /not yet implemented: i64/); } testLoadNYI(''); testLoadNYI('8_s'); @@ -116,7 +116,7 @@ testStore('i32', '', 0, 1, 0, -0x3f3e2c2c); testStore('i32', '', 1, 1, 4, -0x3f3e2c2c); function testStoreNYI(ext) { - assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.store${ext} (i32.const 0) (i32.const 0))))`), TypeError, /NYI/); + assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.store${ext} (i32.const 0) (i32.const 0))))`), TypeError, /not yet implemented: i64/); } testStoreNYI(''); testStoreNYI('8'); diff --git a/js/src/jit-test/tests/wasm/basic.js b/js/src/jit-test/tests/wasm/basic.js index 84854617a5..4b4fd03c23 100644 --- a/js/src/jit-test/tests/wasm/basic.js +++ b/js/src/jit-test/tests/wasm/basic.js @@ -572,17 +572,8 @@ assertEq(numF, 6); function testSelect(type, trueVal, falseVal) { - function toJS(val) { - switch (val) { - case "infinity": return Infinity; - case "nan": return NaN; - case "-0": return -0; - default: return val; - } - } - - var trueJS = toJS(trueVal); - var falseJS = toJS(falseVal); + var trueJS = jsify(trueVal); + var falseJS = jsify(falseVal); // Always true condition var alwaysTrue = wasmEvalText(` diff --git a/js/src/jit-test/tests/wasm/binary.js b/js/src/jit-test/tests/wasm/binary.js index f86d5b5ef7..926a257584 100644 --- a/js/src/jit-test/tests/wasm/binary.js +++ b/js/src/jit-test/tests/wasm/binary.js @@ -6,20 +6,20 @@ const magic1 = 0x61; // 'a' const magic2 = 0x73; // 's' const magic3 = 0x6d; // 'm' -// EncodingVersion = 10 (to be changed to 1 at some point in the future) -const ver0 = 0x0a; +// EncodingVersion = 11 (unofficial; to be reset at some point in the future) +const ver0 = 0x0b; const ver1 = 0x00; const ver2 = 0x00; const ver3 = 0x00; // Section names -const sigId = "signatures"; -const importId = "import_table"; -const functionSignaturesId = "function_signatures"; -const functionTableId = "function_table"; -const exportTableId = "export_table"; -const functionBodiesId = "function_bodies"; -const dataSegmentsId = "data_segments"; +const sigId = "type"; +const importId = "import"; +const functionSignaturesId = "function"; +const functionTableId = "table"; +const exportTableId = "export"; +const functionBodiesId = "code"; +const dataSegmentsId = "data"; const magicError = /failed to match magic number/; const versionError = /failed to match binary version/; @@ -32,8 +32,10 @@ const I64Code = 2; const F32Code = 3; const F64Code = 4; -const NopCode = 0x00; -const BlockCode = 0x01; +const FunctionConstructorCode = 0x40; + +const Block = 0x01; +const End = 0x0f; function toU8(array) { for (let b of array) @@ -75,15 +77,15 @@ function moduleHeaderThen(...rest) { var o = wasmEval(toU8(moduleHeaderThen())); assertEq(Object.getOwnPropertyNames(o).length, 0); -wasmEval(toU8(moduleHeaderThen(1, 0))); // unknown section containing 0-length string -wasmEval(toU8(moduleHeaderThen(2, 1, 0))); // unknown section containing 1-length string ("\0") -wasmEval(toU8(moduleHeaderThen(1, 0, 1, 0))); -wasmEval(toU8(moduleHeaderThen(1, 0, 2, 1, 0))); -wasmEval(toU8(moduleHeaderThen(1, 0, 2, 1, 0))); +wasmEval(toU8(moduleHeaderThen(0, 0))); // unknown section containing 0-length string +wasmEval(toU8(moduleHeaderThen(1, 0, 0))); // unknown section containing 1-length string ("\0") +wasmEval(toU8(moduleHeaderThen(0, 0, 0, 0))); +wasmEval(toU8(moduleHeaderThen(0, 0, 1, 0, 0))); +wasmEval(toU8(moduleHeaderThen(1, 0, 0, 1, 0, 0))); +wasmEval(toU8(moduleHeaderThen(1, 0, 0, 0, 0))); assertErrorMessage(() => wasmEval(toU8(moduleHeaderThen(1))), TypeError, sectionError); -assertErrorMessage(() => wasmEval(toU8(moduleHeaderThen(0, 1))), TypeError, sectionError); -assertErrorMessage(() => wasmEval(toU8(moduleHeaderThen(0, 0))), TypeError, unknownSectionError); +assertErrorMessage(() => wasmEval(toU8(moduleHeaderThen(0, 1))), TypeError, unknownSectionError); function cstring(name) { return (name + '\0').split('').map(c => c.charCodeAt(0)); @@ -101,9 +103,8 @@ function string(name) { function moduleWithSections(sectionArray) { var bytes = moduleHeaderThen(); for (let section of sectionArray) { - var sectionName = string(section.name); - bytes.push(...varU32(sectionName.length + section.body.length)); - bytes.push(...sectionName); + bytes.push(...string(section.name)); + bytes.push(...varU32(section.body.length)); bytes.push(...section.body); } return toU8(bytes); @@ -113,10 +114,13 @@ function sigSection(sigs) { var body = []; body.push(...varU32(sigs.length)); for (let sig of sigs) { + body.push(...varU32(FunctionConstructorCode)); body.push(...varU32(sig.args.length)); - body.push(...varU32(sig.ret)); for (let arg of sig.args) body.push(...varU32(arg)); + body.push(...varU32(sig.ret == VoidCode ? 0 : 1)); + if (sig.ret != VoidCode) + body.push(...varU32(sig.ret)); } return { name: sigId, body }; } @@ -167,8 +171,8 @@ const i2vSig = {args:[I32Code], ret:VoidCode}; const v2vBody = funcBody({locals:[], body:[]}); assertErrorMessage(() => wasmEval(moduleWithSections([ {name: sigId, body: U32MAX_LEB } ])), TypeError, /too many signatures/); -assertErrorMessage(() => wasmEval(moduleWithSections([ {name: sigId, body: [1, ...U32MAX_LEB], } ])), TypeError, /too many arguments in signature/); -assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([{args:[], ret:VoidCode}, {args:[], ret:VoidCode}])])), TypeError, /duplicate signature/); +assertErrorMessage(() => wasmEval(moduleWithSections([ {name: sigId, body: [1, 0], } ])), TypeError, /expected function form/); +assertErrorMessage(() => wasmEval(moduleWithSections([ {name: sigId, body: [1, FunctionConstructorCode, ...U32MAX_LEB], } ])), TypeError, /too many arguments in signature/); assertThrowsInstanceOf(() => wasmEval(moduleWithSections([{name: sigId, body: [1]}])), TypeError); assertThrowsInstanceOf(() => wasmEval(moduleWithSections([{name: sigId, body: [1, 1, 0]}])), TypeError); @@ -209,14 +213,8 @@ assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), decl wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0,0,0]), tableSection([0,1,0,2]), bodySection([v2vBody, v2vBody, v2vBody])])); wasmEval(moduleWithSections([sigSection([v2vSig,i2vSig]), declSection([0,0,1]), tableSection([0,1,2]), bodySection([v2vBody, v2vBody, v2vBody])])); -// Deep nesting shouldn't crash. With iterative decoding, we should test that -// this doesn't even throw. -try { - var manyBlocks = []; - for (var i = 0; i < 20000; i++) - manyBlocks.push(BlockCode, 1); - manyBlocks.push(NopCode); - wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:manyBlocks})])])); -} catch (e) { - assertEq(String(e).indexOf("too much recursion") == -1, false); -} +// Deep nesting shouldn't crash or even throw. +var manyBlocks = []; +for (var i = 0; i < 20000; i++) + manyBlocks.push(Block, End); +wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:manyBlocks})])])); diff --git a/js/src/jit-test/tests/wasm/totext1.js b/js/src/jit-test/tests/wasm/totext1.js index c5ce59fd13..2c6c9257b8 100644 --- a/js/src/jit-test/tests/wasm/totext1.js +++ b/js/src/jit-test/tests/wasm/totext1.js @@ -1,6 +1,9 @@ if (!wasmIsSupported()) quit(); +// FIXME: Enable this test once binary-to-text is implemented again. +quit(); + load(libdir + "asserts.js"); var caught = false; @@ -76,7 +79,7 @@ runTest(` (block $m (block (block (br $m)))) (block $k (br_if 0 (i32.const 0)) (return)) (block $n (block (block (br_if 2 (i32.const 1)) (nop)))) - (block $1 (block $2 (block $3 (br_table $2 $3 $1 (i32.const 1)) )) (nop)) + (block $1 (block $2 (block $3 (br_table $2 $3 $1 (nop) (i32.const 1)) )) (nop)) (loop $exit $cont (br_if $cont (i32.const 0)) (nop)) (return) ) diff --git a/js/src/jit/AliasAnalysis.cpp b/js/src/jit/AliasAnalysis.cpp index 8b1cd18b33..45d250b949 100644 --- a/js/src/jit/AliasAnalysis.cpp +++ b/js/src/jit/AliasAnalysis.cpp @@ -8,6 +8,7 @@ #include +#include "jit/AliasAnalysisShared.h" #include "jit/Ion.h" #include "jit/IonBuilder.h" #include "jit/JitSpewer.h" @@ -56,45 +57,8 @@ class LoopAliasInfo : public TempObject } // namespace jit } // namespace js -namespace { - -// Iterates over the flags in an AliasSet. -class AliasSetIterator -{ - private: - uint32_t flags; - unsigned pos; - - public: - explicit AliasSetIterator(AliasSet set) - : flags(set.flags()), pos(0) - { - while (flags && (flags & 1) == 0) { - flags >>= 1; - pos++; - } - } - AliasSetIterator& operator ++(int) { - do { - flags >>= 1; - pos++; - } while (flags && (flags & 1) == 0); - return *this; - } - explicit operator bool() const { - return !!flags; - } - unsigned operator*() const { - MOZ_ASSERT(pos < AliasSet::NumCategories); - return pos; - } -}; - -} /* anonymous namespace */ - AliasAnalysis::AliasAnalysis(MIRGenerator* mir, MIRGraph& graph) - : mir(mir), - graph_(graph), + : AliasAnalysisShared(mir, graph), loop_(nullptr) { } @@ -231,7 +195,9 @@ AliasAnalysis::analyze() MInstructionVector& aliasedStores = stores[*iter]; for (int i = aliasedStores.length() - 1; i >= 0; i--) { MInstruction* store = aliasedStores[i]; - if (def->mightAlias(store) && BlockMightReach(store->block(), *block)) { + if (def->mightAlias(store) != MDefinition::AliasType::NoAlias && + BlockMightReach(store->block(), *block)) + { if (lastStore->id() < store->id()) lastStore = store; break; @@ -276,7 +242,7 @@ AliasAnalysis::analyze() MInstruction* store = aliasedStores[i]; if (store->id() < firstLoopIns->id()) break; - if (ins->mightAlias(store)) { + if (ins->mightAlias(store) != MDefinition::AliasType::NoAlias) { hasAlias = true; IonSpewDependency(ins, store, "aliases", "store in loop body"); break; @@ -307,6 +273,8 @@ AliasAnalysis::analyze() } } + spewDependencyList(); + MOZ_ASSERT(loop_ == nullptr); return true; } diff --git a/js/src/jit/AliasAnalysis.h b/js/src/jit/AliasAnalysis.h index 99bbd3dc53..264a808ede 100644 --- a/js/src/jit/AliasAnalysis.h +++ b/js/src/jit/AliasAnalysis.h @@ -7,6 +7,7 @@ #ifndef jit_AliasAnalysis_h #define jit_AliasAnalysis_h +#include "jit/AliasAnalysisShared.h" #include "jit/MIR.h" #include "jit/MIRGraph.h" @@ -14,21 +15,14 @@ namespace js { namespace jit { class LoopAliasInfo; -class MIRGraph; -class AliasAnalysis +class AliasAnalysis : public AliasAnalysisShared { - MIRGenerator* mir; - MIRGraph& graph_; LoopAliasInfo* loop_; - TempAllocator& alloc() const { - return graph_.alloc(); - } - public: AliasAnalysis(MIRGenerator* mir, MIRGraph& graph); - bool analyze(); + bool analyze() override; }; } // namespace jit diff --git a/js/src/jit/AliasAnalysisShared.cpp b/js/src/jit/AliasAnalysisShared.cpp new file mode 100644 index 0000000000..501759428d --- /dev/null +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -0,0 +1,44 @@ +/* -*- 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 "jit/AliasAnalysisShared.h" + +namespace js { +namespace jit { + +void +AliasAnalysisShared::spewDependencyList() +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_AliasSummaries)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpew_AliasSummaries); + print.printf("Dependency list for other passes:\n"); + + for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { + for (MInstructionIterator def(block->begin()), end(block->begin(block->lastIns())); + def != end; + ++def) + { + if (!def->dependency()) + continue; + if (!def->getAliasSet().isLoad()) + continue; + + JitSpewHeader(JitSpew_AliasSummaries); + print.printf(" "); + MDefinition::PrintOpcodeName(print, def->op()); + print.printf("%d marked depending on ", def->id()); + MDefinition::PrintOpcodeName(print, def->dependency()->op()); + print.printf("%d\n", def->dependency()->id()); + } + } + } +#endif +} + +} // namespace jit +} // namespace js diff --git a/js/src/jit/AliasAnalysisShared.h b/js/src/jit/AliasAnalysisShared.h new file mode 100644 index 0000000000..a6782177a0 --- /dev/null +++ b/js/src/jit/AliasAnalysisShared.h @@ -0,0 +1,77 @@ +/* -*- 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 jit_AliasAnalysisShared_h +#define jit_AliasAnalysisShared_h + +#include "jit/MIR.h" +#include "jit/MIRGraph.h" + +namespace js { +namespace jit { + +class MIRGraph; + +class AliasAnalysisShared +{ + protected: + MIRGenerator* mir; + MIRGraph& graph_; + + public: + AliasAnalysisShared(MIRGenerator* mir, MIRGraph& graph) + : mir(mir), + graph_(graph) + {} + + virtual bool analyze() { + return true; + } + + protected: + void spewDependencyList(); + + TempAllocator& alloc() const { + return graph_.alloc(); + } +}; + +// Iterates over the flags in an AliasSet. +class AliasSetIterator +{ + private: + uint32_t flags; + unsigned pos; + + public: + explicit AliasSetIterator(AliasSet set) + : flags(set.flags()), pos(0) + { + while (flags && (flags & 1) == 0) { + flags >>= 1; + pos++; + } + } + AliasSetIterator& operator ++(int) { + do { + flags >>= 1; + pos++; + } while (flags && (flags & 1) == 0); + return *this; + } + explicit operator bool() const { + return !!flags; + } + unsigned operator*() const { + MOZ_ASSERT(pos < AliasSet::NumCategories); + return pos; + } +}; + +} // namespace jit +} // namespace js + +#endif /* jit_AliasAnalysisShared_h */ diff --git a/js/src/jit/AlignmentMaskAnalysis.cpp b/js/src/jit/AlignmentMaskAnalysis.cpp index d5ec424df0..97c32e2ebc 100644 --- a/js/src/jit/AlignmentMaskAnalysis.cpp +++ b/js/src/jit/AlignmentMaskAnalysis.cpp @@ -37,7 +37,7 @@ AnalyzeAsmHeapAddress(MDefinition* ptr, MIRGraph& graph) // Putting the add on the outside might seem like it exposes other users of // the expression to the possibility of i32 overflow, if we aren't in asm.js // and they aren't naturally truncating. However, since we use MAdd::NewAsmJS - // with MIRType_Int32, we make sure that the value is truncated, just as it + // with MIRType::Int32, we make sure that the value is truncated, just as it // would be by the MBitAnd. MOZ_ASSERT(IsCompilingAsmJS()); @@ -65,9 +65,9 @@ AnalyzeAsmHeapAddress(MDefinition* ptr, MIRGraph& graph) return; // The pattern was matched! Produce the replacement expression. - MInstruction* and_ = MBitAnd::NewAsmJS(graph.alloc(), op0, rhs, MIRType_Int32); + MInstruction* and_ = MBitAnd::NewAsmJS(graph.alloc(), op0, rhs, MIRType::Int32); ptr->block()->insertBefore(ptr->toBitAnd(), and_); - MInstruction* add = MAdd::NewAsmJS(graph.alloc(), and_, op1, MIRType_Int32); + MInstruction* add = MAdd::NewAsmJS(graph.alloc(), and_, op1, MIRType::Int32); ptr->block()->insertBefore(ptr->toBitAnd(), add); ptr->replaceAllUsesWith(add); ptr->block()->discard(ptr->toBitAnd()); diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 1cd15b4d94..437f59c911 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -580,7 +580,7 @@ static bool InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, HandleFunction fun, HandleScript script, IonScript* ionScript, SnapshotIterator& iter, bool invalidate, BaselineStackBuilder& builder, - AutoValueVector& startFrameFormals, MutableHandleFunction nextCallee, + MutableHandle> startFrameFormals, MutableHandleFunction nextCallee, jsbytecode** callPC, const ExceptionBailoutInfo* excInfo) { // The Baseline frames we will reconstruct on the heap are not rooted, so GC @@ -1530,7 +1530,7 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter RootedScript caller(cx); jsbytecode* callerPC = nullptr; RootedFunction fun(cx, callee); - AutoValueVector startFrameFormals(cx); + Rooted> startFrameFormals(cx, GCVector(cx)); gc::AutoSuppressGC suppress(cx); @@ -1560,7 +1560,7 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter jsbytecode* callPC = nullptr; RootedFunction nextCallee(cx, nullptr); if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(), - snapIter, invalidate, builder, startFrameFormals, + snapIter, invalidate, builder, &startFrameFormals, &nextCallee, &callPC, passExcInfo ? excInfo : nullptr)) { return BAILOUT_RETURN_FATAL_ERROR; diff --git a/js/src/jit/BaselineCacheIR.cpp b/js/src/jit/BaselineCacheIR.cpp index 120040d9a0..0093b95386 100644 --- a/js/src/jit/BaselineCacheIR.cpp +++ b/js/src/jit/BaselineCacheIR.cpp @@ -169,7 +169,7 @@ class MOZ_RAII CacheRegisterAllocator writer_(writer) {} - MOZ_WARN_UNUSED_RESULT bool init(const AllocatableGeneralRegisterSet& available) { + MOZ_MUST_USE bool init(const AllocatableGeneralRegisterSet& available) { availableRegs_ = available; if (!origInputLocations_.resize(writer_.numInputOperands())) return false; @@ -395,12 +395,12 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler stubDataOffset_(stubDataOffset) {} - MOZ_WARN_UNUSED_RESULT bool init(CacheKind kind); + MOZ_MUST_USE bool init(CacheKind kind); JitCode* compile(); private: -#define DEFINE_OP(op) MOZ_WARN_UNUSED_RESULT bool emit##op(); +#define DEFINE_OP(op) MOZ_MUST_USE bool emit##op(); CACHE_IR_OPS(DEFINE_OP) #undef DEFINE_OP diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 335f2221ec..fbb3944d3b 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2495,7 +2495,7 @@ BaselineCompiler::emit_JSOP_SETALIASEDVAR() getScopeCoordinateObject(objReg); Address address = getScopeCoordinateAddressFromObject(objReg, R1.scratchReg()); - masm.patchableCallPreBarrier(address, MIRType_Value); + masm.patchableCallPreBarrier(address, MIRType::Value); masm.storeValue(R0, address); frame.push(R0); @@ -2905,7 +2905,7 @@ BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get) masm.loadValue(argAddr, R0); frame.push(R0); } else { - masm.patchableCallPreBarrier(argAddr, MIRType_Value); + masm.patchableCallPreBarrier(argAddr, MIRType::Value); masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0); masm.storeValue(R0, argAddr); @@ -3941,7 +3941,7 @@ BaselineCompiler::emit_JSOP_INITIALYIELD() Register scopeObj = R0.scratchReg(); Address scopeChainSlot(genObj, GeneratorObject::offsetOfScopeChainSlot()); masm.loadPtr(frame.addressOfScopeChain(), scopeObj); - masm.patchableCallPreBarrier(scopeChainSlot, MIRType_Value); + masm.patchableCallPreBarrier(scopeChainSlot, MIRType::Value); masm.storeValue(JSVAL_TYPE_OBJECT, scopeObj, scopeChainSlot); Register temp = R1.scratchReg(); @@ -3986,7 +3986,7 @@ BaselineCompiler::emit_JSOP_YIELD() Register scopeObj = R0.scratchReg(); Address scopeChainSlot(genObj, GeneratorObject::offsetOfScopeChainSlot()); masm.loadPtr(frame.addressOfScopeChain(), scopeObj); - masm.patchableCallPreBarrier(scopeChainSlot, MIRType_Value); + masm.patchableCallPreBarrier(scopeChainSlot, MIRType::Value); masm.storeValue(JSVAL_TYPE_OBJECT, scopeObj, scopeChainSlot); Register temp = R1.scratchReg(); @@ -4214,7 +4214,7 @@ BaselineCompiler::emit_JSOP_RESUME() } masm.bind(&loopDone); - masm.patchableCallPreBarrier(exprStackSlot, MIRType_Value); + masm.patchableCallPreBarrier(exprStackSlot, MIRType::Value); masm.storeValue(NullValue(), exprStackSlot); regs.add(initLength); } diff --git a/js/src/jit/BaselineFrame.cpp b/js/src/jit/BaselineFrame.cpp index a6d10256bc..f79be037b3 100644 --- a/js/src/jit/BaselineFrame.cpp +++ b/js/src/jit/BaselineFrame.cpp @@ -92,17 +92,17 @@ BaselineFrame::isNonGlobalEvalFrame() const } bool -BaselineFrame::copyRawFrameSlots(AutoValueVector* vec) const +BaselineFrame::copyRawFrameSlots(MutableHandle> vec) const { unsigned nfixed = script()->nfixed(); unsigned nformals = numFormalArgs(); - if (!vec->resize(nformals + nfixed)) + if (!vec.resize(nformals + nfixed)) return false; - mozilla::PodCopy(vec->begin(), argv(), nformals); + mozilla::PodCopy(vec.begin(), argv(), nformals); for (unsigned i = 0; i < nfixed; i++) - (*vec)[nformals + i].set(*valueSlot(i)); + vec[nformals + i].set(*valueSlot(i)); return true; } diff --git a/js/src/jit/BaselineFrame.h b/js/src/jit/BaselineFrame.h index 60fc9a54ce..dc2fbb21b2 100644 --- a/js/src/jit/BaselineFrame.h +++ b/js/src/jit/BaselineFrame.h @@ -229,7 +229,7 @@ class BaselineFrame return UndefinedValue(); } - bool copyRawFrameSlots(AutoValueVector* vec) const; + bool copyRawFrameSlots(MutableHandle> vec) const; bool hasReturnValue() const { return flags_ & HAS_RVAL; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 43bcc0cd92..23d04bb56c 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2742,9 +2742,9 @@ void EmitUnboxedPreBarrierForBaseline(MacroAssembler &masm, T address, JSValueType type) { if (type == JSVAL_TYPE_OBJECT) - EmitPreBarrier(masm, address, MIRType_Object); + EmitPreBarrier(masm, address, MIRType::Object); else if (type == JSVAL_TYPE_STRING) - EmitPreBarrier(masm, address, MIRType_String); + EmitPreBarrier(masm, address, MIRType::String); else MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type)); } @@ -2861,7 +2861,7 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm) ValueOperand tmpVal = regs.takeAnyValue(); masm.loadValue(valueAddr, tmpVal); - EmitPreBarrier(masm, element, MIRType_Value); + EmitPreBarrier(masm, element, MIRType::Value); masm.storeValue(tmpVal, element); } else { // Set element on an unboxed array. @@ -4754,7 +4754,7 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler& masm) // Perform the store. masm.load32(Address(ICStubReg, ICSetProp_Native::offsetOfOffset()), scratch); - EmitPreBarrier(masm, BaseIndex(holderReg, scratch, TimesOne), MIRType_Value); + EmitPreBarrier(masm, BaseIndex(holderReg, scratch, TimesOne), MIRType::Value); masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne)); if (holderReg != objReg) regs.add(holderReg); @@ -4872,7 +4872,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm) // Change the object's group. Address groupAddr(objReg, JSObject::offsetOfGroup()); - EmitPreBarrier(masm, groupAddr, MIRType_ObjectGroup); + EmitPreBarrier(masm, groupAddr, MIRType::ObjectGroup); masm.storePtr(scratch, groupAddr); masm.bind(&noGroupChange); @@ -4888,7 +4888,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm) // Write the expando object's new shape. Address shapeAddr(holderReg, JSObject::offsetOfShape()); - EmitPreBarrier(masm, shapeAddr, MIRType_Shape); + EmitPreBarrier(masm, shapeAddr, MIRType::Shape); masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); masm.storePtr(scratch, shapeAddr); @@ -4897,7 +4897,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm) } else { // Write the object's new shape. Address shapeAddr(objReg, JSObject::offsetOfShape()); - EmitPreBarrier(masm, shapeAddr, MIRType_Shape); + EmitPreBarrier(masm, shapeAddr, MIRType::Shape); masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); masm.storePtr(scratch, shapeAddr); @@ -5084,12 +5084,12 @@ ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm) switch (type) { case ReferenceTypeDescr::TYPE_ANY: - EmitPreBarrier(masm, dest, MIRType_Value); + EmitPreBarrier(masm, dest, MIRType::Value); masm.storeValue(R1, dest); break; case ReferenceTypeDescr::TYPE_OBJECT: { - EmitPreBarrier(masm, dest, MIRType_Object); + EmitPreBarrier(masm, dest, MIRType::Object); Label notObject; masm.branchTestObject(Assembler::NotEqual, R1, ¬Object); Register rhsObject = masm.extractObject(R1, ExtractTemp0); @@ -5102,7 +5102,7 @@ ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm) } case ReferenceTypeDescr::TYPE_STRING: { - EmitPreBarrier(masm, dest, MIRType_String); + EmitPreBarrier(masm, dest, MIRType::String); masm.branchTestString(Assembler::NotEqual, R1, &failure); Register rhsString = masm.extractString(R1, ExtractTemp0); masm.storePtr(rhsString, dest); @@ -5476,7 +5476,7 @@ GetTemplateObjectForNative(JSContext* cx, JSFunction* target, const CallArgs& ar // Check for natives to which template objects can be attached. This is // done to provide templates to Ion for inlining these natives later on. - if (native == ArrayConstructor) { + if (native == ArrayConstructor || native == array_construct) { // Note: the template array won't be used if its length is inaccurately // computed here. (We allocate here because compilation may occur on a // separate thread where allocation is impossible.) diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 18195b0b29..afc4320b86 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -733,7 +733,7 @@ class ICGetElemNativeCompiler : public ICStubCompiler protected: virtual int32_t getKey() const { MOZ_ASSERT(static_cast(acctype_) <= 7); - MOZ_ASSERT(static_cast(unboxedType_) <= 8); + MOZ_ASSERT(static_cast(unboxedType_) <= 15); return static_cast(engine_) | (static_cast(kind) << 1) | (static_cast(needsAtomize_) << 17) | diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index a48e2b23b0..4ef7c42c16 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -254,29 +254,29 @@ MIRType BaselineInspector::expectedResultType(jsbytecode* pc) { // Look at the IC entries for this op to guess what type it will produce, - // returning MIRType_None otherwise. + // returning MIRType::None otherwise. ICStub* stub = monomorphicStub(pc); if (!stub) - return MIRType_None; + return MIRType::None; switch (stub->kind()) { case ICStub::BinaryArith_Int32: if (stub->toBinaryArith_Int32()->allowDouble()) - return MIRType_Double; - return MIRType_Int32; + return MIRType::Double; + return MIRType::Int32; case ICStub::BinaryArith_BooleanWithInt32: case ICStub::UnaryArith_Int32: case ICStub::BinaryArith_DoubleWithInt32: - return MIRType_Int32; + return MIRType::Int32; case ICStub::BinaryArith_Double: case ICStub::UnaryArith_Double: - return MIRType_Double; + return MIRType::Double; case ICStub::BinaryArith_StringConcat: case ICStub::BinaryArith_StringObjectConcat: - return MIRType_String; + return MIRType::String; default: - return MIRType_None; + return MIRType::None; } } @@ -376,12 +376,12 @@ TryToSpecializeBinaryArithOp(ICStub** stubs, return false; if (sawDouble) { - *result = MIRType_Double; + *result = MIRType::Double; return true; } MOZ_ASSERT(sawInt32); - *result = MIRType_Int32; + *result = MIRType::Int32; return true; } @@ -389,7 +389,7 @@ MIRType BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc) { if (!hasBaselineScript()) - return MIRType_None; + return MIRType::None; MIRType result; ICStub* stubs[2]; @@ -399,7 +399,7 @@ BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc) if (stub->isBinaryArith_Fallback() && stub->toBinaryArith_Fallback()->hadUnoptimizableOperands()) { - return MIRType_None; + return MIRType::None; } stubs[0] = monomorphicStub(pc); @@ -413,7 +413,7 @@ BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc) return result; } - return MIRType_None; + return MIRType::None; } bool @@ -772,38 +772,38 @@ GetCacheIRExpectedInputType(ICCacheIR_Monitored* stub) // For now, all CacheIR stubs expect an object. MOZ_ALWAYS_TRUE(reader.matchOp(CacheOp::GuardIsObject, ObjOperandId(0))); - return MIRType_Object; + return MIRType::Object; } MIRType BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) { if (!hasBaselineScript()) - return MIRType_Value; + return MIRType::Value; const ICEntry& entry = icEntryFromPC(pc); - MIRType type = MIRType_None; + MIRType type = MIRType::None; for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { MIRType stubType; switch (stub->kind()) { case ICStub::GetProp_Fallback: if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) - return MIRType_Value; + return MIRType::Value; continue; case ICStub::GetElem_Fallback: if (stub->toGetElem_Fallback()->hadUnoptimizableAccess()) - return MIRType_Value; + return MIRType::Value; continue; case ICStub::GetProp_Generic: - return MIRType_Value; + return MIRType::Value; case ICStub::GetProp_ArgumentsLength: case ICStub::GetElem_Arguments: // Either an object or magic arguments. - return MIRType_Value; + return MIRType::Value; case ICStub::GetProp_Unboxed: case ICStub::GetProp_TypedObject: @@ -825,7 +825,7 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) case ICStub::GetElem_Dense: case ICStub::GetElem_TypedArray: case ICStub::GetElem_UnboxedArray: - stubType = MIRType_Object; + stubType = MIRType::Object; break; case ICStub::GetProp_Primitive: @@ -833,28 +833,28 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) break; case ICStub::GetProp_StringLength: - stubType = MIRType_String; + stubType = MIRType::String; break; case ICStub::CacheIR_Monitored: stubType = GetCacheIRExpectedInputType(stub->toCacheIR_Monitored()); - if (stubType == MIRType_Value) - return MIRType_Value; + if (stubType == MIRType::Value) + return MIRType::Value; break; default: MOZ_CRASH("Unexpected stub"); } - if (type != MIRType_None) { + if (type != MIRType::None) { if (type != stubType) - return MIRType_Value; + return MIRType::Value; } else { type = stubType; } } - return (type == MIRType_None) ? MIRType_Value : type; + return (type == MIRType::None) ? MIRType::Value : type; } bool diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index d16533fc43..2188a97e01 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -181,8 +181,8 @@ jit::EnterBaselineMethod(JSContext* cx, RunState& state) EnterJitData data(cx); data.jitcode = baseline->method()->raw(); - AutoValueVector vals(cx); - if (!SetEnterJitData(cx, data, state, vals)) + Rooted> vals(cx, GCVector(cx)); + if (!SetEnterJitData(cx, data, state, &vals)) return JitExec_Error; JitExecStatus status = EnterBaseline(cx, data); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index e0c04c7555..5cd86b3268 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -197,7 +197,7 @@ CodeGenerator::visitValueToInt32(LValueToInt32* lir) Label* stringEntry; Label* stringRejoin; Register stringReg; - if (input->mightBeType(MIRType_String)) { + if (input->mightBeType(MIRType::String)) { stringReg = ToRegister(lir->temp()); OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, ArgList(stringReg), StoreFloatRegisterTo(temp)); @@ -516,14 +516,14 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand& value, // last one. In particular, whenever tagCount is 1 that means we've tried // all but one of them already so we know exactly what's left based on the // mightBe* booleans. - bool mightBeUndefined = valueMIR->mightBeType(MIRType_Undefined); - bool mightBeNull = valueMIR->mightBeType(MIRType_Null); - bool mightBeBoolean = valueMIR->mightBeType(MIRType_Boolean); - bool mightBeInt32 = valueMIR->mightBeType(MIRType_Int32); - bool mightBeObject = valueMIR->mightBeType(MIRType_Object); - bool mightBeString = valueMIR->mightBeType(MIRType_String); - bool mightBeSymbol = valueMIR->mightBeType(MIRType_Symbol); - bool mightBeDouble = valueMIR->mightBeType(MIRType_Double); + bool mightBeUndefined = valueMIR->mightBeType(MIRType::Undefined); + bool mightBeNull = valueMIR->mightBeType(MIRType::Null); + bool mightBeBoolean = valueMIR->mightBeType(MIRType::Boolean); + bool mightBeInt32 = valueMIR->mightBeType(MIRType::Int32); + bool mightBeObject = valueMIR->mightBeType(MIRType::Object); + bool mightBeString = valueMIR->mightBeType(MIRType::String); + bool mightBeSymbol = valueMIR->mightBeType(MIRType::Symbol); + bool mightBeDouble = valueMIR->mightBeType(MIRType::Double); int tagCount = int(mightBeUndefined) + int(mightBeNull) + int(mightBeBoolean) + int(mightBeInt32) + int(mightBeObject) + int(mightBeString) + int(mightBeSymbol) + int(mightBeDouble); @@ -677,7 +677,7 @@ void CodeGenerator::visitTestOAndBranch(LTestOAndBranch* lir) { MIRType inputType = lir->mir()->input()->type(); - MOZ_ASSERT(inputType == MIRType_ObjectOrNull || lir->mir()->operandMightEmulateUndefined(), + MOZ_ASSERT(inputType == MIRType::ObjectOrNull || lir->mir()->operandMightEmulateUndefined(), "If the object couldn't emulate undefined, this should have been folded."); Label* truthy = getJumpLabelForBranch(lir->ifTruthy()); @@ -685,7 +685,7 @@ CodeGenerator::visitTestOAndBranch(LTestOAndBranch* lir) Register input = ToRegister(lir->input()); if (lir->mir()->operandMightEmulateUndefined()) { - if (inputType == MIRType_ObjectOrNull) + if (inputType == MIRType::ObjectOrNull) masm.branchTestPtr(Assembler::Zero, input, input, falsy); OutOfLineTestObject* ool = new(alloc()) OutOfLineTestObject(); @@ -693,7 +693,7 @@ CodeGenerator::visitTestOAndBranch(LTestOAndBranch* lir) testObjectEmulatesUndefined(input, falsy, truthy, ToRegister(lir->temp()), ool); } else { - MOZ_ASSERT(inputType == MIRType_ObjectOrNull); + MOZ_ASSERT(inputType == MIRType::ObjectOrNull); testZeroEmitBranch(Assembler::NotEqual, input, lir->ifTruthy(), lir->ifFalsy()); } } @@ -707,7 +707,7 @@ CodeGenerator::visitTestVAndBranch(LTestVAndBranch* lir) // out our input after we did cacheOperandMightEmulateUndefined. So we // might think it can emulate undefined _and_ know that it can't be an // object. - if (lir->mir()->operandMightEmulateUndefined() && input->mightBeType(MIRType_Object)) { + if (lir->mir()->operandMightEmulateUndefined() && input->mightBeType(MIRType::Object)) { ool = new(alloc()) OutOfLineTestObject(); addOutOfLineCode(ool, lir->mir()); } @@ -905,7 +905,7 @@ CodeGenerator::visitValueToString(LValueToString* lir) const JSAtomState& names = GetJitContext()->runtime->names(); // String - if (lir->mir()->input()->mightBeType(MIRType_String)) { + if (lir->mir()->input()->mightBeType(MIRType::String)) { Label notString; masm.branchTestString(Assembler::NotEqual, tag, ¬String); masm.unboxString(input, output); @@ -914,7 +914,7 @@ CodeGenerator::visitValueToString(LValueToString* lir) } // Integer - if (lir->mir()->input()->mightBeType(MIRType_Int32)) { + if (lir->mir()->input()->mightBeType(MIRType::Int32)) { Label notInteger; masm.branchTestInt32(Assembler::NotEqual, tag, ¬Integer); Register unboxed = ToTempUnboxRegister(lir->tempToUnbox()); @@ -925,14 +925,14 @@ CodeGenerator::visitValueToString(LValueToString* lir) } // Double - if (lir->mir()->input()->mightBeType(MIRType_Double)) { + if (lir->mir()->input()->mightBeType(MIRType::Double)) { // Note: no fastpath. Need two extra registers and can only convert doubles // that fit integers and are smaller than StaticStrings::INT_STATIC_LIMIT. masm.branchTestDouble(Assembler::Equal, tag, ool->entry()); } // Undefined - if (lir->mir()->input()->mightBeType(MIRType_Undefined)) { + if (lir->mir()->input()->mightBeType(MIRType::Undefined)) { Label notUndefined; masm.branchTestUndefined(Assembler::NotEqual, tag, ¬Undefined); masm.movePtr(ImmGCPtr(names.undefined), output); @@ -941,7 +941,7 @@ CodeGenerator::visitValueToString(LValueToString* lir) } // Null - if (lir->mir()->input()->mightBeType(MIRType_Null)) { + if (lir->mir()->input()->mightBeType(MIRType::Null)) { Label notNull; masm.branchTestNull(Assembler::NotEqual, tag, ¬Null); masm.movePtr(ImmGCPtr(names.null), output); @@ -950,7 +950,7 @@ CodeGenerator::visitValueToString(LValueToString* lir) } // Boolean - if (lir->mir()->input()->mightBeType(MIRType_Boolean)) { + if (lir->mir()->input()->mightBeType(MIRType::Boolean)) { Label notBoolean, true_; masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean); masm.branchTestBooleanTruthy(true, input, &true_); @@ -963,7 +963,7 @@ CodeGenerator::visitValueToString(LValueToString* lir) } // Object - if (lir->mir()->input()->mightBeType(MIRType_Object)) { + if (lir->mir()->input()->mightBeType(MIRType::Object)) { // Bail. MOZ_ASSERT(lir->mir()->fallible()); Label bail; @@ -972,7 +972,7 @@ CodeGenerator::visitValueToString(LValueToString* lir) } // Symbol - if (lir->mir()->input()->mightBeType(MIRType_Symbol)) + if (lir->mir()->input()->mightBeType(MIRType::Symbol)) masm.branchTestSymbol(Assembler::Equal, tag, ool->entry()); #ifdef DEBUG @@ -1218,9 +1218,9 @@ PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Re Address lazySourceAddress(temp1, RegExpStatics::offsetOfLazySource()); Address lazyIndexAddress(temp1, RegExpStatics::offsetOfLazyIndex()); - masm.patchableCallPreBarrier(pendingInputAddress, MIRType_String); - masm.patchableCallPreBarrier(matchesInputAddress, MIRType_String); - masm.patchableCallPreBarrier(lazySourceAddress, MIRType_String); + masm.patchableCallPreBarrier(pendingInputAddress, MIRType::String); + masm.patchableCallPreBarrier(matchesInputAddress, MIRType::String); + masm.patchableCallPreBarrier(lazySourceAddress, MIRType::String); masm.storePtr(input, pendingInputAddress); masm.storePtr(input, matchesInputAddress); @@ -2213,6 +2213,63 @@ CodeGenerator::visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOp masm.jump(ool->rejoin()); } +static void +FindFirstDollarIndex(MacroAssembler& masm, Register str, Register len, Register chars, + Register temp, Register output, bool isLatin1) +{ + masm.loadStringChars(str, chars); + + masm.move32(Imm32(0), output); + + Label start, done; + masm.bind(&start); + if (isLatin1) + masm.load8ZeroExtend(BaseIndex(chars, output, TimesOne), temp); + else + masm.load16ZeroExtend(BaseIndex(chars, output, TimesTwo), temp); + + masm.branch32(Assembler::Equal, temp, Imm32('$'), &done); + + masm.add32(Imm32(1), output); + masm.branch32(Assembler::NotEqual, output, len, &start); + + masm.move32(Imm32(-1), output); + + masm.bind(&done); +} + +typedef bool (*GetFirstDollarIndexRawFn)(JSContext*, HandleString, int32_t*); +static const VMFunction GetFirstDollarIndexRawInfo = FunctionInfo(GetFirstDollarIndexRaw); + +void +CodeGenerator::visitGetFirstDollarIndex(LGetFirstDollarIndex* ins) +{ + Register str = ToRegister(ins->str()); + Register output = ToRegister(ins->output()); + Register temp0 = ToRegister(ins->temp0()); + Register temp1 = ToRegister(ins->temp1()); + Register len = ToRegister(ins->temp2()); + + OutOfLineCode* ool = oolCallVM(GetFirstDollarIndexRawInfo, ins, ArgList(str), + StoreRegisterTo(output)); + + masm.branchIfRope(str, ool->entry()); + masm.loadStringLength(str, len); + + Label isLatin1, done; + masm.branchLatin1String(str, &isLatin1); + { + FindFirstDollarIndex(masm, str, len, temp0, temp1, output, /* isLatin1 = */ false); + } + masm.jump(&done); + { + masm.bind(&isLatin1); + FindFirstDollarIndex(masm, str, len, temp0, temp1, output, /* isLatin1 = */ true); + } + masm.bind(&done); + masm.bind(ool->rejoin()); +} + typedef JSString* (*StringReplaceFn)(JSContext*, HandleString, HandleString, HandleString); static const VMFunction StringFlatReplaceInfo = FunctionInfo(js::str_flat_replace_string); static const VMFunction StringReplaceInfo = FunctionInfo(StringReplace); @@ -2612,7 +2669,7 @@ CodeGenerator::visitTableSwitch(LTableSwitch* ins) Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label(); const LAllocation* temp; - if (mir->getOperand(0)->type() != MIRType_Int32) { + if (mir->getOperand(0)->type() != MIRType::Int32) { temp = ins->tempInt()->output(); // The input is a double, so try and convert it to an integer. @@ -2952,7 +3009,7 @@ CodeGenerator::visitStoreSlotT(LStoreSlotT* lir) MIRType valueType = lir->mir()->value()->type(); - if (valueType == MIRType_ObjectOrNull) { + if (valueType == MIRType::ObjectOrNull) { masm.storeObjectOrNull(ToRegister(lir->value()), dest); } else { ConstantOrRegister value; @@ -3060,7 +3117,7 @@ CodeGenerator::visitGetPropertyPolymorphicT(LGetPropertyPolymorphicT* ins) { Register obj = ToRegister(ins->obj()); TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output())); - Register temp = (output.type() == MIRType_Double) + Register temp = (output.type() == MIRType::Double) ? ToRegister(ins->temp()) : output.typedReg().gpr(); emitGetPropertyPolymorphic(ins, obj, temp, output); @@ -3071,9 +3128,9 @@ static void EmitUnboxedPreBarrier(MacroAssembler &masm, T address, JSValueType type) { if (type == JSVAL_TYPE_OBJECT) - masm.patchableCallPreBarrier(address, MIRType_Object); + masm.patchableCallPreBarrier(address, MIRType::Object); else if (type == JSVAL_TYPE_STRING) - masm.patchableCallPreBarrier(address, MIRType_String); + masm.patchableCallPreBarrier(address, MIRType::String); else MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type)); } @@ -3319,11 +3376,11 @@ CodeGenerator::visitTypeBarrierO(LTypeBarrierO* lir) Register scratch = ToTempRegisterOrInvalid(lir->temp()); Label miss, ok; - if (lir->mir()->type() == MIRType_ObjectOrNull) { - Label* nullTarget = lir->mir()->resultTypeSet()->mightBeMIRType(MIRType_Null) ? &ok : &miss; + if (lir->mir()->type() == MIRType::ObjectOrNull) { + Label* nullTarget = lir->mir()->resultTypeSet()->mightBeMIRType(MIRType::Null) ? &ok : &miss; masm.branchTestPtr(Assembler::Zero, obj, obj, nullTarget); } else { - MOZ_ASSERT(lir->mir()->type() == MIRType_Object); + MOZ_ASSERT(lir->mir()->type() == MIRType::Object); MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly); } @@ -4708,8 +4765,8 @@ CodeGenerator::branchIfInvalidated(Register temp, Label* invalidated) void CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset) { - MOZ_ASSERT(type == MIRType_Object || type == MIRType_ObjectOrNull || - type == MIRType_String || type == MIRType_Symbol); + MOZ_ASSERT(type == MIRType::Object || type == MIRType::ObjectOrNull || + type == MIRType::String || type == MIRType::Symbol); AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); regs.take(input); @@ -4722,12 +4779,12 @@ CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, cons Label done; branchIfInvalidated(temp, &done); - if ((type == MIRType_Object || type == MIRType_ObjectOrNull) && + if ((type == MIRType::Object || type == MIRType::ObjectOrNull) && typeset && !typeset->unknownObject()) { // We have a result TypeSet, assert this object is in it. Label miss, ok; - if (type == MIRType_ObjectOrNull) + if (type == MIRType::ObjectOrNull) masm.branchPtr(Assembler::Equal, input, ImmWord(0), &ok); if (typeset->getObjectCount() > 0) masm.guardObjectType(input, typeset, temp, &miss); @@ -4752,16 +4809,16 @@ CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, cons void* callee; switch (type) { - case MIRType_Object: + case MIRType::Object: callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidObjectPtr); break; - case MIRType_ObjectOrNull: + case MIRType::ObjectOrNull: callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidObjectOrNullPtr); break; - case MIRType_String: + case MIRType::String: callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidStringPtr); break; - case MIRType_Symbol: + case MIRType::Symbol: callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidSymbolPtr); break; default: @@ -4869,13 +4926,13 @@ CodeGenerator::emitDebugResultChecks(LInstruction* ins) return; switch (mir->type()) { - case MIRType_Object: - case MIRType_ObjectOrNull: - case MIRType_String: - case MIRType_Symbol: + case MIRType::Object: + case MIRType::ObjectOrNull: + case MIRType::String: + case MIRType::Symbol: emitObjectOrStringResultChecks(ins, mir); break; - case MIRType_Value: + case MIRType::Value: emitValueResultChecks(ins, mir); break; default: @@ -5451,11 +5508,11 @@ CodeGenerator::visitSimdBox(LSimdBox* lir) Address objectData(object, InlineTypedObject::offsetOfDataStart()); switch (type) { - case MIRType_Bool32x4: - case MIRType_Int32x4: + case MIRType::Bool32x4: + case MIRType::Int32x4: masm.storeUnalignedInt32x4(in, objectData); break; - case MIRType_Float32x4: + case MIRType::Float32x4: masm.storeUnalignedFloat32x4(in, objectData); break; default: @@ -5529,11 +5586,11 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox* lir) // Load the value from the data of the InlineTypedObject. Address objectData(object, InlineTypedObject::offsetOfDataStart()); switch (lir->mir()->type()) { - case MIRType_Bool32x4: - case MIRType_Int32x4: + case MIRType::Bool32x4: + case MIRType::Int32x4: masm.loadUnalignedInt32x4(objectData, simd); break; - case MIRType_Float32x4: + case MIRType::Float32x4: masm.loadUnalignedFloat32x4(objectData, simd); break; default: @@ -6029,8 +6086,8 @@ CodeGenerator::visitGetNextMapEntryForIterator(LGetNextMapEntryForIterator* lir) Address valueAddress(front, ValueMap::Entry::offsetOfValue()); Address keyElemAddress(result, elementsOffset); Address valueElemAddress(result, elementsOffset + sizeof(Value)); - masm.patchableCallPreBarrier(keyElemAddress, MIRType_Value); - masm.patchableCallPreBarrier(valueElemAddress, MIRType_Value); + masm.patchableCallPreBarrier(keyElemAddress, MIRType::Value); + masm.patchableCallPreBarrier(valueElemAddress, MIRType::Value); masm.storeValue(keyAddress, keyElemAddress, temp); masm.storeValue(valueAddress, valueElemAddress, temp); @@ -6564,7 +6621,7 @@ CodeGenerator::visitIsNullOrLikeUndefinedV(LIsNullOrLikeUndefinedV* lir) Register output = ToRegister(lir->output()); if (op == JSOP_EQ || op == JSOP_NE) { - MOZ_ASSERT(lir->mir()->lhs()->type() != MIRType_Object || + MOZ_ASSERT(lir->mir()->lhs()->type() != MIRType::Object || lir->mir()->operandMightEmulateUndefined(), "Operands which can't emulate undefined should have been folded"); @@ -6586,9 +6643,9 @@ CodeGenerator::visitIsNullOrLikeUndefinedV(LIsNullOrLikeUndefinedV* lir) Register tag = masm.splitTagForTest(value); MDefinition* input = lir->mir()->lhs(); - if (input->mightBeType(MIRType_Null)) + if (input->mightBeType(MIRType::Null)) masm.branchTestNull(Assembler::Equal, tag, nullOrLikeUndefined); - if (input->mightBeType(MIRType_Undefined)) + if (input->mightBeType(MIRType::Undefined)) masm.branchTestUndefined(Assembler::Equal, tag, nullOrLikeUndefined); if (ool) { @@ -6650,7 +6707,7 @@ CodeGenerator::visitIsNullOrLikeUndefinedAndBranchV(LIsNullOrLikeUndefinedAndBra op = JSOP_EQ; } - MOZ_ASSERT(lir->cmpMir()->lhs()->type() != MIRType_Object || + MOZ_ASSERT(lir->cmpMir()->lhs()->type() != MIRType::Object || lir->cmpMir()->operandMightEmulateUndefined(), "Operands which can't emulate undefined should have been folded"); @@ -6666,9 +6723,9 @@ CodeGenerator::visitIsNullOrLikeUndefinedAndBranchV(LIsNullOrLikeUndefinedAndBra Label* ifFalseLabel = getJumpLabelForBranch(ifFalse); MDefinition* input = lir->cmpMir()->lhs(); - if (input->mightBeType(MIRType_Null)) + if (input->mightBeType(MIRType::Null)) masm.branchTestNull(Assembler::Equal, tag, ifTrueLabel); - if (input->mightBeType(MIRType_Undefined)) + if (input->mightBeType(MIRType::Undefined)) masm.branchTestUndefined(Assembler::Equal, tag, ifTrueLabel); if (ool) { @@ -6700,13 +6757,13 @@ CodeGenerator::visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT * lir) lir->mir()->compareType() == MCompare::Compare_Null); MIRType lhsType = lir->mir()->lhs()->type(); - MOZ_ASSERT(lhsType == MIRType_Object || lhsType == MIRType_ObjectOrNull); + MOZ_ASSERT(lhsType == MIRType::Object || lhsType == MIRType::ObjectOrNull); JSOp op = lir->mir()->jsop(); - MOZ_ASSERT(lhsType == MIRType_ObjectOrNull || op == JSOP_EQ || op == JSOP_NE, + MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || op == JSOP_EQ || op == JSOP_NE, "Strict equality should have been folded"); - MOZ_ASSERT(lhsType == MIRType_ObjectOrNull || lir->mir()->operandMightEmulateUndefined(), + MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || lir->mir()->operandMightEmulateUndefined(), "If the object couldn't emulate undefined, this should have been folded."); Register objreg = ToRegister(lir->input()); @@ -6719,7 +6776,7 @@ CodeGenerator::visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT * lir) Label* emulatesUndefined = ool->label1(); Label* doesntEmulateUndefined = ool->label2(); - if (lhsType == MIRType_ObjectOrNull) + if (lhsType == MIRType::ObjectOrNull) masm.branchTestPtr(Assembler::Zero, objreg, objreg, emulatesUndefined); branchTestObjectEmulatesUndefined(objreg, emulatesUndefined, doesntEmulateUndefined, @@ -6734,7 +6791,7 @@ CodeGenerator::visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT * lir) masm.move32(Imm32(op == JSOP_EQ), output); masm.bind(&done); } else { - MOZ_ASSERT(lhsType == MIRType_ObjectOrNull); + MOZ_ASSERT(lhsType == MIRType::ObjectOrNull); Label isNull, done; @@ -6758,13 +6815,13 @@ CodeGenerator::visitIsNullOrLikeUndefinedAndBranchT(LIsNullOrLikeUndefinedAndBra compareType == MCompare::Compare_Null); MIRType lhsType = lir->cmpMir()->lhs()->type(); - MOZ_ASSERT(lhsType == MIRType_Object || lhsType == MIRType_ObjectOrNull); + MOZ_ASSERT(lhsType == MIRType::Object || lhsType == MIRType::ObjectOrNull); JSOp op = lir->cmpMir()->jsop(); - MOZ_ASSERT(lhsType == MIRType_ObjectOrNull || op == JSOP_EQ || op == JSOP_NE, + MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || op == JSOP_EQ || op == JSOP_NE, "Strict equality should have been folded"); - MOZ_ASSERT(lhsType == MIRType_ObjectOrNull || lir->cmpMir()->operandMightEmulateUndefined(), + MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || lir->cmpMir()->operandMightEmulateUndefined(), "If the object couldn't emulate undefined, this should have been folded."); MBasicBlock* ifTrue; @@ -6788,14 +6845,14 @@ CodeGenerator::visitIsNullOrLikeUndefinedAndBranchT(LIsNullOrLikeUndefinedAndBra Label* ifTrueLabel = getJumpLabelForBranch(ifTrue); Label* ifFalseLabel = getJumpLabelForBranch(ifFalse); - if (lhsType == MIRType_ObjectOrNull) + if (lhsType == MIRType::ObjectOrNull) masm.branchTestPtr(Assembler::Zero, input, input, ifTrueLabel); // Objects that emulate undefined are loosely equal to null/undefined. Register scratch = ToRegister(lir->temp()); testObjectEmulatesUndefined(input, ifTrueLabel, ifFalseLabel, scratch, ool); } else { - MOZ_ASSERT(lhsType == MIRType_ObjectOrNull); + MOZ_ASSERT(lhsType == MIRType::ObjectOrNull); testZeroEmitBranch(Assembler::Equal, input, ifTrue, ifFalse); } } @@ -7497,7 +7554,7 @@ CodeGenerator::visitNotV(LNotV* lir) // out our operand after we did cacheOperandMightEmulateUndefined. So we // might think it can emulate undefined _and_ know that it can't be an // object. - if (lir->mir()->operandMightEmulateUndefined() && operand->mightBeType(MIRType_Object)) { + if (lir->mir()->operandMightEmulateUndefined() && operand->mightBeType(MIRType::Object)) { ool = new(alloc()) OutOfLineTestObjectWithLabels(); addOutOfLineCode(ool, lir->mir()); ifTruthy = ool->label1(); @@ -7935,11 +7992,11 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) masm.bind(&dontUpdate); } - if (ins->isStoreElementHoleT() && unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType_Double) { + if (ins->isStoreElementHoleT() && unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double) { // The inline path for StoreElementHoleT does not always store the type tag, - // so we do the store on the OOL path. We use MIRType_None for the element type + // so we do the store on the OOL path. We use MIRType::None for the element type // so that storeElementTyped will always store the type tag. - emitStoreElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType_None, + emitStoreElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType::None, elements, index, 0); masm.jump(ool->rejoin()); } else { @@ -7990,11 +8047,11 @@ CodeGenerator::visitStoreUnboxedPointer(LStoreUnboxedPointer* lir) int32_t offsetAdjustment; bool preBarrier; if (lir->mir()->isStoreUnboxedObjectOrNull()) { - type = MIRType_Object; + type = MIRType::Object; offsetAdjustment = lir->mir()->toStoreUnboxedObjectOrNull()->offsetAdjustment(); preBarrier = lir->mir()->toStoreUnboxedObjectOrNull()->preBarrier(); } else if (lir->mir()->isStoreUnboxedString()) { - type = MIRType_String; + type = MIRType::String; offsetAdjustment = lir->mir()->toStoreUnboxedString()->offsetAdjustment(); preBarrier = lir->mir()->toStoreUnboxedString()->preBarrier(); } else { @@ -8578,7 +8635,7 @@ CodeGenerator::visitSetFrameArgumentT(LSetFrameArgumentT* lir) MIRType type = lir->mir()->value()->type(); - if (type == MIRType_Double) { + if (type == MIRType::Double) { // Store doubles directly. FloatRegister input = ToFloatRegister(lir->input()); masm.storeDouble(input, Address(masm.getStackPointer(), argOffset)); @@ -9212,7 +9269,7 @@ CodeGenerator::visitUnboxFloatingPoint(LUnboxFloatingPoint* lir) FloatRegister resultReg = ToFloatRegister(result); masm.branchTestDouble(Assembler::NotEqual, box, ool->entry()); masm.unboxDouble(box, resultReg); - if (lir->type() == MIRType_Float32) + if (lir->type() == MIRType::Float32) masm.convertDoubleToFloat32(resultReg, resultReg); masm.bind(ool->rejoin()); } @@ -9333,7 +9390,7 @@ CodeGenerator::visitLoadFixedSlotAndUnbox(LLoadFixedSlotAndUnbox* ins) Address address(input, NativeObject::getFixedSlotOffset(slot)); Label bail; - if (type == MIRType_Double) { + if (type == MIRType::Double) { MOZ_ASSERT(result.isFloat()); masm.ensureDouble(address, result.fpu(), &bail); if (mir->fallible()) @@ -9342,10 +9399,10 @@ CodeGenerator::visitLoadFixedSlotAndUnbox(LLoadFixedSlotAndUnbox* ins) } if (mir->fallible()) { switch (type) { - case MIRType_Int32: + case MIRType::Int32: masm.branchTestInt32(Assembler::NotEqual, address, &bail); break; - case MIRType_Boolean: + case MIRType::Boolean: masm.branchTestBoolean(Assembler::NotEqual, address, &bail); break; default: @@ -9384,7 +9441,7 @@ CodeGenerator::visitStoreFixedSlotT(LStoreFixedSlotT* ins) if (ins->mir()->needsBarrier()) emitPreBarrier(address); - if (valueType == MIRType_ObjectOrNull) { + if (valueType == MIRType::ObjectOrNull) { Register nvalue = ToRegister(value); masm.storeObjectOrNull(nvalue, address); } else { @@ -9454,7 +9511,7 @@ CodeGenerator::addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, ConstantOrRegister CodeGenerator::toConstantOrRegister(LInstruction* lir, size_t n, MIRType type) { - if (type == MIRType_Value) + if (type == MIRType::Value) return TypedOrValueRegister(ToValue(lir, n)); const LAllocation* value = lir->getOperand(n); @@ -9732,13 +9789,13 @@ CodeGenerator::visitTypeOfV(LTypeOfV* lir) MDefinition* input = lir->mir()->input(); - bool testObject = input->mightBeType(MIRType_Object); - bool testNumber = input->mightBeType(MIRType_Int32) || input->mightBeType(MIRType_Double); - bool testBoolean = input->mightBeType(MIRType_Boolean); - bool testUndefined = input->mightBeType(MIRType_Undefined); - bool testNull = input->mightBeType(MIRType_Null); - bool testString = input->mightBeType(MIRType_String); - bool testSymbol = input->mightBeType(MIRType_Symbol); + bool testObject = input->mightBeType(MIRType::Object); + bool testNumber = input->mightBeType(MIRType::Int32) || input->mightBeType(MIRType::Double); + bool testBoolean = input->mightBeType(MIRType::Boolean); + bool testUndefined = input->mightBeType(MIRType::Undefined); + bool testNull = input->mightBeType(MIRType::Null); + bool testString = input->mightBeType(MIRType::String); + bool testSymbol = input->mightBeType(MIRType::Symbol); unsigned numTests = unsigned(testObject) + unsigned(testNumber) + unsigned(testBoolean) + unsigned(testUndefined) + unsigned(testNull) + unsigned(testString) + unsigned(testSymbol); @@ -10308,7 +10365,7 @@ CodeGenerator::visitClampVToUint8(LClampVToUint8* lir) Label* stringEntry; Label* stringRejoin; - if (input->mightBeType(MIRType_String)) { + if (input->mightBeType(MIRType::String)) { OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, ArgList(output), StoreFloatRegisterTo(tempFloat)); stringEntry = oolString->entry(); @@ -11381,5 +11438,28 @@ CodeGenerator::visitRandom(LRandom* ins) masm.mulDoublePtr(ImmPtr(&ScaleInv), tempReg, output); } +void +CodeGenerator::visitRotate(LRotate* ins) +{ + MRotate* mir = ins->mir(); + Register input = ToRegister(ins->input()); + Register dest = ToRegister(ins->output()); + + const LAllocation* count = ins->count(); + if (count->isConstant()) { + int32_t c = ToInt32(count) & 0x1F; + if (mir->isLeftRotate()) + masm.rotateLeft(Imm32(c), input, dest); + else + masm.rotateRight(Imm32(c), input, dest); + } else { + Register creg = ToRegister(count); + if (mir->isLeftRotate()) + masm.rotateLeft(creg, input, dest); + else + masm.rotateRight(creg, input, dest); + } +} + } // namespace jit } // namespace js diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 89ea417822..cab12e3f49 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -122,6 +122,7 @@ class CodeGenerator : public CodeGeneratorSpecific void visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool); void visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* lir); void visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool); + void visitGetFirstDollarIndex(LGetFirstDollarIndex* lir); void visitStringReplace(LStringReplace* lir); void emitSharedStub(ICStub::Kind kind, LInstruction* lir); void visitBinarySharedStub(LBinarySharedStub* lir); @@ -411,6 +412,7 @@ class CodeGenerator : public CodeGeneratorSpecific void visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir); void visitAsmThrowUnreachable(LAsmThrowUnreachable* lir); void visitRecompileCheck(LRecompileCheck* ins); + void visitRotate(LRotate* ins); void visitRandom(LRandom* ins); diff --git a/js/src/jit/EagerSimdUnbox.cpp b/js/src/jit/EagerSimdUnbox.cpp index 7f33994f48..0b93d145d6 100644 --- a/js/src/jit/EagerSimdUnbox.cpp +++ b/js/src/jit/EagerSimdUnbox.cpp @@ -18,7 +18,7 @@ namespace jit { static bool CanUnboxSimdPhi(const JitCompartment* jitCompartment, MPhi* phi, SimdType unboxType) { - MOZ_ASSERT(phi->type() == MIRType_Object); + MOZ_ASSERT(phi->type() == MIRType::Object); // If we are unboxing, we are more than likely to have boxed this SIMD type // once in baseline, otherwise, we cannot create a MSimdBox as we have no diff --git a/js/src/jit/EffectiveAddressAnalysis.cpp b/js/src/jit/EffectiveAddressAnalysis.cpp index a0a50eb376..3f0bec0562 100644 --- a/js/src/jit/EffectiveAddressAnalysis.cpp +++ b/js/src/jit/EffectiveAddressAnalysis.cpp @@ -14,20 +14,20 @@ using namespace jit; static void AnalyzeLsh(TempAllocator& alloc, MLsh* lsh) { - if (lsh->specialization() != MIRType_Int32) + if (lsh->specialization() != MIRType::Int32) return; if (lsh->isRecoveredOnBailout()) return; MDefinition* index = lsh->lhs(); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); MConstant* shiftValue = lsh->rhs()->maybeConstantValue(); if (!shiftValue) return; - if (shiftValue->type() != MIRType_Int32 || !IsShiftInScaleRange(shiftValue->toInt32())) + if (shiftValue->type() != MIRType::Int32 || !IsShiftInScaleRange(shiftValue->toInt32())) return; Scale scale = ShiftToScale(shiftValue->toInt32()); @@ -44,7 +44,7 @@ AnalyzeLsh(TempAllocator& alloc, MLsh* lsh) break; MAdd* add = use->consumer()->toDefinition()->toAdd(); - if (add->specialization() != MIRType_Int32 || !add->isTruncated()) + if (add->specialization() != MIRType::Int32 || !add->isTruncated()) break; MDefinition* other = add->getOperand(1 - add->indexOf(*use)); @@ -80,7 +80,7 @@ AnalyzeLsh(TempAllocator& alloc, MLsh* lsh) MDefinition* other = bitAnd->getOperand(1 - bitAnd->indexOf(*use)); MConstant* otherConst = other->maybeConstantValue(); - if (!otherConst || otherConst->type() != MIRType_Int32) + if (!otherConst || otherConst->type() != MIRType::Int32) return; uint32_t bitsClearedByShift = elemSize - 1; diff --git a/js/src/jit/ExecutableAllocator.h b/js/src/jit/ExecutableAllocator.h index 8d64d4314a..ba7cce1387 100644 --- a/js/src/jit/ExecutableAllocator.h +++ b/js/src/jit/ExecutableAllocator.h @@ -204,7 +204,7 @@ class ExecutableAllocator static void reprotectPool(JSRuntime* rt, ExecutablePool* pool, ProtectionSetting protection); public: - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static bool makeWritable(void* start, size_t size) { #ifdef NON_WRITABLE_JIT_CODE @@ -214,7 +214,7 @@ class ExecutableAllocator #endif } - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static bool makeExecutable(void* start, size_t size) { #ifdef NON_WRITABLE_JIT_CODE @@ -308,7 +308,7 @@ class ExecutableAllocator void operator=(const ExecutableAllocator&) = delete; #ifdef NON_WRITABLE_JIT_CODE - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static bool reprotectRegion(void*, size_t, ProtectionSetting); #endif diff --git a/js/src/jit/FixedList.h b/js/src/jit/FixedList.h index 04658c7191..dcf26ab00a 100644 --- a/js/src/jit/FixedList.h +++ b/js/src/jit/FixedList.h @@ -32,7 +32,7 @@ class FixedList { } // Dynamic memory allocation requires the ability to report failure. - MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc, size_t length) { + MOZ_MUST_USE bool init(TempAllocator& alloc, size_t length) { length_ = length; if (length == 0) return true; @@ -57,7 +57,7 @@ class FixedList length_ -= num; } - MOZ_WARN_UNUSED_RESULT bool growBy(TempAllocator& alloc, size_t num) { + MOZ_MUST_USE bool growBy(TempAllocator& alloc, size_t num) { size_t newlength = length_ + num; if (newlength < length_) return false; diff --git a/js/src/jit/FlowAliasAnalysis.cpp b/js/src/jit/FlowAliasAnalysis.cpp new file mode 100644 index 0000000000..107f7bd0cb --- /dev/null +++ b/js/src/jit/FlowAliasAnalysis.cpp @@ -0,0 +1,942 @@ +/* -*- 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 "jit/FlowAliasAnalysis.h" + +#include + +#include "jit/AliasAnalysisShared.h" +#include "jit/Ion.h" +#include "jit/IonBuilder.h" +#include "jit/JitSpewer.h" +#include "jit/MIR.h" +#include "jit/MIRGraph.h" + +#include "vm/Printer.h" + +using namespace js; +using namespace js::jit; + +using mozilla::Array; + +namespace js { +namespace jit { + +class LoopInfo : public TempObject +{ + private: + LoopInfo* outer_; + MBasicBlock* loopHeader_; + MDefinitionVector loopinvariant_; + + public: + LoopInfo(TempAllocator& alloc, LoopInfo* outer, MBasicBlock* loopHeader) + : outer_(outer), loopHeader_(loopHeader), loopinvariant_(alloc) + { } + + MBasicBlock* loopHeader() const { + return loopHeader_; + } + LoopInfo* outer() const { + return outer_; + } + MDefinitionVector& loopinvariant() { + return loopinvariant_; + } +}; + +static bool +KeepBlock(MBasicBlock *block) +{ + // Any block that is predecessor to a loopheader need to be kept. + // We need it to process possible loop invariant loads. + if (block->numSuccessors() == 1 && block->getSuccessor(0)->isLoopHeader()) + return true; + +#ifdef DEBUG + // We assume a predecessor to a loopheader has one successor. + for (size_t i = 0; i < block->numSuccessors(); i++) + MOZ_ASSERT(!block->getSuccessor(i)->isLoopHeader()); +#endif + + return false; +} + +class GraphStoreInfo : public TempObject +{ + // The current BlockStoreInfo while iterating the block untill, + // it contains the store info at the end of the block. + BlockStoreInfo* current_; + + // Vector with pointer to BlockStoreInfo at the end of the block for every block. + // Only keeping the info during iteration if needed, else contains nullptr. + GraphStoreVector stores_; + + // All BlockStoreInfo's that aren't needed anymore and can be reused. + GraphStoreVector empty_; + + public: + explicit GraphStoreInfo(TempAllocator& alloc) + : stores_(alloc), + empty_(alloc) + { } + + bool reserve(size_t num) { + return stores_.appendN(nullptr, num); + } + + BlockStoreInfo& current() { + return *current_; + } + + void unsetCurrent() { + current_ = nullptr; + } + + BlockStoreInfo* newCurrent(TempAllocator& alloc, MBasicBlock* block) { + BlockStoreInfo *info = nullptr; + if (empty_.length() != 0) { + info = empty_.popCopy(); + } else { + info = (BlockStoreInfo*) alloc.allocate(sizeof(BlockStoreInfo)); + if (!info) + return nullptr; + new(info) BlockStoreInfo(alloc); + } + + stores_[block->id()] = info; + current_ = info; + return current_; + } + + void swap(MBasicBlock* block1, MBasicBlock* block2) { + BlockStoreInfo* info = stores_[block1->id()]; + stores_[block1->id()] = stores_[block2->id()]; + stores_[block2->id()] = info; + if (stores_[block1->id()] == current_) + current_ = stores_[block2->id()]; + else if (stores_[block2->id()] == current_) + current_ = stores_[block1->id()]; + } + + bool maybeFreePredecessorBlocks(MBasicBlock* block) { + for (size_t i=0; i < block->numPredecessors(); i++) { + + // For some blocks we cannot free the store info. + if (KeepBlock(block->getPredecessor(i))) + continue; + + // Check the given block is the last successor. + bool release = true; + for (size_t j = 0; j < block->getPredecessor(i)->numSuccessors(); j++) { + if (block->getPredecessor(i)->getSuccessor(j)->id() > block->id()) { + release = false; + break; + } + } + if (release) { + BlockStoreInfo *info = stores_[block->getPredecessor(i)->id()]; + if (!empty_.append(info)) + return false; + info->clear(); + + stores_[block->getPredecessor(i)->id()] = nullptr; + } + } + return true; + } + + BlockStoreInfo& get(MBasicBlock* block) { + MOZ_ASSERT(stores_[block->id()] != current_); + return *stores_[block->id()]; + } +}; + +} // namespace jit +} // namespace js + + +FlowAliasAnalysis::FlowAliasAnalysis(MIRGenerator* mir, MIRGraph& graph) + : AliasAnalysisShared(mir, graph), + loop_(nullptr), + output_(graph_.alloc()), + worklist_(graph_.alloc()) +{ + stores_ = new(graph_.alloc()) GraphStoreInfo(graph_.alloc()); +} + +template +static bool +AppendToWorklist(MDefinitionVector& worklist, T& stores) +{ + if (!worklist.reserve(worklist.length() + stores.length())) + return false; + + for (size_t j = 0; j < stores.length(); j++) { + MOZ_ASSERT(stores[j]); + if (stores[j]->isInWorklist()) + continue; + + worklist.infallibleAppend(stores[j]); + stores[j]->setInWorklist(); + } + return true; +} + +static void +SetNotInWorkList(MDefinitionVector& worklist) +{ + for (size_t item = 0; item < worklist.length(); item++) + worklist[item]->setNotInWorklistUnchecked(); +} + +static bool +LoadAliasesStore(MDefinition* load, MDefinition* store) +{ + // Always alias first instruction of graph. + if (store->id() == 0) + return true; + + // Default to alias control instructions which indicates loops. + // Control instructions are special, since we need to determine + // if it aliases anything in the full loop. Which we do lateron. + if (store->isControlInstruction()) + return true; + + // Check if the alias categories alias eachother. + if (!(load->getAliasSet() & store->getAliasSet()).isNone()) + return true; + + // Check if the instruction might alias eachother. + MDefinition::AliasType type = load->mightAlias(store); + if (type != MDefinition::AliasType::NoAlias) + return true; + + return false; +} + +#ifdef JS_JITSPEW +static void +DumpAliasSet(AliasSet set) +{ + Fprinter &print = JitSpewPrinter(); + + if (set.flags() == AliasSet::Any) { + print.printf("Any"); + return; + } + + bool first = true; + for (AliasSetIterator iter(set); iter; iter++) { + if (!first) + print.printf(", "); + print.printf("%s", AliasSet::Name(*iter)); + first = false; + } +} +#endif + +#ifdef JS_JITSPEW +static void +DumpStoreList(BlockStoreInfo& stores) +{ + Fprinter &print = JitSpewPrinter(); + if (stores.length() == 0) { + print.printf("empty"); + return; + } + bool first = true; + for (size_t i = 0; i < stores.length(); i++) { + if (!first) + print.printf(", "); + if (!stores[i]) { + print.printf("nullptr"); + continue; + } + MOZ_ASSERT(stores[i]->isControlInstruction() || + stores[i]->getAliasSet().isStore() || + stores[i]->id() == 0); + MDefinition::PrintOpcodeName(print, stores[i]->op()); + print.printf("%d", stores[i]->id()); + first = false; + } +} +#endif + +static void +DumpAnalyzeStart() +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_Alias) || JitSpewEnabled(JitSpew_AliasSummaries)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpewEnabled(JitSpew_Alias) ? JitSpew_Alias : JitSpew_AliasSummaries); + print.printf("Running Alias Analysis on graph\n"); + } +#endif +} + +static void +DumpBlockStart(MBasicBlock* block) +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_Alias) || JitSpewEnabled(JitSpew_AliasSummaries)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpewEnabled(JitSpew_Alias)?JitSpew_Alias:JitSpew_AliasSummaries); + if (block->isLoopHeader()) + print.printf(" Visiting block %d (loopheader)\n", block->id()); + else + print.printf(" Visiting block %d\n", block->id()); + } +#endif +} + +static void +DumpProcessingDeferredLoads(MBasicBlock* loopHeader) +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_Alias)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpew_Alias); + print.printf(" Process deferred loads of loop %d\n", loopHeader->id()); + } +#endif +} + +static void +DumpBlockSummary(MBasicBlock* block, BlockStoreInfo& blockInfo) +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_AliasSummaries)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpew_AliasSummaries); + print.printf(" Store at end of block: "); + DumpStoreList(blockInfo); + print.printf("\n"); + } +#endif +} + +static void +DumpStore(MDefinition* store) +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_Alias)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpew_Alias); + print.printf(" Store "); + store->PrintOpcodeName(print, store->op()); + print.printf("%d with flags (", store->id()); + DumpAliasSet(store->getAliasSet()); + print.printf(")\n"); + } +#endif +} + +static void +DumpLoad(MDefinition* load) +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_Alias)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpew_Alias); + print.printf(" Load "); + load->PrintOpcodeName(print, load->op()); + print.printf("%d", load->id()); + print.printf(" with flag ("); + DumpAliasSet(load->getAliasSet()); + print.printf(")\n"); + } +#endif +} + +static void +DumpLoadOutcome(MDefinition* load, MDefinitionVector& stores, bool defer) +{ +#ifdef JS_JITSPEW + // Spew what we did. + if (JitSpewEnabled(JitSpew_Alias)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpew_Alias); + print.printf(" Marked depending on "); + DumpStoreList(stores); + if (defer) + print.printf(" deferred"); + print.printf("\n"); + } +#endif +} + +static void +DumpLoopInvariant(MDefinition* load, MBasicBlock* loopheader, bool loopinvariant, + MDefinitionVector& loopInvariantDependency) +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_Alias)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpew_Alias); + if (!loopinvariant) { + print.printf(" Determine not loop invariant to loop %d.\n", loopheader->id()); + } else { + print.printf(" Determine loop invariant to loop %d. Dependendy is now: ", loopheader->id()); + DumpStoreList(loopInvariantDependency); + print.printf("\n"); + } + } +#endif +} + +static void +DumpImprovement(MDefinition *load, MDefinitionVector& input, MDefinitionVector& output) +{ +#ifdef JS_JITSPEW + if (JitSpewEnabled(JitSpew_Alias)) { + Fprinter &print = JitSpewPrinter(); + JitSpewHeader(JitSpew_Alias); + print.printf(" Improve dependency from ", load->id()); + DumpStoreList(input); + print.printf(" to "); + DumpStoreList(output); + print.printf("\n"); + } +#endif +} + +// Flow Sensitive Alias Analysis. +// +// This pass annotates every load instructions with the last store instruction +// on which it depends in their dependency_ field. For loop variant instructions +// this will depend on the control instruction in the specific loop it cannot +// get hoisted out (if there is no store between start loopheader and +// instruction). +// +// We visit the graph in RPO and keep track of the last stores in that block. +// Upon entering a block we merge the stores information of the predecessors. +// Only loopheaders are different, since we eagerly make it depend on the +// control instruction of the loopheader. +// +// During the iteration of a block we keep a running store dependeny list. +// At the end of the iteration, this will contain the last stores +// (which we keep for successors). +// +// When encountering a store or load we do: +// - Store: we update the current block store info and put a StoreDependency +// to create a store-chain. +// +// - Load: we take the current block store dependency info and improve that by +// following the store-chain when encountering not aliasing store. Upon +// encountering a control instruction (indicates loop) it solely depends on +// we defer until the loop has been examined. +// +// The algorithm depends on the invariant that both control instructions and effectful +// instructions (stores) are never hoisted. + +bool +FlowAliasAnalysis::analyze() +{ + DumpAnalyzeStart(); + + // Type analysis may have inserted new instructions. Since this pass depends + // on the instruction number ordering, all instructions are renumbered. + uint32_t newId = 0; + + if (!stores_->reserve(graph_.numBlocks())) + return false; + + for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { + if (mir->shouldCancel("Alias Analysis (main loop)")) + return false; + + DumpBlockStart(*block); + + if (!computeBlockStores(*block)) + return false; + if (!stores_->maybeFreePredecessorBlocks(*block)) + return false; + + if (block->isLoopHeader()) + loop_ = new(alloc()) LoopInfo(alloc(), loop_, *block); + + for (MPhiIterator def(block->phisBegin()), end(block->phisEnd()); def != end; ++def) + def->setId(newId++); + + BlockStoreInfo& blockInfo = stores_->current(); + for (MInstructionIterator def(block->begin()), end(block->begin(block->lastIns())); + def != end; + ++def) + { + def->setId(newId++); + + // For the purposes of alias analysis, all recoverable operations + // are treated as effect free as the memory represented by these + // operations cannot be aliased by others. + if (def->canRecoverOnBailout()) + continue; + + AliasSet set = def->getAliasSet(); + if (set.isStore()) { + if (!processStore(blockInfo, *def)) + return false; + } else if (set.isLoad()) { + if (!processLoad(blockInfo, *def)) + return false; + } + } + + block->lastIns()->setId(newId++); + + if (block->isLoopBackedge()) { + stores_->unsetCurrent(); + + LoopInfo* info = loop_; + loop_ = loop_->outer(); + + if (!processDeferredLoads(info)) + return false; + } + + DumpBlockSummary(*block, blockInfo); + } + + spewDependencyList(); + return true; +} + +bool +FlowAliasAnalysis::processStore(BlockStoreInfo& blockInfo, MDefinition* store) +{ + // Compute and set dependency information. + if (!saveStoreDependency(store, blockInfo)) + return false; + + // Update the block store dependency vector. + blockInfo.clear(); + if (!blockInfo.append(store)) + return false; + + // Spew what we did. + DumpStore(store); + return true; +} + +bool +FlowAliasAnalysis::processLoad(BlockStoreInfo& blockInfo, MDefinition* load) +{ + DumpLoad(load); + + // Compute dependency information. + MDefinitionVector& dependencies = blockInfo; + if (!improveDependency(load, dependencies, output_)) + return false; + saveLoadDependency(load, output_); + + // If possible defer when better loop information is present. + if (deferImproveDependency(output_)) { + if (!loop_->loopinvariant().append(load)) + return false; + + DumpLoadOutcome(load, output_, /* defer = */ true); + return true; + } + + DumpLoadOutcome(load, output_, /* defer = */ false); + return true; +} + +bool +FlowAliasAnalysis::processDeferredLoads(LoopInfo* info) +{ + DumpProcessingDeferredLoads(info->loopHeader()); + MOZ_ASSERT(loopIsFinished(info->loopHeader())); + + for (size_t i = 0; i < info->loopinvariant().length(); i++) { + MDefinition* load = info->loopinvariant()[i]; + + DumpLoad(load); + + // Defer load again when this loop still isn't finished yet. + if (!loopIsFinished(load->dependency()->block())) { + MOZ_ASSERT(loop_); + if (!loop_->loopinvariant().append(load)) + return false; + + DumpLoadOutcome(load, output_, /* defer = */ true); + continue; + } + + MOZ_ASSERT(load->dependency()->block() == info->loopHeader()); + MDefinition* store = load->dependency(); + load->setDependency(nullptr); + + // Test if this load is loop invariant and if it is, + // take the dependencies of non-backedge predecessors of the loop header. + bool loopinvariant; + if (!isLoopInvariant(load, store, &loopinvariant)) + return false; + MDefinitionVector &loopInvariantDependency = + stores_->get(store->block()->loopPredecessor()); + + DumpLoopInvariant(load, info->loopHeader(), /* loopinvariant = */ loopinvariant, + loopInvariantDependency); + + if (loopinvariant) { + if (!improveDependency(load, loopInvariantDependency, output_)) + return false; + saveLoadDependency(load, output_); + + // If possible defer when better loop information is present. + if (deferImproveDependency(output_)) { + if (!loop_->loopinvariant().append(load)) + return false; + + DumpLoadOutcome(load, output_, /* defer = */ true); + } else { + DumpLoadOutcome(load, output_, /* defer = */ false); + } + + } else { + load->setDependency(store); + +#ifdef JS_JITSPEW + output_.clear(); + if (!output_.append(store)) + return false; + DumpLoadOutcome(load, output_, /* defer = */ false); +#endif + } + + } + return true; +} + +// Given a load instruction and an initial store dependency list, +// find the most accurate store dependency list. +bool +FlowAliasAnalysis::improveDependency(MDefinition* load, MDefinitionVector& inputStores, + MDefinitionVector& outputStores) +{ + MOZ_ASSERT(inputStores.length() > 0); + outputStores.clear(); + if (!outputStores.appendAll(inputStores)) + return false; + + bool improved = false; + bool adjusted = true; + while (adjusted) { + adjusted = false; + if (!improveNonAliasedStores(load, outputStores, outputStores, &improved)) + return false; + MOZ_ASSERT(outputStores.length() != 0); + if (!improveStoresInFinishedLoops(load, outputStores, &adjusted)) + return false; + if (adjusted) + improved = true; + } + + if (improved) + DumpImprovement(load, inputStores, outputStores); + + return true; +} + +// For every real store dependencies, follow the chain of stores to find the +// unique set of 'might alias' store dependencies. +bool +FlowAliasAnalysis::improveNonAliasedStores(MDefinition* load, MDefinitionVector& inputStores, + MDefinitionVector& outputStores, bool* improved, + bool onlyControlInstructions) +{ + MOZ_ASSERT(worklist_.length() == 0); + if (!AppendToWorklist(worklist_, inputStores)) + return false; + outputStores.clear(); + + for (size_t i = 0; i < worklist_.length(); i++) { + MOZ_ASSERT(worklist_[i]); + + if (!LoadAliasesStore(load, worklist_[i])) { + StoreDependency* dep = worklist_[i]->storeDependency(); + MOZ_ASSERT(dep); + MOZ_ASSERT(dep->get().length() > 0); + + if (!AppendToWorklist(worklist_, dep->get())) + return false; + + *improved = true; + continue; + } + + if (onlyControlInstructions && !worklist_[i]->isControlInstruction()) { + outputStores.clear(); + break; + } + if (!outputStores.append(worklist_[i])) + return false; + } + + SetNotInWorkList(worklist_); + worklist_.clear(); + return true; +} + +// Given a load instruction and an initial store dependency list, +// find the most accurate store dependency list with only control instructions. +// Returns an empty output list, when there was a non control instructions +// that couldn't get improved to a control instruction. +bool +FlowAliasAnalysis::improveLoopDependency(MDefinition* load, MDefinitionVector& inputStores, + MDefinitionVector& outputStores) +{ + outputStores.clear(); + if (!outputStores.appendAll(inputStores)) + return false; + + bool improved = false; + bool adjusted = true; + while (adjusted) { + adjusted = false; + if (!improveNonAliasedStores(load, outputStores, outputStores, &improved, + /* onlyControlInstructions = */ true)) + { + return false; + } + if (outputStores.length() == 0) + return true; + if (!improveStoresInFinishedLoops(load, outputStores, &adjusted)) + return false; + if (adjusted) + improved = true; + } + + if (improved) + DumpImprovement(load, inputStores, outputStores); + + return true; +} + +// For every control instruction in the output we find out if the load is loop +// invariant to that loop. When it is, improve the output dependency store, +// by pointing to the stores before the loop. +bool +FlowAliasAnalysis::improveStoresInFinishedLoops(MDefinition* load, MDefinitionVector& stores, + bool* improved) +{ + for (size_t i = 0; i < stores.length(); i++) { + if (!stores[i]->isControlInstruction()) + continue; + if (!stores[i]->block()->isLoopHeader()) + continue; + + MOZ_ASSERT(!stores[i]->storeDependency()); + + if (!loopIsFinished(stores[i]->block())) + continue; + + if (load->dependency() == stores[i]) + continue; + + bool loopinvariant; + if (!isLoopInvariant(load, stores[i], &loopinvariant)) + return false; + if (!loopinvariant) + continue; + + MBasicBlock* pred = stores[i]->block()->loopPredecessor(); + BlockStoreInfo& predInfo = stores_->get(pred); + + MOZ_ASSERT(predInfo.length() > 0); + stores[i] = predInfo[0]; + for (size_t j = 1; j < predInfo.length(); j++) { + if (!stores.append(predInfo[j])) + return false; + } + + *improved = true; + } + + return true; +} + +bool +FlowAliasAnalysis::deferImproveDependency(MDefinitionVector& stores) +{ + // Look if the store depends only on 1 non finished loop. + // In that case we will defer until that loop has finished. + return loop_ && stores.length() == 1 && + stores[0]->isControlInstruction() && + stores[0]->block()->isLoopHeader() && + !loopIsFinished(stores[0]->block()); +} + +void +FlowAliasAnalysis::saveLoadDependency(MDefinition* load, MDefinitionVector& dependencies) +{ + MOZ_ASSERT(dependencies.length() > 0); + + // For now we only save the last store before the load for other passes. + // That means the store with the maximum id. + MDefinition* max = dependencies[0]; + MDefinition* maxNonControl = nullptr; + for (size_t i = 0; i < dependencies.length(); i++) { + MDefinition* ins = dependencies[i]; + if (max->id() < ins->id()) + max = ins; + if (!ins->isControlInstruction()) { + if (!maxNonControl || maxNonControl->id() < ins->id()) + maxNonControl = ins; + } + } + + // For loop variant loads with no stores between loopheader and the load, + // the control instruction of the loop header is returned. + // That id is higher than any store inside the loopheader itself. + // Fix for dependency on item in loopheader, but before the "test". + // Which would assume it depends on the loop itself. + if (maxNonControl != max && maxNonControl) { + if (maxNonControl->block() == max->block()) + max = maxNonControl; + } + + load->setDependency(max); +} + +bool +FlowAliasAnalysis::saveStoreDependency(MDefinition* ins, BlockStoreInfo& prevStores) +{ + // To form a store dependency chain, we store the previous last dependencies + // in the current store. + + StoreDependency* dependency = new(alloc()) StoreDependency(alloc()); + if (!dependency) + return false; + if (!dependency->init(prevStores)) + return false; + + ins->setStoreDependency(dependency); + return true; +} + +// Returns if loop has been processed +// and has complete backedge stores information. +bool +FlowAliasAnalysis::loopIsFinished(MBasicBlock* loopheader) +{ + MOZ_ASSERT(loopheader->isLoopHeader()); + + if (!loop_) + return true; + + return loopheader->backedge()->id() < + loop_->loopHeader()->backedge()->id(); +} + + +// Determines if a load is loop invariant. +// +// Get the last store dependencies of the backedge of the loop and follow +// the store chain until finding the aliased stores. Make sure the computed +// aliased stores is only the loop control instruction or control instructions +// of loops it is also loop invariant. Only in that case the load is +// definitely loop invariant. +bool +FlowAliasAnalysis::isLoopInvariant(MDefinition* load, MDefinition* store, bool* loopinvariant) +{ + MOZ_ASSERT(store->isControlInstruction()); + MOZ_ASSERT(!store->storeDependency()); + MOZ_ASSERT(store->block()->isLoopHeader()); + MOZ_ASSERT(loopIsFinished(store->block())); + + *loopinvariant = false; + MBasicBlock* backedge = store->block()->backedge(); + MDefinitionVector output(alloc()); + + // To make sure the improve dependency stops at this loop, + // set the loop control instruction as dependency. + MDefinition* olddep = load->dependency(); + load->setDependency(store); + if (!improveLoopDependency(load, stores_->get(backedge), output)) + return false; + load->setDependency(olddep); + + if (output.length() == 0) + return true; + + for (size_t i = 0; i < output.length(); i++) { + if (output[i]->storeDependency()) + return true; + + if (!output[i]->isControlInstruction()) + return true; + if (!output[i]->block()->isLoopHeader()) + return true; + + if (output[i] == store) + continue; + + return true; + } + + *loopinvariant = true; + return true; +} + +// Compute the store dependencies at the start of this MBasicBlock. +bool +FlowAliasAnalysis::computeBlockStores(MBasicBlock* block) +{ + BlockStoreInfo* blockInfo = stores_->newCurrent(alloc(), block); + if (!blockInfo) + return false; + + // First block depends on the first instruction. + if (block->id() == 0) { + MDefinition* firstIns = *graph_.entryBlock()->begin(); + if (!blockInfo->append(firstIns)) + return false; + return true; + } + + // For loopheaders we take the loopheaders control instruction. + // That is not moveable and easy is to detect. + if (block->isLoopHeader()) { + if (!blockInfo->append(block->lastIns())) + return false; + return true; + } + + + // Optimization for consecutive blocks. + if (block->numPredecessors() == 1) { + MBasicBlock* pred = block->getPredecessor(0); + if (pred->numSuccessors() == 1) { + stores_->swap(block, pred); + return true; + } + MOZ_ASSERT (pred->numSuccessors() > 1); + BlockStoreInfo& predInfo = stores_->get(pred); + return blockInfo->appendAll(predInfo); + } + + // Heuristic: in most cases having more than 5 predecessors, + // increases the number of dependencies too much to still be able + // to do an optimization. Therefore don't do the merge work. + // For simplicity we take an non-dominant always existing instruction. + // That way we cannot accidentally move instructions depending on it. + if (block->numPredecessors() > 5) { + if (!blockInfo->append(block->getPredecessor(0)->lastIns())) + return false; + return true; + } + + // Merging of multiple predecessors. + for (size_t pred = 0; pred < block->numPredecessors(); pred++) { + BlockStoreInfo& predInfo = stores_->get(block->getPredecessor(pred)); + if (!AppendToWorklist(*blockInfo, predInfo)) + return false; + } + SetNotInWorkList(*blockInfo); + + return true; +} diff --git a/js/src/jit/FlowAliasAnalysis.h b/js/src/jit/FlowAliasAnalysis.h new file mode 100644 index 0000000000..6d8364097b --- /dev/null +++ b/js/src/jit/FlowAliasAnalysis.h @@ -0,0 +1,70 @@ +/* -*- 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 jit_FlowAliasAnalysis_h +#define jit_FlowAliasAnalysis_h + +#include "jit/AliasAnalysisShared.h" +#include "jit/MIR.h" +#include "jit/MIRGraph.h" + +namespace js { +namespace jit { + +class LoopInfo; +class MIRGraph; +class GraphStoreInfo; + +typedef MDefinitionVector BlockStoreInfo; +typedef Vector GraphStoreVector; + +class FlowAliasAnalysis : public AliasAnalysisShared +{ + // Info on the graph. + LoopInfo* loop_; + GraphStoreInfo* stores_; + + // Helper vectors. In order to not have to recreate them the whole time. + MDefinitionVector output_; + MDefinitionVector worklist_; + + public: + FlowAliasAnalysis(MIRGenerator* mir, MIRGraph& graph); + bool analyze() override; + + protected: + /* Process instructions. */ + bool processStore(BlockStoreInfo& stores, MDefinition* store); + bool processLoad(BlockStoreInfo& stores, MDefinition* load); + bool processDeferredLoads(LoopInfo* info); + + /* Improve dependency and helpers. */ + bool improveDependency(MDefinition* load, MDefinitionVector& inputStores, + MDefinitionVector& outputStores); + bool improveNonAliasedStores(MDefinition* load, MDefinitionVector& inputStores, + MDefinitionVector& outputStores, bool* improved, + bool onlyControlInstructions = false); + bool improveStoresInFinishedLoops(MDefinition* load, MDefinitionVector& stores, bool* improved); + + bool improveLoopDependency(MDefinition* load, MDefinitionVector& inputStores, + MDefinitionVector& outputStores); + bool deferImproveDependency(MDefinitionVector& stores); + + /* Save dependency info. */ + void saveLoadDependency(MDefinition* load, MDefinitionVector& dependencies); + bool saveStoreDependency(MDefinition* store, BlockStoreInfo& prevStores); + + /* Helper functions. */ + bool computeBlockStores(MBasicBlock* block); + bool isLoopInvariant(MDefinition* load, MDefinition* store, bool* loopinvariant); + bool loopIsFinished(MBasicBlock* loopheader); + +}; + +} // namespace jit +} // namespace js + +#endif /* jit_FlowAliasAnalysis_h */ diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 444d7371f2..3c62633ba8 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -70,6 +70,7 @@ _(IsRegExpObject) \ _(RegExpPrototypeOptimizable) \ _(RegExpInstanceOptimizable) \ + _(GetFirstDollarIndex) \ \ _(String) \ _(StringCharCodeAt) \ diff --git a/js/src/jit/InstructionReordering.cpp b/js/src/jit/InstructionReordering.cpp index cdaa5056e4..48b619b7cb 100644 --- a/js/src/jit/InstructionReordering.cpp +++ b/js/src/jit/InstructionReordering.cpp @@ -149,7 +149,7 @@ jit::ReorderInstructions(MIRGenerator* mir, MIRGraph& graph) // stores to a location read by the instruction. if (prev->isEffectful() && (ins->getAliasSet().flags() & prev->getAliasSet().flags()) && - ins->mightAlias(prev)) + ins->mightAlias(prev) != MDefinition::AliasType::NoAlias) { break; } diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index eedc9e31a7..efc2a8d0ac 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -24,6 +24,7 @@ #include "jit/EagerSimdUnbox.h" #include "jit/EdgeCaseAnalysis.h" #include "jit/EffectiveAddressAnalysis.h" +#include "jit/FlowAliasAnalysis.h" #include "jit/InstructionReordering.h" #include "jit/IonAnalysis.h" #include "jit/IonBuilder.h" @@ -275,27 +276,27 @@ JitRuntime::initialize(JSContext* cx) return false; JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for Value"); - valuePreBarrier_ = generatePreBarrier(cx, MIRType_Value); + valuePreBarrier_ = generatePreBarrier(cx, MIRType::Value); if (!valuePreBarrier_) return false; JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for String"); - stringPreBarrier_ = generatePreBarrier(cx, MIRType_String); + stringPreBarrier_ = generatePreBarrier(cx, MIRType::String); if (!stringPreBarrier_) return false; JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for Object"); - objectPreBarrier_ = generatePreBarrier(cx, MIRType_Object); + objectPreBarrier_ = generatePreBarrier(cx, MIRType::Object); if (!objectPreBarrier_) return false; JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for Shape"); - shapePreBarrier_ = generatePreBarrier(cx, MIRType_Shape); + shapePreBarrier_ = generatePreBarrier(cx, MIRType::Shape); if (!shapePreBarrier_) return false; JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for ObjectGroup"); - objectGroupPreBarrier_ = generatePreBarrier(cx, MIRType_ObjectGroup); + objectGroupPreBarrier_ = generatePreBarrier(cx, MIRType::ObjectGroup); if (!objectGroupPreBarrier_) return false; @@ -815,8 +816,11 @@ JitCode::finalize(FreeOp* fop) // With W^X JIT code, reprotecting memory for each JitCode instance is // slow, so we record the ranges and poison them later all at once. It's // safe to ignore OOM here, it just means we won't poison the code. - if (fop->appendJitPoisonRange(JitPoisonRange(pool_, code_, bufferSize_))) + if (fop->appendJitPoisonRange(JitPoisonRange(pool_, code_ - headerSize_, + headerSize_ + bufferSize_))) + { pool_->addRef(); + } code_ = nullptr; // Code buffers are stored inside ExecutablePools. Pools are refcounted. @@ -1376,7 +1380,7 @@ OptimizeSinCos(MIRGenerator *mir, MIRGraph &graph) continue; // Check if sin/cos is already optimized. - if (insFunc->getOperand(0)->type() == MIRType_SinCosDouble) + if (insFunc->getOperand(0)->type() == MIRType::SinCosDouble) continue; // insFunc is either a |sin(x)| or |cos(x)| instruction. The @@ -1610,15 +1614,24 @@ OptimizeMIR(MIRGenerator* mir) if (mir->optimizationInfo().licmEnabled() || mir->optimizationInfo().gvnEnabled()) { - AutoTraceLog log(logger, TraceLogger_AliasAnalysis); - AliasAnalysis analysis(mir, graph); - if (!analysis.analyze()) - return false; - gs.spewPass("Alias analysis"); - AssertExtendedGraphCoherency(graph); + { + AutoTraceLog log(logger, TraceLogger_AliasAnalysis); + if (JitOptions.disableFlowAA) { + AliasAnalysis analysis(mir, graph); + if (!analysis.analyze()) + return false; + } else { + FlowAliasAnalysis analysis(mir, graph); + if (!analysis.analyze()) + return false; + } - if (mir->shouldCancel("Alias analysis")) - return false; + gs.spewPass("Alias analysis"); + AssertExtendedGraphCoherency(graph); + + if (mir->shouldCancel("Alias analysis")) + return false; + } if (!mir->compilingAsmJS()) { // Eliminating dead resume point operands requires basic block @@ -2779,7 +2792,8 @@ EnterIon(JSContext* cx, EnterJitData& data) } bool -jit::SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, AutoValueVector& vals) +jit::SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, + MutableHandle> vals) { data.osrFrame = nullptr; @@ -2849,8 +2863,8 @@ jit::IonCannon(JSContext* cx, RunState& state) EnterJitData data(cx); data.jitcode = ion->method()->raw(); - AutoValueVector vals(cx); - if (!SetEnterJitData(cx, data, state, vals)) + Rooted> vals(cx, GCVector(cx)); + if (!SetEnterJitData(cx, data, state, &vals)) return JitExec_Error; JitExecStatus status = EnterIon(cx, data); diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 973eb45d6f..b0d00f6c9e 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -114,7 +114,8 @@ IsErrorStatus(JitExecStatus status) struct EnterJitData; -bool SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, AutoValueVector& vals); +bool SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, + MutableHandle> vals); JitExecStatus IonCannon(JSContext* cx, RunState& state); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index b2c1d17bd7..27fafbc920 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -9,6 +9,7 @@ #include "jit/AliasAnalysis.h" #include "jit/BaselineInspector.h" #include "jit/BaselineJIT.h" +#include "jit/FlowAliasAnalysis.h" #include "jit/Ion.h" #include "jit/IonBuilder.h" #include "jit/IonOptimizationLevels.h" @@ -1208,14 +1209,14 @@ GuessPhiType(MPhi* phi, bool* hasInputsWithEmptyTypes) // Check that different magic constants aren't flowing together. Ignore // JS_OPTIMIZED_OUT, since an operand could be legitimately optimized // away. - MIRType magicType = MIRType_None; + MIRType magicType = MIRType::None; for (size_t i = 0; i < phi->numOperands(); i++) { MDefinition* in = phi->getOperand(i); - if (in->type() == MIRType_MagicOptimizedArguments || - in->type() == MIRType_MagicHole || - in->type() == MIRType_MagicIsConstructing) + if (in->type() == MIRType::MagicOptimizedArguments || + in->type() == MIRType::MagicHole || + in->type() == MIRType::MagicIsConstructing) { - if (magicType == MIRType_None) + if (magicType == MIRType::None) magicType = in->type(); MOZ_ASSERT(magicType == in->type()); } @@ -1224,7 +1225,7 @@ GuessPhiType(MPhi* phi, bool* hasInputsWithEmptyTypes) *hasInputsWithEmptyTypes = false; - MIRType type = MIRType_None; + MIRType type = MIRType::None; bool convertibleToFloat32 = false; bool hasPhiInputs = false; for (size_t i = 0, e = phi->numOperands(); i < e; i++) { @@ -1233,7 +1234,7 @@ GuessPhiType(MPhi* phi, bool* hasInputsWithEmptyTypes) hasPhiInputs = true; if (!in->toPhi()->triedToSpecialize()) continue; - if (in->type() == MIRType_None) { + if (in->type() == MIRType::None) { // The operand is a phi we tried to specialize, but we were // unable to guess its type. propagateSpecialization will // propagate the type to this phi when it becomes known. @@ -1247,34 +1248,34 @@ GuessPhiType(MPhi* phi, bool* hasInputsWithEmptyTypes) continue; } - if (type == MIRType_None) { + if (type == MIRType::None) { type = in->type(); if (in->canProduceFloat32()) convertibleToFloat32 = true; continue; } if (type != in->type()) { - if (convertibleToFloat32 && in->type() == MIRType_Float32) { + if (convertibleToFloat32 && in->type() == MIRType::Float32) { // If we only saw definitions that can be converted into Float32 before and // encounter a Float32 value, promote previous values to Float32 - type = MIRType_Float32; + type = MIRType::Float32; } else if (IsTypeRepresentableAsDouble(type) && IsTypeRepresentableAsDouble(in->type())) { // Specialize phis with int32 and double operands as double. - type = MIRType_Double; + type = MIRType::Double; convertibleToFloat32 &= in->canProduceFloat32(); } else { - return MIRType_Value; + return MIRType::Value; } } } - if (type == MIRType_None && !hasPhiInputs) { - // All inputs are non-phis with empty typesets. Use MIRType_Value + if (type == MIRType::None && !hasPhiInputs) { + // All inputs are non-phis with empty typesets. Use MIRType::Value // in this case, as it's impossible to get better type information. MOZ_ASSERT(*hasInputsWithEmptyTypes); - type = MIRType_Value; + type = MIRType::Value; } return type; @@ -1292,7 +1293,7 @@ TypeAnalyzer::respecialize(MPhi* phi, MIRType type) bool TypeAnalyzer::propagateSpecialization(MPhi* phi) { - MOZ_ASSERT(phi->type() != MIRType_None); + MOZ_ASSERT(phi->type() != MIRType::None); // Verify that this specialization matches any phis depending on it. for (MUseDefIterator iter(phi); iter; iter++) { @@ -1301,7 +1302,7 @@ TypeAnalyzer::propagateSpecialization(MPhi* phi) MPhi* use = iter.def()->toPhi(); if (!use->triedToSpecialize()) continue; - if (use->type() == MIRType_None) { + if (use->type() == MIRType::None) { // We tried to specialize this phi, but were unable to guess its // type. Now that we know the type of one of its operands, we can // specialize it. @@ -1311,10 +1312,10 @@ TypeAnalyzer::propagateSpecialization(MPhi* phi) } if (use->type() != phi->type()) { // Specialize phis with int32 that can be converted to float and float operands as floats. - if ((use->type() == MIRType_Int32 && use->canProduceFloat32() && phi->type() == MIRType_Float32) || - (phi->type() == MIRType_Int32 && phi->canProduceFloat32() && use->type() == MIRType_Float32)) + if ((use->type() == MIRType::Int32 && use->canProduceFloat32() && phi->type() == MIRType::Float32) || + (phi->type() == MIRType::Int32 && phi->canProduceFloat32() && use->type() == MIRType::Float32)) { - if (!respecialize(use, MIRType_Float32)) + if (!respecialize(use, MIRType::Float32)) return false; continue; } @@ -1323,13 +1324,13 @@ TypeAnalyzer::propagateSpecialization(MPhi* phi) if (IsTypeRepresentableAsDouble(use->type()) && IsTypeRepresentableAsDouble(phi->type())) { - if (!respecialize(use, MIRType_Double)) + if (!respecialize(use, MIRType::Double)) return false; continue; } // This phi in our use chain can now no longer be specialized. - if (!respecialize(use, MIRType_Value)) + if (!respecialize(use, MIRType::Value)) return false; } } @@ -1350,7 +1351,7 @@ TypeAnalyzer::specializePhis() bool hasInputsWithEmptyTypes; MIRType type = GuessPhiType(*phi, &hasInputsWithEmptyTypes); phi->specialize(type); - if (type == MIRType_None) { + if (type == MIRType::None) { // We tried to guess the type but failed because all operands are // phis we still have to visit. Set the triedToSpecialize flag but // don't propagate the type to other phis, propagateSpecialization @@ -1358,8 +1359,8 @@ TypeAnalyzer::specializePhis() // Edge case: when this phi has a non-phi input with an empty // typeset, it's possible for two phis to have a cyclic - // dependency and they will both have MIRType_None. Specialize - // such phis to MIRType_Value later on. + // dependency and they will both have MIRType::None. Specialize + // such phis to MIRType::Value later on. if (hasInputsWithEmptyTypes && !phisWithEmptyInputTypes.append(*phi)) return false; continue; @@ -1381,14 +1382,14 @@ TypeAnalyzer::specializePhis() // When two phis have a cyclic dependency and inputs that have an empty // typeset (which are ignored by GuessPhiType), we may still have to - // specialize these to MIRType_Value. + // specialize these to MIRType::Value. while (!phisWithEmptyInputTypes.empty()) { if (mir->shouldCancel("Specialize Phis (phisWithEmptyInputTypes)")) return false; MPhi* phi = phisWithEmptyInputTypes.popCopy(); - if (phi->type() == MIRType_None) { - phi->specialize(MIRType_Value); + if (phi->type() == MIRType::None) { + phi->specialize(MIRType::Value); if (!propagateSpecialization(phi)) return false; } @@ -1402,13 +1403,13 @@ bool TypeAnalyzer::adjustPhiInputs(MPhi* phi) { MIRType phiType = phi->type(); - MOZ_ASSERT(phiType != MIRType_None); + MOZ_ASSERT(phiType != MIRType::None); // If we specialized a type that's not Value, there are 3 cases: // 1. Every input is of that type. // 2. Every observed input is of that type (i.e., some inputs haven't been executed yet). // 3. Inputs were doubles and int32s, and was specialized to double. - if (phiType != MIRType_Value) { + if (phiType != MIRType::Value) { for (size_t i = 0, e = phi->numOperands(); i < e; i++) { MDefinition* in = phi->getOperand(i); if (in->type() == phiType) @@ -1422,21 +1423,21 @@ TypeAnalyzer::adjustPhiInputs(MPhi* phi) } else { MInstruction* replacement; - if (phiType == MIRType_Double && IsFloatType(in->type())) { + if (phiType == MIRType::Double && IsFloatType(in->type())) { // Convert int32 operands to double. replacement = MToDouble::New(alloc(), in); - } else if (phiType == MIRType_Float32) { - if (in->type() == MIRType_Int32 || in->type() == MIRType_Double) { + } else if (phiType == MIRType::Float32) { + if (in->type() == MIRType::Int32 || in->type() == MIRType::Double) { replacement = MToFloat32::New(alloc(), in); } else { // See comment below - if (in->type() != MIRType_Value) { + if (in->type() != MIRType::Value) { MBox* box = MBox::New(alloc(), in); in->block()->insertBefore(in->block()->lastIns(), box); in = box; } - MUnbox* unbox = MUnbox::New(alloc(), in, MIRType_Double, MUnbox::Fallible); + MUnbox* unbox = MUnbox::New(alloc(), in, MIRType::Double, MUnbox::Fallible); in->block()->insertBefore(in->block()->lastIns(), unbox); replacement = MToFloat32::New(alloc(), in); } @@ -1444,7 +1445,7 @@ TypeAnalyzer::adjustPhiInputs(MPhi* phi) // If we know this branch will fail to convert to phiType, // insert a box that'll immediately fail in the fallible unbox // below. - if (in->type() != MIRType_Value) { + if (in->type() != MIRType::Value) { MBox* box = MBox::New(alloc(), in); in->block()->insertBefore(in->block()->lastIns(), box); in = box; @@ -1466,7 +1467,7 @@ TypeAnalyzer::adjustPhiInputs(MPhi* phi) // Box every typed input. for (size_t i = 0, e = phi->numOperands(); i < e; i++) { MDefinition* in = phi->getOperand(i); - if (in->type() == MIRType_Value) + if (in->type() == MIRType::Value) continue; // The input is being explicitly unboxed, so sneak past and grab @@ -1474,7 +1475,7 @@ TypeAnalyzer::adjustPhiInputs(MPhi* phi) if (in->isUnbox() && phi->typeIncludes(in->toUnbox()->input())) in = in->toUnbox()->input(); - if (in->type() != MIRType_Value) { + if (in->type() != MIRType::Value) { if (!alloc().ensureBallast()) return false; @@ -1508,19 +1509,19 @@ TypeAnalyzer::replaceRedundantPhi(MPhi* phi) MBasicBlock* block = phi->block(); js::Value v; switch (phi->type()) { - case MIRType_Undefined: + case MIRType::Undefined: v = UndefinedValue(); break; - case MIRType_Null: + case MIRType::Null: v = NullValue(); break; - case MIRType_MagicOptimizedArguments: + case MIRType::MagicOptimizedArguments: v = MagicValue(JS_OPTIMIZED_ARGUMENTS); break; - case MIRType_MagicOptimizedOut: + case MIRType::MagicOptimizedOut: v = MagicValue(JS_OPTIMIZED_OUT); break; - case MIRType_MagicUninitializedLexical: + case MIRType::MagicUninitializedLexical: v = MagicValue(JS_UNINITIALIZED_LEXICAL); break; default: @@ -1544,11 +1545,11 @@ TypeAnalyzer::insertConversions() for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd()); iter != end; ) { MPhi* phi = *iter++; - if (phi->type() == MIRType_Undefined || - phi->type() == MIRType_Null || - phi->type() == MIRType_MagicOptimizedArguments || - phi->type() == MIRType_MagicOptimizedOut || - phi->type() == MIRType_MagicUninitializedLexical) + if (phi->type() == MIRType::Undefined || + phi->type() == MIRType::Null || + phi->type() == MIRType::MagicOptimizedArguments || + phi->type() == MIRType::MagicOptimizedOut || + phi->type() == MIRType::MagicUninitializedLexical) { replaceRedundantPhi(phi); block->discardPhi(phi); @@ -1729,7 +1730,7 @@ TypeAnalyzer::specializeValidFloatOps() if (!ins->isFloat32Commutative()) continue; - if (ins->type() == MIRType_Float32) + if (ins->type() == MIRType::Float32) continue; // This call will try to specialize the instruction iff all uses are consumers and @@ -1748,7 +1749,7 @@ TypeAnalyzer::graphContainsFloat32() return false; for (MDefinitionIterator def(*block); def; def++) { - if (def->type() == MIRType_Float32) + if (def->type() == MIRType::Float32) return true; } } @@ -1788,7 +1789,7 @@ TypeAnalyzer::checkFloatCoherency() return false; for (MDefinitionIterator def(*block); def; def++) { - if (def->type() != MIRType_Float32) + if (def->type() != MIRType::Float32) continue; for (MUseDefIterator use(*def); use; use++) { @@ -1915,8 +1916,20 @@ jit::AccountForCFGChanges(MIRGenerator* mir, MIRGraph& graph, bool updateAliasAn // If needed, update alias analysis dependencies. if (updateAliasAnalysis) { - if (!AliasAnalysis(mir, graph).analyze()) - return false; + TraceLoggerThread* logger; + if (GetJitContext()->runtime->onMainThread()) + logger = TraceLoggerForMainThread(GetJitContext()->runtime); + else + logger = TraceLoggerForCurrentThread(); + AutoTraceLog log(logger, TraceLogger_AliasAnalysis); + + if (JitOptions.disableFlowAA) { + if (!AliasAnalysis(mir, graph).analyze()) + return false; + } else { + if (!FlowAliasAnalysis(mir, graph).analyze()) + return false; + } } AssertExtendedGraphCoherency(graph, underValueNumberer); @@ -2358,12 +2371,12 @@ jit::AssertBasicGraphCoherency(MIRGraph& graph) for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) { MOZ_ASSERT(phi->numOperands() == block->numPredecessors()); MOZ_ASSERT(!phi->isRecoveredOnBailout()); - MOZ_ASSERT(phi->type() != MIRType_None); + MOZ_ASSERT(phi->type() != MIRType::None); MOZ_ASSERT(phi->dependency() == nullptr); } for (MDefinitionIterator iter(*block); iter; iter++) { MOZ_ASSERT(iter->block() == *block); - MOZ_ASSERT_IF(iter->hasUses(), iter->type() != MIRType_None); + MOZ_ASSERT_IF(iter->hasUses(), iter->type() != MIRType::None); MOZ_ASSERT(!iter->isDiscarded()); MOZ_ASSERT_IF(iter->isStart(), *block == graph.entryBlock() || *block == graph.osrBlock()); @@ -2394,7 +2407,7 @@ jit::AssertBasicGraphCoherency(MIRGraph& graph) MControlInstruction* control = block->lastIns(); MOZ_ASSERT(control->block() == *block); MOZ_ASSERT(!control->hasUses()); - MOZ_ASSERT(control->type() == MIRType_None); + MOZ_ASSERT(control->type() == MIRType::None); MOZ_ASSERT(!control->isDiscarded()); MOZ_ASSERT(!control->isRecoveredOnBailout()); MOZ_ASSERT(control->resumePoint() == nullptr); @@ -2505,36 +2518,36 @@ IsResumableMIRType(MIRType type) { // see CodeGeneratorShared::encodeAllocation switch (type) { - case MIRType_Undefined: - case MIRType_Null: - case MIRType_Boolean: - case MIRType_Int32: - case MIRType_Double: - case MIRType_Float32: - case MIRType_String: - case MIRType_Symbol: - case MIRType_Object: - case MIRType_MagicOptimizedArguments: - case MIRType_MagicOptimizedOut: - case MIRType_MagicUninitializedLexical: - case MIRType_Value: - case MIRType_Float32x4: - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Undefined: + case MIRType::Null: + case MIRType::Boolean: + case MIRType::Int32: + case MIRType::Double: + case MIRType::Float32: + case MIRType::String: + case MIRType::Symbol: + case MIRType::Object: + case MIRType::MagicOptimizedArguments: + case MIRType::MagicOptimizedOut: + case MIRType::MagicUninitializedLexical: + case MIRType::Value: + case MIRType::Float32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: return true; - case MIRType_MagicHole: - case MIRType_MagicIsConstructing: - case MIRType_ObjectOrNull: - case MIRType_None: - case MIRType_Slots: - case MIRType_Elements: - case MIRType_Pointer: - case MIRType_Shape: - case MIRType_ObjectGroup: - case MIRType_Doublex2: // NYI, see also RSimdBox::recover - case MIRType_SinCosDouble: - case MIRType_Int64: + case MIRType::MagicHole: + case MIRType::MagicIsConstructing: + case MIRType::ObjectOrNull: + case MIRType::None: + case MIRType::Slots: + case MIRType::Elements: + case MIRType::Pointer: + case MIRType::Shape: + case MIRType::ObjectGroup: + case MIRType::Doublex2: // NYI, see also RSimdBox::recover + case MIRType::SinCosDouble: + case MIRType::Int64: return false; } MOZ_CRASH("Unknown MIRType."); @@ -2565,7 +2578,7 @@ AssertResumePointDominatedByOperands(MResumePoint* resume) { for (size_t i = 0, e = resume->numOperands(); i < e; ++i) { MDefinition* op = resume->getOperand(i); - if (op->type() == MIRType_MagicOptimizedArguments) + if (op->type() == MIRType::MagicOptimizedArguments) continue; MOZ_ASSERT(op->block()->dominates(resume->block()), "Resume point is not dominated by its operands"); @@ -2636,7 +2649,7 @@ jit::AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer) // We sometimes see a phi with a magic-optimized-arguments // operand defined in the normal entry block, while the phi is // also reachable from the OSR entry (auto-regress/bug779818.js) - if (phi->getOperand(i)->type() == MIRType_MagicOptimizedArguments) + if (phi->getOperand(i)->type() == MIRType::MagicOptimizedArguments) continue; MOZ_ASSERT(phi->getOperand(i)->block()->dominates(block->getPredecessor(i)), @@ -2740,7 +2753,7 @@ jit::ExtractLinearSum(MDefinition* ins) if (ins->isBeta()) ins = ins->getOperand(0); - if (ins->type() != MIRType_Int32) + if (ins->type() != MIRType::Int32) return SimpleLinearSum(ins, 0); if (ins->isConstant()) @@ -2749,7 +2762,7 @@ jit::ExtractLinearSum(MDefinition* ins) if (ins->isAdd() || ins->isSub()) { MDefinition* lhs = ins->getOperand(0); MDefinition* rhs = ins->getOperand(1); - if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) { + if (lhs->type() == MIRType::Int32 && rhs->type() == MIRType::Int32) { SimpleLinearSum lsum = ExtractLinearSum(lhs); SimpleLinearSum rsum = ExtractLinearSum(rhs); @@ -2793,8 +2806,8 @@ jit::ExtractLinearInequality(MTest* test, BranchDirection direction, if (!compare->isInt32Comparison()) return false; - MOZ_ASSERT(lhs->type() == MIRType_Int32); - MOZ_ASSERT(rhs->type() == MIRType_Int32); + MOZ_ASSERT(lhs->type() == MIRType::Int32); + MOZ_ASSERT(rhs->type() == MIRType::Int32); JSOp jsop = compare->jsop(); if (direction == FALSE_BRANCH) @@ -2999,7 +3012,7 @@ TryEliminateTypeBarrier(MTypeBarrier* barrier, bool* eliminated) static bool TryOptimizeLoadObjectOrNull(MDefinition* def, MDefinitionVector* peliminateList) { - if (def->type() != MIRType_Value) + if (def->type() != MIRType::Value) return true; // Check if this definition can only produce object or null values. @@ -3031,13 +3044,13 @@ TryOptimizeLoadObjectOrNull(MDefinition* def, MDefinitionVector* peliminateList) return false; break; case MDefinition::Op_Unbox: - if (ndef->type() != MIRType_Object) + if (ndef->type() != MIRType::Object) return true; break; case MDefinition::Op_TypeBarrier: // For now, only handle type barriers which are not consumed // anywhere and only test that the value is null. - if (ndef->hasUses() || ndef->resultTypeSet()->getKnownMIRType() != MIRType_Null) + if (ndef->hasUses() || ndef->resultTypeSet()->getKnownMIRType() != MIRType::Null) return true; break; default: @@ -3060,13 +3073,13 @@ TryOptimizeLoadObjectOrNull(MDefinition* def, MDefinitionVector* peliminateList) return true; #endif // JS_PUNBOX64 - def->setResultType(MIRType_ObjectOrNull); + def->setResultType(MIRType::ObjectOrNull); // Fixup the result type of MTypeBarrier uses. for (MUseDefIterator iter(def); iter; ++iter) { MDefinition* ndef = iter.def(); if (ndef->isTypeBarrier()) - ndef->setResultType(MIRType_ObjectOrNull); + ndef->setResultType(MIRType::ObjectOrNull); } // Eliminate MToObjectOrNull instruction uses. @@ -3189,8 +3202,8 @@ jit::EliminateRedundantChecks(MIRGraph& graph) static bool NeedsKeepAlive(MInstruction* slotsOrElements, MInstruction* use) { - MOZ_ASSERT(slotsOrElements->type() == MIRType_Elements || - slotsOrElements->type() == MIRType_Slots); + MOZ_ASSERT(slotsOrElements->type() == MIRType::Elements || + slotsOrElements->type() == MIRType::Slots); if (slotsOrElements->block() != use->block()) return true; @@ -3236,7 +3249,7 @@ jit::AddKeepAliveInstructions(MIRGraph& graph) for (MInstructionIterator insIter(block->begin()); insIter != block->end(); insIter++) { MInstruction* ins = *insIter; - if (ins->type() != MIRType_Elements && ins->type() != MIRType_Slots) + if (ins->type() != MIRType::Elements && ins->type() != MIRType::Slots) continue; MDefinition* ownerObject; @@ -3260,7 +3273,7 @@ jit::AddKeepAliveInstructions(MIRGraph& graph) MOZ_CRASH("Unexpected op"); } - MOZ_ASSERT(ownerObject->type() == MIRType_Object); + MOZ_ASSERT(ownerObject->type() == MIRType::Object); if (ownerObject->isConstant()) { // Constants are kept alive by other pointers, for instance diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a0bcf0453b..c514cc6546 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -662,18 +662,18 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod } } } else { - MIRType type = MIRType_None; + MIRType type = MIRType::None; switch (*last) { case JSOP_VOID: case JSOP_UNDEFINED: - type = MIRType_Undefined; + type = MIRType::Undefined; break; case JSOP_GIMPLICITTHIS: if (!script()->hasNonSyntacticScope()) - type = MIRType_Undefined; + type = MIRType::Undefined; break; case JSOP_NULL: - type = MIRType_Null; + type = MIRType::Null; break; case JSOP_ZERO: case JSOP_ONE: @@ -688,7 +688,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod case JSOP_RSH: case JSOP_LSH: case JSOP_URSH: - type = MIRType_Int32; + type = MIRType::Int32; break; case JSOP_FALSE: case JSOP_TRUE: @@ -703,19 +703,19 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod case JSOP_STRICTNE: case JSOP_IN: case JSOP_INSTANCEOF: - type = MIRType_Boolean; + type = MIRType::Boolean; break; case JSOP_DOUBLE: - type = MIRType_Double; + type = MIRType::Double; break; case JSOP_STRING: case JSOP_TOSTRING: case JSOP_TYPEOF: case JSOP_TYPEOFEXPR: - type = MIRType_String; + type = MIRType::String; break; case JSOP_SYMBOL: - type = MIRType_Symbol; + type = MIRType::Symbol; break; case JSOP_ADD: case JSOP_SUB: @@ -728,7 +728,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod default: break; } - if (type != MIRType_None) { + if (type != MIRType::None) { if (!phi->addBackedgeType(type, nullptr)) return false; } @@ -901,7 +901,7 @@ IonBuilder::build() // effectful operations). for (uint32_t i = 0; i < info().endArgSlot(); i++) { MInstruction* ins = current->getEntrySlot(i)->toInstruction(); - if (ins->type() != MIRType_Value) + if (ins->type() != MIRType::Value) continue; MResumePoint* entryRpCopy = MResumePoint::Copy(alloc(), current->entryResumePoint()); @@ -1286,7 +1286,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_, MBasicBlock* osrBlock = def->block(); // Clear bogus type information added in newOsrPreheader(). - def->setResultType(MIRType_Value); + def->setResultType(MIRType::Value); def->setResultTypeSet(nullptr); if (typeSet && !typeSet->unknown()) { @@ -1294,9 +1294,9 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_, osrBlock->insertBefore(osrBlock->lastIns(), barrier); osrBlock->rewriteSlot(slot, barrier); def = barrier; - } else if (type == MIRType_Null || - type == MIRType_Undefined || - type == MIRType_MagicOptimizedArguments) + } else if (type == MIRType::Null || + type == MIRType::Undefined || + type == MIRType::MagicOptimizedArguments) { // No unbox instruction will be added below, so check the type by // adding a type barrier for a singleton type set. @@ -1312,12 +1312,12 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_, } switch (type) { - case MIRType_Boolean: - case MIRType_Int32: - case MIRType_Double: - case MIRType_String: - case MIRType_Symbol: - case MIRType_Object: + case MIRType::Boolean: + case MIRType::Int32: + case MIRType::Double: + case MIRType::String: + case MIRType::Symbol: + case MIRType::Object: if (type != def->type()) { MUnbox* unbox = MUnbox::New(alloc(), def, type, MUnbox::Fallible); osrBlock->insertBefore(osrBlock->lastIns(), unbox); @@ -1326,7 +1326,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_, } break; - case MIRType_Null: + case MIRType::Null: { MConstant* c = MConstant::New(alloc(), NullValue()); osrBlock->insertBefore(osrBlock->lastIns(), c); @@ -1335,7 +1335,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_, break; } - case MIRType_Undefined: + case MIRType::Undefined: { MConstant* c = MConstant::New(alloc(), UndefinedValue()); osrBlock->insertBefore(osrBlock->lastIns(), c); @@ -1344,7 +1344,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_, break; } - case MIRType_MagicOptimizedArguments: + case MIRType::MagicOptimizedArguments: { MOZ_ASSERT(hasLazyArguments_); MConstant* lazyArg = MConstant::New(alloc(), MagicValue(JS_OPTIMIZED_ARGUMENTS)); @@ -2625,7 +2625,7 @@ IonBuilder::processWhileCondEnd(CFGState& state) if (!nonStringIteration_ && !inspector->hasSeenNonStringIterMore(iterMorePc)) { MDefinition* val = current->peek(-1); MOZ_ASSERT(val == iterMore); - MInstruction* ins = MUnbox::New(alloc(), val, MIRType_String, MUnbox::Fallible, + MInstruction* ins = MUnbox::New(alloc(), val, MIRType::String, MUnbox::Fallible, Bailout_NonStringInputInvalidate); current->add(ins); current->rewriteAtDepth(-1, ins); @@ -3577,11 +3577,11 @@ IonBuilder::replaceTypeSet(MDefinition* subject, TemporaryTypeSet* type, MTest* ins->toFilterTypeSet()->setResultType(intersect->getKnownMIRType()); ins->toFilterTypeSet()->setResultTypeSet(intersect); - if (ins->type() == MIRType_Undefined) + if (ins->type() == MIRType::Undefined) current->setSlot(i, constant(UndefinedValue())); - else if (ins->type() == MIRType_Null) + else if (ins->type() == MIRType::Null) current->setSlot(i, constant(NullValue())); - else if (ins->type() == MIRType_MagicOptimizedArguments) + else if (ins->type() == MIRType::MagicOptimizedArguments) current->setSlot(i, constant(MagicValue(JS_OPTIMIZED_ARGUMENTS))); else MOZ_ASSERT(!IsMagicType(ins->type())); @@ -3602,11 +3602,11 @@ IonBuilder::replaceTypeSet(MDefinition* subject, TemporaryTypeSet* type, MTest* // instruction doesn't have an AliasSet. replace->setDependency(test); - if (replace->type() == MIRType_Undefined) + if (replace->type() == MIRType::Undefined) replace = constant(UndefinedValue()); - else if (replace->type() == MIRType_Null) + else if (replace->type() == MIRType::Null) replace = constant(NullValue()); - else if (replace->type() == MIRType_MagicOptimizedArguments) + else if (replace->type() == MIRType::MagicOptimizedArguments) replace = constant(MagicValue(JS_OPTIMIZED_ARGUMENTS)); else MOZ_ASSERT(!IsMagicType(ins->type())); @@ -3704,7 +3704,7 @@ IonBuilder::improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* t MTypeOf* typeOf = ins->lhs()->isTypeOf() ? ins->lhs()->toTypeOf() : ins->rhs()->toTypeOf(); MConstant* constant = ins->lhs()->isConstant() ? ins->lhs()->toConstant() : ins->rhs()->toConstant(); - if (constant->type() != MIRType_String) + if (constant->type() != MIRType::String) return true; bool equal = ins->jsop() == JSOP_EQ || ins->jsop() == JSOP_STRICTEQ; @@ -3723,7 +3723,7 @@ IonBuilder::improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* t // Create temporary typeset equal to the type if there is no resultTypeSet. TemporaryTypeSet tmp; if (!inputTypes) { - if (subject->type() == MIRType_Value) + if (subject->type() == MIRType::Value) return true; inputTypes = &tmp; tmp.addType(TypeSet::PrimitiveType(ValueTypeFromMIRType(subject->type())), alloc_->lifoAlloc()); @@ -3805,7 +3805,7 @@ IonBuilder::improveTypesAtNullOrUndefinedCompare(MCompare* ins, bool trueBranch, // Create temporary typeset equal to the type if there is no resultTypeSet. TemporaryTypeSet tmp; if (!inputTypes) { - if (subject->type() == MIRType_Value) + if (subject->type() == MIRType::Value) return true; inputTypes = &tmp; tmp.addType(TypeSet::PrimitiveType(ValueTypeFromMIRType(subject->type())), alloc_->lifoAlloc()); @@ -3869,7 +3869,7 @@ IonBuilder::improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test) // Create temporary typeset equal to the type if there is no resultTypeSet. TemporaryTypeSet tmp; if (!oldType) { - if (subject->type() == MIRType_Value) + if (subject->type() == MIRType::Value) return true; oldType = &tmp; tmp.addType(TypeSet::PrimitiveType(ValueTypeFromMIRType(subject->type())), alloc_->lifoAlloc()); @@ -3948,7 +3948,7 @@ IonBuilder::improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test) // Create temporary typeset equal to the type if there is no resultTypeSet. TemporaryTypeSet tmp; if (!oldType) { - if (ins->type() == MIRType_Value) + if (ins->type() == MIRType::Value) return true; oldType = &tmp; tmp.addType(TypeSet::PrimitiveType(ValueTypeFromMIRType(ins->type())), alloc_->lifoAlloc()); @@ -4636,11 +4636,11 @@ IonBuilder::bitnotTrySpecialized(bool* emitted, MDefinition* input) // Try to emit a specialized bitnot instruction based on the input type // of the operand. - if (input->mightBeType(MIRType_Object) || input->mightBeType(MIRType_Symbol)) + if (input->mightBeType(MIRType::Object) || input->mightBeType(MIRType::Symbol)) return true; MBitNot* ins = MBitNot::New(alloc(), input); - ins->setSpecialization(MIRType_Int32); + ins->setSpecialization(MIRType::Int32); current->add(ins); current->push(ins); @@ -4754,18 +4754,18 @@ IonBuilder::binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left, MDef trackOptimizationAttempt(TrackedStrategy::BinaryArith_Concat); // Make sure one of the inputs is a string. - if (left->type() != MIRType_String && right->type() != MIRType_String) { + if (left->type() != MIRType::String && right->type() != MIRType::String) { trackOptimizationOutcome(TrackedOutcome::OperandNotString); return true; } // The none-string input (if present) should be atleast a numerical type. // Which we can easily coerce to string. - if (right->type() != MIRType_String && !IsNumberType(right->type())) { + if (right->type() != MIRType::String && !IsNumberType(right->type())) { trackOptimizationOutcome(TrackedOutcome::OperandNotStringOrNumber); return true; } - if (left->type() != MIRType_String && !IsNumberType(left->type())) { + if (left->type() != MIRType::String && !IsNumberType(left->type())) { trackOptimizationOutcome(TrackedOutcome::OperandNotStringOrNumber); return true; } @@ -4791,27 +4791,27 @@ IonBuilder::powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* pow MIRType baseType = base->type(); MIRType powerType = power->type(); - if (outputType != MIRType_Int32 && outputType != MIRType_Double) + if (outputType != MIRType::Int32 && outputType != MIRType::Double) return true; if (!IsNumberType(baseType)) return true; if (!IsNumberType(powerType)) return true; - if (powerType == MIRType_Float32) - powerType = MIRType_Double; + if (powerType == MIRType::Float32) + powerType = MIRType::Double; MPow* pow = MPow::New(alloc(), base, power, powerType); current->add(pow); output = pow; // Cast to the right type - if (outputType == MIRType_Int32 && output->type() != MIRType_Int32) { + if (outputType == MIRType::Int32 && output->type() != MIRType::Int32) { MToInt32* toInt = MToInt32::New(alloc(), output); current->add(toInt); output = toInt; } - if (outputType == MIRType_Double && output->type() != MIRType_Double) { + if (outputType == MIRType::Double && output->type() != MIRType::Double) { MToDouble* toDouble = MToDouble::New(alloc(), output); current->add(toDouble); output = toDouble; @@ -4825,12 +4825,12 @@ IonBuilder::powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* pow static inline bool SimpleArithOperand(MDefinition* op) { - return !op->mightBeType(MIRType_Object) - && !op->mightBeType(MIRType_String) - && !op->mightBeType(MIRType_Symbol) - && !op->mightBeType(MIRType_MagicOptimizedArguments) - && !op->mightBeType(MIRType_MagicHole) - && !op->mightBeType(MIRType_MagicIsConstructing); + return !op->mightBeType(MIRType::Object) + && !op->mightBeType(MIRType::String) + && !op->mightBeType(MIRType::Symbol) + && !op->mightBeType(MIRType::MagicOptimizedArguments) + && !op->mightBeType(MIRType::MagicHole) + && !op->mightBeType(MIRType::MagicIsConstructing); } bool @@ -4886,7 +4886,7 @@ IonBuilder::binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, trackOptimizationAttempt(TrackedStrategy::BinaryArith_SpecializedOnBaselineTypes); MIRType specialization = inspector->expectedBinaryArithSpecialization(pc); - if (specialization == MIRType_None) { + if (specialization == MIRType::None) { trackOptimizationOutcome(TrackedOutcome::NoTypeInfo); return true; } @@ -5025,15 +5025,15 @@ IonBuilder::jsop_pow() bool emitted = false; if (!forceInlineCaches()) { - if (!powTrySpecialized(&emitted, base, exponent, MIRType_Double) || emitted) + if (!powTrySpecialized(&emitted, base, exponent, MIRType::Double) || emitted) return emitted; } if (!arithTrySharedStub(&emitted, JSOP_POW, base, exponent) || emitted) return emitted; - // For now, use MIRType_Double, as a safe cover-all. See bug 1188079. - MPow* pow = MPow::New(alloc(), base, exponent, MIRType_Double); + // For now, use MIRType::Double, as a safe cover-all. See bug 1188079. + MPow* pow = MPow::New(alloc(), base, exponent, MIRType::Double); current->add(pow); current->push(pow); return true; @@ -5074,7 +5074,7 @@ IonBuilder::jsop_neg() bool IonBuilder::jsop_tostring() { - if (current->peek(-1)->type() == MIRType_String) + if (current->peek(-1)->type() == MIRType::String) return true; MDefinition* value = current->pop(); @@ -5152,9 +5152,9 @@ IonBuilder::inlineScriptedCall(CallInfo& callInfo, JSFunction* target) return false; MTypeBarrier* barrier = MTypeBarrier::New(alloc(), callInfo.thisArg(), clonedTypes); current->add(barrier); - if (barrier->type() == MIRType_Undefined) + if (barrier->type() == MIRType::Undefined) callInfo.setThis(constant(UndefinedValue())); - else if (barrier->type() == MIRType_Null) + else if (barrier->type() == MIRType::Null) callInfo.setThis(constant(NullValue())); else callInfo.setThis(barrier); @@ -5248,12 +5248,12 @@ IonBuilder::patchInlinedReturn(CallInfo& callInfo, MBasicBlock* exit, MBasicBloc // Constructors must be patched by the caller to always return an object. if (callInfo.constructing()) { - if (rdef->type() == MIRType_Value) { + if (rdef->type() == MIRType::Value) { // Unknown return: dynamically detect objects. MReturnFromCtor* filter = MReturnFromCtor::New(alloc(), rdef, callInfo.thisArg()); exit->add(filter); rdef = filter; - } else if (rdef->type() != MIRType_Object) { + } else if (rdef->type() != MIRType::Object) { // Known non-object return: force |this|. rdef = callInfo.thisArg(); } @@ -5294,17 +5294,17 @@ IonBuilder::specializeInlinedReturn(MDefinition* rdef, MBasicBlock* exit) } else { MIRType observedType = types->getKnownMIRType(); - // Don't specialize if type is MIRType_Float32 and TI reports - // MIRType_Double. Float is more specific than double. - if (observedType == MIRType_Double && rdef->type() == MIRType_Float32) + // Don't specialize if type is MIRType::Float32 and TI reports + // MIRType::Double. Float is more specific than double. + if (observedType == MIRType::Double && rdef->type() == MIRType::Float32) return rdef; - // Don't specialize if types are inaccordance, except for MIRType_Value - // and MIRType_Object (when not unknown object), since the typeset + // Don't specialize if types are inaccordance, except for MIRType::Value + // and MIRType::Object (when not unknown object), since the typeset // contains more specific information. if (observedType == rdef->type() && - observedType != MIRType_Value && - (observedType != MIRType_Object || types->unknownObject())) + observedType != MIRType::Value && + (observedType != MIRType::Object || types->unknownObject())) { return rdef; } @@ -5559,7 +5559,7 @@ IonBuilder::selectInliningTargets(const ObjectVector& targets, CallInfo& callInf static bool CanInlineGetPropertyCache(MGetPropertyCache* cache, MDefinition* thisDef) { - MOZ_ASSERT(cache->object()->type() == MIRType_Object); + MOZ_ASSERT(cache->object()->type() == MIRType::Object); if (cache->object() != thisDef) return false; @@ -5640,11 +5640,11 @@ IonBuilder::getInlineableGetPropertyCache(CallInfo& callInfo) return nullptr; MDefinition* thisDef = callInfo.thisArg(); - if (thisDef->type() != MIRType_Object) + if (thisDef->type() != MIRType::Object) return nullptr; MDefinition* funcDef = callInfo.fun(); - if (funcDef->type() != MIRType_Object) + if (funcDef->type() != MIRType::Object) return nullptr; // MGetPropertyCache with no uses may be optimized away. @@ -5654,12 +5654,12 @@ IonBuilder::getInlineableGetPropertyCache(CallInfo& callInfo) } // Optimize away the following common pattern: - // MTypeBarrier[MIRType_Object] <- MGetPropertyCache + // MTypeBarrier[MIRType::Object] <- MGetPropertyCache if (funcDef->isTypeBarrier()) { MTypeBarrier* barrier = funcDef->toTypeBarrier(); if (barrier->hasUses()) return nullptr; - if (barrier->type() != MIRType_Object) + if (barrier->type() != MIRType::Object) return nullptr; if (!barrier->input()->isGetPropertyCache()) return nullptr; @@ -5861,7 +5861,7 @@ IonBuilder::inlineObjectGroupFallback(CallInfo& callInfo, MBasicBlock* dispatchB getPropBlock->push(cache); } else { MTypeBarrier* barrier = callInfo.fun()->toTypeBarrier(); - MOZ_ASSERT(barrier->type() == MIRType_Object); + MOZ_ASSERT(barrier->type() == MIRType::Object); MOZ_ASSERT(barrier->input()->isGetPropertyCache()); MOZ_ASSERT(barrier->input()->toGetPropertyCache() == cache); @@ -6080,7 +6080,7 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVec } else { MTypeBarrier* barrier = callInfo.fun()->toTypeBarrier(); MOZ_ASSERT(!barrier->hasUses()); - MOZ_ASSERT(barrier->type() == MIRType_Object); + MOZ_ASSERT(barrier->type() == MIRType::Object); MOZ_ASSERT(barrier->input()->isGetPropertyCache()); MOZ_ASSERT(barrier->input()->toGetPropertyCache() == maybeCache); barrier->block()->discard(barrier); @@ -6490,14 +6490,14 @@ IonBuilder::jsop_funapply(uint32_t argc) // to be either definitely |arguments| or definitely not |arguments|. MDefinition* argument = current->peek(-1); if (script()->argumentsHasVarBinding() && - argument->mightBeType(MIRType_MagicOptimizedArguments) && - argument->type() != MIRType_MagicOptimizedArguments) + argument->mightBeType(MIRType::MagicOptimizedArguments) && + argument->type() != MIRType::MagicOptimizedArguments) { return abort("fun.apply with MaybeArguments"); } // Fallback to regular call if arg 2 is not definitely |arguments|. - if (argument->type() != MIRType_MagicOptimizedArguments) { + if (argument->type() != MIRType::MagicOptimizedArguments) { // Optimize fun.apply(self, array) if the length is sane and there are no holes. TemporaryTypeSet* objTypes = argument->resultTypeSet(); if (native && native->isNative() && native->native() == fun_apply && @@ -6748,14 +6748,14 @@ ArgumentTypesMatch(MDefinition* def, StackTypeSet* calleeTypes) return false; if (def->resultTypeSet()) { - MOZ_ASSERT(def->type() == MIRType_Value || def->mightBeType(def->type())); + MOZ_ASSERT(def->type() == MIRType::Value || def->mightBeType(def->type())); return def->resultTypeSet()->isSubset(calleeTypes); } - if (def->type() == MIRType_Value) + if (def->type() == MIRType::Value) return false; - if (def->type() == MIRType_Object) + if (def->type() == MIRType::Object) return calleeTypes->unknownObject(); return calleeTypes->mightBeMIRType(def->type()); @@ -6780,7 +6780,7 @@ IonBuilder::testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo) return true; } for (size_t i = callInfo.argc(); i < target->nargs(); i++) { - if (!TypeScript::ArgTypes(targetScript, i)->mightBeMIRType(MIRType_Undefined)) + if (!TypeScript::ArgTypes(targetScript, i)->mightBeMIRType(MIRType::Undefined)) return true; } @@ -6807,7 +6807,7 @@ IonBuilder::makeCallHelper(JSFunction* target, CallInfo& callInfo) // MCall accordingly. TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet(); if (thisTypes && - thisTypes->getKnownMIRType() == MIRType_Object && + thisTypes->getKnownMIRType() == MIRType::Object && thisTypes->isDOMClass(constraints()) && testShouldDOMCall(thisTypes, target, JSJitInfo::Method)) { @@ -6943,7 +6943,7 @@ IonBuilder::jsop_eval(uint32_t argc) // Direct eval acts as identity on non-string types according to // ES5 15.1.2.1 step 1. - if (!string->mightBeType(MIRType_String)) { + if (!string->mightBeType(MIRType::String)) { current->push(string); TemporaryTypeSet* types = bytecodeTypes(pc); return pushTypeBarrier(string, types, BarrierKind::TypeSet); @@ -6957,7 +6957,7 @@ IonBuilder::jsop_eval(uint32_t argc) // name on the scope chain and the eval is performing a call on that // value. Use a dynamic scope chain lookup rather than a full eval. if (string->isConcat() && - string->getOperand(1)->type() == MIRType_String && + string->getOperand(1)->type() == MIRType::String && string->getOperand(1)->maybeConstantValue()) { JSAtom* atom = &string->getOperand(1)->maybeConstantValue()->toString()->asAtom(); @@ -7031,13 +7031,13 @@ static bool ObjectOrSimplePrimitive(MDefinition* op) { // Return true if op is either undefined/null/boolean/int32 or an object. - return !op->mightBeType(MIRType_String) - && !op->mightBeType(MIRType_Symbol) - && !op->mightBeType(MIRType_Double) - && !op->mightBeType(MIRType_Float32) - && !op->mightBeType(MIRType_MagicOptimizedArguments) - && !op->mightBeType(MIRType_MagicHole) - && !op->mightBeType(MIRType_MagicIsConstructing); + return !op->mightBeType(MIRType::String) + && !op->mightBeType(MIRType::Symbol) + && !op->mightBeType(MIRType::Double) + && !op->mightBeType(MIRType::Float32) + && !op->mightBeType(MIRType::MagicOptimizedArguments) + && !op->mightBeType(MIRType::MagicHole) + && !op->mightBeType(MIRType::MagicIsConstructing); } bool @@ -7057,13 +7057,13 @@ IonBuilder::compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDe // Some compare types need to have the specific type in the rhs. // Swap operands if that is not the case. - if (type == MCompare::Compare_StrictString && right->type() != MIRType_String) + if (type == MCompare::Compare_StrictString && right->type() != MIRType::String) ins->swapOperands(); - else if (type == MCompare::Compare_Null && right->type() != MIRType_Null) + else if (type == MCompare::Compare_Null && right->type() != MIRType::Null) ins->swapOperands(); - else if (type == MCompare::Compare_Undefined && right->type() != MIRType_Undefined) + else if (type == MCompare::Compare_Undefined && right->type() != MIRType::Undefined) ins->swapOperands(); - else if (type == MCompare::Compare_Boolean && right->type() != MIRType_Boolean) + else if (type == MCompare::Compare_Boolean && right->type() != MIRType::Boolean) ins->swapOperands(); // Replace inputs with unsigned variants if needed. @@ -7105,26 +7105,26 @@ IonBuilder::compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefini // Undefined compared loosy to Null is not supported, // because tag is different, but value can be the same (undefined == null). - if ((left->mightBeType(MIRType_Undefined) && right->mightBeType(MIRType_Null)) || - (left->mightBeType(MIRType_Null) && right->mightBeType(MIRType_Undefined))) + if ((left->mightBeType(MIRType::Undefined) && right->mightBeType(MIRType::Null)) || + (left->mightBeType(MIRType::Null) && right->mightBeType(MIRType::Undefined))) { return true; } // Int32 compared loosy to Boolean is not supported, // because tag is different, but value can be the same (1 == true). - if ((left->mightBeType(MIRType_Int32) && right->mightBeType(MIRType_Boolean)) || - (left->mightBeType(MIRType_Boolean) && right->mightBeType(MIRType_Int32))) + if ((left->mightBeType(MIRType::Int32) && right->mightBeType(MIRType::Boolean)) || + (left->mightBeType(MIRType::Boolean) && right->mightBeType(MIRType::Int32))) { return true; } // For loosy comparison of an object with a Boolean/Number/String // the valueOf the object is taken. Therefore not supported. - bool simpleLHS = left->mightBeType(MIRType_Boolean) || left->mightBeType(MIRType_Int32); - bool simpleRHS = right->mightBeType(MIRType_Boolean) || right->mightBeType(MIRType_Int32); - if ((left->mightBeType(MIRType_Object) && simpleRHS) || - (right->mightBeType(MIRType_Object) && simpleLHS)) + bool simpleLHS = left->mightBeType(MIRType::Boolean) || left->mightBeType(MIRType::Int32); + bool simpleRHS = right->mightBeType(MIRType::Boolean) || right->mightBeType(MIRType::Int32); + if ((left->mightBeType(MIRType::Object) && simpleRHS) || + (right->mightBeType(MIRType::Object) && simpleLHS)) { return true; } @@ -7191,7 +7191,7 @@ IonBuilder::compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDef if (!resumeAfter(stub)) return false; - MUnbox* unbox = MUnbox::New(alloc(), current->pop(), MIRType_Boolean, MUnbox::Infallible); + MUnbox* unbox = MUnbox::New(alloc(), current->pop(), MIRType::Boolean, MUnbox::Infallible); current->add(unbox); current->push(unbox); @@ -7471,7 +7471,7 @@ IonBuilder::jsop_initelem_array() else unboxedType = initializer->group()->unboxedLayout().elementType(); } - if (value->type() == MIRType_MagicHole) { + if (value->type() == MIRType::MagicHole) { if (!initializer->hasFlags(constraints(), OBJECT_FLAG_NON_PACKED)) needStub = true; } else if (!initializer->unknownProperties()) { @@ -7844,7 +7844,7 @@ IonBuilder::newOsrPreheader(MBasicBlock* predecessor, jsbytecode* loopEntry, jsb for (uint32_t i = info().startArgSlot(); i < osrBlock->stackDepth(); i++) { MDefinition* existing = current->getSlot(i); MDefinition* def = osrBlock->getSlot(i); - MOZ_ASSERT_IF(!needsArgsObj || !info().isSlotAliasedAtOsr(i), def->type() == MIRType_Value); + MOZ_ASSERT_IF(!needsArgsObj || !info().isSlotAliasedAtOsr(i), def->type() == MIRType::Value); // Aliased slots are never accessed, since they need to go through // the callobject. No need to type them here. @@ -8009,7 +8009,7 @@ IonBuilder::maybeInsertResume() void IonBuilder::maybeMarkEmpty(MDefinition* ins) { - MOZ_ASSERT(ins->type() == MIRType_Value); + MOZ_ASSERT(ins->type() == MIRType::Value); // When one of the operands has no type information, mark the output // as having no possible types too. This is to avoid degrading @@ -8137,29 +8137,29 @@ IonBuilder::testSingletonPropertyTypes(MDefinition* obj, jsid id) return testSingletonProperty(objectSingleton, id); MIRType objType = obj->type(); - if (objType == MIRType_Value && types) + if (objType == MIRType::Value && types) objType = types->getKnownMIRType(); JSProtoKey key; switch (objType) { - case MIRType_String: + case MIRType::String: key = JSProto_String; break; - case MIRType_Symbol: + case MIRType::Symbol: key = JSProto_Symbol; break; - case MIRType_Int32: - case MIRType_Double: + case MIRType::Int32: + case MIRType::Double: key = JSProto_Number; break; - case MIRType_Boolean: + case MIRType::Boolean: key = JSProto_Boolean; break; - case MIRType_Object: { + case MIRType::Object: { if (!types) return nullptr; @@ -8216,7 +8216,7 @@ bool IonBuilder::testNotDefinedProperty(MDefinition* obj, jsid id) { TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject() || types->getKnownMIRType() != MIRType_Object) + if (!types || types->unknownObject() || types->getKnownMIRType() != MIRType::Object) return false; for (unsigned i = 0, count = types->getObjectCount(); i < count; i++) { @@ -8304,9 +8304,9 @@ IonBuilder::addTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, Barrier if (pbarrier) *pbarrier = barrier; - if (barrier->type() == MIRType_Undefined) + if (barrier->type() == MIRType::Undefined) return constant(UndefinedValue()); - if (barrier->type() == MIRType_Null) + if (barrier->type() == MIRType::Null) return constant(NullValue()); return barrier; @@ -8320,7 +8320,7 @@ IonBuilder::pushDOMTypeBarrier(MInstruction* ins, TemporaryTypeSet* observed, JS const JSJitInfo* jitinfo = func->jitInfo(); bool barrier = DOMCallNeedsBarrier(jitinfo, observed); // Need to be a bit careful: if jitinfo->returnType is JSVAL_TYPE_DOUBLE but - // types->getKnownMIRType() is MIRType_Int32, then don't unconditionally + // types->getKnownMIRType() is MIRType::Int32, then don't unconditionally // unbox as a double. Instead, go ahead and barrier on having an int type, // since we know we need a barrier anyway due to the type mismatch. This is // the only situation in which TI actually has more information about the @@ -8328,7 +8328,7 @@ IonBuilder::pushDOMTypeBarrier(MInstruction* ins, TemporaryTypeSet* observed, JS // JSVAL_TYPE_UNKNOWN. MDefinition* replace = ins; if (jitinfo->returnType() != JSVAL_TYPE_DOUBLE || - observed->getKnownMIRType() != MIRType_Int32) { + observed->getKnownMIRType() != MIRType::Int32) { replace = ensureDefiniteType(ins, MIRTypeFromValueType(jitinfo->returnType())); if (replace != ins) { current->pop(); @@ -8347,22 +8347,22 @@ IonBuilder::ensureDefiniteType(MDefinition* def, MIRType definiteType) { MInstruction* replace; switch (definiteType) { - case MIRType_Undefined: + case MIRType::Undefined: def->setImplicitlyUsedUnchecked(); replace = MConstant::New(alloc(), UndefinedValue()); break; - case MIRType_Null: + case MIRType::Null: def->setImplicitlyUsedUnchecked(); replace = MConstant::New(alloc(), NullValue()); break; - case MIRType_Value: + case MIRType::Value: return def; default: { - if (def->type() != MIRType_Value) { - if (def->type() == MIRType_Int32 && definiteType == MIRType_Double) { + if (def->type() != MIRType::Value) { + if (def->type() == MIRType::Int32 && definiteType == MIRType::Double) { replace = MToDouble::New(alloc(), def); break; } @@ -8394,7 +8394,7 @@ IonBuilder::ensureDefiniteTypeSet(MDefinition* def, TemporaryTypeSet* types) // Don't replace if input type is more accurate than given typeset. if (def->type() != types->getKnownMIRType()) { - MOZ_ASSERT(types->getKnownMIRType() == MIRType_Value); + MOZ_ASSERT(types->getKnownMIRType() == MIRType::Value); return def; } @@ -8525,9 +8525,9 @@ IonBuilder::loadStaticSlot(JSObject* staticObject, BarrierKind barrier, Temporar if (barrier == BarrierKind::NoBarrier) { // Try to inline properties that can only have one value. MIRType knownType = types->getKnownMIRType(); - if (knownType == MIRType_Undefined) + if (knownType == MIRType::Undefined) return pushConstant(UndefinedValue()); - if (knownType == MIRType_Null) + if (knownType == MIRType::Null) return pushConstant(NullValue()); } @@ -8535,7 +8535,7 @@ IonBuilder::loadStaticSlot(JSObject* staticObject, BarrierKind barrier, Temporar MIRType rvalType = types->getKnownMIRType(); if (barrier != BarrierKind::NoBarrier) - rvalType = MIRType_Value; + rvalType = MIRType::Value; return loadSlot(obj, slot, NumFixedSlots(staticObject), rvalType, barrier, types); } @@ -8546,7 +8546,7 @@ jit::NeedsPostBarrier(MDefinition* value) { if (!GetJitContext()->runtime->gcNursery().exists()) return false; - return value->mightBeType(MIRType_Object); + return value->mightBeType(MIRType::Object); } bool @@ -8596,9 +8596,9 @@ IonBuilder::setStaticName(JSObject* staticObject, PropertyName* name) // If the property has a known type, we may be able to optimize typed stores by not // storing the type tag. - MIRType slotType = MIRType_None; + MIRType slotType = MIRType::None; MIRType knownType = property.knownMIRType(constraints()); - if (knownType != MIRType_Value) + if (knownType != MIRType::Value) slotType = knownType; bool needsBarrier = property.needsBarrier(constraints()); @@ -8811,13 +8811,13 @@ GetElemKnownType(bool needsHoleCheck, TemporaryTypeSet* types) // comment in IsPhiObservable), we just add an untyped load instruction // and rely on pushTypeBarrier and DCE to replace it with a null/undefined // constant. - if (knownType == MIRType_Undefined || knownType == MIRType_Null) - knownType = MIRType_Value; + if (knownType == MIRType::Undefined || knownType == MIRType::Null) + knownType = MIRType::Value; // Different architectures may want typed element reads which require // hole checks to be done as either value or typed reads. if (needsHoleCheck && !LIRGenerator::allowTypedElementHoleCheck()) - knownType = MIRType_Value; + knownType = MIRType::Value; return knownType; } @@ -8849,7 +8849,7 @@ IonBuilder::jsop_getelem() } obj = maybeUnboxForPropertyAccess(obj); - if (obj->type() == MIRType_Object) + if (obj->type() == MIRType::Object) obj = convertUnboxedObjects(obj); bool emitted = false; @@ -8889,7 +8889,7 @@ IonBuilder::jsop_getelem() return emitted; } - if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType_MagicOptimizedArguments)) + if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType::MagicOptimizedArguments)) return abort("Type is not definitely lazy arguments."); trackOptimizationAttempt(TrackedStrategy::GetElem_InlineCache); @@ -8943,7 +8943,7 @@ IonBuilder::getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* switch (elemPrediction.kind()) { case type::Simd: - // FIXME (bug 894105): load into a MIRType_float32x4 etc + // FIXME (bug 894105): load into a MIRType::float32x4 etc trackOptimizationOutcome(TrackedOutcome::GenericFailure); return true; @@ -9443,7 +9443,7 @@ IonBuilder::getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index { MOZ_ASSERT(*emitted == false); - if (obj->type() != MIRType_String || !IsNumberType(index->type())) { + if (obj->type() != MIRType::String || !IsNumberType(index->type())) { trackOptimizationOutcome(TrackedOutcome::AccessNotString); return true; } @@ -9485,7 +9485,7 @@ IonBuilder::getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* in if (inliningDepth_ > 0) return true; - if (obj->type() != MIRType_MagicOptimizedArguments) + if (obj->type() != MIRType::MagicOptimizedArguments) return true; // Emit GetFrameArgument. @@ -9529,7 +9529,7 @@ IonBuilder::getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinit if (inliningDepth_ == 0) return true; - if (obj->type() != MIRType_MagicOptimizedArguments) + if (obj->type() != MIRType::MagicOptimizedArguments) return true; // Emit inlined arguments. @@ -9539,7 +9539,7 @@ IonBuilder::getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinit // When the id is constant, we can just return the corresponding inlined argument MConstant* indexConst = index->maybeConstantValue(); - if (indexConst && indexConst->type() == MIRType_Int32) { + if (indexConst && indexConst->type() == MIRType::Int32) { MOZ_ASSERT(inliningDepth_ > 0); int32_t id = indexConst->toInt32(); @@ -9565,21 +9565,21 @@ IonBuilder::getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index) MOZ_ASSERT(*emitted == false); // Make sure we have at least an object. - if (!obj->mightBeType(MIRType_Object)) { + if (!obj->mightBeType(MIRType::Object)) { trackOptimizationOutcome(TrackedOutcome::NotObject); return true; } // Don't cache for strings. - if (obj->mightBeType(MIRType_String)) { + if (obj->mightBeType(MIRType::String)) { trackOptimizationOutcome(TrackedOutcome::GetElemStringNotCached); return true; } // Index should be integer, string, or symbol - if (!index->mightBeType(MIRType_Int32) && - !index->mightBeType(MIRType_String) && - !index->mightBeType(MIRType_Symbol)) + if (!index->mightBeType(MIRType::Int32) && + !index->mightBeType(MIRType::String) && + !index->mightBeType(MIRType::Symbol)) { trackOptimizationOutcome(TrackedOutcome::IndexType); return true; @@ -9588,7 +9588,7 @@ IonBuilder::getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index) // Turn off cacheing if the element is int32 and we've seen non-native objects as the target // of this getelem. bool nonNativeGetElement = inspector->hasSeenNonNativeGetElement(pc); - if (index->mightBeType(MIRType_Int32) && nonNativeGetElement) { + if (index->mightBeType(MIRType::Int32) && nonNativeGetElement) { trackOptimizationOutcome(TrackedOutcome::NonNativeReceiver); return true; } @@ -9601,7 +9601,7 @@ IonBuilder::getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index) // Always add a barrier if the index might be a string or symbol, so that // the cache can attach stubs for particular properties. - if (index->mightBeType(MIRType_String) || index->mightBeType(MIRType_Symbol)) + if (index->mightBeType(MIRType::String) || index->mightBeType(MIRType::Symbol)) barrier = BarrierKind::TypeSet; MGetPropertyCache* ins = MGetPropertyCache::New(alloc(), obj, index, @@ -9613,11 +9613,11 @@ IonBuilder::getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index) return false; // Spice up type information. - if (index->type() == MIRType_Int32 && barrier == BarrierKind::NoBarrier) { + if (index->type() == MIRType::Int32 && barrier == BarrierKind::NoBarrier) { bool needHoleCheck = !ElementAccessIsPacked(constraints(), obj); MIRType knownType = GetElemKnownType(needHoleCheck, types); - if (knownType != MIRType_Value && knownType != MIRType_Double) + if (knownType != MIRType::Value && knownType != MIRType::Double) ins->setResultType(knownType); } @@ -9673,7 +9673,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType { TemporaryTypeSet* types = bytecodeTypes(pc); - MOZ_ASSERT(index->type() == MIRType_Int32 || index->type() == MIRType_Double); + MOZ_ASSERT(index->type() == MIRType::Int32 || index->type() == MIRType::Double); if (JSOp(*pc) == JSOP_CALLELEM) { // Indexed call on an element of an array. Populate the observed types // with any objects that could be in the array, to avoid extraneous @@ -9692,7 +9692,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType types->hasType(TypeSet::UndefinedType()) && !ElementAccessHasExtraIndexedProperty(this, obj); - MIRType knownType = MIRType_Value; + MIRType knownType = MIRType::Value; if (unboxedType == JSVAL_TYPE_MAGIC && barrier == BarrierKind::NoBarrier) knownType = GetElemKnownType(needsHoleCheck, types); @@ -9728,7 +9728,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType barrier == BarrierKind::NoBarrier && loopDepth_ && inBounds && - knownType == MIRType_Double && + knownType == MIRType::Double && objTypes && objTypes->convertDoubleElements(constraints()) == TemporaryTypeSet::AlwaysConvertToDoubles; if (loadDouble) @@ -9760,10 +9760,10 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType // If maybeUndefined was true, the typeset must have undefined, and // then either additional types or a barrier. This means we should // never have a typed version of LoadElementHole. - MOZ_ASSERT(knownType == MIRType_Value); + MOZ_ASSERT(knownType == MIRType::Value); } - if (knownType != MIRType_Value) { + if (knownType != MIRType::Value) { load->setResultType(knownType); load->setResultTypeSet(types); } @@ -9777,7 +9777,7 @@ IonBuilder::addArrayBufferByteLength(MDefinition* obj) { MLoadFixedSlot* ins = MLoadFixedSlot::New(alloc(), obj, ArrayBufferObject::BYTE_LENGTH_SLOT); current->add(ins); - ins->setResultType(MIRType_Int32); + ins->setResultType(MIRType::Int32); return ins; } @@ -9792,7 +9792,7 @@ IonBuilder::addTypedArrayLengthAndData(MDefinition* obj, JSObject* tarr = nullptr; if (MConstant* objConst = obj->maybeConstantValue()) { - if (objConst->type() == MIRType_Object) + if (objConst->type() == MIRType::Object) tarr = &objConst->toObject(); } else if (TemporaryTypeSet* types = obj->resultTypeSet()) { tarr = types->maybeSingleton(); @@ -9854,7 +9854,7 @@ IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition* id, // If the index is an already shifted constant, undo the shift to get the // absolute offset being accessed. if (MConstant* idConst = id->maybeConstantValue()) { - if (idConst->type() == MIRType_Int32) { + if (idConst->type() == MIRType::Int32) { int32_t index = idConst->toInt32(); MConstant* offset = MConstant::New(alloc(), Int32Value(index << TypedArrayShift(viewType))); current->add(offset); @@ -9866,7 +9866,7 @@ IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition* id, return nullptr; MConstant* shiftAmount = id->toRsh()->rhs()->maybeConstantValue(); - if (!shiftAmount || shiftAmount->type() != MIRType_Int32) + if (!shiftAmount || shiftAmount->type() != MIRType::Int32) return nullptr; if (uint32_t(shiftAmount->toInt32()) != TypedArrayShift(viewType)) return nullptr; @@ -10011,7 +10011,7 @@ IonBuilder::jsop_setelem() } if (script()->argumentsHasVarBinding() && - object->mightBeType(MIRType_MagicOptimizedArguments) && + object->mightBeType(MIRType::MagicOptimizedArguments) && info().analysisMode() != Analysis_ArgumentsUsage) { return abort("Type is not definitely lazy arguments."); @@ -10056,7 +10056,7 @@ IonBuilder::setElemTryTypedObject(bool* emitted, MDefinition* obj, switch (elemPrediction.kind()) { case type::Simd: - // FIXME (bug 894105): store a MIRType_float32x4 etc + // FIXME (bug 894105): store a MIRType::float32x4 etc trackOptimizationOutcome(TrackedOutcome::GenericFailure); return true; @@ -10236,7 +10236,7 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object, // If AmbiguousDoubleConversion, only handle int32 values for now. if (conversion == TemporaryTypeSet::AmbiguousDoubleConversion && - value->type() != MIRType_Int32) + value->type() != MIRType::Int32) { trackOptimizationOutcome(TrackedOutcome::ArrayDoubleConversion); return true; @@ -10264,7 +10264,7 @@ IonBuilder::setElemTryArguments(bool* emitted, MDefinition* object, { MOZ_ASSERT(*emitted == false); - if (object->type() != MIRType_MagicOptimizedArguments) + if (object->type() != MIRType::MagicOptimizedArguments) return true; // Arguments are not supported yet. @@ -10277,21 +10277,21 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object, { MOZ_ASSERT(*emitted == false); - if (!object->mightBeType(MIRType_Object)) { + if (!object->mightBeType(MIRType::Object)) { trackOptimizationOutcome(TrackedOutcome::NotObject); return true; } - if (!index->mightBeType(MIRType_Int32) && - !index->mightBeType(MIRType_String) && - !index->mightBeType(MIRType_Symbol)) + if (!index->mightBeType(MIRType::Int32) && + !index->mightBeType(MIRType::String) && + !index->mightBeType(MIRType::Symbol)) { trackOptimizationOutcome(TrackedOutcome::IndexType); return true; } bool barrier = true; - bool indexIsInt32 = index->type() == MIRType_Int32; + bool indexIsInt32 = index->type() == MIRType::Int32; if (indexIsInt32 && !PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, @@ -10338,7 +10338,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, MDefinition* obj, MDefinition* id, MDefinition* value, JSValueType unboxedType, bool writeHole) { - MIRType elementType = MIRType_None; + MIRType elementType = MIRType::None; if (unboxedType == JSVAL_TYPE_MAGIC) elementType = DenseNativeElementType(constraints(), obj); bool packed = ElementAccessIsPacked(constraints(), obj); @@ -10374,7 +10374,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, } case TemporaryTypeSet::AmbiguousDoubleConversion: { - MOZ_ASSERT(value->type() == MIRType_Int32); + MOZ_ASSERT(value->type() == MIRType::Int32); MInstruction* maybeDouble = MMaybeToDoubleElement::New(alloc(), elements, value); current->add(maybeDouble); newValue = maybeDouble; @@ -10427,7 +10427,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), JSID_VOID)) common->setNeedsBarrier(); - if (elementType != MIRType_None && packed) + if (elementType != MIRType::None && packed) common->setElementType(elementType); } @@ -10495,7 +10495,7 @@ IonBuilder::jsop_length_fastPath() { TemporaryTypeSet* types = bytecodeTypes(pc); - if (types->getKnownMIRType() != MIRType_Int32) + if (types->getKnownMIRType() != MIRType::Int32) return false; MDefinition* obj = current->peek(-1); @@ -10503,8 +10503,8 @@ IonBuilder::jsop_length_fastPath() if (shouldAbortOnPreliminaryGroups(obj)) return false; - if (obj->mightBeType(MIRType_String)) { - if (obj->mightBeType(MIRType_Object)) + if (obj->mightBeType(MIRType::String)) { + if (obj->mightBeType(MIRType::Object)) return false; current->pop(); MStringLength* ins = MStringLength::New(alloc(), obj); @@ -10513,7 +10513,7 @@ IonBuilder::jsop_length_fastPath() return true; } - if (obj->mightBeType(MIRType_Object)) { + if (obj->mightBeType(MIRType::Object)) { TemporaryTypeSet* objTypes = obj->resultTypeSet(); // Compute the length for array objects. @@ -10700,16 +10700,16 @@ IonBuilder::jsop_checkobjcoercible() { MDefinition* toCheck = current->peek(-1); - if (!toCheck->mightBeType(MIRType_Undefined) && - !toCheck->mightBeType(MIRType_Null)) + if (!toCheck->mightBeType(MIRType::Undefined) && + !toCheck->mightBeType(MIRType::Null)) { toCheck->setImplicitlyUsedUnchecked(); return true; } - MOZ_ASSERT(toCheck->type() == MIRType_Value || - toCheck->type() == MIRType_Null || - toCheck->type() == MIRType_Undefined); + MOZ_ASSERT(toCheck->type() == MIRType::Value || + toCheck->type() == MIRType::Null || + toCheck->type() == MIRType::Undefined); // If we want to squeeze more perf here, we can throw without checking, // if IsNullOrUndefined(toCheck->type()). Since this is a failure case, @@ -11154,7 +11154,7 @@ IonBuilder::loadSlot(MDefinition* obj, Shape* shape, MIRType rvalType, bool IonBuilder::storeSlot(MDefinition* obj, size_t slot, size_t nfixed, MDefinition* value, bool needsBarrier, - MIRType slotType /* = MIRType_None */) + MIRType slotType /* = MIRType::None */) { if (slot < nfixed) { MStoreFixedSlot* store = MStoreFixedSlot::New(alloc(), obj, slot, value); @@ -11173,14 +11173,14 @@ IonBuilder::storeSlot(MDefinition* obj, size_t slot, size_t nfixed, current->push(value); if (needsBarrier) store->setNeedsBarrier(); - if (slotType != MIRType_None) + if (slotType != MIRType::None) store->setSlotType(slotType); return resumeAfter(store); } bool IonBuilder::storeSlot(MDefinition* obj, Shape* shape, MDefinition* value, bool needsBarrier, - MIRType slotType /* = MIRType_None */) + MIRType slotType /* = MIRType::None */) { MOZ_ASSERT(shape->writable()); return storeSlot(obj, shape->slot(), shape->numFixedSlots(), value, needsBarrier, slotType); @@ -11220,11 +11220,11 @@ IonBuilder::shouldAbortOnPreliminaryGroups(MDefinition *obj) MDefinition* IonBuilder::maybeUnboxForPropertyAccess(MDefinition* def) { - if (def->type() != MIRType_Value) + if (def->type() != MIRType::Value) return def; MIRType type = inspector->expectedPropertyAccessInputType(pc); - if (type == MIRType_Value || !def->mightBeType(type)) + if (type == MIRType::Value || !def->mightBeType(type)) return def; MUnbox* unbox = MUnbox::New(alloc(), def, type, MUnbox::Fallible); @@ -11279,7 +11279,7 @@ IonBuilder::jsop_getprop(PropertyName* name) } obj = maybeUnboxForPropertyAccess(obj); - if (obj->type() == MIRType_Object) + if (obj->type() == MIRType::Object) obj = convertUnboxedObjects(obj); BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), @@ -11417,8 +11417,8 @@ IonBuilder::improveThisTypesForCall() // Ensure |this| has types {object, null/undefined}. MDefinition* thisDef = current->peek(-2); - if (thisDef->type() != MIRType_Value || - !thisDef->mightBeType(MIRType_Object) || + if (thisDef->type() != MIRType::Value || + !thisDef->mightBeType(MIRType::Object) || !thisDef->resultTypeSet() || !thisDef->resultTypeSet()->objectOrSentinel()) { @@ -11444,9 +11444,9 @@ IonBuilder::improveThisTypesForCall() bool IonBuilder::checkIsDefinitelyOptimizedArguments(MDefinition* obj, bool* isOptimizedArgs) { - if (obj->type() != MIRType_MagicOptimizedArguments) { + if (obj->type() != MIRType::MagicOptimizedArguments) { if (script()->argumentsHasVarBinding() && - obj->mightBeType(MIRType_MagicOptimizedArguments)) + obj->mightBeType(MIRType::MagicOptimizedArguments)) { return abort("Type is not definitely lazy arguments."); } @@ -11560,7 +11560,7 @@ IonBuilder::getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, Tempora { MOZ_ASSERT(*emitted == false); - if (!types->mightBeMIRType(MIRType_Object)) { + if (!types->mightBeMIRType(MIRType::Object)) { // If we have not observed an object result here, don't look for a // singleton constant. trackOptimizationOutcome(TrackedOutcome::NotObject); @@ -11588,7 +11588,7 @@ IonBuilder::getPropTryNotDefined(bool* emitted, MDefinition* obj, jsid id, Tempo { MOZ_ASSERT(*emitted == false); - if (!types->mightBeMIRType(MIRType_Undefined)) { + if (!types->mightBeMIRType(MIRType::Undefined)) { // Only optimize if we expect this property access to return undefined. trackOptimizationOutcome(TrackedOutcome::NotUndefined); return true; @@ -11620,7 +11620,7 @@ IonBuilder::getPropTryTypedObject(bool* emitted, switch (fieldPrediction.kind()) { case type::Simd: - // FIXME (bug 894104): load into a MIRType_float32x4 etc + // FIXME (bug 894104): load into a MIRType::float32x4 etc return true; case type::Struct: @@ -11773,7 +11773,7 @@ IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName if (slot == UINT32_MAX) return true; - if (obj->type() != MIRType_Object) { + if (obj->type() != MIRType::Object) { MGuardObject* guard = MGuardObject::New(alloc(), obj); current->add(guard); obj = guard; @@ -11871,20 +11871,20 @@ IonBuilder::loadUnboxedValue(MDefinition* elements, size_t elementsOffset, case JSVAL_TYPE_BOOLEAN: load = MLoadUnboxedScalar::New(alloc(), elements, index, Scalar::Uint8, DoesNotRequireMemoryBarrier, elementsOffset); - load->setResultType(MIRType_Boolean); + load->setResultType(MIRType::Boolean); break; case JSVAL_TYPE_INT32: load = MLoadUnboxedScalar::New(alloc(), elements, index, Scalar::Int32, DoesNotRequireMemoryBarrier, elementsOffset); - load->setResultType(MIRType_Int32); + load->setResultType(MIRType::Int32); break; case JSVAL_TYPE_DOUBLE: load = MLoadUnboxedScalar::New(alloc(), elements, index, Scalar::Float64, DoesNotRequireMemoryBarrier, elementsOffset, /* canonicalizeDoubles = */ false); - load->setResultType(MIRType_Double); + load->setResultType(MIRType::Double); break; case JSVAL_TYPE_STRING: @@ -11921,7 +11921,7 @@ IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* nam if (offset == UINT32_MAX) return true; - if (obj->type() != MIRType_Object) { + if (obj->type() != MIRType::Object) { MGuardObject* guard = MGuardObject::New(alloc(), obj); current->add(guard); obj = guard; @@ -12037,7 +12037,7 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName } // Don't call the getter with a primitive value. - if (obj->type() != MIRType_Object) { + if (obj->type() != MIRType::Object) { MGuardObject* guardObj = MGuardObject::New(alloc(), obj); current->add(guardObj); obj = guardObj; @@ -12164,7 +12164,7 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName MIRType rvalType = types->getKnownMIRType(); if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) - rvalType = MIRType_Value; + rvalType = MIRType::Value; if (receivers.length() == 1) { if (!receivers[0].group) { @@ -12276,7 +12276,7 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name, // The input value must either be an object, or we should have strong suspicions // that it can be safely unboxed to an object. - if (obj->type() != MIRType_Object) { + if (obj->type() != MIRType::Object) { TemporaryTypeSet* types = obj->resultTypeSet(); if (!types || !types->objectOrSentinel()) { trackOptimizationOutcome(TrackedOutcome::NoTypeInfo); @@ -12305,7 +12305,7 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name, barrier == BarrierKind::TypeSet); // Try to mark the cache as idempotent. - if (obj->type() == MIRType_Object && !invalidatedIdempotentCache()) { + if (obj->type() == MIRType::Object && !invalidatedIdempotentCache()) { if (PropertyReadIsIdempotent(constraints(), obj, name)) load->setIdempotent(); } @@ -12336,7 +12336,7 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name, MIRType rvalType = types->getKnownMIRType(); if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) - rvalType = MIRType_Value; + rvalType = MIRType::Value; load->setResultType(rvalType); if (!pushTypeBarrier(load, types, barrier)) @@ -12386,7 +12386,7 @@ IonBuilder::tryInnerizeWindow(MDefinition* obj) // Callers should be careful not to pass the inner object to getters or // setters that require outerization. - if (obj->type() != MIRType_Object) + if (obj->type() != MIRType::Object) return obj; TemporaryTypeSet* types = obj->resultTypeSet(); @@ -12575,7 +12575,7 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj, } // Don't call the setter with a primitive value. - if (obj->type() != MIRType_Object) { + if (obj->type() != MIRType::Object) { MGuardObject* guardObj = MGuardObject::New(alloc(), obj); current->add(guardObj); obj = guardObj; @@ -12673,7 +12673,7 @@ IonBuilder::setPropTryTypedObject(bool* emitted, MDefinition* obj, switch (fieldPrediction.kind()) { case type::Simd: - // FIXME (bug 894104): store into a MIRType_float32x4 etc + // FIXME (bug 894104): store into a MIRType::float32x4 etc return true; case type::Reference: @@ -12848,10 +12848,10 @@ IonBuilder::storeUnboxedValue(MDefinition* obj, MDefinition* elements, int32_t e break; case JSVAL_TYPE_OBJECT: - MOZ_ASSERT(value->type() == MIRType_Object || - value->type() == MIRType_Null || - value->type() == MIRType_Value); - MOZ_ASSERT(!value->mightBeType(MIRType_Undefined), + MOZ_ASSERT(value->type() == MIRType::Object || + value->type() == MIRType::Null || + value->type() == MIRType::Value); + MOZ_ASSERT(!value->mightBeType(MIRType::Undefined), "MToObjectOrNull slow path is invalid for unboxed objects"); store = MStoreUnboxedObjectOrNull::New(alloc(), elements, scaledOffset, value, obj, elementsOffset, preBarrier); @@ -12882,7 +12882,7 @@ IonBuilder::setPropTryUnboxed(bool* emitted, MDefinition* obj, if (offset == UINT32_MAX) return true; - if (obj->type() != MIRType_Object) { + if (obj->type() != MIRType::Object) { MGuardObject* guard = MGuardObject::New(alloc(), obj); current->add(guard); obj = guard; @@ -13215,10 +13215,10 @@ IonBuilder::jsop_setarg(uint32_t arg) MOZ_ASSERT(op->resultTypeSet() == &argTypes[arg]); argTypes[arg].addType(TypeSet::UnknownType(), alloc_->lifoAlloc()); if (val->isMul()) { - val->setResultType(MIRType_Double); - val->toMul()->setSpecialization(MIRType_Double); + val->setResultType(MIRType::Double); + val->toMul()->setSpecialization(MIRType::Double); } else { - MOZ_ASSERT(val->type() == MIRType_Int32); + MOZ_ASSERT(val->type() == MIRType::Int32); } val->setResultTypeSet(nullptr); } @@ -13336,7 +13336,7 @@ IonBuilder::jsop_functionthis() return true; } - if (thisTypes && (thisTypes->getKnownMIRType() == MIRType_Object || + if (thisTypes && (thisTypes->getKnownMIRType() == MIRType::Object || (thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject()))) { // This is safe, because if the entry type of |this| is an object, it @@ -13357,7 +13357,7 @@ IonBuilder::jsop_functionthis() // Hard case: |this| may be a primitive we have to wrap. MDefinition* def = current->getSlot(info().thisSlot()); - if (def->type() == MIRType_Object) { + if (def->type() == MIRType::Object) { current->push(def); return true; } @@ -13404,7 +13404,7 @@ bool IonBuilder::jsop_toid() { // No-op if the index is an integer. - if (current->peek(-1)->type() == MIRType_Int32) + if (current->peek(-1)->type() == MIRType::Int32) return true; MDefinition* index = current->pop(); @@ -13762,7 +13762,7 @@ IonBuilder::tryFoldInstanceOf(MDefinition* lhs, JSObject* protoObject) { // Try to fold the js::IsDelegate part of the instanceof operation. - if (!lhs->mightBeType(MIRType_Object)) { + if (!lhs->mightBeType(MIRType::Object)) { // If the lhs is a primitive, the result is false. lhs->setImplicitlyUsedUnchecked(); pushConstant(BooleanValue(false)); @@ -13797,7 +13797,7 @@ IonBuilder::tryFoldInstanceOf(MDefinition* lhs, JSObject* protoObject) } } - if (knownIsInstance && lhsTypes->getKnownMIRType() != MIRType_Object) { + if (knownIsInstance && lhsTypes->getKnownMIRType() != MIRType::Object) { // The result is true for all objects, but the lhs might be a primitive. // We can't fold this completely but we can use a much faster IsObject // test. @@ -14063,7 +14063,7 @@ TypedObjectPrediction IonBuilder::typedObjectPrediction(TemporaryTypeSet* types) { // Type set must be known to be an object. - if (!types || types->getKnownMIRType() != MIRType_Object) + if (!types || types->getKnownMIRType() != MIRType::Object) return TypedObjectPrediction(); // And only known objects. @@ -14113,7 +14113,7 @@ IonBuilder::loadTypedObjectData(MDefinition* typedObj, MDefinition** owner, LinearSum* ownerOffset) { - MOZ_ASSERT(typedObj->type() == MIRType_Object); + MOZ_ASSERT(typedObj->type() == MIRType::Object); // Shortcircuit derived type objects, meaning the intermediate // objects created to represent `a.b` in an expression like @@ -14186,7 +14186,7 @@ IonBuilder::loadTypedObjectElements(MDefinition* typedObj, } else { MDefinition* unscaledOffset = ConvertLinearSum(alloc(), current, ownerByteOffset); *ownerScaledOffset = MDiv::NewAsmJS(alloc(), unscaledOffset, constantInt(scale), - MIRType_Int32, /* unsigned = */ false); + MIRType::Int32, /* unsigned = */ false); current->add((*ownerScaledOffset)->toInstruction()); } } @@ -14231,7 +14231,7 @@ IonBuilder::typeObjectForElementFromArrayStructType(MDefinition* typeObj) MInstruction* elemType = MLoadFixedSlot::New(alloc(), typeObj, JS_DESCR_SLOT_ARRAY_ELEM_TYPE); current->add(elemType); - MInstruction* unboxElemType = MUnbox::New(alloc(), elemType, MIRType_Object, MUnbox::Infallible); + MInstruction* unboxElemType = MUnbox::New(alloc(), elemType, MIRType::Object, MUnbox::Infallible); current->add(unboxElemType); return unboxElemType; @@ -14246,7 +14246,7 @@ IonBuilder::typeObjectForFieldFromStructType(MDefinition* typeObj, MInstruction* fieldTypes = MLoadFixedSlot::New(alloc(), typeObj, JS_DESCR_SLOT_STRUCT_FIELD_TYPES); current->add(fieldTypes); - MInstruction* unboxFieldTypes = MUnbox::New(alloc(), fieldTypes, MIRType_Object, MUnbox::Infallible); + MInstruction* unboxFieldTypes = MUnbox::New(alloc(), fieldTypes, MIRType::Object, MUnbox::Infallible); current->add(unboxFieldTypes); // Index into list with index of field. @@ -14259,7 +14259,7 @@ IonBuilder::typeObjectForFieldFromStructType(MDefinition* typeObj, MInstruction* fieldType = MLoadElement::New(alloc(), fieldTypesElements, fieldIndexDef, false, false); current->add(fieldType); - MInstruction* unboxFieldType = MUnbox::New(alloc(), fieldType, MIRType_Object, MUnbox::Infallible); + MInstruction* unboxFieldType = MUnbox::New(alloc(), fieldType, MIRType::Object, MUnbox::Infallible); current->add(unboxFieldType); return unboxFieldType; @@ -14307,7 +14307,7 @@ IonBuilder::storeReferenceTypedObjectValue(MDefinition* typedObj, MOZ_ASSERT(type == ReferenceTypeDescr::TYPE_ANY || type == ReferenceTypeDescr::TYPE_OBJECT); MIRType implicitType = - (type == ReferenceTypeDescr::TYPE_ANY) ? MIRType_Undefined : MIRType_Null; + (type == ReferenceTypeDescr::TYPE_ANY) ? MIRType::Undefined : MIRType::Null; if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &typedObj, name, &value, /* canModify = */ true, implicitType)) @@ -14442,7 +14442,7 @@ IonBuilder::addLexicalCheck(MDefinition* input) MInstruction* lexicalCheck; // If we're guaranteed to not be JS_UNINITIALIZED_LEXICAL, no need to check. - if (input->type() == MIRType_MagicUninitializedLexical) { + if (input->type() == MIRType::MagicUninitializedLexical) { // Mark the input as implicitly used so the JS_UNINITIALIZED_LEXICAL // magic value will be preserved on bailout. input->setImplicitlyUsedUnchecked(); @@ -14453,7 +14453,7 @@ IonBuilder::addLexicalCheck(MDefinition* input) return constant(UndefinedValue()); } - if (input->type() == MIRType_Value) { + if (input->type() == MIRType::Value) { lexicalCheck = MLexicalCheck::New(alloc(), input); current->add(lexicalCheck); if (failedLexicalCheck_) diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index a6729fb266..0fa6e53d54 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -416,9 +416,9 @@ class IonBuilder BarrierKind barrier, TemporaryTypeSet* types); bool storeSlot(MDefinition* obj, size_t slot, size_t nfixed, MDefinition* value, bool needsBarrier, - MIRType slotType = MIRType_None); + MIRType slotType = MIRType::None); bool storeSlot(MDefinition* obj, Shape* shape, MDefinition* value, bool needsBarrier, - MIRType slotType = MIRType_None); + MIRType slotType = MIRType::None); bool shouldAbortOnPreliminaryGroups(MDefinition *obj); MDefinition* tryInnerizeWindow(MDefinition* obj); @@ -842,6 +842,7 @@ class IonBuilder InliningStatus inlineIsRegExpObject(CallInfo& callInfo); InliningStatus inlineRegExpPrototypeOptimizable(CallInfo& callInfo); InliningStatus inlineRegExpInstanceOptimizable(CallInfo& callInfo); + InliningStatus inlineGetFirstDollarIndex(CallInfo& callInfo); // Object natives and intrinsics. InliningStatus inlineObjectCreate(CallInfo& callInfo); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 3974096f40..c8649231cd 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -779,7 +779,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, { if (output.hasValue()) { scratchReg = output.valueReg().scratchReg(); - } else if (output.type() == MIRType_Double) { + } else if (output.type() == MIRType::Double) { scratchReg = object; masm.push(scratchReg); restoreScratch = true; @@ -930,7 +930,7 @@ EmitGetterCall(JSContext* cx, MacroAssembler& masm, // Construct vp array: // Push object value for |this| - masm.Push(TypedOrValueRegister(MIRType_Object, AnyRegister(object))); + masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(object))); // Push callee/outparam. masm.Push(ObjectValue(*target)); @@ -1046,7 +1046,7 @@ EmitGetterCall(JSContext* cx, MacroAssembler& masm, for (size_t i = 0; i < target->nargs(); i++) masm.Push(UndefinedValue()); - masm.Push(TypedOrValueRegister(MIRType_Object, AnyRegister(object))); + masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(object))); masm.movePtr(ImmGCPtr(target), scratchReg); @@ -1157,7 +1157,7 @@ GenerateArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& if (output.hasValue()) { outReg = output.valueReg().scratchReg(); } else { - MOZ_ASSERT(output.type() == MIRType_Int32); + MOZ_ASSERT(output.type() == MIRType::Int32); outReg = output.typedReg().gpr(); } @@ -1190,7 +1190,7 @@ GenerateUnboxedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAt if (output.hasValue()) { outReg = output.valueReg().scratchReg(); } else { - MOZ_ASSERT(output.type() == MIRType_Int32); + MOZ_ASSERT(output.type() == MIRType::Int32); outReg = output.typedReg().gpr(); } MOZ_ASSERT(object != outReg); @@ -1225,7 +1225,7 @@ GenerateTypedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta if (output.hasValue()) { tmpReg = output.valueReg().scratchReg(); } else { - MOZ_ASSERT(output.type() == MIRType_Int32); + MOZ_ASSERT(output.type() == MIRType::Int32); tmpReg = output.typedReg().gpr(); } MOZ_ASSERT(object != tmpReg); @@ -1255,7 +1255,7 @@ IsCacheableArrayLength(JSContext* cx, HandleObject obj, TypedOrValueRegister out if (!obj->is()) return false; - if (output.type() != MIRType_Value && output.type() != MIRType_Int32) { + if (output.type() != MIRType::Value && output.type() != MIRType::Int32) { // The stub assumes that we always output Int32, so make sure our output // is equipped to handle that. return false; @@ -1362,12 +1362,12 @@ EmitIdGuard(MacroAssembler& masm, jsid id, TypedOrValueRegister idReg, Register { MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SYMBOL(id)); - MOZ_ASSERT(idReg.type() == MIRType_String || - idReg.type() == MIRType_Symbol || - idReg.type() == MIRType_Value); + MOZ_ASSERT(idReg.type() == MIRType::String || + idReg.type() == MIRType::Symbol || + idReg.type() == MIRType::Value); Register payloadReg; - if (idReg.type() == MIRType_Value) { + if (idReg.type() == MIRType::Value) { ValueOperand val = idReg.valueReg(); if (JSID_IS_SYMBOL(id)) { masm.branchTestSymbol(Assembler::NotEqual, val, failures); @@ -1637,7 +1637,7 @@ GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript if (hasTypedArrayLengthStub(obj)) return true; - if (output().type() != MIRType_Value && output().type() != MIRType_Int32) { + if (output().type() != MIRType::Value && output().type() != MIRType::Int32) { // The next execution should cause an invalidation because the type // does not fit. return true; @@ -1990,7 +1990,7 @@ GetPropertyIC::tryAttachArgumentsLength(JSContext* cx, HandleScript outerScript, return true; MIRType outputType = output().type(); - if (!(outputType == MIRType_Value || outputType == MIRType_Int32)) + if (!(outputType == MIRType::Value || outputType == MIRType::Int32)) return true; if (hasArgumentsLengthStub(obj->is())) @@ -2010,7 +2010,7 @@ GetPropertyIC::tryAttachArgumentsLength(JSContext* cx, HandleScript outerScript, if (output().hasValue()) { tmpReg = output().valueReg().scratchReg(); } else { - MOZ_ASSERT(output().type() == MIRType_Int32); + MOZ_ASSERT(output().type() == MIRType::Int32); tmpReg = output().typedReg().gpr(); } MOZ_ASSERT(object() != tmpReg); @@ -2073,7 +2073,7 @@ GenerateReadModuleNamespace(JSContext* cx, IonScript* ion, MacroAssembler& masm, if (output.hasValue()) { scratchReg = output.valueReg().scratchReg(); - } else if (output.type() == MIRType_Double) { + } else if (output.type() == MIRType::Double) { masm.push(object); scratchReg = object; restoreScratch = true; @@ -2387,7 +2387,7 @@ GenerateSetSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att Address addr(object, NativeObject::getFixedSlotOffset(shape->slot())); if (cx->zone()->needsIncrementalBarrier()) - masm.callPreBarrier(addr, MIRType_Value); + masm.callPreBarrier(addr, MIRType::Value); masm.storeConstantOrRegister(value, addr); } else { @@ -2396,7 +2396,7 @@ GenerateSetSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att Address addr(tempReg, obj->as().dynamicSlotIndex(shape->slot()) * sizeof(Value)); if (cx->zone()->needsIncrementalBarrier()) - masm.callPreBarrier(addr, MIRType_Value); + masm.callPreBarrier(addr, MIRType::Value); masm.storeConstantOrRegister(value, addr); } @@ -2755,7 +2755,7 @@ GenerateCallSetter(JSContext* cx, IonScript* ion, MacroAssembler& masm, // Build vp and move the base into argVpReg. masm.Push(value); - masm.Push(TypedOrValueRegister(MIRType_Object, AnyRegister(object))); + masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(object))); masm.Push(ObjectValue(*target)); masm.moveStackPtrTo(argVpReg); @@ -2883,7 +2883,7 @@ GenerateCallSetter(JSContext* cx, IonScript* ion, MacroAssembler& masm, for (size_t i = 1; i < target->nargs(); i++) masm.Push(UndefinedValue()); masm.Push(value); - masm.Push(TypedOrValueRegister(MIRType_Object, AnyRegister(object))); + masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(object))); masm.movePtr(ImmGCPtr(target), tempReg); @@ -3116,7 +3116,7 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att // Write the object or expando object's new shape. Address shapeAddr(object, JSObject::offsetOfShape()); if (cx->zone()->needsIncrementalBarrier()) - masm.callPreBarrier(shapeAddr, MIRType_Shape); + masm.callPreBarrier(shapeAddr, MIRType::Shape); masm.storePtr(ImmGCPtr(newShape), shapeAddr); if (oldGroup != obj->group()) { @@ -3135,7 +3135,7 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att Address groupAddr(object, JSObject::offsetOfGroup()); if (cx->zone()->needsIncrementalBarrier()) - masm.callPreBarrier(groupAddr, MIRType_ObjectGroup); + masm.callPreBarrier(groupAddr, MIRType::ObjectGroup); masm.storePtr(ImmGCPtr(obj->group()), groupAddr); masm.bind(&noTypeChange); @@ -3209,7 +3209,7 @@ CanInlineSetPropTypeCheck(JSObject* obj, jsid id, ConstantOrRegister val, bool* // TIs handling of objects is complicated enough to warrant a runtime // check, as we can't statically handle the case where the typeset // contains the specific object, but doesn't have ANYOBJECT set. - if (reg.hasTyped() && reg.type() != MIRType_Object) { + if (reg.hasTyped() && reg.type() != MIRType::Object) { JSValueType valType = ValueTypeFromMIRType(reg.type()); if (!propTypes->hasType(TypeSet::PrimitiveType(valType))) return false; @@ -3380,9 +3380,9 @@ GenerateSetUnboxed(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& if (cx->zone()->needsIncrementalBarrier()) { if (unboxedType == JSVAL_TYPE_OBJECT) - masm.callPreBarrier(address, MIRType_Object); + masm.callPreBarrier(address, MIRType::Object); else if (unboxedType == JSVAL_TYPE_STRING) - masm.callPreBarrier(address, MIRType_String); + masm.callPreBarrier(address, MIRType::String); else MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType)); } @@ -3937,7 +3937,7 @@ GenerateDenseElementHole(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta indexReg = scratchReg; masm.unboxInt32(val, indexReg); } else { - MOZ_ASSERT(index.type() == MIRType_Int32); + MOZ_ASSERT(index.type() == MIRType::Int32); indexReg = index.typedReg().gpr(); } @@ -4209,7 +4209,7 @@ GetPropertyIC::tryAttachArgumentsElement(JSContext* cx, HandleScript outerScript return true; TypedOrValueRegister index = id().reg(); - if (index.type() != MIRType_Value && index.type() != MIRType_Int32) + if (index.type() != MIRType::Value && index.type() != MIRType::Int32) return true; MOZ_ASSERT(output().hasValue()); @@ -4244,7 +4244,7 @@ GetPropertyIC::tryAttachArgumentsElement(JSContext* cx, HandleScript outerScript masm.unboxInt32(val, indexReg); masm.branch32(Assembler::AboveOrEqual, indexReg, tmpReg, &failureRestoreIndex); } else { - MOZ_ASSERT(index.type() == MIRType_Int32); + MOZ_ASSERT(index.type() == MIRType::Int32); indexReg = index.typedReg().gpr(); masm.branch32(Assembler::AboveOrEqual, indexReg, tmpReg, &failures); } @@ -4379,7 +4379,7 @@ StoreDenseElement(MacroAssembler& masm, ConstantOrRegister value, Register eleme } TypedOrValueRegister reg = value.reg(); - if (reg.hasTyped() && reg.type() != MIRType_Int32) { + if (reg.hasTyped() && reg.type() != MIRType::Int32) { masm.storeTypedOrValue(reg, target); return; } @@ -4398,7 +4398,7 @@ StoreDenseElement(MacroAssembler& masm, ConstantOrRegister value, Register eleme masm.int32ValueToDouble(reg.valueReg(), ScratchDoubleReg); masm.storeDouble(ScratchDoubleReg, target); } else { - MOZ_ASSERT(reg.type() == MIRType_Int32); + MOZ_ASSERT(reg.type() == MIRType::Int32); masm.convertInt32ToDouble(reg.typedReg().gpr(), ScratchDoubleReg); masm.storeDouble(ScratchDoubleReg, target); } @@ -4494,7 +4494,7 @@ GenerateSetDenseElement(JSContext* cx, MacroAssembler& masm, IonCache::StubAttac } if (cx->zone()->needsIncrementalBarrier()) - masm.callPreBarrier(target, MIRType_Value); + masm.callPreBarrier(target, MIRType::Value); // Store the value. if (guardHoles) @@ -5056,4 +5056,3 @@ NameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, Handl return true; } - diff --git a/js/src/jit/IonOptimizationLevels.h b/js/src/jit/IonOptimizationLevels.h index df6d3211e7..4de47267f4 100644 --- a/js/src/jit/IonOptimizationLevels.h +++ b/js/src/jit/IonOptimizationLevels.h @@ -215,6 +215,10 @@ class OptimizationInfo return eliminateRedundantChecks_; } + bool flowAliasAnalysisEnabled() const { + return !JitOptions.disableFlowAA; + } + IonRegisterAllocator registerAllocator() const { if (JitOptions.forcedRegisterAllocator.isSome()) return JitOptions.forcedRegisterAllocator.ref(); diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h index 2955a01440..abcbabbac5 100644 --- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -388,41 +388,41 @@ class SimdConstant { // The ordering of this enumeration is important: Anything < Value is a // specialized type. Furthermore, anything < String has trivial conversion to // a number. -enum MIRType +enum class MIRType { - MIRType_Undefined, - MIRType_Null, - MIRType_Boolean, - MIRType_Int32, - MIRType_Int64, - MIRType_Double, - MIRType_Float32, + Undefined, + Null, + Boolean, + Int32, + Int64, + Double, + Float32, // Types above have trivial conversion to a number. - MIRType_String, - MIRType_Symbol, + String, + Symbol, // Types above are primitive (including undefined and null). - MIRType_Object, - MIRType_MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value. - MIRType_MagicOptimizedOut, // JS_OPTIMIZED_OUT magic value. - MIRType_MagicHole, // JS_ELEMENTS_HOLE magic value. - MIRType_MagicIsConstructing, // JS_IS_CONSTRUCTING magic value. - MIRType_MagicUninitializedLexical, // JS_UNINITIALIZED_LEXICAL magic value. + Object, + MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value. + MagicOptimizedOut, // JS_OPTIMIZED_OUT magic value. + MagicHole, // JS_ELEMENTS_HOLE magic value. + MagicIsConstructing, // JS_IS_CONSTRUCTING magic value. + MagicUninitializedLexical, // JS_UNINITIALIZED_LEXICAL magic value. // Types above are specialized. - MIRType_Value, - MIRType_SinCosDouble, // Optimizing a sin/cos to sincos. - MIRType_ObjectOrNull, - MIRType_None, // Invalid, used as a placeholder. - MIRType_Slots, // A slots vector - MIRType_Elements, // An elements vector - MIRType_Pointer, // An opaque pointer that receives no special treatment - MIRType_Shape, // A Shape pointer. - MIRType_ObjectGroup, // An ObjectGroup pointer. - MIRType_Last = MIRType_ObjectGroup, - MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT), + Value, + SinCosDouble, // Optimizing a sin/cos to sincos. + ObjectOrNull, + None, // Invalid, used as a placeholder. + Slots, // A slots vector + Elements, // An elements vector + Pointer, // An opaque pointer that receives no special treatment + Shape, // A Shape pointer. + ObjectGroup, // An ObjectGroup pointer. + Last = ObjectGroup, + Float32x4 = Float32 | (2 << VECTOR_SCALE_SHIFT), // Representing both SIMD.Int32x4 and SIMD.Uint32x4. - MIRType_Int32x4 = MIRType_Int32 | (2 << VECTOR_SCALE_SHIFT), - MIRType_Bool32x4 = MIRType_Boolean | (2 << VECTOR_SCALE_SHIFT), - MIRType_Doublex2 = MIRType_Double | (1 << VECTOR_SCALE_SHIFT) + Int32x4 = Int32 | (2 << VECTOR_SCALE_SHIFT), + Bool32x4 = Boolean | (2 << VECTOR_SCALE_SHIFT), + Doublex2 = Double | (1 << VECTOR_SCALE_SHIFT) }; static inline MIRType @@ -432,23 +432,23 @@ MIRTypeFromValueType(JSValueType type) // filtered out in MIRTypeFromValue. switch (type) { case JSVAL_TYPE_DOUBLE: - return MIRType_Double; + return MIRType::Double; case JSVAL_TYPE_INT32: - return MIRType_Int32; + return MIRType::Int32; case JSVAL_TYPE_UNDEFINED: - return MIRType_Undefined; + return MIRType::Undefined; case JSVAL_TYPE_STRING: - return MIRType_String; + return MIRType::String; case JSVAL_TYPE_SYMBOL: - return MIRType_Symbol; + return MIRType::Symbol; case JSVAL_TYPE_BOOLEAN: - return MIRType_Boolean; + return MIRType::Boolean; case JSVAL_TYPE_NULL: - return MIRType_Null; + return MIRType::Null; case JSVAL_TYPE_OBJECT: - return MIRType_Object; + return MIRType::Object; case JSVAL_TYPE_UNKNOWN: - return MIRType_Value; + return MIRType::Value; default: MOZ_CRASH("unexpected jsval type"); } @@ -458,29 +458,29 @@ static inline JSValueType ValueTypeFromMIRType(MIRType type) { switch (type) { - case MIRType_Undefined: + case MIRType::Undefined: return JSVAL_TYPE_UNDEFINED; - case MIRType_Null: + case MIRType::Null: return JSVAL_TYPE_NULL; - case MIRType_Boolean: + case MIRType::Boolean: return JSVAL_TYPE_BOOLEAN; - case MIRType_Int32: + case MIRType::Int32: return JSVAL_TYPE_INT32; - case MIRType_Float32: // Fall through, there's no JSVAL for Float32 - case MIRType_Double: + case MIRType::Float32: // Fall through, there's no JSVAL for Float32 + case MIRType::Double: return JSVAL_TYPE_DOUBLE; - case MIRType_String: + case MIRType::String: return JSVAL_TYPE_STRING; - case MIRType_Symbol: + case MIRType::Symbol: return JSVAL_TYPE_SYMBOL; - case MIRType_MagicOptimizedArguments: - case MIRType_MagicOptimizedOut: - case MIRType_MagicHole: - case MIRType_MagicIsConstructing: - case MIRType_MagicUninitializedLexical: + case MIRType::MagicOptimizedArguments: + case MIRType::MagicOptimizedOut: + case MIRType::MagicHole: + case MIRType::MagicIsConstructing: + case MIRType::MagicUninitializedLexical: return JSVAL_TYPE_MAGIC; default: - MOZ_ASSERT(type == MIRType_Object); + MOZ_ASSERT(type == MIRType::Object); return JSVAL_TYPE_OBJECT; } } @@ -495,61 +495,61 @@ static inline const char* StringFromMIRType(MIRType type) { switch (type) { - case MIRType_Undefined: + case MIRType::Undefined: return "Undefined"; - case MIRType_Null: + case MIRType::Null: return "Null"; - case MIRType_Boolean: + case MIRType::Boolean: return "Bool"; - case MIRType_Int32: + case MIRType::Int32: return "Int32"; - case MIRType_Int64: + case MIRType::Int64: return "Int64"; - case MIRType_Double: + case MIRType::Double: return "Double"; - case MIRType_Float32: + case MIRType::Float32: return "Float32"; - case MIRType_String: + case MIRType::String: return "String"; - case MIRType_Symbol: + case MIRType::Symbol: return "Symbol"; - case MIRType_Object: + case MIRType::Object: return "Object"; - case MIRType_MagicOptimizedArguments: + case MIRType::MagicOptimizedArguments: return "MagicOptimizedArguments"; - case MIRType_MagicOptimizedOut: + case MIRType::MagicOptimizedOut: return "MagicOptimizedOut"; - case MIRType_MagicHole: + case MIRType::MagicHole: return "MagicHole"; - case MIRType_MagicIsConstructing: + case MIRType::MagicIsConstructing: return "MagicIsConstructing"; - case MIRType_MagicUninitializedLexical: + case MIRType::MagicUninitializedLexical: return "MagicUninitializedLexical"; - case MIRType_Value: + case MIRType::Value: return "Value"; - case MIRType_SinCosDouble: + case MIRType::SinCosDouble: return "SinCosDouble"; - case MIRType_ObjectOrNull: + case MIRType::ObjectOrNull: return "ObjectOrNull"; - case MIRType_None: + case MIRType::None: return "None"; - case MIRType_Slots: + case MIRType::Slots: return "Slots"; - case MIRType_Elements: + case MIRType::Elements: return "Elements"; - case MIRType_Pointer: + case MIRType::Pointer: return "Pointer"; - case MIRType_Shape: + case MIRType::Shape: return "Shape"; - case MIRType_ObjectGroup: + case MIRType::ObjectGroup: return "ObjectGroup"; - case MIRType_Float32x4: + case MIRType::Float32x4: return "Float32x4"; - case MIRType_Int32x4: + case MIRType::Int32x4: return "Int32x4"; - case MIRType_Bool32x4: + case MIRType::Bool32x4: return "Bool32x4"; - case MIRType_Doublex2: + case MIRType::Doublex2: return "Doublex2"; } MOZ_CRASH("Unknown MIRType."); @@ -558,70 +558,70 @@ StringFromMIRType(MIRType type) static inline bool IsNumberType(MIRType type) { - return type == MIRType_Int32 || - type == MIRType_Double || - type == MIRType_Float32 || - type == MIRType_Int64; + return type == MIRType::Int32 || + type == MIRType::Double || + type == MIRType::Float32 || + type == MIRType::Int64; } static inline bool IsTypeRepresentableAsDouble(MIRType type) { - return type == MIRType_Int32 || - type == MIRType_Double || - type == MIRType_Float32; + return type == MIRType::Int32 || + type == MIRType::Double || + type == MIRType::Float32; } static inline bool IsFloatType(MIRType type) { - return type == MIRType_Int32 || type == MIRType_Float32; + return type == MIRType::Int32 || type == MIRType::Float32; } static inline bool IsFloatingPointType(MIRType type) { - return type == MIRType_Double || type == MIRType_Float32; + return type == MIRType::Double || type == MIRType::Float32; } static inline bool IsNullOrUndefined(MIRType type) { - return type == MIRType_Null || type == MIRType_Undefined; + return type == MIRType::Null || type == MIRType::Undefined; } static inline bool IsSimdType(MIRType type) { - return type == MIRType_Int32x4 || type == MIRType_Float32x4 || type == MIRType_Bool32x4; + return type == MIRType::Int32x4 || type == MIRType::Float32x4 || type == MIRType::Bool32x4; } static inline bool IsFloatingPointSimdType(MIRType type) { - return type == MIRType_Float32x4; + return type == MIRType::Float32x4; } static inline bool IsIntegerSimdType(MIRType type) { - return type == MIRType_Int32x4; + return type == MIRType::Int32x4; } static inline bool IsBooleanSimdType(MIRType type) { - return type == MIRType_Bool32x4; + return type == MIRType::Bool32x4; } static inline bool IsMagicType(MIRType type) { - return type == MIRType_MagicHole || - type == MIRType_MagicOptimizedOut || - type == MIRType_MagicIsConstructing || - type == MIRType_MagicOptimizedArguments || - type == MIRType_MagicUninitializedLexical; + return type == MIRType::MagicHole || + type == MIRType::MagicOptimizedOut || + type == MIRType::MagicIsConstructing || + type == MIRType::MagicOptimizedArguments || + type == MIRType::MagicUninitializedLexical; } // Returns the number of vector elements (hereby called "length") for a given @@ -630,7 +630,7 @@ static inline unsigned SimdTypeToLength(MIRType type) { MOZ_ASSERT(IsSimdType(type)); - return 1 << ((type >> VECTOR_SCALE_SHIFT) & VECTOR_SCALE_MASK); + return 1 << ((unsigned(type) >> VECTOR_SCALE_SHIFT) & VECTOR_SCALE_MASK); } static inline MIRType @@ -644,15 +644,15 @@ ScalarTypeToMIRType(Scalar::Type type) case Scalar::Int32: case Scalar::Uint32: case Scalar::Uint8Clamped: - return MIRType_Int32; + return MIRType::Int32; case Scalar::Float32: - return MIRType_Float32; + return MIRType::Float32; case Scalar::Float64: - return MIRType_Double; + return MIRType::Double; case Scalar::Float32x4: - return MIRType_Float32x4; + return MIRType::Float32x4; case Scalar::Int32x4: - return MIRType_Int32x4; + return MIRType::Int32x4; case Scalar::MaxTypedArrayViewType: break; } @@ -688,9 +688,9 @@ static inline MIRType SimdTypeToLaneType(MIRType type) { MOZ_ASSERT(IsSimdType(type)); - static_assert(MIRType_Last <= ELEMENT_TYPE_MASK, + static_assert(unsigned(MIRType::Last) <= ELEMENT_TYPE_MASK, "ELEMENT_TYPE_MASK should be larger than the last MIRType"); - return MIRType((type >> ELEMENT_TYPE_SHIFT) & ELEMENT_TYPE_MASK); + return MIRType((unsigned(type) >> ELEMENT_TYPE_SHIFT) & ELEMENT_TYPE_MASK); } // Get the type expected when inserting a lane into a SIMD type. @@ -703,7 +703,7 @@ SimdTypeToLaneArgumentType(MIRType type) // Boolean lanes should be pre-converted to an Int32 with the values 0 or -1. // All other lane types are inserted directly. - return laneType == MIRType_Boolean ? MIRType_Int32 : laneType; + return laneType == MIRType::Boolean ? MIRType::Int32 : laneType; } // Indicates a lane in a SIMD register: X for the first lane, Y for the second, diff --git a/js/src/jit/JSONSpewer.cpp b/js/src/jit/JSONSpewer.cpp index 6d47d07a28..d6105f498b 100644 --- a/js/src/jit/JSONSpewer.cpp +++ b/js/src/jit/JSONSpewer.cpp @@ -234,7 +234,7 @@ JSONSpewer::spewMDef(MDefinition* def) if (def->isAdd() || def->isSub() || def->isMod() || def->isMul() || def->isDiv()) isTruncated = static_cast(def)->isTruncated(); - if (def->type() != MIRType_None && def->range()) { + if (def->type() != MIRType::None && def->range()) { beginStringProperty("type"); def->range()->dump(out_); out_.printf(" : %s%s", StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); diff --git a/js/src/jit/JitCompartment.h b/js/src/jit/JitCompartment.h index 436465d079..20bc8ca6fd 100644 --- a/js/src/jit/JitCompartment.h +++ b/js/src/jit/JitCompartment.h @@ -318,11 +318,11 @@ class JitRuntime JitCode* preBarrier(MIRType type) const { switch (type) { - case MIRType_Value: return valuePreBarrier_; - case MIRType_String: return stringPreBarrier_; - case MIRType_Object: return objectPreBarrier_; - case MIRType_Shape: return shapePreBarrier_; - case MIRType_ObjectGroup: return objectGroupPreBarrier_; + case MIRType::Value: return valuePreBarrier_; + case MIRType::String: return stringPreBarrier_; + case MIRType::Object: return objectPreBarrier_; + case MIRType::Shape: return shapePreBarrier_; + case MIRType::ObjectGroup: return objectGroupPreBarrier_; default: MOZ_CRASH(); } } diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index f20180785f..0f2d7bd6fb 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -1682,7 +1682,7 @@ SnapshotIterator::fromStack(int32_t offset) const static Value FromObjectPayload(uintptr_t payload) { - // Note: Both MIRType_Object and MIRType_ObjectOrNull are encoded in + // Note: Both MIRType::Object and MIRType::ObjectOrNull are encoded in // snapshots using JSVAL_TYPE_OBJECT. return ObjectOrNullValue(reinterpret_cast(payload)); } diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp index e04d13908c..dadc6940bc 100644 --- a/js/src/jit/JitOptions.cpp +++ b/js/src/jit/JitOptions.cpp @@ -87,6 +87,9 @@ DefaultJitOptions::DefaultJitOptions() // Toggles whether Edge Case Analysis is gobally disabled. SET_DEFAULT(disableEdgeCaseAnalysis, false); + // Toggles whether to use flow sensitive Alias Analysis. + SET_DEFAULT(disableFlowAA, true); + // Toggle whether global value numbering is globally disabled. SET_DEFAULT(disableGvn, false); diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h index 6b3d8cbc48..da1d5be633 100644 --- a/js/src/jit/JitOptions.h +++ b/js/src/jit/JitOptions.h @@ -51,6 +51,7 @@ struct DefaultJitOptions bool disableEaa; bool disableEagerSimdUnbox; bool disableEdgeCaseAnalysis; + bool disableFlowAA; bool disableGvn; bool disableInlining; bool disableLicm; diff --git a/js/src/jit/JitSpewer.cpp b/js/src/jit/JitSpewer.cpp index 290aea3727..3f99b6a763 100644 --- a/js/src/jit/JitSpewer.cpp +++ b/js/src/jit/JitSpewer.cpp @@ -412,6 +412,7 @@ jit::CheckLogging() " prune Prune unused branches\n" " escape Escape analysis\n" " alias Alias analysis\n" + " alias-sum Alias analysis: shows summaries for every block\n" " gvn Global Value Numbering\n" " licm Loop invariant code motion\n" " sincos Replace sin/cos by sincos\n" @@ -456,6 +457,8 @@ jit::CheckLogging() EnableChannel(JitSpew_Escape); if (ContainsFlag(env, "alias")) EnableChannel(JitSpew_Alias); + if (ContainsFlag(env, "alias-sum")) + EnableChannel(JitSpew_AliasSummaries); if (ContainsFlag(env, "scripts")) EnableChannel(JitSpew_IonScripts); if (ContainsFlag(env, "mir")) diff --git a/js/src/jit/JitSpewer.h b/js/src/jit/JitSpewer.h index d3d8302793..b799c72add 100644 --- a/js/src/jit/JitSpewer.h +++ b/js/src/jit/JitSpewer.h @@ -30,6 +30,8 @@ namespace jit { _(Escape) \ /* Information during alias analysis */ \ _(Alias) \ + /* Information during alias analysis */ \ + _(AliasSummaries) \ /* Information during GVN */ \ _(GVN) \ /* Information during sincos */ \ diff --git a/js/src/jit/LICM.cpp b/js/src/jit/LICM.cpp index f10076b797..d661a1c7d7 100644 --- a/js/src/jit/LICM.cpp +++ b/js/src/jit/LICM.cpp @@ -123,7 +123,7 @@ static bool HasDependencyInLoop(MInstruction* ins, MBasicBlock* header) { // Don't hoist if this instruction depends on a store inside the loop. - if (MInstruction* dep = ins->dependency()) + if (MDefinition* dep = ins->dependency()) return !IsBeforeLoop(dep, header); return false; } diff --git a/js/src/jit/LIR.cpp b/js/src/jit/LIR.cpp index a4ac19ec65..18b609aab6 100644 --- a/js/src/jit/LIR.cpp +++ b/js/src/jit/LIR.cpp @@ -89,7 +89,7 @@ LBlock::init(TempAllocator& alloc) size_t numLPhis = 0; for (MPhiIterator i(block_->phisBegin()), e(block_->phisEnd()); i != e; ++i) { MPhi* phi = *i; - numLPhis += (phi->type() == MIRType_Value) ? BOX_PIECES : 1; + numLPhis += (phi->type() == MIRType::Value) ? BOX_PIECES : 1; } // Allocate space for the LPhis. @@ -105,7 +105,7 @@ LBlock::init(TempAllocator& alloc) MPhi* phi = *i; MOZ_ASSERT(phi->numOperands() == numPreds); - int numPhis = (phi->type() == MIRType_Value) ? BOX_PIECES : 1; + int numPhis = (phi->type() == MIRType::Value) ? BOX_PIECES : 1; for (int i = 0; i < numPhis; i++) { LAllocation* inputs = alloc.allocateArray(numPreds); if (!inputs) diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index ffe7555bf5..3f497f9de6 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -588,39 +588,39 @@ class LDefinition static inline Type TypeFrom(MIRType type) { switch (type) { - case MIRType_Boolean: - case MIRType_Int32: + case MIRType::Boolean: + case MIRType::Int32: // The stack slot allocator doesn't currently support allocating - // 1-byte slots, so for now we lower MIRType_Boolean into INT32. + // 1-byte slots, so for now we lower MIRType::Boolean into INT32. static_assert(sizeof(bool) <= sizeof(int32_t), "bool doesn't fit in an int32 slot"); return LDefinition::INT32; - case MIRType_String: - case MIRType_Symbol: - case MIRType_Object: - case MIRType_ObjectOrNull: + case MIRType::String: + case MIRType::Symbol: + case MIRType::Object: + case MIRType::ObjectOrNull: return LDefinition::OBJECT; - case MIRType_Double: + case MIRType::Double: return LDefinition::DOUBLE; - case MIRType_Float32: + case MIRType::Float32: return LDefinition::FLOAT32; #if defined(JS_PUNBOX64) - case MIRType_Value: + case MIRType::Value: return LDefinition::BOX; #endif - case MIRType_SinCosDouble: + case MIRType::SinCosDouble: return LDefinition::SINCOS; - case MIRType_Slots: - case MIRType_Elements: + case MIRType::Slots: + case MIRType::Elements: return LDefinition::SLOTS; - case MIRType_Pointer: + case MIRType::Pointer: #if JS_BITS_PER_WORD == 64 - case MIRType_Int64: + case MIRType::Int64: #endif return LDefinition::GENERAL; - case MIRType_Bool32x4: - case MIRType_Int32x4: + case MIRType::Bool32x4: + case MIRType::Int32x4: return LDefinition::INT32X4; - case MIRType_Float32x4: + case MIRType::Float32x4: return LDefinition::FLOAT32X4; default: MOZ_CRASH("unexpected type"); diff --git a/js/src/jit/Linker.cpp b/js/src/jit/Linker.cpp new file mode 100644 index 0000000000..0fa0384560 --- /dev/null +++ b/js/src/jit/Linker.cpp @@ -0,0 +1,64 @@ +/* -*- 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 "jit/Linker.h" + +#include "gc/StoreBuffer-inl.h" + +namespace js { +namespace jit { + +template +JitCode* +Linker::newCode(JSContext* cx, CodeKind kind, bool hasPatchableBackedges /* = false */) +{ + MOZ_ASSERT(masm.numAsmJSAbsoluteAddresses() == 0); + MOZ_ASSERT_IF(hasPatchableBackedges, kind == ION_CODE); + + gc::AutoSuppressGC suppressGC(cx); + if (masm.oom()) + return fail(cx); + + ExecutablePool* pool; + size_t bytesNeeded = masm.bytesNeeded() + sizeof(JitCode*) + CodeAlignment; + if (bytesNeeded >= MAX_BUFFER_SIZE) + return fail(cx); + + // ExecutableAllocator requires bytesNeeded to be word-size aligned. + bytesNeeded = AlignBytes(bytesNeeded, sizeof(void*)); + + ExecutableAllocator& execAlloc = hasPatchableBackedges + ? cx->runtime()->jitRuntime()->backedgeExecAlloc() + : cx->runtime()->jitRuntime()->execAlloc(); + uint8_t* result = (uint8_t*)execAlloc.alloc(bytesNeeded, &pool, kind); + if (!result) + return fail(cx); + + // The JitCode pointer will be stored right before the code buffer. + uint8_t* codeStart = result + sizeof(JitCode*); + + // Bump the code up to a nice alignment. + codeStart = (uint8_t*)AlignBytes((uintptr_t)codeStart, CodeAlignment); + uint32_t headerSize = codeStart - result; + JitCode* code = JitCode::New(cx, codeStart, bytesNeeded - headerSize, + headerSize, pool, kind); + if (!code) + return nullptr; + if (masm.oom()) + return fail(cx); + awjc.emplace(result, bytesNeeded); + code->copyFrom(masm); + masm.link(code); + if (masm.embedsNurseryPointers()) + cx->runtime()->gc.storeBuffer.putWholeCell(code); + return code; +} + +template JitCode* Linker::newCode(JSContext* cx, CodeKind kind, bool hasPatchableBackedges); +template JitCode* Linker::newCode(JSContext* cx, CodeKind kind, bool hasPatchableBackedges); + +} // namespace jit +} // namespace js diff --git a/js/src/jit/Linker.h b/js/src/jit/Linker.h index 189c46a152..d8574cdcbc 100644 --- a/js/src/jit/Linker.h +++ b/js/src/jit/Linker.h @@ -37,48 +37,7 @@ class Linker } template - JitCode* newCode(JSContext* cx, CodeKind kind, bool hasPatchableBackedges = false) { - MOZ_ASSERT(masm.numAsmJSAbsoluteAddresses() == 0); - MOZ_ASSERT_IF(hasPatchableBackedges, kind == ION_CODE); - - gc::AutoSuppressGC suppressGC(cx); - if (masm.oom()) - return fail(cx); - - ExecutablePool* pool; - size_t bytesNeeded = masm.bytesNeeded() + sizeof(JitCode*) + CodeAlignment; - if (bytesNeeded >= MAX_BUFFER_SIZE) - return fail(cx); - - // ExecutableAllocator requires bytesNeeded to be word-size aligned. - bytesNeeded = AlignBytes(bytesNeeded, sizeof(void*)); - - ExecutableAllocator& execAlloc = hasPatchableBackedges - ? cx->runtime()->jitRuntime()->backedgeExecAlloc() - : cx->runtime()->jitRuntime()->execAlloc(); - uint8_t* result = (uint8_t*)execAlloc.alloc(bytesNeeded, &pool, kind); - if (!result) - return fail(cx); - - // The JitCode pointer will be stored right before the code buffer. - uint8_t* codeStart = result + sizeof(JitCode*); - - // Bump the code up to a nice alignment. - codeStart = (uint8_t*)AlignBytes((uintptr_t)codeStart, CodeAlignment); - uint32_t headerSize = codeStart - result; - JitCode* code = JitCode::New(cx, codeStart, bytesNeeded - headerSize, - headerSize, pool, kind); - if (!code) - return nullptr; - if (masm.oom()) - return fail(cx); - awjc.emplace(result, bytesNeeded); - code->copyFrom(masm); - masm.link(code); - if (masm.embedsNurseryPointers()) - cx->runtime()->gc.storeBuffer.putWholeCell(code); - return code; - } + JitCode* newCode(JSContext* cx, CodeKind kind, bool hasPatchableBackedges = false); }; } // namespace jit diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 77ea17ab2d..15ea341741 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -43,8 +43,8 @@ LIRGenerator::useBoxAtStart(MDefinition* mir, LUse::Policy policy) void LIRGenerator::visitCloneLiteral(MCloneLiteral* ins) { - MOZ_ASSERT(ins->type() == MIRType_Object); - MOZ_ASSERT(ins->input()->type() == MIRType_Object); + MOZ_ASSERT(ins->type() == MIRType::Object); + MOZ_ASSERT(ins->input()->type() == MIRType::Object); LCloneLiteral* lir = new(alloc()) LCloneLiteral(useRegisterAtStart(ins->input())); defineReturn(lir, ins); @@ -153,14 +153,14 @@ LIRGenerator::visitTableSwitch(MTableSwitch* tableswitch) } // If we don't know the type. - if (opd->type() == MIRType_Value) { + if (opd->type() == MIRType::Value) { LTableSwitchV* lir = newLTableSwitchV(tableswitch); add(lir); return; } // Case indices are numeric, so other types will always go to the default case. - if (opd->type() != MIRType_Int32 && opd->type() != MIRType_Double) { + if (opd->type() != MIRType::Int32 && opd->type() != MIRType::Double) { add(new(alloc()) LGoto(tableswitch->getDefault())); return; } @@ -169,7 +169,7 @@ LIRGenerator::visitTableSwitch(MTableSwitch* tableswitch) // floating-point index. LAllocation index; LDefinition tempInt; - if (opd->type() == MIRType_Int32) { + if (opd->type() == MIRType::Int32) { index = useRegisterAtStart(opd); tempInt = tempCopy(opd, 0); } else { @@ -231,7 +231,7 @@ void LIRGenerator::visitNewArrayDynamicLength(MNewArrayDynamicLength* ins) { MDefinition* length = ins->length(); - MOZ_ASSERT(length->type() == MIRType_Int32); + MOZ_ASSERT(length->type() == MIRType::Int32); LNewArrayDynamicLength* lir = new(alloc()) LNewArrayDynamicLength(useRegister(length), temp()); define(lir, ins); @@ -301,7 +301,7 @@ LIRGenerator::visitNewDerivedTypedObject(MNewDerivedTypedObject* ins) void LIRGenerator::visitNewStringObject(MNewStringObject* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_String); + MOZ_ASSERT(ins->input()->type() == MIRType::String); LNewStringObject* lir = new(alloc()) LNewStringObject(useRegister(ins->input()), temp()); define(lir, ins); @@ -423,8 +423,8 @@ LIRGenerator::visitReturnFromCtor(MReturnFromCtor* ins) void LIRGenerator::visitComputeThis(MComputeThis* ins) { - MOZ_ASSERT(ins->type() == MIRType_Value); - MOZ_ASSERT(ins->input()->type() == MIRType_Value); + MOZ_ASSERT(ins->type() == MIRType::Value); + MOZ_ASSERT(ins->input()->type() == MIRType::Value); // Don't use useBoxAtStart because ComputeThis has a safepoint and needs to // have its inputs in different registers than its return value so that @@ -437,8 +437,8 @@ LIRGenerator::visitComputeThis(MComputeThis* ins) void LIRGenerator::visitArrowNewTarget(MArrowNewTarget* ins) { - MOZ_ASSERT(ins->type() == MIRType_Value); - MOZ_ASSERT(ins->callee()->type() == MIRType_Object); + MOZ_ASSERT(ins->type() == MIRType::Value); + MOZ_ASSERT(ins->callee()->type() == MIRType::Object); LArrowNewTarget* lir = new(alloc()) LArrowNewTarget(useRegister(ins->callee())); defineBox(lir, ins); @@ -467,7 +467,7 @@ LIRGenerator::lowerCallArguments(MCall* call) uint32_t argslot = baseSlot - i; // Values take a slow path. - if (arg->type() == MIRType_Value) { + if (arg->type() == MIRType::Value) { LStackArgV* stack = new(alloc()) LStackArgV(argslot, useBox(arg)); add(stack); } else { @@ -484,7 +484,7 @@ LIRGenerator::visitCall(MCall* call) MOZ_ASSERT(CallTempReg0 != CallTempReg1); MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg); MOZ_ASSERT(CallTempReg1 != ArgumentsRectifierReg); - MOZ_ASSERT(call->getFunction()->type() == MIRType_Object); + MOZ_ASSERT(call->getFunction()->type() == MIRType::Object); lowerCallArguments(call); @@ -536,7 +536,7 @@ LIRGenerator::visitCall(MCall* call) void LIRGenerator::visitApplyArgs(MApplyArgs* apply) { - MOZ_ASSERT(apply->getFunction()->type() == MIRType_Object); + MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object); // Assert if we cannot build a rectifier frame. MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg); @@ -564,7 +564,7 @@ LIRGenerator::visitApplyArgs(MApplyArgs* apply) void LIRGenerator::visitApplyArray(MApplyArray* apply) { - MOZ_ASSERT(apply->getFunction()->type() == MIRType_Object); + MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object); // Assert if we cannot build a rectifier frame. MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg); @@ -620,9 +620,9 @@ LIRGenerator::visitAssertFloat32(MAssertFloat32* assertion) MIRType type = assertion->input()->type(); DebugOnly checkIsFloat32 = assertion->mustBeFloat32(); - if (type != MIRType_Value && !JitOptions.eagerCompilation) { - MOZ_ASSERT_IF(checkIsFloat32, type == MIRType_Float32); - MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType_Float32); + if (type != MIRType::Value && !JitOptions.eagerCompilation) { + MOZ_ASSERT_IF(checkIsFloat32, type == MIRType::Float32); + MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType::Float32); } } @@ -646,10 +646,10 @@ void LIRGenerator::visitGetDynamicName(MGetDynamicName* ins) { MDefinition* scopeChain = ins->getScopeChain(); - MOZ_ASSERT(scopeChain->type() == MIRType_Object); + MOZ_ASSERT(scopeChain->type() == MIRType::Object); MDefinition* name = ins->getName(); - MOZ_ASSERT(name->type() == MIRType_String); + MOZ_ASSERT(name->type() == MIRType::String); LGetDynamicName* lir = new(alloc()) LGetDynamicName(useFixed(scopeChain, CallTempReg0), useFixed(name, CallTempReg1), @@ -665,10 +665,10 @@ void LIRGenerator::visitCallDirectEval(MCallDirectEval* ins) { MDefinition* scopeChain = ins->getScopeChain(); - MOZ_ASSERT(scopeChain->type() == MIRType_Object); + MOZ_ASSERT(scopeChain->type() == MIRType::Object); MDefinition* string = ins->getString(); - MOZ_ASSERT(string->type() == MIRType_String); + MOZ_ASSERT(string->type() == MIRType::String); MDefinition* newTargetValue = ins->getNewTargetValue(); @@ -702,7 +702,7 @@ LIRGenerator::visitTest(MTest* test) // String is converted to length of string in the type analysis phase (see // TestPolicy). - MOZ_ASSERT(opd->type() != MIRType_String); + MOZ_ASSERT(opd->type() != MIRType::String); // Testing a constant. if (MConstant* constant = opd->maybeConstantValue()) { @@ -713,7 +713,7 @@ LIRGenerator::visitTest(MTest* test) } } - if (opd->type() == MIRType_Value) { + if (opd->type() == MIRType::Value) { LDefinition temp0, temp1; if (test->operandMightEmulateUndefined()) { temp0 = temp(); @@ -728,14 +728,14 @@ LIRGenerator::visitTest(MTest* test) return; } - if (opd->type() == MIRType_ObjectOrNull) { + if (opd->type() == MIRType::ObjectOrNull) { LDefinition temp0 = test->operandMightEmulateUndefined() ? temp() : LDefinition::BogusTemp(); add(new(alloc()) LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp0), test); return; } // Objects are truthy, except if it might emulate undefined. - if (opd->type() == MIRType_Object) { + if (opd->type() == MIRType::Object) { if (test->operandMightEmulateUndefined()) add(new(alloc()) LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()), test); else @@ -745,13 +745,13 @@ LIRGenerator::visitTest(MTest* test) // These must be explicitly sniffed out since they are constants and have // no payload. - if (opd->type() == MIRType_Undefined || opd->type() == MIRType_Null) { + if (opd->type() == MIRType::Undefined || opd->type() == MIRType::Null) { add(new(alloc()) LGoto(ifFalse)); return; } // All symbols are truthy. - if (opd->type() == MIRType_Symbol) { + if (opd->type() == MIRType::Symbol) { add(new(alloc()) LGoto(ifTrue)); return; } @@ -779,8 +779,8 @@ LIRGenerator::visitTest(MTest* test) if (comp->compareType() == MCompare::Compare_Null || comp->compareType() == MCompare::Compare_Undefined) { - if (left->type() == MIRType_Object || left->type() == MIRType_ObjectOrNull) { - MOZ_ASSERT(left->type() == MIRType_ObjectOrNull || + if (left->type() == MIRType::Object || left->type() == MIRType::ObjectOrNull) { + MOZ_ASSERT(left->type() == MIRType::ObjectOrNull || comp->operandMightEmulateUndefined(), "MCompare::tryFold should handle the never-emulates-undefined case"); @@ -811,8 +811,8 @@ LIRGenerator::visitTest(MTest* test) // Compare and branch booleans. if (comp->compareType() == MCompare::Compare_Boolean) { - MOZ_ASSERT(left->type() == MIRType_Value); - MOZ_ASSERT(right->type() == MIRType_Boolean); + MOZ_ASSERT(left->type() == MIRType::Value); + MOZ_ASSERT(right->type() == MIRType::Boolean); LCompareBAndBranch* lir = new(alloc()) LCompareBAndBranch(comp, useBox(left), useRegisterOrConstant(right), @@ -888,7 +888,7 @@ LIRGenerator::visitTest(MTest* test) if (opd->isBitAnd() && opd->isEmittedAtUses()) { MDefinition* lhs = opd->getOperand(0); MDefinition* rhs = opd->getOperand(1); - if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) { + if (lhs->type() == MIRType::Int32 && rhs->type() == MIRType::Int32) { ReorderCommutative(&lhs, &rhs, test); lowerForBitAndAndBranch(new(alloc()) LBitAndAndBranch(ifTrue, ifFalse), test, lhs, rhs); return; @@ -897,7 +897,7 @@ LIRGenerator::visitTest(MTest* test) if (opd->isIsObject() && opd->isEmittedAtUses()) { MDefinition* input = opd->toIsObject()->input(); - MOZ_ASSERT(input->type() == MIRType_Value); + MOZ_ASSERT(input->type() == MIRType::Value); LIsObjectAndBranch* lir = new(alloc()) LIsObjectAndBranch(ifTrue, ifFalse, useBoxAtStart(input)); @@ -909,7 +909,7 @@ LIRGenerator::visitTest(MTest* test) MOZ_ASSERT(opd->isEmittedAtUses()); MDefinition* input = opd->toIsNoIter()->input(); - MOZ_ASSERT(input->type() == MIRType_Value); + MOZ_ASSERT(input->type() == MIRType::Value); LIsNoIterAndBranch* lir = new(alloc()) LIsNoIterAndBranch(ifTrue, ifFalse, useBox(input)); @@ -918,14 +918,14 @@ LIRGenerator::visitTest(MTest* test) } switch (opd->type()) { - case MIRType_Double: + case MIRType::Double: add(new(alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse)); break; - case MIRType_Float32: + case MIRType::Float32: add(new(alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse)); break; - case MIRType_Int32: - case MIRType_Boolean: + case MIRType::Int32: + case MIRType::Boolean: add(new(alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse)); break; default: @@ -998,8 +998,8 @@ LIRGenerator::visitCompare(MCompare* comp) // Strict compare between value and string if (comp->compareType() == MCompare::Compare_StrictString) { - MOZ_ASSERT(left->type() == MIRType_Value); - MOZ_ASSERT(right->type() == MIRType_String); + MOZ_ASSERT(left->type() == MIRType::Value); + MOZ_ASSERT(right->type() == MIRType::String); LCompareStrictS* lir = new(alloc()) LCompareStrictS(useBox(left), useRegister(right), tempToUnbox()); @@ -1029,8 +1029,8 @@ LIRGenerator::visitCompare(MCompare* comp) if (comp->compareType() == MCompare::Compare_Null || comp->compareType() == MCompare::Compare_Undefined) { - if (left->type() == MIRType_Object || left->type() == MIRType_ObjectOrNull) { - MOZ_ASSERT(left->type() == MIRType_ObjectOrNull || + if (left->type() == MIRType::Object || left->type() == MIRType::ObjectOrNull) { + MOZ_ASSERT(left->type() == MIRType::ObjectOrNull || comp->operandMightEmulateUndefined(), "MCompare::tryFold should have folded this away"); @@ -1055,8 +1055,8 @@ LIRGenerator::visitCompare(MCompare* comp) // Compare booleans. if (comp->compareType() == MCompare::Compare_Boolean) { - MOZ_ASSERT(left->type() == MIRType_Value); - MOZ_ASSERT(right->type() == MIRType_Boolean); + MOZ_ASSERT(left->type() == MIRType::Value); + MOZ_ASSERT(right->type() == MIRType::Boolean); LCompareB* lir = new(alloc()) LCompareB(useBox(left), useRegisterOrConstant(right)); define(lir, comp); @@ -1121,15 +1121,15 @@ LIRGenerator::lowerBitOp(JSOp op, MInstruction* ins) MDefinition* lhs = ins->getOperand(0); MDefinition* rhs = ins->getOperand(1); - if (lhs->type() == MIRType_Int32) { - MOZ_ASSERT(rhs->type() == MIRType_Int32); + if (lhs->type() == MIRType::Int32) { + MOZ_ASSERT(rhs->type() == MIRType::Int32); ReorderCommutative(&lhs, &rhs, ins); lowerForALU(new(alloc()) LBitOpI(op), ins, lhs, rhs); return; } - if (lhs->type() == MIRType_Int64) { - MOZ_ASSERT(rhs->type() == MIRType_Int64); + if (lhs->type() == MIRType::Int64) { + MOZ_ASSERT(rhs->type() == MIRType::Int64); ReorderCommutative(&lhs, &rhs, ins); lowerForALUInt64(new(alloc()) LBitOpI64(op), ins, lhs, rhs); return; @@ -1144,7 +1144,7 @@ void LIRGenerator::visitTypeOf(MTypeOf* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Value); + MOZ_ASSERT(opd->type() == MIRType::Value); LTypeOfV* lir = new(alloc()) LTypeOfV(useBox(opd), tempToUnbox()); define(lir, ins); @@ -1163,7 +1163,7 @@ LIRGenerator::visitBitNot(MBitNot* ins) { MDefinition* input = ins->getOperand(0); - if (input->type() == MIRType_Int32) { + if (input->type() == MIRType::Int32) { lowerForALU(new(alloc()) LBitNotI(), ins, input); return; } @@ -1179,7 +1179,7 @@ CanEmitBitAndAtUses(MInstruction* ins) if (!ins->canEmitAtUses()) return false; - if (ins->getOperand(0)->type() != MIRType_Int32 || ins->getOperand(1)->type() != MIRType_Int32) + if (ins->getOperand(0)->type() != MIRType::Int32 || ins->getOperand(1)->type() != MIRType::Int32) return false; MUseIterator iter(ins->usesBegin()); @@ -1228,10 +1228,10 @@ LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins) MDefinition* lhs = ins->getOperand(0); MDefinition* rhs = ins->getOperand(1); - if (lhs->type() == MIRType_Int32) { - MOZ_ASSERT(rhs->type() == MIRType_Int32); + if (lhs->type() == MIRType::Int32) { + MOZ_ASSERT(rhs->type() == MIRType::Int32); - if (ins->type() == MIRType_Double) { + if (ins->type() == MIRType::Double) { MOZ_ASSERT(op == JSOP_URSH); lowerUrshD(ins->toUrsh()); return; @@ -1246,13 +1246,13 @@ LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins) return; } - if (lhs->type() == MIRType_Int64) { - MOZ_ASSERT(rhs->type() == MIRType_Int64); + if (lhs->type() == MIRType::Int64) { + MOZ_ASSERT(rhs->type() == MIRType::Int64); lowerForShiftInt64(new(alloc()) LShiftI64(op), ins, lhs, rhs); return; } - MOZ_ASSERT(ins->specialization() == MIRType_None); + MOZ_ASSERT(ins->specialization() == MIRType::None); if (op == JSOP_URSH) { // Result is either int32 or double so we have to use BinaryV. @@ -1283,6 +1283,23 @@ LIRGenerator::visitUrsh(MUrsh* ins) lowerShiftOp(JSOP_URSH, ins); } +void +LIRGenerator::visitRotate(MRotate* ins) +{ + MDefinition* input = ins->input(); + MDefinition* count = ins->count(); + + if (ins->type() == MIRType::Int32) { + auto* lir = new(alloc()) LRotate(); + lowerForShift(lir, ins, input, count); + } else if (ins->type() == MIRType::Int64) { + auto* lir = new(alloc()) LRotate64(); + lowerForShiftInt64(lir, ins, input, count); + } else { + MOZ_CRASH("unexpected type in visitRotate"); + } +} + void LIRGenerator::visitFloor(MFloor* ins) { @@ -1290,7 +1307,7 @@ LIRGenerator::visitFloor(MFloor* ins) MOZ_ASSERT(IsFloatingPointType(type)); LInstructionHelper<1, 1, 0>* lir; - if (type == MIRType_Double) + if (type == MIRType::Double) lir = new(alloc()) LFloor(useRegister(ins->input())); else lir = new(alloc()) LFloorF(useRegister(ins->input())); @@ -1306,7 +1323,7 @@ LIRGenerator::visitCeil(MCeil* ins) MOZ_ASSERT(IsFloatingPointType(type)); LInstructionHelper<1, 1, 0>* lir; - if (type == MIRType_Double) + if (type == MIRType::Double) lir = new(alloc()) LCeil(useRegister(ins->input())); else lir = new(alloc()) LCeilF(useRegister(ins->input())); @@ -1322,7 +1339,7 @@ LIRGenerator::visitRound(MRound* ins) MOZ_ASSERT(IsFloatingPointType(type)); LInstructionHelper<1, 1, 1>* lir; - if (type == MIRType_Double) + if (type == MIRType::Double) lir = new (alloc()) LRound(useRegister(ins->input()), tempDouble()); else lir = new (alloc()) LRoundF(useRegister(ins->input()), tempFloat32()); @@ -1341,13 +1358,13 @@ LIRGenerator::visitMinMax(MMinMax* ins) LMinMaxBase* lir; switch (ins->specialization()) { - case MIRType_Int32: + case MIRType::Int32: lir = new(alloc()) LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second)); break; - case MIRType_Float32: + case MIRType::Float32: lir = new(alloc()) LMinMaxF(useRegisterAtStart(first), useRegister(second)); break; - case MIRType_Double: + case MIRType::Double: lir = new(alloc()) LMinMaxD(useRegisterAtStart(first), useRegister(second)); break; default: @@ -1365,16 +1382,16 @@ LIRGenerator::visitAbs(MAbs* ins) LInstructionHelper<1, 1, 0>* lir; switch (num->type()) { - case MIRType_Int32: + case MIRType::Int32: lir = new(alloc()) LAbsI(useRegisterAtStart(num)); // needed to handle abs(INT32_MIN) if (ins->fallible()) assignSnapshot(lir, Bailout_Overflow); break; - case MIRType_Float32: + case MIRType::Float32: lir = new(alloc()) LAbsF(useRegisterAtStart(num)); break; - case MIRType_Double: + case MIRType::Double: lir = new(alloc()) LAbsD(useRegisterAtStart(num)); break; default: @@ -1418,7 +1435,7 @@ LIRGenerator::visitSqrt(MSqrt* ins) MOZ_ASSERT(IsFloatingPointType(num->type())); LInstructionHelper<1, 1, 0>* lir; - if (num->type() == MIRType_Double) + if (num->type() == MIRType::Double) lir = new(alloc()) LSqrtD(useRegisterAtStart(num)); else lir = new(alloc()) LSqrtF(useRegisterAtStart(num)); @@ -1429,10 +1446,10 @@ void LIRGenerator::visitAtan2(MAtan2* ins) { MDefinition* y = ins->y(); - MOZ_ASSERT(y->type() == MIRType_Double); + MOZ_ASSERT(y->type() == MIRType::Double); MDefinition* x = ins->x(); - MOZ_ASSERT(x->type() == MIRType_Double); + MOZ_ASSERT(x->type() == MIRType::Double); LAtan2D* lir = new(alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x), tempFixed(CallTempReg0)); @@ -1445,7 +1462,7 @@ LIRGenerator::visitHypot(MHypot* ins) LHypot* lir = nullptr; uint32_t length = ins->numOperands(); for (uint32_t i = 0; i < length; ++i) - MOZ_ASSERT(ins->getOperand(i)->type() == MIRType_Double); + MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::Double); switch(length) { case 2: @@ -1477,13 +1494,13 @@ void LIRGenerator::visitPow(MPow* ins) { MDefinition* input = ins->input(); - MOZ_ASSERT(input->type() == MIRType_Double); + MOZ_ASSERT(input->type() == MIRType::Double); MDefinition* power = ins->power(); - MOZ_ASSERT(power->type() == MIRType_Int32 || power->type() == MIRType_Double); + MOZ_ASSERT(power->type() == MIRType::Int32 || power->type() == MIRType::Double); LInstruction* lir; - if (power->type() == MIRType_Int32) { + if (power->type() == MIRType::Int32) { // Note: useRegisterAtStart here is safe, the temp is a GP register so // it will never get the same register. lir = new(alloc()) LPowI(useRegisterAtStart(input), useFixed(power, CallTempReg1), @@ -1499,17 +1516,17 @@ void LIRGenerator::visitMathFunction(MMathFunction* ins) { MOZ_ASSERT(IsFloatingPointType(ins->type())); - MOZ_ASSERT_IF(ins->input()->type() != MIRType_SinCosDouble, + MOZ_ASSERT_IF(ins->input()->type() != MIRType::SinCosDouble, ins->type() == ins->input()->type()); - if (ins->input()->type() == MIRType_SinCosDouble) { - MOZ_ASSERT(ins->type() == MIRType_Double); + if (ins->input()->type() == MIRType::SinCosDouble) { + MOZ_ASSERT(ins->type() == MIRType::Double); redefine(ins, ins->input(), ins->function()); return; } LInstruction* lir; - if (ins->type() == MIRType_Double) { + if (ins->type() == MIRType::Double) { // Note: useRegisterAtStart is safe here, the temp is not a FP register. lir = new(alloc()) LMathFunctionD(useRegisterAtStart(ins->input()), tempFixed(CallTempReg0)); @@ -1560,8 +1577,8 @@ LIRGenerator::visitAdd(MAdd* ins) MOZ_ASSERT(lhs->type() == rhs->type()); - if (ins->specialization() == MIRType_Int32) { - MOZ_ASSERT(lhs->type() == MIRType_Int32); + if (ins->specialization() == MIRType::Int32) { + MOZ_ASSERT(lhs->type() == MIRType::Int32); ReorderCommutative(&lhs, &rhs, ins); LAddI* lir = new(alloc()) LAddI; @@ -1573,23 +1590,23 @@ LIRGenerator::visitAdd(MAdd* ins) return; } - if (ins->specialization() == MIRType_Int64) { - MOZ_ASSERT(lhs->type() == MIRType_Int64); + if (ins->specialization() == MIRType::Int64) { + MOZ_ASSERT(lhs->type() == MIRType::Int64); ReorderCommutative(&lhs, &rhs, ins); LAddI64* lir = new(alloc()) LAddI64; lowerForALUInt64(lir, ins, lhs, rhs); return; } - if (ins->specialization() == MIRType_Double) { - MOZ_ASSERT(lhs->type() == MIRType_Double); + if (ins->specialization() == MIRType::Double) { + MOZ_ASSERT(lhs->type() == MIRType::Double); ReorderCommutative(&lhs, &rhs, ins); lowerForFPU(new(alloc()) LMathD(JSOP_ADD), ins, lhs, rhs); return; } - if (ins->specialization() == MIRType_Float32) { - MOZ_ASSERT(lhs->type() == MIRType_Float32); + if (ins->specialization() == MIRType::Float32) { + MOZ_ASSERT(lhs->type() == MIRType::Float32); ReorderCommutative(&lhs, &rhs, ins); lowerForFPU(new(alloc()) LMathF(JSOP_ADD), ins, lhs, rhs); return; @@ -1606,8 +1623,8 @@ LIRGenerator::visitSub(MSub* ins) MOZ_ASSERT(lhs->type() == rhs->type()); - if (ins->specialization() == MIRType_Int32) { - MOZ_ASSERT(lhs->type() == MIRType_Int32); + if (ins->specialization() == MIRType::Int32) { + MOZ_ASSERT(lhs->type() == MIRType::Int32); LSubI* lir = new(alloc()) LSubI; if (ins->fallible()) @@ -1618,22 +1635,22 @@ LIRGenerator::visitSub(MSub* ins) return; } - if (ins->specialization() == MIRType_Int64) { - MOZ_ASSERT(lhs->type() == MIRType_Int64); + if (ins->specialization() == MIRType::Int64) { + MOZ_ASSERT(lhs->type() == MIRType::Int64); ReorderCommutative(&lhs, &rhs, ins); LSubI64* lir = new(alloc()) LSubI64; lowerForALUInt64(lir, ins, lhs, rhs); return; } - if (ins->specialization() == MIRType_Double) { - MOZ_ASSERT(lhs->type() == MIRType_Double); + if (ins->specialization() == MIRType::Double) { + MOZ_ASSERT(lhs->type() == MIRType::Double); lowerForFPU(new(alloc()) LMathD(JSOP_SUB), ins, lhs, rhs); return; } - if (ins->specialization() == MIRType_Float32) { - MOZ_ASSERT(lhs->type() == MIRType_Float32); + if (ins->specialization() == MIRType::Float32) { + MOZ_ASSERT(lhs->type() == MIRType::Float32); lowerForFPU(new(alloc()) LMathF(JSOP_SUB), ins, lhs, rhs); return; } @@ -1648,8 +1665,8 @@ LIRGenerator::visitMul(MMul* ins) MDefinition* rhs = ins->rhs(); MOZ_ASSERT(lhs->type() == rhs->type()); - if (ins->specialization() == MIRType_Int32) { - MOZ_ASSERT(lhs->type() == MIRType_Int32); + if (ins->specialization() == MIRType::Int32) { + MOZ_ASSERT(lhs->type() == MIRType::Int32); ReorderCommutative(&lhs, &rhs, ins); // If our RHS is a constant -1 and we don't have to worry about @@ -1661,16 +1678,16 @@ LIRGenerator::visitMul(MMul* ins) return; } - if (ins->specialization() == MIRType_Int64) { - MOZ_ASSERT(lhs->type() == MIRType_Int64); + if (ins->specialization() == MIRType::Int64) { + MOZ_ASSERT(lhs->type() == MIRType::Int64); ReorderCommutative(&lhs, &rhs, ins); LMulI64* lir = new(alloc()) LMulI64; lowerForALUInt64(lir, ins, lhs, rhs); return; } - if (ins->specialization() == MIRType_Double) { - MOZ_ASSERT(lhs->type() == MIRType_Double); + if (ins->specialization() == MIRType::Double) { + MOZ_ASSERT(lhs->type() == MIRType::Double); ReorderCommutative(&lhs, &rhs, ins); // If our RHS is a constant -1.0, we can optimize to an LNegD. @@ -1681,8 +1698,8 @@ LIRGenerator::visitMul(MMul* ins) return; } - if (ins->specialization() == MIRType_Float32) { - MOZ_ASSERT(lhs->type() == MIRType_Float32); + if (ins->specialization() == MIRType::Float32) { + MOZ_ASSERT(lhs->type() == MIRType::Float32); ReorderCommutative(&lhs, &rhs, ins); // We apply the same optimizations as for doubles @@ -1703,26 +1720,26 @@ LIRGenerator::visitDiv(MDiv* ins) MDefinition* rhs = ins->rhs(); MOZ_ASSERT(lhs->type() == rhs->type()); - if (ins->specialization() == MIRType_Int32) { - MOZ_ASSERT(lhs->type() == MIRType_Int32); + if (ins->specialization() == MIRType::Int32) { + MOZ_ASSERT(lhs->type() == MIRType::Int32); lowerDivI(ins); return; } - if (ins->specialization() == MIRType_Int64) { - MOZ_ASSERT(lhs->type() == MIRType_Int64); + if (ins->specialization() == MIRType::Int64) { + MOZ_ASSERT(lhs->type() == MIRType::Int64); lowerDivI64(ins); return; } - if (ins->specialization() == MIRType_Double) { - MOZ_ASSERT(lhs->type() == MIRType_Double); + if (ins->specialization() == MIRType::Double) { + MOZ_ASSERT(lhs->type() == MIRType::Double); lowerForFPU(new(alloc()) LMathD(JSOP_DIV), ins, lhs, rhs); return; } - if (ins->specialization() == MIRType_Float32) { - MOZ_ASSERT(lhs->type() == MIRType_Float32); + if (ins->specialization() == MIRType::Float32) { + MOZ_ASSERT(lhs->type() == MIRType::Float32); lowerForFPU(new(alloc()) LMathF(JSOP_DIV), ins, lhs, rhs); return; } @@ -1735,24 +1752,24 @@ LIRGenerator::visitMod(MMod* ins) { MOZ_ASSERT(ins->lhs()->type() == ins->rhs()->type()); - if (ins->specialization() == MIRType_Int32) { - MOZ_ASSERT(ins->type() == MIRType_Int32); - MOZ_ASSERT(ins->lhs()->type() == MIRType_Int32); + if (ins->specialization() == MIRType::Int32) { + MOZ_ASSERT(ins->type() == MIRType::Int32); + MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32); lowerModI(ins); return; } - if (ins->specialization() == MIRType_Int64) { - MOZ_ASSERT(ins->type() == MIRType_Int64); - MOZ_ASSERT(ins->lhs()->type() == MIRType_Int64); + if (ins->specialization() == MIRType::Int64) { + MOZ_ASSERT(ins->type() == MIRType::Int64); + MOZ_ASSERT(ins->lhs()->type() == MIRType::Int64); lowerModI64(ins); return; } - if (ins->specialization() == MIRType_Double) { - MOZ_ASSERT(ins->type() == MIRType_Double); - MOZ_ASSERT(ins->lhs()->type() == MIRType_Double); - MOZ_ASSERT(ins->rhs()->type() == MIRType_Double); + if (ins->specialization() == MIRType::Double) { + MOZ_ASSERT(ins->type() == MIRType::Double); + MOZ_ASSERT(ins->lhs()->type() == MIRType::Double); + MOZ_ASSERT(ins->rhs()->type() == MIRType::Double); // Note: useRegisterAtStart is safe here, the temp is not a FP register. LModD* lir = new(alloc()) LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()), @@ -1770,8 +1787,8 @@ LIRGenerator::lowerBinaryV(JSOp op, MBinaryInstruction* ins) MDefinition* lhs = ins->getOperand(0); MDefinition* rhs = ins->getOperand(1); - MOZ_ASSERT(lhs->type() == MIRType_Value); - MOZ_ASSERT(rhs->type() == MIRType_Value); + MOZ_ASSERT(lhs->type() == MIRType::Value); + MOZ_ASSERT(rhs->type() == MIRType::Value); LBinaryV* lir = new(alloc()) LBinaryV(op, useBoxAtStart(lhs), useBoxAtStart(rhs)); defineReturn(lir, ins); @@ -1784,9 +1801,9 @@ LIRGenerator::visitConcat(MConcat* ins) MDefinition* lhs = ins->getOperand(0); MDefinition* rhs = ins->getOperand(1); - MOZ_ASSERT(lhs->type() == MIRType_String); - MOZ_ASSERT(rhs->type() == MIRType_String); - MOZ_ASSERT(ins->type() == MIRType_String); + MOZ_ASSERT(lhs->type() == MIRType::String); + MOZ_ASSERT(rhs->type() == MIRType::String); + MOZ_ASSERT(ins->type() == MIRType::String); LConcat* lir = new(alloc()) LConcat(useFixedAtStart(lhs, CallTempReg0), useFixedAtStart(rhs, CallTempReg1), @@ -1805,8 +1822,8 @@ LIRGenerator::visitCharCodeAt(MCharCodeAt* ins) MDefinition* str = ins->getOperand(0); MDefinition* idx = ins->getOperand(1); - MOZ_ASSERT(str->type() == MIRType_String); - MOZ_ASSERT(idx->type() == MIRType_Int32); + MOZ_ASSERT(str->type() == MIRType::String); + MOZ_ASSERT(idx->type() == MIRType::Int32); LCharCodeAt* lir = new(alloc()) LCharCodeAt(useRegister(str), useRegister(idx)); define(lir, ins); @@ -1818,7 +1835,7 @@ LIRGenerator::visitFromCharCode(MFromCharCode* ins) { MDefinition* code = ins->getOperand(0); - MOZ_ASSERT(code->type() == MIRType_Int32); + MOZ_ASSERT(code->type() == MIRType::Int32); LFromCharCode* lir = new(alloc()) LFromCharCode(useRegister(code)); define(lir, ins); @@ -1891,7 +1908,7 @@ LIRGenerator::visitToDouble(MToDouble* convert) mozilla::DebugOnly conversion = convert->conversion(); switch (opd->type()) { - case MIRType_Value: + case MIRType::Value: { LValueToDouble* lir = new(alloc()) LValueToDouble(useBox(opd)); assignSnapshot(lir, Bailout_NonPrimitiveInput); @@ -1899,36 +1916,36 @@ LIRGenerator::visitToDouble(MToDouble* convert) break; } - case MIRType_Null: + case MIRType::Null: MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly && conversion != MToFPInstruction::NonNullNonStringPrimitives); lowerConstantDouble(0, convert); break; - case MIRType_Undefined: + case MIRType::Undefined: MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly); lowerConstantDouble(GenericNaN(), convert); break; - case MIRType_Boolean: + case MIRType::Boolean: MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly); MOZ_FALLTHROUGH; - case MIRType_Int32: + case MIRType::Int32: { LInt32ToDouble* lir = new(alloc()) LInt32ToDouble(useRegisterAtStart(opd)); define(lir, convert); break; } - case MIRType_Float32: + case MIRType::Float32: { LFloat32ToDouble* lir = new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd)); define(lir, convert); break; } - case MIRType_Double: + case MIRType::Double: redefine(convert, opd); break; @@ -1946,7 +1963,7 @@ LIRGenerator::visitToFloat32(MToFloat32* convert) mozilla::DebugOnly conversion = convert->conversion(); switch (opd->type()) { - case MIRType_Value: + case MIRType::Value: { LValueToFloat32* lir = new(alloc()) LValueToFloat32(useBox(opd)); assignSnapshot(lir, Bailout_NonPrimitiveInput); @@ -1954,36 +1971,36 @@ LIRGenerator::visitToFloat32(MToFloat32* convert) break; } - case MIRType_Null: + case MIRType::Null: MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly && conversion != MToFPInstruction::NonNullNonStringPrimitives); lowerConstantFloat32(0, convert); break; - case MIRType_Undefined: + case MIRType::Undefined: MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly); lowerConstantFloat32(GenericNaN(), convert); break; - case MIRType_Boolean: + case MIRType::Boolean: MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly); MOZ_FALLTHROUGH; - case MIRType_Int32: + case MIRType::Int32: { LInt32ToFloat32* lir = new(alloc()) LInt32ToFloat32(useRegisterAtStart(opd)); define(lir, convert); break; } - case MIRType_Double: + case MIRType::Double: { LDoubleToFloat32* lir = new(alloc()) LDoubleToFloat32(useRegisterAtStart(opd)); define(lir, convert); break; } - case MIRType_Float32: + case MIRType::Float32: redefine(convert, opd); break; @@ -2000,7 +2017,7 @@ LIRGenerator::visitToInt32(MToInt32* convert) MDefinition* opd = convert->input(); switch (opd->type()) { - case MIRType_Value: + case MIRType::Value: { LValueToInt32* lir = new(alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(), LValueToInt32::NORMAL); @@ -2010,22 +2027,22 @@ LIRGenerator::visitToInt32(MToInt32* convert) break; } - case MIRType_Null: + case MIRType::Null: MOZ_ASSERT(convert->conversion() == MacroAssembler::IntConversion_Any); define(new(alloc()) LInteger(0), convert); break; - case MIRType_Boolean: + case MIRType::Boolean: MOZ_ASSERT(convert->conversion() == MacroAssembler::IntConversion_Any || convert->conversion() == MacroAssembler::IntConversion_NumbersOrBoolsOnly); redefine(convert, opd); break; - case MIRType_Int32: + case MIRType::Int32: redefine(convert, opd); break; - case MIRType_Float32: + case MIRType::Float32: { LFloat32ToInt32* lir = new(alloc()) LFloat32ToInt32(useRegister(opd)); assignSnapshot(lir, Bailout_PrecisionLoss); @@ -2033,7 +2050,7 @@ LIRGenerator::visitToInt32(MToInt32* convert) break; } - case MIRType_Double: + case MIRType::Double: { LDoubleToInt32* lir = new(alloc()) LDoubleToInt32(useRegister(opd)); assignSnapshot(lir, Bailout_PrecisionLoss); @@ -2041,10 +2058,10 @@ LIRGenerator::visitToInt32(MToInt32* convert) break; } - case MIRType_String: - case MIRType_Symbol: - case MIRType_Object: - case MIRType_Undefined: + case MIRType::String: + case MIRType::Symbol: + case MIRType::Object: + case MIRType::Undefined: // Objects might be effectful. Symbols throw. Undefined coerces to NaN, not int32. MOZ_CRASH("ToInt32 invalid input type"); @@ -2059,7 +2076,7 @@ LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) MDefinition* opd = truncate->input(); switch (opd->type()) { - case MIRType_Value: + case MIRType::Value: { LValueToInt32* lir = new(alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(), LValueToInt32::TRUNCATE); @@ -2069,21 +2086,21 @@ LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) break; } - case MIRType_Null: - case MIRType_Undefined: + case MIRType::Null: + case MIRType::Undefined: define(new(alloc()) LInteger(0), truncate); break; - case MIRType_Int32: - case MIRType_Boolean: + case MIRType::Int32: + case MIRType::Boolean: redefine(truncate, opd); break; - case MIRType_Double: + case MIRType::Double: lowerTruncateDToInt32(truncate); break; - case MIRType_Float32: + case MIRType::Float32: lowerTruncateFToInt32(truncate); break; @@ -2094,6 +2111,22 @@ LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) } } +void +LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) +{ + MDefinition* input = ins->input(); + switch (input->type()) { + case MIRType::Double: + case MIRType::Float32: { + auto* lir = new(alloc()) LWasmTruncateToInt32(useRegisterAtStart(input)); + define(lir, ins); + break; + } + default: + MOZ_CRASH("unexpected type in WasmTruncateToInt32"); + } +} + void LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) { @@ -2112,27 +2145,27 @@ LIRGenerator::visitToString(MToString* ins) MDefinition* opd = ins->input(); switch (opd->type()) { - case MIRType_Null: { + case MIRType::Null: { const JSAtomState& names = GetJitContext()->runtime->names(); LPointer* lir = new(alloc()) LPointer(names.null); define(lir, ins); break; } - case MIRType_Undefined: { + case MIRType::Undefined: { const JSAtomState& names = GetJitContext()->runtime->names(); LPointer* lir = new(alloc()) LPointer(names.undefined); define(lir, ins); break; } - case MIRType_Boolean: { + case MIRType::Boolean: { LBooleanToString* lir = new(alloc()) LBooleanToString(useRegister(opd)); define(lir, ins); break; } - case MIRType_Double: { + case MIRType::Double: { LDoubleToString* lir = new(alloc()) LDoubleToString(useRegister(opd), temp()); define(lir, ins); @@ -2140,7 +2173,7 @@ LIRGenerator::visitToString(MToString* ins) break; } - case MIRType_Int32: { + case MIRType::Int32: { LIntToString* lir = new(alloc()) LIntToString(useRegister(opd)); define(lir, ins); @@ -2148,11 +2181,11 @@ LIRGenerator::visitToString(MToString* ins) break; } - case MIRType_String: + case MIRType::String: redefine(ins, ins->input()); break; - case MIRType_Value: { + case MIRType::Value: { LValueToString* lir = new(alloc()) LValueToString(useBox(opd), tempToUnbox()); if (ins->fallible()) assignSnapshot(lir, Bailout_NonPrimitiveInput); @@ -2170,7 +2203,7 @@ LIRGenerator::visitToString(MToString* ins) void LIRGenerator::visitToObjectOrNull(MToObjectOrNull* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Value); + MOZ_ASSERT(ins->input()->type() == MIRType::Value); LValueToObjectOrNull* lir = new(alloc()) LValueToObjectOrNull(useBox(ins->input())); define(lir, ins); @@ -2254,9 +2287,9 @@ LIRGenerator::visitRegExp(MRegExp* ins) void LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins) { - MOZ_ASSERT(ins->regexp()->type() == MIRType_Object); - MOZ_ASSERT(ins->string()->type() == MIRType_String); - MOZ_ASSERT(ins->lastIndex()->type() == MIRType_Int32); + MOZ_ASSERT(ins->regexp()->type() == MIRType::Object); + MOZ_ASSERT(ins->string()->type() == MIRType::String); + MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32); LRegExpMatcher* lir = new(alloc()) LRegExpMatcher(useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg), useFixedAtStart(ins->string(), RegExpMatcherStringReg), @@ -2268,9 +2301,9 @@ LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins) void LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins) { - MOZ_ASSERT(ins->regexp()->type() == MIRType_Object); - MOZ_ASSERT(ins->string()->type() == MIRType_String); - MOZ_ASSERT(ins->lastIndex()->type() == MIRType_Int32); + MOZ_ASSERT(ins->regexp()->type() == MIRType::Object); + MOZ_ASSERT(ins->string()->type() == MIRType::String); + MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32); LRegExpSearcher* lir = new(alloc()) LRegExpSearcher(useFixedAtStart(ins->regexp(), RegExpTesterRegExpReg), useFixedAtStart(ins->string(), RegExpTesterStringReg), @@ -2282,9 +2315,9 @@ LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins) void LIRGenerator::visitRegExpTester(MRegExpTester* ins) { - MOZ_ASSERT(ins->regexp()->type() == MIRType_Object); - MOZ_ASSERT(ins->string()->type() == MIRType_String); - MOZ_ASSERT(ins->lastIndex()->type() == MIRType_Int32); + MOZ_ASSERT(ins->regexp()->type() == MIRType::Object); + MOZ_ASSERT(ins->string()->type() == MIRType::String); + MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32); LRegExpTester* lir = new(alloc()) LRegExpTester(useFixedAtStart(ins->regexp(), RegExpTesterRegExpReg), useFixedAtStart(ins->string(), RegExpTesterStringReg), @@ -2296,8 +2329,8 @@ LIRGenerator::visitRegExpTester(MRegExpTester* ins) void LIRGenerator::visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Boolean); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Boolean); LRegExpPrototypeOptimizable* lir = new(alloc()) LRegExpPrototypeOptimizable(useRegister(ins->object()), temp()); define(lir, ins); @@ -2306,21 +2339,32 @@ LIRGenerator::visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins) void LIRGenerator::visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->proto()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Boolean); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->proto()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Boolean); LRegExpInstanceOptimizable* lir = new(alloc()) LRegExpInstanceOptimizable(useRegister(ins->object()), useRegister(ins->proto()), temp()); define(lir, ins); } +void +LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins) +{ + MOZ_ASSERT(ins->str()->type() == MIRType::String); + MOZ_ASSERT(ins->type() == MIRType::Int32); + LGetFirstDollarIndex* lir = new(alloc()) LGetFirstDollarIndex(useRegister(ins->str()), + temp(), temp(), temp()); + define(lir, ins); + assignSafepoint(lir, ins); +} + void LIRGenerator::visitStringReplace(MStringReplace* ins) { - MOZ_ASSERT(ins->pattern()->type() == MIRType_String); - MOZ_ASSERT(ins->string()->type() == MIRType_String); - MOZ_ASSERT(ins->replacement()->type() == MIRType_String); + MOZ_ASSERT(ins->pattern()->type() == MIRType::String); + MOZ_ASSERT(ins->string()->type() == MIRType::String); + MOZ_ASSERT(ins->replacement()->type() == MIRType::String); LStringReplace* lir = new(alloc()) LStringReplace(useRegisterOrConstantAtStart(ins->string()), useRegisterAtStart(ins->pattern()), @@ -2335,8 +2379,8 @@ LIRGenerator::visitBinarySharedStub(MBinarySharedStub* ins) MDefinition* lhs = ins->getOperand(0); MDefinition* rhs = ins->getOperand(1); - MOZ_ASSERT(ins->type() == MIRType_Value); - MOZ_ASSERT(ins->type() == MIRType_Value); + MOZ_ASSERT(ins->type() == MIRType::Value); + MOZ_ASSERT(ins->type() == MIRType::Value); LBinarySharedStub* lir = new(alloc()) LBinarySharedStub(useBoxFixedAtStart(lhs, R0), useBoxFixedAtStart(rhs, R1)); @@ -2348,7 +2392,7 @@ void LIRGenerator::visitUnarySharedStub(MUnarySharedStub* ins) { MDefinition* input = ins->getOperand(0); - MOZ_ASSERT(ins->type() == MIRType_Value); + MOZ_ASSERT(ins->type() == MIRType::Value); LUnarySharedStub* lir = new(alloc()) LUnarySharedStub(useBoxFixedAtStart(input, R0)); defineSharedStubReturn(lir, ins); @@ -2358,7 +2402,7 @@ LIRGenerator::visitUnarySharedStub(MUnarySharedStub* ins) void LIRGenerator::visitNullarySharedStub(MNullarySharedStub* ins) { - MOZ_ASSERT(ins->type() == MIRType_Value); + MOZ_ASSERT(ins->type() == MIRType::Value); LNullarySharedStub* lir = new(alloc()) LNullarySharedStub(); @@ -2388,8 +2432,8 @@ LIRGenerator::visitLambda(MLambda* ins) void LIRGenerator::visitLambdaArrow(MLambdaArrow* ins) { - MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object); - MOZ_ASSERT(ins->newTargetDef()->type() == MIRType_Value); + MOZ_ASSERT(ins->scopeChain()->type() == MIRType::Object); + MOZ_ASSERT(ins->newTargetDef()->type() == MIRType::Value); LLambdaArrow* lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()), useBox(ins->newTargetDef())); @@ -2401,7 +2445,7 @@ void LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins) { MDefinition* obj = ins->object(); - MOZ_ASSERT(obj->type() == MIRType_Object); + MOZ_ASSERT(obj->type() == MIRType::Object); add(new(alloc()) LKeepAliveObject(useKeepalive(obj)), ins); } @@ -2437,8 +2481,8 @@ LIRGenerator::visitConvertElementsToDoubles(MConvertElementsToDoubles* ins) void LIRGenerator::visitMaybeToDoubleElement(MMaybeToDoubleElement* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->value()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->value()->type() == MIRType::Int32); LMaybeToDoubleElement* lir = new(alloc()) LMaybeToDoubleElement(useRegisterAtStart(ins->elements()), useRegisterAtStart(ins->value()), @@ -2458,12 +2502,12 @@ void LIRGenerator::visitLoadSlot(MLoadSlot* ins) { switch (ins->type()) { - case MIRType_Value: + case MIRType::Value: defineBox(new(alloc()) LLoadSlotV(useRegisterAtStart(ins->slots())), ins); break; - case MIRType_Undefined: - case MIRType_Null: + case MIRType::Undefined: + case MIRType::Null: MOZ_CRASH("typed load must have a payload"); default: @@ -2502,9 +2546,9 @@ LIRGenerator::visitAsmThrowUnreachable(MAsmThrowUnreachable* ins) void LIRGenerator::visitAsmReinterpret(MAsmReinterpret* ins) { - if (ins->type() == MIRType_Int64) + if (ins->type() == MIRType::Int64) defineInt64(new(alloc()) LAsmReinterpretToI64(useRegisterAtStart(ins->input())), ins); - else if (ins->input()->type() == MIRType_Int64) + else if (ins->input()->type() == MIRType::Int64) define(new(alloc()) LAsmReinterpretFromI64(useInt64RegisterAtStart(ins->input())), ins); else define(new(alloc()) LAsmReinterpret(useRegisterAtStart(ins->input())), ins); @@ -2516,16 +2560,16 @@ LIRGenerator::visitStoreSlot(MStoreSlot* ins) LInstruction* lir; switch (ins->value()->type()) { - case MIRType_Value: + case MIRType::Value: lir = new(alloc()) LStoreSlotV(useRegister(ins->slots()), useBox(ins->value())); add(lir, ins); break; - case MIRType_Double: + case MIRType::Double: add(new(alloc()) LStoreSlotT(useRegister(ins->slots()), useRegister(ins->value())), ins); break; - case MIRType_Float32: + case MIRType::Float32: MOZ_CRASH("Float32 shouldn't be stored in a slot."); default: @@ -2551,9 +2595,7 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier* ins) bool needTemp = !types->unknownObject() && types->getObjectCount() > 0; MIRType inputType = ins->getOperand(0)->type(); - DebugOnly outputType = ins->type(); - - MOZ_ASSERT(inputType == outputType); + MOZ_ASSERT(inputType == ins->type()); // Handle typebarrier that will always bail. // (Emit LBail for visibility). @@ -2566,7 +2608,7 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier* ins) } // Handle typebarrier with Value as input. - if (inputType == MIRType_Value) { + if (inputType == MIRType::Value) { LDefinition tmp = needTemp ? temp() : tempToUnbox(); LTypeBarrierV* barrier = new(alloc()) LTypeBarrierV(useBox(ins->input()), tmp); assignSnapshot(barrier, Bailout_TypeBarrierV); @@ -2578,9 +2620,9 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier* ins) // The payload needs to be tested if it either might be null or might have // an object that should be excluded from the barrier. bool needsObjectBarrier = false; - if (inputType == MIRType_ObjectOrNull) + if (inputType == MIRType::ObjectOrNull) needsObjectBarrier = true; - if (inputType == MIRType_Object && !types->hasType(TypeSet::AnyObjectType()) && + if (inputType == MIRType::Object && !types->hasType(TypeSet::AnyObjectType()) && ins->barrierKind() != BarrierKind::TypeTagOnly) { needsObjectBarrier = true; @@ -2628,7 +2670,7 @@ IsNonNurseryConstant(MDefinition* def) void LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); // LPostWriteBarrier assumes that if it has a constant object then that // object is tenured, and does not need to be tested for being in the @@ -2637,8 +2679,8 @@ LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) bool useConstantObject = IsNonNurseryConstant(ins->object()); switch (ins->value()->type()) { - case MIRType_Object: - case MIRType_ObjectOrNull: { + case MIRType::Object: + case MIRType::ObjectOrNull: { LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); LPostWriteBarrierO* lir = new(alloc()) LPostWriteBarrierO(useConstantObject @@ -2649,7 +2691,7 @@ LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) assignSafepoint(lir, ins); break; } - case MIRType_Value: { + case MIRType::Value: { LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); LPostWriteBarrierV* lir = new(alloc()) LPostWriteBarrierV(useConstantObject @@ -2671,8 +2713,8 @@ LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) void LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); // LPostWriteElementBarrier assumes that if it has a constant object then that // object is tenured, and does not need to be tested for being in the @@ -2683,8 +2725,8 @@ LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) !IsInsideNursery(&ins->object()->toConstant()->toObject()); switch (ins->value()->type()) { - case MIRType_Object: - case MIRType_ObjectOrNull: { + case MIRType::Object: + case MIRType::ObjectOrNull: { LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); LPostWriteElementBarrierO* lir = new(alloc()) LPostWriteElementBarrierO(useConstantObject @@ -2697,7 +2739,7 @@ LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) assignSafepoint(lir, ins); break; } - case MIRType_Value: { + case MIRType::Value: { LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); LPostWriteElementBarrierV* lir = new(alloc()) LPostWriteElementBarrierV(useConstantObject @@ -2720,15 +2762,15 @@ LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) void LIRGenerator::visitArrayLength(MArrayLength* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); define(new(alloc()) LArrayLength(useRegisterAtStart(ins->elements())), ins); } void LIRGenerator::visitSetArrayLength(MSetArrayLength* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); MOZ_ASSERT(ins->index()->isConstant()); add(new(alloc()) LSetArrayLength(useRegister(ins->elements()), @@ -2738,8 +2780,8 @@ LIRGenerator::visitSetArrayLength(MSetArrayLength* ins) void LIRGenerator::visitGetNextMapEntryForIterator(MGetNextMapEntryForIterator* ins) { - MOZ_ASSERT(ins->iter()->type() == MIRType_Object); - MOZ_ASSERT(ins->result()->type() == MIRType_Object); + MOZ_ASSERT(ins->iter()->type() == MIRType::Object); + MOZ_ASSERT(ins->result()->type() == MIRType::Object); auto lir = new(alloc()) LGetNextMapEntryForIterator(useRegister(ins->iter()), useRegister(ins->result()), temp(), temp(), temp()); @@ -2750,30 +2792,30 @@ LIRGenerator::visitGetNextMapEntryForIterator(MGetNextMapEntryForIterator* ins) void LIRGenerator::visitTypedArrayLength(MTypedArrayLength* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); define(new(alloc()) LTypedArrayLength(useRegisterAtStart(ins->object())), ins); } void LIRGenerator::visitTypedArrayElements(MTypedArrayElements* ins) { - MOZ_ASSERT(ins->type() == MIRType_Elements); + MOZ_ASSERT(ins->type() == MIRType::Elements); define(new(alloc()) LTypedArrayElements(useRegisterAtStart(ins->object())), ins); } void LIRGenerator::visitSetDisjointTypedElements(MSetDisjointTypedElements* ins) { - MOZ_ASSERT(ins->type() == MIRType_None); + MOZ_ASSERT(ins->type() == MIRType::None); MDefinition* target = ins->target(); - MOZ_ASSERT(target->type() == MIRType_Object); + MOZ_ASSERT(target->type() == MIRType::Object); MDefinition* targetOffset = ins->targetOffset(); - MOZ_ASSERT(targetOffset->type() == MIRType_Int32); + MOZ_ASSERT(targetOffset->type() == MIRType::Int32); MDefinition* source = ins->source(); - MOZ_ASSERT(source->type() == MIRType_Object); + MOZ_ASSERT(source->type() == MIRType::Object); auto lir = new(alloc()) LSetDisjointTypedElements(useRegister(target), useRegister(targetOffset), @@ -2785,14 +2827,14 @@ LIRGenerator::visitSetDisjointTypedElements(MSetDisjointTypedElements* ins) void LIRGenerator::visitTypedObjectDescr(MTypedObjectDescr* ins) { - MOZ_ASSERT(ins->type() == MIRType_Object); + MOZ_ASSERT(ins->type() == MIRType::Object); define(new(alloc()) LTypedObjectDescr(useRegisterAtStart(ins->object())), ins); } void LIRGenerator::visitTypedObjectElements(MTypedObjectElements* ins) { - MOZ_ASSERT(ins->type() == MIRType_Elements); + MOZ_ASSERT(ins->type() == MIRType::Elements); define(new(alloc()) LTypedObjectElements(useRegister(ins->object())), ins); } @@ -2808,15 +2850,15 @@ LIRGenerator::visitSetTypedObjectOffset(MSetTypedObjectOffset* ins) void LIRGenerator::visitInitializedLength(MInitializedLength* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); define(new(alloc()) LInitializedLength(useRegisterAtStart(ins->elements())), ins); } void LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); MOZ_ASSERT(ins->index()->isConstant()); add(new(alloc()) LSetInitializedLength(useRegister(ins->elements()), @@ -2856,7 +2898,7 @@ LIRGenerator::visitNot(MNot* ins) // String is converted to length of string in the type analysis phase (see // TestPolicy). - MOZ_ASSERT(op->type() != MIRType_String); + MOZ_ASSERT(op->type() != MIRType::String); // - boolean: x xor 1 // - int32: LCompare(x, 0) @@ -2864,29 +2906,29 @@ LIRGenerator::visitNot(MNot* ins) // - null or undefined: true // - object: false if it never emulates undefined, else LNotO(x) switch (op->type()) { - case MIRType_Boolean: { + case MIRType::Boolean: { MConstant* cons = MConstant::New(alloc(), Int32Value(1)); ins->block()->insertBefore(ins, cons); lowerForALU(new(alloc()) LBitOpI(JSOP_BITXOR), ins, op, cons); break; } - case MIRType_Int32: + case MIRType::Int32: define(new(alloc()) LNotI(useRegisterAtStart(op)), ins); break; - case MIRType_Double: + case MIRType::Double: define(new(alloc()) LNotD(useRegister(op)), ins); break; - case MIRType_Float32: + case MIRType::Float32: define(new(alloc()) LNotF(useRegister(op)), ins); break; - case MIRType_Undefined: - case MIRType_Null: + case MIRType::Undefined: + case MIRType::Null: define(new(alloc()) LInteger(1), ins); break; - case MIRType_Symbol: + case MIRType::Symbol: define(new(alloc()) LInteger(0), ins); break; - case MIRType_Object: + case MIRType::Object: if (!ins->operandMightEmulateUndefined()) { // Objects that don't emulate undefined can be constant-folded. define(new(alloc()) LInteger(0), ins); @@ -2895,7 +2937,7 @@ LIRGenerator::visitNot(MNot* ins) define(new(alloc()) LNotO(useRegister(op)), ins); } break; - case MIRType_Value: { + case MIRType::Value: { LDefinition temp0, temp1; if (ins->operandMightEmulateUndefined()) { temp0 = temp(); @@ -2948,11 +2990,11 @@ LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins) void LIRGenerator::visitInArray(MInArray* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); - MOZ_ASSERT(ins->initLength()->type() == MIRType_Int32); - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Boolean); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); + MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Boolean); LAllocation object; if (ins->needsNegativeIntCheck()) @@ -2970,10 +3012,10 @@ void LIRGenerator::visitLoadElement(MLoadElement* ins) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); switch (ins->type()) { - case MIRType_Value: + case MIRType::Value: { LLoadElementV* lir = new(alloc()) LLoadElementV(useRegister(ins->elements()), useRegisterOrConstant(ins->index())); @@ -2982,8 +3024,8 @@ LIRGenerator::visitLoadElement(MLoadElement* ins) defineBox(lir, ins); break; } - case MIRType_Undefined: - case MIRType_Null: + case MIRType::Undefined: + case MIRType::Null: MOZ_CRASH("typed load must have a payload"); default: @@ -3001,10 +3043,10 @@ LIRGenerator::visitLoadElement(MLoadElement* ins) void LIRGenerator::visitLoadElementHole(MLoadElementHole* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); - MOZ_ASSERT(ins->initLength()->type() == MIRType_Int32); - MOZ_ASSERT(ins->type() == MIRType_Value); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); + MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32); + MOZ_ASSERT(ins->type() == MIRType::Value); LLoadElementHole* lir = new(alloc()) LLoadElementHole(useRegister(ins->elements()), useRegisterOrConstant(ins->index()), @@ -3018,16 +3060,16 @@ void LIRGenerator::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); - if (ins->type() == MIRType_Object || ins->type() == MIRType_ObjectOrNull) { + if (ins->type() == MIRType::Object || ins->type() == MIRType::ObjectOrNull) { LLoadUnboxedPointerT* lir = new(alloc()) LLoadUnboxedPointerT(useRegister(ins->elements()), useRegisterOrConstant(ins->index())); if (ins->nullBehavior() == MLoadUnboxedObjectOrNull::BailOnNull) assignSnapshot(lir, Bailout_TypeBarrierO); define(lir, ins); } else { - MOZ_ASSERT(ins->type() == MIRType_Value); + MOZ_ASSERT(ins->type() == MIRType::Value); MOZ_ASSERT(ins->nullBehavior() != MLoadUnboxedObjectOrNull::BailOnNull); LLoadUnboxedPointerV* lir = new(alloc()) LLoadUnboxedPointerV(useRegister(ins->elements()), @@ -3040,8 +3082,8 @@ void LIRGenerator::visitLoadUnboxedString(MLoadUnboxedString* ins) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); - MOZ_ASSERT(ins->type() == MIRType_String); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); + MOZ_ASSERT(ins->type() == MIRType::String); LLoadUnboxedPointerT* lir = new(alloc()) LLoadUnboxedPointerT(useRegister(ins->elements()), useRegisterOrConstant(ins->index())); @@ -3052,13 +3094,13 @@ void LIRGenerator::visitStoreElement(MStoreElement* ins) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); switch (ins->value()->type()) { - case MIRType_Value: + case MIRType::Value: { LInstruction* lir = new(alloc()) LStoreElementV(elements, index, useBox(ins->value())); if (ins->fallible()) @@ -3082,8 +3124,8 @@ LIRGenerator::visitStoreElement(MStoreElement* ins) void LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse object = useRegister(ins->object()); const LUse elements = useRegister(ins->elements()); @@ -3096,7 +3138,7 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) LInstruction* lir; switch (ins->value()->type()) { - case MIRType_Value: + case MIRType::Value: lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()), tempDef); break; @@ -3117,10 +3159,10 @@ void LIRGenerator::visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); - MOZ_ASSERT(ins->value()->type() == MIRType_Object || - ins->value()->type() == MIRType_Null || - ins->value()->type() == MIRType_ObjectOrNull); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); + MOZ_ASSERT(ins->value()->type() == MIRType::Object || + ins->value()->type() == MIRType::Null || + ins->value()->type() == MIRType::ObjectOrNull); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrNonDoubleConstant(ins->index()); @@ -3134,8 +3176,8 @@ void LIRGenerator::visitStoreUnboxedString(MStoreUnboxedString* ins) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); - MOZ_ASSERT(ins->value()->type() == MIRType_String); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); + MOZ_ASSERT(ins->value()->type() == MIRType::String); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -3165,15 +3207,15 @@ LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) LUse object = useRegister(ins->object()); switch (ins->type()) { - case MIRType_Value: + case MIRType::Value: { LArrayPopShiftV* lir = new(alloc()) LArrayPopShiftV(object, temp(), temp()); defineBox(lir, ins); assignSafepoint(lir, ins); break; } - case MIRType_Undefined: - case MIRType_Null: + case MIRType::Undefined: + case MIRType::Null: MOZ_CRASH("typed load must have a payload"); default: @@ -3189,12 +3231,12 @@ LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) void LIRGenerator::visitArrayPush(MArrayPush* ins) { - MOZ_ASSERT(ins->type() == MIRType_Int32); + MOZ_ASSERT(ins->type() == MIRType::Int32); LUse object = useRegister(ins->object()); switch (ins->value()->type()) { - case MIRType_Value: + case MIRType::Value: { LArrayPushV* lir = new(alloc()) LArrayPushV(object, useBox(ins->value()), temp()); define(lir, ins); @@ -3216,10 +3258,10 @@ LIRGenerator::visitArrayPush(MArrayPush* ins) void LIRGenerator::visitArraySlice(MArraySlice* ins) { - MOZ_ASSERT(ins->type() == MIRType_Object); - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->begin()->type() == MIRType_Int32); - MOZ_ASSERT(ins->end()->type() == MIRType_Int32); + MOZ_ASSERT(ins->type() == MIRType::Object); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->begin()->type() == MIRType::Int32); + MOZ_ASSERT(ins->end()->type() == MIRType::Int32); LArraySlice* lir = new(alloc()) LArraySlice(useFixed(ins->object(), CallTempReg0), useFixed(ins->begin(), CallTempReg1), @@ -3233,9 +3275,9 @@ LIRGenerator::visitArraySlice(MArraySlice* ins) void LIRGenerator::visitArrayJoin(MArrayJoin* ins) { - MOZ_ASSERT(ins->type() == MIRType_String); - MOZ_ASSERT(ins->array()->type() == MIRType_Object); - MOZ_ASSERT(ins->sep()->type() == MIRType_String); + MOZ_ASSERT(ins->type() == MIRType::String); + MOZ_ASSERT(ins->array()->type() == MIRType::Object); + MOZ_ASSERT(ins->sep()->type() == MIRType::String); LArrayJoin* lir = new(alloc()) LArrayJoin(useRegisterAtStart(ins->array()), useRegisterAtStart(ins->sep())); @@ -3246,10 +3288,10 @@ LIRGenerator::visitArrayJoin(MArrayJoin* ins) void LIRGenerator::visitSinCos(MSinCos *ins) { - MOZ_ASSERT(ins->type() == MIRType_SinCosDouble); - MOZ_ASSERT(ins->input()->type() == MIRType_Double || - ins->input()->type() == MIRType_Float32 || - ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->type() == MIRType::SinCosDouble); + MOZ_ASSERT(ins->input()->type() == MIRType::Double || + ins->input()->type() == MIRType::Float32 || + ins->input()->type() == MIRType::Int32); LSinCos *lir = new (alloc()) LSinCos(useRegisterAtStart(ins->input()), tempFixed(CallTempReg0), @@ -3260,9 +3302,9 @@ LIRGenerator::visitSinCos(MSinCos *ins) void LIRGenerator::visitStringSplit(MStringSplit* ins) { - MOZ_ASSERT(ins->type() == MIRType_Object); - MOZ_ASSERT(ins->string()->type() == MIRType_String); - MOZ_ASSERT(ins->separator()->type() == MIRType_String); + MOZ_ASSERT(ins->type() == MIRType::Object); + MOZ_ASSERT(ins->string()->type() == MIRType::String); + MOZ_ASSERT(ins->separator()->type() == MIRType::String); LStringSplit* lir = new(alloc()) LStringSplit(useRegisterAtStart(ins->string()), useRegisterAtStart(ins->separator())); @@ -3274,13 +3316,13 @@ void LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); MOZ_ASSERT(IsNumberType(ins->type()) || IsSimdType(ins->type()) || - ins->type() == MIRType_Boolean); + ins->type() == MIRType::Boolean); // We need a temp register for Uint32Array with known double result. LDefinition tempDef = LDefinition::BogusTemp(); @@ -3307,21 +3349,21 @@ LIRGenerator::visitClampToUint8(MClampToUint8* ins) MDefinition* in = ins->input(); switch (in->type()) { - case MIRType_Boolean: + case MIRType::Boolean: redefine(ins, in); break; - case MIRType_Int32: + case MIRType::Int32: defineReuseInput(new(alloc()) LClampIToUint8(useRegisterAtStart(in)), ins, 0); break; - case MIRType_Double: + case MIRType::Double: // LClampDToUint8 clobbers its input register. Making it available as // a temp copy describes this behavior to the register allocator. define(new(alloc()) LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)), ins); break; - case MIRType_Value: + case MIRType::Value: { LClampVToUint8* lir = new(alloc()) LClampVToUint8(useBox(in), tempDouble()); assignSnapshot(lir, Bailout_NonPrimitiveInput); @@ -3338,10 +3380,10 @@ LIRGenerator::visitClampToUint8(MClampToUint8* ins) void LIRGenerator::visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); - MOZ_ASSERT(ins->type() == MIRType_Value); + MOZ_ASSERT(ins->type() == MIRType::Value); const LUse object = useRegister(ins->object()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -3369,16 +3411,16 @@ void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); if (ins->isSimdWrite()) { - MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32x4, ins->value()->type() == MIRType_Float32x4); - MOZ_ASSERT_IF(ins->writeType() == Scalar::Int32x4, ins->value()->type() == MIRType_Int32x4); + MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32x4, ins->value()->type() == MIRType::Float32x4); + MOZ_ASSERT_IF(ins->writeType() == Scalar::Int32x4, ins->value()->type() == MIRType::Int32x4); } else if (ins->isFloatWrite()) { - MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32, ins->value()->type() == MIRType_Float32); - MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64, ins->value()->type() == MIRType_Double); + MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32, ins->value()->type() == MIRType::Float32); + MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64, ins->value()->type() == MIRType::Double); } else { - MOZ_ASSERT(ins->value()->type() == MIRType_Int32); + MOZ_ASSERT(ins->value()->type() == MIRType::Int32); } LUse elements = useRegister(ins->elements()); @@ -3409,15 +3451,15 @@ LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) void LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole* ins) { - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); - MOZ_ASSERT(ins->length()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); + MOZ_ASSERT(ins->length()->type() == MIRType::Int32); if (ins->isFloatWrite()) { - MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32, ins->value()->type() == MIRType_Float32); - MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64, ins->value()->type() == MIRType_Double); + MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32, ins->value()->type() == MIRType::Float32); + MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64, ins->value()->type() == MIRType::Double); } else { - MOZ_ASSERT(ins->value()->type() == MIRType_Int32); + MOZ_ASSERT(ins->value()->type() == MIRType::Int32); } LUse elements = useRegister(ins->elements()); @@ -3437,11 +3479,11 @@ void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) { MDefinition* obj = ins->object(); - MOZ_ASSERT(obj->type() == MIRType_Object); + MOZ_ASSERT(obj->type() == MIRType::Object); MIRType type = ins->type(); - if (type == MIRType_Value) { + if (type == MIRType::Value) { LLoadFixedSlotV* lir = new(alloc()) LLoadFixedSlotV(useRegisterAtStart(obj)); defineBox(lir, ins); } else { @@ -3454,7 +3496,7 @@ void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) { MDefinition* obj = ins->object(); - MOZ_ASSERT(obj->type() == MIRType_Object); + MOZ_ASSERT(obj->type() == MIRType::Object); LLoadFixedSlotAndUnbox* lir = new(alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj)); if (ins->fallible()) @@ -3466,9 +3508,9 @@ LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); - if (ins->value()->type() == MIRType_Value) { + if (ins->value()->type() == MIRType::Value) { LStoreFixedSlotV* lir = new(alloc()) LStoreFixedSlotV(useRegister(ins->object()), useBox(ins->value())); add(lir, ins); @@ -3482,7 +3524,7 @@ LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) void LIRGenerator::visitGetNameCache(MGetNameCache* ins) { - MOZ_ASSERT(ins->scopeObj()->type() == MIRType_Object); + MOZ_ASSERT(ins->scopeObj()->type() == MIRType::Object); // Set the performs-call flag so that we don't omit the overrecursed check. // This is necessary because the cache can attach a scripted getter stub @@ -3505,13 +3547,13 @@ LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) void LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); MDefinition* id = ins->idval(); - MOZ_ASSERT(id->type() == MIRType_String || - id->type() == MIRType_Symbol || - id->type() == MIRType_Int32 || - id->type() == MIRType_Value); + MOZ_ASSERT(id->type() == MIRType::String || + id->type() == MIRType::Symbol || + id->type() == MIRType::Int32 || + id->type() == MIRType::Value); if (ins->monitoredResult()) { // Set the performs-call flag so that we don't omit the overrecursed @@ -3522,9 +3564,9 @@ LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) // If this is a GETPROP, the id is a constant string. Allow passing it as a // constant to reduce register allocation pressure. - bool useConstId = id->type() == MIRType_String || id->type() == MIRType_Symbol; + bool useConstId = id->type() == MIRType::String || id->type() == MIRType::Symbol; - if (ins->type() == MIRType_Value) { + if (ins->type() == MIRType::Value) { LGetPropertyCacheV* lir = new(alloc()) LGetPropertyCacheV(useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId)); @@ -3542,15 +3584,15 @@ LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) void LIRGenerator::visitGetPropertyPolymorphic(MGetPropertyPolymorphic* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); - if (ins->type() == MIRType_Value) { + if (ins->type() == MIRType::Value) { LGetPropertyPolymorphicV* lir = new(alloc()) LGetPropertyPolymorphicV(useRegister(ins->obj())); assignSnapshot(lir, Bailout_ShapeGuard); defineBox(lir, ins); } else { - LDefinition maybeTemp = (ins->type() == MIRType_Double) ? temp() : LDefinition::BogusTemp(); + LDefinition maybeTemp = (ins->type() == MIRType::Double) ? temp() : LDefinition::BogusTemp(); LGetPropertyPolymorphicT* lir = new(alloc()) LGetPropertyPolymorphicT(useRegister(ins->obj()), maybeTemp); assignSnapshot(lir, Bailout_ShapeGuard); @@ -3561,9 +3603,9 @@ LIRGenerator::visitGetPropertyPolymorphic(MGetPropertyPolymorphic* ins) void LIRGenerator::visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); - if (ins->value()->type() == MIRType_Value) { + if (ins->value()->type() == MIRType::Value) { LSetPropertyPolymorphicV* lir = new(alloc()) LSetPropertyPolymorphicV(useRegister(ins->obj()), useBox(ins->value()), @@ -3583,8 +3625,8 @@ LIRGenerator::visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins) void LIRGenerator::visitBindNameCache(MBindNameCache* ins) { - MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Object); + MOZ_ASSERT(ins->scopeChain()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Object); LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->scopeChain())); define(lir, ins); @@ -3594,8 +3636,8 @@ LIRGenerator::visitBindNameCache(MBindNameCache* ins) void LIRGenerator::visitCallBindVar(MCallBindVar* ins) { - MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Object); + MOZ_ASSERT(ins->scopeChain()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Object); LCallBindVar* lir = new(alloc()) LCallBindVar(useRegister(ins->scopeChain())); define(lir, ins); @@ -3625,7 +3667,7 @@ LIRGenerator::visitGuardObject(MGuardObject* ins) { // The type policy does all the work, so at this point the input // is guaranteed to be an object. - MOZ_ASSERT(ins->input()->type() == MIRType_Object); + MOZ_ASSERT(ins->input()->type() == MIRType::Object); redefine(ins, ins->input()); } @@ -3634,14 +3676,14 @@ LIRGenerator::visitGuardString(MGuardString* ins) { // The type policy does all the work, so at this point the input // is guaranteed to be a string. - MOZ_ASSERT(ins->input()->type() == MIRType_String); + MOZ_ASSERT(ins->input()->type() == MIRType::String); redefine(ins, ins->input()); } void LIRGenerator::visitGuardSharedTypedArray(MGuardSharedTypedArray* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Object); + MOZ_ASSERT(ins->input()->type() == MIRType::Object); LGuardSharedTypedArray* guard = new(alloc()) LGuardSharedTypedArray(useRegister(ins->obj()), temp()); assignSnapshot(guard, Bailout_NonSharedTypedArrayInput); @@ -3651,15 +3693,15 @@ LIRGenerator::visitGuardSharedTypedArray(MGuardSharedTypedArray* ins) void LIRGenerator::visitPolyInlineGuard(MPolyInlineGuard* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Object); + MOZ_ASSERT(ins->input()->type() == MIRType::Object); redefine(ins, ins->input()); } void LIRGenerator::visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Object); LGuardReceiverPolymorphic* guard = new(alloc()) LGuardReceiverPolymorphic(useRegister(ins->obj()), temp()); @@ -3693,21 +3735,21 @@ LIRGenerator::visitAssertRange(MAssertRange* ins) LInstruction* lir = nullptr; switch (input->type()) { - case MIRType_Boolean: - case MIRType_Int32: + case MIRType::Boolean: + case MIRType::Int32: lir = new(alloc()) LAssertRangeI(useRegisterAtStart(input)); break; - case MIRType_Double: + case MIRType::Double: lir = new(alloc()) LAssertRangeD(useRegister(input), tempDouble()); break; - case MIRType_Float32: { + case MIRType::Float32: { LDefinition armtemp = hasMultiAlias() ? tempDouble() : LDefinition::BogusTemp(); lir = new(alloc()) LAssertRangeF(useRegister(input), tempDouble(), armtemp); break; } - case MIRType_Value: + case MIRType::Value: lir = new(alloc()) LAssertRangeV(useBox(input), tempToUnbox(), tempDouble(), tempDouble()); break; @@ -3731,8 +3773,8 @@ LIRGenerator::visitCallGetProperty(MCallGetProperty* ins) void LIRGenerator::visitCallGetElement(MCallGetElement* ins) { - MOZ_ASSERT(ins->lhs()->type() == MIRType_Value); - MOZ_ASSERT(ins->rhs()->type() == MIRType_Value); + MOZ_ASSERT(ins->lhs()->type() == MIRType::Value); + MOZ_ASSERT(ins->rhs()->type() == MIRType::Value); LCallGetElement* lir = new(alloc()) LCallGetElement(useBoxAtStart(ins->lhs()), useBoxAtStart(ins->rhs())); @@ -3769,17 +3811,17 @@ LIRGenerator::visitDeleteElement(MDeleteElement* ins) void LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); MDefinition* id = ins->idval(); - MOZ_ASSERT(id->type() == MIRType_String || - id->type() == MIRType_Symbol || - id->type() == MIRType_Int32 || - id->type() == MIRType_Value); + MOZ_ASSERT(id->type() == MIRType::String || + id->type() == MIRType::Symbol || + id->type() == MIRType::Int32 || + id->type() == MIRType::Value); // If this is a SETPROP, the id is a constant string. Allow passing it as a // constant to reduce register allocation pressure. - bool useConstId = id->type() == MIRType_String || id->type() == MIRType_Symbol; + bool useConstId = id->type() == MIRType::String || id->type() == MIRType::Symbol; bool useConstValue = IsNonNurseryConstant(ins->value()); // Set the performs-call flag so that we don't omit the overrecursed check. @@ -3793,8 +3835,8 @@ LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) LDefinition tempD = LDefinition::BogusTemp(); LDefinition tempF32 = LDefinition::BogusTemp(); - if (id->mightBeType(MIRType_Int32)) { - if (id->type() != MIRType_Int32) + if (id->mightBeType(MIRType::Int32)) { + if (id->type() != MIRType::Int32) tempToUnboxIndex = tempToUnbox(); tempD = tempDouble(); tempF32 = hasUnaliasedDouble() ? tempFloat32() : LDefinition::BogusTemp(); @@ -3813,9 +3855,9 @@ LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) void LIRGenerator::visitCallSetElement(MCallSetElement* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->index()->type() == MIRType_Value); - MOZ_ASSERT(ins->value()->type() == MIRType_Value); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->index()->type() == MIRType::Value); + MOZ_ASSERT(ins->value()->type() == MIRType::Value); LCallSetElement* lir = new(alloc()) LCallSetElement(useRegisterAtStart(ins->object()), useBoxAtStart(ins->index()), @@ -3874,7 +3916,7 @@ LIRGenerator::visitIteratorEnd(MIteratorEnd* ins) void LIRGenerator::visitStringLength(MStringLength* ins) { - MOZ_ASSERT(ins->string()->type() == MIRType_String); + MOZ_ASSERT(ins->string()->type() == MIRType::String); define(new(alloc()) LStringLength(useRegisterAtStart(ins->string())), ins); } @@ -3903,11 +3945,11 @@ LIRGenerator::visitSetFrameArgument(MSetFrameArgument* ins) { MDefinition* input = ins->input(); - if (input->type() == MIRType_Value) { + if (input->type() == MIRType::Value) { LSetFrameArgumentV* lir = new(alloc()) LSetFrameArgumentV(useBox(input)); add(lir, ins); - } else if (input->type() == MIRType_Undefined || input->type() == MIRType_Null) { - Value val = input->type() == MIRType_Undefined ? UndefinedValue() : NullValue(); + } else if (input->type() == MIRType::Undefined || input->type() == MIRType::Null) { + Value val = input->type() == MIRType::Undefined ? UndefinedValue() : NullValue(); LSetFrameArgumentC* lir = new(alloc()) LSetFrameArgumentC(val); add(lir, ins); } else { @@ -3927,7 +3969,7 @@ LIRGenerator::visitRunOncePrologue(MRunOncePrologue* ins) void LIRGenerator::visitRest(MRest* ins) { - MOZ_ASSERT(ins->numActuals()->type() == MIRType_Int32); + MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32); LRest* lir = new(alloc()) LRest(useFixed(ins->numActuals(), CallTempReg0), tempFixed(CallTempReg1), @@ -3941,7 +3983,7 @@ void LIRGenerator::visitThrow(MThrow* ins) { MDefinition* value = ins->getOperand(0); - MOZ_ASSERT(value->type() == MIRType_Value); + MOZ_ASSERT(value->type() == MIRType::Value); LThrow* lir = new(alloc()) LThrow(useBoxAtStart(value)); add(lir, ins); @@ -3954,8 +3996,8 @@ LIRGenerator::visitIn(MIn* ins) MDefinition* lhs = ins->lhs(); MDefinition* rhs = ins->rhs(); - MOZ_ASSERT(lhs->type() == MIRType_Value); - MOZ_ASSERT(rhs->type() == MIRType_Object); + MOZ_ASSERT(lhs->type() == MIRType::Value); + MOZ_ASSERT(rhs->type() == MIRType::Object); LIn* lir = new(alloc()) LIn(useBoxAtStart(lhs), useRegisterAtStart(rhs)); defineReturn(lir, ins); @@ -3967,9 +4009,9 @@ LIRGenerator::visitInstanceOf(MInstanceOf* ins) { MDefinition* lhs = ins->getOperand(0); - MOZ_ASSERT(lhs->type() == MIRType_Value || lhs->type() == MIRType_Object); + MOZ_ASSERT(lhs->type() == MIRType::Value || lhs->type() == MIRType::Object); - if (lhs->type() == MIRType_Object) { + if (lhs->type() == MIRType::Object) { LInstanceOfO* lir = new(alloc()) LInstanceOfO(useRegister(lhs)); define(lir, ins); assignSafepoint(lir, ins); @@ -3986,8 +4028,8 @@ LIRGenerator::visitCallInstanceOf(MCallInstanceOf* ins) MDefinition* lhs = ins->lhs(); MDefinition* rhs = ins->rhs(); - MOZ_ASSERT(lhs->type() == MIRType_Value); - MOZ_ASSERT(rhs->type() == MIRType_Object); + MOZ_ASSERT(lhs->type() == MIRType::Value); + MOZ_ASSERT(rhs->type() == MIRType::Object); LCallInstanceOf* lir = new(alloc()) LCallInstanceOf(useBoxAtStart(lhs), useRegisterAtStart(rhs)); @@ -3998,16 +4040,16 @@ LIRGenerator::visitCallInstanceOf(MCallInstanceOf* ins) void LIRGenerator::visitIsCallable(MIsCallable* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Boolean); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Boolean); define(new(alloc()) LIsCallable(useRegister(ins->object())), ins); } void LIRGenerator::visitIsConstructor(MIsConstructor* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Boolean); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Boolean); define(new(alloc()) LIsConstructor(useRegister(ins->object())), ins); } @@ -4041,7 +4083,7 @@ LIRGenerator::visitIsObject(MIsObject* ins) } MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Value); + MOZ_ASSERT(opd->type() == MIRType::Value); LIsObject* lir = new(alloc()) LIsObject(useBoxAtStart(opd)); define(lir, ins); } @@ -4049,8 +4091,8 @@ LIRGenerator::visitIsObject(MIsObject* ins) void LIRGenerator::visitHasClass(MHasClass* ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); - MOZ_ASSERT(ins->type() == MIRType_Boolean); + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::Boolean); define(new(alloc()) LHasClass(useRegister(ins->object())), ins); } @@ -4089,16 +4131,16 @@ LIRGenerator::visitAsmJSReturn(MAsmJSReturn* ins) { MDefinition* rval = ins->getOperand(0); LAsmJSReturn* lir = new(alloc()) LAsmJSReturn; - if (rval->type() == MIRType_Float32) + if (rval->type() == MIRType::Float32) lir->setOperand(0, useFixed(rval, ReturnFloat32Reg)); - else if (rval->type() == MIRType_Double) + else if (rval->type() == MIRType::Double) lir->setOperand(0, useFixed(rval, ReturnDoubleReg)); else if (IsSimdType(rval->type())) lir->setOperand(0, useFixed(rval, ReturnSimd128Reg)); - else if (rval->type() == MIRType_Int32) + else if (rval->type() == MIRType::Int32) lir->setOperand(0, useFixed(rval, ReturnReg)); #if JS_BITS_PER_WORD == 64 - else if (rval->type() == MIRType_Int64) + else if (rval->type() == MIRType::Int64) lir->setOperand(0, useFixed(rval, ReturnReg)); #endif else @@ -4141,7 +4183,7 @@ LIRGenerator::visitAsmJSCall(MAsmJSCall* ins) args[ins->dynamicCalleeOperandIndex()] = useFixed(ins->callee().dynamic(), CallTempReg0); LInstruction* lir = new(alloc()) LAsmJSCall(args, ins->numOperands()); - if (ins->type() == MIRType_None) + if (ins->type() == MIRType::None) add(lir, ins); else defineReturn(lir, ins); @@ -4203,11 +4245,11 @@ LIRGenerator::visitGetDOMMember(MGetDOMMember* ins) "Member gets had better not alias the world"); MDefinition* obj = ins->object(); - MOZ_ASSERT(obj->type() == MIRType_Object); + MOZ_ASSERT(obj->type() == MIRType::Object); MIRType type = ins->type(); - if (type == MIRType_Value) { + if (type == MIRType::Value) { LGetDOMMemberV* lir = new(alloc()) LGetDOMMemberV(useRegisterAtStart(obj)); defineBox(lir, ins); } else { @@ -4237,19 +4279,19 @@ LIRGenerator::visitSimdBox(MSimdBox* ins) void LIRGenerator::visitSimdUnbox(MSimdUnbox* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Object); + MOZ_ASSERT(ins->input()->type() == MIRType::Object); MOZ_ASSERT(IsSimdType(ins->type())); LUse in = useRegister(ins->input()); BailoutKind kind; switch (ins->type()) { - case MIRType_Bool32x4: + case MIRType::Bool32x4: kind = Bailout_NonSimdBool32x4Input; break; - case MIRType_Int32x4: + case MIRType::Int32x4: kind = Bailout_NonSimdInt32x4Input; break; - case MIRType_Float32x4: + case MIRType::Float32x4: kind = Bailout_NonSimdFloat32x4Input; break; default: @@ -4267,11 +4309,11 @@ LIRGenerator::visitSimdConstant(MSimdConstant* ins) MOZ_ASSERT(IsSimdType(ins->type())); switch (ins->type()) { - case MIRType_Bool32x4: - case MIRType_Int32x4: + case MIRType::Bool32x4: + case MIRType::Int32x4: define(new(alloc()) LInt32x4(), ins); break; - case MIRType_Float32x4: + case MIRType::Float32x4: define(new(alloc()) LFloat32x4(), ins); break; default: @@ -4285,8 +4327,8 @@ LIRGenerator::visitSimdConvert(MSimdConvert* ins) MOZ_ASSERT(IsSimdType(ins->type())); MDefinition* input = ins->input(); LUse use = useRegister(input); - if (ins->type() == MIRType_Int32x4) { - MOZ_ASSERT(input->type() == MIRType_Float32x4); + if (ins->type() == MIRType::Int32x4) { + MOZ_ASSERT(input->type() == MIRType::Float32x4); switch (ins->signedness()) { case SimdSign::Signed: { LFloat32x4ToInt32x4* lir = new(alloc()) LFloat32x4ToInt32x4(use, temp()); @@ -4306,8 +4348,8 @@ LIRGenerator::visitSimdConvert(MSimdConvert* ins) default: MOZ_CRASH("Unexpected SimdConvert sign"); } - } else if (ins->type() == MIRType_Float32x4) { - MOZ_ASSERT(input->type() == MIRType_Int32x4); + } else if (ins->type() == MIRType::Float32x4) { + MOZ_ASSERT(input->type() == MIRType::Int32x4); MOZ_ASSERT(ins->signedness() == SimdSign::Signed, "Unexpected SimdConvert sign"); define(new(alloc()) LInt32x4ToFloat32x4(use), ins); } else { @@ -4334,12 +4376,12 @@ LIRGenerator::visitSimdExtractElement(MSimdExtractElement* ins) MOZ_ASSERT(!IsSimdType(ins->type())); switch (ins->input()->type()) { - case MIRType_Int32x4: { + case MIRType::Int32x4: { MOZ_ASSERT(ins->signedness() != SimdSign::NotApplicable); // Note: there could be int16x8 in the future, which doesn't use the // same instruction. We either need to pass the arity or create new LIns. LUse use = useRegisterAtStart(ins->input()); - if (ins->type() == MIRType_Double) { + if (ins->type() == MIRType::Double) { // Extract an Uint32 lane into a double. MOZ_ASSERT(ins->signedness() == SimdSign::Unsigned); define(new (alloc()) LSimdExtractElementU2D(use, temp()), ins); @@ -4348,13 +4390,13 @@ LIRGenerator::visitSimdExtractElement(MSimdExtractElement* ins) } break; } - case MIRType_Float32x4: { + case MIRType::Float32x4: { MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable); LUse use = useRegisterAtStart(ins->input()); define(new(alloc()) LSimdExtractElementF(use), ins); break; } - case MIRType_Bool32x4: { + case MIRType::Bool32x4: { MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable); LUse use = useRegisterAtStart(ins->input()); define(new(alloc()) LSimdExtractElementB(use), ins); @@ -4373,11 +4415,11 @@ LIRGenerator::visitSimdInsertElement(MSimdInsertElement* ins) LUse vec = useRegisterAtStart(ins->vector()); LUse val = useRegister(ins->value()); switch (ins->type()) { - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: defineReuseInput(new(alloc()) LSimdInsertElementI(vec, val), ins, 0); break; - case MIRType_Float32x4: + case MIRType::Float32x4: defineReuseInput(new(alloc()) LSimdInsertElementF(vec, val), ins, 0); break; default: @@ -4411,11 +4453,11 @@ LIRGenerator::visitSimdSwizzle(MSimdSwizzle* ins) MOZ_ASSERT(IsSimdType(ins->input()->type())); MOZ_ASSERT(IsSimdType(ins->type())); - if (ins->input()->type() == MIRType_Int32x4) { + if (ins->input()->type() == MIRType::Int32x4) { LUse use = useRegisterAtStart(ins->input()); LSimdSwizzleI* lir = new (alloc()) LSimdSwizzleI(use); define(lir, ins); - } else if (ins->input()->type() == MIRType_Float32x4) { + } else if (ins->input()->type() == MIRType::Float32x4) { LUse use = useRegisterAtStart(ins->input()); LSimdSwizzleF* lir = new (alloc()) LSimdSwizzleF(use); define(lir, ins); @@ -4430,9 +4472,9 @@ LIRGenerator::visitSimdGeneralShuffle(MSimdGeneralShuffle*ins) MOZ_ASSERT(IsSimdType(ins->type())); LSimdGeneralShuffleBase* lir; - if (ins->type() == MIRType_Int32x4) + if (ins->type() == MIRType::Int32x4) lir = new (alloc()) LSimdGeneralShuffleI(temp()); - else if (ins->type() == MIRType_Float32x4) + else if (ins->type() == MIRType::Float32x4) lir = new (alloc()) LSimdGeneralShuffleF(temp()); else MOZ_CRASH("Unknown SIMD kind when doing a shuffle"); @@ -4446,7 +4488,7 @@ LIRGenerator::visitSimdGeneralShuffle(MSimdGeneralShuffle*ins) } for (unsigned i = 0; i < ins->numLanes(); i++) { - MOZ_ASSERT(ins->lane(i)->type() == MIRType_Int32); + MOZ_ASSERT(ins->lane(i)->type() == MIRType::Int32); lir->setOperand(i + ins->numVectors(), useRegister(ins->lane(i))); } @@ -4460,7 +4502,7 @@ LIRGenerator::visitSimdShuffle(MSimdShuffle* ins) MOZ_ASSERT(IsSimdType(ins->lhs()->type())); MOZ_ASSERT(IsSimdType(ins->rhs()->type())); MOZ_ASSERT(IsSimdType(ins->type())); - MOZ_ASSERT(ins->type() == MIRType_Int32x4 || ins->type() == MIRType_Float32x4); + MOZ_ASSERT(ins->type() == MIRType::Int32x4 || ins->type() == MIRType::Float32x4); bool zFromLHS = ins->laneZ() < 4; bool wFromLHS = ins->laneW() < 4; @@ -4483,10 +4525,10 @@ LIRGenerator::visitSimdUnaryArith(MSimdUnaryArith* ins) // Cannot be at start, as the ouput is used as a temporary to store values. LUse in = use(ins->input()); - if (ins->type() == MIRType_Int32x4 || ins->type() == MIRType_Bool32x4) { + if (ins->type() == MIRType::Int32x4 || ins->type() == MIRType::Bool32x4) { LSimdUnaryArithIx4* lir = new(alloc()) LSimdUnaryArithIx4(in); define(lir, ins); - } else if (ins->type() == MIRType_Float32x4) { + } else if (ins->type() == MIRType::Float32x4) { LSimdUnaryArithFx4* lir = new(alloc()) LSimdUnaryArithFx4(in); define(lir, ins); } else { @@ -4504,11 +4546,11 @@ LIRGenerator::visitSimdBinaryComp(MSimdBinaryComp* ins) if (ShouldReorderCommutative(ins->lhs(), ins->rhs(), ins)) ins->reverse(); - if (ins->specialization() == MIRType_Int32x4) { + if (ins->specialization() == MIRType::Int32x4) { MOZ_ASSERT(ins->signedness() == SimdSign::Signed); LSimdBinaryCompIx4* add = new(alloc()) LSimdBinaryCompIx4(); lowerForCompIx4(add, ins, ins->lhs(), ins->rhs()); - } else if (ins->specialization() == MIRType_Float32x4) { + } else if (ins->specialization() == MIRType::Float32x4) { MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable); LSimdBinaryCompFx4* add = new(alloc()) LSimdBinaryCompFx4(); lowerForCompFx4(add, ins, ins->lhs(), ins->rhs()); @@ -4529,9 +4571,9 @@ LIRGenerator::visitSimdBinaryBitwise(MSimdBinaryBitwise* ins) ReorderCommutative(&lhs, &rhs, ins); switch (ins->type()) { - case MIRType_Bool32x4: - case MIRType_Int32x4: - case MIRType_Float32x4: { + case MIRType::Bool32x4: + case MIRType::Int32x4: + case MIRType::Float32x4: { LSimdBinaryBitwiseX4* lir = new(alloc()) LSimdBinaryBitwiseX4; lowerForFPU(lir, ins, lhs, rhs); break; @@ -4544,9 +4586,9 @@ LIRGenerator::visitSimdBinaryBitwise(MSimdBinaryBitwise* ins) void LIRGenerator::visitSimdShift(MSimdShift* ins) { - MOZ_ASSERT(ins->type() == MIRType_Int32x4); - MOZ_ASSERT(ins->lhs()->type() == MIRType_Int32x4); - MOZ_ASSERT(ins->rhs()->type() == MIRType_Int32); + MOZ_ASSERT(ins->type() == MIRType::Int32x4); + MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32x4); + MOZ_ASSERT(ins->rhs()->type() == MIRType::Int32); LUse vector = useRegisterAtStart(ins->lhs()); LAllocation value = useRegisterOrConstant(ins->rhs()); @@ -4561,7 +4603,7 @@ void LIRGenerator::visitLexicalCheck(MLexicalCheck* ins) { MDefinition* input = ins->input(); - MOZ_ASSERT(input->type() == MIRType_Value); + MOZ_ASSERT(input->type() == MIRType::Value); LLexicalCheck* lir = new(alloc()) LLexicalCheck(useBox(input)); assignSnapshot(lir, ins->bailoutKind()); add(lir, ins); @@ -4603,8 +4645,8 @@ LIRGenerator::visitCheckReturn(MCheckReturn* ins) { MDefinition* retVal = ins->returnValue(); MDefinition* thisVal = ins->thisValue(); - MOZ_ASSERT(retVal->type() == MIRType_Value); - MOZ_ASSERT(thisVal->type() == MIRType_Value); + MOZ_ASSERT(retVal->type() == MIRType::Value); + MOZ_ASSERT(thisVal->type() == MIRType::Value); LCheckReturn* lir = new(alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal)); assignSnapshot(lir, Bailout_BadDerivedConstructorReturn); @@ -4616,7 +4658,7 @@ void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) { MDefinition* checkVal = ins->checkValue(); - MOZ_ASSERT(checkVal->type() == MIRType_Value); + MOZ_ASSERT(checkVal->type() == MIRType::Value); LCheckObjCoercible* lir = new(alloc()) LCheckObjCoercible(useBoxAtStart(checkVal)); redefine(ins, checkVal); @@ -4628,7 +4670,7 @@ void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) { MDefinition* checkVal = ins->checkValue(); - MOZ_ASSERT(checkVal->type() == MIRType_Value); + MOZ_ASSERT(checkVal->type() == MIRType::Value); LDebugCheckSelfHosted* lir = new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal)); redefine(ins, checkVal); @@ -4697,7 +4739,7 @@ LIRGenerator::definePhis() size_t lirIndex = 0; MBasicBlock* block = current->mir(); for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) { - if (phi->type() == MIRType_Value) { + if (phi->type() == MIRType::Value) { defineUntypedPhi(*phi, lirIndex); lirIndex += BOX_PIECES; } else { @@ -4765,7 +4807,7 @@ LIRGenerator::visitBlock(MBasicBlock* block) MOZ_ASSERT(opd->type() == phi->type()); - if (phi->type() == MIRType_Value) { + if (phi->type() == MIRType::Value) { lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex); lirIndex += BOX_PIECES; } else { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index 4e72400632..36b403a644 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -123,6 +123,7 @@ class LIRGenerator : public LIRGeneratorSpecific void visitLsh(MLsh* ins); void visitRsh(MRsh* ins); void visitUrsh(MUrsh* ins); + void visitRotate(MRotate* ins); void visitFloor(MFloor* ins); void visitCeil(MCeil* ins); void visitRound(MRound* ins); @@ -158,6 +159,7 @@ class LIRGenerator : public LIRGeneratorSpecific void visitToFloat32(MToFloat32* convert); void visitToInt32(MToInt32* convert); void visitTruncateToInt32(MTruncateToInt32* truncate); + void visitWasmTruncateToInt32(MWasmTruncateToInt32* truncate); void visitWrapInt64ToInt32(MWrapInt64ToInt32* ins); void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins); void visitToString(MToString* convert); @@ -168,6 +170,7 @@ class LIRGenerator : public LIRGeneratorSpecific void visitRegExpTester(MRegExpTester* ins); void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins); void visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins); + void visitGetFirstDollarIndex(MGetFirstDollarIndex* ins); void visitStringReplace(MStringReplace* ins); void visitBinarySharedStub(MBinarySharedStub* ins); void visitUnarySharedStub(MUnarySharedStub* ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 937eeb5cbb..cc14918de5 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -188,6 +188,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineRegExpPrototypeOptimizable(callInfo); case InlinableNative::RegExpInstanceOptimizable: return inlineRegExpInstanceOptimizable(callInfo); + case InlinableNative::GetFirstDollarIndex: + return inlineGetFirstDollarIndex(callInfo); // String natives. case InlinableNative::String: @@ -231,15 +233,15 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) case InlinableNative::IntrinsicUnsafeSetReservedSlot: return inlineUnsafeSetReservedSlot(callInfo); case InlinableNative::IntrinsicUnsafeGetReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType_Value); + return inlineUnsafeGetReservedSlot(callInfo, MIRType::Value); case InlinableNative::IntrinsicUnsafeGetObjectFromReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType_Object); + return inlineUnsafeGetReservedSlot(callInfo, MIRType::Object); case InlinableNative::IntrinsicUnsafeGetInt32FromReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType_Int32); + return inlineUnsafeGetReservedSlot(callInfo, MIRType::Int32); case InlinableNative::IntrinsicUnsafeGetStringFromReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType_String); + return inlineUnsafeGetReservedSlot(callInfo, MIRType::String); case InlinableNative::IntrinsicUnsafeGetBooleanFromReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType_Boolean); + return inlineUnsafeGetReservedSlot(callInfo, MIRType::Boolean); // Utility intrinsics. case InlinableNative::IntrinsicIsCallable: @@ -360,7 +362,7 @@ IonBuilder::inlineNativeGetter(CallInfo& callInfo, JSFunction* target) MLoadFixedSlot* flags = MLoadFixedSlot::New(alloc(), thisArg, RegExpObject::flagsSlot()); current->add(flags); - flags->setResultType(MIRType_Int32); + flags->setResultType(MIRType::Int32); MConstant* maskConst = MConstant::New(alloc(), Int32Value(mask)); current->add(maskConst); MBitAnd* maskedFlag = MBitAnd::New(alloc(), flags, maskConst); @@ -412,7 +414,7 @@ IonBuilder::inlineMathFunction(CallInfo& callInfo, MMathFunction::Function funct if (callInfo.argc() != 1) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Double) + if (getInlineReturnType() != MIRType::Double) return InliningStatus_NotInlined; if (!IsNumberType(callInfo.getArg(0)->type())) return InliningStatus_NotInlined; @@ -465,7 +467,7 @@ IonBuilder::inlineArray(CallInfo& callInfo) // A single integer argument denotes initial length. if (callInfo.argc() == 1) { MDefinition* arg = callInfo.getArg(0); - if (arg->type() != MIRType_Int32) + if (arg->type() != MIRType::Int32) return InliningStatus_NotInlined; if (!arg->isConstant()) { @@ -529,16 +531,16 @@ IonBuilder::inlineArrayIsArray(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; MDefinition* arg = callInfo.getArg(0); bool isArray; - if (!arg->mightBeType(MIRType_Object)) { + if (!arg->mightBeType(MIRType::Object)) { isArray = false; } else { - if (arg->type() != MIRType_Object) + if (arg->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* types = arg->resultTypeSet(); @@ -564,9 +566,9 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) } MIRType returnType = getInlineReturnType(); - if (returnType == MIRType_Undefined || returnType == MIRType_Null) + if (returnType == MIRType::Undefined || returnType == MIRType::Null) return InliningStatus_NotInlined; - if (callInfo.thisArg()->type() != MIRType_Object) + if (callInfo.thisArg()->type() != MIRType::Object) return InliningStatus_NotInlined; // Pop and shift are only handled for dense arrays that have never been @@ -614,7 +616,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, nullptr, returnTypes); if (barrier != BarrierKind::NoBarrier) - returnType = MIRType_Value; + returnType = MIRType::Value; MArrayPopShift* ins = MArrayPopShift::New(alloc(), obj, mode, unboxedType, needsHoleCheck, maybeUndefined); @@ -640,13 +642,13 @@ IonBuilder::inlineArraySplice(CallInfo& callInfo) } // Ensure |this|, argument and result are objects. - if (getInlineReturnType() != MIRType_Object) + if (getInlineReturnType() != MIRType::Object) return InliningStatus_NotInlined; - if (callInfo.thisArg()->type() != MIRType_Object) + if (callInfo.thisArg()->type() != MIRType::Object) return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType_Int32) + if (callInfo.getArg(0)->type() != MIRType::Int32) return InliningStatus_NotInlined; - if (callInfo.getArg(1)->type() != MIRType_Int32) + if (callInfo.getArg(1)->type() != MIRType::Int32) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -679,11 +681,11 @@ IonBuilder::inlineArrayJoin(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_String) + if (getInlineReturnType() != MIRType::String) return InliningStatus_NotInlined; - if (callInfo.thisArg()->type() != MIRType_Object) + if (callInfo.thisArg()->type() != MIRType::Object) return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType_String) + if (callInfo.getArg(0)->type() != MIRType::String) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -715,9 +717,9 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Int32) + if (getInlineReturnType() != MIRType::Int32) return InliningStatus_NotInlined; - if (obj->type() != MIRType_Object) + if (obj->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* thisTypes = obj->resultTypeSet(); @@ -782,17 +784,17 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); // Ensure |this| and result are objects. - if (getInlineReturnType() != MIRType_Object) + if (getInlineReturnType() != MIRType::Object) return InliningStatus_NotInlined; - if (obj->type() != MIRType_Object) + if (obj->type() != MIRType::Object) return InliningStatus_NotInlined; // Arguments for the sliced region must be integers. if (callInfo.argc() > 0) { - if (callInfo.getArg(0)->type() != MIRType_Int32) + if (callInfo.getArg(0)->type() != MIRType::Int32) return InliningStatus_NotInlined; if (callInfo.argc() > 1) { - if (callInfo.getArg(1)->type() != MIRType_Int32) + if (callInfo.getArg(1)->type() != MIRType::Int32) return InliningStatus_NotInlined; } } @@ -904,8 +906,8 @@ IonBuilder::inlineMathAbs(CallInfo& callInfo) // Either argType == returnType, or // argType == Double or Float32, returnType == Int, or // argType == Float32, returnType == Double - if (argType != returnType && !(IsFloatingPointType(argType) && returnType == MIRType_Int32) - && !(argType == MIRType_Float32 && returnType == MIRType_Double)) + if (argType != returnType && !(IsFloatingPointType(argType) && returnType == MIRType::Int32) + && !(argType == MIRType::Float32 && returnType == MIRType::Double)) { return InliningStatus_NotInlined; } @@ -914,7 +916,7 @@ IonBuilder::inlineMathAbs(CallInfo& callInfo) // If the arg is a Float32, we specialize the op as double, it will be specialized // as float32 if necessary later. - MIRType absType = (argType == MIRType_Float32) ? MIRType_Double : argType; + MIRType absType = (argType == MIRType::Float32) ? MIRType::Double : argType; MInstruction* ins = MAbs::New(alloc(), callInfo.getArg(0), absType); current->add(ins); @@ -934,7 +936,7 @@ IonBuilder::inlineMathFloor(CallInfo& callInfo) MIRType returnType = getInlineReturnType(); // Math.floor(int(x)) == int(x) - if (argType == MIRType_Int32 && returnType == MIRType_Int32) { + if (argType == MIRType::Int32 && returnType == MIRType::Int32) { callInfo.setImplicitlyUsedUnchecked(); // The int operand may be something which bails out if the actual value // is not in the range of the result type of the MIR. We need to tell @@ -947,7 +949,7 @@ IonBuilder::inlineMathFloor(CallInfo& callInfo) return InliningStatus_Inlined; } - if (IsFloatingPointType(argType) && returnType == MIRType_Int32) { + if (IsFloatingPointType(argType) && returnType == MIRType::Int32) { callInfo.setImplicitlyUsedUnchecked(); MFloor* ins = MFloor::New(alloc(), callInfo.getArg(0)); current->add(ins); @@ -955,7 +957,7 @@ IonBuilder::inlineMathFloor(CallInfo& callInfo) return InliningStatus_Inlined; } - if (IsFloatingPointType(argType) && returnType == MIRType_Double) { + if (IsFloatingPointType(argType) && returnType == MIRType::Double) { callInfo.setImplicitlyUsedUnchecked(); MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Floor, nullptr); current->add(ins); @@ -978,7 +980,7 @@ IonBuilder::inlineMathCeil(CallInfo& callInfo) MIRType returnType = getInlineReturnType(); // Math.ceil(int(x)) == int(x) - if (argType == MIRType_Int32 && returnType == MIRType_Int32) { + if (argType == MIRType::Int32 && returnType == MIRType::Int32) { callInfo.setImplicitlyUsedUnchecked(); // The int operand may be something which bails out if the actual value // is not in the range of the result type of the MIR. We need to tell @@ -991,7 +993,7 @@ IonBuilder::inlineMathCeil(CallInfo& callInfo) return InliningStatus_Inlined; } - if (IsFloatingPointType(argType) && returnType == MIRType_Int32) { + if (IsFloatingPointType(argType) && returnType == MIRType::Int32) { callInfo.setImplicitlyUsedUnchecked(); MCeil* ins = MCeil::New(alloc(), callInfo.getArg(0)); current->add(ins); @@ -999,7 +1001,7 @@ IonBuilder::inlineMathCeil(CallInfo& callInfo) return InliningStatus_Inlined; } - if (IsFloatingPointType(argType) && returnType == MIRType_Double) { + if (IsFloatingPointType(argType) && returnType == MIRType::Double) { callInfo.setImplicitlyUsedUnchecked(); MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Ceil, nullptr); current->add(ins); @@ -1019,7 +1021,7 @@ IonBuilder::inlineMathClz32(CallInfo& callInfo) } MIRType returnType = getInlineReturnType(); - if (returnType != MIRType_Int32) + if (returnType != MIRType::Int32) return InliningStatus_NotInlined; if (!IsNumberType(callInfo.getArg(0)->type())) @@ -1046,7 +1048,7 @@ IonBuilder::inlineMathRound(CallInfo& callInfo) MIRType argType = callInfo.getArg(0)->type(); // Math.round(int(x)) == int(x) - if (argType == MIRType_Int32 && returnType == MIRType_Int32) { + if (argType == MIRType::Int32 && returnType == MIRType::Int32) { callInfo.setImplicitlyUsedUnchecked(); // The int operand may be something which bails out if the actual value // is not in the range of the result type of the MIR. We need to tell @@ -1059,7 +1061,7 @@ IonBuilder::inlineMathRound(CallInfo& callInfo) return InliningStatus_Inlined; } - if (IsFloatingPointType(argType) && returnType == MIRType_Int32) { + if (IsFloatingPointType(argType) && returnType == MIRType::Int32) { callInfo.setImplicitlyUsedUnchecked(); MRound* ins = MRound::New(alloc(), callInfo.getArg(0)); current->add(ins); @@ -1067,7 +1069,7 @@ IonBuilder::inlineMathRound(CallInfo& callInfo) return InliningStatus_Inlined; } - if (IsFloatingPointType(argType) && returnType == MIRType_Double) { + if (IsFloatingPointType(argType) && returnType == MIRType::Double) { callInfo.setImplicitlyUsedUnchecked(); MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Round, nullptr); current->add(ins); @@ -1087,7 +1089,7 @@ IonBuilder::inlineMathSqrt(CallInfo& callInfo) } MIRType argType = callInfo.getArg(0)->type(); - if (getInlineReturnType() != MIRType_Double) + if (getInlineReturnType() != MIRType::Double) return InliningStatus_NotInlined; if (!IsNumberType(argType)) return InliningStatus_NotInlined; @@ -1108,7 +1110,7 @@ IonBuilder::inlineMathAtan2(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Double) + if (getInlineReturnType() != MIRType::Double) return InliningStatus_NotInlined; MIRType argType0 = callInfo.getArg(0)->type(); @@ -1139,7 +1141,7 @@ IonBuilder::inlineMathHypot(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Double) + if (getInlineReturnType() != MIRType::Double) return InliningStatus_NotInlined; MDefinitionVector vector(alloc()); @@ -1194,7 +1196,7 @@ IonBuilder::inlineMathRandom(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Double) + if (getInlineReturnType() != MIRType::Double) return InliningStatus_NotInlined; // MRandom JIT code directly accesses the RNG. It's (barely) possible to @@ -1219,7 +1221,7 @@ IonBuilder::inlineMathImul(CallInfo& callInfo) } MIRType returnType = getInlineReturnType(); - if (returnType != MIRType_Int32) + if (returnType != MIRType::Int32) return InliningStatus_NotInlined; if (!IsNumberType(callInfo.getArg(0)->type())) @@ -1235,7 +1237,7 @@ IonBuilder::inlineMathImul(CallInfo& callInfo) MInstruction* second = MTruncateToInt32::New(alloc(), callInfo.getArg(1)); current->add(second); - MMul* ins = MMul::New(alloc(), first, second, MIRType_Int32, MMul::Integer); + MMul* ins = MMul::New(alloc(), first, second, MIRType::Int32, MMul::Integer); current->add(ins); current->push(ins); return InliningStatus_Inlined; @@ -1291,12 +1293,12 @@ IonBuilder::inlineMathMinMax(CallInfo& callInfo, bool max) MDefinition* arg = callInfo.getArg(i); switch (arg->type()) { - case MIRType_Int32: + case MIRType::Int32: if (!int32_cases.append(arg)) return InliningStatus_Error; break; - case MIRType_Double: - case MIRType_Float32: + case MIRType::Double: + case MIRType::Float32: // Don't force a double MMinMax for arguments that would be a NOP // when doing an integer MMinMax. if (arg->isConstant()) { @@ -1310,7 +1312,7 @@ IonBuilder::inlineMathMinMax(CallInfo& callInfo, bool max) } // Force double MMinMax if argument is a "effectfull" double. - returnType = MIRType_Double; + returnType = MIRType::Double; break; default: return InliningStatus_NotInlined; @@ -1318,11 +1320,11 @@ IonBuilder::inlineMathMinMax(CallInfo& callInfo, bool max) } if (int32_cases.length() == 0) - returnType = MIRType_Double; + returnType = MIRType::Double; callInfo.setImplicitlyUsedUnchecked(); - MDefinitionVector& cases = (returnType == MIRType_Int32) ? int32_cases : callInfo.argv(); + MDefinitionVector& cases = (returnType == MIRType::Int32) ? int32_cases : callInfo.argv(); if (cases.length() == 1) { MLimitedTruncate* limit = MLimitedTruncate::New(alloc(), cases[0], MDefinition::NoTruncate); @@ -1354,7 +1356,7 @@ IonBuilder::inlineStringObject(CallInfo& callInfo) } // ConvertToString doesn't support objects. - if (callInfo.getArg(0)->mightBeType(MIRType_Object)) + if (callInfo.getArg(0)->mightBeType(MIRType::Object)) return InliningStatus_NotInlined; JSObject* templateObj = inspector->getTemplateObjectForNative(pc, StringConstructor); @@ -1384,11 +1386,11 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo) return InliningStatus_NotInlined; MConstant* strval = callInfo.getArg(0)->toConstant(); - if (strval->type() != MIRType_String) + if (strval->type() != MIRType::String) return InliningStatus_NotInlined; MConstant* sepval = callInfo.getArg(1)->toConstant(); - if (strval->type() != MIRType_String) + if (strval->type() != MIRType::String) return InliningStatus_NotInlined; // Check if exist a template object in stub. @@ -1488,10 +1490,10 @@ IonBuilder::inlineStringSplitString(CallInfo& callInfo) MDefinition* strArg = callInfo.getArg(0); MDefinition* sepArg = callInfo.getArg(1); - if (strArg->type() != MIRType_String) + if (strArg->type() != MIRType::String) return InliningStatus_NotInlined; - if (sepArg->type() != MIRType_String) + if (sepArg->type() != MIRType::String) return InliningStatus_NotInlined; IonBuilder::InliningStatus resultConstStringSplit = inlineConstantStringSplitString(callInfo); @@ -1539,9 +1541,9 @@ IonBuilder::inlineObjectHasPrototype(CallInfo& callInfo) MDefinition* objArg = callInfo.getArg(0); MDefinition* protoArg = callInfo.getArg(1); - if (objArg->type() != MIRType_Object) + if (objArg->type() != MIRType::Object) return InliningStatus_NotInlined; - if (protoArg->type() != MIRType_Object) + if (protoArg->type() != MIRType::Object) return InliningStatus_NotInlined; // Inline only when both obj and proto are singleton objects and @@ -1588,12 +1590,12 @@ IonBuilder::inlineStrCharCodeAt(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Int32) + if (getInlineReturnType() != MIRType::Int32) return InliningStatus_NotInlined; - if (callInfo.thisArg()->type() != MIRType_String && callInfo.thisArg()->type() != MIRType_Value) + if (callInfo.thisArg()->type() != MIRType::String && callInfo.thisArg()->type() != MIRType::Value) return InliningStatus_NotInlined; MIRType argType = callInfo.getArg(0)->type(); - if (argType != MIRType_Int32 && argType != MIRType_Double) + if (argType != MIRType::Int32 && argType != MIRType::Double) return InliningStatus_NotInlined; // Check for STR.charCodeAt(IDX) where STR is a constant string and IDX is a @@ -1629,7 +1631,7 @@ IonBuilder::inlineConstantCharCodeAt(CallInfo& callInfo) MConstant* strval = callInfo.thisArg()->maybeConstantValue(); MConstant* idxval = callInfo.getArg(0)->maybeConstantValue(); - if (strval->type() != MIRType_String || idxval->type() != MIRType_Int32) + if (strval->type() != MIRType::String || idxval->type() != MIRType::Int32) return InliningStatus_NotInlined; JSString* str = strval->toString(); @@ -1662,9 +1664,9 @@ IonBuilder::inlineStrFromCharCode(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_String) + if (getInlineReturnType() != MIRType::String) return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType_Int32) + if (callInfo.getArg(0)->type() != MIRType::Int32) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -1686,12 +1688,12 @@ IonBuilder::inlineStrCharAt(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_String) + if (getInlineReturnType() != MIRType::String) return InliningStatus_NotInlined; - if (callInfo.thisArg()->type() != MIRType_String) + if (callInfo.thisArg()->type() != MIRType::String) return InliningStatus_NotInlined; MIRType argType = callInfo.getArg(0)->type(); - if (argType != MIRType_Int32 && argType != MIRType_Double) + if (argType != MIRType::Int32 && argType != MIRType::Double) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -1729,7 +1731,7 @@ IonBuilder::inlineRegExpMatcher(CallInfo& callInfo) MDefinition* strArg = callInfo.getArg(1); MDefinition* lastIndexArg = callInfo.getArg(2); - if (rxArg->type() != MIRType_Object) + if (rxArg->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* rxTypes = rxArg->resultTypeSet(); @@ -1737,10 +1739,10 @@ IonBuilder::inlineRegExpMatcher(CallInfo& callInfo) if (clasp != &RegExpObject::class_) return InliningStatus_NotInlined; - if (strArg->mightBeType(MIRType_Object)) + if (strArg->mightBeType(MIRType::Object)) return InliningStatus_NotInlined; - if (lastIndexArg->type() != MIRType_Int32) + if (lastIndexArg->type() != MIRType::Int32) return InliningStatus_NotInlined; JSContext* cx = GetJitContext()->cx; @@ -1779,7 +1781,7 @@ IonBuilder::inlineRegExpSearcher(CallInfo& callInfo) MDefinition* strArg = callInfo.getArg(1); MDefinition* lastIndexArg = callInfo.getArg(2); - if (rxArg->type() != MIRType_Object) + if (rxArg->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* regexpTypes = rxArg->resultTypeSet(); @@ -1787,10 +1789,10 @@ IonBuilder::inlineRegExpSearcher(CallInfo& callInfo) if (clasp != &RegExpObject::class_) return InliningStatus_NotInlined; - if (strArg->mightBeType(MIRType_Object)) + if (strArg->mightBeType(MIRType::Object)) return InliningStatus_NotInlined; - if (lastIndexArg->type() != MIRType_Int32) + if (lastIndexArg->type() != MIRType::Int32) return InliningStatus_NotInlined; JSContext* cx = GetJitContext()->cx; @@ -1829,7 +1831,7 @@ IonBuilder::inlineRegExpTester(CallInfo& callInfo) MDefinition* strArg = callInfo.getArg(1); MDefinition* lastIndexArg = callInfo.getArg(2); - if (rxArg->type() != MIRType_Object) + if (rxArg->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* rxTypes = rxArg->resultTypeSet(); @@ -1837,10 +1839,10 @@ IonBuilder::inlineRegExpTester(CallInfo& callInfo) if (clasp != &RegExpObject::class_) return InliningStatus_NotInlined; - if (strArg->mightBeType(MIRType_Object)) + if (strArg->mightBeType(MIRType::Object)) return InliningStatus_NotInlined; - if (lastIndexArg->type() != MIRType_Int32) + if (lastIndexArg->type() != MIRType::Int32) return InliningStatus_NotInlined; JSContext* cx = GetJitContext()->cx; @@ -1869,16 +1871,16 @@ IonBuilder::inlineIsRegExpObject(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; MDefinition* arg = callInfo.getArg(0); bool isRegExpObject; - if (!arg->mightBeType(MIRType_Object)) { + if (!arg->mightBeType(MIRType::Object)) { isRegExpObject = false; } else { - if (arg->type() != MIRType_Object) + if (arg->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* types = arg->resultTypeSet(); @@ -1905,10 +1907,10 @@ IonBuilder::inlineRegExpPrototypeOptimizable(CallInfo& callInfo) MDefinition* protoArg = callInfo.getArg(0); - if (protoArg->type() != MIRType_Object) + if (protoArg->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -1931,13 +1933,13 @@ IonBuilder::inlineRegExpInstanceOptimizable(CallInfo& callInfo) MDefinition* rxArg = callInfo.getArg(0); MDefinition* protoArg = callInfo.getArg(1); - if (rxArg->type() != MIRType_Object) + if (rxArg->type() != MIRType::Object) return InliningStatus_NotInlined; - if (protoArg->type() != MIRType_Object) + if (protoArg->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -1949,6 +1951,31 @@ IonBuilder::inlineRegExpInstanceOptimizable(CallInfo& callInfo) return InliningStatus_Inlined; } +IonBuilder::InliningStatus +IonBuilder::inlineGetFirstDollarIndex(CallInfo& callInfo) +{ + if (callInfo.argc() != 1 || callInfo.constructing()) { + trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); + return InliningStatus_NotInlined; + } + + MDefinition* strArg = callInfo.getArg(0); + + if (strArg->type() != MIRType::String) + return InliningStatus_NotInlined; + + if (getInlineReturnType() != MIRType::Int32) + return InliningStatus_NotInlined; + + callInfo.setImplicitlyUsedUnchecked(); + + MInstruction* ins = MGetFirstDollarIndex::New(alloc(), strArg); + current->add(ins); + current->push(ins); + + return InliningStatus_Inlined; +} + IonBuilder::InliningStatus IonBuilder::inlineStringReplaceString(CallInfo& callInfo) { @@ -1957,20 +1984,20 @@ IonBuilder::inlineStringReplaceString(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_String) + if (getInlineReturnType() != MIRType::String) return InliningStatus_NotInlined; MDefinition* strArg = callInfo.getArg(0); MDefinition* patArg = callInfo.getArg(1); MDefinition* replArg = callInfo.getArg(2); - if (strArg->type() != MIRType_String) + if (strArg->type() != MIRType::String) return InliningStatus_NotInlined; - if (patArg->type() != MIRType_String) + if (patArg->type() != MIRType::String) return InliningStatus_NotInlined; - if (replArg->type() != MIRType_String) + if (replArg->type() != MIRType::String) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -1990,19 +2017,19 @@ IonBuilder::inlineSubstringKernel(CallInfo& callInfo) MOZ_ASSERT(!callInfo.constructing()); // Return: String. - if (getInlineReturnType() != MIRType_String) + if (getInlineReturnType() != MIRType::String) return InliningStatus_NotInlined; // Arg 0: String. - if (callInfo.getArg(0)->type() != MIRType_String) + if (callInfo.getArg(0)->type() != MIRType::String) return InliningStatus_NotInlined; // Arg 1: Int. - if (callInfo.getArg(1)->type() != MIRType_Int32) + if (callInfo.getArg(1)->type() != MIRType::Int32) return InliningStatus_NotInlined; // Arg 2: Int. - if (callInfo.getArg(2)->type() != MIRType_Int32) + if (callInfo.getArg(2)->type() != MIRType::Int32) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -2038,9 +2065,9 @@ IonBuilder::inlineObjectCreate(CallInfo& callInfo) if (!types || types->maybeSingleton() != proto) return InliningStatus_NotInlined; - MOZ_ASSERT(types->getKnownMIRType() == MIRType_Object); + MOZ_ASSERT(types->getKnownMIRType() == MIRType::Object); } else { - if (arg->type() != MIRType_Null) + if (arg->type() != MIRType::Null) return InliningStatus_NotInlined; } @@ -2095,9 +2122,9 @@ IonBuilder::inlineHasClass(CallInfo& callInfo, return InliningStatus_NotInlined; } - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet(); @@ -2145,7 +2172,7 @@ IonBuilder::inlineGetNextMapEntryForIterator(CallInfo& callInfo) MDefinition* iterArg = callInfo.getArg(0); MDefinition* resultArg = callInfo.getArg(1); - if (iterArg->type() != MIRType_Object) + if (iterArg->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* iterTypes = iterArg->resultTypeSet(); @@ -2153,7 +2180,7 @@ IonBuilder::inlineGetNextMapEntryForIterator(CallInfo& callInfo) if (iterClasp != &MapIteratorObject::class_) return InliningStatus_NotInlined; - if (resultArg->type() != MIRType_Object) + if (resultArg->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* resultTypes = resultArg->resultTypeSet(); @@ -2177,7 +2204,7 @@ IonBuilder::inlineGetNextMapEntryForIterator(CallInfo& callInfo) static bool IsArrayBufferObject(CompilerConstraintList* constraints, MDefinition* def) { - MOZ_ASSERT(def->type() == MIRType_Object); + MOZ_ASSERT(def->type() == MIRType::Object); TemporaryTypeSet* types = def->resultTypeSet(); if (!types) @@ -2193,9 +2220,9 @@ IonBuilder::inlineArrayBufferByteLength(CallInfo& callInfo) MOZ_ASSERT(callInfo.argc() == 1); MDefinition* objArg = callInfo.getArg(0); - if (objArg->type() != MIRType_Object) + if (objArg->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Int32) + if (getInlineReturnType() != MIRType::Int32) return InliningStatus_NotInlined; MInstruction* ins = addArrayBufferByteLength(objArg); @@ -2212,9 +2239,9 @@ IonBuilder::inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo) MOZ_ASSERT(callInfo.argc() == 1); MDefinition* objArg = callInfo.getArg(0); - if (objArg->type() != MIRType_Object) + if (objArg->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Int32) + if (getInlineReturnType() != MIRType::Int32) return InliningStatus_NotInlined; if (!IsArrayBufferObject(constraints(), objArg)) @@ -2233,9 +2260,9 @@ IonBuilder::inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappi MOZ_ASSERT(!callInfo.constructing()); MOZ_ASSERT(callInfo.argc() == 1); - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; // The test is elaborate: in-line only if there is exact @@ -2298,7 +2325,7 @@ IonBuilder::inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo) static bool IsTypedArrayObject(CompilerConstraintList* constraints, MDefinition* def) { - MOZ_ASSERT(def->type() == MIRType_Object); + MOZ_ASSERT(def->type() == MIRType::Object); TemporaryTypeSet* types = def->resultTypeSet(); if (!types) @@ -2313,9 +2340,9 @@ IonBuilder::inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo) { MOZ_ASSERT(!callInfo.constructing()); MOZ_ASSERT(callInfo.argc() == 1); - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Int32) + if (getInlineReturnType() != MIRType::Int32) return InliningStatus_NotInlined; if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) @@ -2343,17 +2370,17 @@ IonBuilder::inlineSetDisjointTypedElements(CallInfo& callInfo) // Initial argument requirements. MDefinition* target = callInfo.getArg(0); - if (target->type() != MIRType_Object) + if (target->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Undefined) + if (getInlineReturnType() != MIRType::Undefined) return InliningStatus_NotInlined; MDefinition* targetOffset = callInfo.getArg(1); - MOZ_ASSERT(targetOffset->type() == MIRType_Int32); + MOZ_ASSERT(targetOffset->type() == MIRType::Int32); MDefinition* sourceTypedArray = callInfo.getArg(2); - if (sourceTypedArray->type() != MIRType_Object) + if (sourceTypedArray->type() != MIRType::Object) return InliningStatus_NotInlined; // Only attempt to optimize if |target| and |sourceTypedArray| are both @@ -2385,9 +2412,9 @@ IonBuilder::inlineObjectIsTypeDescr(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; // The test is elaborate: in-line only if there is exact @@ -2428,7 +2455,7 @@ IonBuilder::inlineSetTypedObjectOffset(CallInfo& callInfo) MDefinition* offset = callInfo.getArg(1); // Return type should be undefined or something wacky is going on. - if (getInlineReturnType() != MIRType_Undefined) + if (getInlineReturnType() != MIRType::Undefined) return InliningStatus_NotInlined; // Check typedObj is a, well, typed object. Go ahead and use TI @@ -2438,7 +2465,7 @@ IonBuilder::inlineSetTypedObjectOffset(CallInfo& callInfo) // fall through to the SetTypedObjectOffset intrinsic in such // cases. TemporaryTypeSet* types = typedObj->resultTypeSet(); - if (typedObj->type() != MIRType_Object || !types) + if (typedObj->type() != MIRType::Object || !types) return InliningStatus_NotInlined; switch (types->forAllClasses(constraints(), IsTypedObjectClass)) { case TemporaryTypeSet::ForAllResult::ALL_FALSE: @@ -2450,7 +2477,7 @@ IonBuilder::inlineSetTypedObjectOffset(CallInfo& callInfo) } // Check type of offset argument is an integer. - if (offset->type() != MIRType_Int32) + if (offset->type() != MIRType::Int32) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -2467,11 +2494,11 @@ IonBuilder::inlineUnsafeSetReservedSlot(CallInfo& callInfo) trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Undefined) + if (getInlineReturnType() != MIRType::Undefined) return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return InliningStatus_NotInlined; - if (callInfo.getArg(1)->type() != MIRType_Int32) + if (callInfo.getArg(1)->type() != MIRType::Int32) return InliningStatus_NotInlined; // Don't inline if we don't have a constant slot. @@ -2500,9 +2527,9 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo& callInfo, MIRType knownValueTy trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); return InliningStatus_NotInlined; } - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return InliningStatus_NotInlined; - if (callInfo.getArg(1)->type() != MIRType_Int32) + if (callInfo.getArg(1)->type() != MIRType::Int32) return InliningStatus_NotInlined; // Don't inline if we don't have a constant slot. @@ -2516,7 +2543,7 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo& callInfo, MIRType knownValueTy MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), callInfo.getArg(0), slot); current->add(load); current->push(load); - if (knownValueType != MIRType_Value) { + if (knownValueType != MIRType::Value) { // We know what type we have in this slot. Assert that this is in fact // what we've seen coming from this slot in the past, then tell the // MLoadFixedSlot about its result type. That will make us do an @@ -2543,19 +2570,19 @@ IonBuilder::inlineIsCallable(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; MDefinition* arg = callInfo.getArg(0); // Do not inline if the type of arg is neither primitive nor object. - if (arg->type() > MIRType_Object) + if (arg->type() > MIRType::Object) return InliningStatus_NotInlined; // Try inlining with constant true/false: only objects may be callable at // all, and if we know the class check if it is callable. bool isCallableKnown = false; bool isCallableConstant; - if (arg->type() != MIRType_Object) { + if (arg->type() != MIRType::Object) { // Primitive (including undefined and null). isCallableKnown = true; isCallableConstant = false; @@ -2590,9 +2617,9 @@ IonBuilder::inlineIsConstructor(CallInfo& callInfo) MOZ_ASSERT(!callInfo.constructing()); MOZ_ASSERT(callInfo.argc() == 1); - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -2611,11 +2638,11 @@ IonBuilder::inlineIsObject(CallInfo& callInfo) trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); - if (callInfo.getArg(0)->type() == MIRType_Object) { + if (callInfo.getArg(0)->type() == MIRType::Object) { pushConstant(BooleanValue(true)); } else { MIsObject* isObject = MIsObject::New(alloc(), callInfo.getArg(0)); @@ -2634,9 +2661,9 @@ IonBuilder::inlineToObject(CallInfo& callInfo) } // If we know the input type is an object, nop ToObject. - if (getInlineReturnType() != MIRType_Object) + if (getInlineReturnType() != MIRType::Object) return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -2654,10 +2681,10 @@ IonBuilder::inlineIsWrappedArrayConstructor(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; MDefinition* arg = callInfo.getArg(0); - if (arg->type() != MIRType_Object) + if (arg->type() != MIRType::Object) return InliningStatus_NotInlined; TemporaryTypeSet* types = arg->resultTypeSet(); @@ -2688,20 +2715,20 @@ IonBuilder::inlineToInteger(CallInfo& callInfo) MDefinition* input = callInfo.getArg(0); // Only optimize cases where input contains only number, null or boolean - if (input->mightBeType(MIRType_Object) || - input->mightBeType(MIRType_String) || - input->mightBeType(MIRType_Symbol) || - input->mightBeType(MIRType_Undefined) || + if (input->mightBeType(MIRType::Object) || + input->mightBeType(MIRType::String) || + input->mightBeType(MIRType::Symbol) || + input->mightBeType(MIRType::Undefined) || input->mightBeMagicType()) { return InliningStatus_NotInlined; } - MOZ_ASSERT(input->type() == MIRType_Value || input->type() == MIRType_Null || - input->type() == MIRType_Boolean || IsNumberType(input->type())); + MOZ_ASSERT(input->type() == MIRType::Value || input->type() == MIRType::Null || + input->type() == MIRType::Boolean || IsNumberType(input->type())); // Only optimize cases where output is int32 - if (getInlineReturnType() != MIRType_Int32) + if (getInlineReturnType() != MIRType::Int32) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -2718,7 +2745,7 @@ IonBuilder::inlineToString(CallInfo& callInfo) if (callInfo.argc() != 1 || callInfo.constructing()) return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType_String) + if (getInlineReturnType() != MIRType::String) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -2749,7 +2776,7 @@ IonBuilder::inlineAssertFloat32(CallInfo& callInfo) MDefinition* secondArg = callInfo.getArg(1); - MOZ_ASSERT(secondArg->type() == MIRType_Boolean); + MOZ_ASSERT(secondArg->type() == MIRType::Boolean); MOZ_ASSERT(secondArg->isConstant()); bool mustBeFloat32 = secondArg->toConstant()->toBoolean(); @@ -2779,7 +2806,7 @@ IonBuilder::inlineAssertRecoveredOnBailout(CallInfo& callInfo) MDefinition* secondArg = callInfo.getArg(1); - MOZ_ASSERT(secondArg->type() == MIRType_Boolean); + MOZ_ASSERT(secondArg->type() == MIRType::Boolean); MOZ_ASSERT(secondArg->isConstant()); bool mustBeRecovered = secondArg->toConstant()->toBoolean(); @@ -2814,11 +2841,11 @@ IonBuilder::inlineAtomicsCompareExchange(CallInfo& callInfo) // These guards are desirable here and in subsequent atomics to // avoid bad bailouts with MTruncateToInt32, see https://bugzilla.mozilla.org/show_bug.cgi?id=1141986#c20. MDefinition* oldval = callInfo.getArg(2); - if (oldval->mightBeType(MIRType_Object) || oldval->mightBeType(MIRType_Symbol)) + if (oldval->mightBeType(MIRType::Object) || oldval->mightBeType(MIRType::Symbol)) return InliningStatus_NotInlined; MDefinition* newval = callInfo.getArg(3); - if (newval->mightBeType(MIRType_Object) || newval->mightBeType(MIRType_Symbol)) + if (newval->mightBeType(MIRType::Object) || newval->mightBeType(MIRType::Symbol)) return InliningStatus_NotInlined; Scalar::Type arrayType; @@ -2856,7 +2883,7 @@ IonBuilder::inlineAtomicsExchange(CallInfo& callInfo) } MDefinition* value = callInfo.getArg(2); - if (value->mightBeType(MIRType_Object) || value->mightBeType(MIRType_Symbol)) + if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol)) return InliningStatus_NotInlined; Scalar::Type arrayType; @@ -2930,7 +2957,7 @@ IonBuilder::inlineAtomicsStore(CallInfo& callInfo) } MDefinition* value = callInfo.getArg(2); - if (value->mightBeType(MIRType_Object) || value->mightBeType(MIRType_Symbol)) + if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol)) return InliningStatus_NotInlined; Scalar::Type arrayType; @@ -2948,7 +2975,7 @@ IonBuilder::inlineAtomicsStore(CallInfo& callInfo) addSharedTypedArrayGuard(callInfo.getArg(0)); MDefinition* toWrite = value; - if (value->type() != MIRType_Int32) { + if (value->type() != MIRType::Int32) { toWrite = MTruncateToInt32::New(alloc(), value); current->add(toWrite->toInstruction()); } @@ -2973,7 +3000,7 @@ IonBuilder::inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target) } MDefinition* value = callInfo.getArg(2); - if (value->mightBeType(MIRType_Object) || value->mightBeType(MIRType_Symbol)) + if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol)) return InliningStatus_NotInlined; Scalar::Type arrayType; @@ -3048,10 +3075,10 @@ IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayTyp if (!JitSupportsAtomics()) return false; - if (callInfo.getArg(0)->type() != MIRType_Object) + if (callInfo.getArg(0)->type() != MIRType::Object) return false; - if (callInfo.getArg(1)->type() != MIRType_Int32) + if (callInfo.getArg(1)->type() != MIRType::Int32) return false; // Ensure that the first argument is a TypedArray that maps shared @@ -3074,12 +3101,12 @@ IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayTyp case Scalar::Int16: case Scalar::Uint16: case Scalar::Int32: - return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType_Int32; + return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Int32; case Scalar::Uint32: // Bug 1077305: it would be attractive to allow inlining even // if the inline return type is Int32, which it will frequently // be. - return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType_Double; + return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Double; default: // Excludes floating types and Uint8Clamped. return false; @@ -3105,7 +3132,7 @@ IonBuilder::inlineIsConstructing(CallInfo& callInfo) MOZ_ASSERT(script()->functionNonDelazifying(), "isConstructing() should only be called in function scripts"); - if (getInlineReturnType() != MIRType_Boolean) + if (getInlineReturnType() != MIRType::Boolean) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -3328,7 +3355,7 @@ IonBuilder::convertToBooleanSimdLane(MDefinition* scalar) { MSub* result; - if (scalar->type() == MIRType_Boolean) { + if (scalar->type() == MIRType::Boolean) { // The input scalar is already a boolean with the int32 values 0 / 1. // Compute result = 0 - scalar. result = MSub::New(alloc(), constant(Int32Value(0)), scalar); @@ -3377,14 +3404,14 @@ IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr) MConstant* defVal = nullptr; MIRType laneType = SimdTypeToLaneType(simdType); if (callInfo.argc() < SimdTypeToLength(simdType)) { - if (laneType == MIRType_Int32) { + if (laneType == MIRType::Int32) { defVal = constant(Int32Value(0)); - } else if (laneType == MIRType_Boolean) { + } else if (laneType == MIRType::Boolean) { defVal = constant(BooleanValue(false)); - } else if (laneType == MIRType_Double) { + } else if (laneType == MIRType::Double) { defVal = constant(DoubleNaNValue()); } else { - MOZ_ASSERT(laneType == MIRType_Float32); + MOZ_ASSERT(laneType == MIRType::Float32); defVal = MConstant::NewFloat32(alloc(), JS::GenericNaN()); current->add(defVal); } @@ -3395,7 +3422,7 @@ IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr) lane[i] = callInfo.getArgWithDefault(i, defVal); // Convert boolean lanes into Int32 0 / -1. - if (laneType == MIRType_Boolean) { + if (laneType == MIRType::Boolean) { for (unsigned i = 0; i < 4; i++) lane[i] = convertToBooleanSimdLane(lane[i]); } @@ -3568,7 +3595,7 @@ IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdType type) MDefinition* arg = callInfo.getArg(0); // Convert to 0 / -1 before splatting a boolean lane. - if (SimdTypeToLaneType(mirType) == MIRType_Boolean) + if (SimdTypeToLaneType(mirType) == MIRType::Boolean) arg = convertToBooleanSimdLane(arg); MSimdSplatX4* ins = MSimdSplatX4::New(alloc(), arg, mirType); @@ -3587,7 +3614,7 @@ IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdType // Lane index. MDefinition* arg = callInfo.getArg(1); - if (!arg->isConstant() || arg->type() != MIRType_Int32) + if (!arg->isConstant() || arg->type() != MIRType::Int32) return InliningStatus_NotInlined; int32_t lane = arg->toConstant()->toInt32(); if (lane < 0 || lane >= 4) @@ -3599,9 +3626,9 @@ IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdType MIRType laneType = SimdTypeToLaneType(vecType); SimdSign sign = GetSimdSign(type); - // An Uint32 lane can't be represented in MIRType_Int32. Get it as a double. + // An Uint32 lane can't be represented in MIRType::Int32. Get it as a double. if (type == SimdType::Uint32x4) - laneType = MIRType_Double; + laneType = MIRType::Double; MSimdExtractElement* ins = MSimdExtractElement::New(alloc(), orig, laneType, SimdLane(lane), sign); @@ -3620,7 +3647,7 @@ IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdType // Lane index. MDefinition* arg = callInfo.getArg(1); - if (!arg->isConstant() || arg->type() != MIRType_Int32) + if (!arg->isConstant() || arg->type() != MIRType::Int32) return InliningStatus_NotInlined; int32_t lane = arg->toConstant()->toInt32(); @@ -3633,7 +3660,7 @@ IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdType // Convert to 0 / -1 before inserting a boolean lane. MDefinition* value = callInfo.getArg(2); - if (SimdTypeToLaneType(vecType) == MIRType_Boolean) + if (SimdTypeToLaneType(vecType) == MIRType::Boolean) value = convertToBooleanSimdLane(value); MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), orig, value, SimdLane(lane)); @@ -3725,9 +3752,9 @@ IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative na MUnaryInstruction* ins; if (IsAllTrue) - ins = MSimdAllTrue::New(alloc(), arg, MIRType_Boolean); + ins = MSimdAllTrue::New(alloc(), arg, MIRType::Boolean); else - ins = MSimdAnyTrue::New(alloc(), arg, MIRType_Boolean); + ins = MSimdAnyTrue::New(alloc(), arg, MIRType::Boolean); current->add(ins); current->push(ins); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 0fdca174fd..f5be1cc1c6 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -141,7 +141,7 @@ EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* pt // setNumber eagerly transforms a number to int32. // Transform back to double, if the output type is double. - if (ins->type() == MIRType_Double && ret.isInt32()) + if (ins->type() == MIRType::Double && ret.isInt32()) ret.setDouble(ret.toNumber()); if (ins->type() != MIRTypeFromValue(ret)) { @@ -177,7 +177,7 @@ EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) Value ret; ret.setDouble(1.0 / (double) num); MConstant* foldedRhs; - if (ins->type() == MIRType_Float32) + if (ins->type() == MIRType::Float32) foldedRhs = MConstant::NewFloat32(alloc, ret.toDouble()); else foldedRhs = MConstant::New(alloc, ret); @@ -208,7 +208,7 @@ MDefinition::valueHash() const HashNumber out = op(); for (size_t i = 0, e = numOperands(); i < e; i++) out = addU32ToHash(out, getOperand(i)->id()); - if (MInstruction* dep = dependency()) + if (MDefinition* dep = dependency()) out = addU32ToHash(out, dep->id()); return out; } @@ -249,7 +249,7 @@ MDefinition::mightBeMagicType() const if (IsMagicType(type())) return true; - if (MIRType_Value != type()) + if (MIRType::Value != type()) return false; return !resultTypeSet() || resultTypeSet()->hasType(TypeSet::MagicArgType()); @@ -263,10 +263,10 @@ MInstruction::foldsToStoredValue(TempAllocator& alloc, MDefinition* loaded) if (loaded->type() != type()) { // If we expect to read a type which is more generic than the type seen // by the store, then we box the value used by the store. - if (type() != MIRType_Value) + if (type() != MIRType::Value) return this; - MOZ_ASSERT(loaded->type() < MIRType_Value); + MOZ_ASSERT(loaded->type() < MIRType::Value); MBox* box = MBox::New(alloc, loaded); loaded = box; } @@ -322,7 +322,7 @@ MInstruction::clearResumePoint() bool MDefinition::maybeEmulatesUndefined(CompilerConstraintList* constraints) { - if (!mightBeType(MIRType_Object)) + if (!mightBeType(MIRType::Object)) return false; TemporaryTypeSet* types = resultTypeSet(); @@ -335,7 +335,7 @@ MDefinition::maybeEmulatesUndefined(CompilerConstraintList* constraints) static bool MaybeCallable(CompilerConstraintList* constraints, MDefinition* op) { - if (!op->mightBeType(MIRType_Object)) + if (!op->mightBeType(MIRType::Object)) return false; TemporaryTypeSet* types = op->resultTypeSet(); @@ -345,6 +345,25 @@ MaybeCallable(CompilerConstraintList* constraints, MDefinition* op) return types->maybeCallable(constraints); } +/* static */ const char* +AliasSet::Name(size_t flag) +{ + switch(flag) { + case 0: return "ObjectFields"; + case 1: return "Element"; + case 2: return "UnboxedElement"; + case 3: return "DynamicSlot"; + case 4: return "FixedSlot"; + case 5: return "DOMProperty"; + case 6: return "FrameArgument"; + case 7: return "AsmJSGlobalVar"; + case 8: return "AsmJSHeap"; + case 9: return "TypedArrayLength"; + default: + MOZ_CRASH("Unknown flag"); + } +} + MTest* MTest::New(TempAllocator& alloc, MDefinition* ins, MBasicBlock* ifTrue, MBasicBlock* ifFalse) { @@ -386,12 +405,12 @@ MTest::foldsTo(TempAllocator& alloc) } switch (op->type()) { - case MIRType_Undefined: - case MIRType_Null: + case MIRType::Undefined: + case MIRType::Null: return MGoto::New(alloc, ifFalse()); - case MIRType_Symbol: + case MIRType::Symbol: return MGoto::New(alloc, ifTrue()); - case MIRType_Object: + case MIRType::Object: if (!operandMightEmulateUndefined()) return MGoto::New(alloc, ifTrue()); break; @@ -686,7 +705,7 @@ MConstant::NewInt64(TempAllocator& alloc, int64_t i) MConstant* MConstant::NewAsmJS(TempAllocator& alloc, const Value& v, MIRType type) { - if (type == MIRType_Float32) + if (type == MIRType::Float32) return NewFloat32(alloc, v.toNumber()); MConstant* res = New(alloc, v); MOZ_ASSERT(res->type() == type); @@ -759,38 +778,38 @@ MConstant::MConstant(const js::Value& vp, CompilerConstraintList* constraints) MOZ_ASSERT(payload_.asBits == 0); switch (type()) { - case MIRType_Undefined: - case MIRType_Null: + case MIRType::Undefined: + case MIRType::Null: break; - case MIRType_Boolean: + case MIRType::Boolean: payload_.b = vp.toBoolean(); break; - case MIRType_Int32: + case MIRType::Int32: payload_.i32 = vp.toInt32(); break; - case MIRType_Double: + case MIRType::Double: payload_.d = vp.toDouble(); break; - case MIRType_String: + case MIRType::String: MOZ_ASSERT(vp.toString()->isAtom()); payload_.str = vp.toString(); break; - case MIRType_Symbol: + case MIRType::Symbol: payload_.sym = vp.toSymbol(); break; - case MIRType_Object: + case MIRType::Object: payload_.obj = &vp.toObject(); // Create a singleton type set for the object. This isn't necessary for // other types as the result type encodes all needed information. MOZ_ASSERT_IF(IsInsideNursery(&vp.toObject()), IonCompilationCanUseNurseryPointers()); setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject())); break; - case MIRType_MagicOptimizedArguments: - case MIRType_MagicOptimizedOut: - case MIRType_MagicHole: - case MIRType_MagicIsConstructing: + case MIRType::MagicOptimizedArguments: + case MIRType::MagicOptimizedOut: + case MIRType::MagicHole: + case MIRType::MagicIsConstructing: break; - case MIRType_MagicUninitializedLexical: + case MIRType::MagicUninitializedLexical: // JS_UNINITIALIZED_LEXICAL does not escape to script and is not // observed in type sets. However, it may flow around freely during // Ion compilation. Give it an unknown typeset to poison any type sets @@ -810,21 +829,21 @@ MConstant::MConstant(const js::Value& vp, CompilerConstraintList* constraints) MConstant::MConstant(JSObject* obj) { MOZ_ASSERT_IF(IsInsideNursery(obj), IonCompilationCanUseNurseryPointers()); - setResultType(MIRType_Object); + setResultType(MIRType::Object); payload_.obj = obj; setMovable(); } MConstant::MConstant(float f) { - setResultType(MIRType_Float32); + setResultType(MIRType::Float32); payload_.f = f; setMovable(); } MConstant::MConstant(int64_t i) { - setResultType(MIRType_Int64); + setResultType(MIRType::Int64); payload_.i64 = i; setMovable(); } @@ -837,19 +856,19 @@ MConstant::assertInitializedPayload() const // initialized to zero. Assert this in debug builds. switch (type()) { - case MIRType_Int32: - case MIRType_Float32: + case MIRType::Int32: + case MIRType::Float32: MOZ_ASSERT((payload_.asBits >> 32) == 0); break; - case MIRType_Boolean: + case MIRType::Boolean: MOZ_ASSERT((payload_.asBits >> 1) == 0); break; - case MIRType_Double: - case MIRType_Int64: + case MIRType::Double: + case MIRType::Int64: break; - case MIRType_String: - case MIRType_Object: - case MIRType_Symbol: + case MIRType::String: + case MIRType::Object: + case MIRType::Symbol: MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits >> 32) == 0); break; default: @@ -893,31 +912,31 @@ MConstant::printOpcode(GenericPrinter& out) const PrintOpcodeName(out, op()); out.printf(" "); switch (type()) { - case MIRType_Undefined: + case MIRType::Undefined: out.printf("undefined"); break; - case MIRType_Null: + case MIRType::Null: out.printf("null"); break; - case MIRType_Boolean: + case MIRType::Boolean: out.printf(toBoolean() ? "true" : "false"); break; - case MIRType_Int32: + case MIRType::Int32: out.printf("0x%x", toInt32()); break; - case MIRType_Int64: + case MIRType::Int64: out.printf("0x%" PRIx64, toInt64()); break; - case MIRType_Double: + case MIRType::Double: out.printf("%.16g", toDouble()); break; - case MIRType_Float32: + case MIRType::Float32: { float val = toFloat32(); out.printf("%.16g", val); break; } - case MIRType_Object: + case MIRType::Object: if (toObject().is()) { JSFunction* fun = &toObject().as(); if (fun->displayAtom()) { @@ -936,25 +955,25 @@ MConstant::printOpcode(GenericPrinter& out) const } out.printf("object %p (%s)", (void*)&toObject(), toObject().getClass()->name); break; - case MIRType_Symbol: + case MIRType::Symbol: out.printf("symbol at %p", (void*)toSymbol()); break; - case MIRType_String: + case MIRType::String: out.printf("string %p", (void*)toString()); break; - case MIRType_MagicOptimizedArguments: + case MIRType::MagicOptimizedArguments: out.printf("magic lazyargs"); break; - case MIRType_MagicHole: + case MIRType::MagicHole: out.printf("magic hole"); break; - case MIRType_MagicIsConstructing: + case MIRType::MagicIsConstructing: out.printf("magic is-constructing"); break; - case MIRType_MagicOptimizedOut: + case MIRType::MagicOptimizedOut: out.printf("magic optimized-out"); break; - case MIRType_MagicUninitializedLexical: + case MIRType::MagicUninitializedLexical: out.printf("magic uninitialized-lexical"); break; default: @@ -968,11 +987,11 @@ MConstant::canProduceFloat32() const if (!isTypeRepresentableAsDouble()) return false; - if (type() == MIRType_Int32) + if (type() == MIRType::Int32) return IsFloat32Representable(static_cast(toInt32())); - if (type() == MIRType_Double) + if (type() == MIRType::Double) return IsFloat32Representable(toDouble()); - MOZ_ASSERT(type() == MIRType_Float32); + MOZ_ASSERT(type() == MIRType::Float32); return true; } @@ -984,33 +1003,33 @@ MConstant::toJSValue() const MOZ_ASSERT(!IsCompilingAsmJS()); switch (type()) { - case MIRType_Undefined: + case MIRType::Undefined: return UndefinedValue(); - case MIRType_Null: + case MIRType::Null: return NullValue(); - case MIRType_Boolean: + case MIRType::Boolean: return BooleanValue(toBoolean()); - case MIRType_Int32: + case MIRType::Int32: return Int32Value(toInt32()); - case MIRType_Double: + case MIRType::Double: return DoubleValue(toDouble()); - case MIRType_Float32: + case MIRType::Float32: return Float32Value(toFloat32()); - case MIRType_String: + case MIRType::String: return StringValue(toString()); - case MIRType_Symbol: + case MIRType::Symbol: return SymbolValue(toSymbol()); - case MIRType_Object: + case MIRType::Object: return ObjectValue(toObject()); - case MIRType_MagicOptimizedArguments: + case MIRType::MagicOptimizedArguments: return MagicValue(JS_OPTIMIZED_ARGUMENTS); - case MIRType_MagicOptimizedOut: + case MIRType::MagicOptimizedOut: return MagicValue(JS_OPTIMIZED_OUT); - case MIRType_MagicHole: + case MIRType::MagicHole: return MagicValue(JS_ELEMENTS_HOLE); - case MIRType_MagicIsConstructing: + case MIRType::MagicIsConstructing: return MagicValue(JS_IS_CONSTRUCTING); - case MIRType_MagicUninitializedLexical: + case MIRType::MagicUninitializedLexical: return MagicValue(JS_UNINITIALIZED_LEXICAL); default: MOZ_CRASH("Unexpected type"); @@ -1021,29 +1040,29 @@ bool MConstant::valueToBoolean(bool* res) const { switch (type()) { - case MIRType_Boolean: + case MIRType::Boolean: *res = toBoolean(); return true; - case MIRType_Int32: + case MIRType::Int32: *res = toInt32() != 0; return true; - case MIRType_Double: + case MIRType::Double: *res = !mozilla::IsNaN(toDouble()) && toDouble() != 0.0; return true; - case MIRType_Float32: + case MIRType::Float32: *res = !mozilla::IsNaN(toFloat32()) && toFloat32() != 0.0f; return true; - case MIRType_Null: - case MIRType_Undefined: + case MIRType::Null: + case MIRType::Undefined: *res = false; return true; - case MIRType_Symbol: + case MIRType::Symbol: *res = true; return true; - case MIRType_String: + case MIRType::String: *res = toString()->length() != 0; return true; - case MIRType_Object: + case MIRType::Object: *res = !EmulatesUndefined(&toObject()); return true; default: @@ -1055,7 +1074,9 @@ MConstant::valueToBoolean(bool* res) const MDefinition* MSimdValueX4::foldsTo(TempAllocator& alloc) { - DebugOnly laneType = SimdTypeToLaneArgumentType(type()); +#ifdef DEBUG + MIRType laneType = SimdTypeToLaneArgumentType(type()); +#endif bool allConstants = true; bool allSame = true; @@ -1074,21 +1095,21 @@ MSimdValueX4::foldsTo(TempAllocator& alloc) if (allConstants) { SimdConstant cst; switch (type()) { - case MIRType_Bool32x4: { + case MIRType::Bool32x4: { int32_t a[4]; for (size_t i = 0; i < 4; ++i) a[i] = getOperand(i)->toConstant()->valueToBooleanInfallible() ? -1 : 0; cst = SimdConstant::CreateX4(a); break; } - case MIRType_Int32x4: { + case MIRType::Int32x4: { int32_t a[4]; for (size_t i = 0; i < 4; ++i) a[i] = getOperand(i)->toConstant()->toInt32(); cst = SimdConstant::CreateX4(a); break; } - case MIRType_Float32x4: { + case MIRType::Float32x4: { float a[4]; for (size_t i = 0; i < 4; ++i) a[i] = getOperand(i)->toConstant()->numberToDouble(); @@ -1108,7 +1129,9 @@ MSimdValueX4::foldsTo(TempAllocator& alloc) MDefinition* MSimdSplatX4::foldsTo(TempAllocator& alloc) { - DebugOnly laneType = SimdTypeToLaneArgumentType(type()); +#ifdef DEBUG + MIRType laneType = SimdTypeToLaneArgumentType(type()); +#endif MDefinition* op = getOperand(0); if (!op->isConstant()) return this; @@ -1116,17 +1139,17 @@ MSimdSplatX4::foldsTo(TempAllocator& alloc) SimdConstant cst; switch (type()) { - case MIRType_Bool32x4: { + case MIRType::Bool32x4: { int32_t v = op->toConstant()->valueToBooleanInfallible() ? -1 : 0; cst = SimdConstant::SplatX4(v); break; } - case MIRType_Int32x4: { + case MIRType::Int32x4: { int32_t v = op->toConstant()->toInt32(); cst = SimdConstant::SplatX4(v); break; } - case MIRType_Float32x4: { + case MIRType::Float32x4: { float v = op->toConstant()->numberToDouble(); cst = SimdConstant::SplatX4(v); break; @@ -1173,7 +1196,7 @@ MSimdGeneralShuffle::foldsTo(TempAllocator& alloc) return this; for (size_t i = 0; i < numLanes(); i++) { - if (!lane(i)->isConstant() || lane(i)->type() != MIRType_Int32) + if (!lane(i)->isConstant() || lane(i)->type() != MIRType::Int32) return this; int32_t temp = lane(i)->toConstant()->toInt32(); if (temp < 0 || uint32_t(temp) >= numLanes() * numVectors()) @@ -1202,7 +1225,7 @@ MSimdConvert::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition // This architecture can't do Uint32x4 <-> Float32x4 conversions (Hi SSE!) MOZ_ASSERT(sign == SimdSign::Unsigned); - if (fromType == MIRType_Int32x4 && toType == MIRType_Float32x4) { + if (fromType == MIRType::Int32x4 && toType == MIRType::Float32x4) { // Converting Uint32x4 -> Float32x4. This algorithm is from LLVM. // // Split the input number into high and low parts: @@ -1232,34 +1255,34 @@ MSimdConvert::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition // Compute lo = obj & 0xffff (lane-wise). MInstruction* m16 = - MSimdConstant::New(alloc, SimdConstant::SplatX4(0xffff), MIRType_Int32x4); + MSimdConstant::New(alloc, SimdConstant::SplatX4(0xffff), MIRType::Int32x4); addTo->add(m16); MInstruction* lo = MSimdBinaryBitwise::New(alloc, obj, m16, MSimdBinaryBitwise::and_); addTo->add(lo); // Mix in the exponents. MInstruction* exphi = - MSimdConstant::New(alloc, SimdConstant::SplatX4(0x53000000), MIRType_Int32x4); + MSimdConstant::New(alloc, SimdConstant::SplatX4(0x53000000), MIRType::Int32x4); addTo->add(exphi); MInstruction* mhi = MSimdBinaryBitwise::New(alloc, hi, exphi, MSimdBinaryBitwise::or_); addTo->add(mhi); MInstruction* explo = - MSimdConstant::New(alloc, SimdConstant::SplatX4(0x4b000000), MIRType_Int32x4); + MSimdConstant::New(alloc, SimdConstant::SplatX4(0x4b000000), MIRType::Int32x4); addTo->add(explo); MInstruction* mlo = MSimdBinaryBitwise::New(alloc, lo, explo, MSimdBinaryBitwise::or_); addTo->add(mlo); // Bit-cast both to Float32x4. - MInstruction* fhi = MSimdReinterpretCast::New(alloc, mhi, MIRType_Float32x4); + MInstruction* fhi = MSimdReinterpretCast::New(alloc, mhi, MIRType::Float32x4); addTo->add(fhi); - MInstruction* flo = MSimdReinterpretCast::New(alloc, mlo, MIRType_Float32x4); + MInstruction* flo = MSimdReinterpretCast::New(alloc, mlo, MIRType::Float32x4); addTo->add(flo); // Subtract out the bias: 0x1.0p39f + 0x1.0p23f. // MSVC doesn't support the hexadecimal float syntax. const float BiasValue = 549755813888.f + 8388608.f; MInstruction* bias = - MSimdConstant::New(alloc, SimdConstant::SplatX4(BiasValue), MIRType_Float32x4); + MSimdConstant::New(alloc, SimdConstant::SplatX4(BiasValue), MIRType::Float32x4); addTo->add(bias); MInstruction* fhi_debiased = MSimdBinaryArith::New(alloc, fhi, bias, MSimdBinaryArith::Op_sub); @@ -1273,7 +1296,7 @@ MSimdConvert::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition return result; } - if (fromType == MIRType_Float32x4 && toType == MIRType_Int32x4) { + if (fromType == MIRType::Float32x4 && toType == MIRType::Int32x4) { // The Float32x4 -> Uint32x4 conversion can throw if the input is out of // range. This is handled by the LFloat32x4ToUint32x4 expansion. MInstruction* ins = New(alloc, obj, toType, sign); @@ -1294,7 +1317,7 @@ MSimdBinaryComp::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinit bool IsEquality = op == equal || op == notEqual; if (!SupportsUint32x4Compares && sign == SimdSign::Unsigned && !IsEquality) { - MOZ_ASSERT(opType == MIRType_Int32x4); + MOZ_ASSERT(opType == MIRType::Int32x4); // This is an order comparison of Uint32x4 vectors which are not supported on this target. // Simply offset |left| and |right| by INT_MIN, then do a signed comparison. MInstruction* bias = @@ -1314,7 +1337,7 @@ MSimdBinaryComp::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinit return result; } - if (!SupportsUint32x4Compares && sign == SimdSign::Unsigned && opType == MIRType_Int32x4) { + if (!SupportsUint32x4Compares && sign == SimdSign::Unsigned && opType == MIRType::Int32x4) { // The sign doesn't matter for equality tests. Flip it to make the // backend assertions happy. MOZ_ASSERT(IsEquality); @@ -1556,7 +1579,7 @@ MMathFunction::foldsTo(TempAllocator& alloc) return this; } - if (input->type() == MIRType_Float32) + if (input->type() == MIRType::Float32) return MConstant::NewFloat32(alloc, out); return MConstant::New(alloc, DoubleValue(out)); } @@ -1565,7 +1588,7 @@ MDefinition* MAtomicIsLockFree::foldsTo(TempAllocator& alloc) { MDefinition* input = getOperand(0); - if (!input->isConstant() || input->type() != MIRType_Int32) + if (!input->isConstant() || input->type() != MIRType::Int32) return this; int32_t i = input->toConstant()->toInt32(); @@ -1660,7 +1683,7 @@ MCallDOMNative::getAliasSet() const // per se, but it should prevent us being moved or DCE-ed, unless we // know the incoming things match that arg type and won't throw. // - if ((actualType == MIRType_Value || actualType == MIRType_Object) || + if ((actualType == MIRType::Value || actualType == MIRType::Object) || (*argType & JSJitInfo::Object)) { return AliasSet::Store(AliasSet::Any); @@ -1754,7 +1777,7 @@ MApplyArray::New(TempAllocator& alloc, JSFunction* target, MDefinition* fun, MDe MDefinition* MStringLength::foldsTo(TempAllocator& alloc) { - if (type() == MIRType_Int32 && string()->isConstant()) { + if (type() == MIRType::Int32 && string()->isConstant()) { JSAtom* atom = &string()->toConstant()->toString()->asAtom(); return MConstant::New(alloc, Int32Value(atom->length())); } @@ -1779,7 +1802,7 @@ EnsureFloatInputOrConvert(MUnaryInstruction* owner, TempAllocator& alloc) { MDefinition* input = owner->input(); if (!input->canProduceFloat32()) { - if (input->type() == MIRType_Float32) + if (input->type() == MIRType::Float32) ConvertDefinitionToDouble<0>(alloc, input, owner); return false; } @@ -1789,25 +1812,25 @@ EnsureFloatInputOrConvert(MUnaryInstruction* owner, TempAllocator& alloc) void MFloor::trySpecializeFloat32(TempAllocator& alloc) { - MOZ_ASSERT(type() == MIRType_Int32); + MOZ_ASSERT(type() == MIRType::Int32); if (EnsureFloatInputOrConvert(this, alloc)) - specialization_ = MIRType_Float32; + specialization_ = MIRType::Float32; } void MCeil::trySpecializeFloat32(TempAllocator& alloc) { - MOZ_ASSERT(type() == MIRType_Int32); + MOZ_ASSERT(type() == MIRType::Int32); if (EnsureFloatInputOrConvert(this, alloc)) - specialization_ = MIRType_Float32; + specialization_ = MIRType::Float32; } void MRound::trySpecializeFloat32(TempAllocator& alloc) { - MOZ_ASSERT(type() == MIRType_Int32); + MOZ_ASSERT(type() == MIRType::Int32); if (EnsureFloatInputOrConvert(this, alloc)) - specialization_ = MIRType_Float32; + specialization_ = MIRType::Float32; } MCompare* @@ -1826,7 +1849,7 @@ MCompare::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MCompare* comp = new(alloc) MCompare(left, right, op); comp->compareType_ = compareType; comp->operandMightEmulateUndefined_ = false; - comp->setResultType(MIRType_Int32); + comp->setResultType(MIRType::Int32); return comp; } @@ -1858,12 +1881,12 @@ MUnbox::printOpcode(GenericPrinter& out) const out.printf(" "); switch (type()) { - case MIRType_Int32: out.printf("to Int32"); break; - case MIRType_Double: out.printf("to Double"); break; - case MIRType_Boolean: out.printf("to Boolean"); break; - case MIRType_String: out.printf("to String"); break; - case MIRType_Symbol: out.printf("to Symbol"); break; - case MIRType_Object: out.printf("to Object"); break; + case MIRType::Int32: out.printf("to Int32"); break; + case MIRType::Double: out.printf("to Double"); break; + case MIRType::Boolean: out.printf("to Boolean"); break; + case MIRType::String: out.printf("to String"); break; + case MIRType::Symbol: out.printf("to Symbol"); break; + case MIRType::Object: out.printf("to Object"); break; default: break; } @@ -1881,9 +1904,9 @@ MUnbox::foldsTo(TempAllocator &alloc) if (!input()->isLoadFixedSlot()) return this; MLoadFixedSlot* load = input()->toLoadFixedSlot(); - if (load->type() != MIRType_Value) + if (load->type() != MIRType::Value) return this; - if (type() != MIRType_Boolean && !IsNumberType(type())) + if (type() != MIRType::Boolean && !IsNumberType(type())) return this; // Only optimize if the load comes immediately before the unbox, so it's // safe to copy the load's dependency field. @@ -2052,7 +2075,7 @@ MPhi::foldsTernary() // If testArg is an int32 type we can: // - fold testArg ? testArg : 0 to testArg // - fold testArg ? 0 : testArg to 0 - if (testArg->type() == MIRType_Int32 && c->numberToDouble() == 0) { + if (testArg->type() == MIRType::Int32 && c->numberToDouble() == 0) { // When folding to the constant we need to hoist it. if (trueDef == c && !c->block()->dominates(block())) c->block()->moveBefore(pred->lastIns(), c); @@ -2062,7 +2085,7 @@ MPhi::foldsTernary() // If testArg is a string type we can: // - fold testArg ? testArg : "" to testArg // - fold testArg ? "" : testArg to "" - if (testArg->type() == MIRType_String && + if (testArg->type() == MIRType::String && c->toString() == GetJitContext()->runtime->emptyString()) { // When folding to the constant we need to hoist it. @@ -2179,8 +2202,8 @@ MPhi::congruentTo(const MDefinition* ins) const static inline TemporaryTypeSet* MakeMIRTypeSet(MIRType type) { - MOZ_ASSERT(type != MIRType_Value); - TypeSet::Type ntype = type == MIRType_Object + MOZ_ASSERT(type != MIRType::Value); + TypeSet::Type ntype = type == MIRType::Object ? TypeSet::AnyObjectType() : TypeSet::PrimitiveType(ValueTypeFromMIRType(type)); LifoAlloc* alloc = GetJitContext()->temp->lifoAlloc(); @@ -2195,21 +2218,21 @@ jit::MergeTypes(MIRType* ptype, TemporaryTypeSet** ptypeSet, return true; if (newType != *ptype) { if (IsTypeRepresentableAsDouble(newType) && IsTypeRepresentableAsDouble(*ptype)) { - *ptype = MIRType_Double; - } else if (*ptype != MIRType_Value) { + *ptype = MIRType::Double; + } else if (*ptype != MIRType::Value) { if (!*ptypeSet) { *ptypeSet = MakeMIRTypeSet(*ptype); if (!*ptypeSet) return false; } - *ptype = MIRType_Value; + *ptype = MIRType::Value; } else if (*ptypeSet && (*ptypeSet)->empty()) { *ptype = newType; } } if (*ptypeSet) { LifoAlloc* alloc = GetJitContext()->temp->lifoAlloc(); - if (!newTypeSet && newType != MIRType_Value) { + if (!newTypeSet && newType != MIRType::Value) { newTypeSet = MakeMIRTypeSet(newType); if (!newTypeSet) return false; @@ -2236,21 +2259,21 @@ jit::TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes) return inputTypes && inputTypes->empty(); switch (input) { - case MIRType_Undefined: - case MIRType_Null: - case MIRType_Boolean: - case MIRType_Int32: - case MIRType_Double: - case MIRType_Float32: - case MIRType_String: - case MIRType_Symbol: - case MIRType_MagicOptimizedArguments: + case MIRType::Undefined: + case MIRType::Null: + case MIRType::Boolean: + case MIRType::Int32: + case MIRType::Double: + case MIRType::Float32: + case MIRType::String: + case MIRType::Symbol: + case MIRType::MagicOptimizedArguments: return types->hasType(TypeSet::PrimitiveType(ValueTypeFromMIRType(input))); - case MIRType_Object: + case MIRType::Object: return types->unknownObject() || (inputTypes && inputTypes->isSubset(types)); - case MIRType_Value: + case MIRType::Value: return types->unknown() || (inputTypes && inputTypes->isSubset(types)); default: @@ -2376,20 +2399,20 @@ MPhi::addBackedgeType(MIRType type, TemporaryTypeSet* typeSet) bool MPhi::typeIncludes(MDefinition* def) { - if (def->type() == MIRType_Int32 && this->type() == MIRType_Double) + if (def->type() == MIRType::Int32 && this->type() == MIRType::Double) return true; if (TemporaryTypeSet* types = def->resultTypeSet()) { if (this->resultTypeSet()) return types->isSubset(this->resultTypeSet()); - if (this->type() == MIRType_Value || types->empty()) + if (this->type() == MIRType::Value || types->empty()) return true; return this->type() == types->getKnownMIRType(); } - if (def->type() == MIRType_Value) { + if (def->type() == MIRType::Value) { // This phi must be able to be any value. - return this->type() == MIRType_Value + return this->type() == MIRType::Value && (!this->resultTypeSet() || this->resultTypeSet()->unknown()); } @@ -2434,7 +2457,7 @@ IsConstant(MDefinition* def, double v) MDefinition* MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) { - if (specialization_ != MIRType_Int32) + if (specialization_ != MIRType::Int32) return this; if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) @@ -2446,7 +2469,7 @@ MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() { - if (specialization_ != MIRType_Int32) + if (specialization_ != MIRType::Int32) return this; // Eliminate bitwise operations that are no-ops when used on integer @@ -2472,13 +2495,13 @@ MBinaryBitwiseInstruction::foldUnnecessaryBitop() if (maskMatchesRightRange) { MOZ_ASSERT(lhs->isConstant()); - MOZ_ASSERT(lhs->type() == MIRType_Int32); + MOZ_ASSERT(lhs->type() == MIRType::Int32); return foldIfAllBitsSet(0); } if (maskMatchesLeftRange) { MOZ_ASSERT(rhs->isConstant()); - MOZ_ASSERT(rhs->type() == MIRType_Int32); + MOZ_ASSERT(rhs->type() == MIRType::Int32); return foldIfAllBitsSet(1); } @@ -2488,19 +2511,19 @@ MBinaryBitwiseInstruction::foldUnnecessaryBitop() void MBinaryBitwiseInstruction::infer(BaselineInspector*, jsbytecode*) { - if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(0)->mightBeType(MIRType_Symbol) || - getOperand(1)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Symbol)) + if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(0)->mightBeType(MIRType::Symbol) || + getOperand(1)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Symbol)) { - specialization_ = MIRType_None; + specialization_ = MIRType::None; } else { - specializeAs(MIRType_Int32); + specializeAs(MIRType::Int32); } } void MBinaryBitwiseInstruction::specializeAs(MIRType type) { - MOZ_ASSERT(type == MIRType_Int32 || type == MIRType_Int64); + MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64); MOZ_ASSERT(this->type() == type); specialization_ = type; @@ -2512,32 +2535,32 @@ MBinaryBitwiseInstruction::specializeAs(MIRType type) void MShiftInstruction::infer(BaselineInspector*, jsbytecode*) { - if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object) || - getOperand(0)->mightBeType(MIRType_Symbol) || getOperand(1)->mightBeType(MIRType_Symbol)) - specialization_ = MIRType_None; + if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Object) || + getOperand(0)->mightBeType(MIRType::Symbol) || getOperand(1)->mightBeType(MIRType::Symbol)) + specialization_ = MIRType::None; else - specialization_ = MIRType_Int32; + specialization_ = MIRType::Int32; } void MUrsh::infer(BaselineInspector* inspector, jsbytecode* pc) { - if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object) || - getOperand(0)->mightBeType(MIRType_Symbol) || getOperand(1)->mightBeType(MIRType_Symbol)) + if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Object) || + getOperand(0)->mightBeType(MIRType::Symbol) || getOperand(1)->mightBeType(MIRType::Symbol)) { - specialization_ = MIRType_None; - setResultType(MIRType_Value); + specialization_ = MIRType::None; + setResultType(MIRType::Value); return; } if (inspector->hasSeenDoubleResult(pc)) { - specialization_ = MIRType_Double; - setResultType(MIRType_Double); + specialization_ = MIRType::Double; + setResultType(MIRType::Double); return; } - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); } static inline bool @@ -2547,7 +2570,7 @@ CanProduceNegativeZero(MDefinition* def) // and changing types. switch (def->op()) { case MDefinition::Op_Constant: - if (def->type() == MIRType_Double && def->toConstant()->toDouble() == -0.0) + if (def->type() == MIRType::Double && def->toConstant()->toDouble() == -0.0) return true; MOZ_FALLTHROUGH; case MDefinition::Op_BitAnd: @@ -2693,10 +2716,10 @@ void MBinaryArithInstruction::setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc) { - setSpecialization(MIRType_Double); + setSpecialization(MIRType::Double); // Try to specialize as int32. - if (getOperand(0)->type() == MIRType_Int32 && getOperand(1)->type() == MIRType_Int32) { + if (getOperand(0)->type() == MIRType::Int32 && getOperand(1)->type() == MIRType::Int32) { bool seenDouble = inspector->hasSeenDoubleResult(pc); // Use int32 specialization if the operation doesn't overflow on its @@ -2717,10 +2740,10 @@ MBinaryArithInstruction::constantDoubleResult(TempAllocator& alloc) MDefinition* MBinaryArithInstruction::foldsTo(TempAllocator& alloc) { - if (specialization_ == MIRType_None) + if (specialization_ == MIRType::None) return this; - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return this; MDefinition* lhs = getOperand(0); @@ -2735,7 +2758,7 @@ MBinaryArithInstruction::foldsTo(TempAllocator& alloc) } // 0 + -0 = 0. So we can't remove addition - if (isAdd() && specialization_ != MIRType_Int32) + if (isAdd() && specialization_ != MIRType::Int32) return this; if (IsConstant(rhs, getIdentity())) { @@ -2761,10 +2784,10 @@ void MFilterTypeSet::trySpecializeFloat32(TempAllocator& alloc) { MDefinition* in = input(); - if (in->type() != MIRType_Float32) + if (in->type() != MIRType::Float32) return; - setResultType(MIRType_Float32); + setResultType(MIRType::Float32); } bool @@ -2793,9 +2816,9 @@ void MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) { // Do not use Float32 if we can use int32. - if (specialization_ == MIRType_Int32) + if (specialization_ == MIRType::Int32) return; - if (specialization_ == MIRType_None) + if (specialization_ == MIRType::None) return; MDefinition* left = lhs(); @@ -2804,38 +2827,38 @@ MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) if (!left->canProduceFloat32() || !right->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) { - if (left->type() == MIRType_Float32) + if (left->type() == MIRType::Float32) ConvertDefinitionToDouble<0>(alloc, left, this); - if (right->type() == MIRType_Float32) + if (right->type() == MIRType::Float32) ConvertDefinitionToDouble<1>(alloc, right, this); return; } - specialization_ = MIRType_Float32; - setResultType(MIRType_Float32); + specialization_ = MIRType::Float32; + setResultType(MIRType::Float32); } void MMinMax::trySpecializeFloat32(TempAllocator& alloc) { - if (specialization_ == MIRType_Int32) + if (specialization_ == MIRType::Int32) return; MDefinition* left = lhs(); MDefinition* right = rhs(); - if (!(left->canProduceFloat32() || (left->isMinMax() && left->type() == MIRType_Float32)) || - !(right->canProduceFloat32() || (right->isMinMax() && right->type() == MIRType_Float32))) + if (!(left->canProduceFloat32() || (left->isMinMax() && left->type() == MIRType::Float32)) || + !(right->canProduceFloat32() || (right->isMinMax() && right->type() == MIRType::Float32))) { - if (left->type() == MIRType_Float32) + if (left->type() == MIRType::Float32) ConvertDefinitionToDouble<0>(alloc, left, this); - if (right->type() == MIRType_Float32) + if (right->type() == MIRType::Float32) ConvertDefinitionToDouble<1>(alloc, right, this); return; } - specialization_ = MIRType_Float32; - setResultType(MIRType_Float32); + specialization_ = MIRType::Float32; + setResultType(MIRType::Float32); } MDefinition* @@ -2863,14 +2886,14 @@ MMinMax::foldsTo(TempAllocator& alloc) // The folded MConstant should maintain the same MIRType with // the original MMinMax. - if (type() == MIRType_Int32) { + if (type() == MIRType::Int32) { int32_t cast; if (mozilla::NumberEqualsInt32(result, &cast)) return MConstant::New(alloc, Int32Value(cast)); - } else if (type() == MIRType_Float32) { + } else if (type() == MIRType::Float32) { return MConstant::NewFloat32(alloc, result); } else { - MOZ_ASSERT(type() == MIRType_Double); + MOZ_ASSERT(type() == MIRType::Double); return MConstant::New(alloc, DoubleValue(result)); } } @@ -2878,7 +2901,7 @@ MMinMax::foldsTo(TempAllocator& alloc) MDefinition* operand = lhs()->isConstant() ? rhs() : lhs(); MConstant* constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant(); - if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) { + if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType::Int32) { // min(int32, cte >= INT32_MAX) = int32 if (!isMax() && constant->isTypeRepresentableAsDouble() && @@ -2925,7 +2948,7 @@ MPow::foldsTo(TempAllocator& alloc) block()->insertBefore(this, half); MConstant* one = MConstant::New(alloc, DoubleValue(1.0)); block()->insertBefore(this, one); - return MDiv::New(alloc, one, half, MIRType_Double); + return MDiv::New(alloc, one, half, MIRType::Double); } // Math.pow(x, 1) == x. @@ -2963,26 +2986,26 @@ void MAbs::trySpecializeFloat32(TempAllocator& alloc) { // Do not use Float32 if we can use int32. - if (input()->type() == MIRType_Int32) + if (input()->type() == MIRType::Int32) return; if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) { - if (input()->type() == MIRType_Float32) + if (input()->type() == MIRType::Float32) ConvertDefinitionToDouble<0>(alloc, input(), this); return; } - setResultType(MIRType_Float32); - specialization_ = MIRType_Float32; + setResultType(MIRType::Float32); + specialization_ = MIRType::Float32; } MDefinition* MDiv::foldsTo(TempAllocator& alloc) { - if (specialization_ == MIRType_None) + if (specialization_ == MIRType::None) return this; - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return this; if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) @@ -2998,11 +3021,11 @@ void MDiv::analyzeEdgeCasesForward() { // This is only meaningful when doing integer division. - if (specialization_ != MIRType_Int32) + if (specialization_ != MIRType::Int32) return; - MOZ_ASSERT(lhs()->type() == MIRType_Int32); - MOZ_ASSERT(rhs()->type() == MIRType_Int32); + MOZ_ASSERT(lhs()->type() == MIRType::Int32); + MOZ_ASSERT(rhs()->type() == MIRType::Int32); // Try removing divide by zero check if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) @@ -3022,7 +3045,7 @@ MDiv::analyzeEdgeCasesForward() setCanBeNegativeZero(false); // If rhs is >= 0, likewise. - if (rhs()->isConstant() && rhs()->type() == MIRType_Int32) { + if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) { if (rhs()->toConstant()->toInt32() >= 0) setCanBeNegativeZero(false); } @@ -3044,10 +3067,10 @@ MDiv::fallible() const MDefinition* MMod::foldsTo(TempAllocator& alloc) { - if (specialization_ == MIRType_None) + if (specialization_ == MIRType::None) return this; - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return this; if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) @@ -3060,7 +3083,7 @@ void MMod::analyzeEdgeCasesForward() { // These optimizations make sense only for integer division - if (specialization_ != MIRType_Int32) + if (specialization_ != MIRType::Int32) return; if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) @@ -3084,13 +3107,13 @@ void MMathFunction::trySpecializeFloat32(TempAllocator& alloc) { if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) { - if (input()->type() == MIRType_Float32) + if (input()->type() == MIRType::Float32) ConvertDefinitionToDouble<0>(alloc, input(), this); return; } - setResultType(MIRType_Float32); - specialization_ = MIRType_Float32; + setResultType(MIRType::Float32); + specialization_ = MIRType::Float32; } MHypot* MHypot::New(TempAllocator& alloc, const MDefinitionVector & vector) @@ -3135,7 +3158,7 @@ MMul::foldsTo(TempAllocator& alloc) if (out != this) return out; - if (specialization() != MIRType_Int32) + if (specialization() != MIRType::Int32) return this; if (lhs() == rhs()) @@ -3149,17 +3172,17 @@ MMul::analyzeEdgeCasesForward() { // Try to remove the check for negative zero // This only makes sense when using the integer multiplication - if (specialization() != MIRType_Int32) + if (specialization() != MIRType::Int32) return; // If lhs is > 0, no need for negative zero check. - if (lhs()->isConstant() && lhs()->type() == MIRType_Int32) { + if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) { if (lhs()->toConstant()->toInt32() > 0) setCanBeNegativeZero(false); } // If rhs is > 0, likewise. - if (rhs()->isConstant() && rhs()->type() == MIRType_Int32) { + if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) { if (rhs()->toConstant()->toInt32() > 0) setCanBeNegativeZero(false); } @@ -3203,12 +3226,12 @@ MUrsh::fallible() const static inline bool SimpleArithOperand(MDefinition* op) { - return !op->mightBeType(MIRType_Object) - && !op->mightBeType(MIRType_String) - && !op->mightBeType(MIRType_Symbol) - && !op->mightBeType(MIRType_MagicOptimizedArguments) - && !op->mightBeType(MIRType_MagicHole) - && !op->mightBeType(MIRType_MagicIsConstructing); + return !op->mightBeType(MIRType::Object) + && !op->mightBeType(MIRType::String) + && !op->mightBeType(MIRType::Symbol) + && !op->mightBeType(MIRType::MagicOptimizedArguments) + && !op->mightBeType(MIRType::MagicHole) + && !op->mightBeType(MIRType::MagicIsConstructing); } static bool @@ -3216,7 +3239,7 @@ SafelyCoercesToDouble(MDefinition* op) { // Strings and symbols are unhandled -- visitToDouble() doesn't support them yet. // Null is unhandled -- ToDouble(null) == 0, but (0 == null) is false. - return SimpleArithOperand(op) && !op->mightBeType(MIRType_Null); + return SimpleArithOperand(op) && !op->mightBeType(MIRType::Null); } MIRType @@ -3224,31 +3247,31 @@ MCompare::inputType() { switch(compareType_) { case Compare_Undefined: - return MIRType_Undefined; + return MIRType::Undefined; case Compare_Null: - return MIRType_Null; + return MIRType::Null; case Compare_Boolean: - return MIRType_Boolean; + return MIRType::Boolean; case Compare_UInt32: case Compare_Int32: case Compare_Int32MaybeCoerceBoth: case Compare_Int32MaybeCoerceLHS: case Compare_Int32MaybeCoerceRHS: - return MIRType_Int32; + return MIRType::Int32; case Compare_Double: case Compare_DoubleMaybeCoerceLHS: case Compare_DoubleMaybeCoerceRHS: - return MIRType_Double; + return MIRType::Double; case Compare_Float32: - return MIRType_Float32; + return MIRType::Float32; case Compare_String: case Compare_StrictString: - return MIRType_String; + return MIRType::String; case Compare_Object: - return MIRType_Object; + return MIRType::Object; case Compare_Unknown: case Compare_Bitwise: - return MIRType_Value; + return MIRType::Value; default: MOZ_CRASH("No known conversion"); } @@ -3267,7 +3290,7 @@ MustBeUInt32(MDefinition* def, MDefinition** pwrapped) if (MConstant* defConst = def->maybeConstantValue()) { *pwrapped = defConst; - return defConst->type() == MIRType_Int32 && defConst->toInt32() >= 0; + return defConst->type() == MIRType::Int32 && defConst->toInt32() >= 0; } *pwrapped = nullptr; // silence GCC warning @@ -3280,11 +3303,11 @@ MBinaryInstruction::unsignedOperands(MDefinition* left, MDefinition* right) MDefinition* replace; if (!MustBeUInt32(left, &replace)) return false; - if (replace->type() != MIRType_Int32) + if (replace->type() != MIRType::Int32) return false; if (!MustBeUInt32(right, &replace)) return false; - if (replace->type() != MIRType_Int32) + if (replace->type() != MIRType::Int32) return false; return true; } @@ -3326,16 +3349,16 @@ MCompare::determineCompareType(JSOp op, MDefinition* left, MDefinition* right) return Compare_UInt32; // Integer to integer or boolean to boolean comparisons may be treated as Int32. - if ((lhs == MIRType_Int32 && rhs == MIRType_Int32) || - (lhs == MIRType_Boolean && rhs == MIRType_Boolean)) + if ((lhs == MIRType::Int32 && rhs == MIRType::Int32) || + (lhs == MIRType::Boolean && rhs == MIRType::Boolean)) { return Compare_Int32MaybeCoerceBoth; } // Loose/relational cross-integer/boolean comparisons may be treated as Int32. if (!strictEq && - (lhs == MIRType_Int32 || lhs == MIRType_Boolean) && - (rhs == MIRType_Int32 || rhs == MIRType_Boolean)) + (lhs == MIRType::Int32 || lhs == MIRType::Boolean) && + (rhs == MIRType::Int32 || rhs == MIRType::Boolean)) { return Compare_Int32MaybeCoerceBoth; } @@ -3351,29 +3374,29 @@ MCompare::determineCompareType(JSOp op, MDefinition* left, MDefinition* right) return Compare_DoubleMaybeCoerceRHS; // Handle object comparison. - if (!relationalEq && lhs == MIRType_Object && rhs == MIRType_Object) + if (!relationalEq && lhs == MIRType::Object && rhs == MIRType::Object) return Compare_Object; // Handle string comparisons. (Relational string compares are still unsupported). - if (!relationalEq && lhs == MIRType_String && rhs == MIRType_String) + if (!relationalEq && lhs == MIRType::String && rhs == MIRType::String) return Compare_String; // Handle strict string compare. - if (strictEq && lhs == MIRType_String) + if (strictEq && lhs == MIRType::String) return Compare_StrictString; - if (strictEq && rhs == MIRType_String) + if (strictEq && rhs == MIRType::String) return Compare_StrictString; // Handle compare with lhs or rhs being Undefined or Null. if (!relationalEq && IsNullOrUndefined(lhs)) - return (lhs == MIRType_Null) ? Compare_Null : Compare_Undefined; + return (lhs == MIRType::Null) ? Compare_Null : Compare_Undefined; if (!relationalEq && IsNullOrUndefined(rhs)) - return (rhs == MIRType_Null) ? Compare_Null : Compare_Undefined; + return (rhs == MIRType::Null) ? Compare_Null : Compare_Undefined; // Handle strict comparison with lhs/rhs being typed Boolean. - if (strictEq && (lhs == MIRType_Boolean || rhs == MIRType_Boolean)) { + if (strictEq && (lhs == MIRType::Boolean || rhs == MIRType::Boolean)) { // bool/bool case got an int32 specialization earlier. - MOZ_ASSERT(!(lhs == MIRType_Boolean && rhs == MIRType_Boolean)); + MOZ_ASSERT(!(lhs == MIRType::Boolean && rhs == MIRType::Boolean)); return Compare_Boolean; } @@ -3403,15 +3426,15 @@ MBitNot* MBitNot::NewAsmJS(TempAllocator& alloc, MDefinition* input) { MBitNot* ins = new(alloc) MBitNot(input); - ins->specialization_ = MIRType_Int32; - MOZ_ASSERT(ins->type() == MIRType_Int32); + ins->specialization_ = MIRType::Int32; + MOZ_ASSERT(ins->type() == MIRType::Int32); return ins; } MDefinition* MBitNot::foldsTo(TempAllocator& alloc) { - if (specialization_ != MIRType_Int32) + if (specialization_ != MIRType::Int32) return this; MDefinition* input = getOperand(0); @@ -3421,8 +3444,8 @@ MBitNot::foldsTo(TempAllocator& alloc) return MConstant::New(alloc, v); } - if (input->isBitNot() && input->toBitNot()->specialization_ == MIRType_Int32) { - MOZ_ASSERT(input->toBitNot()->getOperand(0)->type() == MIRType_Int32); + if (input->isBitNot() && input->toBitNot()->specialization_ == MIRType::Int32) { + MOZ_ASSERT(input->toBitNot()->getOperand(0)->type() == MIRType::Int32); return MTruncateToInt32::New(alloc, input->toBitNot()->input()); // ~~x => x | 0 } @@ -3434,32 +3457,32 @@ MTypeOf::foldsTo(TempAllocator& alloc) { // Note: we can't use input->type() here, type analysis has // boxed the input. - MOZ_ASSERT(input()->type() == MIRType_Value); + MOZ_ASSERT(input()->type() == MIRType::Value); JSType type; switch (inputType()) { - case MIRType_Double: - case MIRType_Float32: - case MIRType_Int32: + case MIRType::Double: + case MIRType::Float32: + case MIRType::Int32: type = JSTYPE_NUMBER; break; - case MIRType_String: + case MIRType::String: type = JSTYPE_STRING; break; - case MIRType_Symbol: + case MIRType::Symbol: type = JSTYPE_SYMBOL; break; - case MIRType_Null: + case MIRType::Null: type = JSTYPE_OBJECT; break; - case MIRType_Undefined: + case MIRType::Undefined: type = JSTYPE_VOID; break; - case MIRType_Boolean: + case MIRType::Boolean: type = JSTYPE_BOOLEAN; break; - case MIRType_Object: + case MIRType::Object: if (!inputMaybeCallableOrEmulatesUndefined()) { // Object is not callable and does not emulate undefined, so it's // safe to fold to "object". @@ -3486,7 +3509,7 @@ MTypeOf::cacheInputMaybeCallableOrEmulatesUndefined(CompilerConstraintList* cons MBitAnd* MBitAnd::New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MBitAnd(left, right, MIRType_Int32); + return new(alloc) MBitAnd(left, right, MIRType::Int32); } MBitAnd* @@ -3500,7 +3523,7 @@ MBitAnd::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, M MBitOr* MBitOr::New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MBitOr(left, right, MIRType_Int32); + return new(alloc) MBitOr(left, right, MIRType::Int32); } MBitOr* @@ -3514,7 +3537,7 @@ MBitOr::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MI MBitXor* MBitXor::New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MBitXor(left, right, MIRType_Int32); + return new(alloc) MBitXor(left, right, MIRType::Int32); } MBitXor* @@ -3528,7 +3551,7 @@ MBitXor::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, M MLsh* MLsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MLsh(left, right, MIRType_Int32); + return new(alloc) MLsh(left, right, MIRType::Int32); } MLsh* @@ -3542,7 +3565,7 @@ MLsh::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRT MRsh* MRsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MRsh(left, right, MIRType_Int32); + return new(alloc) MRsh(left, right, MIRType::Int32); } MRsh* @@ -3556,7 +3579,7 @@ MRsh::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRT MUrsh* MUrsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MUrsh(left, right, MIRType_Int32); + return new(alloc) MUrsh(left, right, MIRType::Int32); } MUrsh* @@ -3738,17 +3761,17 @@ MToInt32::foldsTo(TempAllocator& alloc) if (input->isConstant()) { DebugOnly convert = conversion(); switch (input->type()) { - case MIRType_Null: + case MIRType::Null: MOZ_ASSERT(convert == MacroAssembler::IntConversion_Any); return MConstant::New(alloc, Int32Value(0)); - case MIRType_Boolean: + case MIRType::Boolean: MOZ_ASSERT(convert == MacroAssembler::IntConversion_Any || convert == MacroAssembler::IntConversion_NumbersOrBoolsOnly); return MConstant::New(alloc, Int32Value(input->toConstant()->toBoolean())); - case MIRType_Int32: + case MIRType::Int32: return MConstant::New(alloc, Int32Value(input->toConstant()->toInt32())); - case MIRType_Float32: - case MIRType_Double: + case MIRType::Float32: + case MIRType::Double: int32_t ival; // Only the value within the range of Int32 can be substituted as constant. if (mozilla::NumberEqualsInt32(input->toConstant()->numberToDouble(), &ival)) @@ -3759,7 +3782,7 @@ MToInt32::foldsTo(TempAllocator& alloc) } } - if (input->type() == MIRType_Int32) + if (input->type() == MIRType::Int32) return input; return this; } @@ -3778,10 +3801,10 @@ MTruncateToInt32::foldsTo(TempAllocator& alloc) if (input->isBox()) input = input->getOperand(0); - if (input->type() == MIRType_Int32) + if (input->type() == MIRType::Int32) return input; - if (input->type() == MIRType_Double && input->isConstant()) { + if (input->type() == MIRType::Double && input->isConstant()) { int32_t ret = ToInt32(input->toConstant()->toDouble()); return MConstant::New(alloc, Int32Value(ret)); } @@ -3789,6 +3812,40 @@ MTruncateToInt32::foldsTo(TempAllocator& alloc) return this; } +MDefinition* +MWasmTruncateToInt32::foldsTo(TempAllocator& alloc) +{ + MDefinition* input = getOperand(0); + if (input->type() == MIRType::Int32) + return input; + + if (input->type() == MIRType::Double && input->isConstant()) { + double d = input->toConstant()->toDouble(); + if (IsNaN(d)) + return this; + + if (!isUnsigned_ && d <= double(INT32_MAX) && d >= double(INT32_MIN)) + return MConstant::New(alloc, Int32Value(ToInt32(d))); + + if (isUnsigned_ && d <= double(UINT32_MAX) && d >= 0) + return MConstant::New(alloc, Int32Value(ToInt32(d))); + } + + if (input->type() == MIRType::Float32 && input->isConstant()) { + double f = double(input->toConstant()->toFloat32()); + if (IsNaN(f)) + return this; + + if (!isUnsigned_ && f <= double(INT32_MAX) && f >= double(INT32_MIN)) + return MConstant::New(alloc, Int32Value(ToInt32(f))); + + if (isUnsigned_ && f <= double(UINT32_MAX) && f >= 0) + return MConstant::New(alloc, Int32Value(ToInt32(f))); + } + + return this; +} + MDefinition* MWrapInt64ToInt32::foldsTo(TempAllocator& alloc) { @@ -3821,7 +3878,7 @@ MToDouble::foldsTo(TempAllocator& alloc) if (input->isBox()) input = input->getOperand(0); - if (input->type() == MIRType_Double) + if (input->type() == MIRType::Double) return input; if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble()) { @@ -3839,11 +3896,11 @@ MToFloat32::foldsTo(TempAllocator& alloc) if (input->isBox()) input = input->getOperand(0); - if (input->type() == MIRType_Float32) + if (input->type() == MIRType::Float32) return input; // If x is a Float32, Float32(Double(x)) == x - if (input->isToDouble() && input->toToDouble()->input()->type() == MIRType_Float32) + if (input->isToDouble() && input->toToDouble()->input()->type() == MIRType::Float32) return input->toToDouble()->input(); if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble()) @@ -3859,7 +3916,7 @@ MToString::foldsTo(TempAllocator& alloc) if (in->isBox()) in = in->getOperand(0); - if (in->type() == MIRType_String) + if (in->type() == MIRType::String) return in; return this; } @@ -3926,7 +3983,7 @@ MCompare::tryFoldTypeOf(bool* result) MTypeOf* typeOf = lhs()->isTypeOf() ? lhs()->toTypeOf() : rhs()->toTypeOf(); MConstant* constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant(); - if (constant->type() != MIRType_String) + if (constant->type() != MIRType::String) return false; if (jsop() != JSOP_STRICTEQ && jsop() != JSOP_STRICTNE && @@ -3937,38 +3994,38 @@ MCompare::tryFoldTypeOf(bool* result) const JSAtomState& names = GetJitContext()->runtime->names(); if (constant->toString() == TypeName(JSTYPE_VOID, names)) { - if (!typeOf->input()->mightBeType(MIRType_Undefined) && + if (!typeOf->input()->mightBeType(MIRType::Undefined) && !typeOf->inputMaybeCallableOrEmulatesUndefined()) { *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE); return true; } } else if (constant->toString() == TypeName(JSTYPE_BOOLEAN, names)) { - if (!typeOf->input()->mightBeType(MIRType_Boolean)) { + if (!typeOf->input()->mightBeType(MIRType::Boolean)) { *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE); return true; } } else if (constant->toString() == TypeName(JSTYPE_NUMBER, names)) { - if (!typeOf->input()->mightBeType(MIRType_Int32) && - !typeOf->input()->mightBeType(MIRType_Float32) && - !typeOf->input()->mightBeType(MIRType_Double)) + if (!typeOf->input()->mightBeType(MIRType::Int32) && + !typeOf->input()->mightBeType(MIRType::Float32) && + !typeOf->input()->mightBeType(MIRType::Double)) { *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE); return true; } } else if (constant->toString() == TypeName(JSTYPE_STRING, names)) { - if (!typeOf->input()->mightBeType(MIRType_String)) { + if (!typeOf->input()->mightBeType(MIRType::String)) { *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE); return true; } } else if (constant->toString() == TypeName(JSTYPE_SYMBOL, names)) { - if (!typeOf->input()->mightBeType(MIRType_Symbol)) { + if (!typeOf->input()->mightBeType(MIRType::Symbol)) { *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE); return true; } } else if (constant->toString() == TypeName(JSTYPE_OBJECT, names)) { - if (!typeOf->input()->mightBeType(MIRType_Object) && - !typeOf->input()->mightBeType(MIRType_Null)) + if (!typeOf->input()->mightBeType(MIRType::Object) && + !typeOf->input()->mightBeType(MIRType::Null)) { *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE); return true; @@ -4011,9 +4068,9 @@ MCompare::tryFold(bool* result) *result = (op == JSOP_EQ); return true; } - if (!lhs()->mightBeType(MIRType_Null) && - !lhs()->mightBeType(MIRType_Undefined) && - !(lhs()->mightBeType(MIRType_Object) && operandMightEmulateUndefined())) + if (!lhs()->mightBeType(MIRType::Null) && + !lhs()->mightBeType(MIRType::Undefined) && + !(lhs()->mightBeType(MIRType::Object) && operandMightEmulateUndefined())) { *result = (op == JSOP_NE); return true; @@ -4024,10 +4081,10 @@ MCompare::tryFold(bool* result) if (compareType_ == Compare_Boolean) { MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE); - MOZ_ASSERT(rhs()->type() == MIRType_Boolean); - MOZ_ASSERT(lhs()->type() != MIRType_Boolean, "Should use Int32 comparison"); + MOZ_ASSERT(rhs()->type() == MIRType::Boolean); + MOZ_ASSERT(lhs()->type() != MIRType::Boolean, "Should use Int32 comparison"); - if (!lhs()->mightBeType(MIRType_Boolean)) { + if (!lhs()->mightBeType(MIRType::Boolean)) { *result = (op == JSOP_STRICTNE); return true; } @@ -4036,10 +4093,10 @@ MCompare::tryFold(bool* result) if (compareType_ == Compare_StrictString) { MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE); - MOZ_ASSERT(rhs()->type() == MIRType_String); - MOZ_ASSERT(lhs()->type() != MIRType_String, "Should use String comparison"); + MOZ_ASSERT(rhs()->type() == MIRType::String); + MOZ_ASSERT(lhs()->type() != MIRType::String, "Should use String comparison"); - if (!lhs()->mightBeType(MIRType_String)) { + if (!lhs()->mightBeType(MIRType::String)) { *result = (op == JSOP_STRICTNE); return true; } @@ -4067,7 +4124,7 @@ FoldComparison(JSOp op, T left, T right) bool MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) { - if (type() != MIRType_Boolean && type() != MIRType_Int32) + if (type() != MIRType::Boolean && type() != MIRType::Int32) return false; MDefinition* left = getOperand(0); @@ -4083,10 +4140,10 @@ MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) MDefinition* operand = left->isConstant() ? right : left; MConstant* constant = left->isConstant() ? left->toConstant() : right->toConstant(); - MOZ_ASSERT(constant->type() == MIRType_Double); + MOZ_ASSERT(constant->type() == MIRType::Double); double cte = constant->toDouble(); - if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) { + if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType::Int32) { bool replaced = false; switch (jsop_) { case JSOP_LT: @@ -4161,7 +4218,7 @@ MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) MConstant* rhs = right->toConstant(); // Fold away some String equality comparisons. - if (lhs->type() == MIRType_String && rhs->type() == MIRType_String) { + if (lhs->type() == MIRType::String && rhs->type() == MIRType::String) { int32_t comp = 0; // Default to equal. if (left != right) comp = CompareAtoms(&lhs->toString()->asAtom(), &rhs->toString()->asAtom()); @@ -4198,10 +4255,10 @@ MCompare::foldsTo(TempAllocator& alloc) bool result; if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) { - if (type() == MIRType_Int32) + if (type() == MIRType::Int32) return MConstant::New(alloc, Int32Value(result)); - MOZ_ASSERT(type() == MIRType_Boolean); + MOZ_ASSERT(type() == MIRType::Boolean); return MConstant::New(alloc, BooleanValue(result)); } @@ -4217,9 +4274,9 @@ MCompare::trySpecializeFloat32(TempAllocator& alloc) if (lhs->canProduceFloat32() && rhs->canProduceFloat32() && compareType_ == Compare_Double) { compareType_ = Compare_Float32; } else { - if (lhs->type() == MIRType_Float32) + if (lhs->type() == MIRType::Float32) ConvertDefinitionToDouble<0>(alloc, lhs, this); - if (rhs->type() == MIRType_Float32) + if (rhs->type() == MIRType::Float32) ConvertDefinitionToDouble<1>(alloc, rhs, this); } } @@ -4271,7 +4328,7 @@ MNot::foldsTo(TempAllocator& alloc) if (MConstant* inputConst = input()->maybeConstantValue()) { bool b; if (inputConst->valueToBoolean(&b)) { - if (type() == MIRType_Int32) + if (type() == MIRType::Int32) return MConstant::New(alloc, Int32Value(!b)); return MConstant::New(alloc, BooleanValue(!b)); } @@ -4288,15 +4345,15 @@ MNot::foldsTo(TempAllocator& alloc) } // NOT of an undefined or null value is always true - if (input()->type() == MIRType_Undefined || input()->type() == MIRType_Null) + if (input()->type() == MIRType::Undefined || input()->type() == MIRType::Null) return MConstant::New(alloc, BooleanValue(true)); // NOT of a symbol is always false. - if (input()->type() == MIRType_Symbol) + if (input()->type() == MIRType::Symbol) return MConstant::New(alloc, BooleanValue(false)); // NOT of an object that can't emulate undefined is always false. - if (input()->type() == MIRType_Object && !operandMightEmulateUndefined()) + if (input()->type() == MIRType::Object && !operandMightEmulateUndefined()) return MConstant::New(alloc, BooleanValue(false)); return this; @@ -4306,7 +4363,7 @@ void MNot::trySpecializeFloat32(TempAllocator& alloc) { MDefinition* in = input(); - if (!in->canProduceFloat32() && in->type() == MIRType_Float32) + if (!in->canProduceFloat32() && in->type() == MIRType::Float32) ConvertDefinitionToDouble<0>(alloc, in, this); } @@ -4360,14 +4417,14 @@ MObjectState::MObjectState(MObjectState* state) operandIndex_(state->operandIndex_) { // This instruction is only used as a summary for bailout paths. - setResultType(MIRType_Object); + setResultType(MIRType::Object); setRecoveredOnBailout(); } MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex) { // This instruction is only used as a summary for bailout paths. - setResultType(MIRType_Object); + setResultType(MIRType::Object); setRecoveredOnBailout(); if (templateObject->is()) { @@ -4487,7 +4544,7 @@ MObjectState::Copy(TempAllocator& alloc, MObjectState* state) MArrayState::MArrayState(MDefinition* arr) { // This instruction is only used as a summary for bailout paths. - setResultType(MIRType_Object); + setResultType(MIRType::Object); setRecoveredOnBailout(); numElements_ = arr->toNewArray()->length(); } @@ -4537,7 +4594,7 @@ MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t length, MCons convertDoubleElements_(false), pc_(pc) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); if (templateObject()) { if (TemporaryTypeSet* types = MakeSingletonTypeSet(constraints, templateObject())) { setResultTypeSet(types); @@ -4547,20 +4604,20 @@ MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t length, MCons } } -bool +MDefinition::AliasType MLoadFixedSlot::mightAlias(const MDefinition* store) const { if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot()) - return false; - return true; + return AliasType::NoAlias; + return AliasType::MayAlias; } -bool +MDefinition::AliasType MLoadFixedSlotAndUnbox::mightAlias(const MDefinition* store) const { if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot()) - return false; - return true; + return AliasType::NoAlias; + return AliasType::MayAlias; } MDefinition* @@ -4582,20 +4639,21 @@ MLoadFixedSlot::foldsTo(TempAllocator& alloc) return foldsToStoredValue(alloc, store->value()); } -bool +MDefinition::AliasType MAsmJSLoadHeap::mightAlias(const MDefinition* def) const { if (def->isAsmJSStoreHeap()) { const MAsmJSStoreHeap* store = def->toAsmJSStoreHeap(); if (store->accessType() != accessType()) - return true; + return AliasType::MayAlias; if (!base()->isConstant() || !store->base()->isConstant()) - return true; + return AliasType::MayAlias; const MConstant* otherBase = store->base()->toConstant(); - return base()->toConstant()->equals(otherBase) && - offset() == store->offset(); + if (base()->toConstant()->equals(otherBase) && offset() == store->offset()) + return AliasType::MayAlias; + return AliasType::NoAlias; } - return true; + return AliasType::MayAlias; } bool @@ -4609,14 +4667,15 @@ MAsmJSLoadHeap::congruentTo(const MDefinition* ins) const congruentIfOperandsEqual(load); } -bool +MDefinition::AliasType MAsmJSLoadGlobalVar::mightAlias(const MDefinition* def) const { if (def->isAsmJSStoreGlobalVar()) { const MAsmJSStoreGlobalVar* store = def->toAsmJSStoreGlobalVar(); - return store->globalDataOffset() == globalDataOffset_; + return (store->globalDataOffset() == globalDataOffset_) ? AliasType::MayAlias : + AliasType::NoAlias; } - return true; + return AliasType::MayAlias; } HashNumber @@ -4698,12 +4757,12 @@ MAsmJSLoadFFIFunc::congruentTo(const MDefinition* ins) const return false; } -bool +MDefinition::AliasType MLoadSlot::mightAlias(const MDefinition* store) const { if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot()) - return false; - return true; + return AliasType::NoAlias; + return AliasType::MayAlias; } HashNumber @@ -4777,7 +4836,7 @@ MLoadUnboxedObjectOrNull::foldsTo(TempAllocator& alloc) if (store->index() != index()) return this; - if (store->value()->type() == MIRType_ObjectOrNull) + if (store->value()->type() == MIRType::ObjectOrNull) return this; if (store->offsetAdjustment() != offsetAdjustment()) @@ -4797,7 +4856,7 @@ MaybeUnwrapElements(const MDefinition* elementsOrObj) return MaybeUnwrapElements(elementsOrObj->toConvertElementsToDoubles()->elements()); // For inline elements, the object may be passed directly, for example as MUnbox. - if (elementsOrObj->type() == MIRType_Object) + if (elementsOrObj->type() == MIRType::Object) return nullptr; // MTypedArrayElements and MTypedObjectElements aren't handled. @@ -4810,7 +4869,7 @@ MaybeUnwrapElements(const MDefinition* elementsOrObj) static inline const MDefinition* GetElementsObject(const MDefinition* elementsOrObj) { - if (elementsOrObj->type() == MIRType_Object) + if (elementsOrObj->type() == MIRType::Object) return elementsOrObj; const MDefinition* elements = MaybeUnwrapElements(elementsOrObj); @@ -4846,7 +4905,7 @@ GetStoreObject(const MDefinition* store) } // Implements mightAlias() logic common to all load operations. -static bool +static MDefinition::AliasType GenericLoadMightAlias(const MDefinition* elementsOrObj, const MDefinition* store) { const MElements* elements = MaybeUnwrapElements(elementsOrObj); @@ -4854,71 +4913,77 @@ GenericLoadMightAlias(const MDefinition* elementsOrObj, const MDefinition* store return elements->mightAlias(store); // Unhandled Elements kind. - if (elementsOrObj->type() != MIRType_Object) - return true; + if (elementsOrObj->type() != MIRType::Object) + return MDefinition::AliasType::MayAlias; // Inline storage for objects. // Refer to IsValidElementsType(). const MDefinition* object = elementsOrObj; - MOZ_ASSERT(object->type() == MIRType_Object); + MOZ_ASSERT(object->type() == MIRType::Object); if (!object->resultTypeSet()) - return true; + return MDefinition::AliasType::MayAlias; const MDefinition* storeObject = GetStoreObject(store); if (!storeObject) - return true; + return MDefinition::AliasType::MayAlias; if (!storeObject->resultTypeSet()) - return true; + return MDefinition::AliasType::MayAlias; - return object->resultTypeSet()->objectsIntersect(storeObject->resultTypeSet()); + if (object->resultTypeSet()->objectsIntersect(storeObject->resultTypeSet())) + return MDefinition::AliasType::MayAlias; + return MDefinition::AliasType::NoAlias; } -bool +MDefinition::AliasType MElements::mightAlias(const MDefinition* store) const { if (!input()->resultTypeSet()) - return true; + return AliasType::MayAlias; const MDefinition* storeObj = GetStoreObject(store); if (!storeObj) - return true; + return AliasType::MayAlias; if (!storeObj->resultTypeSet()) - return true; + return AliasType::MayAlias; - return input()->resultTypeSet()->objectsIntersect(storeObj->resultTypeSet()); + return AliasType::MayAlias; + + if (input()->resultTypeSet()->objectsIntersect(storeObj->resultTypeSet())) + return AliasType::MayAlias; + return AliasType::NoAlias; } -bool +MDefinition::AliasType MLoadElement::mightAlias(const MDefinition* store) const { return GenericLoadMightAlias(elements(), store); } -bool +MDefinition::AliasType MInitializedLength::mightAlias(const MDefinition* store) const { return GenericLoadMightAlias(elements(), store); } -bool +MDefinition::AliasType MLoadUnboxedObjectOrNull::mightAlias(const MDefinition* store) const { return GenericLoadMightAlias(elements(), store); } -bool +MDefinition::AliasType MLoadUnboxedString::mightAlias(const MDefinition* store) const { return GenericLoadMightAlias(elements(), store); } -bool +MDefinition::AliasType MLoadUnboxedScalar::mightAlias(const MDefinition* store) const { return GenericLoadMightAlias(elements(), store); } -bool +MDefinition::AliasType MUnboxedArrayInitializedLength::mightAlias(const MDefinition* store) const { return GenericLoadMightAlias(object(), store); @@ -5072,14 +5137,14 @@ MStoreTypedArrayElementStatic::length() const return someTypedArray_->as().byteLength(); } -bool +MDefinition::AliasType MGetPropertyPolymorphic::mightAlias(const MDefinition* store) const { // Allow hoisting this instruction if the store does not write to a // slot read by this instruction. if (!store->isStoreFixedSlot() && !store->isStoreSlot()) - return true; + return AliasType::MayAlias; for (size_t i = 0; i < numReceivers(); i++) { const Shape* shape = this->shape(i); @@ -5101,10 +5166,10 @@ MGetPropertyPolymorphic::mightAlias(const MDefinition* store) const continue; } - return true; + return AliasType::MayAlias; } - return false; + return AliasType::NoAlias; } void @@ -5129,7 +5194,7 @@ MGetPropertyCache::updateForReplacement(MDefinition* ins) MDefinition* MAsmJSUnsignedToDouble::foldsTo(TempAllocator& alloc) { - if (input()->isConstant() && input()->type() == MIRType_Int32) + if (input()->isConstant() && input()->type() == MIRType::Int32) return MConstant::New(alloc, DoubleValue(uint32_t(input()->toConstant()->toInt32()))); return this; @@ -5138,10 +5203,10 @@ MAsmJSUnsignedToDouble::foldsTo(TempAllocator& alloc) MDefinition* MAsmJSUnsignedToFloat32::foldsTo(TempAllocator& alloc) { - if (input()->isConstant() && input()->type() == MIRType_Int32) { + if (input()->isConstant() && input()->type() == MIRType::Int32) { double dval = double(uint32_t(input()->toConstant()->toInt32())); if (IsFloat32Representable(dval)) - return MConstant::NewAsmJS(alloc, JS::Float32Value(float(dval)), MIRType_Float32); + return MConstant::NewAsmJS(alloc, JS::Float32Value(float(dval)), MIRType::Float32); } return this; @@ -5173,13 +5238,13 @@ MAsmJSCall::New(TempAllocator& alloc, const wasm::CallSiteDesc& desc, Callee cal void MSqrt::trySpecializeFloat32(TempAllocator& alloc) { if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) { - if (input()->type() == MIRType_Float32) + if (input()->type() == MIRType::Float32) ConvertDefinitionToDouble<0>(alloc, input(), this); return; } - setResultType(MIRType_Float32); - specialization_ = MIRType_Float32; + setResultType(MIRType::Float32); + specialization_ = MIRType::Float32; } MDefinition* @@ -5240,11 +5305,11 @@ MTableSwitch::foldsTo(TempAllocator& alloc) // If we only have one successor, convert to a plain goto to the only // successor. TableSwitch indices are numeric; other types will always go to // the only successor. - if (numSuccessors() == 1 || (op->type() != MIRType_Value && !IsNumberType(op->type()))) + if (numSuccessors() == 1 || (op->type() != MIRType::Value && !IsNumberType(op->type()))) return MGoto::New(alloc, getDefault()); if (MConstant* opConst = op->maybeConstantValue()) { - if (op->type() == MIRType_Int32) { + if (op->type() == MIRType::Int32) { int32_t i = opConst->toInt32() - low_; MBasicBlock* target; if (size_t(i) < numCases()) @@ -5290,6 +5355,18 @@ MArrayJoin::foldsTo(TempAllocator& alloc) return substr; } +MDefinition* +MGetFirstDollarIndex::foldsTo(TempAllocator& alloc) +{ + MDefinition* strArg = str(); + if (!strArg->isConstant()) + return this; + + JSAtom* atom = &strArg->toConstant()->toString()->asAtom(); + int32_t index = GetFirstDollarIndexRawFlat(atom); + return MConstant::New(alloc, Int32Value(index)); +} + MConvertUnboxedObjectToNative* MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group) { @@ -5323,10 +5400,10 @@ bool jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id) { - if (obj->mightBeType(MIRType_String)) + if (obj->mightBeType(MIRType::String)) return false; - if (id->type() != MIRType_Int32 && id->type() != MIRType_Double) + if (id->type() != MIRType::Int32 && id->type() != MIRType::Double) return false; TemporaryTypeSet* types = obj->resultTypeSet(); @@ -5342,10 +5419,10 @@ JSValueType jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id) { - if (obj->mightBeType(MIRType_String)) + if (obj->mightBeType(MIRType::String)) return JSVAL_TYPE_MAGIC; - if (id && id->type() != MIRType_Int32 && id->type() != MIRType_Double) + if (id && id->type() != MIRType::Int32 && id->type() != MIRType::Double) return JSVAL_TYPE_MAGIC; TemporaryTypeSet* types = obj->resultTypeSet(); @@ -5385,10 +5462,10 @@ jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id, Scalar::Type* arrayType) { - if (obj->mightBeType(MIRType_String)) + if (obj->mightBeType(MIRType::String)) return false; - if (id->type() != MIRType_Int32 && id->type() != MIRType_Double) + if (id->type() != MIRType::Int32 && id->type() != MIRType::Double) return false; TemporaryTypeSet* types = obj->resultTypeSet(); @@ -5428,7 +5505,7 @@ MIRType jit::DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj) { TemporaryTypeSet* types = obj->resultTypeSet(); - MIRType elementType = MIRType_None; + MIRType elementType = MIRType::None; unsigned count = types->getObjectCount(); for (unsigned i = 0; i < count; i++) { @@ -5437,18 +5514,18 @@ jit::DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* ob continue; if (key->unknownProperties()) - return MIRType_None; + return MIRType::None; HeapTypeSetKey elementTypes = key->property(JSID_VOID); MIRType type = elementTypes.knownMIRType(constraints); - if (type == MIRType_None) - return MIRType_None; + if (type == MIRType::None) + return MIRType::None; - if (elementType == MIRType_None) + if (elementType == MIRType::None) elementType = type; else if (elementType != type) - return MIRType_None; + return MIRType::None; } return elementType; @@ -5484,7 +5561,7 @@ PropertyReadNeedsTypeBarrier(CompilerConstraintList* constraints, jsid id = name ? NameToId(name) : JSID_VOID; HeapTypeSetKey property = key->property(id); if (property.maybeTypes()) { - if (!TypeSetIncludes(observed, MIRType_Value, property.maybeTypes())) { + if (!TypeSetIncludes(observed, MIRType::Value, property.maybeTypes())) { // If all possible objects have been observed, we don't have to // guard on the specific object types. if (property.maybeTypes()->objectsAreSubset(observed)) { @@ -5812,11 +5889,11 @@ static bool PropertyTypeIncludes(TempAllocator& alloc, HeapTypeSetKey property, MDefinition* value, MIRType implicitType) { - // If implicitType is not MIRType_None, it is an additional type which the + // If implicitType is not MIRType::None, it is an additional type which the // property implicitly includes. In this case, make a new type set which // explicitly contains the type. TypeSet* types = property.maybeTypes(); - if (implicitType != MIRType_None) { + if (implicitType != MIRType::None) { TypeSet::Type newType = TypeSet::PrimitiveType(ValueTypeFromMIRType(implicitType)); if (types) types = types->clone(alloc.lifoAlloc()); @@ -5875,17 +5952,17 @@ TryAddTypeBarrierForWrite(TempAllocator& alloc, CompilerConstraintList* constrai MIRType propertyType = aggregateProperty->knownMIRType(constraints); switch (propertyType) { - case MIRType_Boolean: - case MIRType_Int32: - case MIRType_Double: - case MIRType_String: - case MIRType_Symbol: { + case MIRType::Boolean: + case MIRType::Int32: + case MIRType::Double: + case MIRType::String: + case MIRType::Symbol: { // The property is a particular primitive type, guard by unboxing the // value before the write. if (!(*pvalue)->mightBeType(propertyType)) { // The value's type does not match the property type. Just do a VM // call as it will always trigger invalidation of the compiled code. - MOZ_ASSERT_IF((*pvalue)->type() != MIRType_Value, (*pvalue)->type() != propertyType); + MOZ_ASSERT_IF((*pvalue)->type() != MIRType::Value, (*pvalue)->type() != propertyType); return false; } MInstruction* ins = MUnbox::New(alloc, *pvalue, propertyType, MUnbox::Fallible); @@ -5896,7 +5973,7 @@ TryAddTypeBarrierForWrite(TempAllocator& alloc, CompilerConstraintList* constrai default:; } - if ((*pvalue)->type() != MIRType_Value) + if ((*pvalue)->type() != MIRType::Value) return false; TemporaryTypeSet* types = aggregateProperty->maybeTypes()->clone(alloc.lifoAlloc()); @@ -5941,7 +6018,7 @@ AddGroupGuard(TempAllocator& alloc, MBasicBlock* current, MDefinition* obj, bool jit::CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints, HeapTypeSetKey property, MDefinition* value, - MIRType implicitType /* = MIRType_None */) + MIRType implicitType /* = MIRType::None */) { if (property.couldBeConstant(constraints)) return false; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 4c99db8568..0cd36a0c22 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -46,19 +46,19 @@ static inline MIRType MIRTypeFromValue(const js::Value& vp) { if (vp.isDouble()) - return MIRType_Double; + return MIRType::Double; if (vp.isMagic()) { switch (vp.whyMagic()) { case JS_OPTIMIZED_ARGUMENTS: - return MIRType_MagicOptimizedArguments; + return MIRType::MagicOptimizedArguments; case JS_OPTIMIZED_OUT: - return MIRType_MagicOptimizedOut; + return MIRType::MagicOptimizedOut; case JS_ELEMENTS_HOLE: - return MIRType_MagicHole; + return MIRType::MagicHole; case JS_IS_CONSTRUCTING: - return MIRType_MagicIsConstructing; + return MIRType::MagicIsConstructing; case JS_UNINITIALIZED_LEXICAL: - return MIRType_MagicUninitializedLexical; + return MIRType::MagicUninitializedLexical; default: MOZ_ASSERT(!"Unexpected magic constant"); } @@ -75,9 +75,9 @@ bool MaybeSimdTypeToMIRType(SimdType type, MIRType* mirType) { switch (type) { case SimdType::Uint32x4: - case SimdType::Int32x4: *mirType = MIRType_Int32x4; return true; - case SimdType::Float32x4: *mirType = MIRType_Float32x4; return true; - case SimdType::Bool32x4: *mirType = MIRType_Bool32x4; return true; + case SimdType::Int32x4: *mirType = MIRType::Int32x4; return true; + case SimdType::Float32x4: *mirType = MIRType::Float32x4; return true; + case SimdType::Bool32x4: *mirType = MIRType::Bool32x4; return true; default: return false; } } @@ -89,7 +89,7 @@ bool MaybeSimdTypeToMIRType(SimdType type, MIRType* mirType) static inline MIRType SimdTypeToMIRType(SimdType type) { - MIRType ret = MIRType_None; + MIRType ret = MIRType::None; JS_ALWAYS_TRUE(MaybeSimdTypeToMIRType(type, &ret)); return ret; } @@ -98,9 +98,9 @@ static inline SimdType MIRTypeToSimdType(MIRType type) { switch (type) { - case MIRType_Float32x4: return SimdType::Float32x4; - case MIRType_Int32x4: return SimdType::Int32x4; - case MIRType_Bool32x4: return SimdType::Bool32x4; + case MIRType::Float32x4: return SimdType::Float32x4; + case MIRType::Int32x4: return SimdType::Int32x4; + case MIRType::Bool32x4: return SimdType::Bool32x4; default: break; } MOZ_CRASH("unhandled MIRType"); @@ -371,6 +371,8 @@ class AliasSet { } public: + static const char* Name(size_t flag); + inline bool isNone() const { return flags_ == None_; } @@ -405,6 +407,30 @@ class AliasSet { } }; +typedef Vector MDefinitionVector; +typedef Vector MInstructionVector; +typedef Vector MStoreVector; + +class StoreDependency : public TempObject +{ + MStoreVector all_; + + public: + explicit StoreDependency(TempAllocator& alloc) + : all_(alloc) + { } + + bool init(MDefinitionVector& all) { + if (!all_.appendAll(all)) + return false; + return true; + } + + MStoreVector& get() { + return all_; + } +}; + // An MDefinition is an SSA name. class MDefinition : public MNode { @@ -427,8 +453,8 @@ class MDefinition : public MNode MIRType resultType_; // Representation of result type. TemporaryTypeSet* resultTypeSet_; // Optional refinement of the result type. union { - MInstruction* dependency_; // Implicit dependency (store, call, etc.) of this instruction. - // Used by alias analysis, GVN and LICM. + MDefinition* loadDependency_; // Implicit dependency (store, call, etc.) of this + StoreDependency* storeDependency_; // instruction. Used by alias analysis, GVN and LICM. uint32_t virtualRegister_; // Used by lowering to map definitions to virtual registers. }; @@ -467,9 +493,9 @@ class MDefinition : public MNode : id_(0), flags_(0), range_(nullptr), - resultType_(MIRType_None), + resultType_(MIRType::None), resultTypeSet_(nullptr), - dependency_(nullptr), + loadDependency_(nullptr), trackedSite_(nullptr) { } @@ -480,7 +506,7 @@ class MDefinition : public MNode range_(other.range_), resultType_(other.resultType_), resultTypeSet_(other.resultTypeSet_), - dependency_(other.dependency_), + loadDependency_(other.loadDependency_), trackedSite_(other.trackedSite_) { } @@ -555,11 +581,11 @@ class MDefinition : public MNode // errors. Instead, one should define the collectRangeInfoPreTrunc() to set // the right set of flags which are dependent on the range of the inputs. Range* range() const { - MOZ_ASSERT(type() != MIRType_None); + MOZ_ASSERT(type() != MIRType::None); return range_; } void setRange(Range* range) { - MOZ_ASSERT(type() != MIRType_None); + MOZ_ASSERT(type() != MIRType::None); range_ = range; } @@ -680,7 +706,7 @@ class MDefinition : public MNode // // Unless this is an MUrsh that has bailouts disabled, which, as a special // case, may return a value in (INT32_MAX,UINT32_MAX] even when its type() - // is MIRType_Int32. + // is MIRType::Int32. MIRType type() const { return resultType_; } @@ -691,16 +717,16 @@ class MDefinition : public MNode bool emptyResultTypeSet() const; bool mightBeType(MIRType type) const { - MOZ_ASSERT(type != MIRType_Value); - MOZ_ASSERT(type != MIRType_ObjectOrNull); + MOZ_ASSERT(type != MIRType::Value); + MOZ_ASSERT(type != MIRType::ObjectOrNull); if (type == this->type()) return true; - if (this->type() == MIRType_ObjectOrNull) - return type == MIRType_Object || type == MIRType_Null; + if (this->type() == MIRType::ObjectOrNull) + return type == MIRType::Object || type == MIRType::Null; - if (this->type() == MIRType_Value) + if (this->type() == MIRType::Value) return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type); return false; @@ -719,7 +745,7 @@ class MDefinition : public MNode #ifdef DEBUG // Used during the pass that checks that Float32 flow into valid MDefinitions virtual bool isConsistentFloat32Use(MUse* use) const { - return type() == MIRType_Float32 || canConsumeFloat32(use); + return type() == MIRType::Float32 || canConsumeFloat32(use); } #endif @@ -869,17 +895,28 @@ class MDefinition : public MNode void setResultTypeSet(TemporaryTypeSet* types) { resultTypeSet_ = types; } - - MInstruction* dependency() const { - return dependency_; - } - void setDependency(MInstruction* dependency) { - dependency_ = dependency; - } virtual AliasSet getAliasSet() const { // Instructions are effectful by default. return AliasSet::Store(AliasSet::Any); } + + MDefinition* dependency() const { + if (getAliasSet().isStore()) + return nullptr; + return loadDependency_; + } + void setDependency(MDefinition* dependency) { + MOZ_ASSERT(!getAliasSet().isStore()); + loadDependency_ = dependency; + } + void setStoreDependency(StoreDependency* dependency) { + MOZ_ASSERT(getAliasSet().isStore()); + storeDependency_ = dependency; + } + StoreDependency* storeDependency() { + MOZ_ASSERT_IF(!getAliasSet().isStore(), !storeDependency_); + return storeDependency_; + } bool isEffectful() const { return getAliasSet().isStore(); } @@ -890,13 +927,20 @@ class MDefinition : public MNode return isEffectful(); } #endif - virtual bool mightAlias(const MDefinition* store) const { + + enum class AliasType : uint32_t { + NoAlias = 0, + MayAlias = 1, + MustAlias = 2 + }; + virtual AliasType mightAlias(const MDefinition* store) const { // Return whether this load may depend on the specified store, given // that the alias sets intersect. This may be refined to exclude // possible aliasing in cases where alias set flags are too imprecise. + if (!(getAliasSet().flags() & store->getAliasSet().flags())) + return AliasType::NoAlias; MOZ_ASSERT(!isEffectful() && store->isEffectful()); - MOZ_ASSERT(getAliasSet().flags() & store->getAliasSet().flags()); - return true; + return AliasType::MayAlias; } virtual bool canRecoverOnBailout() const { @@ -949,9 +993,6 @@ class MUseDefIterator } }; -typedef Vector MDefinitionVector; -typedef Vector MInstructionVector; - // An instruction is an SSA name that is inserted into a basic block's IR // stream. class MInstruction @@ -975,7 +1016,7 @@ class MInstruction // if the types are match, and boxing the value if they do not match. // // Note: There is no need for such function in AsmJS functions as they do - // not use any MIRType_Value. + // not use any MIRType::Value. MDefinition* foldsToStoredValue(TempAllocator& alloc, MDefinition* loaded); void setResumePoint(MResumePoint* resumePoint); @@ -1221,7 +1262,7 @@ class MVariadicT : public T FixedList operands_; protected: - MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc, size_t length) { + MOZ_MUST_USE bool init(TempAllocator& alloc, size_t length) { return operands_.init(alloc, length); } void initOperand(size_t index, MDefinition* operand) { @@ -1272,7 +1313,7 @@ class MOsrEntry : public MNullaryInstruction { protected: MOsrEntry() { - setResultType(MIRType_Pointer); + setResultType(MIRType::Pointer); } public: @@ -1319,7 +1360,7 @@ class MLimitedTruncate truncate_(NoTruncate), truncateLimit_(limit) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setResultTypeSet(input->resultTypeSet()); setMovable(); } @@ -1390,7 +1431,7 @@ class MConstant : public MNullaryInstruction static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v); // Try to convert this constant to boolean, similar to js::ToBoolean. - // Returns false if the type is MIRType_Magic*. + // Returns false if the type is MIRType::Magic*. bool valueToBoolean(bool* res) const; // Like valueToBoolean, but returns the result directly instead of using @@ -1414,10 +1455,10 @@ class MConstant : public MNullaryInstruction MConstant* c = def->toConstant(); // During constant folding, we don't want to replace a float32 // value by a double value. - if (type() == MIRType_Float32) - return c->type() == MIRType_Float32; - if (type() == MIRType_Double) - return c->type() != MIRType_Float32; + if (type() == MIRType::Float32) + return c->type() == MIRType::Float32; + if (type() == MIRType::Double) + return c->type() != MIRType::Float32; return true; } @@ -1435,44 +1476,44 @@ class MConstant : public MNullaryInstruction } bool toBoolean() const { - MOZ_ASSERT(type() == MIRType_Boolean); + MOZ_ASSERT(type() == MIRType::Boolean); return payload_.b; } int32_t toInt32() const { - MOZ_ASSERT(type() == MIRType_Int32); + MOZ_ASSERT(type() == MIRType::Int32); return payload_.i32; } int64_t toInt64() const { - MOZ_ASSERT(type() == MIRType_Int64); + MOZ_ASSERT(type() == MIRType::Int64); return payload_.i64; } bool isInt32(int32_t i) const { - return type() == MIRType_Int32 && payload_.i32 == i; + return type() == MIRType::Int32 && payload_.i32 == i; } double toDouble() const { - MOZ_ASSERT(type() == MIRType_Double); + MOZ_ASSERT(type() == MIRType::Double); return payload_.d; } float toFloat32() const { - MOZ_ASSERT(type() == MIRType_Float32); + MOZ_ASSERT(type() == MIRType::Float32); return payload_.f; } JSString* toString() const { - MOZ_ASSERT(type() == MIRType_String); + MOZ_ASSERT(type() == MIRType::String); return payload_.str; } JS::Symbol* toSymbol() const { - MOZ_ASSERT(type() == MIRType_Symbol); + MOZ_ASSERT(type() == MIRType::Symbol); return payload_.sym; } JSObject& toObject() const { - MOZ_ASSERT(type() == MIRType_Object); + MOZ_ASSERT(type() == MIRType::Object); return *payload_.obj; } JSObject* toObjectOrNull() const { - if (type() == MIRType_Object) + if (type() == MIRType::Object) return payload_.obj; - MOZ_ASSERT(type() == MIRType_Null); + MOZ_ASSERT(type() == MIRType::Null); return nullptr; } @@ -1481,9 +1522,9 @@ class MConstant : public MNullaryInstruction } double numberToDouble() const { MOZ_ASSERT(isTypeRepresentableAsDouble()); - if (type() == MIRType_Int32) + if (type() == MIRType::Int32) return toInt32(); - if (type() == MIRType_Double) + if (type() == MIRType::Double) return toDouble(); return toFloat32(); } @@ -1521,7 +1562,7 @@ class MSimdValueX4 } bool canConsumeFloat32(MUse* use) const override { - return SimdTypeToLaneType(type()) == MIRType_Float32; + return SimdTypeToLaneType(type()) == MIRType::Float32; } AliasSet getAliasSet() const override { @@ -1560,7 +1601,7 @@ class MSimdSplatX4 } bool canConsumeFloat32(MUse* use) const override { - return SimdTypeToLaneType(type()) == MIRType_Float32; + return SimdTypeToLaneType(type()) == MIRType::Float32; } AliasSet getAliasSet() const override { @@ -1733,13 +1774,13 @@ class MSimdExtractElement // Allow extracting boolean lanes directly into an Int32 (for asm.js). // Allow extracting Uint32 lanes into a double. // - // We also allow extracting Uint32 lanes into a MIRType_Int32. This is + // We also allow extracting Uint32 lanes into a MIRType::Int32. This is // equivalent to extracting the Uint32 lane to a double and then // applying MTruncateToInt32, but it bypasses the conversion to/from // double. MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType || - (IsBooleanSimdType(vecType) && laneType == MIRType_Int32) || - (vecType == MIRType_Int32x4 && laneType == MIRType_Double && + (IsBooleanSimdType(vecType) && laneType == MIRType::Int32) || + (vecType == MIRType::Int32x4 && laneType == MIRType::Double && sign == SimdSign::Unsigned)); setMovable(); @@ -1825,7 +1866,7 @@ class MSimdInsertElement } bool canConsumeFloat32(MUse* use) const override { - return use == getUseFor(1) && SimdTypeToLaneType(type()) == MIRType_Float32; + return use == getUseFor(1) && SimdTypeToLaneType(type()) == MIRType::Float32; } AliasSet getAliasSet() const override { @@ -1852,7 +1893,7 @@ class MSimdAllTrue { MIRType simdType = obj->type(); MOZ_ASSERT(IsBooleanSimdType(simdType)); - MOZ_ASSERT(result == MIRType_Boolean || result == MIRType_Int32); + MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32); setResultType(result); specialization_ = simdType; setMovable(); @@ -1886,7 +1927,7 @@ class MSimdAnyTrue { MIRType simdType = obj->type(); MOZ_ASSERT(IsBooleanSimdType(simdType)); - MOZ_ASSERT(result == MIRType_Boolean || result == MIRType_Int32); + MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32); setResultType(result); specialization_ = simdType; setMovable(); @@ -2022,7 +2063,7 @@ class MSimdGeneralShuffle : return new(alloc) MSimdGeneralShuffle(numVectors, numLanes, type); } - MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc) { + MOZ_MUST_USE bool init(TempAllocator& alloc) { return MVariadicInstruction::init(alloc, numVectors_ + numLanes_); } void setVector(unsigned i, MDefinition* vec) { @@ -2157,7 +2198,7 @@ class MSimdUnaryArith { MIRType type = def->type(); MOZ_ASSERT(IsSimdType(type)); - MOZ_ASSERT_IF(type == MIRType_Int32x4, op == neg || op == not_); + MOZ_ASSERT_IF(type == MIRType::Int32x4, op == neg || op == not_); setResultType(type); setMovable(); } @@ -2222,7 +2263,7 @@ class MSimdBinaryComp MOZ_ASSERT(IsSimdType(opType)); MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(opType), "Signedness must be specified for integer SIMD compares"); - setResultType(MIRType_Bool32x4); + setResultType(MIRType::Bool32x4); specialization_ = opType; setMovable(); if (op == equal || op == notEqual) @@ -2312,7 +2353,7 @@ class MSimdBinaryArith { MOZ_ASSERT(left->type() == right->type()); MIRType type = left->type(); - MOZ_ASSERT_IF(type == MIRType_Int32x4, op == Op_add || op == Op_sub || op == Op_mul); + MOZ_ASSERT_IF(type == MIRType::Int32x4, op == Op_add || op == Op_sub || op == Op_mul); MOZ_ASSERT(IsSimdType(type)); setResultType(type); setMovable(); @@ -2516,7 +2557,7 @@ class MCloneLiteral explicit MCloneLiteral(MDefinition* obj) : MUnaryInstruction(obj) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -2534,7 +2575,7 @@ class MParameter : public MNullaryInstruction MParameter(int32_t index, TemporaryTypeSet* types) : index_(index) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setResultTypeSet(types); } @@ -2556,7 +2597,7 @@ class MCallee : public MNullaryInstruction public: MCallee() { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setMovable(); } @@ -2579,7 +2620,7 @@ class MIsConstructing : public MNullaryInstruction { public: MIsConstructing() { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); } @@ -2666,7 +2707,7 @@ class MTableSwitch final return successors_.length(); } - MOZ_WARN_UNUSED_RESULT bool addSuccessor(MBasicBlock* successor, size_t* index) { + MOZ_MUST_USE bool addSuccessor(MBasicBlock* successor, size_t* index) { MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2)); MOZ_ASSERT(!successors_.empty()); *index = successors_.length(); @@ -2711,14 +2752,14 @@ class MTableSwitch final return high() - low() + 1; } - MOZ_WARN_UNUSED_RESULT bool addDefault(MBasicBlock* block, size_t* index = nullptr) { + MOZ_MUST_USE bool addDefault(MBasicBlock* block, size_t* index = nullptr) { MOZ_ASSERT(successors_.empty()); if (index) *index = 0; return successors_.append(block); } - MOZ_WARN_UNUSED_RESULT bool addCase(size_t successorIndex) { + MOZ_MUST_USE bool addCase(size_t successorIndex) { return cases_.append(successorIndex); } @@ -2727,7 +2768,7 @@ class MTableSwitch final return blocks_[i]; } - MOZ_WARN_UNUSED_RESULT bool addBlock(MBasicBlock* block) { + MOZ_MUST_USE bool addBlock(MBasicBlock* block) { return blocks_.append(block); } @@ -3120,7 +3161,7 @@ class MNewArrayCopyOnWrite : public MNullaryInstruction initialHeap_(initialHeap) { MOZ_ASSERT(!templateObject->isSingleton()); - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); } @@ -3162,7 +3203,7 @@ class MNewArrayDynamicLength initialHeap_(initialHeap) { setGuard(); // Need to throw if length is negative. - setResultType(MIRType_Object); + setResultType(MIRType::Object); if (!templateObject->isSingleton()) setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); } @@ -3210,7 +3251,7 @@ class MNewObject mode_(mode) { MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject()); - setResultType(MIRType_Object); + setResultType(MIRType::Object); if (JSObject* obj = templateObject()) setResultTypeSet(MakeSingletonTypeSet(constraints, obj)); @@ -3220,7 +3261,7 @@ class MNewObject // making it emittedAtUses, we do not produce register allocations for // it and inline its content inside the code produced by the // CodeGenerator. - if (templateConst->toConstant()->type() == MIRType_Object) + if (templateConst->toConstant()->type() == MIRType::Object) templateConst->setEmittedAtUses(); } @@ -3265,7 +3306,7 @@ class MNewTypedObject : public MNullaryInstruction : templateObject_(templateObject), initialHeap_(initialHeap) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); } @@ -3301,7 +3342,7 @@ class MTypedObjectDescr explicit MTypedObjectDescr(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setMovable(); } @@ -3347,7 +3388,7 @@ class MSimdBox { MOZ_ASSERT(IsSimdType(op->type())); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); if (constraints) setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); } @@ -3472,7 +3513,7 @@ class MNewDerivedTypedObject prediction_(prediction) { setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -3630,7 +3671,7 @@ class MArrayState explicit MArrayState(MDefinition* arr); - MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* len); + MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* len); void initElement(uint32_t index, MDefinition* def) { initOperand(index + 2, def); @@ -3682,7 +3723,7 @@ class MMutateProto { initOperand(0, obj); initOperand(1, value); - setResultType(MIRType_None); + setResultType(MIRType::None); } public: @@ -3718,7 +3759,7 @@ class MInitProp { initOperand(0, obj); initOperand(1, value); - setResultType(MIRType_None); + setResultType(MIRType::None); } public: @@ -3786,7 +3827,7 @@ class MInitElem initOperand(0, obj); initOperand(1, id); initOperand(2, value); - setResultType(MIRType_None); + setResultType(MIRType::None); } public: @@ -3868,7 +3909,7 @@ class MCall construct_(construct), needsArgCheck_(true) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -4037,7 +4078,7 @@ class MApplyArgs initOperand(0, fun); initOperand(1, argc); initOperand(2, self); - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -4080,7 +4121,7 @@ class MApplyArray initOperand(0, fun); initOperand(1, elements); initOperand(2, self); - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -4189,7 +4230,7 @@ class MAssertRecoveredOnBailout MAssertRecoveredOnBailout(MDefinition* ins, bool mustBeRecovered) : MUnaryInstruction(ins), mustBeRecovered_(mustBeRecovered) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setRecoveredOnBailout(); setGuard(); } @@ -4245,7 +4286,7 @@ class MGetDynamicName { initOperand(0, scopeChain); initOperand(1, name); - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -4281,7 +4322,7 @@ class MCallDirectEval initOperand(0, scopeChain); initOperand(1, string); initOperand(2, newTargetValue); - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -4404,7 +4445,7 @@ class MCompare operandsAreNeverNaN_(false), truncateOperands_(false) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); } @@ -4510,11 +4551,11 @@ class MBox MBox(TempAllocator& alloc, MDefinition* ins) : MUnaryInstruction(ins) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); if (ins->resultTypeSet()) { setResultTypeSet(ins->resultTypeSet()); - } else if (ins->type() != MIRType_Value) { - TypeSet::Type ntype = ins->type() == MIRType_Object + } else if (ins->type() != MIRType::Value) { + TypeSet::Type ntype = ins->type() == MIRType::Object ? TypeSet::AnyObjectType() : TypeSet::PrimitiveType(ValueTypeFromMIRType(ins->type())); setResultTypeSet(alloc.lifoAlloc()->new_(alloc.lifoAlloc(), ntype)); @@ -4527,7 +4568,7 @@ class MBox static MBox* New(TempAllocator& alloc, MDefinition* ins) { // Cannot box a box. - MOZ_ASSERT(ins->type() != MIRType_Value); + MOZ_ASSERT(ins->type() != MIRType::Value); return new(alloc) MBox(alloc, ins); } @@ -4572,20 +4613,20 @@ class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data : MUnaryInstruction(ins), mode_(mode) { - // Only allow unboxing a non MIRType_Value when input and output types + // Only allow unboxing a non MIRType::Value when input and output types // don't match. This is often used to force a bailout. Boxing happens // during type analysis. - MOZ_ASSERT_IF(ins->type() != MIRType_Value, type != ins->type()); + MOZ_ASSERT_IF(ins->type() != MIRType::Value, type != ins->type()); - MOZ_ASSERT(type == MIRType_Boolean || - type == MIRType_Int32 || - type == MIRType_Double || - type == MIRType_String || - type == MIRType_Symbol || - type == MIRType_Object); + MOZ_ASSERT(type == MIRType::Boolean || + type == MIRType::Int32 || + type == MIRType::Double || + type == MIRType::String || + type == MIRType::Symbol || + type == MIRType::Object); TemporaryTypeSet* resultSet = ins->resultTypeSet(); - if (resultSet && type == MIRType_Object) + if (resultSet && type == MIRType::Object) resultSet = resultSet->cloneObjectsOnly(alloc.lifoAlloc()); setResultType(type); @@ -4605,22 +4646,22 @@ class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data // the type we expect. BailoutKind kind; switch (type) { - case MIRType_Boolean: + case MIRType::Boolean: kind = Bailout_NonBooleanInput; break; - case MIRType_Int32: + case MIRType::Int32: kind = Bailout_NonInt32Input; break; - case MIRType_Double: + case MIRType::Double: kind = Bailout_NonNumericInput; // Int32s are fine too break; - case MIRType_String: + case MIRType::String: kind = Bailout_NonStringInput; break; - case MIRType_Symbol: + case MIRType::Symbol: kind = Bailout_NonSymbolInput; break; - case MIRType_Object: + case MIRType::Object: kind = Bailout_NonObjectInput; break; default: @@ -4677,7 +4718,7 @@ class MGuardObject { setGuard(); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(ins->resultTypeSet()); } @@ -4701,7 +4742,7 @@ class MGuardString { setGuard(); setMovable(); - setResultType(MIRType_String); + setResultType(MIRType::String); } public: @@ -4724,7 +4765,7 @@ class MPolyInlineGuard : MUnaryInstruction(ins) { setGuard(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(ins->resultTypeSet()); } @@ -4752,7 +4793,7 @@ class MAssertRange : MUnaryInstruction(ins), assertedRange_(assertedRange) { setGuard(); - setResultType(MIRType_None); + setResultType(MIRType::None); } public: @@ -4786,7 +4827,7 @@ class MCreateThisWithTemplate : MUnaryInstruction(templateConst), initialHeap_(initialHeap) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject())); } @@ -4825,7 +4866,7 @@ class MCreateThisWithProto MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype) : MTernaryInstruction(callee, newTarget, prototype) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -4864,7 +4905,7 @@ class MCreateThis explicit MCreateThis(MDefinition* callee, MDefinition* newTarget) : MBinaryInstruction(callee, newTarget) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -4898,7 +4939,7 @@ class MCreateArgumentsObject explicit MCreateArgumentsObject(MDefinition* callObj) : MUnaryInstruction(callObj) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setGuard(); } @@ -4931,7 +4972,7 @@ class MGetArgumentsObjectArg : MUnaryInstruction(argsObject), argno_(argno) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -5011,7 +5052,7 @@ class MRunOncePrologue } }; -// Given a MIRType_Value A and a MIRType_Object B: +// Given a MIRType::Value A and a MIRType::Object B: // If the Value may be safely unboxed to an Object, return Object(A). // Otherwise, return B. // Used to implement return behavior for inlined constructors. @@ -5022,7 +5063,7 @@ class MReturnFromCtor MReturnFromCtor(MDefinition* value, MDefinition* object) { initOperand(0, value); initOperand(1, object); - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -5081,12 +5122,12 @@ class MToDouble explicit MToDouble(MDefinition* def, ConversionKind conversion = NonStringPrimitives) : MToFPInstruction(def, conversion), implicitTruncate_(NoTruncate) { - setResultType(MIRType_Double); + setResultType(MIRType::Double); setMovable(); // An object might have "valueOf", which means it is effectful. // ToNumber(symbol) throws. - if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol)) + if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol)) setGuard(); } @@ -5129,9 +5170,9 @@ class MToDouble bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - if (input()->type() == MIRType_Value) + if (input()->type() == MIRType::Value) return false; - if (input()->type() == MIRType_Symbol) + if (input()->type() == MIRType::Symbol) return false; return true; @@ -5149,12 +5190,12 @@ class MToFloat32 MToFloat32(MDefinition* def, ConversionKind conversion) : MToFPInstruction(def, conversion) { - setResultType(MIRType_Float32); + setResultType(MIRType::Float32); setMovable(); // An object might have "valueOf", which means it is effectful. // ToNumber(symbol) throws. - if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol)) + if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol)) setGuard(); } @@ -5200,7 +5241,7 @@ class MAsmJSUnsignedToDouble explicit MAsmJSUnsignedToDouble(MDefinition* def) : MUnaryInstruction(def) { - setResultType(MIRType_Double); + setResultType(MIRType::Double); setMovable(); } @@ -5227,7 +5268,7 @@ class MAsmJSUnsignedToFloat32 explicit MAsmJSUnsignedToFloat32(MDefinition* def) : MUnaryInstruction(def) { - setResultType(MIRType_Float32); + setResultType(MIRType::Float32); setMovable(); } @@ -5255,7 +5296,7 @@ class MWrapInt64ToInt32 explicit MWrapInt64ToInt32(MDefinition* def) : MUnaryInstruction(def) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } @@ -5284,7 +5325,7 @@ class MExtendInt32ToInt64 : MUnaryInstruction(def), isUnsigned_(isUnsigned) { - setResultType(MIRType_Int64); + setResultType(MIRType::Int64); setMovable(); } @@ -5309,40 +5350,75 @@ class MExtendInt32ToInt64 } }; -class MTruncateToInt64 +class MWasmTruncateToInt64 : public MUnaryInstruction, public NoTypePolicy::Data { bool isUnsigned_; - MTruncateToInt64(MDefinition* def, bool isUnsigned) + MWasmTruncateToInt64(MDefinition* def, bool isUnsigned) : MUnaryInstruction(def), isUnsigned_(isUnsigned) { - setResultType(MIRType_Int64); + setResultType(MIRType::Int64); setMovable(); } public: - INSTRUCTION_HEADER(TruncateToInt64) - static MTruncateToInt64* NewAsmJS(TempAllocator& alloc, MDefinition* def, bool isUnsigned) { - return new(alloc) MTruncateToInt64(def, isUnsigned); + INSTRUCTION_HEADER(WasmTruncateToInt64) + static MWasmTruncateToInt64* NewAsmJS(TempAllocator& alloc, MDefinition* def, bool isUnsigned) { + return new(alloc) MWasmTruncateToInt64(def, isUnsigned); } bool isUnsigned() const { return isUnsigned_; } bool congruentTo(const MDefinition* ins) const override { - if (!ins->isTruncateToInt64()) - return false; - if (ins->toTruncateToInt64()->isUnsigned_ != isUnsigned_) - return false; - return congruentIfOperandsEqual(ins); + return congruentIfOperandsEqual(ins) && + ins->toWasmTruncateToInt64()->isUnsigned() == isUnsigned_; } AliasSet getAliasSet() const override { return AliasSet::None(); } }; +// Truncate a value to an int32, with wasm semantics: this will trap when the +// value is out of range. +class MWasmTruncateToInt32 + : public MUnaryInstruction, + public NoTypePolicy::Data +{ + bool isUnsigned_; + + explicit MWasmTruncateToInt32(MDefinition* def, bool isUnsigned) + : MUnaryInstruction(def), isUnsigned_(isUnsigned) + { + setResultType(MIRType::Int32); + setMovable(); + } + + public: + INSTRUCTION_HEADER(WasmTruncateToInt32) + + static MWasmTruncateToInt32* NewAsmJS(TempAllocator& alloc, MDefinition* def, bool isUnsigned) { + return new(alloc) MWasmTruncateToInt32(def, isUnsigned); + } + + bool isUnsigned() const { + return isUnsigned_; + } + + MDefinition* foldsTo(TempAllocator& alloc) override; + + bool congruentTo(const MDefinition* ins) const override { + return congruentIfOperandsEqual(ins) && + ins->toWasmTruncateToInt32()->isUnsigned() == isUnsigned_; + } + + AliasSet getAliasSet() const override { + return AliasSet::None(); + } +}; + class MInt64ToFloatingPoint : public MUnaryInstruction, public NoTypePolicy::Data @@ -5395,12 +5471,12 @@ class MToInt32 canBeNegativeZero_(true), conversion_(conversion) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); // An object might have "valueOf", which means it is effectful. // ToNumber(symbol) throws. - if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol)) + if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol)) setGuard(); } @@ -5457,12 +5533,12 @@ class MTruncateToInt32 explicit MTruncateToInt32(MDefinition* def) : MUnaryInstruction(def) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); // An object might have "valueOf", which means it is effectful. // ToInt32(symbol) throws. - if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol)) + if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol)) setGuard(); } @@ -5471,7 +5547,7 @@ class MTruncateToInt32 static MTruncateToInt32* New(TempAllocator& alloc, MDefinition* def) { return new(alloc) MTruncateToInt32(def); } - static MTruncateToInt32* NewAsmJS(TempAllocator& alloc, MDefinition* def) { + static MTruncateToInt32* NewAsmJS(TempAllocator& alloc, MDefinition* def, bool _) { return new(alloc) MTruncateToInt32(def); } @@ -5494,7 +5570,7 @@ class MTruncateToInt32 bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return input()->type() < MIRType_Symbol; + return input()->type() < MIRType::Symbol; } ALLOW_CLONE(MTruncateToInt32) @@ -5508,11 +5584,11 @@ class MToString : explicit MToString(MDefinition* def) : MUnaryInstruction(def) { - setResultType(MIRType_String); + setResultType(MIRType::String); setMovable(); // Objects might override toString and Symbols throw. - if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol)) + if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol)) setGuard(); } @@ -5534,7 +5610,7 @@ class MToString : } bool fallible() const { - return input()->mightBeType(MIRType_Object); + return input()->mightBeType(MIRType::Object); } ALLOW_CLONE(MToString) @@ -5548,7 +5624,7 @@ class MToObjectOrNull : explicit MToObjectOrNull(MDefinition* def) : MUnaryInstruction(def) { - setResultType(MIRType_ObjectOrNull); + setResultType(MIRType::ObjectOrNull); setMovable(); } @@ -5578,8 +5654,8 @@ class MBitNot explicit MBitNot(MDefinition* input) : MUnaryInstruction(input) { - specialization_ = MIRType_None; - setResultType(MIRType_Int32); + specialization_ = MIRType::None; + setResultType(MIRType::Int32); setMovable(); } @@ -5598,7 +5674,7 @@ class MBitNot return congruentIfOperandsEqual(ins); } AliasSet getAliasSet() const override { - if (specialization_ == MIRType_None) + if (specialization_ == MIRType::None) return AliasSet::Store(AliasSet::Any); return AliasSet::None(); } @@ -5606,7 +5682,7 @@ class MBitNot bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ != MIRType_None; + return specialization_ != MIRType::None; } ALLOW_CLONE(MBitNot) @@ -5623,7 +5699,7 @@ class MTypeOf : MUnaryInstruction(def), inputType_(inputType), inputMaybeCallableOrEmulatesUndefined_(true) { - setResultType(MIRType_String); + setResultType(MIRType::String); setMovable(); } @@ -5678,7 +5754,7 @@ class MToId explicit MToId(MDefinition* index) : MUnaryInstruction(index) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -5698,7 +5774,7 @@ class MBinaryBitwiseInstruction : MBinaryInstruction(left, right), maskMatchesLeftRange(false), maskMatchesRightRange(false) { - MOZ_ASSERT(type == MIRType_Int32 || type == MIRType_Int64); + MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64); setResultType(type); setMovable(); } @@ -5718,15 +5794,15 @@ class MBinaryBitwiseInstruction void collectRangeInfoPreTrunc() override; void setInt32Specialization() { - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); } bool congruentTo(const MDefinition* ins) const override { return binaryCongruentTo(ins); } AliasSet getAliasSet() const override { - if (specialization_ >= MIRType_Object) + if (specialization_ >= MIRType::Object) return AliasSet::Store(AliasSet::Any); return AliasSet::None(); } @@ -5763,7 +5839,7 @@ class MBitAnd : public MBinaryBitwiseInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ != MIRType_None; + return specialization_ != MIRType::None; } ALLOW_CLONE(MBitAnd) @@ -5796,7 +5872,7 @@ class MBitOr : public MBinaryBitwiseInstruction void computeRange(TempAllocator& alloc) override; bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ != MIRType_None; + return specialization_ != MIRType::None; } ALLOW_CLONE(MBitOr) @@ -5830,7 +5906,7 @@ class MBitXor : public MBinaryBitwiseInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ < MIRType_Object; + return specialization_ < MIRType::Object; } ALLOW_CLONE(MBitXor) @@ -5878,7 +5954,7 @@ class MLsh : public MShiftInstruction void computeRange(TempAllocator& alloc) override; bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ != MIRType_None; + return specialization_ != MIRType::None; } ALLOW_CLONE(MLsh) @@ -5905,7 +5981,7 @@ class MRsh : public MShiftInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ < MIRType_Object; + return specialization_ < MIRType::Object; } ALLOW_CLONE(MRsh) @@ -5947,7 +6023,7 @@ class MUrsh : public MShiftInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ < MIRType_Object; + return specialization_ < MIRType::Object; } ALLOW_CLONE(MUrsh) @@ -5972,7 +6048,7 @@ class MBinaryArithInstruction : MBinaryInstruction(left, right), implicitTruncate_(NoTruncate) { - specialization_ = MIRType_None; + specialization_ = MIRType::None; setMovable(); } @@ -5990,8 +6066,8 @@ class MBinaryArithInstruction setResultType(type); } void setInt32Specialization() { - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); } void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc); @@ -6001,7 +6077,7 @@ class MBinaryArithInstruction return binaryCongruentTo(ins); } AliasSet getAliasSet() const override { - if (specialization_ >= MIRType_Object) + if (specialization_ >= MIRType::Object) return AliasSet::Store(AliasSet::Any); return AliasSet::None(); } @@ -6092,7 +6168,7 @@ class MAbs } static MAbs* NewAsmJS(TempAllocator& alloc, MDefinition* num, MIRType type) { MAbs* ins = new(alloc) MAbs(num, type); - if (type == MIRType_Int32) + if (type == MIRType::Int32) ins->implicitTruncate_ = true; return ins; } @@ -6127,8 +6203,8 @@ class MClz operandIsNeverZero_(false) { MOZ_ASSERT(IsNumberType(num->type())); - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); setMovable(); } @@ -6171,8 +6247,8 @@ class MCtz operandIsNeverZero_(false) { MOZ_ASSERT(IsNumberType(num->type())); - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); setMovable(); } @@ -6212,8 +6288,8 @@ class MPopcnt : MUnaryInstruction(num) { MOZ_ASSERT(IsNumberType(num->type())); - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); setMovable(); } @@ -6256,7 +6332,7 @@ class MSqrt public: INSTRUCTION_HEADER(Sqrt) static MSqrt* New(TempAllocator& alloc, MDefinition* num) { - return new(alloc) MSqrt(num, MIRType_Double); + return new(alloc) MSqrt(num, MIRType::Double); } static MSqrt* NewAsmJS(TempAllocator& alloc, MDefinition* num, MIRType type) { MOZ_ASSERT(IsFloatingPointType(type)); @@ -6290,7 +6366,7 @@ class MAtan2 MAtan2(MDefinition* y, MDefinition* x) : MBinaryInstruction(y, x) { - setResultType(MIRType_Double); + setResultType(MIRType::Double); setMovable(); } @@ -6335,7 +6411,7 @@ class MHypot { MHypot() { - setResultType(MIRType_Double); + setResultType(MIRType::Double); setMovable(); } @@ -6379,7 +6455,7 @@ class MPow : MBinaryInstruction(input, power) { specialization_ = powerType; - setResultType(MIRType_Double); + setResultType(MIRType::Double); setMovable(); } @@ -6388,7 +6464,7 @@ class MPow static MPow* New(TempAllocator& alloc, MDefinition* input, MDefinition* power, MIRType powerType) { - MOZ_ASSERT(powerType == MIRType_Double || powerType == MIRType_Int32); + MOZ_ASSERT(powerType == MIRType::Double || powerType == MIRType::Int32); return new(alloc) MPow(input, power, powerType); } @@ -6433,7 +6509,7 @@ class MPowHalf operandIsNeverNegativeZero_(false), operandIsNeverNaN_(false) { - setResultType(MIRType_Double); + setResultType(MIRType::Double); setMovable(); } @@ -6471,7 +6547,7 @@ class MRandom : public MNullaryInstruction { MRandom() { - setResultType(MIRType_Double); + setResultType(MIRType::Double); } public: @@ -6532,8 +6608,8 @@ class MMathFunction MMathFunction(MDefinition* input, Function function, const MathCache* cache) : MUnaryInstruction(input), function_(function), cache_(cache) { - setResultType(MIRType_Double); - specialization_ = MIRType_Double; + setResultType(MIRType::Double); + specialization_ = MIRType::Double; setMovable(); } @@ -6581,7 +6657,7 @@ class MMathFunction void computeRange(TempAllocator& alloc) override; bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - if (input()->type() == MIRType_SinCosDouble) + if (input()->type() == MIRType::SinCosDouble) return false; switch(function_) { case Sin: @@ -6602,7 +6678,7 @@ class MAdd : public MBinaryArithInstruction MAdd(MDefinition* left, MDefinition* right) : MBinaryArithInstruction(left, right) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -6617,7 +6693,7 @@ class MAdd : public MBinaryArithInstruction MAdd* add = new(alloc) MAdd(left, right); add->specialization_ = type; add->setResultType(type); - if (type == MIRType_Int32) { + if (type == MIRType::Int32) { add->setTruncateKind(Truncate); add->setCommutative(); } @@ -6638,7 +6714,7 @@ class MAdd : public MBinaryArithInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ < MIRType_Object; + return specialization_ < MIRType::Object; } ALLOW_CLONE(MAdd) @@ -6649,7 +6725,7 @@ class MSub : public MBinaryArithInstruction MSub(MDefinition* left, MDefinition* right) : MBinaryArithInstruction(left, right) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -6663,7 +6739,7 @@ class MSub : public MBinaryArithInstruction MSub* sub = new(alloc) MSub(left, right); sub->specialization_ = type; sub->setResultType(type); - if (type == MIRType_Int32) + if (type == MIRType::Int32) sub->setTruncateKind(Truncate); return sub; } @@ -6682,7 +6758,7 @@ class MSub : public MBinaryArithInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ < MIRType_Object; + return specialization_ < MIRType::Object; } ALLOW_CLONE(MSub) @@ -6717,7 +6793,7 @@ class MMul : public MBinaryArithInstruction } MOZ_ASSERT_IF(mode != Integer, mode == Normal); - if (type != MIRType_Value) + if (type != MIRType::Value) specialization_ = type; setResultType(type); } @@ -6725,7 +6801,7 @@ class MMul : public MBinaryArithInstruction public: INSTRUCTION_HEADER(Mul) static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MMul(left, right, MIRType_Value, MMul::Normal); + return new(alloc) MMul(left, right, MIRType::Value, MMul::Normal); } static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type, Mode mode = Normal) @@ -6786,7 +6862,7 @@ class MMul : public MBinaryArithInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ < MIRType_Object; + return specialization_ < MIRType::Object; } ALLOW_CLONE(MMul) @@ -6808,7 +6884,7 @@ class MDiv : public MBinaryArithInstruction canBeNegativeDividend_(true), unsigned_(false) { - if (type != MIRType_Value) + if (type != MIRType::Value) specialization_ = type; setResultType(type); } @@ -6816,7 +6892,7 @@ class MDiv : public MBinaryArithInstruction public: INSTRUCTION_HEADER(Div) static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MDiv(left, right, MIRType_Value); + return new(alloc) MDiv(left, right, MIRType::Value); } static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type) { return new(alloc) MDiv(left, right, type); @@ -6826,7 +6902,7 @@ class MDiv : public MBinaryArithInstruction { MDiv* div = new(alloc) MDiv(left, right, type); div->unsigned_ = unsignd; - if (type == MIRType_Int32) + if (type == MIRType::Int32) div->setTruncateKind(Truncate); return div; } @@ -6900,7 +6976,7 @@ class MDiv : public MBinaryArithInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ < MIRType_Object; + return specialization_ < MIRType::Object; } bool congruentTo(const MDefinition* ins) const override { @@ -6925,7 +7001,7 @@ class MMod : public MBinaryArithInstruction canBePowerOfTwoDivisor_(true), canBeDivideByZero_(true) { - if (type != MIRType_Value) + if (type != MIRType::Value) specialization_ = type; setResultType(type); } @@ -6933,14 +7009,14 @@ class MMod : public MBinaryArithInstruction public: INSTRUCTION_HEADER(Mod) static MMod* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) { - return new(alloc) MMod(left, right, MIRType_Value); + return new(alloc) MMod(left, right, MIRType::Value); } static MMod* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type, bool unsignd) { MMod* mod = new(alloc) MMod(left, right, type); mod->unsigned_ = unsignd; - if (type == MIRType_Int32) + if (type == MIRType::Int32) mod->setTruncateKind(Truncate); return mod; } @@ -6952,18 +7028,18 @@ class MMod : public MBinaryArithInstruction } bool canBeNegativeDividend() const { - MOZ_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Int64); + MOZ_ASSERT(specialization_ == MIRType::Int32 || specialization_ == MIRType::Int64); MOZ_ASSERT(!unsigned_); return canBeNegativeDividend_; } bool canBeDivideByZero() const { - MOZ_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Int64); + MOZ_ASSERT(specialization_ == MIRType::Int32 || specialization_ == MIRType::Int64); return canBeDivideByZero_; } bool canBePowerOfTwoDivisor() const { - MOZ_ASSERT(specialization_ == MIRType_Int32); + MOZ_ASSERT(specialization_ == MIRType::Int32); return canBePowerOfTwoDivisor_; } @@ -6975,7 +7051,7 @@ class MMod : public MBinaryArithInstruction bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { - return specialization_ < MIRType_Object; + return specialization_ < MIRType::Object; } bool fallible() const; @@ -7002,10 +7078,10 @@ class MConcat : MBinaryInstruction(left, right) { // At least one input should be definitely string - MOZ_ASSERT(left->type() == MIRType_String || right->type() == MIRType_String); + MOZ_ASSERT(left->type() == MIRType::String || right->type() == MIRType::String); setMovable(); - setResultType(MIRType_String); + setResultType(MIRType::String); } public: @@ -7038,7 +7114,7 @@ class MCharCodeAt : MBinaryInstruction(str, index) { setMovable(); - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } public: @@ -7075,7 +7151,7 @@ class MFromCharCode : MUnaryInstruction(code) { setMovable(); - setResultType(MIRType_String); + setResultType(MIRType::String); } public: @@ -7108,8 +7184,8 @@ class MSinCos MSinCos(MDefinition *input, const MathCache *cache) : MUnaryInstruction(input), cache_(cache) { - setResultType(MIRType_SinCosDouble); - specialization_ = MIRType_Double; + setResultType(MIRType::SinCosDouble); + specialization_ = MIRType::Double; setMovable(); } @@ -7142,7 +7218,7 @@ class MStringSplit MConstant* templateObject) : MTernaryInstruction(string, sep, templateObject) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(templateObject->resultTypeSet()); } @@ -7190,7 +7266,7 @@ class MComputeThis explicit MComputeThis(MDefinition* def) : MUnaryInstruction(def) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -7215,7 +7291,7 @@ class MArrowNewTarget explicit MArrowNewTarget(MDefinition* callee) : MUnaryInstruction(callee) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setMovable(); } @@ -7289,7 +7365,7 @@ class MPhi final setResultType(resultType); } - static MPhi* New(TempAllocator& alloc, MIRType resultType = MIRType_Value) { + static MPhi* New(TempAllocator& alloc, MIRType resultType = MIRType::Value) { return new(alloc) MPhi(alloc, resultType); } @@ -7349,11 +7425,11 @@ class MPhi final // Add types for this phi which speculate about new inputs that may come in // via a loop backedge. - MOZ_WARN_UNUSED_RESULT bool addBackedgeType(MIRType type, TemporaryTypeSet* typeSet); + MOZ_MUST_USE bool addBackedgeType(MIRType type, TemporaryTypeSet* typeSet); // Initializes the operands vector to the given capacity, // permitting use of addInput() instead of addInputSlow(). - MOZ_WARN_UNUSED_RESULT bool reserveLength(size_t length) { + MOZ_MUST_USE bool reserveLength(size_t length) { return inputs_.reserve(length); } @@ -7364,7 +7440,7 @@ class MPhi final // Appends a new input to the input vector. May perform reallocation. // Prefer reserveLength() and addInput() instead, where possible. - MOZ_WARN_UNUSED_RESULT bool addInputSlow(MDefinition* ins) { + MOZ_MUST_USE bool addInputSlow(MDefinition* ins) { return inputs_.emplaceBack(ins, this); } @@ -7469,7 +7545,7 @@ class MOsrValue : MUnaryInstruction(entry), frameOffset_(frameOffset) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -7501,7 +7577,7 @@ class MOsrScopeChain explicit MOsrScopeChain(MOsrEntry* entry) : MUnaryInstruction(entry) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -7525,7 +7601,7 @@ class MOsrArgumentsObject explicit MOsrArgumentsObject(MOsrEntry* entry) : MUnaryInstruction(entry) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -7549,7 +7625,7 @@ class MOsrReturnValue explicit MOsrReturnValue(MOsrEntry* entry) : MUnaryInstruction(entry) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -7571,7 +7647,7 @@ class MBinarySharedStub explicit MBinarySharedStub(MDefinition* left, MDefinition* right) : MBinaryInstruction(left, right) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -7591,7 +7667,7 @@ class MUnarySharedStub explicit MUnarySharedStub(MDefinition* input) : MUnaryInstruction(input) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -7609,7 +7685,7 @@ class MNullarySharedStub explicit MNullarySharedStub() : MNullaryInstruction() { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -7694,7 +7770,7 @@ class MLexicalCheck : MUnaryInstruction(input), kind_(kind) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setResultTypeSet(input->resultTypeSet()); setMovable(); setGuard(); @@ -7734,7 +7810,7 @@ class MThrowRuntimeLexicalError : public MNullaryInstruction : errorNumber_(errorNumber) { setGuard(); - setResultType(MIRType_None); + setResultType(MIRType::None); } public: @@ -7873,7 +7949,7 @@ class MRegExp : public MNullaryInstruction : source_(source), mustClone_(mustClone) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(MakeSingletonTypeSet(constraints, source)); } @@ -7917,7 +7993,7 @@ class MRegExpMatcher setMovable(); // May be object or null. - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -7966,7 +8042,7 @@ class MRegExpSearcher initOperand(2, lastIndex); setMovable(); - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } public: @@ -8015,7 +8091,7 @@ class MRegExpTester initOperand(2, lastIndex); setMovable(); - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } public: @@ -8054,7 +8130,7 @@ class MRegExpPrototypeOptimizable explicit MRegExpPrototypeOptimizable(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); } public: @@ -8078,7 +8154,7 @@ class MRegExpInstanceOptimizable explicit MRegExpInstanceOptimizable(MDefinition* object, MDefinition* proto) : MBinaryInstruction(object, proto) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); } public: @@ -8099,6 +8175,33 @@ class MRegExpInstanceOptimizable } }; +class MGetFirstDollarIndex + : public MUnaryInstruction, + public StringPolicy<0>::Data +{ + explicit MGetFirstDollarIndex(MDefinition* str) + : MUnaryInstruction(str) + { + setResultType(MIRType::Int32); + setMovable(); + } + + public: + INSTRUCTION_HEADER(GetFirstDollarIndex) + + static MGetFirstDollarIndex* New(TempAllocator& alloc, MDefinition* str) { + return new(alloc) MGetFirstDollarIndex(str); + } + MDefinition* str() const { + return getOperand(0); + } + AliasSet getAliasSet() const override { + return AliasSet::None(); + } + + MDefinition* foldsTo(TempAllocator& alloc) override; +}; + class MStringReplace : public MTernaryInstruction, public Mix3Policy, StringPolicy<1>, StringPolicy<2> >::Data @@ -8111,7 +8214,7 @@ class MStringReplace : MTernaryInstruction(string, pattern, replacement), isFlatReplacement_(false) { setMovable(); - setResultType(MIRType_String); + setResultType(MIRType::String); } public: @@ -8175,7 +8278,7 @@ class MSubstr MSubstr(MDefinition* string, MDefinition* begin, MDefinition* length) : MTernaryInstruction(string, begin, length) { - setResultType(MIRType_String); + setResultType(MIRType::String); } public: @@ -8242,7 +8345,7 @@ class MLambda MLambda(CompilerConstraintList* constraints, MDefinition* scopeChain, MConstant* cst) : MBinaryInstruction(scopeChain, cst), info_(&cst->toObject().as()) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); if (!info().fun->isSingleton() && !ObjectGroup::useSingletonForClone(info().fun)) setResultTypeSet(MakeSingletonTypeSet(constraints, info().fun)); } @@ -8280,7 +8383,7 @@ class MLambdaArrow MDefinition* newTarget_, JSFunction* fun) : MBinaryInstruction(scopeChain, newTarget_), info_(fun) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); MOZ_ASSERT(!ObjectGroup::useSingletonForClone(fun)); if (!fun->isSingleton()) setResultTypeSet(MakeSingletonTypeSet(constraints, fun)); @@ -8313,7 +8416,7 @@ class MSlots explicit MSlots(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Slots); + setResultType(MIRType::Slots); setMovable(); } @@ -8347,7 +8450,7 @@ class MElements explicit MElements(MDefinition* object, bool unboxed) : MUnaryInstruction(object), unboxed_(unboxed) { - setResultType(MIRType_Elements); + setResultType(MIRType::Elements); setMovable(); } @@ -8371,7 +8474,7 @@ class MElements AliasSet getAliasSet() const override { return AliasSet::Load(AliasSet::ObjectFields); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; ALLOW_CLONE(MElements) }; @@ -8385,7 +8488,7 @@ class MConstantElements : public MNullaryInstruction explicit MConstantElements(SharedMem v) : value_(v) { - setResultType(MIRType_Elements); + setResultType(MIRType::Elements); setMovable(); } @@ -8426,7 +8529,7 @@ class MConvertElementsToDoubles { setGuard(); setMovable(); - setResultType(MIRType_Elements); + setResultType(MIRType::Elements); } public: @@ -8463,9 +8566,9 @@ class MMaybeToDoubleElement MMaybeToDoubleElement(MDefinition* elements, MDefinition* value) : MBinaryInstruction(elements, value) { - MOZ_ASSERT(elements->type() == MIRType_Elements); + MOZ_ASSERT(elements->type() == MIRType::Elements); setMovable(); - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -8503,7 +8606,7 @@ class MMaybeCopyElementsForWrite { setGuard(); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(object->resultTypeSet()); } @@ -8545,7 +8648,7 @@ class MInitializedLength explicit MInitializedLength(MDefinition* elements) : MUnaryInstruction(elements) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } @@ -8565,7 +8668,7 @@ class MInitializedLength AliasSet getAliasSet() const override { return AliasSet::Load(AliasSet::ObjectFields); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; void computeRange(TempAllocator& alloc) override; @@ -8611,7 +8714,7 @@ class MUnboxedArrayLength explicit MUnboxedArrayLength(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } @@ -8643,7 +8746,7 @@ class MUnboxedArrayInitializedLength explicit MUnboxedArrayInitializedLength(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } @@ -8663,7 +8766,7 @@ class MUnboxedArrayInitializedLength AliasSet getAliasSet() const override { return AliasSet::Load(AliasSet::ObjectFields); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; ALLOW_CLONE(MUnboxedArrayInitializedLength) }; @@ -8732,7 +8835,7 @@ class MArrayLength explicit MArrayLength(MDefinition* elements) : MUnaryInstruction(elements) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } @@ -8795,7 +8898,7 @@ class MGetNextMapEntryForIterator explicit MGetNextMapEntryForIterator(MDefinition* iter, MDefinition* result) : MBinaryInstruction(iter, result) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); } public: @@ -8823,7 +8926,7 @@ class MTypedArrayLength explicit MTypedArrayLength(MDefinition* obj) : MUnaryInstruction(obj) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } @@ -8855,7 +8958,7 @@ class MTypedArrayElements explicit MTypedArrayElements(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Elements); + setResultType(MIRType::Elements); setMovable(); } @@ -8887,10 +8990,10 @@ class MSetDisjointTypedElements MDefinition* source) : MTernaryInstruction(target, targetOffset, source) { - MOZ_ASSERT(target->type() == MIRType_Object); - MOZ_ASSERT(targetOffset->type() == MIRType_Int32); - MOZ_ASSERT(source->type() == MIRType_Object); - setResultType(MIRType_None); + MOZ_ASSERT(target->type() == MIRType::Object); + MOZ_ASSERT(targetOffset->type() == MIRType::Int32); + MOZ_ASSERT(source->type() == MIRType::Object); + setResultType(MIRType::None); } public: @@ -8936,7 +9039,7 @@ class MTypedObjectElements : MUnaryInstruction(object), definitelyOutline_(definitelyOutline) { - setResultType(MIRType_Elements); + setResultType(MIRType::Elements); setMovable(); } @@ -8976,9 +9079,9 @@ class MSetTypedObjectOffset MSetTypedObjectOffset(MDefinition* object, MDefinition* offset) : MBinaryInstruction(object, offset) { - MOZ_ASSERT(object->type() == MIRType_Object); - MOZ_ASSERT(offset->type() == MIRType_Int32); - setResultType(MIRType_None); + MOZ_ASSERT(object->type() == MIRType::Object); + MOZ_ASSERT(offset->type() == MIRType::Int32); + setResultType(MIRType::None); } public: @@ -9013,7 +9116,7 @@ class MKeepAliveObject explicit MKeepAliveObject(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_None); + setResultType(MIRType::None); setGuard(); } @@ -9042,7 +9145,7 @@ class MNot operandMightEmulateUndefined_(true), operandIsNeverNaN_(false) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); if (constraints) cacheOperandMightEmulateUndefined(constraints); @@ -9058,7 +9161,7 @@ class MNot } static MNot* NewAsmJS(TempAllocator& alloc, MDefinition* elements) { MNot* ins = new(alloc) MNot(elements); - ins->setResultType(MIRType_Int32); + ins->setResultType(MIRType::Int32); return ins; } @@ -9114,11 +9217,11 @@ class MBoundsCheck { setGuard(); setMovable(); - MOZ_ASSERT(index->type() == MIRType_Int32); - MOZ_ASSERT(length->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); + MOZ_ASSERT(length->type() == MIRType::Int32); // Returns the checked index. - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } public: @@ -9183,7 +9286,7 @@ class MBoundsCheckLower { setGuard(); setMovable(); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); } public: @@ -9218,8 +9321,8 @@ class MBoundsCheckLower static inline bool IsValidElementsType(MDefinition* elements, int32_t offsetAdjustment) { - return elements->type() == MIRType_Elements || - (elements->type() == MIRType_Object && offsetAdjustment != 0); + return elements->type() == MIRType::Elements || + (elements->type() == MIRType::Object && offsetAdjustment != 0); } // Load a value from a dense array's element vector and does a hole check if the @@ -9245,10 +9348,10 @@ class MLoadElement // have to invalidate when we read a hole. setGuard(); } - setResultType(MIRType_Value); + setResultType(MIRType::Value); setMovable(); MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment)); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); } public: @@ -9293,7 +9396,7 @@ class MLoadElement AliasSet getAliasSet() const override { return AliasSet::Load(AliasSet::Element); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; ALLOW_CLONE(MLoadElement) }; @@ -9318,7 +9421,7 @@ class MLoadElementHole needsNegativeIntCheck_(true), needsHoleCheck_(needsHoleCheck) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setMovable(); // Set the guard flag to make sure we bail when we see a negative @@ -9326,9 +9429,9 @@ class MLoadElementHole // collectRangeInfoPreTrunc. setGuard(); - MOZ_ASSERT(elements->type() == MIRType_Elements); - MOZ_ASSERT(index->type() == MIRType_Int32); - MOZ_ASSERT(initLength->type() == MIRType_Int32); + MOZ_ASSERT(elements->type() == MIRType::Elements); + MOZ_ASSERT(index->type() == MIRType::Int32); + MOZ_ASSERT(initLength->type() == MIRType::Int32); } public: @@ -9405,10 +9508,10 @@ class MLoadUnboxedObjectOrNull // same reason as MLoadElement. setGuard(); } - setResultType(nullBehavior == HandleNull ? MIRType_Value : MIRType_Object); + setResultType(nullBehavior == HandleNull ? MIRType::Value : MIRType::Object); setMovable(); MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment)); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); } public: @@ -9450,7 +9553,7 @@ class MLoadUnboxedObjectOrNull return AliasSet::Load(AliasSet::UnboxedElement); } MDefinition* foldsTo(TempAllocator& alloc) override; - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; ALLOW_CLONE(MLoadUnboxedObjectOrNull) }; @@ -9465,10 +9568,10 @@ class MLoadUnboxedString : MBinaryInstruction(elements, index), offsetAdjustment_(offsetAdjustment) { - setResultType(MIRType_String); + setResultType(MIRType::String); setMovable(); MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment)); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); } public: @@ -9500,7 +9603,7 @@ class MLoadUnboxedString AliasSet getAliasSet() const override { return AliasSet::Load(AliasSet::UnboxedElement); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; ALLOW_CLONE(MLoadUnboxedString) }; @@ -9512,7 +9615,7 @@ class MStoreElementCommon protected: MStoreElementCommon() - : elementType_(MIRType_Value), + : elementType_(MIRType::Value), needsBarrier_(false) { } @@ -9521,7 +9624,7 @@ class MStoreElementCommon return elementType_; } void setElementType(MIRType elementType) { - MOZ_ASSERT(elementType != MIRType_None); + MOZ_ASSERT(elementType != MIRType::None); elementType_ = elementType; } bool needsBarrier() const { @@ -9549,7 +9652,7 @@ class MStoreElement needsHoleCheck_ = needsHoleCheck; offsetAdjustment_ = offsetAdjustment; MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment)); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); } public: @@ -9604,8 +9707,8 @@ class MStoreElementHole initOperand(1, elements); initOperand(2, index); initOperand(3, value); - MOZ_ASSERT(elements->type() == MIRType_Elements); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(elements->type() == MIRType::Elements); + MOZ_ASSERT(index->type() == MIRType::Int32); } public: @@ -9653,8 +9756,8 @@ class MStoreUnboxedObjectOrNull initOperand(2, value); initOperand(3, typedObj); MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment)); - MOZ_ASSERT(index->type() == MIRType_Int32); - MOZ_ASSERT(typedObj->type() == MIRType_Object); + MOZ_ASSERT(index->type() == MIRType::Int32); + MOZ_ASSERT(typedObj->type() == MIRType::Object); } public: @@ -9714,7 +9817,7 @@ class MStoreUnboxedString initOperand(1, index); initOperand(2, value); MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment)); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); } public: @@ -9763,7 +9866,7 @@ class MConvertUnboxedObjectToNative { setGuard(); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -9866,7 +9969,7 @@ class MArrayPush MArrayPush(MDefinition* object, MDefinition* value, JSValueType unboxedType) : MBinaryInstruction(object, value), unboxedType_(unboxedType) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } public: @@ -9912,7 +10015,7 @@ class MArraySlice initialHeap_(initialHeap), unboxedType_(unboxedType) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -9965,7 +10068,7 @@ class MArrayJoin MArrayJoin(MDefinition* array, MDefinition* sep) : MBinaryInstruction(array, sep) { - setResultType(MIRType_String); + setResultType(MIRType::String); } public: INSTRUCTION_HEADER(ArrayJoin) @@ -10037,13 +10140,13 @@ class MLoadUnboxedScalar offsetAdjustment_(offsetAdjustment), canonicalizeDoubles_(canonicalizeDoubles) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); if (requiresBarrier_) setGuard(); // Not removable or movable else setMovable(); MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment)); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType); } @@ -10078,7 +10181,7 @@ class MLoadUnboxedScalar } bool fallible() const { // Bailout if the result does not fit in an int32. - return readType_ == Scalar::Uint32 && type() == MIRType_Int32; + return readType_ == Scalar::Uint32 && type() == MIRType::Int32; } bool requiresMemoryBarrier() const { return requiresBarrier_; @@ -10102,7 +10205,7 @@ class MLoadUnboxedScalar return AliasSet::Store(AliasSet::UnboxedElement); return AliasSet::Load(AliasSet::UnboxedElement); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; bool congruentTo(const MDefinition* ins) const override { if (requiresBarrier_) @@ -10143,9 +10246,9 @@ class MLoadTypedArrayElementHole MLoadTypedArrayElementHole(MDefinition* object, MDefinition* index, Scalar::Type arrayType, bool allowDouble) : MBinaryInstruction(object, index), arrayType_(arrayType), allowDouble_(allowDouble) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setMovable(); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType); } @@ -10203,11 +10306,11 @@ class MLoadTypedArrayElementStatic { int type = accessType(); if (type == Scalar::Float32) - setResultType(MIRType_Float32); + setResultType(MIRType::Float32); else if (type == Scalar::Float64) - setResultType(MIRType_Double); + setResultType(MIRType::Double); else - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } CompilerObject someTypedArray_; @@ -10339,7 +10442,7 @@ class MStoreUnboxedScalar else setMovable(); MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment)); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType); } @@ -10414,9 +10517,9 @@ class MStoreTypedArrayElementHole initOperand(2, index); initOperand(3, value); setMovable(); - MOZ_ASSERT(elements->type() == MIRType_Elements); - MOZ_ASSERT(length->type() == MIRType_Int32); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(elements->type() == MIRType::Elements); + MOZ_ASSERT(length->type() == MIRType::Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType); } @@ -10526,10 +10629,10 @@ class MEffectiveAddress MEffectiveAddress(MDefinition* base, MDefinition* index, Scale scale, int32_t displacement) : MBinaryInstruction(base, index), scale_(scale), displacement_(displacement) { - MOZ_ASSERT(base->type() == MIRType_Int32); - MOZ_ASSERT(index->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); + MOZ_ASSERT(index->type() == MIRType::Int32); setMovable(); - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } Scale scale_; @@ -10567,7 +10670,7 @@ class MClampToUint8 explicit MClampToUint8(MDefinition* input) : MUnaryInstruction(input) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } @@ -10601,7 +10704,7 @@ class MLoadFixedSlot MLoadFixedSlot(MDefinition* obj, size_t slot) : MUnaryInstruction(obj), slot_(slot) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setMovable(); } @@ -10632,7 +10735,7 @@ class MLoadFixedSlot return AliasSet::Load(AliasSet::FixedSlot); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; ALLOW_CLONE(MLoadFixedSlot) }; @@ -10693,7 +10796,7 @@ class MLoadFixedSlotAndUnbox return AliasSet::Load(AliasSet::FixedSlot); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; ALLOW_CLONE(MLoadFixedSlotAndUnbox); }; @@ -10845,7 +10948,7 @@ class MGetPropertyCache location_(), inlinePropertyTable_(nullptr) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); // The cache will invalidate if there are objects with e.g. lookup or // resolve hooks on the proto chain. setGuard ensures this check is not @@ -10943,7 +11046,7 @@ class MGetPropertyPolymorphic { setGuard(); setMovable(); - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -10996,7 +11099,7 @@ class MGetPropertyPolymorphic (hasUnboxedLoad ? AliasSet::UnboxedElement : 0)); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; }; // Emit code to store a value to an object's slots if its shape/group matches @@ -11246,7 +11349,7 @@ class MBindNameCache MBindNameCache(MDefinition* scopeChain, PropertyName* name, JSScript* script, jsbytecode* pc) : MUnaryInstruction(scopeChain), name_(name), script_(script), pc_(pc) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -11279,7 +11382,7 @@ class MCallBindVar explicit MCallBindVar(MDefinition* scopeChain) : MUnaryInstruction(scopeChain) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setMovable(); } @@ -11320,7 +11423,7 @@ class MGuardShape { setGuard(); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(obj->resultTypeSet()); // Disallow guarding on unboxed object shapes. The group is better to @@ -11374,7 +11477,7 @@ class MGuardReceiverPolymorphic { setGuard(); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(obj->resultTypeSet()); } @@ -11424,7 +11527,7 @@ class MGuardObjectGroup { setGuard(); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); // Unboxed groups which might be converted to natives can't be guarded // on, due to MConvertUnboxedObjectToNative. @@ -11481,7 +11584,7 @@ class MGuardObjectIdentity { setGuard(); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -11570,7 +11673,7 @@ class MGuardUnboxedExpando { setGuard(); setMovable(); - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -11611,7 +11714,7 @@ class MLoadUnboxedExpando explicit MLoadUnboxedExpando(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setMovable(); } @@ -11644,9 +11747,9 @@ class MLoadSlot : MUnaryInstruction(slots), slot_(slot) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setMovable(); - MOZ_ASSERT(slots->type() == MIRType_Slots); + MOZ_ASSERT(slots->type() == MIRType::Slots); } public: @@ -11675,10 +11778,10 @@ class MLoadSlot MDefinition* foldsTo(TempAllocator& alloc) override; AliasSet getAliasSet() const override { - MOZ_ASSERT(slots()->type() == MIRType_Slots); + MOZ_ASSERT(slots()->type() == MIRType::Slots); return AliasSet::Load(AliasSet::DynamicSlot); } - bool mightAlias(const MDefinition* store) const override; + AliasType mightAlias(const MDefinition* store) const override; ALLOW_CLONE(MLoadSlot) }; @@ -11692,7 +11795,7 @@ class MFunctionEnvironment explicit MFunctionEnvironment(MDefinition* function) : MUnaryInstruction(function) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setMovable(); } @@ -11726,10 +11829,10 @@ class MStoreSlot MStoreSlot(MDefinition* slots, uint32_t slot, MDefinition* value, bool barrier) : MBinaryInstruction(slots, value), slot_(slot), - slotType_(MIRType_Value), + slotType_(MIRType::Value), needsBarrier_(barrier) { - MOZ_ASSERT(slots->type() == MIRType_Slots); + MOZ_ASSERT(slots->type() == MIRType::Slots); } public: @@ -11759,7 +11862,7 @@ class MStoreSlot return slotType_; } void setSlotType(MIRType slotType) { - MOZ_ASSERT(slotType != MIRType_None); + MOZ_ASSERT(slotType != MIRType::None); slotType_ = slotType; } bool needsBarrier() const { @@ -11794,7 +11897,7 @@ class MGetNameCache name_(name), kind_(kind) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -11823,7 +11926,7 @@ class MCallGetIntrinsicValue : public MNullaryInstruction explicit MCallGetIntrinsicValue(PropertyName* name) : name_(name) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -11909,7 +12012,7 @@ class MDeleteProperty name_(name), strict_(strict) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); } public: @@ -11941,7 +12044,7 @@ class MDeleteElement : MBinaryInstruction(value, index), strict_(strict) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); } public: @@ -12048,7 +12151,7 @@ class MCallGetProperty : MUnaryInstruction(value), name_(name), idempotent_(false) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -12090,7 +12193,7 @@ class MCallGetElement MCallGetElement(MDefinition* lhs, MDefinition* rhs) : MBinaryInstruction(lhs, rhs) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -12230,7 +12333,7 @@ class MGetDOMProperty setGuard(); } - setResultType(MIRType_Value); + setResultType(MIRType::Value); } const JSJitInfo* info() const { @@ -12372,7 +12475,7 @@ class MStringLength explicit MStringLength(MDefinition* string) : MUnaryInstruction(string) { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } public: @@ -12414,8 +12517,8 @@ class MFloor explicit MFloor(MDefinition* num) : MUnaryInstruction(num) { - setResultType(MIRType_Int32); - specialization_ = MIRType_Double; + setResultType(MIRType::Int32); + specialization_ = MIRType::Double; setMovable(); } @@ -12458,8 +12561,8 @@ class MCeil explicit MCeil(MDefinition* num) : MUnaryInstruction(num) { - setResultType(MIRType_Int32); - specialization_ = MIRType_Double; + setResultType(MIRType::Int32); + specialization_ = MIRType::Double; setMovable(); } @@ -12502,8 +12605,8 @@ class MRound explicit MRound(MDefinition* num) : MUnaryInstruction(num) { - setResultType(MIRType_Int32); - specialization_ = MIRType_Double; + setResultType(MIRType::Int32); + specialization_ = MIRType::Double; setMovable(); } @@ -12548,7 +12651,7 @@ class MIteratorStart MIteratorStart(MDefinition* obj, uint8_t flags) : MUnaryInstruction(obj), flags_(flags) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -12573,7 +12676,7 @@ class MIteratorMore explicit MIteratorMore(MDefinition* iter) : MUnaryInstruction(iter) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -12595,7 +12698,7 @@ class MIsNoIter explicit MIsNoIter(MDefinition* def) : MUnaryInstruction(def) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); } @@ -12639,7 +12742,7 @@ class MIn MIn(MDefinition* key, MDefinition* obj) : MBinaryInstruction(key, obj) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); } public: @@ -12672,11 +12775,11 @@ class MInArray needsNegativeIntCheck_(true), unboxedType_(unboxedType) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); - MOZ_ASSERT(elements->type() == MIRType_Elements); - MOZ_ASSERT(index->type() == MIRType_Int32); - MOZ_ASSERT(initLength->type() == MIRType_Int32); + MOZ_ASSERT(elements->type() == MIRType::Elements); + MOZ_ASSERT(index->type() == MIRType::Int32); + MOZ_ASSERT(initLength->type() == MIRType::Int32); } public: @@ -12740,7 +12843,7 @@ class MInstanceOf : MUnaryInstruction(obj), protoObj_(proto) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); } public: @@ -12763,7 +12866,7 @@ class MCallInstanceOf MCallInstanceOf(MDefinition* obj, MDefinition* proto) : MBinaryInstruction(obj, proto) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); } public: @@ -12779,7 +12882,7 @@ class MArgumentsLength : public MNullaryInstruction { MArgumentsLength() { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); setMovable(); } @@ -12818,7 +12921,7 @@ class MGetFrameArgument : MUnaryInstruction(idx), scriptHasSetArg_(scriptHasSetArg) { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setMovable(); } @@ -12848,7 +12951,7 @@ class MGetFrameArgument class MNewTarget : public MNullaryInstruction { MNewTarget() : MNullaryInstruction() { - setResultType(MIRType_Value); + setResultType(MIRType::Value); setMovable(); } @@ -12934,7 +13037,7 @@ class MRest : MUnaryInstruction(numActuals), MRestCommon(numFormals, templateObject) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); } @@ -13046,14 +13149,14 @@ class MTypeBarrier // If mirtype of input doesn't agree with mirtype of barrier, // we will definitely bail. MIRType type = resultTypeSet()->getKnownMIRType(); - if (type == MIRType_Value) + if (type == MIRType::Value) return false; - if (input()->type() == MIRType_Value) + if (input()->type() == MIRType::Value) return false; - if (input()->type() == MIRType_ObjectOrNull) { + if (input()->type() == MIRType::ObjectOrNull) { // The ObjectOrNull optimization is only performed when the - // barrier's type is MIRType_Null. - MOZ_ASSERT(type == MIRType_Null); + // barrier's type is MIRType::Null. + MOZ_ASSERT(type == MIRType::Null); return false; } return input()->type() != type; @@ -13198,7 +13301,7 @@ class MNewDeclEnvObject : public MNullaryInstruction : MNullaryInstruction(), templateObj_(templateObj) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -13225,7 +13328,7 @@ class MNewCallObjectBase : public MNullaryInstruction : MNullaryInstruction(), templateObj_(templateObj) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -13279,7 +13382,7 @@ class MNewStringObject : : MUnaryInstruction(input), templateObj_(templateObj) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -13298,7 +13401,7 @@ class MEnclosingScope : public MLoadFixedSlot explicit MEnclosingScope(MDefinition* obj) : MLoadFixedSlot(obj, ScopeObject::enclosingScopeSlot()) { - setResultType(MIRType_Object); + setResultType(MIRType::Object); } public: @@ -13363,7 +13466,7 @@ class MResumePoint final : protected: // Initializes operands_ to an empty array of a fixed length. // The array may then be filled in by inherit(). - MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc); + MOZ_MUST_USE bool init(TempAllocator& alloc); void clearOperand(size_t index) { // FixedList doesn't initialize its elements, so do an unchecked init. @@ -13479,7 +13582,7 @@ class MIsCallable explicit MIsCallable(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); } @@ -13505,7 +13608,7 @@ class MIsConstructor explicit MIsConstructor(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); } @@ -13530,7 +13633,7 @@ class MIsObject explicit MIsObject(MDefinition* object) : MUnaryInstruction(object) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); } public: @@ -13559,8 +13662,8 @@ class MHasClass : MUnaryInstruction(object) , class_(clasp) { - MOZ_ASSERT(object->type() == MIRType_Object); - setResultType(MIRType_Boolean); + MOZ_ASSERT(object->type() == MIRType::Object); + setResultType(MIRType::Boolean); setMovable(); } @@ -13597,7 +13700,7 @@ class MCheckReturn : MBinaryInstruction(retVal, thisVal) { setGuard(); - setResultType(MIRType_Value); + setResultType(MIRType::Value); setResultTypeSet(retVal->resultTypeSet()); } @@ -13690,7 +13793,7 @@ class MAtomicIsLockFree explicit MAtomicIsLockFree(MDefinition* value) : MUnaryInstruction(value) { - setResultType(MIRType_Boolean); + setResultType(MIRType::Boolean); setMovable(); } @@ -13921,7 +14024,7 @@ class MCheckObjCoercible : MUnaryInstruction(toCheck) { setGuard(); - setResultType(MIRType_Value); + setResultType(MIRType::Value); setResultTypeSet(toCheck->resultTypeSet()); } @@ -13944,7 +14047,7 @@ class MDebugCheckSelfHosted : MUnaryInstruction(toCheck) { setGuard(); - setResultType(MIRType_Value); + setResultType(MIRType::Value); setResultTypeSet(toCheck->resultTypeSet()); } @@ -14014,13 +14117,8 @@ class MAsmJSHeapAccess bool needsBoundsCheck() const { return needsBoundsCheck_; } void removeBoundsCheck() { needsBoundsCheck_ = false; } unsigned numSimdElems() const { MOZ_ASSERT(Scalar::isSimdType(accessType_)); return numSimdElems_; } - void setOffset(uint32_t o) { - offset_ = o; - } - void setAlign(uint32_t a) { - MOZ_ASSERT(mozilla::IsPowerOfTwo(a)); - align_ = a; - } + void setOffset(uint32_t o) { offset_ = o; } + void setAlign(uint32_t a) { MOZ_ASSERT(mozilla::IsPowerOfTwo(a)); align_ = a; } MemoryBarrierBits barrierBefore() const { return barrierBefore_; } MemoryBarrierBits barrierAfter() const { return barrierAfter_; } bool isAtomicAccess() const { return (barrierBefore_|barrierAfter_) != MembarNobits; } @@ -14047,19 +14145,19 @@ class MAsmJSLoadHeap case Scalar::Uint16: case Scalar::Int32: case Scalar::Uint32: - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); break; case Scalar::Float32: - setResultType(MIRType_Float32); + setResultType(MIRType::Float32); break; case Scalar::Float64: - setResultType(MIRType_Double); + setResultType(MIRType::Double); break; case Scalar::Float32x4: - setResultType(MIRType_Float32x4); + setResultType(MIRType::Float32x4); break; case Scalar::Int32x4: - setResultType(MIRType_Int32x4); + setResultType(MIRType::Int32x4); break; case Scalar::Uint8Clamped: case Scalar::MaxTypedArrayViewType: @@ -14087,7 +14185,7 @@ class MAsmJSLoadHeap return AliasSet::Store(AliasSet::AsmJSHeap); return AliasSet::Load(AliasSet::AsmJSHeap); } - bool mightAlias(const MDefinition* def) const override; + AliasType mightAlias(const MDefinition* def) const override; }; class MAsmJSStoreHeap @@ -14134,7 +14232,7 @@ class MAsmJSCompareExchangeHeap MAsmJSHeapAccess(access) { setGuard(); // Not removable - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } public: @@ -14167,7 +14265,7 @@ class MAsmJSAtomicExchangeHeap MAsmJSHeapAccess(access) { setGuard(); // Not removable - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } public: @@ -14202,7 +14300,7 @@ class MAsmJSAtomicBinopHeap op_(op) { setGuard(); // Not removable - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); } public: @@ -14256,7 +14354,7 @@ class MAsmJSLoadGlobalVar : public MNullaryInstruction return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::AsmJSGlobalVar); } - bool mightAlias(const MDefinition* def) const override; + AliasType mightAlias(const MDefinition* def) const override; }; class MAsmJSStoreGlobalVar @@ -14293,7 +14391,7 @@ class MAsmJSLoadFuncPtr : MUnaryInstruction(index), hasLimit_(hasLimit), limit_(limit), alwaysThrow_(alwaysThrow), globalDataOffset_(globalDataOffset) { - setResultType(MIRType_Pointer); + setResultType(MIRType::Pointer); } bool hasLimit_; @@ -14331,7 +14429,7 @@ class MAsmJSLoadFFIFunc : public MNullaryInstruction explicit MAsmJSLoadFFIFunc(unsigned globalDataOffset) : globalDataOffset_(globalDataOffset) { - setResultType(MIRType_Pointer); + setResultType(MIRType::Pointer); } unsigned globalDataOffset_; @@ -14506,7 +14604,7 @@ class MAsmSelect MAsmSelect(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition *condExpr) : MTernaryInstruction(trueExpr, falseExpr, condExpr) { - MOZ_ASSERT(condExpr->type() == MIRType_Int32); + MOZ_ASSERT(condExpr->type() == MIRType::Int32); MOZ_ASSERT(trueExpr->type() == falseExpr->type()); setResultType(trueExpr->type()); setMovable(); @@ -14550,10 +14648,10 @@ class MAsmReinterpret : MUnaryInstruction(val) { switch (val->type()) { - case MIRType_Int32: MOZ_ASSERT(toType == MIRType_Float32); break; - case MIRType_Float32: MOZ_ASSERT(toType == MIRType_Int32); break; - case MIRType_Double: MOZ_ASSERT(toType == MIRType_Int64); break; - case MIRType_Int64: MOZ_ASSERT(toType == MIRType_Double); break; + case MIRType::Int32: MOZ_ASSERT(toType == MIRType::Float32); break; + case MIRType::Float32: MOZ_ASSERT(toType == MIRType::Int32); break; + case MIRType::Double: MOZ_ASSERT(toType == MIRType::Int64); break; + case MIRType::Int64: MOZ_ASSERT(toType == MIRType::Double); break; default: MOZ_CRASH("unexpected reinterpret conversion"); } setMovable(); @@ -14563,7 +14661,7 @@ class MAsmReinterpret public: INSTRUCTION_HEADER(AsmReinterpret) - static MAsmReinterpret* New(TempAllocator& alloc, MDefinition* val, MIRType toType) + static MAsmReinterpret* NewAsmJS(TempAllocator& alloc, MDefinition* val, MIRType toType) { return new(alloc) MAsmReinterpret(val, toType); } @@ -14578,11 +14676,53 @@ class MAsmReinterpret ALLOW_CLONE(MAsmReinterpret) }; +class MRotate + : public MBinaryInstruction, + public NoTypePolicy::Data +{ + bool isLeftRotate_; + + MRotate(MDefinition* input, MDefinition* count, MIRType type, bool isLeftRotate) + : MBinaryInstruction(input, count), isLeftRotate_(isLeftRotate) + { + setMovable(); + setResultType(type); + } + + public: + INSTRUCTION_HEADER(Rotate) + + static MRotate* NewAsmJS(TempAllocator& alloc, MDefinition* input, MDefinition* count, + MIRType type, bool isLeft) + { + return new(alloc) MRotate(input, count, type, isLeft); + } + + AliasSet getAliasSet() const override { + return AliasSet::None(); + } + bool congruentTo(const MDefinition* ins) const override { + return congruentIfOperandsEqual(ins) && ins->toRotate()->isLeftRotate() == isLeftRotate_; + } + + MDefinition* input() const { + return getOperand(0); + } + MDefinition* count() const { + return getOperand(1); + } + bool isLeftRotate() const { + return isLeftRotate_; + } + + ALLOW_CLONE(MRotate) +}; + class MUnknownValue : public MNullaryInstruction { protected: MUnknownValue() { - setResultType(MIRType_Value); + setResultType(MIRType::Value); } public: @@ -14710,11 +14850,11 @@ void AddObjectsForPropertyRead(MDefinition* obj, PropertyName* name, TemporaryTypeSet* observed); bool CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints, HeapTypeSetKey property, MDefinition* value, - MIRType implicitType = MIRType_None); + MIRType implicitType = MIRType::None); bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* constraints, MBasicBlock* current, MDefinition** pobj, PropertyName* name, MDefinition** pvalue, - bool canModify, MIRType implicitType = MIRType_None); + bool canModify, MIRType implicitType = MIRType::None); bool ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script); bool TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types); @@ -14728,13 +14868,13 @@ MIRTypeForTypedArrayRead(Scalar::Type arrayType, bool observedDouble) case Scalar::Int16: case Scalar::Uint16: case Scalar::Int32: - return MIRType_Int32; + return MIRType::Int32; case Scalar::Uint32: - return observedDouble ? MIRType_Double : MIRType_Int32; + return observedDouble ? MIRType::Double : MIRType::Int32; case Scalar::Float32: - return MIRType_Float32; + return MIRType::Float32; case Scalar::Float64: - return MIRType_Double; + return MIRType::Double; default: break; } diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index ddbfe5219d..4447e1e004 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -132,8 +132,8 @@ MIRGenerator::foldableOffsetRange(const MAsmJSHeapAccess* access) const size_t MIRGenerator::foldableOffsetRange(bool accessNeedsBoundsCheck, bool atomic) const { - // This determines whether it's ok to fold up to WasmImmediateSize - // offsets, instead of just WasmCheckedImmediateSize. + // This determines whether it's ok to fold up to WasmImmediateRange + // offsets, instead of just WasmCheckedImmediateRange. static_assert(WasmCheckedImmediateRange <= WasmImmediateRange, "WasmImmediateRange should be the size of an unconstrained " @@ -434,7 +434,7 @@ MBasicBlock::NewAsmJS(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pre for (size_t i = 0; i < nphis; i++) { MDefinition* predSlot = pred->getSlot(i); - MOZ_ASSERT(predSlot->type() != MIRType_Value); + MOZ_ASSERT(predSlot->type() != MIRType::Value); MPhi* phi; if (i < nfree) @@ -686,7 +686,7 @@ MBasicBlock::linkOsrValues(MStart* start) cloneRp = def->toOsrReturnValue(); } else if (info().hasArguments() && i == info().argsObjSlot()) { MOZ_ASSERT(def->isConstant() || def->isOsrArgumentsObject()); - MOZ_ASSERT_IF(def->isConstant(), def->toConstant()->type() == MIRType_Undefined); + MOZ_ASSERT_IF(def->isConstant(), def->toConstant()->type() == MIRType::Undefined); if (def->isOsrArgumentsObject()) cloneRp = def->toOsrArgumentsObject(); } else { @@ -696,7 +696,7 @@ MBasicBlock::linkOsrValues(MStart* start) // A constant Undefined can show up here for an argument slot when // the function has an arguments object, but the argument in // question is stored on the scope chain. - MOZ_ASSERT_IF(def->isConstant(), def->toConstant()->type() == MIRType_Undefined); + MOZ_ASSERT_IF(def->isConstant(), def->toConstant()->type() == MIRType::Undefined); if (def->isOsrValue()) cloneRp = def->toOsrValue(); @@ -875,7 +875,7 @@ MBasicBlock::optimizedOutConstant(TempAllocator& alloc) // If the first instruction is a MConstant(MagicValue(JS_OPTIMIZED_OUT)) // then reuse it. MInstruction* ins = *begin(); - if (ins->type() == MIRType_MagicOptimizedOut) + if (ins->type() == MIRType::MagicOptimizedOut) return ins->toConstant(); MConstant* constant = MConstant::New(alloc, MagicValue(JS_OPTIMIZED_OUT)); @@ -1338,7 +1338,7 @@ MBasicBlock::setBackedgeAsmJS(MBasicBlock* pred) // Assert that the phi already has the correct type. MOZ_ASSERT(entryDef->type() == exitDef->type()); - MOZ_ASSERT(entryDef->type() != MIRType_Value); + MOZ_ASSERT(entryDef->type() != MIRType::Value); if (entryDef == exitDef) { // If the exit def is the same as the entry def, make a redundant diff --git a/js/src/jit/MIRGraph.h b/js/src/jit/MIRGraph.h index 16ff92ed5d..dca6ab1a0e 100644 --- a/js/src/jit/MIRGraph.h +++ b/js/src/jit/MIRGraph.h @@ -47,11 +47,11 @@ class MBasicBlock : public TempObject, public InlineListNode private: MBasicBlock(MIRGraph& graph, const CompileInfo& info, BytecodeSite* site, Kind kind); - MOZ_WARN_UNUSED_RESULT bool init(); + MOZ_MUST_USE bool init(); void copySlots(MBasicBlock* from); - MOZ_WARN_UNUSED_RESULT bool inherit(TempAllocator& alloc, BytecodeAnalysis* analysis, MBasicBlock* pred, + MOZ_MUST_USE bool inherit(TempAllocator& alloc, BytecodeAnalysis* analysis, MBasicBlock* pred, uint32_t popped, unsigned stackPhiCount = 0); - MOZ_WARN_UNUSED_RESULT bool inheritResumePoint(MBasicBlock* pred); + MOZ_MUST_USE bool inheritResumePoint(MBasicBlock* pred); void assertUsesAreNotWithin(MUseIterator use, MUseIterator end); // This block cannot be reached by any means. @@ -154,8 +154,8 @@ class MBasicBlock : public TempObject, public InlineListNode MDefinition* argumentsObject(); // Increase the number of slots available - MOZ_WARN_UNUSED_RESULT bool increaseSlots(size_t num); - MOZ_WARN_UNUSED_RESULT bool ensureHasSlots(size_t num); + MOZ_MUST_USE bool increaseSlots(size_t num); + MOZ_MUST_USE bool ensureHasSlots(size_t num); // Initializes a slot value; must not be called for normal stack // operations, as it will not create new SSA names for copies. @@ -166,7 +166,7 @@ class MBasicBlock : public TempObject, public InlineListNode // In an OSR block, set all MOsrValues to use the MResumePoint attached to // the MStart. - MOZ_WARN_UNUSED_RESULT bool linkOsrValues(MStart* start); + MOZ_MUST_USE bool linkOsrValues(MStart* start); // Sets the instruction associated with various slot types. The // instruction must lie at the top of the stack. @@ -220,17 +220,17 @@ class MBasicBlock : public TempObject, public InlineListNode // Adds a predecessor. Every predecessor must have the same exit stack // depth as the entry state to this block. Adding a predecessor // automatically creates phi nodes and rewrites uses as needed. - MOZ_WARN_UNUSED_RESULT bool addPredecessor(TempAllocator& alloc, MBasicBlock* pred); - MOZ_WARN_UNUSED_RESULT bool addPredecessorPopN(TempAllocator& alloc, MBasicBlock* pred, uint32_t popped); + MOZ_MUST_USE bool addPredecessor(TempAllocator& alloc, MBasicBlock* pred); + MOZ_MUST_USE bool addPredecessorPopN(TempAllocator& alloc, MBasicBlock* pred, uint32_t popped); // Add a predecessor which won't introduce any new phis to this block. // This may be called after the contents of this block have been built. void addPredecessorSameInputsAs(MBasicBlock* pred, MBasicBlock* existingPred); // Stranger utilities used for inlining. - MOZ_WARN_UNUSED_RESULT bool addPredecessorWithoutPhis(MBasicBlock* pred); + MOZ_MUST_USE bool addPredecessorWithoutPhis(MBasicBlock* pred); void inheritSlots(MBasicBlock* parent); - MOZ_WARN_UNUSED_RESULT bool initEntrySlots(TempAllocator& alloc); + MOZ_MUST_USE bool initEntrySlots(TempAllocator& alloc); // Replaces an edge for a given block with a new block. This is // used for critical edge splitting. @@ -255,8 +255,8 @@ class MBasicBlock : public TempObject, public InlineListNode // Sets a back edge. This places phi nodes and rewrites instructions within // the current loop as necessary. If the backedge introduces new types for // phis at the loop header, returns a disabling abort. - MOZ_WARN_UNUSED_RESULT AbortReason setBackedge(MBasicBlock* block); - MOZ_WARN_UNUSED_RESULT bool setBackedgeAsmJS(MBasicBlock* block); + MOZ_MUST_USE AbortReason setBackedge(MBasicBlock* block); + MOZ_MUST_USE bool setBackedgeAsmJS(MBasicBlock* block); // Resets a LOOP_HEADER block to a NORMAL block. This is needed when // optimizations remove the backedge. @@ -271,10 +271,10 @@ class MBasicBlock : public TempObject, public InlineListNode void inheritPhis(MBasicBlock* header); // Propagates backedge slots into phis operands of the loop header. - MOZ_WARN_UNUSED_RESULT bool inheritPhisFromBackedge(MBasicBlock* backedge, bool* hadTypeChange); + MOZ_MUST_USE bool inheritPhisFromBackedge(MBasicBlock* backedge, bool* hadTypeChange); // Compute the types for phis in this block according to their inputs. - MOZ_WARN_UNUSED_RESULT bool specializePhis(); + MOZ_MUST_USE bool specializePhis(); void insertBefore(MInstruction* at, MInstruction* ins); void insertAfter(MInstruction* at, MInstruction* ins); @@ -773,7 +773,7 @@ class MIRGraph return returnAccumulator_; } - MOZ_WARN_UNUSED_RESULT bool addReturn(MBasicBlock* returnBlock) { + MOZ_MUST_USE bool addReturn(MBasicBlock* returnBlock) { if (!returnAccumulator_) return true; diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index ed834249a9..07c2e6fd63 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -119,7 +119,7 @@ namespace jit { _(ToFloat32) \ _(ToInt32) \ _(TruncateToInt32) \ - _(TruncateToInt64) \ + _(WasmTruncateToInt64) \ _(WrapInt64ToInt32) \ _(ExtendInt32ToInt64) \ _(Int64ToFloatingPoint) \ @@ -151,6 +151,7 @@ namespace jit { _(RegExpTester) \ _(RegExpPrototypeOptimizable) \ _(RegExpInstanceOptimizable) \ + _(GetFirstDollarIndex) \ _(StringReplace) \ _(Lambda) \ _(LambdaArrow) \ @@ -265,6 +266,7 @@ namespace jit { _(IsCallable) \ _(IsObject) \ _(HasClass) \ + _(WasmTruncateToInt32) \ _(AsmJSNeg) \ _(AsmJSUnsignedToDouble) \ _(AsmJSUnsignedToFloat32) \ @@ -281,6 +283,7 @@ namespace jit { _(AsmJSCall) \ _(AsmSelect) \ _(AsmReinterpret) \ + _(Rotate) \ _(NewDerivedTypedObject) \ _(RecompileCheck) \ _(AsmJSCompareExchangeHeap) \ diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index abf8f234b5..dea4487ffa 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -518,17 +518,17 @@ void MacroAssembler::branchTestMIRType(Condition cond, const Value& val, MIRType type, Label* label) { switch (type) { - case MIRType_Null: return branchTestNull(cond, val, label); - case MIRType_Undefined: return branchTestUndefined(cond, val, label); - case MIRType_Boolean: return branchTestBoolean(cond, val, label); - case MIRType_Int32: return branchTestInt32(cond, val, label); - case MIRType_String: return branchTestString(cond, val, label); - case MIRType_Symbol: return branchTestSymbol(cond, val, label); - case MIRType_Object: return branchTestObject(cond, val, label); - case MIRType_Double: return branchTestDouble(cond, val, label); - case MIRType_MagicOptimizedArguments: // Fall through. - case MIRType_MagicIsConstructing: - case MIRType_MagicHole: return branchTestMagic(cond, val, label); + case MIRType::Null: return branchTestNull(cond, val, label); + case MIRType::Undefined: return branchTestUndefined(cond, val, label); + case MIRType::Boolean: return branchTestBoolean(cond, val, label); + case MIRType::Int32: return branchTestInt32(cond, val, label); + case MIRType::String: return branchTestString(cond, val, label); + case MIRType::Symbol: return branchTestSymbol(cond, val, label); + case MIRType::Object: return branchTestObject(cond, val, label); + case MIRType::Double: return branchTestDouble(cond, val, label); + case MIRType::MagicOptimizedArguments: // Fall through. + case MIRType::MagicIsConstructing: + case MIRType::MagicHole: return branchTestMagic(cond, val, label); default: MOZ_CRASH("Bad MIRType"); } diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 083aeeaf65..f630117b5c 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -327,7 +327,7 @@ MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T& src, AnyRegi // Bail out if the value doesn't fit into a signed int32 value. This // is what allows MLoadUnboxedScalar to have a type() of - // MIRType_Int32 for UInt32 array loads. + // MIRType::Int32 for UInt32 array loads. branchTest32(Assembler::Signed, dest.gpr(), dest.gpr(), fail); } break; @@ -453,7 +453,7 @@ MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueReg switch (type) { case JSVAL_TYPE_INT32: { // Handle loading an int32 into a double reg. - if (output.type() == MIRType_Double) { + if (output.type() == MIRType::Double) { convertInt32ToDouble(address, output.typedReg().fpu()); break; } @@ -568,7 +568,7 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type, else StoreUnboxedFailure(*this, failure); } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType_Boolean) + if (value.reg().type() == MIRType::Boolean) store8(value.reg().typedReg().gpr(), address); else StoreUnboxedFailure(*this, failure); @@ -586,7 +586,7 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type, else StoreUnboxedFailure(*this, failure); } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType_Int32) + if (value.reg().type() == MIRType::Int32) store32(value.reg().typedReg().gpr(), address); else StoreUnboxedFailure(*this, failure); @@ -606,10 +606,10 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type, StoreUnboxedFailure(*this, failure); } } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType_Int32) { + if (value.reg().type() == MIRType::Int32) { convertInt32ToDouble(value.reg().typedReg().gpr(), ScratchDoubleReg); storeDouble(ScratchDoubleReg, address); - } else if (value.reg().type() == MIRType_Double) { + } else if (value.reg().type() == MIRType::Double) { storeDouble(value.reg().typedReg().fpu(), address); } else { StoreUnboxedFailure(*this, failure); @@ -636,8 +636,8 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type, else StoreUnboxedFailure(*this, failure); } else if (value.reg().hasTyped()) { - MOZ_ASSERT(value.reg().type() != MIRType_Null); - if (value.reg().type() == MIRType_Object) + MOZ_ASSERT(value.reg().type() != MIRType::Null); + if (value.reg().type() == MIRType::Object) storePtr(value.reg().typedReg().gpr(), address); else StoreUnboxedFailure(*this, failure); @@ -659,7 +659,7 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type, else StoreUnboxedFailure(*this, failure); } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType_String) + if (value.reg().type() == MIRType::String) storePtr(value.reg().typedReg().gpr(), address); else StoreUnboxedFailure(*this, failure); @@ -1690,11 +1690,11 @@ MacroAssembler::convertValueToFloatingPoint(ValueOperand value, FloatRegister ou bind(&isDouble); FloatRegister tmp = output; - if (outputType == MIRType_Float32 && hasMultiAlias()) + if (outputType == MIRType::Float32 && hasMultiAlias()) tmp = ScratchDoubleReg; unboxDouble(value, tmp); - if (outputType == MIRType_Float32) + if (outputType == MIRType::Float32) convertDoubleToFloat32(tmp, output); bind(&done); @@ -1761,16 +1761,16 @@ MacroAssembler::convertTypedOrValueToFloatingPoint(TypedOrValueRegister src, Flo return; } - bool outputIsDouble = outputType == MIRType_Double; + bool outputIsDouble = outputType == MIRType::Double; switch (src.type()) { - case MIRType_Null: + case MIRType::Null: loadConstantFloatingPoint(0.0, 0.0f, output, outputType); break; - case MIRType_Boolean: - case MIRType_Int32: + case MIRType::Boolean: + case MIRType::Int32: convertInt32ToFloatingPoint(src.typedReg().gpr(), output, outputType); break; - case MIRType_Float32: + case MIRType::Float32: if (outputIsDouble) { convertFloat32ToDouble(src.typedReg().fpu(), output); } else { @@ -1778,7 +1778,7 @@ MacroAssembler::convertTypedOrValueToFloatingPoint(TypedOrValueRegister src, Flo moveFloat32(src.typedReg().fpu(), output); } break; - case MIRType_Double: + case MIRType::Double: if (outputIsDouble) { if (src.typedReg().fpu() != output) moveDouble(src.typedReg().fpu(), output); @@ -1786,12 +1786,12 @@ MacroAssembler::convertTypedOrValueToFloatingPoint(TypedOrValueRegister src, Flo convertDoubleToFloat32(src.typedReg().fpu(), output); } break; - case MIRType_Object: - case MIRType_String: - case MIRType_Symbol: + case MIRType::Object: + case MIRType::String: + case MIRType::Symbol: jump(fail); break; - case MIRType_Undefined: + case MIRType::Undefined: loadConstantFloatingPoint(GenericNaN(), float(GenericNaN()), output, outputType); break; default: @@ -1838,10 +1838,10 @@ MacroAssembler::convertValueToInt(ValueOperand value, MDefinition* maybeInput, Label done, isInt32, isBool, isDouble, isNull, isString; - maybeBranchTestType(MIRType_Int32, maybeInput, tag, &isInt32); + maybeBranchTestType(MIRType::Int32, maybeInput, tag, &isInt32); if (conversion == IntConversion_Any || conversion == IntConversion_NumbersOrBoolsOnly) - maybeBranchTestType(MIRType_Boolean, maybeInput, tag, &isBool); - maybeBranchTestType(MIRType_Double, maybeInput, tag, &isDouble); + maybeBranchTestType(MIRType::Boolean, maybeInput, tag, &isBool); + maybeBranchTestType(MIRType::Double, maybeInput, tag, &isDouble); if (conversion == IntConversion_Any) { // If we are not truncating, we fail for anything that's not @@ -1854,10 +1854,10 @@ MacroAssembler::convertValueToInt(ValueOperand value, MDefinition* maybeInput, case IntConversion_Truncate: case IntConversion_ClampToUint8: - maybeBranchTestType(MIRType_Null, maybeInput, tag, &isNull); + maybeBranchTestType(MIRType::Null, maybeInput, tag, &isNull); if (handleStrings) - maybeBranchTestType(MIRType_String, maybeInput, tag, &isString); - maybeBranchTestType(MIRType_Object, maybeInput, tag, fail); + maybeBranchTestType(MIRType::String, maybeInput, tag, &isString); + maybeBranchTestType(MIRType::Object, maybeInput, tag, fail); branchTestUndefined(Assembler::NotEqual, tag, fail); break; } @@ -1985,28 +1985,28 @@ MacroAssembler::convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister } switch (src.type()) { - case MIRType_Undefined: - case MIRType_Null: + case MIRType::Undefined: + case MIRType::Null: move32(Imm32(0), output); break; - case MIRType_Boolean: - case MIRType_Int32: + case MIRType::Boolean: + case MIRType::Int32: if (src.typedReg().gpr() != output) move32(src.typedReg().gpr(), output); - if (src.type() == MIRType_Int32 && behavior == IntConversion_ClampToUint8) + if (src.type() == MIRType::Int32 && behavior == IntConversion_ClampToUint8) clampIntToUint8(output); break; - case MIRType_Double: + case MIRType::Double: convertDoubleToInt(src.typedReg().fpu(), output, temp, nullptr, fail, behavior); break; - case MIRType_Float32: + case MIRType::Float32: // Conversion to Double simplifies implementation at the expense of performance. convertFloat32ToDouble(src.typedReg().fpu(), temp); convertDoubleToInt(temp, output, temp, nullptr, fail, behavior); break; - case MIRType_String: - case MIRType_Symbol: - case MIRType_Object: + case MIRType::String: + case MIRType::Symbol: + case MIRType::Object: jump(fail); break; default: @@ -2256,7 +2256,7 @@ MacroAssembler::Push(TypedOrValueRegister v) Push(v.valueReg()); } else if (IsFloatingPointType(v.type())) { FloatRegister reg = v.typedReg().fpu(); - if (v.type() == MIRType_Float32) { + if (v.type() == MIRType::Float32) { convertFloat32ToDouble(reg, ScratchDoubleReg); reg = ScratchDoubleReg; } @@ -2427,13 +2427,13 @@ MacroAssembler::passABIArg(const MoveOperand& from, MoveOp::Type type) ABIArg arg; switch (type) { case MoveOp::FLOAT32: - arg = abiArgs_.next(MIRType_Float32); + arg = abiArgs_.next(MIRType::Float32); break; case MoveOp::DOUBLE: - arg = abiArgs_.next(MIRType_Double); + arg = abiArgs_.next(MIRType::Double); break; case MoveOp::GENERAL: - arg = abiArgs_.next(MIRType_Pointer); + arg = abiArgs_.next(MIRType::Pointer); break; default: MOZ_CRASH("Unexpected argument type"); @@ -2520,25 +2520,25 @@ MacroAssembler::maybeBranchTestType(MIRType type, MDefinition* maybeDef, Registe { if (!maybeDef || maybeDef->mightBeType(type)) { switch (type) { - case MIRType_Null: + case MIRType::Null: branchTestNull(Equal, tag, label); break; - case MIRType_Boolean: + case MIRType::Boolean: branchTestBoolean(Equal, tag, label); break; - case MIRType_Int32: + case MIRType::Int32: branchTestInt32(Equal, tag, label); break; - case MIRType_Double: + case MIRType::Double: branchTestDouble(Equal, tag, label); break; - case MIRType_String: + case MIRType::String: branchTestString(Equal, tag, label); break; - case MIRType_Symbol: + case MIRType::Symbol: branchTestSymbol(Equal, tag, label); break; - case MIRType_Object: + case MIRType::Object: branchTestObject(Equal, tag, label); break; default: @@ -2553,20 +2553,20 @@ void MacroAssembler::BranchType::emit(MacroAssembler& masm) { MOZ_ASSERT(isInitialized()); - MIRType mirType = MIRType_None; + MIRType mirType = MIRType::None; if (type_.isPrimitive()) { if (type_.isMagicArguments()) - mirType = MIRType_MagicOptimizedArguments; + mirType = MIRType::MagicOptimizedArguments; else mirType = MIRTypeFromValueType(type_.primitive()); } else if (type_.isAnyObject()) { - mirType = MIRType_Object; + mirType = MIRType::Object; } else { MOZ_CRASH("Unknown conversion to mirtype"); } - if (mirType == MIRType_Double) + if (mirType == MIRType::Double) masm.branchTestNumber(cond(), reg(), jump()); else masm.branchTestMIRType(cond(), reg(), mirType, jump()); diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index cca5d4cfc8..b2bd92c4ac 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -794,6 +794,13 @@ class MacroAssembler : public MacroAssemblerSpecific inline void rshift64(Imm32 imm, Register64 dest) PER_ARCH; + // =============================================================== + // Rotation functions + inline void rotateLeft(Imm32 count, Register input, Register dest) PER_SHARED_ARCH; + inline void rotateLeft(Register count, Register input, Register dest) PER_SHARED_ARCH; + inline void rotateRight(Imm32 count, Register input, Register dest) PER_SHARED_ARCH; + inline void rotateRight(Register count, Register input, Register dest) PER_SHARED_ARCH; + // =============================================================== // Branch functions @@ -1167,7 +1174,7 @@ class MacroAssembler : public MacroAssemblerSpecific storeValue(src.valueReg(), dest); } else if (IsFloatingPointType(src.type())) { FloatRegister reg = src.typedReg().fpu(); - if (src.type() == MIRType_Float32) { + if (src.type() == MIRType::Float32) { convertFloat32ToDouble(reg, ScratchDoubleReg); reg = ScratchDoubleReg; } @@ -1247,7 +1254,7 @@ class MacroAssembler : public MacroAssemblerSpecific void callPreBarrier(const T& address, MIRType type) { Label done; - if (type == MIRType_Value) + if (type == MIRType::Value) branchTestGCThing(Assembler::NotEqual, address, &done); Push(PreBarrierReg); @@ -1349,7 +1356,7 @@ class MacroAssembler : public MacroAssemblerSpecific Register extractObject(const TypedOrValueRegister& reg, Register scratch) { if (reg.hasValue()) return extractObject(reg.valueReg(), scratch); - MOZ_ASSERT(reg.type() == MIRType_Object); + MOZ_ASSERT(reg.type() == MIRType::Object); return reg.typedReg().gpr(); } @@ -1540,7 +1547,7 @@ class MacroAssembler : public MacroAssemblerSpecific #define DISPATCH_FLOATING_POINT_OP(method, type, arg1d, arg1f, arg2) \ MOZ_ASSERT(IsFloatingPointType(type)); \ - if (type == MIRType_Double) \ + if (type == MIRType::Double) \ method##Double(arg1d, arg2); \ else \ method##Float32(arg1f, arg2); \ @@ -1572,33 +1579,33 @@ class MacroAssembler : public MacroAssemblerSpecific void convertInt32ValueToDouble(const Address& address, Register scratch, Label* done); void convertValueToDouble(ValueOperand value, FloatRegister output, Label* fail) { - convertValueToFloatingPoint(value, output, fail, MIRType_Double); + convertValueToFloatingPoint(value, output, fail, MIRType::Double); } bool convertValueToDouble(JSContext* cx, const Value& v, FloatRegister output, Label* fail) { - return convertValueToFloatingPoint(cx, v, output, fail, MIRType_Double); + return convertValueToFloatingPoint(cx, v, output, fail, MIRType::Double); } bool convertConstantOrRegisterToDouble(JSContext* cx, ConstantOrRegister src, FloatRegister output, Label* fail) { - return convertConstantOrRegisterToFloatingPoint(cx, src, output, fail, MIRType_Double); + return convertConstantOrRegisterToFloatingPoint(cx, src, output, fail, MIRType::Double); } void convertTypedOrValueToDouble(TypedOrValueRegister src, FloatRegister output, Label* fail) { - convertTypedOrValueToFloatingPoint(src, output, fail, MIRType_Double); + convertTypedOrValueToFloatingPoint(src, output, fail, MIRType::Double); } void convertValueToFloat(ValueOperand value, FloatRegister output, Label* fail) { - convertValueToFloatingPoint(value, output, fail, MIRType_Float32); + convertValueToFloatingPoint(value, output, fail, MIRType::Float32); } bool convertValueToFloat(JSContext* cx, const Value& v, FloatRegister output, Label* fail) { - return convertValueToFloatingPoint(cx, v, output, fail, MIRType_Float32); + return convertValueToFloatingPoint(cx, v, output, fail, MIRType::Float32); } bool convertConstantOrRegisterToFloat(JSContext* cx, ConstantOrRegister src, FloatRegister output, Label* fail) { - return convertConstantOrRegisterToFloatingPoint(cx, src, output, fail, MIRType_Float32); + return convertConstantOrRegisterToFloatingPoint(cx, src, output, fail, MIRType::Float32); } void convertTypedOrValueToFloat(TypedOrValueRegister src, FloatRegister output, Label* fail) { - convertTypedOrValueToFloatingPoint(src, output, fail, MIRType_Float32); + convertTypedOrValueToFloatingPoint(src, output, fail, MIRType::Float32); } enum IntConversionBehavior { diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index 3f4551f736..286917ab97 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -1094,7 +1094,7 @@ IonBuilder::trackTypeInfoUnchecked(TrackedTypeSite kind, JSObject* obj) { BytecodeSite* site = current->trackedSite(); // OOMs are handled as if optimization tracking were turned off. - OptimizationTypeInfo typeInfo(alloc(), kind, MIRType_Object); + OptimizationTypeInfo typeInfo(alloc(), kind, MIRType::Object); if (!typeInfo.trackType(TypeSet::ObjectType(obj))) return; if (!site->optimizations()->trackTypeInfo(mozilla::Move(typeInfo))) diff --git a/js/src/jit/PerfSpewer.cpp b/js/src/jit/PerfSpewer.cpp index b03784853a..cd69b4b4ce 100644 --- a/js/src/jit/PerfSpewer.cpp +++ b/js/src/jit/PerfSpewer.cpp @@ -7,6 +7,7 @@ #include "jit/PerfSpewer.h" #include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/SizePrintfMacros.h" #if defined(__linux__) # include diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 9c47004326..8746589355 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -114,7 +114,7 @@ static inline void SpewRange(MDefinition* def) { #ifdef JS_JITSPEW - if (JitSpewEnabled(JitSpew_Range) && def->type() != MIRType_None && def->range()) { + if (JitSpewEnabled(JitSpew_Range) && def->type() != MIRType::None && def->range()) { JitSpewHeader(JitSpew_Range); Fprinter& out = JitSpewPrinter(); def->printName(out); @@ -203,7 +203,7 @@ RangeAnalysis::addBetaNodes() } else if (rightConst && rightConst->isTypeRepresentableAsDouble()) { bound = rightConst->numberToDouble(); val = left; - } else if (left->type() == MIRType_Int32 && right->type() == MIRType_Int32) { + } else if (left->type() == MIRType::Int32 && right->type() == MIRType::Int32) { MDefinition* smaller = nullptr; MDefinition* greater = nullptr; if (jsop == JSOP_LT) { @@ -242,7 +242,7 @@ RangeAnalysis::addBetaNodes() break; case JSOP_LT: // For integers, if x < c, the upper bound of x is c-1. - if (val->type() == MIRType_Int32) { + if (val->type() == MIRType::Int32) { int32_t intbound; if (NumberEqualsInt32(bound, &intbound) && SafeSub(intbound, 1, &intbound)) bound = intbound; @@ -258,7 +258,7 @@ RangeAnalysis::addBetaNodes() break; case JSOP_GT: // For integers, if x > c, the lower bound of x is c+1. - if (val->type() == MIRType_Int32) { + if (val->type() == MIRType::Int32) { int32_t intbound; if (NumberEqualsInt32(bound, &intbound) && SafeAdd(intbound, 1, &intbound)) bound = intbound; @@ -592,17 +592,17 @@ Range::Range(const MDefinition* def) // and truncation can increase range again. So doing wrapAround to // mimick a possible truncation. switch (def->type()) { - case MIRType_Int32: + case MIRType::Int32: // MToInt32 cannot truncate. So we can safely clamp. if (def->isToInt32()) clampToInt32(); else wrapAroundToInt32(); break; - case MIRType_Boolean: + case MIRType::Boolean: wrapAroundToBoolean(); break; - case MIRType_None: + case MIRType::None: MOZ_CRASH("Asking for the range of an instruction with no value"); default: break; @@ -612,13 +612,13 @@ Range::Range(const MDefinition* def) // because we don't care what value the instruction actually produces, // but what value we might get after we get past the bailouts. switch (def->type()) { - case MIRType_Int32: + case MIRType::Int32: setInt32(JSVAL_INT_MIN, JSVAL_INT_MAX); break; - case MIRType_Boolean: + case MIRType::Boolean: setInt32(0, 1); break; - case MIRType_None: + case MIRType::None: MOZ_CRASH("Asking for the range of an instruction with no value"); default: setUnknown(); @@ -627,14 +627,14 @@ Range::Range(const MDefinition* def) } // As a special case, MUrsh is permitted to claim a result type of - // MIRType_Int32 while actually returning values in [0,UINT32_MAX] without + // MIRType::Int32 while actually returning values in [0,UINT32_MAX] without // bailouts. If range analysis hasn't ruled out values in // (INT32_MAX,UINT32_MAX], set the range to be conservatively correct for // use as either a uint32 or an int32. if (!hasInt32UpperBound() && def->isUrsh() && def->toUrsh()->bailoutsDisabled() && - def->type() != MIRType_Int64) + def->type() != MIRType::Int64) { lower_ = INT32_MIN; } @@ -1250,7 +1250,7 @@ Range::update(const Range* other) void MPhi::computeRange(TempAllocator& alloc) { - if (type() != MIRType_Int32 && type() != MIRType_Double) + if (type() != MIRType::Int32 && type() != MIRType::Double) return; Range* range = nullptr; @@ -1297,7 +1297,7 @@ MConstant::computeRange(TempAllocator& alloc) if (isTypeRepresentableAsDouble()) { double d = numberToDouble(); setRange(Range::NewDoubleSingletonRange(alloc, d)); - } else if (type() == MIRType_Boolean) { + } else if (type() == MIRType::Boolean) { bool b = toBoolean(); setRange(Range::NewInt32Range(alloc, b, b)); } @@ -1319,7 +1319,7 @@ MClampToUint8::computeRange(TempAllocator& alloc) void MBitAnd::computeRange(TempAllocator& alloc) { - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return; Range left(getOperand(0)); @@ -1333,7 +1333,7 @@ MBitAnd::computeRange(TempAllocator& alloc) void MBitOr::computeRange(TempAllocator& alloc) { - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return; Range left(getOperand(0)); @@ -1347,7 +1347,7 @@ MBitOr::computeRange(TempAllocator& alloc) void MBitXor::computeRange(TempAllocator& alloc) { - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return; Range left(getOperand(0)); @@ -1370,7 +1370,7 @@ MBitNot::computeRange(TempAllocator& alloc) void MLsh::computeRange(TempAllocator& alloc) { - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return; Range left(getOperand(0)); @@ -1378,7 +1378,7 @@ MLsh::computeRange(TempAllocator& alloc) left.wrapAroundToInt32(); MConstant* rhsConst = getOperand(1)->maybeConstantValue(); - if (rhsConst && rhsConst->type() == MIRType_Int32) { + if (rhsConst && rhsConst->type() == MIRType::Int32) { int32_t c = rhsConst->toInt32(); setRange(Range::lsh(alloc, &left, c)); return; @@ -1391,7 +1391,7 @@ MLsh::computeRange(TempAllocator& alloc) void MRsh::computeRange(TempAllocator& alloc) { - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return; Range left(getOperand(0)); @@ -1399,7 +1399,7 @@ MRsh::computeRange(TempAllocator& alloc) left.wrapAroundToInt32(); MConstant* rhsConst = getOperand(1)->maybeConstantValue(); - if (rhsConst && rhsConst->type() == MIRType_Int32) { + if (rhsConst && rhsConst->type() == MIRType::Int32) { int32_t c = rhsConst->toInt32(); setRange(Range::rsh(alloc, &left, c)); return; @@ -1412,7 +1412,7 @@ MRsh::computeRange(TempAllocator& alloc) void MUrsh::computeRange(TempAllocator& alloc) { - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return; Range left(getOperand(0)); @@ -1427,7 +1427,7 @@ MUrsh::computeRange(TempAllocator& alloc) right.wrapAroundToShiftCount(); MConstant* rhsConst = getOperand(1)->maybeConstantValue(); - if (rhsConst && rhsConst->type() == MIRType_Int32) { + if (rhsConst && rhsConst->type() == MIRType::Int32) { int32_t c = rhsConst->toInt32(); setRange(Range::ursh(alloc, &left, c)); } else { @@ -1440,7 +1440,7 @@ MUrsh::computeRange(TempAllocator& alloc) void MAbs::computeRange(TempAllocator& alloc) { - if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double) + if (specialization_ != MIRType::Int32 && specialization_ != MIRType::Double) return; Range other(getOperand(0)); @@ -1485,7 +1485,7 @@ MPopcnt::computeRange(TempAllocator& alloc) void MMinMax::computeRange(TempAllocator& alloc) { - if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double) + if (specialization_ != MIRType::Int32 && specialization_ != MIRType::Double) return; Range left(getOperand(0)); @@ -1496,7 +1496,7 @@ MMinMax::computeRange(TempAllocator& alloc) void MAdd::computeRange(TempAllocator& alloc) { - if (specialization() != MIRType_Int32 && specialization() != MIRType_Double) + if (specialization() != MIRType::Int32 && specialization() != MIRType::Double) return; Range left(getOperand(0)); Range right(getOperand(1)); @@ -1509,7 +1509,7 @@ MAdd::computeRange(TempAllocator& alloc) void MSub::computeRange(TempAllocator& alloc) { - if (specialization() != MIRType_Int32 && specialization() != MIRType_Double) + if (specialization() != MIRType::Int32 && specialization() != MIRType::Double) return; Range left(getOperand(0)); Range right(getOperand(1)); @@ -1522,7 +1522,7 @@ MSub::computeRange(TempAllocator& alloc) void MMul::computeRange(TempAllocator& alloc) { - if (specialization() != MIRType_Int32 && specialization() != MIRType_Double) + if (specialization() != MIRType::Int32 && specialization() != MIRType::Double) return; Range left(getOperand(0)); Range right(getOperand(1)); @@ -1540,7 +1540,7 @@ MMul::computeRange(TempAllocator& alloc) void MMod::computeRange(TempAllocator& alloc) { - if (specialization() != MIRType_Int32 && specialization() != MIRType_Double) + if (specialization() != MIRType::Int32 && specialization() != MIRType::Double) return; Range lhs(getOperand(0)); Range rhs(getOperand(1)); @@ -1556,7 +1556,7 @@ MMod::computeRange(TempAllocator& alloc) // If both operands are non-negative integers, we can optimize this to an // unsigned mod. - if (specialization() == MIRType_Int32 && lhs.lower() >= 0 && rhs.lower() > 0 && + if (specialization() == MIRType::Int32 && lhs.lower() >= 0 && rhs.lower() > 0 && !lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart()) { unsigned_ = true; @@ -1635,7 +1635,7 @@ MMod::computeRange(TempAllocator& alloc) void MDiv::computeRange(TempAllocator& alloc) { - if (specialization() != MIRType_Int32 && specialization() != MIRType_Double) + if (specialization() != MIRType::Int32 && specialization() != MIRType::Double) return; Range lhs(getOperand(0)); Range rhs(getOperand(1)); @@ -2333,8 +2333,8 @@ RangeAnalysis::addRangeAssertions() // Perform range checking for all numeric and numeric-like types. if (!IsNumberType(ins->type()) && - ins->type() != MIRType_Boolean && - ins->type() != MIRType_Value) + ins->type() != MIRType::Boolean && + ins->type() != MIRType::Value) { continue; } @@ -2348,7 +2348,7 @@ RangeAnalysis::addRangeAssertions() Range r(ins); // Don't insert assertions if there's nothing interesting to assert. - if (r.isUnknown() || (ins->type() == MIRType_Int32 && r.isUnknownInt32())) + if (r.isUnknown() || (ins->type() == MIRType::Int32 && r.isUnknownInt32())) continue; // Don't add a use to an instruction that is recovered on bailout. @@ -2459,7 +2459,7 @@ MConstant::truncate() int32_t res = ToInt32(numberToDouble()); payload_.asBits = 0; payload_.i32 = res; - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); if (range()) range()->setInt32(res, res); } @@ -2467,7 +2467,7 @@ MConstant::truncate() bool MPhi::needTruncation(TruncateKind kind) { - if (type() == MIRType_Double || type() == MIRType_Int32) { + if (type() == MIRType::Double || type() == MIRType::Int32) { truncateKind_ = kind; return true; } @@ -2478,7 +2478,7 @@ MPhi::needTruncation(TruncateKind kind) void MPhi::truncate() { - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); if (truncateKind_ >= IndirectTruncate && range()) range()->wrapAroundToInt32(); } @@ -2489,15 +2489,15 @@ MAdd::needTruncation(TruncateKind kind) // Remember analysis, needed for fallible checks. setTruncateKind(kind); - return type() == MIRType_Double || type() == MIRType_Int32; + return type() == MIRType::Double || type() == MIRType::Int32; } void MAdd::truncate() { MOZ_ASSERT(needTruncation(truncateKind())); - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); if (truncateKind() >= IndirectTruncate && range()) range()->wrapAroundToInt32(); } @@ -2508,15 +2508,15 @@ MSub::needTruncation(TruncateKind kind) // Remember analysis, needed for fallible checks. setTruncateKind(kind); - return type() == MIRType_Double || type() == MIRType_Int32; + return type() == MIRType::Double || type() == MIRType::Int32; } void MSub::truncate() { MOZ_ASSERT(needTruncation(truncateKind())); - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); if (truncateKind() >= IndirectTruncate && range()) range()->wrapAroundToInt32(); } @@ -2527,15 +2527,15 @@ MMul::needTruncation(TruncateKind kind) // Remember analysis, needed for fallible checks. setTruncateKind(kind); - return type() == MIRType_Double || type() == MIRType_Int32; + return type() == MIRType::Double || type() == MIRType::Int32; } void MMul::truncate() { MOZ_ASSERT(needTruncation(truncateKind())); - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); if (truncateKind() >= IndirectTruncate) { setCanBeNegativeZero(false); if (range()) @@ -2549,15 +2549,15 @@ MDiv::needTruncation(TruncateKind kind) // Remember analysis, needed for fallible checks. setTruncateKind(kind); - return type() == MIRType_Double || type() == MIRType_Int32; + return type() == MIRType::Double || type() == MIRType::Int32; } void MDiv::truncate() { MOZ_ASSERT(needTruncation(truncateKind())); - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); // Divisions where the lhs and rhs are unsigned and the result is // truncated can be lowered more efficiently. @@ -2573,7 +2573,7 @@ MMod::needTruncation(TruncateKind kind) // Remember analysis, needed for fallible checks. setTruncateKind(kind); - return type() == MIRType_Double || type() == MIRType_Int32; + return type() == MIRType::Double || type() == MIRType::Int32; } void @@ -2581,8 +2581,8 @@ MMod::truncate() { // As for division, handle unsigned modulus with a truncated result. MOZ_ASSERT(needTruncation(truncateKind())); - specialization_ = MIRType_Int32; - setResultType(MIRType_Int32); + specialization_ = MIRType::Int32; + setResultType(MIRType::Int32); if (unsignedOperands()) { replaceWithUnsignedOperands(); @@ -2593,7 +2593,7 @@ MMod::truncate() bool MToDouble::needTruncation(TruncateKind kind) { - MOZ_ASSERT(type() == MIRType_Double); + MOZ_ASSERT(type() == MIRType::Double); setTruncateKind(kind); return true; @@ -2606,7 +2606,7 @@ MToDouble::truncate() // We use the return type to flag that this MToDouble should be replaced by // a MTruncateToInt32 when modifying the graph. - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); if (truncateKind() >= IndirectTruncate) { if (range()) range()->wrapAroundToInt32(); @@ -2629,7 +2629,7 @@ bool MLimitedTruncate::needTruncation(TruncateKind kind) { setTruncateKind(kind); - setResultType(MIRType_Int32); + setResultType(MIRType::Int32); if (kind >= IndirectTruncate && range()) range()->wrapAroundToInt32(); return false; @@ -2779,7 +2779,7 @@ TruncateTest(TempAllocator& alloc, MTest* test) // If all possible inputs to the test are either int32 or boolean, // convert those inputs to int32 so that an int32 test can be performed. - if (test->input()->type() != MIRType_Value) + if (test->input()->type() != MIRType::Value) return true; if (!test->input()->isPhi() || !test->input()->hasOneDefUse() || test->input()->isImplicitlyUsed()) @@ -2791,24 +2791,24 @@ TruncateTest(TempAllocator& alloc, MTest* test) if (!def->isBox()) return true; MDefinition* inner = def->getOperand(0); - if (inner->type() != MIRType_Boolean && inner->type() != MIRType_Int32) + if (inner->type() != MIRType::Boolean && inner->type() != MIRType::Int32) return true; } for (size_t i = 0; i < phi->numOperands(); i++) { MDefinition* inner = phi->getOperand(i)->getOperand(0); - if (inner->type() != MIRType_Int32) { + if (inner->type() != MIRType::Int32) { if (!alloc.ensureBallast()) return false; MBasicBlock* block = inner->block(); inner = MToInt32::New(alloc, inner); block->insertBefore(block->lastIns(), inner->toInstruction()); } - MOZ_ASSERT(inner->type() == MIRType_Int32); + MOZ_ASSERT(inner->type() == MIRType::Int32); phi->replaceOperand(i, inner); } - phi->setResultType(MIRType_Int32); + phi->setResultType(MIRType::Int32); return true; } @@ -2965,7 +2965,7 @@ ComputeTruncateKind(MDefinition* candidate, bool* shouldClone) // Special case integer division and modulo: a/b can be infinite, and a%b // can be NaN but cannot actually have rounding errors induced by truncation. if ((candidate->isDiv() || candidate->isMod()) && - static_cast(candidate)->specialization() == MIRType_Int32) + static_cast(candidate)->specialization() == MIRType::Int32) { canHaveRoundingErrors = false; } @@ -2984,7 +2984,7 @@ RemoveTruncatesOnOutput(MDefinition* truncated) if (truncated->isCompare()) return; - MOZ_ASSERT(truncated->type() == MIRType_Int32); + MOZ_ASSERT(truncated->type() == MIRType::Int32); MOZ_ASSERT(Range(truncated).isInt32()); for (MUseDefIterator use(truncated); use; use++) { @@ -3006,10 +3006,10 @@ AdjustTruncatedInputs(TempAllocator& alloc, MDefinition* truncated) continue; MDefinition* input = truncated->getOperand(i); - if (input->type() == MIRType_Int32) + if (input->type() == MIRType::Int32) continue; - if (input->isToDouble() && input->getOperand(0)->type() == MIRType_Int32) { + if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) { truncated->replaceOperand(i, input->getOperand(0)); } else { MInstruction* op; @@ -3063,7 +3063,7 @@ RangeAnalysis::truncate() if (iter->isRecoveredOnBailout()) continue; - if (iter->type() == MIRType_None) { + if (iter->type() == MIRType::None) { if (iter->isTest()) { if (!TruncateTest(alloc(), iter->toTest())) return false; @@ -3389,7 +3389,7 @@ MPowHalf::collectRangeInfoPreTrunc() void MUrsh::collectRangeInfoPreTrunc() { - if (specialization_ == MIRType_Int64) + if (specialization_ == MIRType::Int64) return; Range lhsRange(lhs()), rhsRange(rhs()); @@ -3429,13 +3429,13 @@ MBinaryBitwiseInstruction::collectRangeInfoPreTrunc() Range lhsRange(lhs()); Range rhsRange(rhs()); - if (lhs()->isConstant() && lhs()->type() == MIRType_Int32 && + if (lhs()->isConstant() && lhs()->type() == MIRType::Int32 && DoesMaskMatchRange(lhs()->toConstant()->toInt32(), rhsRange)) { maskMatchesRightRange = true; } - if (rhs()->isConstant() && rhs()->type() == MIRType_Int32 && + if (rhs()->isConstant() && rhs()->type() == MIRType::Int32 && DoesMaskMatchRange(rhs()->toConstant()->toInt32(), lhsRange)) { maskMatchesLeftRange = true; diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index c1333f9c94..5a3b24a8e8 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -337,7 +337,7 @@ MAdd::writeRecoverData(CompactBufferWriter& writer) const { MOZ_ASSERT(canRecoverOnBailout()); writer.writeUnsigned(uint32_t(RInstruction::Recover_Add)); - writer.writeByte(specialization_ == MIRType_Float32); + writer.writeByte(specialization_ == MIRType::Float32); return true; } @@ -357,7 +357,7 @@ RAdd::recover(JSContext* cx, SnapshotIterator& iter) const if (!js::AddValues(cx, &lhs, &rhs, &result)) return false; - // MIRType_Float32 is a specialization embedding the fact that the result is + // MIRType::Float32 is a specialization embedding the fact that the result is // rounded to a Float32. if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) return false; @@ -371,7 +371,7 @@ MSub::writeRecoverData(CompactBufferWriter& writer) const { MOZ_ASSERT(canRecoverOnBailout()); writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub)); - writer.writeByte(specialization_ == MIRType_Float32); + writer.writeByte(specialization_ == MIRType::Float32); return true; } @@ -391,7 +391,7 @@ RSub::recover(JSContext* cx, SnapshotIterator& iter) const if (!js::SubValues(cx, &lhs, &rhs, &result)) return false; - // MIRType_Float32 is a specialization embedding the fact that the result is + // MIRType::Float32 is a specialization embedding the fact that the result is // rounded to a Float32. if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) return false; @@ -405,7 +405,7 @@ MMul::writeRecoverData(CompactBufferWriter& writer) const { MOZ_ASSERT(canRecoverOnBailout()); writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul)); - writer.writeByte(specialization_ == MIRType_Float32); + writer.writeByte(specialization_ == MIRType::Float32); MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_); writer.writeByte(uint8_t(mode_)); return true; @@ -428,7 +428,7 @@ RMul::recover(JSContext* cx, SnapshotIterator& iter) const if (!js::MulValues(cx, &lhs, &rhs, &result)) return false; - // MIRType_Float32 is a specialization embedding the fact that the + // MIRType::Float32 is a specialization embedding the fact that the // result is rounded to a Float32. if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) return false; @@ -447,7 +447,7 @@ MDiv::writeRecoverData(CompactBufferWriter& writer) const { MOZ_ASSERT(canRecoverOnBailout()); writer.writeUnsigned(uint32_t(RInstruction::Recover_Div)); - writer.writeByte(specialization_ == MIRType_Float32); + writer.writeByte(specialization_ == MIRType::Float32); return true; } @@ -466,7 +466,7 @@ RDiv::recover(JSContext* cx, SnapshotIterator& iter) const if (!js::DivValues(cx, &lhs, &rhs, &result)) return false; - // MIRType_Float32 is a specialization embedding the fact that the result is + // MIRType::Float32 is a specialization embedding the fact that the result is // rounded to a Float32. if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) return false; @@ -830,7 +830,7 @@ MSqrt::writeRecoverData(CompactBufferWriter& writer) const { MOZ_ASSERT(canRecoverOnBailout()); writer.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt)); - writer.writeByte(type() == MIRType_Float32); + writer.writeByte(type() == MIRType::Float32); return true; } @@ -849,7 +849,7 @@ RSqrt::recover(JSContext* cx, SnapshotIterator& iter) const if (!math_sqrt_handle(cx, num, &result)) return false; - // MIRType_Float32 is a specialization embedding the fact that the result is + // MIRType::Float32 is a specialization embedding the fact that the result is // rounded to a Float32. if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) return false; diff --git a/js/src/jit/RegisterSets.h b/js/src/jit/RegisterSets.h index 0437d249dd..c66baf4c46 100644 --- a/js/src/jit/RegisterSets.h +++ b/js/src/jit/RegisterSets.h @@ -196,7 +196,7 @@ class TypedOrValueRegister public: TypedOrValueRegister() - : type_(MIRType_None) + : type_(MIRType::None) {} TypedOrValueRegister(MIRType type, AnyRegister reg) @@ -206,7 +206,7 @@ class TypedOrValueRegister } MOZ_IMPLICIT TypedOrValueRegister(ValueOperand value) - : type_(MIRType_Value) + : type_(MIRType::Value) { dataValue() = value; } @@ -216,11 +216,11 @@ class TypedOrValueRegister } bool hasTyped() const { - return type() != MIRType_None && type() != MIRType_Value; + return type() != MIRType::None && type() != MIRType::Value; } bool hasValue() const { - return type() == MIRType_Value; + return type() == MIRType::Value; } AnyRegister typedReg() const { diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index e2f38a925a..6596080671 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -142,7 +142,7 @@ IsLambdaEscaped(MLambda* lambda, JSObject* obj) static bool IsObjectEscaped(MInstruction* ins, JSObject* objDefault) { - MOZ_ASSERT(ins->type() == MIRType_Object); + MOZ_ASSERT(ins->type() == MIRType::Object); MOZ_ASSERT(ins->isNewObject() || ins->isGuardShape() || ins->isCreateThisWithTemplate() || ins->isNewCallObject() || ins->isFunctionEnvironment()); @@ -781,7 +781,7 @@ IndexOf(MDefinition* ins, int32_t* res) if (indexDef->isToInt32()) indexDef = indexDef->toToInt32()->getOperand(0); MConstant* indexDefConst = indexDef->maybeConstantValue(); - if (!indexDefConst || indexDefConst->type() != MIRType_Int32) + if (!indexDefConst || indexDefConst->type() != MIRType::Int32) return false; *res = indexDefConst->toInt32(); return true; @@ -796,7 +796,7 @@ IsElementEscaped(MElements* def, uint32_t arraySize) JitSpewIndent spewIndent(JitSpew_Escape); for (MUseIterator i(def->usesBegin()); i != def->usesEnd(); i++) { - // The MIRType_Elements cannot be captured in a resume point as + // The MIRType::Elements cannot be captured in a resume point as // it does not represent a value allocation. MDefinition* access = (*i)->consumer()->toDefinition(); @@ -858,7 +858,7 @@ IsElementEscaped(MElements* def, uint32_t arraySize) } // We are not yet encoding magic hole constants in resume points. - if (access->toStoreElement()->value()->type() == MIRType_MagicHole) { + if (access->toStoreElement()->value()->type() == MIRType::MagicHole) { JitSpewDef(JitSpew_Escape, "has a store element with an magic-hole constant\n", access); return true; } @@ -894,7 +894,7 @@ IsElementEscaped(MElements* def, uint32_t arraySize) static bool IsArrayEscaped(MInstruction* ins) { - MOZ_ASSERT(ins->type() == MIRType_Object); + MOZ_ASSERT(ins->type() == MIRType::Object); MOZ_ASSERT(ins->isNewArray()); uint32_t length = ins->toNewArray()->length(); diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp index 9f3d361b29..44bde5a9e1 100644 --- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -21,7 +21,7 @@ static void EnsureOperandNotFloat32(TempAllocator& alloc, MInstruction* def, unsigned op) { MDefinition* in = def->getOperand(op); - if (in->type() == MIRType_Float32) { + if (in->type() == MIRType::Float32) { MToDouble* replace = MToDouble::New(alloc, in); def->block()->insertBefore(def, replace); if (def->isRecoveredOnBailout()) @@ -35,7 +35,7 @@ js::jit::AlwaysBoxAt(TempAllocator& alloc, MInstruction* at, MDefinition* operan { MDefinition* boxedOperand = operand; // Replace Float32 by double - if (operand->type() == MIRType_Float32) { + if (operand->type() == MIRType::Float32) { MInstruction* replace = MToDouble::New(alloc, operand); at->block()->insertBefore(at, replace); boxedOperand = replace; @@ -58,7 +58,7 @@ BoxInputsPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) { for (size_t i = 0, e = ins->numOperands(); i < e; i++) { MDefinition* in = ins->getOperand(i); - if (in->type() == MIRType_Value) + if (in->type() == MIRType::Value) continue; ins->replaceOperand(i, BoxAt(alloc, ins, in)); } @@ -69,10 +69,10 @@ bool ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { MIRType specialization = ins->typePolicySpecialization(); - if (specialization == MIRType_None) + if (specialization == MIRType::None) return BoxInputsPolicy::staticAdjustInputs(alloc, ins); - MOZ_ASSERT(ins->type() == MIRType_Double || ins->type() == MIRType_Int32 || ins->type() == MIRType_Float32); + MOZ_ASSERT(ins->type() == MIRType::Double || ins->type() == MIRType::Int32 || ins->type() == MIRType::Float32); for (size_t i = 0, e = ins->numOperands(); i < e; i++) { MDefinition* in = ins->getOperand(i); @@ -81,9 +81,9 @@ ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) MInstruction* replace; - if (ins->type() == MIRType_Double) + if (ins->type() == MIRType::Double) replace = MToDouble::New(alloc, in); - else if (ins->type() == MIRType_Float32) + else if (ins->type() == MIRType::Float32) replace = MToFloat32::New(alloc, in); else replace = MToInt32::New(alloc, in); @@ -103,7 +103,7 @@ AllDoublePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { for (size_t i = 0, e = ins->numOperands(); i < e; i++) { MDefinition* in = ins->getOperand(i); - if (in->type() == MIRType_Double) + if (in->type() == MIRType::Double) continue; if (!alloc.ensureBallast()) @@ -129,7 +129,7 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) // Convert Float32 operands to doubles for (size_t i = 0; i < 2; i++) { MDefinition* in = def->getOperand(i); - if (in->type() == MIRType_Float32) { + if (in->type() == MIRType::Float32) { MInstruction* replace = MToDouble::New(alloc, in); def->block()->insertBefore(def, replace); def->replaceOperand(i, replace); @@ -148,7 +148,7 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) // This matches other comparisons of the form bool === bool and // generated code of Compare_Int32 is more efficient. if (compare->compareType() == MCompare::Compare_Boolean && - def->getOperand(0)->type() == MIRType_Boolean) + def->getOperand(0)->type() == MIRType::Boolean) { compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth); } @@ -158,23 +158,23 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) if (compare->compareType() == MCompare::Compare_Boolean) { // Unbox rhs that is definitely Boolean MDefinition* rhs = def->getOperand(1); - if (rhs->type() != MIRType_Boolean) { - MInstruction* unbox = MUnbox::New(alloc, rhs, MIRType_Boolean, MUnbox::Infallible); + if (rhs->type() != MIRType::Boolean) { + MInstruction* unbox = MUnbox::New(alloc, rhs, MIRType::Boolean, MUnbox::Infallible); def->block()->insertBefore(def, unbox); def->replaceOperand(1, unbox); if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) return false; } - MOZ_ASSERT(def->getOperand(0)->type() != MIRType_Boolean); - MOZ_ASSERT(def->getOperand(1)->type() == MIRType_Boolean); + MOZ_ASSERT(def->getOperand(0)->type() != MIRType::Boolean); + MOZ_ASSERT(def->getOperand(1)->type() == MIRType::Boolean); return true; } // Compare_StrictString specialization is done for "Anything === String" // If the LHS is string, we set the specialization to Compare_String. if (compare->compareType() == MCompare::Compare_StrictString && - def->getOperand(0)->type() == MIRType_String) + def->getOperand(0)->type() == MIRType::String) { compare->setCompareType(MCompare::Compare_String); } @@ -184,16 +184,16 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) if (compare->compareType() == MCompare::Compare_StrictString) { // Unbox rhs that is definitely String MDefinition* rhs = def->getOperand(1); - if (rhs->type() != MIRType_String) { - MInstruction* unbox = MUnbox::New(alloc, rhs, MIRType_String, MUnbox::Infallible); + if (rhs->type() != MIRType::String) { + MInstruction* unbox = MUnbox::New(alloc, rhs, MIRType::String, MUnbox::Infallible); def->block()->insertBefore(def, unbox); def->replaceOperand(1, unbox); if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) return false; } - MOZ_ASSERT(def->getOperand(0)->type() != MIRType_String); - MOZ_ASSERT(def->getOperand(1)->type() == MIRType_String); + MOZ_ASSERT(def->getOperand(0)->type() != MIRType::String); + MOZ_ASSERT(def->getOperand(1)->type() == MIRType::String); return true; } @@ -206,8 +206,8 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) // Convert all inputs to the right input type MIRType type = compare->inputType(); - MOZ_ASSERT(type == MIRType_Int32 || type == MIRType_Double || - type == MIRType_Object || type == MIRType_String || type == MIRType_Float32); + MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Double || + type == MIRType::Object || type == MIRType::String || type == MIRType::Float32); for (size_t i = 0; i < 2; i++) { MDefinition* in = def->getOperand(i); if (in->type() == type) @@ -216,7 +216,7 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) MInstruction* replace; switch (type) { - case MIRType_Double: { + case MIRType::Double: { MToFPInstruction::ConversionKind convert = MToFPInstruction::NumbersOnly; if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) convert = MToFPInstruction::NonNullNonStringPrimitives; @@ -225,7 +225,7 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) replace = MToDouble::New(alloc, in, convert); break; } - case MIRType_Float32: { + case MIRType::Float32: { MToFPInstruction::ConversionKind convert = MToFPInstruction::NumbersOnly; if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) convert = MToFPInstruction::NonNullNonStringPrimitives; @@ -234,7 +234,7 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) replace = MToFloat32::New(alloc, in, convert); break; } - case MIRType_Int32: { + case MIRType::Int32: { MacroAssembler::IntConversionInputKind convert = MacroAssembler::IntConversion_NumbersOnly; if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth || (compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS && i == 0) || @@ -245,11 +245,11 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) replace = MToInt32::New(alloc, in, convert); break; } - case MIRType_Object: - replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible); + case MIRType::Object: + replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Infallible); break; - case MIRType_String: - replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Infallible); + case MIRType::String: + replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Infallible); break; default: MOZ_CRASH("Unknown compare specialization"); @@ -277,16 +277,16 @@ TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) return true; // Output is a value, currently box the input. - if (outputType == MIRType_Value) { + if (outputType == MIRType::Value) { // XXX: Possible optimization: decrease resultTypeSet to only include // the inputType. This will remove the need for boxing. - MOZ_ASSERT(inputType != MIRType_Value); + MOZ_ASSERT(inputType != MIRType::Value); ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); return true; } // Box input if needed. - if (inputType != MIRType_Value) { + if (inputType != MIRType::Value) { MOZ_ASSERT(ins->alwaysBails()); ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); } @@ -295,9 +295,9 @@ TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) // also a value. // Note: Using setResultType shouldn't be done in TypePolicies, // Here it is fine, since the type barrier has no uses. - if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) { + if (IsNullOrUndefined(outputType) || outputType == MIRType::MagicOptimizedArguments) { MOZ_ASSERT(!ins->hasDefUses()); - ins->setResultType(MIRType_Value); + ins->setResultType(MIRType::Value); return true; } @@ -325,18 +325,18 @@ TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { MDefinition* op = ins->getOperand(0); switch (op->type()) { - case MIRType_Value: - case MIRType_Null: - case MIRType_Undefined: - case MIRType_Boolean: - case MIRType_Int32: - case MIRType_Double: - case MIRType_Float32: - case MIRType_Symbol: - case MIRType_Object: + case MIRType::Value: + case MIRType::Null: + case MIRType::Undefined: + case MIRType::Boolean: + case MIRType::Int32: + case MIRType::Double: + case MIRType::Float32: + case MIRType::Symbol: + case MIRType::Object: break; - case MIRType_String: + case MIRType::String: { MStringLength* length = MStringLength::New(alloc, op); ins->block()->insertBefore(ins, length); @@ -355,16 +355,16 @@ bool BitwisePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { MIRType specialization = ins->typePolicySpecialization(); - if (specialization == MIRType_None) + if (specialization == MIRType::None) return BoxInputsPolicy::staticAdjustInputs(alloc, ins); MOZ_ASSERT(ins->type() == specialization); - MOZ_ASSERT(specialization == MIRType_Int32 || specialization == MIRType_Double); + MOZ_ASSERT(specialization == MIRType::Int32 || specialization == MIRType::Double); // This policy works for both unary and binary bitwise operations. for (size_t i = 0, e = ins->numOperands(); i < e; i++) { MDefinition* in = ins->getOperand(i); - if (in->type() == MIRType_Int32) + if (in->type() == MIRType::Int32) continue; MInstruction* replace = MTruncateToInt32::New(alloc, in); @@ -382,14 +382,14 @@ bool PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { MIRType specialization = ins->typePolicySpecialization(); - MOZ_ASSERT(specialization == MIRType_Int32 || specialization == MIRType_Double); + MOZ_ASSERT(specialization == MIRType::Int32 || specialization == MIRType::Double); // Input must be a double. if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins)) return false; // Power may be an int32 or a double. Integers receive a faster path. - if (specialization == MIRType_Double) + if (specialization == MIRType::Double) return DoublePolicy<1>::staticAdjustInputs(alloc, ins); return IntPolicy<1>::staticAdjustInputs(alloc, ins); } @@ -399,10 +399,10 @@ bool StringPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) { MDefinition* in = ins->getOperand(Op); - if (in->type() == MIRType_String) + if (in->type() == MIRType::String) return true; - MUnbox* replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible); + MUnbox* replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Fallible); ins->block()->insertBefore(ins, replace); ins->replaceOperand(Op, replace); @@ -418,7 +418,7 @@ bool ConvertToStringPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) { MDefinition* in = ins->getOperand(Op); - if (in->type() == MIRType_String) + if (in->type() == MIRType::String) return true; MToString* replace = MToString::New(alloc, in); @@ -440,10 +440,10 @@ bool BooleanPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) { MDefinition* in = def->getOperand(Op); - if (in->type() == MIRType_Boolean) + if (in->type() == MIRType::Boolean) return true; - MUnbox* replace = MUnbox::New(alloc, in, MIRType_Boolean, MUnbox::Fallible); + MUnbox* replace = MUnbox::New(alloc, in, MIRType::Boolean, MUnbox::Fallible); def->block()->insertBefore(def, replace); def->replaceOperand(Op, replace); @@ -457,10 +457,10 @@ bool IntPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) { MDefinition* in = def->getOperand(Op); - if (in->type() == MIRType_Int32) + if (in->type() == MIRType::Int32) return true; - MUnbox* replace = MUnbox::New(alloc, in, MIRType_Int32, MUnbox::Fallible); + MUnbox* replace = MUnbox::New(alloc, in, MIRType::Int32, MUnbox::Fallible); def->block()->insertBefore(def, replace); def->replaceOperand(Op, replace); @@ -477,7 +477,7 @@ bool ConvertToInt32Policy::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) { MDefinition* in = def->getOperand(Op); - if (in->type() == MIRType_Int32) + if (in->type() == MIRType::Int32) return true; MToInt32* replace = MToInt32::New(alloc, in); @@ -494,7 +494,7 @@ bool TruncateToInt32Policy::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) { MDefinition* in = def->getOperand(Op); - if (in->type() == MIRType_Int32) + if (in->type() == MIRType::Int32) return true; MTruncateToInt32* replace = MTruncateToInt32::New(alloc, in); @@ -512,7 +512,7 @@ bool DoublePolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) { MDefinition* in = def->getOperand(Op); - if (in->type() == MIRType_Double || in->type() == MIRType_SinCosDouble) + if (in->type() == MIRType::Double || in->type() == MIRType::SinCosDouble) return true; MToDouble* replace = MToDouble::New(alloc, in); @@ -530,7 +530,7 @@ bool Float32Policy::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) { MDefinition* in = def->getOperand(Op); - if (in->type() == MIRType_Float32) + if (in->type() == MIRType::Float32) return true; MToFloat32* replace = MToFloat32::New(alloc, in); @@ -549,7 +549,7 @@ bool FloatingPointPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) { MIRType policyType = def->typePolicySpecialization(); - if (policyType == MIRType_Double) + if (policyType == MIRType::Double) return DoublePolicy::staticAdjustInputs(alloc, def); return Float32Policy::staticAdjustInputs(alloc, def); } @@ -592,9 +592,9 @@ SimdScalarPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins // A vector with boolean lanes requires Int32 inputs that have already been // converted to 0/-1. - // We can't insert a MIRType_Boolean lane directly - it requires conversion. - if (laneType == MIRType_Boolean) { - MOZ_ASSERT(in->type() == MIRType_Int32, "Boolean SIMD vector requires Int32 lanes."); + // We can't insert a MIRType::Boolean lane directly - it requires conversion. + if (laneType == MIRType::Boolean) { + MOZ_ASSERT(in->type() == MIRType::Int32, "Boolean SIMD vector requires Int32 lanes."); return true; } @@ -602,10 +602,10 @@ SimdScalarPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins return true; MInstruction* replace; - if (laneType == MIRType_Int32) { + if (laneType == MIRType::Int32) { replace = MTruncateToInt32::New(alloc, in); } else { - MOZ_ASSERT(laneType == MIRType_Float32); + MOZ_ASSERT(laneType == MIRType::Float32); replace = MToFloat32::New(alloc, in); } @@ -625,7 +625,7 @@ bool BoxPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) { MDefinition* in = ins->getOperand(Op); - if (in->type() == MIRType_Value) + if (in->type() == MIRType::Value) return true; ins->replaceOperand(Op, BoxAt(alloc, ins, in)); @@ -646,11 +646,11 @@ BoxExceptPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction return BoxPolicy::staticAdjustInputs(alloc, ins); } -template bool BoxExceptPolicy<0, MIRType_String>::staticAdjustInputs(TempAllocator& alloc, +template bool BoxExceptPolicy<0, MIRType::String>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); -template bool BoxExceptPolicy<1, MIRType_String>::staticAdjustInputs(TempAllocator& alloc, +template bool BoxExceptPolicy<1, MIRType::String>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); -template bool BoxExceptPolicy<2, MIRType_String>::staticAdjustInputs(TempAllocator& alloc, +template bool BoxExceptPolicy<2, MIRType::String>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); template @@ -659,9 +659,9 @@ CacheIdPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) { MDefinition* in = ins->getOperand(Op); switch (in->type()) { - case MIRType_Int32: - case MIRType_String: - case MIRType_Symbol: + case MIRType::Int32: + case MIRType::String: + case MIRType::Symbol: return true; default: return BoxPolicy::staticAdjustInputs(alloc, ins); @@ -683,28 +683,28 @@ ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) conversion = ins->toToFloat32()->conversion(); switch (in->type()) { - case MIRType_Int32: - case MIRType_Float32: - case MIRType_Double: - case MIRType_Value: + case MIRType::Int32: + case MIRType::Float32: + case MIRType::Double: + case MIRType::Value: // No need for boxing for these types. return true; - case MIRType_Null: + case MIRType::Null: // No need for boxing, when we will convert. if (conversion == MToFPInstruction::NonStringPrimitives) return true; break; - case MIRType_Undefined: - case MIRType_Boolean: + case MIRType::Undefined: + case MIRType::Boolean: // No need for boxing, when we will convert. if (conversion == MToFPInstruction::NonStringPrimitives) return true; if (conversion == MToFPInstruction::NonNullNonStringPrimitives) return true; break; - case MIRType_Object: - case MIRType_String: - case MIRType_Symbol: + case MIRType::Object: + case MIRType::String: + case MIRType::Symbol: // Objects might be effectful. Symbols give TypeError. break; default: @@ -727,32 +727,32 @@ ToInt32Policy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) MDefinition* in = ins->getOperand(0); switch (in->type()) { - case MIRType_Int32: - case MIRType_Float32: - case MIRType_Double: - case MIRType_Value: + case MIRType::Int32: + case MIRType::Float32: + case MIRType::Double: + case MIRType::Value: // No need for boxing for these types. return true; - case MIRType_Undefined: + case MIRType::Undefined: // No need for boxing when truncating. if (ins->isTruncateToInt32()) return true; break; - case MIRType_Null: + case MIRType::Null: // No need for boxing, when we will convert. if (conversion == MacroAssembler::IntConversion_Any) return true; break; - case MIRType_Boolean: + case MIRType::Boolean: // No need for boxing, when we will convert. if (conversion == MacroAssembler::IntConversion_Any) return true; if (conversion == MacroAssembler::IntConversion_NumbersOrBoolsOnly) return true; break; - case MIRType_Object: - case MIRType_String: - case MIRType_Symbol: + case MIRType::Object: + case MIRType::String: + case MIRType::Symbol: // Objects might be effectful. Symbols give TypeError. break; default: @@ -770,7 +770,7 @@ ToStringPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) MOZ_ASSERT(ins->isToString()); MIRType type = ins->getOperand(0)->type(); - if (type == MIRType_Object || type == MIRType_Symbol) { + if (type == MIRType::Object || type == MIRType::Symbol) { ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); return true; } @@ -786,13 +786,13 @@ bool ObjectPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) { MDefinition* in = ins->getOperand(Op); - if (in->type() == MIRType_Object || in->type() == MIRType_Slots || - in->type() == MIRType_Elements) + if (in->type() == MIRType::Object || in->type() == MIRType::Slots || + in->type() == MIRType::Elements) { return true; } - MUnbox* replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Fallible); + MUnbox* replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Fallible); ins->block()->insertBefore(ins, replace); ins->replaceOperand(Op, replace); @@ -847,7 +847,7 @@ SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) // Next inputs are the lanes, which need to be int32 for (unsigned i = 0; i < s->numLanes(); i++) { MDefinition* in = ins->getOperand(s->numVectors() + i); - if (in->type() == MIRType_Int32) + if (in->type() == MIRType::Int32) continue; MInstruction* replace = MToInt32::New(alloc, in, MacroAssembler::IntConversion_NumbersOnly); @@ -864,7 +864,7 @@ bool SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { // First input is the mask, which has to be a bool32x4. - MOZ_ASSERT(ins->getOperand(0)->type() == MIRType_Bool32x4); + MOZ_ASSERT(ins->getOperand(0)->type() == MIRType::Bool32x4); // Next inputs are the two vectors of a particular type. for (unsigned i = 1; i < 3; i++) @@ -879,8 +879,8 @@ CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) MCall* call = ins->toCall(); MDefinition* func = call->getFunction(); - if (func->type() != MIRType_Object) { - MInstruction* unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible); + if (func->type() != MIRType::Object) { + MInstruction* unbox = MUnbox::New(alloc, func, MIRType::Object, MUnbox::Fallible); call->block()->insertBefore(call, unbox); call->replaceFunction(unbox); @@ -906,7 +906,7 @@ CallSetElementPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) // Box the index and value operands. for (size_t i = 1, e = ins->numOperands(); i < e; i++) { MDefinition* in = ins->getOperand(i); - if (in->type() == MIRType_Value) + if (in->type() == MIRType::Value) continue; ins->replaceOperand(i, BoxAt(alloc, ins, in)); } @@ -917,7 +917,7 @@ bool InstanceOfPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) { // Box first operand if it isn't object - if (def->getOperand(0)->type() != MIRType_Object) + if (def->getOperand(0)->type() != MIRType::Object) BoxPolicy<0>::staticAdjustInputs(alloc, def); return true; @@ -939,25 +939,25 @@ StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, MInstruction* i // First, ensure the value is int32, boolean, double or Value. // The conversion is based on TypedArrayObjectTemplate::setElementTail. switch (value->type()) { - case MIRType_Int32: - case MIRType_Double: - case MIRType_Float32: - case MIRType_Boolean: - case MIRType_Value: + case MIRType::Int32: + case MIRType::Double: + case MIRType::Float32: + case MIRType::Boolean: + case MIRType::Value: break; - case MIRType_Null: + case MIRType::Null: value->setImplicitlyUsedUnchecked(); value = MConstant::New(alloc, Int32Value(0)); ins->block()->insertBefore(ins, value->toInstruction()); break; - case MIRType_Undefined: + case MIRType::Undefined: value->setImplicitlyUsedUnchecked(); value = MConstant::New(alloc, DoubleNaNValue()); ins->block()->insertBefore(ins, value->toInstruction()); break; - case MIRType_Object: - case MIRType_String: - case MIRType_Symbol: + case MIRType::Object: + case MIRType::String: + case MIRType::Symbol: value = BoxAt(alloc, ins, value); break; default: @@ -969,11 +969,11 @@ StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, MInstruction* i curValue = value; } - MOZ_ASSERT(value->type() == MIRType_Int32 || - value->type() == MIRType_Boolean || - value->type() == MIRType_Double || - value->type() == MIRType_Float32 || - value->type() == MIRType_Value); + MOZ_ASSERT(value->type() == MIRType::Int32 || + value->type() == MIRType::Boolean || + value->type() == MIRType::Double || + value->type() == MIRType::Float32 || + value->type() == MIRType::Value); switch (writeType) { case Scalar::Int8: @@ -982,23 +982,23 @@ StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, MInstruction* i case Scalar::Uint16: case Scalar::Int32: case Scalar::Uint32: - if (value->type() != MIRType_Int32) { + if (value->type() != MIRType::Int32) { value = MTruncateToInt32::New(alloc, value); ins->block()->insertBefore(ins, value->toInstruction()); } break; case Scalar::Uint8Clamped: // IonBuilder should have inserted ClampToUint8. - MOZ_ASSERT(value->type() == MIRType_Int32); + MOZ_ASSERT(value->type() == MIRType::Int32); break; case Scalar::Float32: - if (value->type() != MIRType_Float32) { + if (value->type() != MIRType::Float32) { value = MToFloat32::New(alloc, value); ins->block()->insertBefore(ins, value->toInstruction()); } break; case Scalar::Float64: - if (value->type() != MIRType_Double) { + if (value->type() != MIRType::Double) { value = MToDouble::New(alloc, value); ins->block()->insertBefore(ins, value->toInstruction()); } @@ -1020,7 +1020,7 @@ StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) MStoreUnboxedScalar* store = ins->toStoreUnboxedScalar(); MOZ_ASSERT(IsValidElementsType(store->elements(), store->offsetAdjustment())); - MOZ_ASSERT(store->index()->type() == MIRType_Int32); + MOZ_ASSERT(store->index()->type() == MIRType::Int32); return adjustValueInput(alloc, store, store->writeType(), store->value(), 2); } @@ -1029,9 +1029,9 @@ bool StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { MStoreTypedArrayElementHole* store = ins->toStoreTypedArrayElementHole(); - MOZ_ASSERT(store->elements()->type() == MIRType_Elements); - MOZ_ASSERT(store->index()->type() == MIRType_Int32); - MOZ_ASSERT(store->length()->type() == MIRType_Int32); + MOZ_ASSERT(store->elements()->type() == MIRType::Elements); + MOZ_ASSERT(store->index()->type() == MIRType::Int32); + MOZ_ASSERT(store->length()->type() == MIRType::Int32); return StoreUnboxedScalarPolicy::adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3); } @@ -1056,14 +1056,14 @@ StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc, MInstruction* // and whatever its new value is, unless the value is definitely null. MStoreUnboxedObjectOrNull* store = ins->toStoreUnboxedObjectOrNull(); - MOZ_ASSERT(store->typedObj()->type() == MIRType_Object); + MOZ_ASSERT(store->typedObj()->type() == MIRType::Object); MDefinition* value = store->value(); - if (value->type() == MIRType_Object || - value->type() == MIRType_Null || - value->type() == MIRType_ObjectOrNull) + if (value->type() == MIRType::Object || + value->type() == MIRType::Null || + value->type() == MIRType::ObjectOrNull) { - if (value->type() != MIRType_Null) { + if (value->type() != MIRType::Null) { MInstruction* barrier = MPostWriteBarrier::New(alloc, store->typedObj(), value); store->block()->insertBefore(store, barrier); } @@ -1089,9 +1089,9 @@ ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) MDefinition* in = ins->toClampToUint8()->input(); switch (in->type()) { - case MIRType_Int32: - case MIRType_Double: - case MIRType_Value: + case MIRType::Int32: + case MIRType::Double: + case MIRType::Value: break; default: ins->replaceOperand(0, BoxAt(alloc, ins, in)); @@ -1109,14 +1109,14 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) MIRType outputType = ins->type(); // Special case when output is a Float32, but input isn't. - if (outputType == MIRType_Float32 && inputType != MIRType_Float32) { + if (outputType == MIRType::Float32 && inputType != MIRType::Float32) { // Create a MToFloat32 to add between the MFilterTypeSet and // its uses. MInstruction* replace = MToFloat32::New(alloc, ins); ins->justReplaceAllUsesWithExcept(replace); ins->block()->insertAfter(ins, replace); - // Reset the type to not MIRType_Float32 + // Reset the type to not MIRType::Float32 // Note: setResultType shouldn't happen in TypePolicies, // Here it is fine, since there is just one use we just // added ourself. And the resulting type after MToFloat32 @@ -1137,8 +1137,8 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) return true; // Output is a value, box the input. - if (outputType == MIRType_Value) { - MOZ_ASSERT(inputType != MIRType_Value); + if (outputType == MIRType::Value) { + MOZ_ASSERT(inputType != MIRType::Value); ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); return true; } @@ -1146,7 +1146,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) // The outputType should be a subset of the inputType else we are in code // that has never executed yet. Bail to see the new type (if that hasn't // happened yet). - if (inputType != MIRType_Value) { + if (inputType != MIRType::Value) { MBail* bail = MBail::New(alloc); ins->block()->insertBefore(ins, bail); bail->setDependency(ins->dependency()); @@ -1158,9 +1158,9 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) // also a value. // Note: Using setResultType shouldn't be done in TypePolicies, // Here it is fine, since the type barrier has no uses. - if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) { + if (IsNullOrUndefined(outputType) || outputType == MIRType::MagicOptimizedArguments) { MOZ_ASSERT(!ins->hasDefUses()); - ins->setResultType(MIRType_Value); + ins->setResultType(MIRType::Value); return true; } @@ -1206,7 +1206,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) _(TypeBarrierPolicy) #define TEMPLATE_TYPE_POLICY_LIST(_) \ - _(BoxExceptPolicy<0, MIRType_String>) \ + _(BoxExceptPolicy<0, MIRType::String>) \ _(BoxPolicy<0>) \ _(ConvertToInt32Policy<0>) \ _(ConvertToStringPolicy<0>) \ diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 875347273d..790c748335 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -611,17 +611,19 @@ PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index) { MOZ_ASSERT(!IsInsideNursery(obj)); if (obj->is() && + !obj->as().isInWholeCellBuffer() && uint32_t(index) < obj->as().getDenseInitializedLength() && (obj->as().getDenseInitializedLength() > MAX_WHOLE_CELL_BUFFER_SIZE #ifdef JS_GC_ZEAL || rt->hasZealMode(gc::ZealMode::ElementsBarrier) #endif - )) + )) { rt->gc.storeBuffer.putSlot(&obj->as(), HeapSlot::Element, index, 1); - } else { - rt->gc.storeBuffer.putWholeCell(obj); + return; } + + rt->gc.storeBuffer.putWholeCell(obj); } void diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index c1afd80fce..1c5fb08e13 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -716,15 +716,15 @@ inline void* IonMarkFunction(MIRType type) { switch (type) { - case MIRType_Value: + case MIRType::Value: return JS_FUNC_TO_DATA_PTR(void*, MarkValueFromIon); - case MIRType_String: + case MIRType::String: return JS_FUNC_TO_DATA_PTR(void*, MarkStringFromIon); - case MIRType_Object: + case MIRType::Object: return JS_FUNC_TO_DATA_PTR(void*, MarkObjectFromIon); - case MIRType_Shape: + case MIRType::Shape: return JS_FUNC_TO_DATA_PTR(void*, MarkShapeFromIon); - case MIRType_ObjectGroup: + case MIRType::ObjectGroup: return JS_FUNC_TO_DATA_PTR(void*, MarkObjectGroupFromIon); default: MOZ_CRASH(); } diff --git a/js/src/jit/ValueNumbering.cpp b/js/src/jit/ValueNumbering.cpp index 5313eba604..e8b245274b 100644 --- a/js/src/jit/ValueNumbering.cpp +++ b/js/src/jit/ValueNumbering.cpp @@ -757,7 +757,7 @@ ValueNumberer::visitDefinition(MDefinition* def) // If this instruction has a dependency() into an unreachable block, we'll // need to update AliasAnalysis. - MInstruction* dep = def->dependency(); + MDefinition* dep = def->dependency(); if (dep != nullptr && (dep->isDiscarded() || dep->block()->isDead())) { JitSpew(JitSpew_GVN, " AliasAnalysis invalidated"); if (updateAliasAnalysis_ && !dependenciesBroken_) { diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index 4dc3855fdd..e452ca3ab1 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -47,8 +47,8 @@ ABIArg ABIArgGenerator::softNext(MIRType type) { switch (type) { - case MIRType_Int32: - case MIRType_Pointer: + case MIRType::Int32: + case MIRType::Pointer: if (intRegIndex_ == NumIntArgRegs) { current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint32_t); @@ -57,7 +57,7 @@ ABIArgGenerator::softNext(MIRType type) current_ = ABIArg(Register::FromCode(intRegIndex_)); intRegIndex_++; break; - case MIRType_Float32: + case MIRType::Float32: if (intRegIndex_ == NumIntArgRegs) { current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint32_t); @@ -66,7 +66,7 @@ ABIArgGenerator::softNext(MIRType type) current_ = ABIArg(Register::FromCode(intRegIndex_)); intRegIndex_++; break; - case MIRType_Double: + case MIRType::Double: // Make sure to use an even register index. Increase to next even number // when odd. intRegIndex_ = (intRegIndex_ + 1) & ~1; @@ -92,8 +92,8 @@ ABIArg ABIArgGenerator::hardNext(MIRType type) { switch (type) { - case MIRType_Int32: - case MIRType_Pointer: + case MIRType::Int32: + case MIRType::Pointer: if (intRegIndex_ == NumIntArgRegs) { current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint32_t); @@ -102,7 +102,7 @@ ABIArgGenerator::hardNext(MIRType type) current_ = ABIArg(Register::FromCode(intRegIndex_)); intRegIndex_++; break; - case MIRType_Float32: + case MIRType::Float32: if (floatRegIndex_ == NumFloatArgRegs) { static const int align = sizeof(double) - 1; stackOffset_ = (stackOffset_ + align) & ~align; @@ -113,7 +113,7 @@ ABIArgGenerator::hardNext(MIRType type) current_ = ABIArg(VFPRegister(floatRegIndex_, VFPRegister::Single)); floatRegIndex_++; break; - case MIRType_Double: + case MIRType::Double: // Double register are composed of 2 float registers, thus we have to // skip any float register which cannot be used in a pair of float // registers in which a double value can be stored. diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 8188cfaf93..7e188dfb1a 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -1359,7 +1359,7 @@ CodeGeneratorARM::visitBoxFloatingPoint(LBoxFloatingPoint* box) const LAllocation* in = box->getOperand(0); FloatRegister reg = ToFloatRegister(in); - if (box->type() == MIRType_Float32) { + if (box->type() == MIRType::Float32) { ScratchFloat32Scope scratch(masm); masm.convertFloat32ToDouble(reg, scratch); masm.ma_vxfer(VFPRegister(scratch), ToRegister(payload), ToRegister(type)); @@ -2118,7 +2118,7 @@ CodeGeneratorARM::visitAsmSelect(LAsmSelect* ins) Register cond = ToRegister(ins->condExpr()); masm.ma_cmp(cond, Imm32(0)); - if (mirType == MIRType_Int32) { + if (mirType == MIRType::Int32) { Register falseExpr = ToRegister(ins->falseExpr()); Register out = ToRegister(ins->output()); MOZ_ASSERT(ToRegister(ins->trueExpr()) == out, "true expr input is reused for output"); @@ -2131,9 +2131,9 @@ CodeGeneratorARM::visitAsmSelect(LAsmSelect* ins) FloatRegister falseExpr = ToFloatRegister(ins->falseExpr()); - if (mirType == MIRType_Double) + if (mirType == MIRType::Double) masm.moveDouble(falseExpr, out, Assembler::Zero); - else if (mirType == MIRType_Float32) + else if (mirType == MIRType::Float32) masm.moveFloat32(falseExpr, out, Assembler::Zero); else MOZ_CRASH("unhandled type in visitAsmSelect!"); @@ -2149,16 +2149,16 @@ CodeGeneratorARM::visitAsmReinterpret(LAsmReinterpret* lir) DebugOnly from = ins->input()->type(); switch (to) { - case MIRType_Int32: - MOZ_ASSERT(from == MIRType_Float32); + case MIRType::Int32: + MOZ_ASSERT(from == MIRType::Float32); masm.ma_vxfer(ToFloatRegister(lir->input()), ToRegister(lir->output())); break; - case MIRType_Float32: - MOZ_ASSERT(from == MIRType_Int32); + case MIRType::Float32: + MOZ_ASSERT(from == MIRType::Int32); masm.ma_vxfer(ToRegister(lir->input()), ToFloatRegister(lir->output())); break; - case MIRType_Double: - case MIRType_Int64: + case MIRType::Double: + case MIRType::Int64: MOZ_CRASH("not handled by this LIR opcode"); default: MOZ_CRASH("unexpected AsmReinterpret"); @@ -2198,10 +2198,10 @@ CodeGeneratorARM::visitAsmJSCall(LAsmJSCall* ins) emitAsmJSCall(ins); switch (mir->type()) { - case MIRType_Double: + case MIRType::Double: masm.ma_vxfer(r0, r1, d0); break; - case MIRType_Float32: + case MIRType::Float32: masm.as_vxfer(r0, InvalidReg, VFPRegister(d0).singleOverlay(), Assembler::CoreToFloat); break; default: @@ -2723,9 +2723,9 @@ CodeGeneratorARM::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins) { const MAsmJSLoadGlobalVar* mir = ins->mir(); unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - if (mir->type() == MIRType_Int32) { + if (mir->type() == MIRType::Int32) { masm.ma_dtr(IsLoad, GlobalReg, Imm32(addr), ToRegister(ins->output())); - } else if (mir->type() == MIRType_Float32) { + } else if (mir->type() == MIRType::Float32) { VFPRegister vd(ToFloatRegister(ins->output())); masm.ma_vldr(Address(GlobalReg, addr), vd.singleOverlay()); } else { @@ -2742,9 +2742,9 @@ CodeGeneratorARM::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins) MOZ_ASSERT(IsNumberType(type)); unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - if (type == MIRType_Int32) { + if (type == MIRType::Int32) { masm.ma_dtr(IsStore, GlobalReg, Imm32(addr), ToRegister(ins->value())); - } else if (type == MIRType_Float32) { + } else if (type == MIRType::Float32) { VFPRegister vd(ToFloatRegister(ins->value())); masm.ma_vstr(vd.singleOverlay(), Address(GlobalReg, addr)); } else { @@ -2836,3 +2836,136 @@ CodeGeneratorARM::setReturnDoubleRegs(LiveRegisterSet* regs) regs->add(s1); regs->add(ReturnDoubleReg); } + +void +CodeGeneratorARM::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir) +{ + auto input = ToFloatRegister(lir->input()); + auto output = ToRegister(lir->output()); + + MWasmTruncateToInt32* mir = lir->mir(); + MIRType fromType = mir->input()->type(); + + auto* ool = new(alloc()) OutOfLineWasmTruncateCheck(mir, input); + addOutOfLineCode(ool, mir); + + // vcvt* converts NaN into 0, so check for NaNs here. + { + if (fromType == MIRType::Double) + masm.compareDouble(input, input); + else if (fromType == MIRType::Float32) + masm.compareFloat(input, input); + else + MOZ_CRASH("unexpected type in visitWasmTruncateToInt32"); + + masm.ma_b(ool->entry(), Assembler::VFP_Unordered); + } + + ScratchDoubleScope scratchScope(masm); + FloatRegister scratch = scratchScope.uintOverlay(); + + // ARM conversion instructions clamp the value to ensure it fits within the + // target's type bounds, so every time we see those, we need to check the + // input. + if (mir->isUnsigned()) { + if (fromType == MIRType::Double) + masm.ma_vcvt_F64_U32(input, scratch); + else if (fromType == MIRType::Float32) + masm.ma_vcvt_F32_U32(input, scratch); + else + MOZ_CRASH("unexpected type in visitWasmTruncateToInt32"); + + masm.ma_vxfer(scratch, output); + + // int32_t(UINT32_MAX) == -1. + masm.ma_cmp(output, Imm32(-1)); + masm.ma_cmp(output, Imm32(0), Assembler::NotEqual); + masm.ma_b(ool->entry(), Assembler::Equal); + + masm.bind(ool->rejoin()); + return; + } + + scratch = scratchScope.sintOverlay(); + + if (fromType == MIRType::Double) + masm.ma_vcvt_F64_I32(input, scratch); + else if (fromType == MIRType::Float32) + masm.ma_vcvt_F32_I32(input, scratch); + else + MOZ_CRASH("unexpected type in visitWasmTruncateToInt32"); + + masm.ma_vxfer(scratch, output); + masm.ma_cmp(output, Imm32(INT32_MAX)); + masm.ma_cmp(output, Imm32(INT32_MIN), Assembler::NotEqual); + masm.ma_b(ool->entry(), Assembler::Equal); + + masm.bind(ool->rejoin()); +} + +void +CodeGeneratorARM::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool) +{ + MIRType fromType = ool->fromType(); + FloatRegister input = ool->input(); + + ScratchDoubleScope scratchScope(masm); + FloatRegister scratch; + + // Eagerly take care of NaNs. + Label inputIsNaN; + if (fromType == MIRType::Double) + masm.branchDouble(Assembler::DoubleUnordered, input, input, &inputIsNaN); + else if (fromType == MIRType::Float32) + masm.branchFloat(Assembler::DoubleUnordered, input, input, &inputIsNaN); + else + MOZ_CRASH("unexpected type in visitOutOfLineWasmTruncateCheck"); + + // Handle special values. + Label fail; + + double minValue, maxValue; + if (ool->isUnsigned()) { + minValue = -1; + maxValue = double(UINT32_MAX) + 1.0; + } else { + minValue = double(INT32_MIN) - 1.0; + maxValue = double(INT32_MAX) + 1.0; + } + + if (fromType == MIRType::Double) { + scratch = scratchScope.doubleOverlay(); + masm.loadConstantDouble(minValue, scratch); + masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, scratch, &fail); + + masm.loadConstantDouble(maxValue, scratch); + masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, scratch, &fail); + } else { + MOZ_ASSERT(fromType == MIRType::Float32); + scratch = scratchScope.singleOverlay(); + + // For int32, float(minValue) rounds to INT32_MIN, we want to fail when + // input < float(minValue). + // For uint32, float(minValue) == -1, we want to fail when input <= -1. + auto condition = minValue == -1.0 + ? Assembler::DoubleLessThanOrEqual + : Assembler::DoubleLessThan; + + masm.loadConstantFloat32(float(minValue), scratch); + masm.branchFloat(condition, input, scratch, &fail); + + // maxValue is exactly represented in both cases. + masm.loadConstantFloat32(float(maxValue), scratch); + masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, input, scratch, &fail); + } + + // We had an actual correct value, get back to where we were. + masm.ma_b(ool->rejoin()); + + // Handle errors. + masm.bind(&fail); + masm.jump(wasm::JumpTarget::IntegerOverflowTrap); + + masm.bind(&inputIsNaN); + masm.jump(wasm::JumpTarget::InvalidConversionToIntegerTrap); +} diff --git a/js/src/jit/arm/CodeGenerator-arm.h b/js/src/jit/arm/CodeGenerator-arm.h index 325ed49ab6..7eaff18f85 100644 --- a/js/src/jit/arm/CodeGenerator-arm.h +++ b/js/src/jit/arm/CodeGenerator-arm.h @@ -217,6 +217,8 @@ class CodeGeneratorARM : public CodeGeneratorShared void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins); + void visitWasmTruncateToInt32(LWasmTruncateToInt32* ins); + void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool); void visitMemoryBarrier(LMemoryBarrier* ins); diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index 9f215094ef..c9b9b43e6e 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -20,7 +20,7 @@ using mozilla::FloorLog2; LBoxAllocation LIRGeneratorARM::useBoxFixed(MDefinition* mir, Register reg1, Register reg2, bool useAtStart) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); MOZ_ASSERT(reg1 != reg2); ensureDefined(mir); @@ -91,7 +91,7 @@ LIRGeneratorARM::visitUnbox(MUnbox* unbox) { MDefinition* inner = unbox->getOperand(0); - if (inner->type() == MIRType_ObjectOrNull) { + if (inner->type() == MIRType::ObjectOrNull) { LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner)); if (unbox->fallible()) assignSnapshot(lir, unbox->bailoutKind()); @@ -102,7 +102,7 @@ LIRGeneratorARM::visitUnbox(MUnbox* unbox) // An unbox on arm reads in a type tag (either in memory or a register) and // a payload. Unlike most instructions consuming a box, we ask for the type // second, so that the result can re-use the first input. - MOZ_ASSERT(inner->type() == MIRType_Value); + MOZ_ASSERT(inner->type() == MIRType::Value); ensureDefined(inner); @@ -134,7 +134,7 @@ void LIRGeneratorARM::visitReturn(MReturn* ret) { MDefinition* opd = ret->getOperand(0); - MOZ_ASSERT(opd->type() == MIRType_Value); + MOZ_ASSERT(opd->type() == MIRType::Value); LReturn* ins = new(alloc()) LReturn; ins->setOperand(0, LUse(JSReturnReg_Type)); @@ -354,7 +354,7 @@ void LIRGeneratorARM::visitPowHalf(MPowHalf* ins) { MDefinition* input = ins->input(); - MOZ_ASSERT(input->type() == MIRType_Double); + MOZ_ASSERT(input->type() == MIRType::Double); LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input)); defineReuseInput(lir, ins, 0); } @@ -376,7 +376,7 @@ LIRGeneratorARM::newLTableSwitchV(MTableSwitch* tableswitch) void LIRGeneratorARM::visitGuardShape(MGuardShape* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); LDefinition tempObj = temp(LDefinition::OBJECT); LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->obj()), tempObj); @@ -388,7 +388,7 @@ LIRGeneratorARM::visitGuardShape(MGuardShape* ins) void LIRGeneratorARM::visitGuardObjectGroup(MGuardObjectGroup* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); LDefinition tempObj = temp(LDefinition::OBJECT); LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->obj()), tempObj); @@ -403,8 +403,8 @@ LIRGeneratorARM::lowerUrshD(MUrsh* mir) MDefinition* lhs = mir->lhs(); MDefinition* rhs = mir->rhs(); - MOZ_ASSERT(lhs->type() == MIRType_Int32); - MOZ_ASSERT(rhs->type() == MIRType_Int32); + MOZ_ASSERT(lhs->type() == MIRType::Int32); + MOZ_ASSERT(rhs->type() == MIRType::Int32); LUrshD* lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp()); define(lir, mir); @@ -413,7 +413,7 @@ LIRGeneratorARM::lowerUrshD(MUrsh* mir) void LIRGeneratorARM::visitAsmSelect(MAsmSelect* ins) { - MOZ_ASSERT(ins->type() != MIRType_Int64); + MOZ_ASSERT(ins->type() != MIRType::Int64); auto* lir = new(alloc()) LAsmSelect(useRegisterAtStart(ins->trueExpr()), useRegister(ins->falseExpr()), @@ -426,12 +426,12 @@ LIRGeneratorARM::visitAsmSelect(MAsmSelect* ins) void LIRGeneratorARM::visitAsmJSNeg(MAsmJSNeg* ins) { - if (ins->type() == MIRType_Int32) { + if (ins->type() == MIRType::Int32) { define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins); - } else if (ins->type() == MIRType_Float32) { + } else if (ins->type() == MIRType::Float32) { define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins); } else { - MOZ_ASSERT(ins->type() == MIRType_Double); + MOZ_ASSERT(ins->type() == MIRType::Double); define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins); } } @@ -483,7 +483,7 @@ LIRGeneratorARM::lowerUMod(MMod* mod) void LIRGeneratorARM::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->input()->type() == MIRType::Int32); LAsmJSUInt32ToDouble* lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input())); define(lir, ins); } @@ -491,7 +491,7 @@ LIRGeneratorARM::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins) void LIRGeneratorARM::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->input()->type() == MIRType::Int32); LAsmJSUInt32ToFloat32* lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input())); define(lir, ins); } @@ -502,7 +502,7 @@ LIRGeneratorARM::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) MOZ_ASSERT(ins->offset() == 0); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); LAllocation baseAlloc; // For the ARM it is best to keep the 'base' in a register if a bounds check is needed. @@ -523,7 +523,7 @@ LIRGeneratorARM::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) MOZ_ASSERT(ins->offset() == 0); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); LAllocation baseAlloc; if (base->isConstant() && !ins->needsBoundsCheck()) { @@ -546,7 +546,7 @@ void LIRGeneratorARM::lowerTruncateDToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Double); + MOZ_ASSERT(opd->type() == MIRType::Double); define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); } @@ -555,7 +555,7 @@ void LIRGeneratorARM::lowerTruncateFToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Float32); + MOZ_ASSERT(opd->type() == MIRType::Float32); define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); } @@ -596,8 +596,8 @@ LIRGeneratorARM::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayE MOZ_ASSERT(HasLDSTREXBHD()); MOZ_ASSERT(ins->arrayType() <= Scalar::Uint32); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -608,7 +608,7 @@ LIRGeneratorARM::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayE const LAllocation value = useRegister(ins->value()); LDefinition tempDef = LDefinition::BogusTemp(); if (ins->arrayType() == Scalar::Uint32) { - MOZ_ASSERT(ins->type() == MIRType_Double); + MOZ_ASSERT(ins->type() == MIRType::Double); tempDef = temp(); } @@ -625,8 +625,8 @@ LIRGeneratorARM::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop MOZ_ASSERT(ins->arrayType() != Scalar::Float32); MOZ_ASSERT(ins->arrayType() != Scalar::Float64); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -666,8 +666,8 @@ LIRGeneratorARM::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArra MOZ_ASSERT(ins->arrayType() != Scalar::Float32); MOZ_ASSERT(ins->arrayType() != Scalar::Float64); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -698,7 +698,7 @@ LIRGeneratorARM::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins) MOZ_ASSERT(ins->offset() == 0); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); if (byteSize(ins->accessType()) != 4 && !HasLDSTREXBHD()) { LAsmJSCompareExchangeCallout* lir = @@ -720,7 +720,7 @@ LIRGeneratorARM::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins) void LIRGeneratorARM::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins) { - MOZ_ASSERT(ins->base()->type() == MIRType_Int32); + MOZ_ASSERT(ins->base()->type() == MIRType::Int32); MOZ_ASSERT(ins->accessType() < Scalar::Float32); MOZ_ASSERT(ins->offset() == 0); @@ -743,7 +743,7 @@ LIRGeneratorARM::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins) MOZ_ASSERT(ins->offset() == 0); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); if (byteSize(ins->accessType()) != 4 && !HasLDSTREXBHD()) { LAsmJSAtomicBinopCallout* lir = @@ -795,7 +795,7 @@ LIRGeneratorARM::visitRandom(MRandom* ins) } void -LIRGeneratorARM::visitTruncateToInt64(MTruncateToInt64* ins) +LIRGeneratorARM::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) { MOZ_CRASH("NY"); } diff --git a/js/src/jit/arm/Lowering-arm.h b/js/src/jit/arm/Lowering-arm.h index 985a9c1d03..720ea4c09d 100644 --- a/js/src/jit/arm/Lowering-arm.h +++ b/js/src/jit/arm/Lowering-arm.h @@ -113,7 +113,7 @@ class LIRGeneratorARM : public LIRGeneratorShared void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins); void visitSubstr(MSubstr* ins); void visitRandom(MRandom* ins); - void visitTruncateToInt64(MTruncateToInt64* ins); + void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins); void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); }; diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 9013029b65..9f5ce360a2 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -419,6 +419,38 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) as_mov(dest.high, lsr(dest.high, imm.value)); } +// =============================================================== +// Rotate functions +void +MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest) +{ + if (count.value) + ma_rol(count, input, dest); + else + ma_mov(input, dest); +} + +void +MacroAssembler::rotateLeft(Register count, Register input, Register dest) +{ + ma_rol(count, input, dest); +} + +void +MacroAssembler::rotateRight(Imm32 count, Register input, Register dest) +{ + if (count.value) + ma_ror(count, input, dest); + else + ma_mov(input, dest); +} + +void +MacroAssembler::rotateRight(Register count, Register input, Register dest) +{ + ma_ror(count, input, dest); +} + // =============================================================== // Branch functions @@ -682,7 +714,7 @@ MacroAssembler::branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegis ma_b(label, ConditionFromDoubleCondition(cond)); } -// There are two options for implementing emitTruncateDouble: +// There are two options for implementing branchTruncateDouble: // // 1. Convert the floating point value to an integer, if it did not fit, then it // was clamped to INT_MIN/INT_MAX, and we can test it. NOTE: if the value diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 57ec350081..a2c82dd683 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -2443,7 +2443,6 @@ void MacroAssemblerARMCompat::setStackArg(Register reg, uint32_t arg) { ma_dataTransferN(IsStore, 32, true, sp, Imm32(arg * sizeof(intptr_t)), reg); - } void @@ -3073,7 +3072,7 @@ void MacroAssemblerARMCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType) { - if (valueType == MIRType_Double) { + if (valueType == MIRType::Double) { storeDouble(value.reg().typedReg().fpu(), dest); return; } diff --git a/js/src/jit/arm64/Assembler-arm64.cpp b/js/src/jit/arm64/Assembler-arm64.cpp index bafed1b5db..e8034b6f57 100644 --- a/js/src/jit/arm64/Assembler-arm64.cpp +++ b/js/src/jit/arm64/Assembler-arm64.cpp @@ -32,8 +32,8 @@ ABIArg ABIArgGenerator::next(MIRType type) { switch (type) { - case MIRType_Int32: - case MIRType_Pointer: + case MIRType::Int32: + case MIRType::Pointer: if (intRegIndex_ == NumIntArgRegs) { current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uintptr_t); @@ -43,15 +43,15 @@ ABIArgGenerator::next(MIRType type) intRegIndex_++; break; - case MIRType_Float32: - case MIRType_Double: + case MIRType::Float32: + case MIRType::Double: if (floatRegIndex_ == NumFloatArgRegs) { current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(double); break; } current_ = ABIArg(FloatRegister(floatRegIndex_, - type == MIRType_Double ? FloatRegisters::Double + type == MIRType::Double ? FloatRegisters::Double : FloatRegisters::Single)); floatRegIndex_++; break; diff --git a/js/src/jit/arm64/Lowering-arm64.cpp b/js/src/jit/arm64/Lowering-arm64.cpp index fc9a747998..c592d20afc 100644 --- a/js/src/jit/arm64/Lowering-arm64.cpp +++ b/js/src/jit/arm64/Lowering-arm64.cpp @@ -343,7 +343,7 @@ LIRGeneratorARM64::visitRandom(MRandom* ins) } void -LIRGeneratorARM64::visitTruncateToInt64(MTruncateToInt64* ins) +LIRGeneratorARM64::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) { MOZ_CRASH("NY"); } diff --git a/js/src/jit/arm64/Lowering-arm64.h b/js/src/jit/arm64/Lowering-arm64.h index 905573e4e6..7aac7648b8 100644 --- a/js/src/jit/arm64/Lowering-arm64.h +++ b/js/src/jit/arm64/Lowering-arm64.h @@ -34,7 +34,7 @@ class LIRGeneratorARM64 : public LIRGeneratorShared bool needTempForPostBarrier() { return true; } // ARM64 has a scratch register, so no need for another temp for dispatch ICs. - LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) { + LDefinition tempForDispatchCache(MIRType outputType = MIRType::None) { return LDefinition::BogusTemp(); } @@ -116,7 +116,7 @@ class LIRGeneratorARM64 : public LIRGeneratorShared void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins); void visitSubstr(MSubstr* ins); void visitRandom(MRandom* ins); - void visitTruncateToInt64(MTruncateToInt64* ins); + void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins); void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); }; diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 47b8840a2f..133c419a9b 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -466,6 +466,29 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) rshiftPtr(imm, dest.reg); } +// =============================================================== +// Rotation functions +void +MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest) +{ + MOZ_CRASH("NYI"); +} +void +MacroAssembler::rotateLeft(Register count, Register input, Register dest) +{ + MOZ_CRASH("NYI"); +} +void +MacroAssembler::rotateRight(Imm32 count, Register input, Register dest) +{ + MOZ_CRASH("NYI"); +} +void +MacroAssembler::rotateRight(Register count, Register input, Register dest) +{ + MOZ_CRASH("NYI"); +} + // =============================================================== // Branch functions diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 005f076acf..1a2306a8a6 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -286,17 +286,17 @@ class MacroAssemblerCompat : public vixl::MacroAssembler template void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType) { - if (valueType == MIRType_Double) { + if (valueType == MIRType::Double) { storeDouble(value.reg().typedReg().fpu(), dest); return; } // For known integers and booleans, we can just store the unboxed value if // the slot has the same type. - if ((valueType == MIRType_Int32 || valueType == MIRType_Boolean) && slotType == valueType) { + if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) { if (value.constant()) { Value val = value.value(); - if (valueType == MIRType_Int32) + if (valueType == MIRType::Int32) store32(Imm32(val.toInt32()), dest); else store32(Imm32(val.toBoolean() ? 1 : 0), dest); @@ -1842,7 +1842,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler MOZ_ASSERT(scratch64.asUnsized() != address.base); Ldr(scratch64, toMemOperand(address)); int32OrDouble(scratch64.asUnsized(), ARMFPRegister(dest.fpu(), 64)); - } else if (type == MIRType_Int32 || type == MIRType_Boolean) { + } else if (type == MIRType::Int32 || type == MIRType::Boolean) { load32(address, dest.gpr()); } else { loadPtr(address, dest.gpr()); @@ -1858,7 +1858,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler MOZ_ASSERT(scratch64.asUnsized() != address.index); doBaseIndex(scratch64, address, vixl::LDR_x); int32OrDouble(scratch64.asUnsized(), ARMFPRegister(dest.fpu(), 64)); - } else if (type == MIRType_Int32 || type == MIRType_Boolean) { + } else if (type == MIRType::Int32 || type == MIRType::Boolean) { load32(address, dest.gpr()); } else { loadPtr(address, dest.gpr()); diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index 7e5df2f0fd..1284e57c9e 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -1914,7 +1914,7 @@ CodeGeneratorMIPSShared::visitAsmSelect(LAsmSelect* ins) Register cond = ToRegister(ins->condExpr()); const LAllocation* falseExpr = ins->falseExpr(); - if (mirType == MIRType_Int32) { + if (mirType == MIRType::Int32) { Register out = ToRegister(ins->output()); MOZ_ASSERT(ToRegister(ins->trueExpr()) == out, "true expr input is reused for output"); masm.as_movz(out, ToRegister(falseExpr), cond); @@ -1925,9 +1925,9 @@ CodeGeneratorMIPSShared::visitAsmSelect(LAsmSelect* ins) MOZ_ASSERT(ToFloatRegister(ins->trueExpr()) == out, "true expr input is reused for output"); if (falseExpr->isFloatReg()) { - if (mirType == MIRType_Float32) + if (mirType == MIRType::Float32) masm.as_movz(Assembler::SingleFloat, out, ToFloatRegister(falseExpr), cond); - else if (mirType == MIRType_Double) + else if (mirType == MIRType::Double) masm.as_movz(Assembler::DoubleFloat, out, ToFloatRegister(falseExpr), cond); else MOZ_CRASH("unhandled type in visitAsmSelect!"); @@ -1935,9 +1935,9 @@ CodeGeneratorMIPSShared::visitAsmSelect(LAsmSelect* ins) Label done; masm.ma_b(cond, cond, &done, Assembler::NonZero, ShortJump); - if (mirType == MIRType_Float32) + if (mirType == MIRType::Float32) masm.loadFloat32(ToAddress(falseExpr), out); - else if (mirType == MIRType_Double) + else if (mirType == MIRType::Double) masm.loadDouble(ToAddress(falseExpr), out); else MOZ_CRASH("unhandled type in visitAsmSelect!"); @@ -1956,16 +1956,16 @@ CodeGeneratorMIPSShared::visitAsmReinterpret(LAsmReinterpret* lir) DebugOnly from = ins->input()->type(); switch (to) { - case MIRType_Int32: - MOZ_ASSERT(from == MIRType_Float32); + case MIRType::Int32: + MOZ_ASSERT(from == MIRType::Float32); masm.as_mfc1(ToRegister(lir->output()), ToFloatRegister(lir->input())); break; - case MIRType_Float32: - MOZ_ASSERT(from == MIRType_Int32); + case MIRType::Float32: + MOZ_ASSERT(from == MIRType::Int32); masm.as_mtc1(ToRegister(lir->input()), ToFloatRegister(lir->output())); break; - case MIRType_Double: - case MIRType_Int64: + case MIRType::Double: + case MIRType::Int64: MOZ_CRASH("not handled by this LIR opcode"); default: MOZ_CRASH("unexpected AsmReinterpret"); @@ -2028,9 +2028,9 @@ CodeGeneratorMIPSShared::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins) { const MAsmJSLoadGlobalVar* mir = ins->mir(); unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - if (mir->type() == MIRType_Int32) + if (mir->type() == MIRType::Int32) masm.load32(Address(GlobalReg, addr), ToRegister(ins->output())); - else if (mir->type() == MIRType_Float32) + else if (mir->type() == MIRType::Float32) masm.loadFloat32(Address(GlobalReg, addr), ToFloatRegister(ins->output())); else masm.loadDouble(Address(GlobalReg, addr), ToFloatRegister(ins->output())); @@ -2043,9 +2043,9 @@ CodeGeneratorMIPSShared::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins) MOZ_ASSERT(IsNumberType(mir->value()->type())); unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - if (mir->value()->type() == MIRType_Int32) + if (mir->value()->type() == MIRType::Int32) masm.store32(ToRegister(ins->value()), Address(GlobalReg, addr)); - else if (mir->value()->type() == MIRType_Float32) + else if (mir->value()->type() == MIRType::Float32) masm.storeFloat32(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); else masm.storeDouble(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); diff --git a/js/src/jit/mips-shared/Lowering-mips-shared.cpp b/js/src/jit/mips-shared/Lowering-mips-shared.cpp index 9fcefaad80..8d475feff7 100644 --- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp +++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp @@ -204,7 +204,7 @@ void LIRGeneratorMIPSShared::visitPowHalf(MPowHalf* ins) { MDefinition* input = ins->input(); - MOZ_ASSERT(input->type() == MIRType_Double); + MOZ_ASSERT(input->type() == MIRType::Double); LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input)); defineReuseInput(lir, ins, 0); } @@ -226,7 +226,7 @@ LIRGeneratorMIPSShared::newLTableSwitchV(MTableSwitch* tableswitch) void LIRGeneratorMIPSShared::visitGuardShape(MGuardShape* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); LDefinition tempObj = temp(LDefinition::OBJECT); LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->obj()), tempObj); @@ -238,7 +238,7 @@ LIRGeneratorMIPSShared::visitGuardShape(MGuardShape* ins) void LIRGeneratorMIPSShared::visitGuardObjectGroup(MGuardObjectGroup* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); LDefinition tempObj = temp(LDefinition::OBJECT); LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->obj()), tempObj); @@ -253,8 +253,8 @@ LIRGeneratorMIPSShared::lowerUrshD(MUrsh* mir) MDefinition* lhs = mir->lhs(); MDefinition* rhs = mir->rhs(); - MOZ_ASSERT(lhs->type() == MIRType_Int32); - MOZ_ASSERT(rhs->type() == MIRType_Int32); + MOZ_ASSERT(lhs->type() == MIRType::Int32); + MOZ_ASSERT(rhs->type() == MIRType::Int32); LUrshD* lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp()); define(lir, mir); @@ -263,12 +263,12 @@ LIRGeneratorMIPSShared::lowerUrshD(MUrsh* mir) void LIRGeneratorMIPSShared::visitAsmJSNeg(MAsmJSNeg* ins) { - if (ins->type() == MIRType_Int32) { + if (ins->type() == MIRType::Int32) { define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins); - } else if (ins->type() == MIRType_Float32) { + } else if (ins->type() == MIRType::Float32) { define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins); } else { - MOZ_ASSERT(ins->type() == MIRType_Double); + MOZ_ASSERT(ins->type() == MIRType::Double); define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins); } } @@ -276,7 +276,7 @@ LIRGeneratorMIPSShared::visitAsmJSNeg(MAsmJSNeg* ins) void LIRGeneratorMIPSShared::visitAsmSelect(MAsmSelect* ins) { - if (ins->type() == MIRType_Int64) { + if (ins->type() == MIRType::Int64) { auto* lir = new(alloc()) LAsmSelectI64(useInt64RegisterAtStart(ins->trueExpr()), useInt64(ins->falseExpr()), useRegister(ins->condExpr()) @@ -327,7 +327,7 @@ LIRGeneratorMIPSShared::lowerUMod(MMod* mod) void LIRGeneratorMIPSShared::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->input()->type() == MIRType::Int32); LAsmJSUInt32ToDouble* lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input())); define(lir, ins); } @@ -335,7 +335,7 @@ LIRGeneratorMIPSShared::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins) void LIRGeneratorMIPSShared::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->input()->type() == MIRType::Int32); LAsmJSUInt32ToFloat32* lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input())); define(lir, ins); } @@ -346,7 +346,7 @@ LIRGeneratorMIPSShared::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) MOZ_ASSERT(ins->offset() == 0); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); LAllocation baseAlloc; // For MIPS it is best to keep the 'base' in a register if a bounds check @@ -367,7 +367,7 @@ LIRGeneratorMIPSShared::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) MOZ_ASSERT(ins->offset() == 0); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); LAllocation baseAlloc; if (base->isConstant() && !ins->needsBoundsCheck()) { @@ -434,8 +434,8 @@ LIRGeneratorMIPSShared::visitCompareExchangeTypedArrayElement(MCompareExchangeTy MOZ_ASSERT(ins->arrayType() != Scalar::Float32); MOZ_ASSERT(ins->arrayType() != Scalar::Float64); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -462,8 +462,8 @@ LIRGeneratorMIPSShared::visitAtomicExchangeTypedArrayElement(MAtomicExchangeType { MOZ_ASSERT(ins->arrayType() <= Scalar::Uint32); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -474,7 +474,7 @@ LIRGeneratorMIPSShared::visitAtomicExchangeTypedArrayElement(MAtomicExchangeType const LAllocation value = useRegister(ins->value()); LDefinition uint32Temp = LDefinition::BogusTemp(); if (ins->arrayType() == Scalar::Uint32) { - MOZ_ASSERT(ins->type() == MIRType_Double); + MOZ_ASSERT(ins->type() == MIRType::Double); uint32Temp = temp(); } @@ -493,7 +493,7 @@ LIRGeneratorMIPSShared::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* MOZ_ASSERT(ins->offset() == 0); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); LAsmJSCompareExchangeHeap* lir = new(alloc()) LAsmJSCompareExchangeHeap(useRegister(base), @@ -509,7 +509,7 @@ LIRGeneratorMIPSShared::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* void LIRGeneratorMIPSShared::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins) { - MOZ_ASSERT(ins->base()->type() == MIRType_Int32); + MOZ_ASSERT(ins->base()->type() == MIRType::Int32); MOZ_ASSERT(ins->offset() == 0); const LAllocation base = useRegister(ins->base()); @@ -534,7 +534,7 @@ LIRGeneratorMIPSShared::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins) MOZ_ASSERT(ins->offset() == 0); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); if (!ins->hasUses()) { LAsmJSAtomicBinopHeapForEffect* lir = @@ -567,8 +567,8 @@ LIRGeneratorMIPSShared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayEleme MOZ_ASSERT(ins->arrayType() != Scalar::Float32); MOZ_ASSERT(ins->arrayType() != Scalar::Float64); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -604,7 +604,7 @@ LIRGeneratorMIPSShared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayEleme } void -LIRGeneratorMIPSShared::visitTruncateToInt64(MTruncateToInt64* ins) +LIRGeneratorMIPSShared::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) { MOZ_CRASH("NY"); } diff --git a/js/src/jit/mips-shared/Lowering-mips-shared.h b/js/src/jit/mips-shared/Lowering-mips-shared.h index b0445a06e2..4605b971d9 100644 --- a/js/src/jit/mips-shared/Lowering-mips-shared.h +++ b/js/src/jit/mips-shared/Lowering-mips-shared.h @@ -97,7 +97,7 @@ class LIRGeneratorMIPSShared : public LIRGeneratorShared void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins); void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins); void visitSubstr(MSubstr* ins); - void visitTruncateToInt64(MTruncateToInt64* ins); + void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins); void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); }; diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index 2ce400ffca..c0e7b6e42e 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -191,6 +191,29 @@ MacroAssembler::negateDouble(FloatRegister reg) as_negd(reg, reg); } +// =============================================================== +// Rotation functions +void +MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest) +{ + MOZ_CRASH("NYI"); +} +void +MacroAssembler::rotateLeft(Register count, Register input, Register dest) +{ + MOZ_CRASH("NYI"); +} +void +MacroAssembler::rotateRight(Imm32 count, Register input, Register dest) +{ + MOZ_CRASH("NYI"); +} +void +MacroAssembler::rotateRight(Register count, Register input, Register dest) +{ + MOZ_CRASH("NYI"); +} + // =============================================================== // Branch functions diff --git a/js/src/jit/mips32/Assembler-mips32.cpp b/js/src/jit/mips32/Assembler-mips32.cpp index 7d86e4c02c..1514366590 100644 --- a/js/src/jit/mips32/Assembler-mips32.cpp +++ b/js/src/jit/mips32/Assembler-mips32.cpp @@ -25,15 +25,15 @@ ABIArgGenerator::next(MIRType type) { Register destReg; switch (type) { - case MIRType_Int32: - case MIRType_Pointer: + case MIRType::Int32: + case MIRType::Pointer: if (GetIntArgReg(usedArgSlots_, &destReg)) current_ = ABIArg(destReg); else current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t)); usedArgSlots_++; break; - case MIRType_Float32: + case MIRType::Float32: if (!usedArgSlots_) { current_ = ABIArg(f12.asSingle()); firstArgFloatSize_ = 1; @@ -48,7 +48,7 @@ ABIArgGenerator::next(MIRType type) } usedArgSlots_++; break; - case MIRType_Double: + case MIRType::Double: if (!usedArgSlots_) { current_ = ABIArg(f12); usedArgSlots_ = 2; diff --git a/js/src/jit/mips32/CodeGenerator-mips32.cpp b/js/src/jit/mips32/CodeGenerator-mips32.cpp index 148199af52..a7ec176bd0 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.cpp +++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp @@ -181,7 +181,7 @@ CodeGeneratorMIPS::visitBoxFloatingPoint(LBoxFloatingPoint* box) const LAllocation* in = box->getOperand(0); FloatRegister reg = ToFloatRegister(in); - if (box->type() == MIRType_Float32) { + if (box->type() == MIRType::Float32) { masm.convertFloat32ToDouble(reg, ScratchDoubleReg); reg = ScratchDoubleReg; } diff --git a/js/src/jit/mips32/Lowering-mips32.cpp b/js/src/jit/mips32/Lowering-mips32.cpp index 515acfdbdb..41ae2641b0 100644 --- a/js/src/jit/mips32/Lowering-mips32.cpp +++ b/js/src/jit/mips32/Lowering-mips32.cpp @@ -18,7 +18,7 @@ using namespace js::jit; LBoxAllocation LIRGeneratorMIPS::useBoxFixed(MDefinition* mir, Register reg1, Register reg2, bool useAtStart) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); MOZ_ASSERT(reg1 != reg2); ensureDefined(mir); @@ -71,7 +71,7 @@ LIRGeneratorMIPS::visitUnbox(MUnbox* unbox) { MDefinition* inner = unbox->getOperand(0); - if (inner->type() == MIRType_ObjectOrNull) { + if (inner->type() == MIRType::ObjectOrNull) { LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner)); if (unbox->fallible()) assignSnapshot(lir, unbox->bailoutKind()); @@ -82,7 +82,7 @@ LIRGeneratorMIPS::visitUnbox(MUnbox* unbox) // An unbox on mips reads in a type tag (either in memory or a register) and // a payload. Unlike most instructions consuming a box, we ask for the type // second, so that the result can re-use the first input. - MOZ_ASSERT(inner->type() == MIRType_Value); + MOZ_ASSERT(inner->type() == MIRType::Value); ensureDefined(inner); @@ -115,7 +115,7 @@ void LIRGeneratorMIPS::visitReturn(MReturn* ret) { MDefinition* opd = ret->getOperand(0); - MOZ_ASSERT(opd->type() == MIRType_Value); + MOZ_ASSERT(opd->type() == MIRType::Value); LReturn* ins = new(alloc()) LReturn; ins->setOperand(0, LUse(JSReturnReg_Type)); @@ -158,7 +158,7 @@ void LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Double); + MOZ_ASSERT(opd->type() == MIRType::Double); define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); } @@ -167,7 +167,7 @@ void LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Float32); + MOZ_ASSERT(opd->type() == MIRType::Float32); define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index a8e3a99469..742e2e6e2f 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1359,7 +1359,7 @@ void MacroAssemblerMIPSCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType) { - if (valueType == MIRType_Double) { + if (valueType == MIRType::Double) { storeDouble(value.reg().typedReg().fpu(), dest); return; } diff --git a/js/src/jit/mips64/Assembler-mips64.cpp b/js/src/jit/mips64/Assembler-mips64.cpp index e60466755c..f2686cfd6c 100644 --- a/js/src/jit/mips64/Assembler-mips64.cpp +++ b/js/src/jit/mips64/Assembler-mips64.cpp @@ -23,8 +23,8 @@ ABIArg ABIArgGenerator::next(MIRType type) { switch (type) { - case MIRType_Int32: - case MIRType_Pointer: { + case MIRType::Int32: + case MIRType::Pointer: { Register destReg; if (GetIntArgReg(usedArgSlots_, &destReg)) current_ = ABIArg(destReg); @@ -33,13 +33,13 @@ ABIArgGenerator::next(MIRType type) usedArgSlots_++; break; } - case MIRType_Float32: - case MIRType_Double: { + case MIRType::Float32: + case MIRType::Double: { FloatRegister destFReg; FloatRegister::ContentType contentType; if (!usedArgSlots_) firstArgFloat = true; - contentType = (type == MIRType_Double) ? + contentType = (type == MIRType::Double) ? FloatRegisters::Double : FloatRegisters::Single; if (GetFloatArgReg(usedArgSlots_, &destFReg)) current_ = ABIArg(FloatRegister(destFReg.id(), contentType)); diff --git a/js/src/jit/mips64/CodeGenerator-mips64.cpp b/js/src/jit/mips64/CodeGenerator-mips64.cpp index f8423bf29b..2ba462e7ae 100644 --- a/js/src/jit/mips64/CodeGenerator-mips64.cpp +++ b/js/src/jit/mips64/CodeGenerator-mips64.cpp @@ -155,7 +155,7 @@ CodeGeneratorMIPS64::visitBox(LBox* box) if (IsFloatingPointType(box->type())) { FloatRegister reg = ToFloatRegister(in); - if (box->type() == MIRType_Float32) { + if (box->type() == MIRType::Float32) { masm.convertFloat32ToDouble(reg, ScratchDoubleReg); reg = ScratchDoubleReg; } @@ -182,19 +182,19 @@ CodeGeneratorMIPS64::visitUnbox(LUnbox* unbox) if (input->isRegister()) { Register inputReg = ToRegister(input); switch (mir->type()) { - case MIRType_Int32: + case MIRType::Int32: masm.unboxInt32(inputReg, result); break; - case MIRType_Boolean: + case MIRType::Boolean: masm.unboxBoolean(inputReg, result); break; - case MIRType_Object: + case MIRType::Object: masm.unboxObject(inputReg, result); break; - case MIRType_String: + case MIRType::String: masm.unboxString(inputReg, result); break; - case MIRType_Symbol: + case MIRType::Symbol: masm.unboxSymbol(inputReg, result); break; default: @@ -205,19 +205,19 @@ CodeGeneratorMIPS64::visitUnbox(LUnbox* unbox) Address inputAddr = ToAddress(input); switch (mir->type()) { - case MIRType_Int32: + case MIRType::Int32: masm.unboxInt32(inputAddr, result); break; - case MIRType_Boolean: + case MIRType::Boolean: masm.unboxBoolean(inputAddr, result); break; - case MIRType_Object: + case MIRType::Object: masm.unboxObject(inputAddr, result); break; - case MIRType_String: + case MIRType::String: masm.unboxString(inputAddr, result); break; - case MIRType_Symbol: + case MIRType::Symbol: masm.unboxSymbol(inputAddr, result); break; default: @@ -306,7 +306,7 @@ CodeGeneratorMIPS64::visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir) void CodeGeneratorMIPS64::visitAsmSelectI64(LAsmSelectI64* lir) { - MOZ_ASSERT(lir->mir()->type() == MIRType_Int64); + MOZ_ASSERT(lir->mir()->type() == MIRType::Int64); Register cond = ToRegister(lir->condExpr()); const LAllocation* falseExpr = lir->falseExpr(); @@ -327,16 +327,16 @@ CodeGeneratorMIPS64::visitAsmSelectI64(LAsmSelectI64* lir) void CodeGeneratorMIPS64::visitAsmReinterpretFromI64(LAsmReinterpretFromI64* lir) { - MOZ_ASSERT(lir->mir()->type() == MIRType_Double); - MOZ_ASSERT(lir->mir()->input()->type() == MIRType_Int64); + MOZ_ASSERT(lir->mir()->type() == MIRType::Double); + MOZ_ASSERT(lir->mir()->input()->type() == MIRType::Int64); masm.as_dmtc1(ToRegister(lir->input()), ToFloatRegister(lir->output())); } void CodeGeneratorMIPS64::visitAsmReinterpretToI64(LAsmReinterpretToI64* lir) { - MOZ_ASSERT(lir->mir()->type() == MIRType_Int64); - MOZ_ASSERT(lir->mir()->input()->type() == MIRType_Double); + MOZ_ASSERT(lir->mir()->type() == MIRType::Int64); + MOZ_ASSERT(lir->mir()->input()->type() == MIRType::Double); masm.as_dmfc1(ToRegister(lir->output()), ToFloatRegister(lir->input())); } diff --git a/js/src/jit/mips64/Lowering-mips64.cpp b/js/src/jit/mips64/Lowering-mips64.cpp index df01c0b602..45cd5ba35e 100644 --- a/js/src/jit/mips64/Lowering-mips64.cpp +++ b/js/src/jit/mips64/Lowering-mips64.cpp @@ -18,7 +18,7 @@ using namespace js::jit; LBoxAllocation LIRGeneratorMIPS64::useBoxFixed(MDefinition* mir, Register reg1, Register reg2, bool useAtStart) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); ensureDefined(mir); return LBoxAllocation(LUse(reg1, mir->virtualRegister(), useAtStart)); @@ -48,7 +48,7 @@ LIRGeneratorMIPS64::visitUnbox(MUnbox* unbox) { MDefinition* box = unbox->getOperand(0); - if (box->type() == MIRType_ObjectOrNull) { + if (box->type() == MIRType::ObjectOrNull) { LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(box)); if (unbox->fallible()) assignSnapshot(lir, unbox->bailoutKind()); @@ -56,7 +56,7 @@ LIRGeneratorMIPS64::visitUnbox(MUnbox* unbox) return; } - MOZ_ASSERT(box->type() == MIRType_Value); + MOZ_ASSERT(box->type() == MIRType::Value); LUnbox* lir; if (IsFloatingPointType(unbox->type())) { @@ -79,7 +79,7 @@ void LIRGeneratorMIPS64::visitReturn(MReturn* ret) { MDefinition* opd = ret->getOperand(0); - MOZ_ASSERT(opd->type() == MIRType_Value); + MOZ_ASSERT(opd->type() == MIRType::Value); LReturn* ins = new(alloc()) LReturn; ins->setOperand(0, useFixed(opd, JSReturnReg)); @@ -103,7 +103,7 @@ void LIRGeneratorMIPS64::lowerTruncateDToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Double); + MOZ_ASSERT(opd->type() == MIRType::Double); define(new(alloc()) LTruncateDToInt32(useRegister(opd), tempDouble()), ins); @@ -113,7 +113,7 @@ void LIRGeneratorMIPS64::lowerTruncateFToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Float32); + MOZ_ASSERT(opd->type() == MIRType::Float32); define(new(alloc()) LTruncateFToInt32(useRegister(opd), tempFloat32()), ins); diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index bd81c0b8a2..d73d4db118 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -1530,17 +1530,17 @@ void MacroAssemblerMIPS64Compat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType) { - if (valueType == MIRType_Double) { + if (valueType == MIRType::Double) { storeDouble(value.reg().typedReg().fpu(), dest); return; } // For known integers and booleans, we can just store the unboxed value if // the slot has the same type. - if ((valueType == MIRType_Int32 || valueType == MIRType_Boolean) && slotType == valueType) { + if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) { if (value.constant()) { Value val = value.value(); - if (valueType == MIRType_Int32) + if (valueType == MIRType::Int32) store32(Imm32(val.toInt32()), dest); else store32(Imm32(val.toBoolean() ? 1 : 0), dest); diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 4a49b38a97..74eff505d1 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -426,9 +426,9 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void loadUnboxedValue(const T& address, MIRType type, AnyRegister dest) { if (dest.isFloat()) loadInt32OrDouble(address, dest.fpu()); - else if (type == MIRType_Int32) + else if (type == MIRType::Int32) unboxInt32(address, dest.gpr()); - else if (type == MIRType_Boolean) + else if (type == MIRType::Boolean) unboxBoolean(address, dest.gpr()); else unboxNonDouble(address, dest.gpr()); diff --git a/js/src/jit/none/Lowering-none.h b/js/src/jit/none/Lowering-none.h index b484aabbd1..06bb04ea7c 100644 --- a/js/src/jit/none/Lowering-none.h +++ b/js/src/jit/none/Lowering-none.h @@ -95,7 +95,7 @@ class LIRGeneratorNone : public LIRGeneratorShared void visitSubstr(MSubstr*) { MOZ_CRASH(); } void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); } void visitRandom(js::jit::MRandom*) { MOZ_CRASH(); } - void visitTruncateToInt64(MTruncateToInt64*) { MOZ_CRASH(); } + void visitWasmTruncateToInt64(MWasmTruncateToInt64*) { MOZ_CRASH(); } void visitInt64ToFloatingPoint(MInt64ToFloatingPoint*) { MOZ_CRASH(); } }; diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 6ef85e4d8e..618d509c5e 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -386,14 +386,14 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir, mir = mir->toBox()->getOperand(0); MIRType type = - mir->isRecoveredOnBailout() ? MIRType_None : - mir->isUnused() ? MIRType_MagicOptimizedOut : + mir->isRecoveredOnBailout() ? MIRType::None : + mir->isUnused() ? MIRType::MagicOptimizedOut : mir->type(); RValueAllocation alloc; switch (type) { - case MIRType_None: + case MIRType::None: { MOZ_ASSERT(mir->isRecoveredOnBailout()); uint32_t index = 0; @@ -422,19 +422,19 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir, alloc = RValueAllocation::RecoverInstruction(index); break; } - case MIRType_Undefined: + case MIRType::Undefined: alloc = RValueAllocation::Undefined(); break; - case MIRType_Null: + case MIRType::Null: alloc = RValueAllocation::Null(); break; - case MIRType_Int32: - case MIRType_String: - case MIRType_Symbol: - case MIRType_Object: - case MIRType_ObjectOrNull: - case MIRType_Boolean: - case MIRType_Double: + case MIRType::Int32: + case MIRType::String: + case MIRType::Symbol: + case MIRType::Object: + case MIRType::ObjectOrNull: + case MIRType::Boolean: + case MIRType::Double: { LAllocation* payload = snapshot->payloadOfSlot(*allocIndex); if (payload->isConstant()) { @@ -446,7 +446,7 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir, } JSValueType valueType = - (type == MIRType_ObjectOrNull) ? JSVAL_TYPE_OBJECT : ValueTypeFromMIRType(type); + (type == MIRType::ObjectOrNull) ? JSVAL_TYPE_OBJECT : ValueTypeFromMIRType(type); MOZ_ASSERT(payload->isMemory() || payload->isRegister()); if (payload->isMemory()) @@ -457,10 +457,10 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir, alloc = RValueAllocation::Double(ToFloatRegister(payload)); break; } - case MIRType_Float32: - case MIRType_Bool32x4: - case MIRType_Int32x4: - case MIRType_Float32x4: + case MIRType::Float32: + case MIRType::Bool32x4: + case MIRType::Int32x4: + case MIRType::Float32x4: { LAllocation* payload = snapshot->payloadOfSlot(*allocIndex); if (payload->isConstant()) { @@ -478,14 +478,14 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir, alloc = RValueAllocation::AnyFloat(ToStackIndex(payload)); break; } - case MIRType_MagicOptimizedArguments: - case MIRType_MagicOptimizedOut: - case MIRType_MagicUninitializedLexical: + case MIRType::MagicOptimizedArguments: + case MIRType::MagicOptimizedOut: + case MIRType::MagicUninitializedLexical: { uint32_t index; - Value v = MagicValue(type == MIRType_MagicOptimizedArguments + Value v = MagicValue(type == MIRType::MagicOptimizedArguments ? JS_OPTIMIZED_ARGUMENTS - : (type == MIRType_MagicOptimizedOut + : (type == MIRType::MagicOptimizedOut ? JS_OPTIMIZED_OUT : JS_UNINITIALIZED_LEXICAL)); masm.propagateOOM(graph.addConstantToPool(v, &index)); @@ -494,7 +494,7 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir, } default: { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); LAllocation* payload = snapshot->payloadOfSlot(*allocIndex); #ifdef JS_NUNBOX32 LAllocation* type = snapshot->typeOfSlot(*allocIndex); @@ -1536,17 +1536,17 @@ CodeGeneratorShared::emitPreBarrier(Register base, const LAllocation* index, int { if (index->isConstant()) { Address address(base, ToInt32(index) * sizeof(Value) + offsetAdjustment); - masm.patchableCallPreBarrier(address, MIRType_Value); + masm.patchableCallPreBarrier(address, MIRType::Value); } else { BaseIndex address(base, ToRegister(index), TimesEight, offsetAdjustment); - masm.patchableCallPreBarrier(address, MIRType_Value); + masm.patchableCallPreBarrier(address, MIRType::Value); } } void CodeGeneratorShared::emitPreBarrier(Address address) { - masm.patchableCallPreBarrier(address, MIRType_Value); + masm.patchableCallPreBarrier(address, MIRType::Value); } Label* @@ -1620,7 +1620,7 @@ CodeGeneratorShared::jumpToBlock(MBasicBlock* mir, Assembler::Condition cond) } #endif -MOZ_WARN_UNUSED_RESULT bool +MOZ_MUST_USE bool CodeGeneratorShared::addCacheLocations(const CacheLocationList& locs, size_t* numLocs, size_t* curIndex) { diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index c25f55c8bf..71ed022dcf 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -33,6 +33,7 @@ template class OutOfLineCallVM; class OutOfLineTruncateSlow; +class OutOfLineWasmTruncateCheck; struct PatchableBackedgeInfo { @@ -262,7 +263,7 @@ class CodeGeneratorShared : public LElementVisitor }; protected: - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool allocateData(size_t size, size_t* offset) { MOZ_ASSERT(size % sizeof(void*) == 0); *offset = runtimeData_.length(); @@ -484,6 +485,10 @@ class CodeGeneratorShared : public LElementVisitor void visitOutOfLineTruncateSlow(OutOfLineTruncateSlow* ool); + virtual void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool) { + MOZ_CRASH("NYI"); + } + bool omitOverRecursedCheck() const; #ifdef JS_TRACE_LOGGING @@ -770,6 +775,34 @@ CodeGeneratorShared::visitOutOfLineCallVM(OutOfLineCallVM masm.jump(ool->rejoin()); } +class OutOfLineWasmTruncateCheck : public OutOfLineCodeBase +{ + MIRType fromType_; + MIRType toType_; + FloatRegister input_; + bool isUnsigned_; + + public: + OutOfLineWasmTruncateCheck(MWasmTruncateToInt32* mir, FloatRegister input) + : fromType_(mir->input()->type()), toType_(MIRType::Int32), input_(input), + isUnsigned_(mir->isUnsigned()) + { } + + OutOfLineWasmTruncateCheck(MWasmTruncateToInt64* mir, FloatRegister input) + : fromType_(mir->input()->type()), toType_(MIRType::Int64), input_(input), + isUnsigned_(mir->isUnsigned()) + { } + + void accept(CodeGeneratorShared* codegen) { + codegen->visitOutOfLineWasmTruncateCheck(this); + } + + FloatRegister input() const { return input_; } + MIRType toType() const { return toType_; } + MIRType fromType() const { return fromType_; } + bool isUnsigned() const { return isUnsigned_; } +}; + } // namespace jit } // namespace js diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index f2cec0701c..afcfa0ac64 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1297,6 +1297,32 @@ class LAsmReinterpretToI64 : public LAsmReinterpretBase } }; +namespace details { + template + class RotateBase : public LInstructionHelper + { + typedef LInstructionHelper Base; + public: + MRotate* mir() { + return Base::mir_->toRotate(); + } + const LAllocation* input() { return Base::getOperand(0); } + const LAllocation* count() { return Base::getOperand(1); } + }; +} // details + +class LRotate : public details::RotateBase<1, 2> +{ + public: + LIR_HEADER(Rotate); +}; + +class LRotate64 : public details::RotateBase +{ + public: + LIR_HEADER(Rotate64); +}; + class LInterruptCheck : public LInstructionHelper<0, 0, 0> { Label* oolEntry_; @@ -4013,6 +4039,20 @@ class LTruncateFToInt32 : public LInstructionHelper<1, 1, 1> } }; +class LWasmTruncateToInt32 : public LInstructionHelper<1, 1, 0> +{ + public: + LIR_HEADER(WasmTruncateToInt32) + + explicit LWasmTruncateToInt32(const LAllocation& in) { + setOperand(0, in); + } + + MWasmTruncateToInt32* mir() const { + return mir_->toWasmTruncateToInt32(); + } +}; + class LWrapInt64ToInt32 : public LInstructionHelper<1, INT64_PIECES, 0> { public: @@ -4439,6 +4479,32 @@ class LRegExpInstanceOptimizable : public LInstructionHelper<1, 2, 1> } }; +class LGetFirstDollarIndex : public LInstructionHelper<1, 1, 3> +{ + public: + LIR_HEADER(GetFirstDollarIndex); + explicit LGetFirstDollarIndex(const LAllocation& str, const LDefinition& temp0, + const LDefinition& temp1, const LDefinition& temp2) { + setOperand(0, str); + setTemp(0, temp0); + setTemp(1, temp1); + setTemp(2, temp2); + } + + const LAllocation* str() { + return getOperand(0); + } + const LDefinition* temp0() { + return getTemp(0); + } + const LDefinition* temp1() { + return getTemp(1); + } + const LDefinition* temp2() { + return getTemp(2); + } +}; + class LStringReplace: public LCallInstructionHelper<1, 3, 0> { public: diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index a65e08921e..241b54ec8a 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -189,6 +189,7 @@ _(Float32ToInt32) \ _(TruncateDToInt32) \ _(TruncateFToInt32) \ + _(WasmTruncateToInt32) \ _(WrapInt64ToInt32) \ _(ExtendInt32ToInt64) \ _(BooleanToString) \ @@ -211,6 +212,7 @@ _(RegExpTester) \ _(RegExpPrototypeOptimizable) \ _(RegExpInstanceOptimizable) \ + _(GetFirstDollarIndex) \ _(StringReplace) \ _(Substr) \ _(BinarySharedStub) \ @@ -351,6 +353,8 @@ _(AsmReinterpret) \ _(AsmReinterpretToI64) \ _(AsmReinterpretFromI64) \ + _(Rotate) \ + _(Rotate64) \ _(GetDOMProperty) \ _(GetDOMMemberV) \ _(GetDOMMemberT) \ diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index d9c3346ed3..d5bfdee868 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -28,8 +28,8 @@ LIRGeneratorShared::use(MDefinition* mir, LUse policy) { // It is illegal to call use() on an instruction with two defs. #if BOX_PIECES > 1 - MOZ_ASSERT(mir->type() != MIRType_Value); - MOZ_ASSERT(mir->type() != MIRType_Int64); + MOZ_ASSERT(mir->type() != MIRType::Value); + MOZ_ASSERT(mir->type() != MIRType::Int64); #endif ensureDefined(mir); policy.setVirtualRegister(mir->virtualRegister()); @@ -151,7 +151,7 @@ LIRGeneratorShared::defineBox(LInstructionHelper* lir, M { // Call instructions should use defineReturn. MOZ_ASSERT(!lir->isCall()); - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); uint32_t vreg = getVirtualRegister(); @@ -174,7 +174,7 @@ LIRGeneratorShared::defineInt64(LInstructionHelper* li { // Call instructions should use defineReturn. MOZ_ASSERT(!lir->isCall()); - MOZ_ASSERT(mir->type() == MIRType_Int64); + MOZ_ASSERT(mir->type() == MIRType::Int64); uint32_t vreg = getVirtualRegister(); @@ -197,7 +197,7 @@ LIRGeneratorShared::defineSharedStubReturn(LInstruction* lir, MDefinition* mir) lir->setMir(mir); MOZ_ASSERT(lir->isBinarySharedStub() || lir->isUnarySharedStub() || lir->isNullarySharedStub()); - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); uint32_t vreg = getVirtualRegister(); @@ -225,7 +225,7 @@ LIRGeneratorShared::defineReturn(LInstruction* lir, MDefinition* mir) uint32_t vreg = getVirtualRegister(); switch (mir->type()) { - case MIRType_Value: + case MIRType::Value: #if defined(JS_NUNBOX32) lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, LGeneralReg(JSReturnReg_Type))); @@ -236,17 +236,17 @@ LIRGeneratorShared::defineReturn(LInstruction* lir, MDefinition* mir) lir->setDef(0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg))); #endif break; - case MIRType_Float32: + case MIRType::Float32: lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32, LFloatReg(ReturnFloat32Reg))); break; - case MIRType_Double: + case MIRType::Double: lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg))); break; - case MIRType_Bool32x4: - case MIRType_Int32x4: + case MIRType::Bool32x4: + case MIRType::Int32x4: lir->setDef(0, LDefinition(vreg, LDefinition::INT32X4, LFloatReg(ReturnSimd128Reg))); break; - case MIRType_Float32x4: + case MIRType::Float32x4: lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32X4, LFloatReg(ReturnSimd128Reg))); break; default: @@ -302,8 +302,8 @@ IsCompatibleLIRCoercion(MIRType to, MIRType from) { if (to == from) return true; - if ((to == MIRType_Int32 || to == MIRType_Boolean) && - (from == MIRType_Int32 || from == MIRType_Boolean)) { + if ((to == MIRType::Int32 || to == MIRType::Boolean) && + (from == MIRType::Int32 || from == MIRType::Boolean)) { return true; } // SIMD types can be coerced with from*Bits operators. @@ -318,7 +318,7 @@ void LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func) { MOZ_ASSERT(def->isMathFunction()); - MOZ_ASSERT(def->type() == MIRType_Double && as->type() == MIRType_SinCosDouble); + MOZ_ASSERT(def->type() == MIRType::Double && as->type() == MIRType::SinCosDouble); MOZ_ASSERT(MMathFunction::Sin == func || MMathFunction::Cos == func); ensureDefined(as); @@ -347,12 +347,12 @@ LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as) if (as->isEmittedAtUses() && (def->type() == as->type() || (as->isConstant() && - (def->type() == MIRType_Int32 || def->type() == MIRType_Boolean) && - (as->type() == MIRType_Int32 || as->type() == MIRType_Boolean)))) + (def->type() == MIRType::Int32 || def->type() == MIRType::Boolean) && + (as->type() == MIRType::Int32 || as->type() == MIRType::Boolean)))) { MInstruction* replacement; if (def->type() != as->type()) { - if (as->type() == MIRType_Int32) + if (as->type() == MIRType::Int32) replacement = MConstant::New(alloc(), BooleanValue(as->toConstant()->toInt32())); else replacement = MConstant::New(alloc(), Int32Value(as->toConstant()->toBoolean())); @@ -372,15 +372,15 @@ LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as) !def->resultTypeSet()->equals(as->resultTypeSet())) { switch (def->type()) { - case MIRType_Object: - case MIRType_ObjectOrNull: - case MIRType_String: - case MIRType_Symbol: { + case MIRType::Object: + case MIRType::ObjectOrNull: + case MIRType::String: + case MIRType::Symbol: { LAssertResultT* check = new(alloc()) LAssertResultT(useRegister(def)); add(check, def->toInstruction()); break; } - case MIRType_Value: { + case MIRType::Value: { LAssertResultV* check = new(alloc()) LAssertResultV(useBox(def)); add(check, def->toInstruction()); break; @@ -469,7 +469,7 @@ LIRGeneratorShared::useRegisterOrZeroAtStart(MDefinition* mir) LAllocation LIRGeneratorShared::useRegisterOrNonDoubleConstant(MDefinition* mir) { - if (mir->isConstant() && mir->type() != MIRType_Double && mir->type() != MIRType_Float32) + if (mir->isConstant() && mir->type() != MIRType::Double && mir->type() != MIRType::Float32) return LAllocation(mir->toConstant()); return useRegister(mir); } @@ -622,7 +622,7 @@ VirtualRegisterOfPayload(MDefinition* mir) { if (mir->isBox()) { MDefinition* inner = mir->toBox()->getOperand(0); - if (!inner->isConstant() && inner->type() != MIRType_Double && inner->type() != MIRType_Float32) + if (!inner->isConstant() && inner->type() != MIRType::Double && inner->type() != MIRType::Float32) return inner->virtualRegister(); } if (mir->isTypeBarrier()) @@ -635,7 +635,7 @@ VirtualRegisterOfPayload(MDefinition* mir) LUse LIRGeneratorShared::useType(MDefinition* mir, LUse::Policy policy) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); return LUse(mir->virtualRegister() + VREG_TYPE_OFFSET, policy); } @@ -643,7 +643,7 @@ LIRGeneratorShared::useType(MDefinition* mir, LUse::Policy policy) LUse LIRGeneratorShared::usePayload(MDefinition* mir, LUse::Policy policy) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); return LUse(VirtualRegisterOfPayload(mir), policy); } @@ -651,7 +651,7 @@ LIRGeneratorShared::usePayload(MDefinition* mir, LUse::Policy policy) LUse LIRGeneratorShared::usePayloadAtStart(MDefinition* mir, LUse::Policy policy) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); return LUse(VirtualRegisterOfPayload(mir), policy, true); } @@ -674,14 +674,14 @@ LIRGeneratorShared::fillBoxUses(LInstruction* lir, size_t n, MDefinition* mir) LUse LIRGeneratorShared::useRegisterForTypedLoad(MDefinition* mir, MIRType type) { - MOZ_ASSERT(type != MIRType_Value && type != MIRType_None); - MOZ_ASSERT(mir->type() == MIRType_Object || mir->type() == MIRType_Slots); + MOZ_ASSERT(type != MIRType::Value && type != MIRType::None); + MOZ_ASSERT(mir->type() == MIRType::Object || mir->type() == MIRType::Slots); #ifdef JS_PUNBOX64 // On x64, masm.loadUnboxedValue emits slightly less efficient code when // the input and output use the same register and we're not loading an // int32/bool/double, so we just call useRegister in this case. - if (type != MIRType_Int32 && type != MIRType_Boolean && type != MIRType_Double) + if (type != MIRType::Int32 && type != MIRType::Boolean && type != MIRType::Double) return useRegister(mir); #endif @@ -691,7 +691,7 @@ LIRGeneratorShared::useRegisterForTypedLoad(MDefinition* mir, MIRType type) LBoxAllocation LIRGeneratorShared::useBox(MDefinition* mir, LUse::Policy policy, bool useAtStart) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); ensureDefined(mir); @@ -706,7 +706,7 @@ LIRGeneratorShared::useBox(MDefinition* mir, LUse::Policy policy, bool useAtStar LBoxAllocation LIRGeneratorShared::useBoxOrTypedOrConstant(MDefinition* mir, bool useConstant) { - if (mir->type() == MIRType_Value) + if (mir->type() == MIRType::Value) return useBox(mir); @@ -728,7 +728,7 @@ LIRGeneratorShared::useBoxOrTypedOrConstant(MDefinition* mir, bool useConstant) LInt64Allocation LIRGeneratorShared::useInt64(MDefinition* mir, LUse::Policy policy, bool useAtStart) { - MOZ_ASSERT(mir->type() == MIRType_Int64); + MOZ_ASSERT(mir->type() == MIRType::Int64); ensureDefined(mir); diff --git a/js/src/jit/shared/Lowering-shared.cpp b/js/src/jit/shared/Lowering-shared.cpp index 27013c685b..2a3c75df70 100644 --- a/js/src/jit/shared/Lowering-shared.cpp +++ b/js/src/jit/shared/Lowering-shared.cpp @@ -80,28 +80,28 @@ LIRGeneratorShared::visitConstant(MConstant* ins) } switch (ins->type()) { - case MIRType_Double: + case MIRType::Double: define(new(alloc()) LDouble(ins->toDouble()), ins); break; - case MIRType_Float32: + case MIRType::Float32: define(new(alloc()) LFloat32(ins->toFloat32()), ins); break; - case MIRType_Boolean: + case MIRType::Boolean: define(new(alloc()) LInteger(ins->toBoolean()), ins); break; - case MIRType_Int32: + case MIRType::Int32: define(new(alloc()) LInteger(ins->toInt32()), ins); break; - case MIRType_Int64: + case MIRType::Int64: defineInt64(new(alloc()) LInteger64(ins->toInt64()), ins); break; - case MIRType_String: + case MIRType::String: define(new(alloc()) LPointer(ins->toString()), ins); break; - case MIRType_Symbol: + case MIRType::Symbol: define(new(alloc()) LPointer(ins->toSymbol()), ins); break; - case MIRType_Object: + case MIRType::Object: define(new(alloc()) LPointer(&ins->toObject()), ins); break; default: @@ -154,7 +154,7 @@ LRecoverInfo::OperandIter::canOptimizeOutIfUnused() // We check ins->type() in addition to ins->isUnused() because // EliminateDeadResumePointOperands may replace nodes with the constant // MagicValue(JS_OPTIMIZED_OUT). - if ((ins->isUnused() || ins->type() == MIRType_MagicOptimizedOut) && + if ((ins->isUnused() || ins->type() == MIRType::MagicOptimizedOut) && (*it_)->isResumePoint()) { return !(*it_)->toResumePoint()->isObservableOperand(op_); @@ -209,7 +209,7 @@ LIRGeneratorShared::buildSnapshot(LInstruction* ins, MResumePoint* rp, BailoutKi if (ins->isConstant() || ins->isUnused()) { *type = LAllocation(); *payload = LAllocation(); - } else if (ins->type() != MIRType_Value) { + } else if (ins->type() != MIRType::Value) { *type = LAllocation(); *payload = use(ins, LUse(LUse::KEEPALIVE)); } else { diff --git a/js/src/jit/x64/Assembler-x64.cpp b/js/src/jit/x64/Assembler-x64.cpp index fc7d8e2b79..dc36805e51 100644 --- a/js/src/jit/x64/Assembler-x64.cpp +++ b/js/src/jit/x64/Assembler-x64.cpp @@ -44,20 +44,20 @@ ABIArgGenerator::next(MIRType type) return current_; } switch (type) { - case MIRType_Int32: - case MIRType_Int64: - case MIRType_Pointer: + case MIRType::Int32: + case MIRType::Int64: + case MIRType::Pointer: current_ = ABIArg(IntArgRegs[regIndex_++]); break; - case MIRType_Float32: + case MIRType::Float32: current_ = ABIArg(FloatArgRegs[regIndex_++].asSingle()); break; - case MIRType_Double: + case MIRType::Double: current_ = ABIArg(FloatArgRegs[regIndex_++]); break; - case MIRType_Bool32x4: - case MIRType_Int32x4: - case MIRType_Float32x4: + case MIRType::Bool32x4: + case MIRType::Int32x4: + case MIRType::Float32x4: // On Win64, >64 bit args need to be passed by reference, but asm.js // doesn't allow passing SIMD values to FFIs. The only way to reach // here is asm to asm calls, so we can break the ABI here. @@ -69,9 +69,9 @@ ABIArgGenerator::next(MIRType type) return current_; #else switch (type) { - case MIRType_Int32: - case MIRType_Int64: - case MIRType_Pointer: + case MIRType::Int32: + case MIRType::Int64: + case MIRType::Pointer: if (intRegIndex_ == NumIntArgRegs) { current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint64_t); @@ -79,21 +79,21 @@ ABIArgGenerator::next(MIRType type) } current_ = ABIArg(IntArgRegs[intRegIndex_++]); break; - case MIRType_Double: - case MIRType_Float32: + case MIRType::Double: + case MIRType::Float32: if (floatRegIndex_ == NumFloatArgRegs) { current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint64_t); break; } - if (type == MIRType_Float32) + if (type == MIRType::Float32) current_ = ABIArg(FloatArgRegs[floatRegIndex_++].asSingle()); else current_ = ABIArg(FloatArgRegs[floatRegIndex_++]); break; - case MIRType_Bool32x4: - case MIRType_Int32x4: - case MIRType_Float32x4: + case MIRType::Bool32x4: + case MIRType::Int32x4: + case MIRType::Float32x4: if (floatRegIndex_ == NumFloatArgRegs) { stackOffset_ = AlignBytes(stackOffset_, SimdMemoryAlignment); current_ = ABIArg(stackOffset_); diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index ad26cef0b8..e5f2bb996d 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -589,6 +589,18 @@ class Assembler : public AssemblerX86Shared void sarq_cl(Register dest) { masm.sarq_CLr(dest.encoding()); } + void rolq(Imm32 imm, Register dest) { + masm.rolq_ir(imm.value, dest.encoding()); + } + void rolq_cl(Register dest) { + masm.rolq_CLr(dest.encoding()); + } + void rorq(Imm32 imm, Register dest) { + masm.rorq_ir(imm.value, dest.encoding()); + } + void rorq_cl(Register dest) { + masm.rorq_CLr(dest.encoding()); + } void orq(Imm32 imm, Register dest) { masm.orq_ir(imm.value, dest.encoding()); } diff --git a/js/src/jit/x64/BaseAssembler-x64.h b/js/src/jit/x64/BaseAssembler-x64.h index 5921050833..304bbeb1e3 100644 --- a/js/src/jit/x64/BaseAssembler-x64.h +++ b/js/src/jit/x64/BaseAssembler-x64.h @@ -287,6 +287,40 @@ class BaseAssemblerX64 : public BaseAssembler } } + void rolq_ir(int32_t imm, RegisterID dst) + { + MOZ_ASSERT(imm < 64); + spew("rolq $%d, %s", imm, GPReg64Name(dst)); + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_ROL); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_ROL); + m_formatter.immediate8u(imm); + } + } + void rolq_CLr(RegisterID dst) + { + spew("rolq %%cl, %s", GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_GROUP2_EvCL, dst, GROUP2_OP_ROL); + } + + void rorq_ir(int32_t imm, RegisterID dst) + { + MOZ_ASSERT(imm < 64); + spew("rorq $%d, %s", imm, GPReg64Name(dst)); + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_ROR); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_ROR); + m_formatter.immediate8u(imm); + } + } + void rorq_CLr(RegisterID dst) + { + spew("rorq %%cl, %s", GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_GROUP2_EvCL, dst, GROUP2_OP_ROR); + } + void imulq_rr(RegisterID src, RegisterID dst) { spew("imulq %s, %s", GPReg64Name(src), GPReg64Name(dst)); @@ -617,7 +651,7 @@ class BaseAssemblerX64 : public BaseAssembler m_formatter.oneByteOp64(OP_MOVSXD_GvEv, offset, base, index, scale, dst); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc movl_ripr(RegisterID dst) { m_formatter.oneByteRipOp(OP_MOV_GvEv, 0, (RegisterID)dst); @@ -626,7 +660,7 @@ class BaseAssemblerX64 : public BaseAssembler return label; } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc movl_rrip(RegisterID src) { m_formatter.oneByteRipOp(OP_MOV_EvGv, 0, (RegisterID)src); @@ -635,7 +669,7 @@ class BaseAssemblerX64 : public BaseAssembler return label; } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc movq_ripr(RegisterID dst) { m_formatter.oneByteRipOp64(OP_MOV_GvEv, 0, dst); @@ -650,7 +684,7 @@ class BaseAssemblerX64 : public BaseAssembler m_formatter.oneByteOp64(OP_LEA, offset, base, dst); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc leaq_rip(RegisterID dst) { m_formatter.oneByteRipOp64(OP_LEA, 0, dst); @@ -714,44 +748,44 @@ class BaseAssemblerX64 : public BaseAssembler twoByteOpInt64Simd("vmovq", VEX_PD, OP2_MOVD_VdEd, src, invalid_xmm, dst); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc vmovsd_ripr(XMMRegisterID dst) { return twoByteRipOpSimd("vmovsd", VEX_SD, OP2_MOVSD_VsdWsd, invalid_xmm, dst); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc vmovss_ripr(XMMRegisterID dst) { return twoByteRipOpSimd("vmovss", VEX_SS, OP2_MOVSD_VsdWsd, invalid_xmm, dst); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc vmovsd_rrip(XMMRegisterID src) { return twoByteRipOpSimd("vmovsd", VEX_SD, OP2_MOVSD_WsdVsd, invalid_xmm, src); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc vmovss_rrip(XMMRegisterID src) { return twoByteRipOpSimd("vmovss", VEX_SS, OP2_MOVSD_WsdVsd, invalid_xmm, src); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc vmovdqa_rrip(XMMRegisterID src) { return twoByteRipOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_WdqVdq, invalid_xmm, src); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc vmovaps_rrip(XMMRegisterID src) { return twoByteRipOpSimd("vmovdqa", VEX_PS, OP2_MOVAPS_WsdVsd, invalid_xmm, src); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc vmovaps_ripr(XMMRegisterID dst) { return twoByteRipOpSimd("vmovaps", VEX_PS, OP2_MOVAPS_VsdWsd, invalid_xmm, dst); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc vmovdqa_ripr(XMMRegisterID dst) { return twoByteRipOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_VdqWdq, invalid_xmm, dst); @@ -759,7 +793,7 @@ class BaseAssemblerX64 : public BaseAssembler private: - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc twoByteRipOpSimd(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, XMMRegisterID src0, XMMRegisterID dst) { diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp index e46d64124e..7802be0915 100644 --- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -76,7 +76,7 @@ CodeGeneratorX64::visitBox(LBox* box) if (IsFloatingPointType(box->type())) { ScratchDoubleScope scratch(masm); FloatRegister reg = ToFloatRegister(in); - if (box->type() == MIRType_Float32) { + if (box->type() == MIRType::Float32) { masm.convertFloat32ToDouble(reg, scratch); reg = scratch; } @@ -95,19 +95,19 @@ CodeGeneratorX64::visitUnbox(LUnbox* unbox) const ValueOperand value = ToValue(unbox, LUnbox::Input); Assembler::Condition cond; switch (mir->type()) { - case MIRType_Int32: + case MIRType::Int32: cond = masm.testInt32(Assembler::NotEqual, value); break; - case MIRType_Boolean: + case MIRType::Boolean: cond = masm.testBoolean(Assembler::NotEqual, value); break; - case MIRType_Object: + case MIRType::Object: cond = masm.testObject(Assembler::NotEqual, value); break; - case MIRType_String: + case MIRType::String: cond = masm.testString(Assembler::NotEqual, value); break; - case MIRType_Symbol: + case MIRType::Symbol: cond = masm.testSymbol(Assembler::NotEqual, value); break; default: @@ -119,19 +119,19 @@ CodeGeneratorX64::visitUnbox(LUnbox* unbox) Operand input = ToOperand(unbox->getOperand(LUnbox::Input)); Register result = ToRegister(unbox->output()); switch (mir->type()) { - case MIRType_Int32: + case MIRType::Int32: masm.unboxInt32(input, result); break; - case MIRType_Boolean: + case MIRType::Boolean: masm.unboxBoolean(input, result); break; - case MIRType_Object: + case MIRType::Object: masm.unboxObject(input, result); break; - case MIRType_String: + case MIRType::String: masm.unboxString(input, result); break; - case MIRType_Symbol: + case MIRType::Symbol: masm.unboxSymbol(input, result); break; default: @@ -323,6 +323,30 @@ CodeGeneratorX64::visitShiftI64(LShiftI64* lir) } } +void +CodeGeneratorX64::visitRotate64(LRotate64* lir) +{ + MRotate* mir = lir->mir(); + Register input = ToRegister(lir->input()); + const LAllocation* count = lir->count(); + + if (count->isConstant()) { + int32_t c = int32_t(ToInt64(count) & 0x3F); + if (!c) + return; + if (mir->isLeftRotate()) + masm.rolq(Imm32(c), input); + else + masm.rorq(Imm32(c), input); + } else { + MOZ_ASSERT(ToRegister(count) == ecx); + if (mir->isLeftRotate()) + masm.rolq_cl(input); + else + masm.rorq_cl(input); + } +} + void CodeGeneratorX64::visitAddI64(LAddI64* lir) { @@ -480,7 +504,7 @@ CodeGeneratorX64::visitUDivOrMod64(LUDivOrMod64* lir) void CodeGeneratorX64::visitAsmSelectI64(LAsmSelectI64* lir) { - MOZ_ASSERT(lir->mir()->type() == MIRType_Int64); + MOZ_ASSERT(lir->mir()->type() == MIRType::Int64); Register cond = ToRegister(lir->condExpr()); Operand falseExpr = ToOperand(lir->falseExpr()); @@ -495,16 +519,16 @@ CodeGeneratorX64::visitAsmSelectI64(LAsmSelectI64* lir) void CodeGeneratorX64::visitAsmReinterpretFromI64(LAsmReinterpretFromI64* lir) { - MOZ_ASSERT(lir->mir()->type() == MIRType_Double); - MOZ_ASSERT(lir->mir()->input()->type() == MIRType_Int64); + MOZ_ASSERT(lir->mir()->type() == MIRType::Double); + MOZ_ASSERT(lir->mir()->input()->type() == MIRType::Int64); masm.vmovq(ToRegister(lir->input()), ToFloatRegister(lir->output())); } void CodeGeneratorX64::visitAsmReinterpretToI64(LAsmReinterpretToI64* lir) { - MOZ_ASSERT(lir->mir()->type() == MIRType_Int64); - MOZ_ASSERT(lir->mir()->input()->type() == MIRType_Double); + MOZ_ASSERT(lir->mir()->type() == MIRType::Int64); + MOZ_ASSERT(lir->mir()->input()->type() == MIRType::Double); masm.vmovq(ToFloatRegister(lir->input()), ToRegister(lir->output())); } @@ -1007,22 +1031,22 @@ CodeGeneratorX64::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins) CodeOffset label; switch (type) { - case MIRType_Int32: + case MIRType::Int32: label = masm.loadRipRelativeInt32(ToRegister(ins->output())); break; - case MIRType_Float32: + case MIRType::Float32: label = masm.loadRipRelativeFloat32(ToFloatRegister(ins->output())); break; - case MIRType_Double: + case MIRType::Double: label = masm.loadRipRelativeDouble(ToFloatRegister(ins->output())); break; // Aligned access: code is aligned on PageSize + there is padding // before the global data section. - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: label = masm.loadRipRelativeInt32x4(ToFloatRegister(ins->output())); break; - case MIRType_Float32x4: + case MIRType::Float32x4: label = masm.loadRipRelativeFloat32x4(ToFloatRegister(ins->output())); break; default: @@ -1042,22 +1066,22 @@ CodeGeneratorX64::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins) CodeOffset label; switch (type) { - case MIRType_Int32: + case MIRType::Int32: label = masm.storeRipRelativeInt32(ToRegister(ins->value())); break; - case MIRType_Float32: + case MIRType::Float32: label = masm.storeRipRelativeFloat32(ToFloatRegister(ins->value())); break; - case MIRType_Double: + case MIRType::Double: label = masm.storeRipRelativeDouble(ToFloatRegister(ins->value())); break; // Aligned access: code is aligned on PageSize + there is padding // before the global data section. - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: label = masm.storeRipRelativeInt32x4(ToFloatRegister(ins->value())); break; - case MIRType_Float32x4: + case MIRType::Float32x4: label = masm.storeRipRelativeFloat32x4(ToFloatRegister(ins->value())); break; default: @@ -1145,77 +1169,101 @@ CodeGeneratorX64::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir) } void -CodeGeneratorX64::visitTruncateToInt64(LTruncateToInt64* lir) +CodeGeneratorX64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir) { FloatRegister input = ToFloatRegister(lir->input()); Register output = ToRegister(lir->output()); - MIRType inputType = lir->mir()->input()->type(); + MWasmTruncateToInt64* mir = lir->mir(); + MIRType inputType = mir->input()->type(); - // We should trap on invalid inputs, but for now we just return - // 0x8000000000000000. Note that we can remove some unnecessary jumps - // once we get rid of this trap Label. - Label trap; + auto* ool = new(alloc()) OutOfLineWasmTruncateCheck(mir, input); + addOutOfLineCode(ool, mir); - Label done; - if (lir->mir()->isUnsigned()) { + if (mir->isUnsigned()) { FloatRegister tempDouble = ToFloatRegister(lir->temp()); // If the input < INT64_MAX, vcvttsd2sq will do the right thing, so // we use it directly. Else, we subtract INT64_MAX, convert to int64, // and then add INT64_MAX to the result. - if (inputType == MIRType_Double) { + if (inputType == MIRType::Double) { Label isLarge; masm.loadConstantDouble(double(0x8000000000000000), ScratchDoubleReg); masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg, &isLarge); masm.vcvttsd2sq(input, output); - masm.branchTestPtr(Assembler::Signed, output, output, &trap); - masm.jump(&done); + masm.branchTestPtr(Assembler::Signed, output, output, ool->entry()); + masm.jump(ool->rejoin()); masm.bind(&isLarge); masm.moveDouble(input, tempDouble); masm.subDouble(ScratchDoubleReg, tempDouble); masm.vcvttsd2sq(tempDouble, output); - masm.branchTestPtr(Assembler::Signed, output, output, &trap); + masm.branchTestPtr(Assembler::Signed, output, output, ool->entry()); masm.or64(Imm64(0x8000000000000000), Register64(output)); - masm.jump(&done); } else { - MOZ_ASSERT(inputType == MIRType_Float32); + MOZ_ASSERT(inputType == MIRType::Float32); Label isLarge; masm.loadConstantFloat32(float(0x8000000000000000), ScratchDoubleReg); masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg, &isLarge); masm.vcvttss2sq(input, output); - masm.branchTestPtr(Assembler::Signed, output, output, &trap); - masm.jump(&done); + masm.branchTestPtr(Assembler::Signed, output, output, ool->entry()); + masm.jump(ool->rejoin()); masm.bind(&isLarge); masm.moveFloat32(input, tempDouble); masm.vsubss(ScratchDoubleReg, tempDouble, tempDouble); masm.vcvttss2sq(tempDouble, output); - masm.branchTestPtr(Assembler::Signed, output, output, &trap); + masm.branchTestPtr(Assembler::Signed, output, output, ool->entry()); masm.or64(Imm64(0x8000000000000000), Register64(output)); - masm.jump(&done); } } else { - if (inputType == MIRType_Double) { + if (inputType == MIRType::Double) { masm.vcvttsd2sq(input, output); masm.cmpq(Imm32(1), output); - masm.j(Assembler::Overflow, &trap); - masm.jump(&done); + masm.j(Assembler::Overflow, ool->entry()); } else { - MOZ_ASSERT(inputType == MIRType_Float32); + MOZ_ASSERT(inputType == MIRType::Float32); masm.vcvttss2sq(input, output); masm.cmpq(Imm32(1), output); - masm.j(Assembler::Overflow, &trap); - masm.jump(&done); + masm.j(Assembler::Overflow, ool->entry()); } } - masm.bind(&trap); - masm.movePtr(ImmWord(0x8000000000000000), output); + masm.bind(ool->rejoin()); +} - masm.bind(&done); +void +CodeGeneratorX64::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir) +{ + auto input = ToFloatRegister(lir->input()); + auto output = ToRegister(lir->output()); + + MWasmTruncateToInt32* mir = lir->mir(); + MIRType fromType = mir->input()->type(); + + auto* ool = new (alloc()) OutOfLineWasmTruncateCheck(mir, input); + addOutOfLineCode(ool, mir); + + if (mir->isUnsigned()) { + if (fromType == MIRType::Double) + masm.vcvttsd2sq(input, output); + else if (fromType == MIRType::Float32) + masm.vcvttss2sq(input, output); + else + MOZ_CRASH("unexpected type in visitWasmTruncateToInt32"); + + // Check that the result is in the uint32_t range. + ScratchRegisterScope scratch(masm); + masm.move32(Imm32(0xffffffff), scratch); + masm.cmpq(scratch, output); + masm.j(Assembler::Above, ool->entry()); + return; + } + + emitWasmSignedTruncateToInt32(ool, output); + + masm.bind(ool->rejoin()); } void @@ -1225,10 +1273,10 @@ CodeGeneratorX64::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir) FloatRegister output = ToFloatRegister(lir->output()); MIRType outputType = lir->mir()->type(); - MOZ_ASSERT(outputType == MIRType_Double || outputType == MIRType_Float32); + MOZ_ASSERT(outputType == MIRType::Double || outputType == MIRType::Float32); // Zero the output register to break dependencies, see convertInt32ToDouble. - if (outputType == MIRType_Double) + if (outputType == MIRType::Double) masm.zeroDouble(output); else masm.zeroFloat32(output); @@ -1238,7 +1286,7 @@ CodeGeneratorX64::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir) // If the input is unsigned, we use cvtsq2sd or vcvtsq2ss directly. // Else, we divide by 2, convert to double or float, and multiply the // result by 2. - if (outputType == MIRType_Double) { + if (outputType == MIRType::Double) { Label isSigned; masm.branchTestPtr(Assembler::Signed, input, input, &isSigned); masm.vcvtsq2sd(input, output, output); @@ -1264,7 +1312,7 @@ CodeGeneratorX64::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir) masm.vaddss(output, output, output); } } else { - if (outputType == MIRType_Double) + if (outputType == MIRType::Double) masm.vcvtsq2sd(input, output, output); else masm.vcvtsq2ss(input, output, output); diff --git a/js/src/jit/x64/CodeGenerator-x64.h b/js/src/jit/x64/CodeGenerator-x64.h index 4ae961734f..ad6757461f 100644 --- a/js/src/jit/x64/CodeGenerator-x64.h +++ b/js/src/jit/x64/CodeGenerator-x64.h @@ -46,6 +46,7 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared void visitCompare64AndBranch(LCompare64AndBranch* lir); void visitBitOpI64(LBitOpI64* lir); void visitShiftI64(LShiftI64* lir); + void visitRotate64(LRotate64* lir); void visitAddI64(LAddI64* lir); void visitSubI64(LSubI64* lir); void visitMulI64(LMulI64* lir); @@ -55,7 +56,7 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared void visitTruncateFToInt32(LTruncateFToInt32* ins); void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir); void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir); - void visitTruncateToInt64(LTruncateToInt64* lir); + void visitWasmTruncateToInt64(LWasmTruncateToInt64* lir); void visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir); void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins); void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins); @@ -75,6 +76,8 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir); void visitAsmReinterpretFromI64(LAsmReinterpretFromI64* lir); void visitAsmReinterpretToI64(LAsmReinterpretToI64* lir); + + void visitWasmTruncateToInt32(LWasmTruncateToInt32* lir); }; typedef CodeGeneratorX64 CodeGeneratorSpecific; diff --git a/js/src/jit/x64/LIR-x64.h b/js/src/jit/x64/LIR-x64.h index 176f523d88..53e71941a7 100644 --- a/js/src/jit/x64/LIR-x64.h +++ b/js/src/jit/x64/LIR-x64.h @@ -164,18 +164,18 @@ class LUDivOrMod64 : public LBinaryMath<1> } }; -class LTruncateToInt64 : public LInstructionHelper<1, 1, 1> +class LWasmTruncateToInt64 : public LInstructionHelper<1, 1, 1> { public: - LIR_HEADER(TruncateToInt64); + LIR_HEADER(WasmTruncateToInt64); - LTruncateToInt64(const LAllocation& in, const LDefinition& temp) { + LWasmTruncateToInt64(const LAllocation& in, const LDefinition& temp) { setOperand(0, in); setTemp(0, temp); } - MTruncateToInt64* mir() const { - return mir_->toTruncateToInt64(); + MWasmTruncateToInt64* mir() const { + return mir_->toWasmTruncateToInt64(); } const LDefinition* temp() { diff --git a/js/src/jit/x64/LOpcodes-x64.h b/js/src/jit/x64/LOpcodes-x64.h index 3868017d9b..7640d97278 100644 --- a/js/src/jit/x64/LOpcodes-x64.h +++ b/js/src/jit/x64/LOpcodes-x64.h @@ -13,7 +13,7 @@ _(DivOrModConstantI) \ _(DivOrModI64) \ _(UDivOrMod64) \ - _(TruncateToInt64) \ + _(WasmTruncateToInt64) \ _(Int64ToFloatingPoint) \ _(SimdValueInt32x4) \ _(SimdValueFloat32x4) \ diff --git a/js/src/jit/x64/Lowering-x64.cpp b/js/src/jit/x64/Lowering-x64.cpp index c56ea95563..6006fc39e8 100644 --- a/js/src/jit/x64/Lowering-x64.cpp +++ b/js/src/jit/x64/Lowering-x64.cpp @@ -17,7 +17,7 @@ using namespace js::jit; LBoxAllocation LIRGeneratorX64::useBoxFixed(MDefinition* mir, Register reg1, Register, bool useAtStart) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); ensureDefined(mir); return LBoxAllocation(LUse(reg1, mir->virtualRegister(), useAtStart)); @@ -71,7 +71,7 @@ LIRGeneratorX64::visitUnbox(MUnbox* unbox) { MDefinition* box = unbox->getOperand(0); - if (box->type() == MIRType_ObjectOrNull) { + if (box->type() == MIRType::ObjectOrNull) { LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(box)); if (unbox->fallible()) assignSnapshot(lir, unbox->bailoutKind()); @@ -79,7 +79,7 @@ LIRGeneratorX64::visitUnbox(MUnbox* unbox) return; } - MOZ_ASSERT(box->type() == MIRType_Value); + MOZ_ASSERT(box->type() == MIRType::Value); LUnboxBase* lir; if (IsFloatingPointType(unbox->type())) { @@ -102,7 +102,7 @@ void LIRGeneratorX64::visitReturn(MReturn* ret) { MDefinition* opd = ret->getOperand(0); - MOZ_ASSERT(opd->type() == MIRType_Value); + MOZ_ASSERT(opd->type() == MIRType::Value); LReturn* ins = new(alloc()) LReturn; ins->setOperand(0, useFixed(opd, JSReturnReg)); @@ -142,7 +142,7 @@ LIRGeneratorX64::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop void LIRGeneratorX64::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->input()->type() == MIRType::Int32); LAsmJSUInt32ToDouble* lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input())); define(lir, ins); } @@ -150,7 +150,7 @@ LIRGeneratorX64::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins) void LIRGeneratorX64::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->input()->type() == MIRType::Int32); LAsmJSUInt32ToFloat32* lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input())); define(lir, ins); } @@ -159,7 +159,7 @@ void LIRGeneratorX64::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) { MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); // For simplicity, require a register if we're going to emit a bounds-check // branch, so that we don't have special cases for constants. @@ -174,7 +174,7 @@ void LIRGeneratorX64::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) { MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); // For simplicity, require a register if we're going to emit a bounds-check // branch, so that we don't have special cases for constants. @@ -209,7 +209,7 @@ void LIRGeneratorX64::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins) { MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); // The output may not be used but will be clobbered regardless, so // pin the output to eax. @@ -228,7 +228,7 @@ LIRGeneratorX64::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins) void LIRGeneratorX64::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins) { - MOZ_ASSERT(ins->base()->type() == MIRType_Int32); + MOZ_ASSERT(ins->base()->type() == MIRType::Int32); const LAllocation base = useRegister(ins->base()); const LAllocation value = useRegister(ins->value()); @@ -246,7 +246,7 @@ void LIRGeneratorX64::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins) { MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); // Case 1: the result of the operation is not used. // @@ -387,20 +387,20 @@ LIRGeneratorX64::lowerUMod64(MMod* mod) } void -LIRGeneratorX64::visitTruncateToInt64(MTruncateToInt64* ins) +LIRGeneratorX64::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Double || opd->type() == MIRType_Float32); + MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32); LDefinition maybeTemp = ins->isUnsigned() ? tempDouble() : LDefinition::BogusTemp(); - defineInt64(new(alloc()) LTruncateToInt64(useRegister(opd), maybeTemp), ins); + defineInt64(new(alloc()) LWasmTruncateToInt64(useRegister(opd), maybeTemp), ins); } void LIRGeneratorX64::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Int64); + MOZ_ASSERT(opd->type() == MIRType::Int64); MOZ_ASSERT(IsFloatingPointType(ins->type())); define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd)), ins); diff --git a/js/src/jit/x64/Lowering-x64.h b/js/src/jit/x64/Lowering-x64.h index 76164a0f0c..67eba7b4c0 100644 --- a/js/src/jit/x64/Lowering-x64.h +++ b/js/src/jit/x64/Lowering-x64.h @@ -59,7 +59,7 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins); void visitSubstr(MSubstr* ins); void visitRandom(MRandom* ins); - void visitTruncateToInt64(MTruncateToInt64* ins); + void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins); void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); }; diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 77ccce04ac..3c7e022018 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -230,17 +230,17 @@ void MacroAssemblerX64::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType) { - if (valueType == MIRType_Double) { + if (valueType == MIRType::Double) { storeDouble(value.reg().typedReg().fpu(), dest); return; } // For known integers and booleans, we can just store the unboxed value if // the slot has the same type. - if ((valueType == MIRType_Int32 || valueType == MIRType_Boolean) && slotType == valueType) { + if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) { if (value.constant()) { Value val = value.value(); - if (valueType == MIRType_Int32) + if (valueType == MIRType::Int32) store32(Imm32(val.toInt32()), dest); else store32(Imm32(val.toBoolean() ? 1 : 0), dest); diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 3e66f466e3..46175f9978 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -882,7 +882,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) { if (dest.isFloat()) loadInt32OrDouble(src, dest.fpu()); - else if (type == MIRType_Int32 || type == MIRType_Boolean) + else if (type == MIRType::Int32 || type == MIRType::Boolean) movl(Operand(src), dest.gpr()); else unboxNonDouble(Operand(src), dest.gpr()); diff --git a/js/src/jit/x86-shared/Assembler-x86-shared.h b/js/src/jit/x86-shared/Assembler-x86-shared.h index 968d58076a..83b410fa98 100644 --- a/js/src/jit/x86-shared/Assembler-x86-shared.h +++ b/js/src/jit/x86-shared/Assembler-x86-shared.h @@ -1657,6 +1657,19 @@ class AssemblerX86Shared : public AssemblerShared masm.sarl_CLr(dest.encoding()); } + void roll(const Imm32 imm, Register dest) { + masm.roll_ir(imm.value, dest.encoding()); + } + void roll_cl(Register dest) { + masm.roll_CLr(dest.encoding()); + } + void rorl(const Imm32 imm, Register dest) { + masm.rorl_ir(imm.value, dest.encoding()); + } + void rorl_cl(Register dest) { + masm.rorl_CLr(dest.encoding()); + } + void incl(const Operand& op) { switch (op.kind()) { case Operand::MEM_REG_DISP: diff --git a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h index f9400d2316..c0f0d51984 100644 --- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h @@ -1281,6 +1281,40 @@ public: m_formatter.oneByteOp(OP_GROUP2_EvCL, dst, GROUP2_OP_SHL); } + void roll_ir(int32_t imm, RegisterID dst) + { + MOZ_ASSERT(imm < 32); + spew("roll $%d, %s", imm, GPReg32Name(dst)); + if (imm == 1) + m_formatter.oneByteOp(OP_GROUP2_Ev1, dst, GROUP2_OP_ROL); + else { + m_formatter.oneByteOp(OP_GROUP2_EvIb, dst, GROUP2_OP_ROL); + m_formatter.immediate8u(imm); + } + } + void roll_CLr(RegisterID dst) + { + spew("roll %%cl, %s", GPReg32Name(dst)); + m_formatter.oneByteOp(OP_GROUP2_EvCL, dst, GROUP2_OP_ROL); + } + + void rorl_ir(int32_t imm, RegisterID dst) + { + MOZ_ASSERT(imm < 32); + spew("rorl $%d, %s", imm, GPReg32Name(dst)); + if (imm == 1) + m_formatter.oneByteOp(OP_GROUP2_Ev1, dst, GROUP2_OP_ROR); + else { + m_formatter.oneByteOp(OP_GROUP2_EvIb, dst, GROUP2_OP_ROR); + m_formatter.immediate8u(imm); + } + } + void rorl_CLr(RegisterID dst) + { + spew("rorl %%cl, %s", GPReg32Name(dst)); + m_formatter.oneByteOp(OP_GROUP2_EvCL, dst, GROUP2_OP_ROR); + } + void bsr_rr(RegisterID src, RegisterID dst) { spew("bsr %s, %s", GPReg32Name(src), GPReg32Name(dst)); @@ -1504,7 +1538,7 @@ public: } } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc cmpl_im_disp32(int32_t rhs, int32_t offset, RegisterID base) { spew("cmpl $0x%x, " MEM_o32b, rhs, ADDR_o32b(offset, base)); @@ -1521,7 +1555,7 @@ public: return r; } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc cmpl_im_disp32(int32_t rhs, const void* addr) { spew("cmpl $0x%x, %p", rhs, addr); @@ -2236,7 +2270,7 @@ public: // Flow control: - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc call() { m_formatter.oneByteOp(OP_CALL_rel32); @@ -2260,7 +2294,7 @@ public: // Comparison of EAX against a 32-bit immediate. The immediate is patched // in as if it were a jump target. The intention is to toggle the first // byte of the instruction between a CMP and a JMP to produce a pseudo-NOP. - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc cmp_eax() { m_formatter.oneByteOp(OP_CMP_EAXIv); @@ -2285,7 +2319,7 @@ public: m_formatter.immediate32(diff - 5); } } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc jmp() { m_formatter.oneByteOp(OP_JMP_rel32); @@ -2328,7 +2362,7 @@ public: } } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc jCC(Condition cond) { m_formatter.twoByteOp(jccRel32(cond)); @@ -4669,7 +4703,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off m_buffer.putInt64Unchecked(imm); } - MOZ_WARN_UNUSED_RESULT JmpSrc + MOZ_MUST_USE JmpSrc immediateRel32() { m_buffer.putIntUnchecked(0); diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index 3026d42ee7..64f0b9a0e7 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -281,17 +281,17 @@ CodeGeneratorX86Shared::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins) masm.storePtr(ToRegister(ins->arg()), dst); } else { switch (mir->input()->type()) { - case MIRType_Double: - case MIRType_Float32: + case MIRType::Double: + case MIRType::Float32: masm.storeDouble(ToFloatRegister(ins->arg()), dst); return; // StackPointer is SIMD-aligned and ABIArgGenerator guarantees // stack offsets are SIMD-aligned. - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: masm.storeAlignedInt32x4(ToFloatRegister(ins->arg()), dst); return; - case MIRType_Float32x4: + case MIRType::Float32x4: masm.storeAlignedFloat32x4(ToFloatRegister(ins->arg()), dst); return; default: break; @@ -311,7 +311,7 @@ CodeGeneratorX86Shared::visitAsmSelect(LAsmSelect* ins) masm.test32(cond, cond); - if (mirType == MIRType_Int32) { + if (mirType == MIRType::Int32) { Register out = ToRegister(ins->output()); MOZ_ASSERT(ToRegister(ins->trueExpr()) == out, "true expr input is reused for output"); masm.cmovz(falseExpr, out); @@ -324,12 +324,12 @@ CodeGeneratorX86Shared::visitAsmSelect(LAsmSelect* ins) Label done; masm.j(Assembler::NonZero, &done); - if (mirType == MIRType_Float32) { + if (mirType == MIRType::Float32) { if (falseExpr.kind() == Operand::FPREG) masm.moveFloat32(ToFloatRegister(ins->falseExpr()), out); else masm.loadFloat32(falseExpr, out); - } else if (mirType == MIRType_Double) { + } else if (mirType == MIRType::Double) { if (falseExpr.kind() == Operand::FPREG) masm.moveDouble(ToFloatRegister(ins->falseExpr()), out); else @@ -349,19 +349,21 @@ CodeGeneratorX86Shared::visitAsmReinterpret(LAsmReinterpret* lir) MAsmReinterpret* ins = lir->mir(); MIRType to = ins->type(); - DebugOnly from = ins->input()->type(); +#ifdef DEBUG + MIRType from = ins->input()->type(); +#endif switch (to) { - case MIRType_Int32: - MOZ_ASSERT(from == MIRType_Float32); + case MIRType::Int32: + MOZ_ASSERT(from == MIRType::Float32); masm.vmovd(ToFloatRegister(lir->input()), ToRegister(lir->output())); break; - case MIRType_Float32: - MOZ_ASSERT(from == MIRType_Int32); + case MIRType::Float32: + MOZ_ASSERT(from == MIRType::Int32); masm.vmovd(ToRegister(lir->input()), ToFloatRegister(lir->output())); break; - case MIRType_Double: - case MIRType_Int64: + case MIRType::Double: + case MIRType::Int64: MOZ_CRASH("not handled by this LIR opcode"); default: MOZ_CRASH("unexpected AsmReinterpret"); @@ -2583,7 +2585,7 @@ CodeGeneratorX86Shared::visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins) void CodeGeneratorX86Shared::visitSimdValueInt32x4(LSimdValueInt32x4* ins) { - MOZ_ASSERT(ins->mir()->type() == MIRType_Int32x4 || ins->mir()->type() == MIRType_Bool32x4); + MOZ_ASSERT(ins->mir()->type() == MIRType::Int32x4 || ins->mir()->type() == MIRType::Bool32x4); FloatRegister output = ToFloatRegister(ins->output()); if (AssemblerX86Shared::HasSSE41()) { @@ -2607,7 +2609,7 @@ CodeGeneratorX86Shared::visitSimdValueInt32x4(LSimdValueInt32x4* ins) void CodeGeneratorX86Shared::visitSimdValueFloat32x4(LSimdValueFloat32x4* ins) { - MOZ_ASSERT(ins->mir()->type() == MIRType_Float32x4); + MOZ_ASSERT(ins->mir()->type() == MIRType::Float32x4); FloatRegister r0 = ToFloatRegister(ins->getOperand(0)); FloatRegister r1 = ToFloatRegister(ins->getOperand(1)); @@ -2634,14 +2636,14 @@ CodeGeneratorX86Shared::visitSimdSplatX4(LSimdSplatX4* ins) JS_STATIC_ASSERT(sizeof(float) == sizeof(int32_t)); switch (mir->type()) { - case MIRType_Int32x4: - case MIRType_Bool32x4: { + case MIRType::Int32x4: + case MIRType::Bool32x4: { Register r = ToRegister(ins->getOperand(0)); masm.vmovd(r, output); masm.vpshufd(0, output, output); break; } - case MIRType_Float32x4: { + case MIRType::Float32x4: { FloatRegister r = ToFloatRegister(ins->getOperand(0)); FloatRegister rCopy = masm.reusedInputFloat32x4(r, output); masm.vshufps(0, rCopy, rCopy, output); @@ -2662,10 +2664,10 @@ CodeGeneratorX86Shared::visitSimdReinterpretCast(LSimdReinterpretCast* ins) return; switch (ins->mir()->type()) { - case MIRType_Int32x4: + case MIRType::Int32x4: masm.vmovdqa(input, output); break; - case MIRType_Float32x4: + case MIRType::Float32x4: masm.vmovaps(input, output); break; default: @@ -3532,19 +3534,19 @@ CodeGeneratorX86Shared::visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4* ins) MSimdBinaryBitwise::Operation op = ins->operation(); switch (op) { case MSimdBinaryBitwise::and_: - if (ins->type() == MIRType_Float32x4) + if (ins->type() == MIRType::Float32x4) masm.vandps(rhs, lhs, output); else masm.vpand(rhs, lhs, output); return; case MSimdBinaryBitwise::or_: - if (ins->type() == MIRType_Float32x4) + if (ins->type() == MIRType::Float32x4) masm.vorps(rhs, lhs, output); else masm.vpor(rhs, lhs, output); return; case MSimdBinaryBitwise::xor_: - if (ins->type() == MIRType_Float32x4) + if (ins->type() == MIRType::Float32x4) masm.vxorps(rhs, lhs, output); else masm.vpxor(rhs, lhs, output); @@ -4009,5 +4011,89 @@ CodeGeneratorX86Shared::setReturnDoubleRegs(LiveRegisterSet* regs) regs->add(ReturnSimd128Reg); } +void +CodeGeneratorX86Shared::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool) +{ + FloatRegister input = ool->input(); + MIRType fromType = ool->fromType(); + MIRType toType = ool->toType(); + + // Eagerly take care of NaNs. + Label inputIsNaN; + if (fromType == MIRType::Double) + masm.branchDouble(Assembler::DoubleUnordered, input, input, &inputIsNaN); + else if (fromType == MIRType::Float32) + masm.branchFloat(Assembler::DoubleUnordered, input, input, &inputIsNaN); + else + MOZ_CRASH("unexpected type in visitOutOfLineWasmTruncateCheck"); + + Label fail; + + // Handle special values (not needed for unsigned values). + if (!ool->isUnsigned()) { + if (toType == MIRType::Int32) { + // MWasmTruncateToInt32 + if (fromType == MIRType::Double) { + // We've used vcvttsd2si. The only valid double values that can + // truncate to INT32_MIN are in ]INT32_MIN - 1; INT32_MIN]. + masm.loadConstantDouble(double(INT32_MIN) - 1.0, ScratchDoubleReg); + masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, ScratchDoubleReg, &fail); + + masm.loadConstantDouble(double(INT32_MIN), ScratchDoubleReg); + masm.branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg, &fail); + } else { + MOZ_ASSERT(fromType == MIRType::Float32); + + // We've used vcvttss2si. Check that the input wasn't + // float(INT32_MIN), which is the only legimitate input that + // would truncate to INT32_MIN. + masm.loadConstantFloat32(float(INT32_MIN), ScratchFloat32Reg); + masm.branchFloat(Assembler::DoubleNotEqual, input, ScratchFloat32Reg, &fail); + } + } else { + // MWasmTruncateToInt64 + MOZ_ASSERT(toType == MIRType::Int64); + if (fromType == MIRType::Double) { + // We've used vcvtsd2sq. The only legit value whose i64 + // truncation is INT64_MIN is double(INT64_MIN): exponent is so + // high that the highest resolution around is much more than 1. + masm.loadConstantDouble(double(int64_t(INT64_MIN)), ScratchDoubleReg); + masm.branchDouble(Assembler::DoubleNotEqual, input, ScratchDoubleReg, &fail); + } else { + // We've used vcvtss2sq. Same comment applies. + MOZ_ASSERT(fromType == MIRType::Float32); + masm.loadConstantFloat32(float(int64_t(INT64_MIN)), ScratchFloat32Reg); + masm.branchFloat(Assembler::DoubleNotEqual, input, ScratchFloat32Reg, &fail); + } + } + masm.jump(ool->rejoin()); + } + + // Handle errors. + masm.bind(&fail); + masm.jump(wasm::JumpTarget::IntegerOverflowTrap); + + masm.bind(&inputIsNaN); + masm.jump(wasm::JumpTarget::InvalidConversionToIntegerTrap); +} + +void +CodeGeneratorX86Shared::emitWasmSignedTruncateToInt32(OutOfLineWasmTruncateCheck* ool, + Register output) +{ + FloatRegister input = ool->input(); + MIRType fromType = ool->fromType(); + + if (fromType == MIRType::Double) + masm.vcvttsd2si(input, output); + else if (fromType == MIRType::Float32) + masm.vcvttss2si(input, output); + else + MOZ_CRASH("unexpected type in emitWasmSignedTruncateToInt32"); + + masm.cmp32(output, Imm32(1)); + masm.j(Assembler::Overflow, ool->entry()); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h index 7f58813fbf..de3d104816 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h @@ -32,6 +32,8 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared void bailout(const T& t, LSnapshot* snapshot); protected: + void emitWasmSignedTruncateToInt32(OutOfLineWasmTruncateCheck* ool, Register output); + // Load a NaN or zero into a register for an out of bounds AsmJS or static // typed array load. class OutOfLineLoadTypedArrayOutOfBounds : public OutOfLineCodeBase @@ -92,23 +94,23 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared }; private: - MOZ_WARN_UNUSED_RESULT uint32_t + MOZ_MUST_USE uint32_t emitAsmJSBoundsCheckBranch(const MAsmJSHeapAccess* mir, const MInstruction* ins, Register ptr, Label* fail); public: // For SIMD and atomic loads and stores (which throw on out-of-bounds): - MOZ_WARN_UNUSED_RESULT uint32_t + MOZ_MUST_USE uint32_t maybeEmitThrowingAsmJSBoundsCheck(const MAsmJSHeapAccess* mir, const MInstruction* ins, const LAllocation* ptr); // For asm.js plain and atomic loads that possibly require a bounds check: - MOZ_WARN_UNUSED_RESULT uint32_t + MOZ_MUST_USE uint32_t maybeEmitAsmJSLoadBoundsCheck(const MAsmJSLoadHeap* mir, LAsmJSLoadHeap* ins, OutOfLineLoadTypedArrayOutOfBounds** ool); // For asm.js plain and atomic stores that possibly require a bounds check: - MOZ_WARN_UNUSED_RESULT uint32_t + MOZ_MUST_USE uint32_t maybeEmitAsmJSStoreBoundsCheck(const MAsmJSStoreHeap* mir, LAsmJSStoreHeap* ins, Label** rejoin); @@ -280,6 +282,8 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared void visitNegD(LNegD* lir); void visitNegF(LNegF* lir); + void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool); + // SIMD operators void visitSimdValueInt32x4(LSimdValueInt32x4* lir); void visitSimdValueFloat32x4(LSimdValueFloat32x4* lir); diff --git a/js/src/jit/x86-shared/Encoding-x86-shared.h b/js/src/jit/x86-shared/Encoding-x86-shared.h index 68d7434e1f..9fb1499e01 100644 --- a/js/src/jit/x86-shared/Encoding-x86-shared.h +++ b/js/src/jit/x86-shared/Encoding-x86-shared.h @@ -291,6 +291,8 @@ enum GroupOpcodeID { GROUP1A_OP_POP = 0, + GROUP2_OP_ROL = 0, + GROUP2_OP_ROR = 1, GROUP2_OP_SHL = 4, GROUP2_OP_SHR = 5, GROUP2_OP_SAR = 7, diff --git a/js/src/jit/x86-shared/Lowering-x86-shared.cpp b/js/src/jit/x86-shared/Lowering-x86-shared.cpp index b293c0a499..e1e9c40281 100644 --- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp +++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp @@ -36,7 +36,7 @@ LIRGeneratorX86Shared::newLTableSwitchV(MTableSwitch* tableswitch) void LIRGeneratorX86Shared::visitGuardShape(MGuardShape* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); LGuardShape* guard = new(alloc()) LGuardShape(useRegisterAtStart(ins->obj())); assignSnapshot(guard, ins->bailoutKind()); @@ -47,7 +47,7 @@ LIRGeneratorX86Shared::visitGuardShape(MGuardShape* ins) void LIRGeneratorX86Shared::visitGuardObjectGroup(MGuardObjectGroup* ins) { - MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->obj()->type() == MIRType::Object); LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegisterAtStart(ins->obj())); assignSnapshot(guard, ins->bailoutKind()); @@ -59,7 +59,7 @@ void LIRGeneratorX86Shared::visitPowHalf(MPowHalf* ins) { MDefinition* input = ins->input(); - MOZ_ASSERT(input->type() == MIRType_Double); + MOZ_ASSERT(input->type() == MIRType::Double); LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input)); define(lir, ins); } @@ -291,7 +291,7 @@ LIRGeneratorX86Shared::lowerModI(MMod* mod) void LIRGeneratorX86Shared::visitAsmSelect(MAsmSelect* ins) { - if (ins->type() == MIRType_Int64) { + if (ins->type() == MIRType::Int64) { auto* lir = new(alloc()) LAsmSelectI64(useInt64RegisterAtStart(ins->trueExpr()), useInt64(ins->falseExpr()), useRegister(ins->condExpr()) @@ -313,13 +313,13 @@ void LIRGeneratorX86Shared::visitAsmJSNeg(MAsmJSNeg* ins) { switch (ins->type()) { - case MIRType_Int32: + case MIRType::Int32: defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins, 0); break; - case MIRType_Float32: + case MIRType::Float32: defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins, 0); break; - case MIRType_Double: + case MIRType::Double: defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins, 0); break; default: @@ -394,9 +394,9 @@ LIRGeneratorX86Shared::lowerUrshD(MUrsh* mir) MDefinition* lhs = mir->lhs(); MDefinition* rhs = mir->rhs(); - MOZ_ASSERT(lhs->type() == MIRType_Int32); - MOZ_ASSERT(rhs->type() == MIRType_Int32); - MOZ_ASSERT(mir->type() == MIRType_Double); + MOZ_ASSERT(lhs->type() == MIRType::Int32); + MOZ_ASSERT(rhs->type() == MIRType::Int32); + MOZ_ASSERT(mir->type() == MIRType::Double); #ifdef JS_CODEGEN_X64 MOZ_ASSERT(ecx == rcx); @@ -413,7 +413,7 @@ void LIRGeneratorX86Shared::lowerTruncateDToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Double); + MOZ_ASSERT(opd->type() == MIRType::Double); LDefinition maybeTemp = Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempDouble(); define(new(alloc()) LTruncateDToInt32(useRegister(opd), maybeTemp), ins); @@ -423,7 +423,7 @@ void LIRGeneratorX86Shared::lowerTruncateFToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Float32); + MOZ_ASSERT(opd->type() == MIRType::Float32); LDefinition maybeTemp = Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempFloat32(); define(new(alloc()) LTruncateFToInt32(useRegister(opd), maybeTemp), ins); @@ -436,8 +436,8 @@ LIRGeneratorX86Shared::lowerCompareExchangeTypedArrayElement(MCompareExchangeTyp MOZ_ASSERT(ins->arrayType() != Scalar::Float32); MOZ_ASSERT(ins->arrayType() != Scalar::Float64); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -488,8 +488,8 @@ LIRGeneratorX86Shared::lowerAtomicExchangeTypedArrayElement(MAtomicExchangeTyped { MOZ_ASSERT(ins->arrayType() <= Scalar::Uint32); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -508,7 +508,7 @@ LIRGeneratorX86Shared::lowerAtomicExchangeTypedArrayElement(MAtomicExchangeTyped LDefinition tempDef = LDefinition::BogusTemp(); if (ins->arrayType() == Scalar::Uint32) { // This restriction is bug 1077305. - MOZ_ASSERT(ins->type() == MIRType_Double); + MOZ_ASSERT(ins->type() == MIRType::Double); tempDef = temp(); } @@ -529,8 +529,8 @@ LIRGeneratorX86Shared::lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElemen MOZ_ASSERT(ins->arrayType() != Scalar::Float32); MOZ_ASSERT(ins->arrayType() != Scalar::Float64); - MOZ_ASSERT(ins->elements()->type() == MIRType_Elements); - MOZ_ASSERT(ins->index()->type() == MIRType_Int32); + MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); + MOZ_ASSERT(ins->index()->type() == MIRType::Int32); const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); @@ -647,7 +647,7 @@ LIRGeneratorX86Shared::visitSimdBinaryArith(MSimdBinaryArith* ins) if (ins->isCommutative()) ReorderCommutative(&lhs, &rhs, ins); - if (ins->type() == MIRType_Int32x4) { + if (ins->type() == MIRType::Int32x4) { LSimdBinaryArithIx4* lir = new(alloc()) LSimdBinaryArithIx4(); bool needsTemp = ins->operation() == MSimdBinaryArith::Op_mul && !MacroAssembler::HasSSE41(); lir->setTemp(0, needsTemp ? temp(LDefinition::INT32X4) : LDefinition::BogusTemp()); @@ -655,7 +655,7 @@ LIRGeneratorX86Shared::visitSimdBinaryArith(MSimdBinaryArith* ins) return; } - MOZ_ASSERT(ins->type() == MIRType_Float32x4, "unknown simd type on binary arith operation"); + MOZ_ASSERT(ins->type() == MIRType::Float32x4, "unknown simd type on binary arith operation"); LSimdBinaryArithFx4* lir = new(alloc()) LSimdBinaryArithFx4(); @@ -671,7 +671,7 @@ void LIRGeneratorX86Shared::visitSimdSelect(MSimdSelect* ins) { MOZ_ASSERT(IsSimdType(ins->type())); - MOZ_ASSERT(ins->type() == MIRType_Int32x4 || ins->type() == MIRType_Float32x4, + MOZ_ASSERT(ins->type() == MIRType::Int32x4 || ins->type() == MIRType::Float32x4, "Unknown SIMD kind when doing bitwise operations"); LSimdSelect* lins = new(alloc()) LSimdSelect; @@ -694,11 +694,11 @@ LIRGeneratorX86Shared::visitSimdSplatX4(MSimdSplatX4* ins) LSimdSplatX4* lir = new(alloc()) LSimdSplatX4(x); switch (ins->type()) { - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: define(lir, ins); break; - case MIRType_Float32x4: + case MIRType::Float32x4: // (Non-AVX) codegen actually wants the input and the output to be in // the same register, but we can't currently use defineReuseInput // because they have different types (scalar vs vector), so a spill slot @@ -714,7 +714,7 @@ void LIRGeneratorX86Shared::visitSimdValueX4(MSimdValueX4* ins) { switch (ins->type()) { - case MIRType_Float32x4: { + case MIRType::Float32x4: { // Ideally, x would be used at start and reused for the output, however // register allocation currently doesn't permit us to tie together two // virtual registers with different types. @@ -726,8 +726,8 @@ LIRGeneratorX86Shared::visitSimdValueX4(MSimdValueX4* ins) define(new (alloc()) LSimdValueFloat32x4(x, y, z, w, t), ins); break; } - case MIRType_Bool32x4: - case MIRType_Int32x4: { + case MIRType::Bool32x4: + case MIRType::Int32x4: { // No defineReuseInput => useAtStart for everyone. LAllocation x = useRegisterAtStart(ins->getOperand(0)); LAllocation y = useRegisterAtStart(ins->getOperand(1)); diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 6d56c72096..4254fcf146 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -180,6 +180,40 @@ MacroAssembler::negateDouble(FloatRegister reg) vxorpd(scratch, reg, reg); // s ^ 0x80000000000000 } +// =============================================================== +// Rotation instructions +void +MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest) +{ + MOZ_ASSERT(input == dest, "defineReuseInput"); + if (count.value) + roll(count, input); +} + +void +MacroAssembler::rotateLeft(Register count, Register input, Register dest) +{ + MOZ_ASSERT(input == dest, "defineReuseInput"); + MOZ_ASSERT(count == ecx, "defineFixed(ecx)"); + roll_cl(input); +} + +void +MacroAssembler::rotateRight(Imm32 count, Register input, Register dest) +{ + MOZ_ASSERT(input == dest, "defineReuseInput"); + if (count.value) + rorl(count, input); +} + +void +MacroAssembler::rotateRight(Register count, Register input, Register dest) +{ + MOZ_ASSERT(input == dest, "defineReuseInput"); + MOZ_ASSERT(count == ecx, "defineFixed(ecx)"); + rorl_cl(input); +} + // =============================================================== // Branch instructions diff --git a/js/src/jit/x86/Assembler-x86.cpp b/js/src/jit/x86/Assembler-x86.cpp index 6c5a32436b..ab7cbd5068 100644 --- a/js/src/jit/x86/Assembler-x86.cpp +++ b/js/src/jit/x86/Assembler-x86.cpp @@ -20,19 +20,19 @@ ABIArg ABIArgGenerator::next(MIRType type) { switch (type) { - case MIRType_Int32: - case MIRType_Pointer: + case MIRType::Int32: + case MIRType::Pointer: current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint32_t); break; - case MIRType_Float32: // Float32 moves are actually double moves - case MIRType_Double: + case MIRType::Float32: // Float32 moves are actually double moves + case MIRType::Double: current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint64_t); break; - case MIRType_Int32x4: - case MIRType_Float32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Float32x4: + case MIRType::Bool32x4: // SIMD values aren't passed in or out of C++, so we can make up // whatever internal ABI we like. visitAsmJSPassArg assumes // SimdMemoryAlignment. diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index 5fbf034fca..8c85fee7bc 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -115,7 +115,7 @@ CodeGeneratorX86::visitBoxFloatingPoint(LBoxFloatingPoint* box) const ValueOperand out = ToOutValue(box); FloatRegister reg = ToFloatRegister(in); - if (box->type() == MIRType_Float32) { + if (box->type() == MIRType::Float32) { masm.convertFloat32ToDouble(reg, ScratchFloat32Reg); reg = ScratchFloat32Reg; } @@ -280,7 +280,7 @@ CodeGeneratorX86::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* { const MLoadTypedArrayElementStatic* mir = ins->mir(); Scalar::Type accessType = mir->accessType(); - MOZ_ASSERT_IF(accessType == Scalar::Float32, mir->type() == MIRType_Float32); + MOZ_ASSERT_IF(accessType == Scalar::Float32, mir->type() == MIRType::Float32); Register ptr = ToRegister(ins->ptr()); const LDefinition* out = ins->output(); @@ -319,14 +319,14 @@ CodeGeneratorX86::visitAsmJSCall(LAsmJSCall* ins) emitAsmJSCall(ins); if (IsFloatingPointType(mir->type()) && mir->callee().which() == MAsmJSCall::Callee::Builtin) { - if (mir->type() == MIRType_Float32) { + if (mir->type() == MIRType::Float32) { masm.reserveStack(sizeof(float)); Operand op(esp, 0); masm.fstp32(op); masm.loadFloat32(op, ReturnFloat32Reg); masm.freeStack(sizeof(float)); } else { - MOZ_ASSERT(mir->type() == MIRType_Double); + MOZ_ASSERT(mir->type() == MIRType::Double); masm.reserveStack(sizeof(double)); Operand op(esp, 0); masm.fstp(op); @@ -763,22 +763,22 @@ CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins) CodeOffset label; switch (type) { - case MIRType_Int32: + case MIRType::Int32: label = masm.movlWithPatch(PatchedAbsoluteAddress(), ToRegister(ins->output())); break; - case MIRType_Float32: + case MIRType::Float32: label = masm.vmovssWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); break; - case MIRType_Double: + case MIRType::Double: label = masm.vmovsdWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); break; // Aligned access: code is aligned on PageSize + there is padding // before the global data section. - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: label = masm.vmovdqaWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); break; - case MIRType_Float32x4: + case MIRType::Float32x4: label = masm.vmovapsWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); break; default: @@ -797,22 +797,22 @@ CodeGeneratorX86::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins) CodeOffset label; switch (type) { - case MIRType_Int32: + case MIRType::Int32: label = masm.movlWithPatch(ToRegister(ins->value()), PatchedAbsoluteAddress()); break; - case MIRType_Float32: + case MIRType::Float32: label = masm.vmovssWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); break; - case MIRType_Double: + case MIRType::Double: label = masm.vmovsdWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); break; // Aligned access: code is aligned on PageSize + there is padding // before the global data section. - case MIRType_Int32x4: - case MIRType_Bool32x4: + case MIRType::Int32x4: + case MIRType::Bool32x4: label = masm.vmovdqaWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); break; - case MIRType_Float32x4: + case MIRType::Float32x4: label = masm.vmovapsWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); break; default: @@ -1099,3 +1099,43 @@ CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool) masm.jump(ool->rejoin()); } + +void +CodeGeneratorX86::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir) +{ + auto input = ToFloatRegister(lir->input()); + auto output = ToRegister(lir->output()); + + MWasmTruncateToInt32* mir = lir->mir(); + MIRType fromType = mir->input()->type(); + + auto* ool = new (alloc()) OutOfLineWasmTruncateCheck(mir, input); + addOutOfLineCode(ool, mir); + + if (mir->isUnsigned()) { + Label done; + if (fromType == MIRType::Double) { + masm.vcvttsd2si(input, output); + masm.branch32(Assembler::Condition::NotSigned, output, Imm32(0), &done); + masm.loadConstantDouble(double(int32_t(0x80000000)), ScratchDoubleReg); + masm.addDouble(input, ScratchDoubleReg); + masm.vcvttsd2si(ScratchDoubleReg, output); + } else { + MOZ_ASSERT(fromType == MIRType::Float32); + masm.vcvttss2si(input, output); + masm.branch32(Assembler::Condition::NotSigned, output, Imm32(0), &done); + masm.loadConstantFloat32(float(int32_t(0x80000000)), ScratchFloat32Reg); + masm.addFloat32(input, ScratchFloat32Reg); + masm.vcvttss2si(ScratchFloat32Reg, output); + } + + masm.branch32(Assembler::Condition::Signed, output, Imm32(0), ool->entry()); + masm.or32(Imm32(0x80000000), output); + masm.bind(&done); + return; + } + + emitWasmSignedTruncateToInt32(ool, output); + + masm.bind(ool->rejoin()); +} diff --git a/js/src/jit/x86/CodeGenerator-x86.h b/js/src/jit/x86/CodeGenerator-x86.h index cbee97fd94..30cd31a5cb 100644 --- a/js/src/jit/x86/CodeGenerator-x86.h +++ b/js/src/jit/x86/CodeGenerator-x86.h @@ -68,6 +68,7 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins); void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); + void visitWasmTruncateToInt32(LWasmTruncateToInt32* ins); void visitOutOfLineTruncate(OutOfLineTruncate* ool); void visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool); diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp index fc939a90d9..e64dd2a70c 100644 --- a/js/src/jit/x86/Lowering-x86.cpp +++ b/js/src/jit/x86/Lowering-x86.cpp @@ -17,7 +17,7 @@ using namespace js::jit; LBoxAllocation LIRGeneratorX86::useBoxFixed(MDefinition* mir, Register reg1, Register reg2, bool useAtStart) { - MOZ_ASSERT(mir->type() == MIRType_Value); + MOZ_ASSERT(mir->type() == MIRType::Value); MOZ_ASSERT(reg1 != reg2); ensureDefined(mir); @@ -88,7 +88,7 @@ LIRGeneratorX86::visitUnbox(MUnbox* unbox) { MDefinition* inner = unbox->getOperand(0); - if (inner->type() == MIRType_ObjectOrNull) { + if (inner->type() == MIRType::ObjectOrNull) { LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner)); if (unbox->fallible()) assignSnapshot(lir, unbox->bailoutKind()); @@ -99,7 +99,7 @@ LIRGeneratorX86::visitUnbox(MUnbox* unbox) // An unbox on x86 reads in a type tag (either in memory or a register) and // a payload. Unlike most instructions consuming a box, we ask for the type // second, so that the result can re-use the first input. - MOZ_ASSERT(inner->type() == MIRType_Value); + MOZ_ASSERT(inner->type() == MIRType::Value); ensureDefined(inner); @@ -131,7 +131,7 @@ void LIRGeneratorX86::visitReturn(MReturn* ret) { MDefinition* opd = ret->getOperand(0); - MOZ_ASSERT(opd->type() == MIRType_Value); + MOZ_ASSERT(opd->type() == MIRType::Value); LReturn* ins = new(alloc()) LReturn; ins->setOperand(0, LUse(JSReturnReg_Type)); @@ -190,7 +190,7 @@ LIRGeneratorX86::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop void LIRGeneratorX86::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->input()->type() == MIRType::Int32); LAsmJSUInt32ToDouble* lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()), temp()); define(lir, ins); } @@ -198,7 +198,7 @@ LIRGeneratorX86::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins) void LIRGeneratorX86::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); + MOZ_ASSERT(ins->input()->type() == MIRType::Int32); LAsmJSUInt32ToFloat32* lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()), temp()); define(lir, ins); } @@ -207,7 +207,7 @@ void LIRGeneratorX86::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) { MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); // For simplicity, require a register if we're going to emit a bounds-check // branch, so that we don't have special cases for constants. @@ -222,7 +222,7 @@ void LIRGeneratorX86::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) { MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); // For simplicity, require a register if we're going to emit a bounds-check // branch, so that we don't have special cases for constants. @@ -281,7 +281,7 @@ LIRGeneratorX86::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins) MOZ_ASSERT(ins->accessType() < Scalar::Float32); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); bool byteArray = byteSize(ins->accessType()) == 1; @@ -311,7 +311,7 @@ LIRGeneratorX86::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins) void LIRGeneratorX86::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins) { - MOZ_ASSERT(ins->base()->type() == MIRType_Int32); + MOZ_ASSERT(ins->base()->type() == MIRType::Int32); const LAllocation base = useRegister(ins->base()); const LAllocation value = useRegister(ins->value()); @@ -332,7 +332,7 @@ LIRGeneratorX86::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins) MOZ_ASSERT(ins->accessType() < Scalar::Float32); MDefinition* base = ins->base(); - MOZ_ASSERT(base->type() == MIRType_Int32); + MOZ_ASSERT(base->type() == MIRType::Int32); bool byteArray = byteSize(ins->accessType()) == 1; @@ -460,7 +460,7 @@ LIRGeneratorX86::visitRandom(MRandom* ins) } void -LIRGeneratorX86::visitTruncateToInt64(MTruncateToInt64* ins) +LIRGeneratorX86::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) { MOZ_CRASH("NY"); } diff --git a/js/src/jit/x86/Lowering-x86.h b/js/src/jit/x86/Lowering-x86.h index c82a1c5c45..34c699d33f 100644 --- a/js/src/jit/x86/Lowering-x86.h +++ b/js/src/jit/x86/Lowering-x86.h @@ -63,7 +63,7 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins); void visitSubstr(MSubstr* ins); void visitRandom(MRandom* ins); - void visitTruncateToInt64(MTruncateToInt64* ins); + void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins); void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); void lowerPhi(MPhi* phi); diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 2b2819d1b5..975fea3bd3 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -278,7 +278,7 @@ void MacroAssemblerX86::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType) { - if (valueType == MIRType_Double) { + if (valueType == MIRType::Double) { storeDouble(value.reg().typedReg().fpu(), dest); return; } diff --git a/js/src/js.msg b/js/src/js.msg index 3bfa3d4087..3a73a765a3 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -350,9 +350,16 @@ MSG_DEF(JSMSG_WASM_BAD_IND_CALL, 0, JSEXN_ERR, "wasm indirect call sig MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be a typed array") MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument, if present, must be an object") MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_ERR, "reached unreachable trap") +MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW, 0, JSEXN_ERR, "integer overflow") +MSG_DEF(JSMSG_WASM_INVALID_CONVERSION, 0, JSEXN_ERR, "invalid conversion to integer") // Proxy MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value") +MSG_DEF(JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler returned a non-object, non-null value") +MSG_DEF(JSMSG_INCONSISTENT_GETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler didn't return the target object's prototype") +MSG_DEF(JSMSG_PROXY_SETPROTOTYPEOF_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy setPrototypeOf handler returned false") +MSG_DEF(JSMSG_PROXY_ISEXTENSIBLE_RETURNED_FALSE,0,JSEXN_TYPEERR,"proxy isExtensible handler must return the same extensibility as target") +MSG_DEF(JSMSG_INCONSISTENT_SETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy setPrototypeOf handler returned true, even though the target's prototype is immutable because the target is non-extensible") MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 0, JSEXN_TYPEERR, "can't change object's extensibility") MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor") MSG_DEF(JSMSG_CANT_DEFINE_NEW, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object") diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index 8493897ddc..66da9230ab 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -68,6 +68,7 @@ UNIFIED_SOURCES += [ 'testParseJSON.cpp', 'testPersistentRooted.cpp', 'testPreserveJitCode.cpp', + 'testPrivateGCThingValue.cpp', 'testProfileStrings.cpp', 'testPropCache.cpp', 'testRegExp.cpp', diff --git a/js/src/jsapi-tests/testGCUniqueId.cpp b/js/src/jsapi-tests/testGCUniqueId.cpp index 09f2fac8eb..9f90d8fba6 100644 --- a/js/src/jsapi-tests/testGCUniqueId.cpp +++ b/js/src/jsapi-tests/testGCUniqueId.cpp @@ -82,7 +82,7 @@ BEGIN_TEST(testGCUID) // Allocate a few arenas worth of objects to ensure we get some compaction. const static size_t N = 2049; - using ObjectVector = js::GCVector; + using ObjectVector = JS::GCVector; JS::Rooted vec(cx, ObjectVector(cx)); for (size_t i = 0; i < N; ++i) { obj = JS_NewPlainObject(cx); diff --git a/js/src/jsapi-tests/testJitDCEinGVN.cpp b/js/src/jsapi-tests/testJitDCEinGVN.cpp index b92f9e6382..8ca016e825 100644 --- a/js/src/jsapi-tests/testJitDCEinGVN.cpp +++ b/js/src/jsapi-tests/testJitDCEinGVN.cpp @@ -26,11 +26,11 @@ BEGIN_TEST(testJitDCEinGVN_ins) // return p MParameter* p = func.createParameter(); block->add(p); - MMul* mul0 = MMul::New(func.alloc, p, p, MIRType_Double); + MMul* mul0 = MMul::New(func.alloc, p, p, MIRType::Double); block->add(mul0); if (!mul0->typePolicy()->adjustInputs(func.alloc, mul0)) return false; - MMul* mul1 = MMul::New(func.alloc, mul0, mul0, MIRType_Double); + MMul* mul1 = MMul::New(func.alloc, mul0, mul0, MIRType::Double); block->add(mul1); if (!mul1->typePolicy()->adjustInputs(func.alloc, mul1)) return false; @@ -126,7 +126,7 @@ BEGIN_TEST(testJitDCEinGVN_phi) // return y joinBlock->addPhi(x); joinBlock->addPhi(y); - MMul* z = MMul::New(func.alloc, x, y, MIRType_Double); + MMul* z = MMul::New(func.alloc, x, y, MIRType::Double); joinBlock->add(z); MReturn* ret = MReturn::New(func.alloc, y); joinBlock->end(ret); diff --git a/js/src/jsapi-tests/testJitFoldsTo.cpp b/js/src/jsapi-tests/testJitFoldsTo.cpp index cf88919d63..c3a9f1452f 100644 --- a/js/src/jsapi-tests/testJitFoldsTo.cpp +++ b/js/src/jsapi-tests/testJitFoldsTo.cpp @@ -26,7 +26,7 @@ BEGIN_TEST(testJitFoldsTo_DivReciprocal) block->add(p); MConstant* c = MConstant::New(func.alloc, DoubleValue(4.0)); block->add(c); - MDiv* div = MDiv::New(func.alloc, p, c, MIRType_Double); + MDiv* div = MDiv::New(func.alloc, p, c, MIRType::Double); block->add(div); if (!div->typePolicy()->adjustInputs(func.alloc, div)) return false; @@ -57,7 +57,7 @@ BEGIN_TEST(testJitFoldsTo_NoDivReciprocal) block->add(p); MConstant* c = MConstant::New(func.alloc, DoubleValue(5.0)); block->add(c); - MDiv* div = MDiv::New(func.alloc, p, c, MIRType_Double); + MDiv* div = MDiv::New(func.alloc, p, c, MIRType::Double); block->add(div); if (!div->typePolicy()->adjustInputs(func.alloc, div)) return false; @@ -219,7 +219,7 @@ BEGIN_TEST(testJitFoldsTo_UnsignedDiv) block->add(c0); MConstant* c1 = MConstant::New(func.alloc, Int32Value(0xffffffff)); block->add(c1); - MDiv* div = MDiv::NewAsmJS(func.alloc, c0, c1, MIRType_Int32, /*unsignd=*/true); + MDiv* div = MDiv::NewAsmJS(func.alloc, c0, c1, MIRType::Int32, /*unsignd=*/true); block->add(div); MReturn* ret = MReturn::New(func.alloc, div); block->end(ret); @@ -244,7 +244,7 @@ BEGIN_TEST(testJitFoldsTo_UnsignedMod) block->add(c0); MConstant* c1 = MConstant::New(func.alloc, Int32Value(0xffffffff)); block->add(c1); - MMod* mod = MMod::NewAsmJS(func.alloc, c0, c1, MIRType_Int32, /*unsignd=*/true); + MMod* mod = MMod::NewAsmJS(func.alloc, c0, c1, MIRType::Int32, /*unsignd=*/true); block->add(mod); MReturn* ret = MReturn::New(func.alloc, mod); block->end(ret); diff --git a/js/src/jsapi-tests/testJitRangeAnalysis.cpp b/js/src/jsapi-tests/testJitRangeAnalysis.cpp index c7006f1ba5..1c45f8a64a 100644 --- a/js/src/jsapi-tests/testJitRangeAnalysis.cpp +++ b/js/src/jsapi-tests/testJitRangeAnalysis.cpp @@ -134,7 +134,7 @@ BEGIN_TEST(testJitRangeAnalysis_MathSignBeta) // { // return Math.sign(p + -0); // } - MAdd* thenAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType_Double); + MAdd* thenAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType::Double); thenBlock->add(thenAdd); MMathFunction* thenSign = MMathFunction::New(func.alloc, thenAdd, MMathFunction::Sign, &cache); thenBlock->add(thenSign); @@ -152,7 +152,7 @@ BEGIN_TEST(testJitRangeAnalysis_MathSignBeta) // { // return Math.sign(p + -0); // } - MAdd* elseThenAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType_Double); + MAdd* elseThenAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType::Double); elseThenBlock->add(elseThenAdd); MMathFunction* elseThenSign = MMathFunction::New(func.alloc, elseThenAdd, MMathFunction::Sign, &cache); elseThenBlock->add(elseThenSign); @@ -164,7 +164,7 @@ BEGIN_TEST(testJitRangeAnalysis_MathSignBeta) // return Math.sign(p + -0); // } // } - MAdd* elseElseAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType_Double); + MAdd* elseElseAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType::Double); elseElseBlock->add(elseElseAdd); MMathFunction* elseElseSign = MMathFunction::New(func.alloc, elseElseAdd, MMathFunction::Sign, &cache); elseElseBlock->add(elseElseSign); @@ -236,7 +236,7 @@ BEGIN_TEST(testJitRangeAnalysis_StrictCompareBeta) // } MConstant* cm0 = MConstant::New(func.alloc, DoubleValue(-0.0)); thenBlock->add(cm0); - MAdd* thenAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType_Double); + MAdd* thenAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType::Double); thenBlock->add(thenAdd); MReturn* thenRet = MReturn::New(func.alloc, thenAdd); thenBlock->end(thenRet); diff --git a/js/src/jsapi-tests/testPrivateGCThingValue.cpp b/js/src/jsapi-tests/testPrivateGCThingValue.cpp new file mode 100644 index 0000000000..ff12d50e49 --- /dev/null +++ b/js/src/jsapi-tests/testPrivateGCThingValue.cpp @@ -0,0 +1,57 @@ +/* -*- 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 "jsapi.h" + +#include "js/HeapAPI.h" +#include "jsapi-tests/tests.h" + +class TestTracer : public JS::CallbackTracer +{ + void onChild(const JS::GCCellPtr& thing) override { + if (thing.asCell() == expectedCell && thing.kind() == expectedKind) + found = true; + } + + public: + js::gc::Cell* expectedCell; + JS::TraceKind expectedKind; + bool found; + + explicit TestTracer(JSContext* cx) + : JS::CallbackTracer(JS_GetRuntime(cx)), + found(false) + { } +}; + +static const JSClass TestClass = { + "TestClass", + JSCLASS_HAS_RESERVED_SLOTS(1) +}; + +BEGIN_TEST(testPrivateGCThingValue) +{ + JS::RootedObject obj(cx, JS_NewObject(cx, &TestClass)); + CHECK(obj); + + // Make a JSScript to stick into a PrivateGCThingValue. + JS::RootedScript script(cx); + const char code[] = "'objet petit a'"; + JS::CompileOptions options(cx); + options.setFileAndLine(__FILE__, __LINE__); + CHECK(JS_CompileScript(cx, code, sizeof(code) - 1, options, &script)); + JS_SetReservedSlot(obj, 0, PrivateGCThingValue(script)); + + TestTracer trc(cx); + trc.expectedCell = script; + trc.expectedKind = JS::TraceKind::Script; + JS::TraceChildren(&trc, JS::GCCellPtr(obj, JS::TraceKind::Object)); + CHECK(trc.found); + + return true; +} +END_TEST(testPrivateGCThingValue) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 5b2f48dcba..623d978e3d 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2026,6 +2026,13 @@ JS_SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto) return SetPrototype(cx, obj, proto); } +JS_PUBLIC_API(bool) +JS_GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj, bool* isOrdinary, + MutableHandleObject result) +{ + return GetPrototypeIfOrdinary(cx, obj, isOrdinary, result); +} + JS_PUBLIC_API(bool) JS_IsExtensible(JSContext* cx, HandleObject obj, bool* extensible) { @@ -3671,7 +3678,7 @@ JS_GetFunctionObject(JSFunction* fun) JS_PUBLIC_API(JSString*) JS_GetFunctionId(JSFunction* fun) { - return fun->atom(); + return fun->name(); } JS_PUBLIC_API(JSString*) @@ -6595,3 +6602,10 @@ JS::GetObjectZone(JSObject* obj) { return obj->zone(); } + +JS_PUBLIC_API(JS::TraceKind) +JS::GCThingTraceKind(void* thing) +{ + MOZ_ASSERT(thing); + return static_cast(thing)->getTraceKind(); +} diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 26be774cdc..961121ddcd 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -219,9 +219,9 @@ typedef AutoVectorRooter AutoValueVector; typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; -using ValueVector = js::GCVector; -using IdVector = js::GCVector; -using ScriptVector = js::GCVector; +using ValueVector = JS::GCVector; +using IdVector = JS::GCVector; +using ScriptVector = JS::GCVector; template class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter @@ -2219,7 +2219,8 @@ class JS_PUBLIC_API(CompartmentCreationOptions) preserveJitCode_(false), cloneSingletons_(false), experimentalDateTimeFormatFormatToPartsEnabled_(false), - sharedMemoryAndAtomics_(false) + sharedMemoryAndAtomics_(false), + secureContext_(false) { zone_.spec = JS::FreshZone; } @@ -2302,6 +2303,16 @@ class JS_PUBLIC_API(CompartmentCreationOptions) bool getSharedMemoryAndAtomicsEnabled() const; CompartmentCreationOptions& setSharedMemoryAndAtomicsEnabled(bool flag); + // This flag doesn't affect JS engine behavior. It is used by Gecko to + // mark whether content windows and workers are "Secure Context"s. See + // https://w3c.github.io/webappsec-secure-contexts/ + // https://bugzilla.mozilla.org/show_bug.cgi?id=1162772#c34 + bool secureContext() const { return secureContext_; } + CompartmentCreationOptions& setSecureContext(bool flag) { + secureContext_ = flag; + return *this; + } + private: JSAddonId* addonId_; JSTraceOp traceGlobal_; @@ -2315,6 +2326,7 @@ class JS_PUBLIC_API(CompartmentCreationOptions) bool cloneSingletons_; bool experimentalDateTimeFormatFormatToPartsEnabled_; bool sharedMemoryAndAtomics_; + bool secureContext_; }; /** @@ -2877,6 +2889,17 @@ FromPropertyDescriptor(JSContext* cx, extern JS_PUBLIC_API(bool) JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject result); +/** + * If |obj| (underneath any functionally-transparent wrapper proxies) has as + * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined + * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype + * in |result|. Otherwise set |*isOrdinary = false|. In case of error, both + * outparams have unspecified value. + */ +extern JS_PUBLIC_API(bool) +JS_GetPrototypeIfOrdinary(JSContext* cx, JS::HandleObject obj, bool* isOrdinary, + JS::MutableHandleObject result); + /** * Change the prototype of obj. * diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 0d5843aaab..b7124d016b 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1721,9 +1721,9 @@ MatchNumericComparator(JSContext* cx, const Value& v) template static inline bool -MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector* vec) +MergeSortByKey(K keys, size_t len, K scratch, C comparator, MutableHandle> vec) { - MOZ_ASSERT(vec->length() >= len); + MOZ_ASSERT(vec.length() >= len); /* Sort keys. */ if (!MergeSort(keys, len, scratch, comparator)) @@ -1747,18 +1747,18 @@ MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector* vec continue; // fixed point MOZ_ASSERT(j > i, "Everything less than |i| should be in the right place!"); - Value tv = (*vec)[j]; + Value tv = vec[j]; do { size_t k = keys[j].elementIndex; keys[j].elementIndex = j; - (*vec)[j].set((*vec)[k]); + vec[j].set(vec[k]); j = k; } while (j != i); // We could assert the loop invariant that |i == keys[i].elementIndex| // here if we synced |keys[i].elementIndex|. But doing so would render // the assertion vacuous, so don't bother, even in debug builds. - (*vec)[i].set(tv); + vec[i].set(tv); } return true; @@ -1771,9 +1771,9 @@ MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector* vec * to strings at once, then sorts the elements by these cached strings. */ static bool -SortLexicographically(JSContext* cx, AutoValueVector* vec, size_t len) +SortLexicographically(JSContext* cx, MutableHandle> vec, size_t len) { - MOZ_ASSERT(vec->length() >= len); + MOZ_ASSERT(vec.length() >= len); StringBuffer sb(cx); Vector strElements(cx); @@ -1788,7 +1788,7 @@ SortLexicographically(JSContext* cx, AutoValueVector* vec, size_t len) if (!CheckForInterrupt(cx)) return false; - if (!ValueToStringBuffer(cx, (*vec)[i], sb)) + if (!ValueToStringBuffer(cx, vec[i], sb)) return false; strElements[i] = { cursor, sb.length(), i }; @@ -1807,9 +1807,10 @@ SortLexicographically(JSContext* cx, AutoValueVector* vec, size_t len) * numerics at once, then sorts the elements by these cached numerics. */ static bool -SortNumerically(JSContext* cx, AutoValueVector* vec, size_t len, ComparatorMatchResult comp) +SortNumerically(JSContext* cx, MutableHandle> vec, size_t len, + ComparatorMatchResult comp) { - MOZ_ASSERT(vec->length() >= len); + MOZ_ASSERT(vec.length() >= len); Vector numElements(cx); @@ -1823,7 +1824,7 @@ SortNumerically(JSContext* cx, AutoValueVector* vec, size_t len, ComparatorMatch return false; double dv; - if (!ToNumber(cx, (*vec)[i], &dv)) + if (!ToNumber(cx, vec[i], &dv)) return false; numElements[i] = { dv, i }; @@ -1912,7 +1913,7 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp) */ size_t n, undefs; { - AutoValueVector vec(cx); + Rooted> vec(cx, GCVector(cx)); if (!vec.reserve(2 * size_t(len))) return false; @@ -3171,15 +3172,20 @@ const JSPropertySpec array_static_props[] = { JS_PS_END }; -/* ES5 15.4.2 */ -bool -js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) +static inline bool +ArrayConstructorImpl(JSContext* cx, CallArgs& args, bool isConstructor) { - CallArgs args = CallArgsFromVp(argc, vp); - RootedObject proto(cx); - if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) - return false; + if (isConstructor) { + if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) + return false; + } else { + // We're emulating |new Array(n)| with |std_Array(n)| in self-hosted JS, + // and the proto should be %ArrayPrototype% regardless of the callee. + proto = GlobalObject::getOrCreateArrayPrototype(cx, cx->global()); + if (!proto) + return false; + } if (args.length() != 1 || !args[0].isNumber()) return ArrayFromCallArgs(cx, args, proto); @@ -3209,6 +3215,24 @@ js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) return true; } +/* ES5 15.4.2 */ +bool +js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + return ArrayConstructorImpl(cx, args, /* isConstructor = */ true); +} + +bool +js::array_construct(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(!args.isConstructing()); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isNumber()); + return ArrayConstructorImpl(cx, args, /* isConstructor = */ false); +} + JSObject* js::ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group, int32_t lengthInt) { diff --git a/js/src/jsarray.h b/js/src/jsarray.h index a00c88e546..b2d08354d9 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -212,6 +212,10 @@ ArrayInfo(JSContext* cx, unsigned argc, Value* vp); extern bool ArrayConstructor(JSContext* cx, unsigned argc, Value* vp); +// Like Array constructor, but doesn't perform GetPrototypeFromConstructor. +extern bool +array_construct(JSContext* cx, unsigned argc, Value* vp); + extern bool IsWrappedArrayConstructor(JSContext* cx, const Value& v, bool* result); diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 5da3a24508..249ace291b 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -107,7 +107,7 @@ struct AtomHasher static void rekey(AtomStateEntry& k, const AtomStateEntry& newKey) { k = newKey; } }; -using AtomSet = js::GCHashSet; +using AtomSet = JS::GCHashSet; // This class is a wrapper for AtomSet that is used to ensure the AtomSet is // not modified. It should only expose read-only methods from AtomSet. diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 514807b497..5f2c43f4a8 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -879,12 +879,11 @@ js::ReportMissingArg(JSContext* cx, HandleValue v, unsigned arg) { char argbuf[11]; UniqueChars bytes; - RootedAtom atom(cx); JS_snprintf(argbuf, sizeof argbuf, "%u", arg); if (IsFunctionObject(v)) { - atom = v.toObject().as().atom(); - bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, atom); + RootedAtom name(cx, v.toObject().as().name()); + bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, name); if (!bytes) return; } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index a4b6f45aec..5ea7626b57 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -434,7 +434,7 @@ struct JSContext : public js::ExclusiveContext, return throwing; } - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool getPendingException(JS::MutableHandleValue rval); bool isThrowingOutOfMemory(); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 04bbe7f2ba..ab163983cf 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -503,6 +503,16 @@ JSCompartment::wrap(JSContext* cx, MutableHandle desc) return wrap(cx, desc.value()); } +bool +JSCompartment::wrap(JSContext* cx, MutableHandle> vec) +{ + for (size_t i = 0; i < vec.length(); ++i) { + if (!wrap(cx, vec[i])) + return false; + } + return true; +} + ClonedBlockObject* JSCompartment::getOrCreateNonSyntacticLexicalScope(JSContext* cx, HandleObject enclosingStatic, diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 69a314704f..f2183a3e7c 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -521,27 +521,19 @@ struct JSCompartment JSCompartment(JS::Zone* zone, const JS::CompartmentOptions& options); ~JSCompartment(); - MOZ_WARN_UNUSED_RESULT bool init(JSContext* maybecx); + MOZ_MUST_USE bool init(JSContext* maybecx); - MOZ_WARN_UNUSED_RESULT inline bool wrap(JSContext* cx, JS::MutableHandleValue vp, + MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp, JS::HandleObject existing = nullptr); - MOZ_WARN_UNUSED_RESULT bool wrap(JSContext* cx, js::MutableHandleString strp); - MOZ_WARN_UNUSED_RESULT bool wrap(JSContext* cx, JS::MutableHandleObject obj, + MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp); + MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj, JS::HandleObject existingArg = nullptr); - MOZ_WARN_UNUSED_RESULT bool wrap(JSContext* cx, JS::MutableHandle desc); + MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle desc); + MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle> vec); - template MOZ_WARN_UNUSED_RESULT bool wrap(JSContext* cx, - JS::AutoVectorRooter& vec) { - for (size_t i = 0; i < vec.length(); ++i) { - if (!wrap(cx, vec[i])) - return false; - } - return true; - }; - - MOZ_WARN_UNUSED_RESULT bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped, - const js::Value& wrapper); + MOZ_MUST_USE bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped, + const js::Value& wrapper); js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) const { return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(wrapped)); diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 6b474a4089..a8b8af2677 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -1030,49 +1030,49 @@ JS::CreateError(JSContext* cx, JSExnType type, HandleObject stack, HandleString const char* js::ValueToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& bytes) { - if (val.isUndefined()) { + if (val.isUndefined()) return "undefined"; - } - if (val.isNull()) { + + if (val.isNull()) return "null"; - } + + AutoClearPendingException acpe(cx); RootedString str(cx, JS_ValueToSource(cx, val)); - if (!str) { - JS_ClearPendingException(cx); + if (!str) return "<>"; - } StringBuffer sb(cx); if (val.isObject()) { RootedObject valObj(cx, val.toObjectOrNull()); ESClassValue cls; - if (!GetBuiltinClass(cx, valObj, &cls)) { - JS_ClearPendingException(cx); + if (!GetBuiltinClass(cx, valObj, &cls)) return "<>"; - } - if (cls == ESClass_Array) { - sb.append("the array "); - } else if (cls == ESClass_ArrayBuffer) { - sb.append("the array buffer "); - } else if (JS_IsArrayBufferViewObject(valObj)) { - sb.append("the typed array "); - } else { - sb.append("the object "); - } + const char* s; + if (cls == ESClass_Array) + s = "the array "; + else if (cls == ESClass_ArrayBuffer) + s = "the array buffer "; + else if (JS_IsArrayBufferViewObject(valObj)) + s = "the typed array "; + else + s = "the object "; + if (!sb.append(s, strlen(s))) + return "<>"; } else if (val.isNumber()) { - sb.append("the number "); + if (!sb.append("the number ")) + return "<>"; } else if (val.isString()) { - sb.append("the string "); + if (!sb.append("the string ")) + return "<>"; } else { MOZ_ASSERT(val.isBoolean() || val.isSymbol()); return bytes.encodeLatin1(cx, str); } - sb.append(str); - str = sb.finishString(); - if (!str) { - JS_ClearPendingException(cx); + if (!sb.append(str)) + return "<>"; + str = sb.finishString(); + if (!str) return "<>"; - } return bytes.encodeLatin1(cx, str); } diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 6e1aae13b7..493161e37a 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -143,6 +143,12 @@ JS_NewObjectWithoutMetadata(JSContext* cx, const JSClass* clasp, JS::HandlecreationOptions().secureContext(); +} + JS_FRIEND_API(JSPrincipals*) JS_GetCompartmentPrincipals(JSCompartment* compartment) { @@ -581,13 +587,6 @@ js::ZoneGlobalsAreAllGray(JS::Zone* zone) return true; } -JS_FRIEND_API(JS::TraceKind) -js::GCThingTraceKind(void* thing) -{ - MOZ_ASSERT(thing); - return static_cast(thing)->getTraceKind(); -} - JS_FRIEND_API(void) js::VisitGrayWrapperTargets(Zone* zone, GCThingCallback callback, void* closure) { @@ -1270,32 +1269,6 @@ js::HasObjectMovedOp(JSObject* obj) { } #endif -JS_FRIEND_API(void) -JS_StoreObjectPostBarrierCallback(JSContext* cx, - void (*callback)(JSTracer* trc, JSObject* key, void* data), - JSObject* key, void* data) -{ - JSRuntime* rt = cx->runtime(); - if (IsInsideNursery(key)) - rt->gc.storeBuffer.putCallback(callback, key, data); -} - -extern JS_FRIEND_API(void) -JS_StoreStringPostBarrierCallback(JSContext* cx, - void (*callback)(JSTracer* trc, JSString* key, void* data), - JSString* key, void* data) -{ - JSRuntime* rt = cx->runtime(); - if (IsInsideNursery(key)) - rt->gc.storeBuffer.putCallback(callback, key, data); -} - -extern JS_FRIEND_API(void) -JS_ClearAllPostBarrierCallbacks(JSRuntime* rt) -{ - rt->gc.clearPostBarrierCallbacks(); -} - JS_FRIEND_API(bool) js::ForwardToNative(JSContext* cx, JSNative native, const CallArgs& args) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 818a5a1855..53a616ceb3 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -9,6 +9,7 @@ #include "mozilla/Atomics.h" #include "mozilla/Casting.h" +#include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" #include "mozilla/UniquePtr.h" @@ -107,6 +108,9 @@ JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr shape extern JS_FRIEND_API(void) JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr group); +extern JS_FRIEND_API(bool) +JS_GetIsSecureContext(JSCompartment* compartment); + extern JS_FRIEND_API(JSPrincipals*) JS_GetCompartmentPrincipals(JSCompartment* compartment); @@ -467,9 +471,6 @@ VisitGrayWrapperTargets(JS::Zone* zone, GCThingCallback callback, void* closure) extern JS_FRIEND_API(JSObject*) GetWeakmapKeyDelegate(JSObject* key); -JS_FRIEND_API(JS::TraceKind) -GCThingTraceKind(void* thing); - /** * Invoke cellCallback on every gray JS_OBJECT in the given zone. */ @@ -1257,27 +1258,33 @@ GetErrorMessage(void* userRef, const unsigned errorNumber); */ class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars) { + /* + * When copying string char, use this many bytes of inline storage. This is + * chosen to allow the inline string types to be copied without allocating. + * This is asserted in AutoStableStringChars::allocOwnChars. + */ + static const size_t InlineCapacity = 24; + /* Ensure the string is kept alive while we're using its chars. */ JS::RootedString s_; union { const char16_t* twoByteChars_; const JS::Latin1Char* latin1Chars_; }; + mozilla::Maybe> ownChars_; enum State { Uninitialized, Latin1, TwoByte }; State state_; - bool ownsChars_; public: explicit AutoStableStringChars(JSContext* cx) - : s_(cx), state_(Uninitialized), ownsChars_(false) + : s_(cx), state_(Uninitialized) {} - ~AutoStableStringChars(); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool init(JSContext* cx, JSString* s); /* Like init(), but Latin1 chars are inflated to TwoByte. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool initTwoByte(JSContext* cx, JSString* s); bool isLatin1() const { return state_ == Latin1; } @@ -1297,16 +1304,16 @@ class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars) mozilla::Range twoByteRange() const { MOZ_ASSERT(state_ == TwoByte); return mozilla::Range(twoByteChars_, - GetStringLength(s_)); + GetStringLength(s_)); } /* If we own the chars, transfer ownership to the caller. */ bool maybeGiveOwnershipToCaller() { MOZ_ASSERT(state_ != Uninitialized); - if (!ownsChars_) + if (!ownChars_.isSome() || !ownChars_->extractRawBuffer()) return false; state_ = Uninitialized; - ownsChars_ = false; + ownChars_.reset(); return true; } @@ -1315,8 +1322,9 @@ class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars) void operator=(const AutoStableStringChars& other) = delete; bool baseIsInline(JS::Handle linearString); - bool copyLatin1Chars(JSContext*, JS::Handle linearString); - bool copyTwoByteChars(JSContext*, JS::Handle linearString); + template T* allocOwnChars(JSContext* cx, size_t count); + bool copyLatin1Chars(JSContext* cx, JS::Handle linearString); + bool copyTwoByteChars(JSContext* cx, JS::Handle linearString); bool copyAndInflateLatin1Chars(JSContext*, JS::Handle linearString); }; @@ -2847,26 +2855,6 @@ ToWindowIfWindowProxy(JSObject* obj); } /* namespace js */ -extern JS_FRIEND_API(void) -JS_StoreObjectPostBarrierCallback(JSContext* cx, - void (*callback)(JSTracer* trc, JSObject* key, void* data), - JSObject* key, void* data); - -extern JS_FRIEND_API(void) -JS_StoreStringPostBarrierCallback(JSContext* cx, - void (*callback)(JSTracer* trc, JSString* key, void* data), - JSString* key, void* data); - -/** - * Forcibly clear postbarrier callbacks queued by the previous two methods. - * This should be used when the object owning the postbarriered pointers is - * being destroyed outside of a garbage collection. - * - * This currently works by performing a minor GC. - */ -extern JS_FRIEND_API(void) -JS_ClearAllPostBarrierCallbacks(JSRuntime *rt); - class NativeProfiler { public: diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 4be9177e8a..862f6af626 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -504,15 +504,15 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp) // It's impossible to have an empty named class expression. We // use empty as a sentinel when creating default class // constructors. - MOZ_ASSERT(fun->atom() != cx->names().empty); + MOZ_ASSERT(fun->name() != cx->names().empty); // Unnamed class expressions should not get a .name property // at all. - if (fun->atom() == nullptr) + if (fun->name() == nullptr) return true; } - v.setString(fun->atom() == nullptr ? cx->runtime()->emptyString : fun->atom()); + v.setString(fun->name() == nullptr ? cx->runtime()->emptyString : fun->name()); } if (!NativeDefineProperty(cx, fun, id, v, nullptr, nullptr, @@ -566,7 +566,7 @@ js::XDRInterpretedFunction(XDRState* xdr, HandleObject enclosingScope, Han return false; } - if (fun->atom() || fun->hasGuessedAtom()) + if (fun->name() || fun->hasGuessedAtom()) firstword |= HasAtom; if (fun->isStarGenerator()) @@ -1062,8 +1062,8 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen) if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function "))) return nullptr; } - if (fun->atom()) { - if (!out.append(fun->atom())) + if (fun->name()) { + if (!out.append(fun->name())) return nullptr; } diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 8c6526cd85..1257780fd0 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -313,11 +313,7 @@ class JSFunction : public js::NativeObject flags_ |= RESOLVED_NAME; } - JSAtom* atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); } - - js::PropertyName* name() const { - return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); - } + JSAtom* name() const { return hasGuessedAtom() ? nullptr : atom_.get(); } void initAtom(JSAtom* atom) { atom_.init(atom); } diff --git a/js/src/jsfuninlines.h b/js/src/jsfuninlines.h index b2ef7055c0..79caaaa6b2 100644 --- a/js/src/jsfuninlines.h +++ b/js/src/jsfuninlines.h @@ -16,9 +16,8 @@ namespace js { inline const char* GetFunctionNameBytes(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes) { - JSAtom* atom = fun->atom(); - if (atom) - return bytes->encodeLatin1(cx, atom); + if (JSAtom* name = fun->name()) + return bytes->encodeLatin1(cx, name); return js_anonymous_str; } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index b165a89a88..004d8ff021 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -373,76 +373,69 @@ const uint32_t Arena::ThingsPerArena[] = { struct js::gc::FinalizePhase { - size_t length; - const AllocKind* kinds; gcstats::Phase statsPhase; + AllocKinds kinds; }; -#define PHASE(x, p) { ArrayLength(x), x, p } - /* - * Finalization order for incrementally swept things. + * Finalization order for GC things swept incrementally on the main thrad. */ - -static const AllocKind IncrementalPhaseStrings[] = { - AllocKind::EXTERNAL_STRING -}; - -static const AllocKind IncrementalPhaseScripts[] = { - AllocKind::SCRIPT -}; - -static const AllocKind IncrementalPhaseJitCode[] = { - AllocKind::JITCODE -}; - static const FinalizePhase IncrementalFinalizePhases[] = { - PHASE(IncrementalPhaseStrings, gcstats::PHASE_SWEEP_STRING), - PHASE(IncrementalPhaseScripts, gcstats::PHASE_SWEEP_SCRIPT), - PHASE(IncrementalPhaseJitCode, gcstats::PHASE_SWEEP_JITCODE) + { + gcstats::PHASE_SWEEP_STRING, { + AllocKind::EXTERNAL_STRING + } + }, + { + gcstats::PHASE_SWEEP_SCRIPT, { + AllocKind::SCRIPT + } + }, + { + gcstats::PHASE_SWEEP_JITCODE, { + AllocKind::JITCODE + } + } }; /* - * Finalization order for things swept in the background. + * Finalization order for GC things swept on the background thread. */ - -static const AllocKind BackgroundPhaseObjects[] = { - AllocKind::FUNCTION, - AllocKind::FUNCTION_EXTENDED, - AllocKind::OBJECT0_BACKGROUND, - AllocKind::OBJECT2_BACKGROUND, - AllocKind::OBJECT4_BACKGROUND, - AllocKind::OBJECT8_BACKGROUND, - AllocKind::OBJECT12_BACKGROUND, - AllocKind::OBJECT16_BACKGROUND -}; - -static const AllocKind BackgroundPhaseScripts[] = { - AllocKind::LAZY_SCRIPT -}; - -static const AllocKind BackgroundPhaseStringsAndSymbols[] = { - AllocKind::FAT_INLINE_STRING, - AllocKind::STRING, - AllocKind::SYMBOL -}; - -static const AllocKind BackgroundPhaseShapes[] = { - AllocKind::SHAPE, - AllocKind::ACCESSOR_SHAPE, - AllocKind::BASE_SHAPE, - AllocKind::OBJECT_GROUP -}; - static const FinalizePhase BackgroundFinalizePhases[] = { - PHASE(BackgroundPhaseScripts, gcstats::PHASE_SWEEP_SCRIPT), - PHASE(BackgroundPhaseObjects, gcstats::PHASE_SWEEP_OBJECT), - PHASE(BackgroundPhaseStringsAndSymbols, gcstats::PHASE_SWEEP_STRING), - PHASE(BackgroundPhaseShapes, gcstats::PHASE_SWEEP_SHAPE) + { + gcstats::PHASE_SWEEP_SCRIPT, { + AllocKind::LAZY_SCRIPT + } + }, + { + gcstats::PHASE_SWEEP_OBJECT, { + AllocKind::FUNCTION, + AllocKind::FUNCTION_EXTENDED, + AllocKind::OBJECT0_BACKGROUND, + AllocKind::OBJECT2_BACKGROUND, + AllocKind::OBJECT4_BACKGROUND, + AllocKind::OBJECT8_BACKGROUND, + AllocKind::OBJECT12_BACKGROUND, + AllocKind::OBJECT16_BACKGROUND + } + }, + { + gcstats::PHASE_SWEEP_STRING, { + AllocKind::FAT_INLINE_STRING, + AllocKind::STRING, + AllocKind::SYMBOL + } + }, + { + gcstats::PHASE_SWEEP_SHAPE, { + AllocKind::SHAPE, + AllocKind::ACCESSOR_SHAPE, + AllocKind::BASE_SHAPE, + AllocKind::OBJECT_GROUP + } + } }; -#undef PHASE - template<> JSObject* ArenaCellIterImpl::get() const @@ -1145,7 +1138,7 @@ GCRuntime::GCRuntime(JSRuntime* rt) : zoneGroups(nullptr), currentZoneGroup(nullptr), sweepZone(nullptr), - sweepKindIndex(0), + sweepKind(AllocKind::FIRST), abortSweepAfterCurrentGroup(false), arenasAllocatedDuringSweep(nullptr), startedCompacting(false), @@ -2048,6 +2041,7 @@ static const AllocKind AllocKindsToRelocate[] = { AllocKind::LAZY_SCRIPT, AllocKind::SHAPE, AllocKind::ACCESSOR_SHAPE, + AllocKind::BASE_SHAPE, AllocKind::FAT_INLINE_STRING, AllocKind::STRING, AllocKind::EXTERNAL_STRING @@ -2421,6 +2415,14 @@ MovingTracer::onLazyScriptEdge(LazyScript** lazyp) *lazyp = Forwarded(lazy); } +void +MovingTracer::onBaseShapeEdge(BaseShape** basep) +{ + BaseShape* base = *basep; + if (IsForwarded(base)) + *basep = Forwarded(base); +} + void Zone::prepareForCompacting() { @@ -2557,65 +2559,25 @@ struct ArenaListSegment struct ArenasToUpdate { - enum UpdateKind { - NONE = 0, - FOREGROUND = 1, - BACKGROUND = 2, - ALL = FOREGROUND | BACKGROUND - }; - ArenasToUpdate(Zone* zone, UpdateKind kind); + ArenasToUpdate(Zone* zone, AllocKinds kinds); bool done() { return kind == AllocKind::LIMIT; } ArenaListSegment getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned maxLength); private: - UpdateKind kinds; // Selects which thing kinds to iterate - Zone* zone; // Zone to process - AllocKind kind; // Current alloc kind to process - Arena* arena; // Next arena to process + AllocKinds kinds; // Selects which thing kinds to update + Zone* zone; // Zone to process + AllocKind kind; // Current alloc kind to process + Arena* arena; // Next arena to process AllocKind nextAllocKind(AllocKind i) { return AllocKind(uint8_t(i) + 1); } - UpdateKind updateKind(AllocKind kind); bool shouldProcessKind(AllocKind kind); Arena* next(AutoLockHelperThreadState& lock); }; -ArenasToUpdate::UpdateKind -ArenasToUpdate::updateKind(AllocKind kind) -{ - MOZ_ASSERT(IsValidAllocKind(kind)); - - // GC things that do not contain pointers to cells we relocate don't need - // updating. Note that AllocKind::STRING is the only string kind which can - // be a rope and hence contain relocatable pointers. - if (kind == AllocKind::FAT_INLINE_STRING || - kind == AllocKind::EXTERNAL_STRING || - kind == AllocKind::SYMBOL) - { - return NONE; - } - - // We try to update as many GC things in parallel as we can, but there are - // kinds for which this might not be safe: - // - we assume JSObjects that are foreground finalized are not safe to - // update in parallel - // - updating a shape touches child shapes in fixupShapeTreeAfterMovingGC() - if (!js::gc::IsBackgroundFinalized(kind) || IsShapeAllocKind(kind)) - return FOREGROUND; - - return BACKGROUND; -} - -bool -ArenasToUpdate::shouldProcessKind(AllocKind kind) -{ - return (updateKind(kind) & kinds) != 0; -} - -ArenasToUpdate::ArenasToUpdate(Zone* zone, UpdateKind kinds) +ArenasToUpdate::ArenasToUpdate(Zone* zone, AllocKinds kinds) : kinds(kinds), zone(zone), kind(AllocKind::FIRST), arena(nullptr) { MOZ_ASSERT(zone->isGCCompacting()); - MOZ_ASSERT(!(kinds & ~ALL)); } Arena* @@ -2628,7 +2590,7 @@ ArenasToUpdate::next(AutoLockHelperThreadState& lock) // object and we just return when we find an arena. for (; kind < AllocKind::LIMIT; kind = nextAllocKind(kind)) { - if (shouldProcessKind(kind)) { + if (kinds.contains(kind)) { if (!arena) arena = zone->arenas.getFirstArena(kind); else @@ -2672,7 +2634,10 @@ struct UpdatePointersTask : public GCParallelTask UpdatePointersTask(JSRuntime* rt, ArenasToUpdate* source, AutoLockHelperThreadState& lock) : rt_(rt), source_(source) - {} + { + arenas_.begin = nullptr; + arenas_.end = nullptr; + } ~UpdatePointersTask() override { join(); } @@ -2725,18 +2690,46 @@ CellUpdateBackgroundTaskCount() return Min(Max(targetTaskCount, MinCellUpdateBackgroundTasks), MaxCellUpdateBackgroundTasks); } -void -GCRuntime::updateAllCellPointers(MovingTracer* trc, Zone* zone) +static bool +CanUpdateKindInBackground(AllocKind kind) { + // We try to update as many GC things in parallel as we can, but there are + // kinds for which this might not be safe: + // - we assume JSObjects that are foreground finalized are not safe to + // update in parallel + // - updating a shape touches child shapes in fixupShapeTreeAfterMovingGC() + if (!js::gc::IsBackgroundFinalized(kind) || IsShapeAllocKind(kind)) + return false; + + return true; +} + +static AllocKinds +ForegroundUpdateKinds(AllocKinds kinds) { - AutoDisableProxyCheck noProxyCheck(rt); // These checks assert when run in parallel. + AllocKinds result; + for (AllocKind kind : kinds) { + if (!CanUpdateKindInBackground(kind)) + result += kind; + } + return result; +} - size_t bgTaskCount = CellUpdateBackgroundTaskCount(); +void +GCRuntime::updateTypeDescrObjects(MovingTracer* trc, Zone* zone) +{ + zone->typeDescrObjects.sweep(); + for (auto r = zone->typeDescrObjects.all(); !r.empty(); r.popFront()) + UpdateCellPointers(trc, r.front().get()); +} - ArenasToUpdate - fgArenas(zone, bgTaskCount == 0 ? ArenasToUpdate::ALL : ArenasToUpdate::FOREGROUND); - ArenasToUpdate - bgArenas(zone, bgTaskCount == 0 ? ArenasToUpdate::NONE : ArenasToUpdate::BACKGROUND); +void +GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, size_t bgTaskCount) +{ + AllocKinds fgKinds = bgTaskCount == 0 ? kinds : ForegroundUpdateKinds(kinds); + AllocKinds bgKinds = kinds - fgKinds; + ArenasToUpdate fgArenas(zone, fgKinds); + ArenasToUpdate bgArenas(zone, bgKinds); Maybe fgTask; Maybe bgTasks[MaxCellUpdateBackgroundTasks]; @@ -2764,12 +2757,48 @@ GCRuntime::updateAllCellPointers(MovingTracer* trc, Zone* zone) } } +static const AllocKinds UpdatePhaseMisc { + AllocKind::SCRIPT, + AllocKind::LAZY_SCRIPT, + AllocKind::SHAPE, + AllocKind::BASE_SHAPE, + AllocKind::ACCESSOR_SHAPE, + AllocKind::OBJECT_GROUP, + AllocKind::STRING, + AllocKind::JITCODE +}; + +static const AllocKinds UpdatePhaseObjects { + AllocKind::FUNCTION, + AllocKind::FUNCTION_EXTENDED, + AllocKind::OBJECT0, + AllocKind::OBJECT0_BACKGROUND, + AllocKind::OBJECT2, + AllocKind::OBJECT2_BACKGROUND, + AllocKind::OBJECT4, + AllocKind::OBJECT4_BACKGROUND, + AllocKind::OBJECT8, + AllocKind::OBJECT8_BACKGROUND, + AllocKind::OBJECT12, + AllocKind::OBJECT12_BACKGROUND, + AllocKind::OBJECT16, + AllocKind::OBJECT16_BACKGROUND +}; + void -GCRuntime::updateTypeDescrObjects(MovingTracer* trc, Zone* zone) +GCRuntime::updateAllCellPointers(MovingTracer* trc, Zone* zone) { - zone->typeDescrObjects.sweep(); - for (auto r = zone->typeDescrObjects.all(); !r.empty(); r.popFront()) - UpdateCellPointers(trc, r.front().get()); + AutoDisableProxyCheck noProxyCheck(rt); // These checks assert when run in parallel. + + size_t bgTaskCount = CellUpdateBackgroundTaskCount(); + + updateCellPointers(trc, zone, UpdatePhaseMisc, bgTaskCount); + + // Update TypeDescrs before all other objects as typed objects access these + // objects when we trace them. + updateTypeDescrObjects(trc, zone); + + updateCellPointers(trc, zone, UpdatePhaseObjects, bgTaskCount); } /* @@ -2793,10 +2822,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone) JSCompartment::fixupCrossCompartmentWrappersAfterMovingGC(&trc); rt->spsProfiler.fixupStringsMapAfterMovingGC(); - // Update TypeDescrs before all other objects as typed objects access these - // objects when we trace them. - updateTypeDescrObjects(&trc, zone); - // Iterate through all cells that can contain relocatable pointers to update // them. Since updating each cell is independent we try to parallelize this // as much as possible. @@ -2955,8 +2980,8 @@ void ArenaLists::finalizeNow(FreeOp* fop, const FinalizePhase& phase) { gcstats::AutoPhase ap(fop->runtime()->gc.stats, phase.statsPhase); - for (unsigned i = 0; i < phase.length; ++i) - finalizeNow(fop, phase.kinds[i], RELEASE_ARENAS, nullptr); + for (auto kind : phase.kinds) + finalizeNow(fop, kind, RELEASE_ARENAS, nullptr); } void @@ -2996,8 +3021,8 @@ void ArenaLists::queueForForegroundSweep(FreeOp* fop, const FinalizePhase& phase) { gcstats::AutoPhase ap(fop->runtime()->gc.stats, phase.statsPhase); - for (unsigned i = 0; i < phase.length; ++i) - queueForForegroundSweep(fop, phase.kinds[i]); + for (auto kind : phase.kinds) + queueForForegroundSweep(fop, kind); } void @@ -3015,8 +3040,8 @@ void ArenaLists::queueForBackgroundSweep(FreeOp* fop, const FinalizePhase& phase) { gcstats::AutoPhase ap(fop->runtime()->gc.stats, phase.statsPhase); - for (unsigned i = 0; i < phase.length; ++i) - queueForBackgroundSweep(fop, phase.kinds[i]); + for (auto kind : phase.kinds) + queueForBackgroundSweep(fop, kind); } inline void @@ -3470,8 +3495,7 @@ GCRuntime::sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks, ThreadT FreeOp fop(rt, threadType); for (unsigned phase = 0 ; phase < ArrayLength(BackgroundFinalizePhases) ; ++phase) { for (Zone* zone = zones.front(); zone; zone = zone->nextZone()) { - for (unsigned index = 0 ; index < BackgroundFinalizePhases[phase].length ; ++index) { - AllocKind kind = BackgroundFinalizePhases[phase].kinds[index]; + for (auto kind : BackgroundFinalizePhases[phase].kinds) { Arena* arenas = zone->arenas.arenaListsToSweep[kind]; MOZ_RELEASE_ASSERT(uintptr_t(arenas) != uintptr_t(-1)); if (arenas) @@ -3481,7 +3505,22 @@ GCRuntime::sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks, ThreadT } AutoLockGC lock(rt); - ReleaseArenaList(rt, emptyArenas, lock); + + // Release swept areans, dropping and reaquiring the lock every so often to + // avoid blocking the main thread from allocating chunks. + static const size_t LockReleasePeriod = 32; + size_t releaseCount = 0; + Arena* next; + for (Arena* arena = emptyArenas; arena; arena = next) { + next = arena->next; + rt->gc.releaseArena(arena, lock); + releaseCount++; + if (releaseCount % LockReleasePeriod == 0) { + lock.unlock(); + lock.lock(); + } + } + while (!zones.isEmpty()) zones.removeFront(); } @@ -5363,7 +5402,7 @@ GCRuntime::beginSweepingZoneGroup() finalizePhase = 0; sweepZone = currentZoneGroup; - sweepKindIndex = 0; + sweepKind = AllocKind::FIRST; { gcstats::AutoPhase ap(stats, gcstats::PHASE_FINALIZE_END); @@ -5574,8 +5613,9 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget) for (; sweepZone; sweepZone = sweepZone->nextNodeInGroup()) { Zone* zone = sweepZone; - while (sweepKindIndex < IncrementalFinalizePhases[finalizePhase].length) { - AllocKind kind = IncrementalFinalizePhases[finalizePhase].kinds[sweepKindIndex]; + for (auto kind : SomeAllocKinds(sweepKind, AllocKind::LIMIT)) { + if (!IncrementalFinalizePhases[finalizePhase].kinds.contains(kind)) + continue; /* Set the number of things per arena for this AllocKind. */ size_t thingsPerArena = Arena::thingsPerArena(kind); @@ -5583,14 +5623,15 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget) if (!zone->arenas.foregroundFinalize(&fop, kind, sliceBudget, incrementalSweepList)) + { + sweepKind = kind; return NotFinished; + } /* Reset the slots of the sweep list that we used. */ incrementalSweepList.reset(thingsPerArena); - - ++sweepKindIndex; } - sweepKindIndex = 0; + sweepKind = AllocKind::FIRST; } sweepZone = currentZoneGroup; } @@ -6763,13 +6804,6 @@ GCRuntime::minorGC(JSContext* cx, JS::gcreason::Reason reason) } } -void -GCRuntime::clearPostBarrierCallbacks() -{ - if (storeBuffer.hasPostBarrierCallbacks()) - evictNursery(); -} - void GCRuntime::disableGenerationalGC() { @@ -7387,6 +7421,8 @@ JS::GCCellPtr::GCCellPtr(const Value& v) ptr = checkedCast(&v.toObject(), JS::TraceKind::Object); else if (v.isSymbol()) ptr = checkedCast(v.toSymbol(), JS::TraceKind::Symbol); + else if (v.isPrivateGCThing()) + ptr = checkedCast(v.toGCThing(), v.toGCThing()->getTraceKind()); else ptr = checkedCast(nullptr, JS::TraceKind::Null); } diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 8736b8abf2..49d84d3a51 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1105,6 +1105,7 @@ struct MightBeForwarded static const bool value = mozilla::IsBaseOf::value || mozilla::IsBaseOf::value || + mozilla::IsBaseOf::value || mozilla::IsBaseOf::value || mozilla::IsBaseOf::value || mozilla::IsBaseOf::value; @@ -1144,7 +1145,7 @@ Forwarded(T* t) struct ForwardedFunctor : public IdentityDefaultAdaptor { template inline Value operator()(T* t) { - return js::gc::RewrapTaggedPointer::wrap(Forwarded(t)); + return js::gc::RewrapTaggedPointer::wrap(Forwarded(t)); } }; diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index 4ed0fd7b25..e861eee910 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -193,8 +193,16 @@ class ZoneCellIterImpl public: ZoneCellIterImpl(JS::Zone* zone, AllocKind kind) { + JSRuntime* rt = zone->runtimeFromAnyThread(); MOZ_ASSERT(zone); - MOZ_ASSERT(zone->runtimeFromAnyThread()->gc.nursery.isEmpty()); + MOZ_ASSERT(rt->gc.nursery.isEmpty()); + + // We have a single-threaded runtime, so there's no need to protect + // against other threads iterating or allocating. However, we do have + // background finalization; we may have to wait for this to finish if + // it's currently active. + if (IsBackgroundFinalized(kind) && zone->arenas.needBackgroundFinalizeWait(kind)) + rt->gc.waitBackgroundSweepEnd(); arenaIter.init(zone, kind); if (!arenaIter.done()) @@ -248,13 +256,6 @@ class ZoneCellIter // that allows us to iterate. JSRuntime* rt = zone->runtimeFromMainThread(); if (!rt->isHeapBusy()) { - // We have a single-threaded runtime, so there's no need to protect - // against other threads iterating or allocating. However, we do - // have background finalization; we have to wait for this to finish - // if it's currently active. - if (IsBackgroundFinalized(kind) && zone->arenas.needBackgroundFinalizeWait(kind)) - rt->gc.waitBackgroundSweepEnd(); - // Evict the nursery before iterating so we can see all things. rt->gc.evictNursery(); diff --git a/js/src/jsnum.h b/js/src/jsnum.h index ee5d4b9fe7..a6e078c192 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -34,7 +34,7 @@ namespace js { class StringBuffer; -extern bool +extern MOZ_MUST_USE bool InitRuntimeNumberState(JSRuntime* rt); #if !EXPOSE_INTL_API @@ -83,7 +83,7 @@ Int32ToAtom(ExclusiveContext* cx, int32_t si); * Convert an integer or double (contained in the given value) to a string and * append to the given buffer. */ -extern bool JS_FASTCALL +extern MOZ_MUST_USE bool JS_FASTCALL NumberValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb); /* Same as js_NumberToString, different signature. */ @@ -151,7 +151,7 @@ ParseDecimalNumber(const mozilla::Range chars); * *dp == 0 and *endp == start upon return. */ template -extern bool +extern MOZ_MUST_USE bool GetPrefixInteger(ExclusiveContext* cx, const CharT* start, const CharT* end, int base, const CharT** endp, double* dp); @@ -160,14 +160,14 @@ GetPrefixInteger(ExclusiveContext* cx, const CharT* start, const CharT* end, int * and |endp| outparam. It should only be used when the characters are known to * only contain digits. */ -extern bool +extern MOZ_MUST_USE bool GetDecimalInteger(ExclusiveContext* cx, const char16_t* start, const char16_t* end, double* dp); -extern bool +extern MOZ_MUST_USE bool StringToNumber(ExclusiveContext* cx, JSString* str, double* result); /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */ -MOZ_ALWAYS_INLINE bool +MOZ_ALWAYS_INLINE MOZ_MUST_USE bool ToNumber(JSContext* cx, JS::MutableHandleValue vp) { if (vp.isNumber()) @@ -181,7 +181,7 @@ ToNumber(JSContext* cx, JS::MutableHandleValue vp) return true; } -bool +MOZ_MUST_USE bool num_parseInt(JSContext* cx, unsigned argc, Value* vp); } /* namespace js */ @@ -199,16 +199,16 @@ num_parseInt(JSContext* cx, unsigned argc, Value* vp); * Return false if out of memory. */ template -extern bool +extern MOZ_MUST_USE bool js_strtod(js::ExclusiveContext* cx, const CharT* begin, const CharT* end, const CharT** dEnd, double* d); namespace js { -extern bool +extern MOZ_MUST_USE bool num_toString(JSContext* cx, unsigned argc, Value* vp); -extern bool +extern MOZ_MUST_USE bool num_valueOf(JSContext* cx, unsigned argc, Value* vp); static MOZ_ALWAYS_INLINE bool @@ -248,7 +248,7 @@ IsDefinitelyIndex(const Value& v, uint32_t* indexp) } /* ES5 9.4 ToInteger. */ -static inline bool +static MOZ_MUST_USE inline bool ToInteger(JSContext* cx, HandleValue v, double* dp) { if (v.isInt32()) { @@ -273,7 +273,7 @@ ToInteger(JSContext* cx, HandleValue v, double* dp) * For JSContext and ExclusiveContext. */ template -bool ToLengthClamped(T* cx, HandleValue v, uint32_t* out, bool* overflow); +MOZ_MUST_USE bool ToLengthClamped(T* cx, HandleValue v, uint32_t* out, bool* overflow); /* Convert and range check an index value as for DataView, SIMD, and Atomics * operations, eg ES7 24.2.1.1, DataView's GetViewValue(): @@ -293,9 +293,9 @@ bool ToLengthClamped(T* cx, HandleValue v, uint32_t* out, bool* overflow); * * The returned index will always be in the range 0 <= *index <= 2^53. */ -bool ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index); +MOZ_MUST_USE bool ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index); -inline bool +MOZ_MUST_USE inline bool SafeAdd(int32_t one, int32_t two, int32_t* res) { #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_sadd_overflow) @@ -310,7 +310,7 @@ SafeAdd(int32_t one, int32_t two, int32_t* res) #endif } -inline bool +MOZ_MUST_USE inline bool SafeSub(int32_t one, int32_t two, int32_t* res) { #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_ssub_overflow) @@ -322,7 +322,7 @@ SafeSub(int32_t one, int32_t two, int32_t* res) #endif } -inline bool +MOZ_MUST_USE inline bool SafeMul(int32_t one, int32_t two, int32_t* res) { #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_smul_overflow) @@ -334,12 +334,12 @@ SafeMul(int32_t one, int32_t two, int32_t* res) #endif } -extern bool +extern MOZ_MUST_USE bool ToNumberSlow(ExclusiveContext* cx, Value v, double* dp); // Variant of ToNumber which takes an ExclusiveContext instead of a JSContext. // ToNumber is part of the API and can't use ExclusiveContext directly. -MOZ_ALWAYS_INLINE bool +MOZ_ALWAYS_INLINE MOZ_MUST_USE bool ToNumber(ExclusiveContext* cx, const Value& v, double* out) { if (v.isNumber()) { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 7097bd2813..0c2d7940ec 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1176,7 +1176,7 @@ js::CloneObject(JSContext* cx, HandleObject obj, Handle proto) } static bool -GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, AutoValueVector& values) +GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle> values) { MOZ_ASSERT(!obj->isSingleton()); MOZ_ASSERT(obj->is() || obj->is()); @@ -1286,8 +1286,8 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin MOZ_ASSERT(newKind != SingletonObject); if (obj->is() || obj->is()) { - AutoValueVector values(cx); - if (!GetScriptArrayObjectElements(cx, obj, values)) + Rooted> values(cx, GCVector(cx)); + if (!GetScriptArrayObjectElements(cx, obj, &values)) return nullptr; // Deep clone any elements. @@ -1415,8 +1415,8 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj) RootedId tmpId(cx); if (isArray) { - AutoValueVector values(cx); - if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, values)) + Rooted> values(cx, GCVector(cx)); + if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, &values)) return false; uint32_t initialized; @@ -2494,6 +2494,20 @@ JSObject::reportNotExtensible(JSContext* cx, unsigned report) nullptr, nullptr); } +bool +js::GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj, bool* isOrdinary, + MutableHandleObject protop) +{ + if (obj->getTaggedProto().isLazy()) { + MOZ_ASSERT(obj->is()); + return js::Proxy::getPrototypeIfOrdinary(cx, obj, isOrdinary, protop); + } + + *isOrdinary = true; + protop.set(obj->getTaggedProto().toObjectOrNull()); + return true; +} + // Our immutable-prototype behavior is non-standard, and it's unclear whether // it's shippable. (Or at least it's unclear whether it's shippable with any // provided-by-default uses exposed to script.) If this bool is true, @@ -2587,14 +2601,17 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object * possibly-Window object we're setting the proto on. */ RootedObject objMaybeWindowProxy(cx, ToWindowProxyIfWindow(obj)); - RootedObject obj2(cx); - for (obj2 = proto; obj2; ) { + RootedObject obj2(cx, proto); + while (obj2) { MOZ_ASSERT(!IsWindow(obj2)); if (obj2 == objMaybeWindowProxy) return result.fail(JSMSG_CANT_SET_PROTO_CYCLE); - if (!GetPrototype(cx, obj2, &obj2)) + bool isOrdinary; + if (!GetPrototypeIfOrdinary(cx, obj2, &isOrdinary, &obj2)) return false; + if (!isOrdinary) + break; } // Convert unboxed objects to their native representations before changing @@ -3918,3 +3935,23 @@ js::SpeciesConstructor(JSContext* cx, HandleObject obj, HandleValue defaultCtor, pctor.set(args.rval()); return true; } + +bool +js::Unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp) +{ + if (MOZ_UNLIKELY(obj->is())) + return Proxy::boxedValue_unbox(cx, obj, vp); + + if (obj->is()) + vp.setBoolean(obj->as().unbox()); + else if (obj->is()) + vp.setNumber(obj->as().unbox()); + else if (obj->is()) + vp.setString(obj->as().unbox()); + else if (obj->is()) + vp.set(obj->as().UTCTime()); + else + vp.setUndefined(); + + return true; +} diff --git a/js/src/jsobj.h b/js/src/jsobj.h index cc56342257..845681ad9d 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -34,7 +34,7 @@ struct ClassInfo; namespace js { -using PropertyDescriptorVector = GCVector; +using PropertyDescriptorVector = JS::GCVector; class GCMarker; class Nursery; @@ -949,6 +949,17 @@ DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& r /*** SpiderMonkey nonstandard internal methods ***************************************************/ +/** + * If |obj| (underneath any functionally-transparent wrapper proxies) has as + * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined + * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype + * in |result|. Otherwise set |*isOrdinary = false|. In case of error, both + * outparams have unspecified value. + */ +extern bool +GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj, bool* isOrdinary, + MutableHandleObject protop); + /* * Attempt to make |obj|'s [[Prototype]] immutable, such that subsequently * trying to change it will not work. If an internal error occurred, diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 05379af10f..c607349ee7 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -285,7 +285,7 @@ ClassCanHaveFixedData(const Class* clasp) // returned in place of the pointer passed. If a GC occurs, the returned pointer // may be the passed pointer, relocated by GC. If no GC could occur, it's just // passed through. We root nothing unless necessary. -static MOZ_ALWAYS_INLINE MOZ_WARN_UNUSED_RESULT JSObject* +static MOZ_ALWAYS_INLINE MOZ_MUST_USE JSObject* SetNewObjectMetadata(ExclusiveContext* cxArg, JSObject* obj) { MOZ_ASSERT(!cxArg->compartment()->hasObjectPendingMetadata()); @@ -824,26 +824,6 @@ GetClassOfValue(JSContext* cx, HandleValue v, ESClassValue* classValue) return GetBuiltinClass(cx, obj, classValue); } -inline bool -Unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp) -{ - if (MOZ_UNLIKELY(obj->is())) - return Proxy::boxedValue_unbox(cx, obj, vp); - - if (obj->is()) - vp.setBoolean(obj->as().unbox()); - else if (obj->is()) - vp.setNumber(obj->as().unbox()); - else if (obj->is()) - vp.setString(obj->as().unbox()); - else if (obj->is()) - vp.set(obj->as().UTCTime()); - else - vp.setUndefined(); - - return true; -} - extern NativeObject* InitClass(JSContext* cx, HandleObject obj, HandleObject parent_proto, const Class* clasp, JSNative constructor, unsigned nargs, diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index bb29a7aec1..3ed1bff245 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1695,15 +1695,15 @@ js::GetPCCountScriptCount(JSContext* cx) enum MaybeComma {NO_COMMA, COMMA}; -static void +static MOZ_MUST_USE bool AppendJSONProperty(StringBuffer& buf, const char* name, MaybeComma comma = COMMA) { - if (comma) - buf.append(','); + if (comma && !buf.append(',')) + return false; - buf.append('\"'); - buf.append(name, strlen(name)); - buf.append("\":", 2); + return buf.append('\"') && + buf.append(name, strlen(name)) && + buf.append("\":", 2); } JS_FRIEND_API(JSString*) @@ -1726,24 +1726,32 @@ js::GetPCCountScriptSummary(JSContext* cx, size_t index) */ StringBuffer buf(cx); - buf.append('{'); + if (!buf.append('{')) + return nullptr; - AppendJSONProperty(buf, "file", NO_COMMA); + if (!AppendJSONProperty(buf, "file", NO_COMMA)) + return nullptr; JSString* str = JS_NewStringCopyZ(cx, script->filename()); if (!str || !(str = StringToSource(cx, str))) return nullptr; - buf.append(str); + if (!buf.append(str)) + return nullptr; - AppendJSONProperty(buf, "line"); - NumberValueToStringBuffer(cx, Int32Value(script->lineno()), buf); + if (!AppendJSONProperty(buf, "line")) + return nullptr; + if (!NumberValueToStringBuffer(cx, Int32Value(script->lineno()), buf)) { + return nullptr; + } if (script->functionNonDelazifying()) { JSAtom* atom = script->functionNonDelazifying()->displayAtom(); if (atom) { - AppendJSONProperty(buf, "name"); + if (!AppendJSONProperty(buf, "name")) + return nullptr; if (!(str = StringToSource(cx, atom))) return nullptr; - buf.append(str); + if (!buf.append(str)) + return nullptr; } } @@ -1757,11 +1765,15 @@ js::GetPCCountScriptSummary(JSContext* cx, size_t index) total += counts->numExec(); } - AppendJSONProperty(buf, "totals"); - buf.append('{'); + if (!AppendJSONProperty(buf, "totals")) + return nullptr; + if (!buf.append('{')) + return nullptr; - AppendJSONProperty(buf, PCCounts::numExecName, NO_COMMA); - NumberValueToStringBuffer(cx, DoubleValue(total), buf); + if (!AppendJSONProperty(buf, PCCounts::numExecName, NO_COMMA)) + return nullptr; + if (!NumberValueToStringBuffer(cx, DoubleValue(total), buf)) + return nullptr; uint64_t ionActivity = 0; jit::IonScriptCounts* ionCounts = sac.getIonCounts(); @@ -1771,15 +1783,18 @@ js::GetPCCountScriptSummary(JSContext* cx, size_t index) ionCounts = ionCounts->previous(); } if (ionActivity) { - AppendJSONProperty(buf, "ion", COMMA); - NumberValueToStringBuffer(cx, DoubleValue(ionActivity), buf); + if (!AppendJSONProperty(buf, "ion", COMMA)) + return nullptr; + if (!NumberValueToStringBuffer(cx, DoubleValue(ionActivity), buf)) + return nullptr; } - buf.append('}'); - buf.append('}'); - - if (cx->isExceptionPending()) + if (!buf.append('}')) return nullptr; + if (!buf.append('}')) + return nullptr; + + MOZ_ASSERT(!cx->isExceptionPending()); return buf.finishString(); } @@ -1789,20 +1804,27 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf) { RootedScript script(cx, sac.script); - buf.append('{'); - AppendJSONProperty(buf, "text", NO_COMMA); + if (!buf.append('{')) + return false; + if (!AppendJSONProperty(buf, "text", NO_COMMA)) + return false; JSString* str = JS_DecompileScript(cx, script, nullptr, 0); if (!str || !(str = StringToSource(cx, str))) return false; - buf.append(str); + if (!buf.append(str)) + return false; - AppendJSONProperty(buf, "line"); - NumberValueToStringBuffer(cx, Int32Value(script->lineno()), buf); + if (!AppendJSONProperty(buf, "line")) + return false; + if (!NumberValueToStringBuffer(cx, Int32Value(script->lineno()), buf)) + return false; - AppendJSONProperty(buf, "opcodes"); - buf.append('['); + if (!AppendJSONProperty(buf, "opcodes")) + return false; + if (!buf.append('[')) + return false; bool comma = false; SrcNoteLineScanner scanner(script->notes(), script->lineno()); @@ -1819,26 +1841,35 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf) if (counts) hits = counts->numExec(); - if (comma) - buf.append(','); + if (comma && !buf.append(',')) + return false; comma = true; - buf.append('{'); + if (!buf.append('{')) + return false; - AppendJSONProperty(buf, "id", NO_COMMA); - NumberValueToStringBuffer(cx, Int32Value(offset), buf); + if (!AppendJSONProperty(buf, "id", NO_COMMA)) + return false; + if (!NumberValueToStringBuffer(cx, Int32Value(offset), buf)) + return false; scanner.advanceTo(offset); - AppendJSONProperty(buf, "line"); - NumberValueToStringBuffer(cx, Int32Value(scanner.getLine()), buf); + if (!AppendJSONProperty(buf, "line")) + return false; + if (!NumberValueToStringBuffer(cx, Int32Value(scanner.getLine()), buf)) + return false; { const char* name = CodeName[op]; - AppendJSONProperty(buf, "name"); - buf.append('\"'); - buf.append(name, strlen(name)); - buf.append('\"'); + if (!AppendJSONProperty(buf, "name")) + return false; + if (!buf.append('\"')) + return false; + if (!buf.append(name, strlen(name))) + return false; + if (!buf.append('\"')) + return false; } { @@ -1850,24 +1881,32 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf) char* text; if (!ed.getOutput(&text)) return false; - AppendJSONProperty(buf, "text"); JSString* str = JS_NewStringCopyZ(cx, text); js_free(text); + if (!AppendJSONProperty(buf, "text")) + return false; if (!str || !(str = StringToSource(cx, str))) return false; - buf.append(str); + if (!buf.append(str)) + return false; } - AppendJSONProperty(buf, "counts"); - buf.append('{'); + if (!AppendJSONProperty(buf, "counts")) + return false; + if (!buf.append('{')) + return false; if (hits > 0) { - AppendJSONProperty(buf, PCCounts::numExecName, NO_COMMA); - NumberValueToStringBuffer(cx, DoubleValue(hits), buf); + if (!AppendJSONProperty(buf, PCCounts::numExecName, NO_COMMA)) + return false; + if (!NumberValueToStringBuffer(cx, DoubleValue(hits), buf)) + return false; } - buf.append('}'); - buf.append('}'); + if (!buf.append('}')) + return false; + if (!buf.append('}')) + return false; // If the current instruction has thrown, // then decrement the hit counts with the number of throws. @@ -1876,57 +1915,79 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf) hits -= counts->numExec(); } - buf.append(']'); + if (!buf.append(']')) + return false; jit::IonScriptCounts* ionCounts = sac.getIonCounts(); if (ionCounts) { - AppendJSONProperty(buf, "ion"); - buf.append('['); + if (!AppendJSONProperty(buf, "ion")) + return false; + if (!buf.append('[')) + return false; bool comma = false; while (ionCounts) { - if (comma) - buf.append(','); + if (comma && !buf.append(',')) + return false; comma = true; - buf.append('['); + if (!buf.append('[')) + return false; for (size_t i = 0; i < ionCounts->numBlocks(); i++) { - if (i) - buf.append(','); + if (i && !buf.append(',')) + return false; const jit::IonBlockCounts& block = ionCounts->block(i); - buf.append('{'); - AppendJSONProperty(buf, "id", NO_COMMA); - NumberValueToStringBuffer(cx, Int32Value(block.id()), buf); - AppendJSONProperty(buf, "offset"); - NumberValueToStringBuffer(cx, Int32Value(block.offset()), buf); - AppendJSONProperty(buf, "successors"); - buf.append('['); + if (!buf.append('{')) + return false; + if (!AppendJSONProperty(buf, "id", NO_COMMA)) + return false; + if (!NumberValueToStringBuffer(cx, Int32Value(block.id()), buf)) + return false; + if (!AppendJSONProperty(buf, "offset")) + return false; + if (!NumberValueToStringBuffer(cx, Int32Value(block.offset()), buf)) + return false; + if (!AppendJSONProperty(buf, "successors")) + return false; + if (!buf.append('[')) + return false; for (size_t j = 0; j < block.numSuccessors(); j++) { - if (j) - buf.append(','); - NumberValueToStringBuffer(cx, Int32Value(block.successor(j)), buf); + if (j && !buf.append(',')) + return false; + if (!NumberValueToStringBuffer(cx, Int32Value(block.successor(j)), buf)) + return false; } - buf.append(']'); - AppendJSONProperty(buf, "hits"); - NumberValueToStringBuffer(cx, DoubleValue(block.hitCount()), buf); + if (!buf.append(']')) + return false; + if (!AppendJSONProperty(buf, "hits")) + return false; + if (!NumberValueToStringBuffer(cx, DoubleValue(block.hitCount()), buf)) + return false; - AppendJSONProperty(buf, "code"); + if (!AppendJSONProperty(buf, "code")) + return false; JSString* str = JS_NewStringCopyZ(cx, block.code()); if (!str || !(str = StringToSource(cx, str))) return false; - buf.append(str); - buf.append('}'); + if (!buf.append(str)) + return false; + if (!buf.append('}')) + return false; } - buf.append(']'); + if (!buf.append(']')) + return false; ionCounts = ionCounts->previous(); } - buf.append(']'); + if (!buf.append(']')) + return false; } - buf.append('}'); + if (!buf.append('}')) + return false; - return !cx->isExceptionPending(); + MOZ_ASSERT(!cx->isExceptionPending()); + return true; } JS_FRIEND_API(JSString*) diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp index 9892463a3e..026366609e 100644 --- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -239,7 +239,7 @@ Shape::fixupDictionaryShapeAfterMovingGC() // list then it points to the shape_ field of the object the list is for. // We can tell which it is because the base shape is owned if this is the // last property and not otherwise. - bool listpPointsIntoShape = !base()->isOwned(); + bool listpPointsIntoShape = !MaybeForwarded(base())->isOwned(); #ifdef DEBUG // Check that we got this right by interrogating the arena. diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 6e3fa463f7..05674d220c 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1809,7 +1809,7 @@ JSScript::sourceData(JSContext* cx) } UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() - : cache_(nullptr), source_(nullptr), charsToFree_(nullptr) + : cache_(nullptr), source_(nullptr) { } @@ -1824,24 +1824,19 @@ UncompressedSourceCache::AutoHoldEntry::holdEntry(UncompressedSourceCache* cache } void -UncompressedSourceCache::AutoHoldEntry::deferDelete(const char16_t* chars) +UncompressedSourceCache::AutoHoldEntry::deferDelete(UniqueTwoByteChars chars) { // Take ownership of source chars now the cache is being purged. Remove our // reference to the ScriptSource which might soon be destroyed. MOZ_ASSERT(cache_ && source_ && !charsToFree_); cache_ = nullptr; source_ = nullptr; - charsToFree_ = chars; + charsToFree_ = Move(chars); } UncompressedSourceCache::AutoHoldEntry::~AutoHoldEntry() { - // The holder is going out of scope. If it has taken ownership of cached - // chars then delete them, otherwise unregister ourself with the cache. - if (charsToFree_) { - MOZ_ASSERT(!cache_ && !source_); - js_free(const_cast(charsToFree_)); - } else if (cache_) { + if (cache_) { MOZ_ASSERT(source_); cache_->releaseEntry(*this); } @@ -1870,29 +1865,25 @@ UncompressedSourceCache::lookup(ScriptSource* ss, AutoHoldEntry& holder) return nullptr; if (Map::Ptr p = map_->lookup(ss)) { holdEntry(holder, ss); - return p->value(); + return p->value().get(); } return nullptr; } bool -UncompressedSourceCache::put(ScriptSource* ss, const char16_t* str, AutoHoldEntry& holder) +UncompressedSourceCache::put(ScriptSource* ss, UniqueTwoByteChars str, AutoHoldEntry& holder) { MOZ_ASSERT(!holder_); if (!map_) { - map_ = js_new(); - if (!map_) + UniquePtr map = MakeUnique(); + if (!map || !map->init()) return false; - if (!map_->init()) { - js_delete(map_); - map_ = nullptr; - return false; - } + map_ = Move(map); } - if (!map_->put(ss, str)) + if (!map_->put(ss, Move(str))) return false; holdEntry(holder, ss); @@ -1906,17 +1897,13 @@ UncompressedSourceCache::purge() return; for (Map::Range r = map_->all(); !r.empty(); r.popFront()) { - const char16_t* chars = r.front().value(); if (holder_ && r.front().key() == holder_->source()) { - holder_->deferDelete(chars); + holder_->deferDelete(Move(r.front().value())); holder_ = nullptr; - } else { - js_free(const_cast(chars)); } } - js_delete(map_); - map_ = nullptr; + map_.reset(); } size_t @@ -1925,10 +1912,8 @@ UncompressedSourceCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) size_t n = 0; if (map_ && !map_->empty()) { n += map_->sizeOfIncludingThis(mallocSizeOf); - for (Map::Range r = map_->all(); !r.empty(); r.popFront()) { - const char16_t* v = r.front().value(); - n += mallocSizeOf(v); - } + for (Map::Range r = map_->all(); !r.empty(); r.popFront()) + n += mallocSizeOf(r.front().value().get()); } return n; } @@ -1959,29 +1944,45 @@ ScriptSource::chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holde if (const char16_t* decompressed = cx->runtime()->uncompressedSourceCache.lookup(&ss, holder)) return decompressed; - const size_t nbytes = sizeof(char16_t) * (ss.length() + 1); - char16_t* decompressed = static_cast(js_malloc(nbytes)); + const size_t lengthWithNull = ss.length() + 1; + UniqueTwoByteChars decompressed(js_pod_malloc(lengthWithNull)); if (!decompressed) { JS_ReportOutOfMemory(cx); return nullptr; } - if (!DecompressString((const unsigned char*) ss.compressedData(), ss.compressedBytes(), - reinterpret_cast(decompressed), nbytes)) { + if (!DecompressString((const unsigned char*) ss.compressedData(), + ss.compressedBytes(), + reinterpret_cast(decompressed.get()), + lengthWithNull * sizeof(char16_t))) + { JS_ReportOutOfMemory(cx); - js_free(decompressed); return nullptr; } decompressed[ss.length()] = 0; + ReturnType ret = decompressed.get(); - if (!cx->runtime()->uncompressedSourceCache.put(&ss, decompressed, holder)) { - JS_ReportOutOfMemory(cx); - js_free(decompressed); - return nullptr; + // Decompressing a huge script is expensive. With lazy parsing and + // relazification, this can happen repeatedly, so conservatively go + // back to storing the data uncompressed to avoid wasting too much + // time decompressing. + const size_t HUGE_SCRIPT = 5 * 1024 * 1024; + if (lengthWithNull > HUGE_SCRIPT) { + if (ss.inCompressedSourceSet) { + TlsPerThreadData.get()->runtimeFromMainThread()->compressedSourceSet.remove(&ss); + ss.inCompressedSourceSet = false; + } + js_free(ss.compressedData()); + ss.data = SourceType(Uncompressed(decompressed.release(), true)); + } else { + if (!cx->runtime()->uncompressedSourceCache.put(&ss, Move(decompressed), holder)) { + JS_ReportOutOfMemory(cx); + return nullptr; + } } - return decompressed; + return ret; } ReturnType match(Parent& p) { @@ -2096,9 +2097,6 @@ ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf, // There are several cases where source compression is not a good idea: // - If the script is tiny, then compression will save little or no space. - // - If the script is enormous, then decompression can take seconds. With - // lazy parsing, decompression is not uncommon, so this can significantly - // increase latency. // - If there is only one core, then compression will contend with JS // execution (which hurts benchmarketing). // - If the source contains a giant string, then parsing will finish much @@ -2120,8 +2118,7 @@ ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf, HelperThreadState().threadCount >= 2 && CanUseExtraThreads(); const size_t TINY_SCRIPT = 256; - const size_t HUGE_SCRIPT = 5 * 1024 * 1024; - if (TINY_SCRIPT <= srcBuf.length() && srcBuf.length() < HUGE_SCRIPT && canCompressOffThread) { + if (TINY_SCRIPT <= srcBuf.length() && canCompressOffThread) { task->ss = this; if (!StartOffThreadCompression(cx, task)) return false; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 440be3138f..13ecac32dd 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -578,7 +578,7 @@ class ScriptSource; class UncompressedSourceCache { typedef HashMap, SystemAllocPolicy> Map; @@ -588,26 +588,26 @@ class UncompressedSourceCache { UncompressedSourceCache* cache_; ScriptSource* source_; - const char16_t* charsToFree_; + UniqueTwoByteChars charsToFree_; public: explicit AutoHoldEntry(); ~AutoHoldEntry(); private: void holdEntry(UncompressedSourceCache* cache, ScriptSource* source); - void deferDelete(const char16_t* chars); + void deferDelete(UniqueTwoByteChars chars); ScriptSource* source() const { return source_; } friend class UncompressedSourceCache; }; private: - Map* map_; + UniquePtr map_; AutoHoldEntry* holder_; public: - UncompressedSourceCache() : map_(nullptr), holder_(nullptr) {} + UncompressedSourceCache() : holder_(nullptr) {} const char16_t* lookup(ScriptSource* ss, AutoHoldEntry& asp); - bool put(ScriptSource* ss, const char16_t* chars, AutoHoldEntry& asp); + bool put(ScriptSource* ss, UniqueTwoByteChars chars, AutoHoldEntry& asp); void purge(); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 9c29c53dd3..0452de9f74 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1372,7 +1372,7 @@ class StringSegmentRange : stack(cx, StringVector(cx)), cur(cx) {} - MOZ_WARN_UNUSED_RESULT bool init(JSString* str) { + MOZ_MUST_USE bool init(JSString* str) { MOZ_ASSERT(stack.empty()); return settle(str); } @@ -1386,7 +1386,7 @@ class StringSegmentRange return cur; } - MOZ_WARN_UNUSED_RESULT bool popFront() { + MOZ_MUST_USE bool popFront() { MOZ_ASSERT(!empty()); if (stack.empty()) { cur = nullptr; @@ -3091,6 +3091,7 @@ js_fputs(const char16_t* s, FILE* f) while (*s != 0) { if (fputwc(wchar_t(*s), f) == WEOF) return WEOF; + s++; } return 1; } diff --git a/js/src/jsutil.h b/js/src/jsutil.h index 87ab63b88c..13eac5ef0b 100644 --- a/js/src/jsutil.h +++ b/js/src/jsutil.h @@ -314,6 +314,36 @@ PodSet(T* aDst, T aSrc, size_t aNElem) } /* namespace mozilla */ +/* + * Patterns used by SpiderMonkey to overwrite unused memory. If you are + * accessing an object with one of these pattern, you probably have a dangling + * pointer. These values should be odd, see the comment in IsThingPoisoned. + * + * Note: new patterns should also be added to the array in IsThingPoisoned! + */ +#define JS_FRESH_NURSERY_PATTERN 0x2F +#define JS_SWEPT_NURSERY_PATTERN 0x2B +#define JS_ALLOCATED_NURSERY_PATTERN 0x2D +#define JS_FRESH_TENURED_PATTERN 0x4F +#define JS_MOVED_TENURED_PATTERN 0x49 +#define JS_SWEPT_TENURED_PATTERN 0x4B +#define JS_ALLOCATED_TENURED_PATTERN 0x4D + +/* + * Ensure JS_SWEPT_CODE_PATTERN is a byte pattern that will crash immediately + * when executed, so either an undefined instruction or an instruction that's + * illegal in user mode. + */ +#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_NONE) +# define JS_SWEPT_CODE_PATTERN 0xED // IN instruction, crashes in user mode. +#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) +# define JS_SWEPT_CODE_PATTERN 0xA3 // undefined instruction +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +# define JS_SWEPT_CODE_PATTERN 0x01 // undefined instruction +#else +# error "JS_SWEPT_CODE_PATTERN not defined for this platform" +#endif + static inline void* Poison(void* ptr, uint8_t value, size_t num) { diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 726225cd60..31c36fcefe 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -124,6 +124,8 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, @@ -179,6 +181,8 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrap MutableHandleObject protop) const override; virtual bool setPrototype(JSContext* cx, HandleObject wrapper, HandleObject proto, ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper, bool* isOrdinary, + MutableHandleObject protop) const override; virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper, bool* succeeded) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, diff --git a/js/src/moz.build b/js/src/moz.build index 516b73ac49..164e50175c 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -156,6 +156,7 @@ UNIFIED_SOURCES += [ 'asmjs/AsmJS.cpp', 'asmjs/Wasm.cpp', 'asmjs/WasmBinary.cpp', + 'asmjs/WasmBinaryIterator.cpp', 'asmjs/WasmBinaryToText.cpp', 'asmjs/WasmFrameIterator.cpp', 'asmjs/WasmGenerator.cpp', @@ -211,6 +212,7 @@ UNIFIED_SOURCES += [ 'irregexp/RegExpParser.cpp', 'irregexp/RegExpStack.cpp', 'jit/AliasAnalysis.cpp', + 'jit/AliasAnalysisShared.cpp', 'jit/AlignmentMaskAnalysis.cpp', 'jit/BacktrackingAllocator.cpp', 'jit/Bailouts.cpp', @@ -234,6 +236,7 @@ UNIFIED_SOURCES += [ 'jit/EdgeCaseAnalysis.cpp', 'jit/EffectiveAddressAnalysis.cpp', 'jit/ExecutableAllocator.cpp', + 'jit/FlowAliasAnalysis.cpp', 'jit/InstructionReordering.cpp', 'jit/Ion.cpp', 'jit/IonAnalysis.cpp', @@ -246,6 +249,7 @@ UNIFIED_SOURCES += [ 'jit/JitSpewer.cpp', 'jit/JSONSpewer.cpp', 'jit/LICM.cpp', + 'jit/Linker.cpp', 'jit/LIR.cpp', 'jit/LoopUnroller.cpp', 'jit/Lowering.cpp', diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index 1fa146817b..ec0d392fd6 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -396,7 +396,7 @@ BaseProxyHandler::weakmapKeyDelegate(JSObject* proxy) const bool BaseProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const { - MOZ_CRASH("Must override getPrototype with lazy prototype."); + MOZ_CRASH("must override getPrototype with lazy prototype"); } bool @@ -411,6 +411,13 @@ BaseProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject p return false; } +bool +BaseProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const +{ + MOZ_CRASH("must override getPrototypeIfOrdinary with lazy prototype"); +} + bool BaseProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const { diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 3060e51f88..43bbb0b4cc 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -108,6 +108,24 @@ CrossCompartmentWrapper::setPrototype(JSContext* cx, HandleObject wrapper, NOTHING); } +bool +CrossCompartmentWrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper, + bool* isOrdinary, MutableHandleObject protop) const +{ + { + RootedObject wrapped(cx, wrappedObject(wrapper)); + AutoCompartment call(cx, wrapped); + if (!GetPrototypeIfOrdinary(cx, wrapped, isOrdinary, protop)) + return false; + if (protop) { + if (!protop->setDelegate(cx)) + return false; + } + } + + return cx->compartment()->wrap(cx, protop); +} + bool CrossCompartmentWrapper::setImmutablePrototype(JSContext* cx, HandleObject wrapper, bool* succeeded) const { diff --git a/js/src/proxy/DeadObjectProxy.cpp b/js/src/proxy/DeadObjectProxy.cpp index 5d72062b34..8cc19849e3 100644 --- a/js/src/proxy/DeadObjectProxy.cpp +++ b/js/src/proxy/DeadObjectProxy.cpp @@ -60,6 +60,14 @@ DeadObjectProxy::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleOb return true; } +bool +DeadObjectProxy::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const +{ + *isOrdinary = false; + return true; +} + bool DeadObjectProxy::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const { diff --git a/js/src/proxy/DeadObjectProxy.h b/js/src/proxy/DeadObjectProxy.h index b071efc06e..a06083cf67 100644 --- a/js/src/proxy/DeadObjectProxy.h +++ b/js/src/proxy/DeadObjectProxy.h @@ -30,6 +30,8 @@ class DeadObjectProxy : public BaseProxyHandler ObjectOpResult& result) const override; virtual bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; virtual bool preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const override; virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override; diff --git a/js/src/proxy/DirectProxyHandler.cpp b/js/src/proxy/DirectProxyHandler.cpp index 683b389e0f..a3292fea53 100644 --- a/js/src/proxy/DirectProxyHandler.cpp +++ b/js/src/proxy/DirectProxyHandler.cpp @@ -142,6 +142,14 @@ DirectProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject return SetPrototype(cx, target, proto, result); } +bool +DirectProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, + bool* isOrdinary, MutableHandleObject protop) const +{ + RootedObject target(cx, proxy->as().target()); + return GetPrototypeIfOrdinary(cx, target, isOrdinary, protop); +} + bool DirectProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const { diff --git a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp index 6a70cd5294..3603aa53b1 100644 --- a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp +++ b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp @@ -64,6 +64,15 @@ OpaqueCrossCompartmentWrapper::setPrototype(JSContext* cx, HandleObject proxy, H return result.succeed(); } +bool +OpaqueCrossCompartmentWrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, + bool* isOrdinary, + MutableHandleObject protop) const +{ + *isOrdinary = false; + return true; +} + bool OpaqueCrossCompartmentWrapper::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index b8ae33a981..ba5f52bdf9 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -196,6 +196,16 @@ Proxy::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, Objec return proxy->as().handler()->setPrototype(cx, proxy, proto, result); } +/* static */ bool +Proxy::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject proto) +{ + MOZ_ASSERT(proxy->hasLazyPrototype()); + JS_CHECK_RECURSION(cx, return false); + return proxy->as().handler()->getPrototypeIfOrdinary(cx, proxy, isOrdinary, + proto); +} + /* static */ bool Proxy::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) { diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index d2b955bbe5..4319ebba63 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -38,6 +38,8 @@ class Proxy static bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop); static bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result); + static bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop); static bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded); static bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp); static bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id, diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 703bb4e84a..679af0d658 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -165,33 +165,152 @@ GetProxyTrap(JSContext* cx, HandleObject handler, HandlePropertyName name, Mutab return true; } -// ES6 implements both getPrototype and setPrototype traps. We don't have them yet (see bug -// 888969). For now, use these, to account for proxy revocation. +// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.1 Proxy.[[GetPrototypeOf]]. bool ScriptedDirectProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const { - RootedObject target(cx, proxy->as().target()); - // Though handler is used elsewhere, spec mandates that both get set to null. - if (!target) { + // Steps 1-3. + RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); + if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } - return GetPrototype(cx, target, protop); + // Step 4. + RootedObject target(cx, proxy->as().target()); + MOZ_ASSERT(target); + + // Step 5. + RootedValue trap(cx); + if (!GetProxyTrap(cx, handler, cx->names().getPrototypeOf, &trap)) + return false; + + // Step 6. + if (trap.isUndefined()) + return GetPrototype(cx, target, protop); + + // Step 7. + RootedValue handlerProto(cx); + { + FixedInvokeArgs<1> args(cx); + + args[0].setObject(*target); + + handlerProto.setObject(*handler); + + if (!js::Call(cx, trap, handlerProto, args, &handlerProto)) + return false; + } + + // Step 8. + if (!handlerProto.isObjectOrNull()) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN); + return false; + } + + // Step 9. + bool extensibleTarget; + if (!IsExtensible(cx, target, &extensibleTarget)) + return false; + + // Step 10. + if (extensibleTarget) { + protop.set(handlerProto.toObjectOrNull()); + return true; + } + + // Step 11. + RootedObject targetProto(cx); + if (!GetPrototype(cx, target, &targetProto)) + return false; + + // Step 12. + if (handlerProto.toObjectOrNull() != targetProto) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCONSISTENT_GETPROTOTYPEOF_TRAP); + return false; + } + + // Step 13. + protop.set(handlerProto.toObjectOrNull()); + return true; } +// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.2 Proxy.[[SetPrototypeOf]]. bool ScriptedDirectProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const { - RootedObject target(cx, proxy->as().target()); - if (!target) { + // Steps 1-4. + RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); + if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } - return SetPrototype(cx, target, proto, result); + // Step 5. + RootedObject target(cx, proxy->as().target()); + MOZ_ASSERT(target); + + // Step 6. + RootedValue trap(cx); + if (!GetProxyTrap(cx, handler, cx->names().setPrototypeOf, &trap)) + return false; + + // Step 7. + if (trap.isUndefined()) + return SetPrototype(cx, target, proto, result); + + // Step 8. + bool booleanTrapResult; + { + FixedInvokeArgs<2> args(cx); + + args[0].setObject(*target); + args[1].setObjectOrNull(proto); + + RootedValue hval(cx, ObjectValue(*handler)); + if (!js::Call(cx, trap, hval, args, &hval)) + return false; + + booleanTrapResult = ToBoolean(hval); + } + + // Step 9. + if (!booleanTrapResult) + return result.fail(JSMSG_PROXY_SETPROTOTYPEOF_RETURNED_FALSE); + + // Step 10. + bool extensibleTarget; + if (!IsExtensible(cx, target, &extensibleTarget)) + return false; + + // Step 11. + if (extensibleTarget) + return result.succeed(); + + // Step 12. + RootedObject targetProto(cx); + if (!GetPrototype(cx, target, &targetProto)) + return false; + + // Step 13. + if (proto != targetProto) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCONSISTENT_SETPROTOTYPEOF_TRAP); + return false; + } + + // Step 14. + return result.succeed(); +} + +bool +ScriptedDirectProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, + bool* isOrdinary, + MutableHandleObject protop) const +{ + *isOrdinary = false; + return true; } // Not yet part of ES6, but hopefully to be standards-tracked -- and needed to diff --git a/js/src/proxy/ScriptedDirectProxyHandler.h b/js/src/proxy/ScriptedDirectProxyHandler.h index 840827572f..abc1446e9e 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.h +++ b/js/src/proxy/ScriptedDirectProxyHandler.h @@ -34,6 +34,9 @@ class ScriptedDirectProxyHandler : public BaseProxyHandler { MutableHandleObject protop) const override; virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const override; + /* Non-standard, but needed to implement OrdinaryGetPrototypeOf. */ + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; /* Non-standard, but needed to handle revoked proxies. */ virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index d2734d0006..e30c10b989 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -5557,7 +5557,7 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = { JS_INLINABLE_FN_HELP("assertFloat32", testingFunc_assertFloat32, 2, 0, TestAssertFloat32, "assertFloat32(value, isFloat32)", -" In IonMonkey only, asserts that value has (resp. hasn't) the MIRType_Float32 if isFloat32 is true (resp. false)."), +" In IonMonkey only, asserts that value has (resp. hasn't) the MIRType::Float32 if isFloat32 is true (resp. false)."), JS_INLINABLE_FN_HELP("assertRecoveredOnBailout", testingFunc_assertRecoveredOnBailout, 2, 0, TestAssertRecoveredOnBailout, @@ -6694,6 +6694,15 @@ SetRuntimeOptions(JSRuntime* rt, const OptionParser& op) } } + if (const char* str = op.getStringOption("ion-aa")) { + if (strcmp(str, "flow-sensitive") == 0) + jit::JitOptions.disableFlowAA = false; + else if (strcmp(str, "flow-insensitive") == 0) + jit::JitOptions.disableFlowAA = true; + else + return OptionFailure("ion-aa", str); + } + if (const char* str = op.getStringOption("ion-licm")) { if (strcmp(str, "on") == 0) jit::JitOptions.disableLicm = false; @@ -7130,6 +7139,9 @@ main(int argc, char** argv, char** envp) " on: enable GVN (default)\n") || !op.addStringOption('\0', "ion-licm", "on/off", "Loop invariant code motion (default: on, off to disable)") + || !op.addStringOption('\0', "ion-aa", "flow-sensitive/flow-insensitive", + "Specify wheter or not to use flow sensitive Alias Analysis" + "(default: flow-insensitive)") || !op.addStringOption('\0', "ion-edgecase-analysis", "on/off", "Find edge cases where Ion can avoid bailouts (default: on, off to disable)") || !op.addStringOption('\0', "ion-pgo", "on/off", diff --git a/js/src/tests/ecma_6/Class/methodName.js b/js/src/tests/ecma_6/Class/methodName.js new file mode 100644 index 0000000000..02a726c105 --- /dev/null +++ b/js/src/tests/ecma_6/Class/methodName.js @@ -0,0 +1,40 @@ +class TestClass { + get getter() { } + set setter(x) { } + method() { } + + static get staticGetter() { } + static set staticSetter(x) { } + static staticMethod() { } + + get 1() { } + set 2(v) { } + 3() { } + + static get 4() { } + static set 5(x) { } + static 6() { } +} + +function name(obj, property, get) { + let desc = Object.getOwnPropertyDescriptor(obj, property); + return (get ? desc.get : desc.set).name; +} + +assertEq(name(TestClass.prototype, "getter", true), "get getter"); +assertEq(name(TestClass.prototype, "setter", false), "set setter"); +assertEq(TestClass.prototype.method.name, "method"); + +assertEq(name(TestClass, "staticGetter", true), "get staticGetter"); +assertEq(name(TestClass, "staticSetter", false), "set staticSetter"); +assertEq(TestClass.staticMethod.name, "staticMethod"); + +assertEq(name(TestClass.prototype, "1", true), "get 1"); +assertEq(name(TestClass.prototype, "2", false), "set 2"); +assertEq(TestClass.prototype[3].name, "3"); + +assertEq(name(TestClass, "4", true), "get 4"); +assertEq(name(TestClass, "5", false), "set 5"); +assertEq(TestClass[6].name, "6"); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/accessor-name.js b/js/src/tests/ecma_6/Object/accessor-name.js new file mode 100644 index 0000000000..1b5268e072 --- /dev/null +++ b/js/src/tests/ecma_6/Object/accessor-name.js @@ -0,0 +1,36 @@ +function name(obj, property, get) { + let desc = Object.getOwnPropertyDescriptor(obj, property); + return (get ? desc.get : desc.set).name; +} + +assertEq(name({get a() {}}, "a", true), "get a"); +assertEq(name({set a(v) {}}, "a", false), "set a"); + +assertEq(name({get 123() {}}, "123", true), "get 123"); +assertEq(name({set 123(v) {}}, "123", false), "set 123"); + +assertEq(name({get case() {}}, "case", true), "get case"); +assertEq(name({set case(v) {}}, "case", false), "set case"); + +assertEq(name({get get() {}}, "get", true), "get get"); +assertEq(name({set set(v) {}}, "set", false), "set set"); + +let o = {get a() { }, set a(v) {}}; +assertEq(name(o, "a", true), "get a"); +assertEq(name(o, "a", false), "set a"); + +o = {get 123() { }, set 123(v) {}} +assertEq(name(o, "123", true), "get 123"); +assertEq(name(o, "123", false), "set 123"); + +o = {get case() { }, set case(v) {}} +assertEq(name(o, "case", true), "get case"); +assertEq(name(o, "case", false), "set case"); + +// Congratulations on implementing these! +assertEq(name({get ["a"]() {}}, "a", true), ""); +assertEq(name({get [123]() {}}, "123", true), ""); +assertEq(name({set ["a"](v) {}}, "a", false), ""); +assertEq(name({set [123](v) {}}, "123", false), ""); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Proxy/getPrototypeOf.js b/js/src/tests/ecma_6/Proxy/getPrototypeOf.js new file mode 100644 index 0000000000..a0676c0c91 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/getPrototypeOf.js @@ -0,0 +1,285 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "getPrototypeOf.js"; +var BUGNUMBER = 888969; +var summary = "Scripted proxies' [[GetPrototypeOf]] behavior"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +const log = []; + +function observe(obj) +{ + var observingHandler = new Proxy({}, { + get(target, p, receiver) { + log.push(p); + return Reflect.get(target, p, receiver); + } + }); + + return new Proxy(obj, observingHandler); +} + +function nop() {} + +var p, h; + +// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. +// 2. If handler is null, throw a TypeError exception. +// 3. Assert: Type(handler) is Object. +var rev = Proxy.revocable({}, {}); +p = rev.proxy; + +assertEq(Object.getPrototypeOf(p), Object.prototype); +rev.revoke(); +assertThrowsInstanceOf(() => Object.getPrototypeOf(p), TypeError); + +// 4. Let target be the value of the [[ProxyTarget]] internal slot of O. +// 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). + +// Getting handler.getPrototypeOf might throw. +assertThrowsValue(() => Object.getPrototypeOf(new Proxy({}, + { get getPrototypeOf() { + throw 17; + } })), + 17); + +// The handler's getPrototypeOf, once gotten, might throw. +p = new Proxy({}, { getPrototypeOf() { throw 42; } }); + +assertThrowsValue(() => Object.getPrototypeOf(p), 42); + +// The trap might not be callable. +p = new Proxy({}, { getPrototypeOf: 17 }); + +assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + +// 6. If trap is undefined, then +// a. Return ? target.[[GetPrototypeOf]](). + +var x, tp; + +tp = + new Proxy(new Number(8675309), // behavior overridden by getPrototypeOf + { getPrototypeOf() { x = "getPrototypeOf trap"; return null; } }); + +// The target's [[GetPrototypeOf]] should be invoked if the handler's +// .getPrototypeOf is undefined. +p = new Proxy(tp, { getPrototypeOf: undefined }); +x = "unset"; +assertEq(Object.getPrototypeOf(p), null); +assertEq(x, "getPrototypeOf trap"); + +// Likewise if the handler's .getPrototypeOf is null. +p = new Proxy(tp, { getPrototypeOf: null }); +x = "unset"; +assertEq(Object.getPrototypeOf(p), null); +assertEq(x, "getPrototypeOf trap"); + +// Now the target is an empty object with a Number object as its [[Prototype]]. +var customProto = new Number(8675309); +tp = + new Proxy({}, + { getPrototypeOf() { + x = "getPrototypeOf trap"; + return customProto; + } }); + +// The target's [[GetPrototypeOf]] should be invoked if the handler's +// .getPrototypeOf is undefined. +p = new Proxy(tp, { getPrototypeOf: undefined }); +x = "unset"; +assertEq(Object.getPrototypeOf(p), customProto); +assertEq(x, "getPrototypeOf trap"); + +// Likewise if the handler's .getPrototypeOf is null. +p = new Proxy(tp, { getPrototypeOf: null }); +x = "unset"; +assertEq(Object.getPrototypeOf(p), customProto); +assertEq(x, "getPrototypeOf trap"); + +// 7. Let handlerProto be ? Call(trap, handler, « target »). + +// The trap callable might throw. +p = new Proxy({}, { getPrototypeOf() { throw "ohai"; } }); + +assertThrowsValue(() => Object.getPrototypeOf(p), + "ohai"); + +var throwingTrap = + new Proxy(function() { throw "not called"; }, + { apply() { throw 37; } }); + +p = new Proxy({}, { getPrototypeOf: throwingTrap }); + +assertThrowsValue(() => Object.getPrototypeOf(p), + 37); + +// The trap callable must *only* be called. +p = new Proxy({}, + { + getPrototypeOf: observe(function() { throw "boo-urns"; }) + }); + +log.length = 0; +assertThrowsValue(() => Object.getPrototypeOf(p), + "boo-urns"); + +assertEq(log.length, 1); +assertEq(log[0], "apply"); + +// 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError exception. + +var rval; + +var typeTestingTarget = {}; +p = new Proxy(typeTestingTarget, { getPrototypeOf() { return rval; } }); + +function returnsPrimitives() +{ + rval = undefined; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = true; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = false; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = 0.0; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = -0.0; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = 3.141592654; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = NaN; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = -Infinity; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = "[[Prototype]] FOR REALZ"; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = Symbol("[[Prototype]] FOR REALZ"); + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); +} + +returnsPrimitives(); +Object.preventExtensions(typeTestingTarget); +returnsPrimitives(); + +// 9. Let extensibleTarget be ? IsExtensible(target). + +var act, extens; + +var typeTestingProxyTarget = + new Proxy({}, { isExtensible() { + seen = act(); + return extens; + } }); + +p = new Proxy(typeTestingProxyTarget, { getPrototypeOf() { return rval; } }); + +rval = null; +act = () => { throw "fnord" }; +assertThrowsValue(() => Object.getPrototypeOf(p), + "fnord"); + +rval = /abc/; +act = () => { throw "fnord again" }; +assertThrowsValue(() => Object.getPrototypeOf(p), + "fnord again"); + +rval = Object.prototype; +act = () => { throw "fnord" }; +assertThrowsValue(() => Object.getPrototypeOf(p), + "fnord"); + +// 10. If extensibleTarget is true, return handlerProto. + +p = new Proxy({}, { getPrototypeOf() { return rval; } }); + +rval = Number.prototype; +assertEq(Object.getPrototypeOf(p), Number.prototype); + +// 11. Let targetProto be ? target.[[GetPrototypeOf]](). + +var targetProto; + +var targetWithProto = + new Proxy(Object.preventExtensions(Object.create(null)), + { getPrototypeOf() { act2(); return targetProto; } }); + +p = new Proxy(targetWithProto, + { getPrototypeOf() { act1(); return rval; } }); + +rval = null; +targetProto = null; + +var regex = /targetProto/; + +act1 = () => log.push("act1"); +act2 = () => log.push("act2"); + +log.length = 0; +assertEq(Object.getPrototypeOf(p), null); +assertEq(log.length, 2); +assertEq(log[0], "act1"); +assertEq(log[1], "act2"); + +act1 = () => log.push("act1 again"); +act2 = () => { throw "target throw"; }; + +log.length = 0; +assertThrowsValue(() => Object.getPrototypeOf(p), + "target throw"); +assertEq(log.length, 1); +assertEq(log[0], "act1 again"); + +// 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception. + +act1 = act2 = nop; +rval = /a/; +assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + +// 13. Return handlerProto. + +rval = null; +targetProto = null; + +assertEq(Object.getPrototypeOf(p), null); + +p = new Proxy(Object.preventExtensions(new Number(55)), + { getPrototypeOf() { return Number.prototype; } }); + +assertEq(Object.getPrototypeOf(p), Number.prototype); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Proxy/setPrototypeOf.js b/js/src/tests/ecma_6/Proxy/setPrototypeOf.js new file mode 100644 index 0000000000..d79c53fd96 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/setPrototypeOf.js @@ -0,0 +1,258 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "setPrototypeOf.js"; +var BUGNUMBER = 888969; +var summary = "Scripted proxies' [[SetPrototypeOf]] behavior"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +const log = []; + +function observe(obj) +{ + var observingHandler = new Proxy({}, { + get(target, p, receiver) { + log.push(p); + return Reflect.get(target, p, receiver); + } + }); + + return new Proxy(obj, observingHandler); +} + +var p, h; + +// 1. Assert: Either Type(V) is Object or Type(V) is Null. +// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. +// 3. If handler is null, throw a TypeError exception. +// 4. Assert: Type(handler) is Object. +// 5. Let target be the value of the [[ProxyTarget]] internal slot of O. + +var rev = Proxy.revocable({}, {}); +p = rev.proxy; + +var originalProto = Reflect.getPrototypeOf(p); +assertEq(originalProto, Object.prototype); + +rev.revoke(); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, originalProto), + TypeError); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +// 6. Let trap be ? GetMethod(handler, "setPrototypeOf"). + +// handler has uncallable (and not null/undefined) property +p = new Proxy({}, { setPrototypeOf: 9 }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: -3.7 }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: NaN }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: Infinity }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: true }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: /x/ }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: Symbol(42) }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: class X {} }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, observe({})); + +assertEq(Reflect.setPrototypeOf(p, Object.prototype), true); +assertEq(log.length, 1); +assertEq(log[0], "get"); + +h = observe({ setPrototypeOf() { throw 3.14; } }); +p = new Proxy(Object.create(Object.prototype), h); + +// "setting" without change +log.length = 0; +assertThrowsValue(() => Reflect.setPrototypeOf(p, Object.prototype), + 3.14); +assertEq(log.length, 1); +assertEq(log[0], "get"); + +// "setting" with change +log.length = 0; +assertThrowsValue(() => Reflect.setPrototypeOf(p, /foo/), + 3.14); +assertEq(log.length, 1); +assertEq(log[0], "get"); + +// 7. If trap is undefined, then +// a. Return ? target.[[SetPrototypeOf]](V). + +var settingProtoThrows = + new Proxy({}, { setPrototypeOf() { throw "agnizes"; } }); + +p = new Proxy(settingProtoThrows, { setPrototypeOf: undefined }); +assertThrowsValue(() => Reflect.setPrototypeOf(p, null), + "agnizes"); + +p = new Proxy(settingProtoThrows, { setPrototypeOf: null }); +assertThrowsValue(() => Reflect.setPrototypeOf(p, null), + "agnizes"); + +var anotherProto = + new Proxy({}, + { setPrototypeOf(t, p) { + log.push("reached"); + return Reflect.setPrototypeOf(t, p); + } }); + +p = new Proxy(anotherProto, { setPrototypeOf: undefined }); + +log.length = 0; +assertEq(Reflect.setPrototypeOf(p, null), true); +assertEq(log.length, 1); +assertEq(log[0], "reached"); + +p = new Proxy(anotherProto, { setPrototypeOf: null }); + +log.length = 0; +assertEq(Reflect.setPrototypeOf(p, null), true); +assertEq(log.length, 1); +assertEq(log[0], "reached"); + +// 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V »)). + +// The trap callable might throw. +p = new Proxy({}, { setPrototypeOf() { throw "ohai"; } }); + +assertThrowsValue(() => Reflect.setPrototypeOf(p, /x/), + "ohai"); + +var throwingTrap = + new Proxy(function() { throw "not called"; }, + { apply() { throw 37; } }); + +p = new Proxy({}, { setPrototypeOf: throwingTrap }); + +assertThrowsValue(() => Reflect.setPrototypeOf(p, Object.prototype), + 37); + +// The trap callable must *only* be called. +p = new Proxy({}, + { + setPrototypeOf: observe(function() { throw "boo-urns"; }) + }); + +log.length = 0; +assertThrowsValue(() => Reflect.setPrototypeOf(p, Object.prototype), + "boo-urns"); + +assertEq(log.length, 1); +assertEq(log[0], "apply"); + +// 9. If booleanTrapResult is false, return false. + +p = new Proxy({}, { setPrototypeOf() { return false; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return +0; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return -0; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return NaN; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return ""; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return undefined; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +// 10. Let extensibleTarget be ? IsExtensible(target). + +var targetThrowIsExtensible = + new Proxy({}, { isExtensible() { throw "psych!"; } }); + +p = new Proxy(targetThrowIsExtensible, { setPrototypeOf() { return true; } }); +assertThrowsValue(() => Reflect.setPrototypeOf(p, Object.prototype), + "psych!"); + +// 11. If extensibleTarget is true, return true. + +var targ = {}; + +p = new Proxy(targ, { setPrototypeOf() { return true; } }); +assertEq(Reflect.setPrototypeOf(p, /x/), true); +assertEq(Reflect.getPrototypeOf(targ), Object.prototype); +assertEq(Reflect.getPrototypeOf(p), Object.prototype); + +p = new Proxy(targ, { setPrototypeOf() { return /x/; } }); +assertEq(Reflect.setPrototypeOf(p, /x/), true); +assertEq(Reflect.getPrototypeOf(targ), Object.prototype); +assertEq(Reflect.getPrototypeOf(p), Object.prototype); + +p = new Proxy(targ, { setPrototypeOf() { return Infinity; } }); +assertEq(Reflect.setPrototypeOf(p, /x/), true); +assertEq(Reflect.getPrototypeOf(targ), Object.prototype); +assertEq(Reflect.getPrototypeOf(p), Object.prototype); + +p = new Proxy(targ, { setPrototypeOf() { return Symbol(true); } }); +assertEq(Reflect.setPrototypeOf(p, /x/), true); +assertEq(Reflect.getPrototypeOf(targ), Object.prototype); +assertEq(Reflect.getPrototypeOf(p), Object.prototype); + +// 12. Let targetProto be ? target.[[GetPrototypeOf]](). + +var targetNotExtensibleGetProtoThrows = + new Proxy(Object.preventExtensions({}), + { getPrototypeOf() { throw NaN; } }); + +p = new Proxy(targetNotExtensibleGetProtoThrows, + { setPrototypeOf() { log.push("goober"); return true; } }); + +log.length = 0; +assertThrowsValue(() => Reflect.setPrototypeOf(p, /abcd/), + NaN); + +// 13. If SameValue(V, targetProto) is false, throw a TypeError exception. + +var newProto; + +p = new Proxy(Object.preventExtensions(Object.create(Math)), + { setPrototypeOf(t, p) { return true; } }); + +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +// 14. Return true. + +assertEq(Reflect.setPrototypeOf(p, Math), true); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Reflect/getPrototypeOf.js b/js/src/tests/ecma_6/Reflect/getPrototypeOf.js index c9f130802d..6a29d4a9b2 100644 --- a/js/src/tests/ecma_6/Reflect/getPrototypeOf.js +++ b/js/src/tests/ecma_6/Reflect/getPrototypeOf.js @@ -6,16 +6,11 @@ assertEq(Reflect.getPrototypeOf({}), Object.prototype); assertEq(Reflect.getPrototypeOf(Object.prototype), null); assertEq(Reflect.getPrototypeOf(Object.create(null)), null); -// Sleeper test for when scripted proxies support the getPrototypeOf handler -// method (bug 888969). var proxy = new Proxy({}, { getPrototypeOf(t) { return Math; } }); -var result = Reflect.getPrototypeOf(proxy); -if (result === Math) { - throw new Error("Congratulations on fixing bug 888969! " + - "Please update this test to cover scripted proxies."); -} + +assertEq(Reflect.getPrototypeOf(proxy), Math); // For more Reflect.getPrototypeOf tests, see target.js. diff --git a/js/src/tests/ecma_6/Reflect/setPrototypeOf.js b/js/src/tests/ecma_6/Reflect/setPrototypeOf.js index 95fa133e73..ed7857a028 100644 --- a/js/src/tests/ecma_6/Reflect/setPrototypeOf.js +++ b/js/src/tests/ecma_6/Reflect/setPrototypeOf.js @@ -22,7 +22,7 @@ for (proto of [undefined, false, 0, 1.6, "that", Symbol.iterator]) { assertThrowsInstanceOf(() => Reflect.setPrototypeOf(obj, proto), TypeError); } -// Return false if the target is inextensible. +// Return false if the target isn't extensible. proto = {}; obj = Object.preventExtensions(Object.create(proto)); assertEq(Reflect.setPrototypeOf(obj, {}), false); @@ -46,14 +46,10 @@ assertEq(Reflect.setPrototypeOf(proto, obj), false); // cycle check quietly exits on encountering the proxy.) obj = {}; var proxy = new Proxy(Object.create(obj), {}); -if (Reflect.setPrototypeOf(obj, proxy) !== false) { - throw new Error("Congratulations on implementing ES6 [[SetPrototype]]! " + - "Update this test for 1 karma point!"); - // ...by deleting this if-block and uncommenting the three assertions below. -} -// assertEq(Reflect.setPrototypeOf(obj, proxy), true); -// assertEq(Reflect.getPrototypeOf(obj), proxy); -// assertEq(Reflect.getPrototypeOf(proxy), obj); + +assertEq(Reflect.setPrototypeOf(obj, proxy), true); +assertEq(Reflect.getPrototypeOf(obj), proxy); +assertEq(Reflect.getPrototypeOf(proxy), obj); // If a proxy handler returns a false-y value, return false. var hits = 0; @@ -67,14 +63,9 @@ proxy = new Proxy(obj, { return 0; } }); -if (Reflect.setPrototypeOf(proxy, proto) !== true) { - throw new Error("Congratulations on implementing the setPrototypeOf trap for proxies! " + - "Please update this test."); - // ...by deleting this if-block and uncommenting the two assertions below. - // As of this writing, the setPrototypeOf hook is never called; see bug 888969. -} -// assertEq(Reflect.setPrototypeOf(proxy, proto), false); -// assertEq(hits, 1); + +assertEq(Reflect.setPrototypeOf(proxy, proto), false); +assertEq(hits, 1); // For more Reflect.setPrototypeOf tests, see target.js. diff --git a/js/src/tests/js1_8_5/reflect-parse/classes.js b/js/src/tests/js1_8_5/reflect-parse/classes.js index d479f56fc8..2ddd37d7f9 100644 --- a/js/src/tests/js1_8_5/reflect-parse/classes.js +++ b/js/src/tests/js1_8_5/reflect-parse/classes.js @@ -4,8 +4,19 @@ function testClasses() { function methodFun(id, kind, generator, args, body = []) { assertEq(generator && kind === "method", generator); assertEq(typeof id === 'string' || id === null, true); - let idN = typeof id === 'string' ? ident(id) : null; - let methodName = kind !== "method" ? null : idN; + let methodName; + switch (kind) { + case "method": + methodName = typeof id === 'string' ? ident(id) : null; + break; + case "get": + case "set": + methodName = ident(`${kind} ${typeof id === 'string' ? id : ""}`); + break; + default: + methodName = null; + break; + } return generator ? genFunExpr("es6", methodName, args.map(ident), blockStmt(body)) : funExpr(methodName, args.map(ident), blockStmt(body)); diff --git a/js/src/tests/js1_8_5/reflect-parse/methodDefn.js b/js/src/tests/js1_8_5/reflect-parse/methodDefn.js index fb3986179e..cad9b44435 100644 --- a/js/src/tests/js1_8_5/reflect-parse/methodDefn.js +++ b/js/src/tests/js1_8_5/reflect-parse/methodDefn.js @@ -19,11 +19,11 @@ assertError("({ a() false })", SyntaxError); assertExpr("({ get x() { return 42 } })", objExpr([ { key: ident("x"), - value: funExpr(null, [], blockStmt([returnStmt(lit(42))])), + value: funExpr(ident("get x"), [], blockStmt([returnStmt(lit(42))])), kind: "get" } ])); assertExpr("({ set x(v) { return 42 } })", objExpr([ { key: ident("x"), - value: funExpr(null, [ident("v")], blockStmt([returnStmt(lit(42))])), + value: funExpr(ident("set x"), [ident("v")], blockStmt([returnStmt(lit(42))])), kind: "set" } ])); // Bug 1073809 - Getter/setter syntax with generators diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index f8f97f32f0..5101d4e271 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -282,7 +282,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared // Detach this buffer from its original memory. (This necessarily makes // views of this buffer unusable for modifying that original memory.) - static MOZ_WARN_UNUSED_RESULT bool + static MOZ_MUST_USE bool detach(JSContext* cx, Handle buffer, BufferContents newContents); private: diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 0a57ae07a3..1203592fa3 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -122,10 +122,12 @@ macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \ macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \ macro(get, get, "get") \ + macro(getPrefix, getPrefix, "get ") \ macro(getInternals, getInternals, "getInternals") \ macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \ macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \ macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \ + macro(getPrototypeOf, getPrototypeOf, "getPrototypeOf") \ macro(global, global, "global") \ macro(Handle, Handle, "Handle") \ macro(has, has, "has") \ @@ -236,6 +238,8 @@ macro(sensitivity, sensitivity, "sensitivity") \ macro(separator, separator, "separator") \ macro(set, set, "set") \ + macro(setPrefix, setPrefix, "set ") \ + macro(setPrototypeOf, setPrototypeOf, "setPrototypeOf") \ macro(shape, shape, "shape") \ macro(size, size, "size") \ macro(source, source, "source") \ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 965b0b3697..cbc07fa70e 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -7716,7 +7716,7 @@ DebuggerObject_getName(JSContext* cx, unsigned argc, Value* vp) return true; } - JSString* name = obj->as().atom(); + JSString* name = obj->as().name(); if (!name) { args.rval().setUndefined(); return true; @@ -8065,7 +8065,7 @@ DebuggerObject_getPromiseDependentPromises(JSContext* cx, unsigned argc, Value* { THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseDependentPromises", args, dbg, refobj); - AutoValueVector values(cx); + Rooted> values(cx, GCVector()); { JSAutoCompartment ac(cx, promise); if (!promise->dependentPromises(cx, values)) diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 6a461e3cf9..f7aaa6a5c8 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -767,10 +767,10 @@ GlobalObject::getSelfHostedFunction(JSContext* cx, Handle global, return false; if (exists) { RootedFunction fun(cx, &funVal.toObject().as()); - if (fun->atom() == name) + if (fun->name() == name) return true; - if (fun->atom() == selfHostedName) { + if (fun->name() == selfHostedName) { // This function was initially cloned because it was called by // other self-hosted code, so the clone kept its self-hosted name, // instead of getting the name it's intended to have in content diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 576ed3e5a3..3b7ee831c3 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1543,11 +1543,11 @@ class ReservedRooted : public ReservedRootedBase } explicit ReservedRooted(Rooted* root) : savedRoot(root) { - *root = js::GCPolicy::initial(); + *root = JS::GCPolicy::initial(); } ~ReservedRooted() { - *savedRoot = js::GCPolicy::initial(); + *savedRoot = JS::GCPolicy::initial(); } void set(const T& p) const { *savedRoot = p; } @@ -4257,7 +4257,7 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject scopeChain, parent = parent->enclosingScope(); /* ES5 10.5 (NB: with subsequent errata). */ - RootedPropertyName name(cx, fun->atom()->asPropertyName()); + RootedPropertyName name(cx, fun->name()->asPropertyName()); RootedShape shape(cx); RootedObject pobj(cx); @@ -4969,8 +4969,8 @@ js::ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame) if (fun->isDerivedClassConstructor()) { const char* name = "anonymous"; JSAutoByteString str; - if (fun->atom()) { - if (!AtomToPrintableString(cx, fun->atom(), &str)) + if (fun->name()) { + if (!AtomToPrintableString(cx, fun->name(), &str)) return false; name = str.ptr(); } diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index a3946de93c..0e5e0fbb2a 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -14,6 +14,7 @@ #include "jsobj.h" #include "jsscript.h" +#include "asmjs/WasmModule.h" #include "gc/Heap.h" #include "jit/BaselineJIT.h" #include "jit/Ion.h" @@ -395,6 +396,43 @@ AddClassInfo(Granularity granularity, CompartmentStats& cStats, const char* clas } } +template +static void +CollectScriptSourceStats(StatsClosure* closure, ScriptSource* ss) +{ + RuntimeStats* rtStats = closure->rtStats; + + SourceSet::AddPtr entry = closure->seenSources.lookupForAdd(ss); + if (entry) + return; + + bool ok = closure->seenSources.add(entry, ss); + (void)ok; // Not much to be done on failure. + + JS::ScriptSourceInfo info; // This zeroes all the sizes. + ss->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &info); + MOZ_ASSERT(info.compressed == 0 || info.uncompressed == 0); + + rtStats->runtime.scriptSourceInfo.add(info); + + if (granularity == FineGrained) { + const char* filename = ss->filename(); + if (!filename) + filename = ""; + + JS::RuntimeSizes::ScriptSourcesHashMap::AddPtr p = + rtStats->runtime.allScriptSources->lookupForAdd(filename); + if (!p) { + bool ok = rtStats->runtime.allScriptSources->add(p, filename, info); + // Ignore failure -- we just won't record the script source as notable. + (void)ok; + } else { + p->value().add(info); + } + } +} + + // The various kinds of hashing are expensive, and the results are unused when // doing coarse-grained measurements. Skipping them more than doubles the // profile speed for complex pages such as gmail.com. @@ -425,6 +463,11 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin if (opv->getISupports_(obj, &iface) && iface) cStats.objectsPrivate += opv->sizeOfIncludingThis(iface); } + + if (obj->is()) { + if (ScriptSource* ss = obj->as().module().maybeScriptSource()) + CollectScriptSourceStats(closure, ss); + } break; } @@ -437,36 +480,7 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin jit::AddSizeOfBaselineData(script, rtStats->mallocSizeOf_, &cStats.baselineData, &cStats.baselineStubsFallback); cStats.ionData += jit::SizeOfIonData(script, rtStats->mallocSizeOf_); - - ScriptSource* ss = script->scriptSource(); - SourceSet::AddPtr entry = closure->seenSources.lookupForAdd(ss); - if (!entry) { - bool ok = closure->seenSources.add(entry, ss); - (void)ok; // Not much to be done on failure. - - JS::ScriptSourceInfo info; // This zeroes all the sizes. - ss->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &info); - MOZ_ASSERT(info.compressed == 0 || info.uncompressed == 0); - - rtStats->runtime.scriptSourceInfo.add(info); - - if (granularity == FineGrained) { - const char* filename = ss->filename(); - if (!filename) - filename = ""; - - JS::RuntimeSizes::ScriptSourcesHashMap::AddPtr p = - rtStats->runtime.allScriptSources->lookupForAdd(filename); - if (!p) { - bool ok = rtStats->runtime.allScriptSources->add(p, filename, info); - // Ignore failure -- we just won't record the script source as notable. - (void)ok; - } else { - p->value().add(info); - } - } - } - + CollectScriptSourceStats(closure, script->scriptSource()); break; } diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index a08dbe6ebe..2bec5aa49f 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -92,6 +92,12 @@ ObjectElements::MakeElementsCopyOnWrite(ExclusiveContext* cx, NativeObject* obj) ObjectElements* header = obj->getElementsHeader(); + // As soon as we have (or may soon have) multiple objects referencing a + // single header, it isn't clear which object the "I'm already in the + // whole-cell store buffer" bit is describing, so just disable that + // optimization. + header->clearInWholeCellBuffer(); + // Note: this method doesn't update type information to indicate that the // elements might be copy on write. Handling this is left to the caller. MOZ_ASSERT(!header->isCopyOnWrite()); diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 79c755a331..941a7b6309 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -180,7 +180,15 @@ class ObjectElements // For TypedArrays only: this TypedArray's storage is mapping shared // memory. This is a static property of the TypedArray, set when it // is created and never changed. - SHARED_MEMORY = 0x8 + SHARED_MEMORY = 0x8, + + // Set if the object has already been added to the whole-cell store + // buffer, and therefore adding individual elements into the slots store + // buffer would be pointless. This is never set for the empty or shared + // elements headers, nor if the elements are copy on write; in such + // situations it isn't clear *which* object that references this + // elements header has already been put in the whole-cell store buffer. + IN_WHOLE_CELL_BUFFER = 0x10, }; private: @@ -237,6 +245,19 @@ class ObjectElements MOZ_ASSERT(isCopyOnWrite()); flags &= ~COPY_ON_WRITE; } + bool isInWholeCellBuffer() const { + return flags & IN_WHOLE_CELL_BUFFER; + } + void setInWholeCellBuffer() { + MOZ_ASSERT(!isSharedMemory()); + MOZ_ASSERT(!isCopyOnWrite()); + flags |= IN_WHOLE_CELL_BUFFER; + } + void clearInWholeCellBuffer() { + MOZ_ASSERT(!isSharedMemory()); + MOZ_ASSERT(!isCopyOnWrite()); + flags &= ~IN_WHOLE_CELL_BUFFER; + } public: MOZ_CONSTEXPR ObjectElements(uint32_t capacity, uint32_t length) @@ -459,6 +480,18 @@ class NativeObject : public JSObject elements_ = emptyObjectElementsShared; } + bool isInWholeCellBuffer() const { + return getElementsHeader()->isInWholeCellBuffer(); + } + void setInWholeCellBuffer() { + if (!hasEmptyElements() && !isSharedMemory() && !getElementsHeader()->isCopyOnWrite()) + getElementsHeader()->setInWholeCellBuffer(); + } + void clearInWholeCellBuffer() { + if (!hasEmptyElements() && !isSharedMemory() && !getElementsHeader()->isCopyOnWrite()) + getElementsHeader()->clearInWholeCellBuffer(); + } + protected: #ifdef DEBUG void checkShapeConsistency(); diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 583ceaf26f..6200fd4c52 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -1711,7 +1711,7 @@ ObjectGroupCompartment::clearTables() ObjectGroupCompartment::PlainObjectTableSweepPolicy::needsSweep(PlainObjectKey* key, PlainObjectEntry* entry) { - if (!(GCPolicy::needsSweep(key) || entry->needsSweep(key->nproperties))) + if (!(JS::GCPolicy::needsSweep(key) || entry->needsSweep(key->nproperties))) return false; js_free(key->properties); js_free(entry->types); diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 1fd8f3b792..9c5dd39f3d 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -557,7 +557,7 @@ class ObjectGroupCompartment struct PlainObjectTableSweepPolicy { static bool needsSweep(PlainObjectKey* key, PlainObjectEntry* entry); }; - using PlainObjectTable = js::GCHashMap; diff --git a/js/src/vm/SavedFrame.h b/js/src/vm/SavedFrame.h index 905e8f2f01..f071726d84 100644 --- a/js/src/vm/SavedFrame.h +++ b/js/src/vm/SavedFrame.h @@ -136,9 +136,9 @@ class SavedFrame : public NativeObject { struct Lookup; struct HashPolicy; - typedef GCHashSet, - HashPolicy, - SystemAllocPolicy> Set; + typedef JS::GCHashSet, + HashPolicy, + SystemAllocPolicy> Set; class AutoLookupVector; diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index eadc5f3124..19ae97f5b7 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -683,7 +683,7 @@ DeclEnvObject::createTemplateObject(JSContext* cx, HandleFunction fun, NewObject return nullptr; // Assign a fixed slot to a property with the same name as the lambda. - Rooted id(cx, AtomToId(fun->atom())); + Rooted id(cx, AtomToId(fun->name())); const Class* clasp = obj->getClass(); unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY; @@ -1381,7 +1381,7 @@ const Class RuntimeLexicalErrorObject::class_ = { static inline JSAtom* CallObjectLambdaName(JSFunction& fun) { - return fun.isNamedLambda() ? fun.atom() : nullptr; + return fun.isNamedLambda() ? fun.name() : nullptr; } ScopeIter::ScopeIter(JSContext* cx, const ScopeIter& si @@ -2729,7 +2729,7 @@ DebugScopes::onPopCall(AbstractFramePtr frame, JSContext* cx) * aliasing. This unnecessarily includes aliased variables * but it simplifies later indexing logic. */ - AutoValueVector vec(cx); + Rooted> vec(cx, GCVector(cx)); if (!frame.copyRawFrameSlots(&vec) || vec.length() == 0) return; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index a4afa839a5..40bcb7df59 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2231,7 +2231,7 @@ WarnOnceAboutFlagsArgument(JSContext* cx, unsigned argc, Value* vp) // Additionally, a set of C++-implemented helper functions is defined on the // self-hosting global. static const JSFunctionSpec intrinsic_functions[] = { - JS_INLINABLE_FN("std_Array", ArrayConstructor, 1,0, Array), + JS_INLINABLE_FN("std_Array", array_construct, 1,0, Array), JS_FN("std_Array_join", array_join, 1,0), JS_INLINABLE_FN("std_Array_push", array_push, 1,0, ArrayPush), JS_INLINABLE_FN("std_Array_pop", array_pop, 0,0, ArrayPop), @@ -2559,6 +2559,8 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("RegExpEscapeMetaChars", intrinsic_RegExpEscapeMetaChars, 1,0), JS_FN("GetElemBaseForLambda", intrinsic_GetElemBaseForLambda, 1,0), JS_FN("GetStringDataProperty", intrinsic_GetStringDataProperty, 2,0), + JS_INLINABLE_FN("GetFirstDollarIndex", GetFirstDollarIndex, 1,0, + GetFirstDollarIndex), JS_FN("FlatStringMatch", FlatStringMatch, 2,0), JS_FN("FlatStringSearch", FlatStringSearch, 2,0), @@ -2900,7 +2902,7 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject) RootedObject clone(cx); if (selfHostedObject->is()) { RootedFunction selfHostedFunction(cx, &selfHostedObject->as()); - bool hasName = selfHostedFunction->atom() != nullptr; + bool hasName = selfHostedFunction->name() != nullptr; // Arrow functions use the first extended slot for their lexical |this| value. MOZ_ASSERT(!selfHostedFunction->isArrow()); @@ -2916,7 +2918,7 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject) // self-hosting compartment has to be stored on the clone. if (clone && hasName) { clone->as().setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, - StringValue(selfHostedFunction->atom())); + StringValue(selfHostedFunction->name())); } } else if (selfHostedObject->is()) { RegExpObject& reobj = selfHostedObject->as(); @@ -2998,9 +3000,9 @@ JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName s if (!selfHostedFun) return false; - if (!selfHostedFun->hasGuessedAtom() && selfHostedFun->atom() != selfHostedName) { + if (!selfHostedFun->hasGuessedAtom() && selfHostedFun->name() != selfHostedName) { MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean()); - funName = selfHostedFun->atom(); + funName = selfHostedFun->name(); } fun.set(NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY, diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 123f454a61..92e0b9f54a 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -98,6 +98,14 @@ Shape::new_(ExclusiveContext* cx, Handle other, uint32_t nfixed) return shape; } +inline void +Shape::updateBaseShapeAfterMovingGC() +{ + BaseShape* base = base_.unbarrieredGet(); + if (IsForwarded(base)) + base_.unsafeSet(Forwarded(base)); +} + template /* static */ inline bool EmptyShape::ensureInitialCustomShape(ExclusiveContext* cx, Handle obj) diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 5403833a48..be919c5c91 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1335,8 +1335,6 @@ BaseShape::traceChildren(JSTracer* trc) void BaseShape::traceChildrenSkipShapeTable(JSTracer* trc) { - assertConsistency(); - if (trc->isMarkingTracer()) compartment()->mark(); @@ -1346,6 +1344,8 @@ BaseShape::traceChildrenSkipShapeTable(JSTracer* trc) JSObject* global = compartment()->unsafeUnbarrieredMaybeGlobal(); if (global) TraceManuallyBarrieredEdge(trc, &global, "global"); + + assertConsistency(); } void @@ -1589,6 +1589,7 @@ JSCompartment::fixupInitialShapeTable() shape = Forwarded(shape); e.mutableFront().shape.set(shape); } + shape->updateBaseShapeAfterMovingGC(); // If the prototype has moved we have to rekey the entry. InitialShapeEntry entry = e.front(); diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 7f94d78c72..28b99d334b 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -525,7 +525,7 @@ struct StackBaseShape : public DefaultHasher> static inline bool match(ReadBarriered key, const Lookup& lookup); }; -using BaseShapeSet = js::GCHashSet, +using BaseShapeSet = JS::GCHashSet, StackBaseShape, SystemAllocPolicy>; @@ -963,6 +963,7 @@ class Shape : public gc::TenuredCell void fixupAfterMovingGC(); void fixupGetterSetterForBarrier(JSTracer* trc); + void updateBaseShapeAfterMovingGC(); /* For JIT usage */ static inline size_t offsetOfBase() { return offsetof(Shape, base_); } @@ -1124,7 +1125,7 @@ struct InitialShapeEntry } }; -using InitialShapeSet = js::GCHashSet; +using InitialShapeSet = JS::GCHashSet; struct StackShape { diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 8ad581211e..534142f9f7 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -757,7 +757,7 @@ AbstractFramePtr::initArgsObj(ArgumentsObject& argsobj) const } inline bool -AbstractFramePtr::copyRawFrameSlots(AutoValueVector* vec) const +AbstractFramePtr::copyRawFrameSlots(MutableHandle> vec) const { if (isInterpreterFrame()) return asInterpreterFrame()->copyRawFrameSlots(vec); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 007c6adfa6..f310279c83 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -81,12 +81,12 @@ InterpreterFrame::isNonGlobalEvalFrame() const } bool -InterpreterFrame::copyRawFrameSlots(AutoValueVector* vec) +InterpreterFrame::copyRawFrameSlots(MutableHandle> vec) { - if (!vec->resize(numFormalArgs() + script()->nfixed())) + if (!vec.resize(numFormalArgs() + script()->nfixed())) return false; - PodCopy(vec->begin(), argv(), numFormalArgs()); - PodCopy(vec->begin() + numFormalArgs(), slots(), script()->nfixed()); + PodCopy(vec.begin(), argv(), numFormalArgs()); + PodCopy(vec.begin() + numFormalArgs(), slots(), script()->nfixed()); return true; } diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 8cdf22a916..b9d357939f 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -233,7 +233,7 @@ class AbstractFramePtr inline void initArgsObj(ArgumentsObject& argsobj) const; inline bool createSingleton() const; - inline bool copyRawFrameSlots(AutoValueVector* vec) const; + inline bool copyRawFrameSlots(MutableHandle> vec) const; inline Value& unaliasedLocal(uint32_t i); inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING); @@ -500,7 +500,7 @@ class InterpreterFrame inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING); template inline void unaliasedForEachActual(Op op); - bool copyRawFrameSlots(AutoValueVector* v); + bool copyRawFrameSlots(MutableHandle> v); unsigned numFormalArgs() const { MOZ_ASSERT(hasArgs()); return callee().nargs(); } unsigned numActualArgs() const { MOZ_ASSERT(hasArgs()); return nactual_; } diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index ce9c9dfa72..082f69da59 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -874,17 +874,6 @@ StaticStrings::isStatic(JSAtom* atom) : isStatic(atom->twoByteChars(nogc), atom->length()); } -AutoStableStringChars::~AutoStableStringChars() -{ - if (ownsChars_) { - MOZ_ASSERT(state_ == Latin1 || state_ == TwoByte); - if (state_ == Latin1) - js_free(const_cast(latin1Chars_)); - else - js_free(const_cast(twoByteChars_)); - } -} - bool AutoStableStringChars::init(JSContext* cx, JSString* s) { @@ -944,10 +933,33 @@ bool AutoStableStringChars::baseIsInline(HandleLinearString linearString) return base->isInline(); } +template +T* +AutoStableStringChars::allocOwnChars(JSContext* cx, size_t count) +{ + static_assert( + InlineCapacity >= sizeof(JS::Latin1Char) * (JSFatInlineString::MAX_LENGTH_LATIN1 + 1) && + InlineCapacity >= sizeof(char16_t) * (JSFatInlineString::MAX_LENGTH_TWO_BYTE + 1), + "InlineCapacity too small to hold fat inline strings"); + + static_assert((JSString::MAX_LENGTH & mozilla::tl::MulOverflowMask::value) == 0, + "Size calculation can overflow"); + MOZ_ASSERT(count <= JSString::MAX_LENGTH); + size_t size = sizeof(T) * count; + + ownChars_.emplace(cx); + if (!ownChars_->resize(size)) { + ownChars_.reset(); + return nullptr; + } + + return reinterpret_cast(ownChars_->begin()); +} + bool AutoStableStringChars::copyAndInflateLatin1Chars(JSContext* cx, HandleLinearString linearString) { - char16_t* chars = cx->pod_malloc(linearString->length() + 1); + char16_t* chars = allocOwnChars(cx, linearString->length() + 1); if (!chars) return false; @@ -956,7 +968,6 @@ AutoStableStringChars::copyAndInflateLatin1Chars(JSContext* cx, HandleLinearStri chars[linearString->length()] = 0; state_ = TwoByte; - ownsChars_ = true; twoByteChars_ = chars; s_ = linearString; return true; @@ -966,7 +977,7 @@ bool AutoStableStringChars::copyLatin1Chars(JSContext* cx, HandleLinearString linearString) { size_t length = linearString->length(); - JS::Latin1Char* chars = cx->pod_malloc(length + 1); + JS::Latin1Char* chars = allocOwnChars(cx, length + 1); if (!chars) return false; @@ -974,7 +985,6 @@ AutoStableStringChars::copyLatin1Chars(JSContext* cx, HandleLinearString linearS chars[length] = 0; state_ = Latin1; - ownsChars_ = true; latin1Chars_ = chars; s_ = linearString; return true; @@ -984,7 +994,7 @@ bool AutoStableStringChars::copyTwoByteChars(JSContext* cx, HandleLinearString linearString) { size_t length = linearString->length(); - char16_t* chars = cx->pod_malloc(length + 1); + char16_t* chars = allocOwnChars(cx, length + 1); if (!chars) return false; @@ -992,7 +1002,6 @@ AutoStableStringChars::copyTwoByteChars(JSContext* cx, HandleLinearString linear chars[length] = 0; state_ = TwoByte; - ownsChars_ = true; twoByteChars_ = chars; s_ = linearString; return true; diff --git a/js/src/vm/String.h b/js/src/vm/String.h index 733708a878..15a2292239 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -1140,7 +1140,7 @@ NameToId(PropertyName* name) return NON_INTEGER_ATOM_TO_JSID(name); } -using PropertyNameVector = js::GCVector; +using PropertyNameVector = JS::GCVector; template void diff --git a/js/src/vm/StringBuffer.cpp b/js/src/vm/StringBuffer.cpp index 31e7e15b4e..fc4bfe3a9c 100644 --- a/js/src/vm/StringBuffer.cpp +++ b/js/src/vm/StringBuffer.cpp @@ -21,7 +21,7 @@ ExtractWellSized(ExclusiveContext* cx, Buffer& cb) size_t capacity = cb.capacity(); size_t length = cb.length(); - CharT* buf = cb.extractRawBuffer(); + CharT* buf = cb.extractOrCopyRawBuffer(); if (!buf) return nullptr; diff --git a/js/src/vm/StringBuffer.h b/js/src/vm/StringBuffer.h index 1e42f1d8b3..ff086834f0 100644 --- a/js/src/vm/StringBuffer.h +++ b/js/src/vm/StringBuffer.h @@ -72,7 +72,7 @@ class StringBuffer return cb.ref(); } - bool inflateChars(); + MOZ_MUST_USE bool inflateChars(); public: explicit StringBuffer(ExclusiveContext* cx) @@ -85,25 +85,25 @@ class StringBuffer cb.construct(cx); } - inline bool reserve(size_t len) { + MOZ_MUST_USE bool reserve(size_t len) { if (len > reserved_) reserved_ = len; return isLatin1() ? latin1Chars().reserve(len) : twoByteChars().reserve(len); } - inline bool resize(size_t len) { + MOZ_MUST_USE bool resize(size_t len) { return isLatin1() ? latin1Chars().resize(len) : twoByteChars().resize(len); } - inline bool empty() const { + bool empty() const { return isLatin1() ? latin1Chars().empty() : twoByteChars().empty(); } - inline size_t length() const { + size_t length() const { return isLatin1() ? latin1Chars().length() : twoByteChars().length(); } - inline char16_t getChar(size_t idx) const { + char16_t getChar(size_t idx) const { return isLatin1() ? latin1Chars()[idx] : twoByteChars()[idx]; } - inline bool ensureTwoByteChars() { + MOZ_MUST_USE bool ensureTwoByteChars() { if (isLatin1() && !inflateChars()) return false; @@ -113,7 +113,7 @@ class StringBuffer return true; } - inline bool append(const char16_t c) { + MOZ_MUST_USE bool append(const char16_t c) { if (isLatin1()) { if (c <= JSString::MAX_LATIN1_CHAR) return latin1Chars().append(Latin1Char(c)); @@ -122,43 +122,44 @@ class StringBuffer } return twoByteChars().append(c); } - inline bool append(Latin1Char c) { + MOZ_MUST_USE bool append(Latin1Char c) { return isLatin1() ? latin1Chars().append(c) : twoByteChars().append(c); } - inline bool append(char c) { + MOZ_MUST_USE bool append(char c) { return append(Latin1Char(c)); } - inline bool append(const char16_t* begin, const char16_t* end); - inline bool append(const char16_t* chars, size_t len) { + inline MOZ_MUST_USE bool append(const char16_t* begin, const char16_t* end); + + MOZ_MUST_USE bool append(const char16_t* chars, size_t len) { return append(chars, chars + len); } - inline bool append(const Latin1Char* begin, const Latin1Char* end) { + MOZ_MUST_USE bool append(const Latin1Char* begin, const Latin1Char* end) { return isLatin1() ? latin1Chars().append(begin, end) : twoByteChars().append(begin, end); } - inline bool append(const Latin1Char* chars, size_t len) { + MOZ_MUST_USE bool append(const Latin1Char* chars, size_t len) { return append(chars, chars + len); } - inline bool append(const JS::ConstCharPtr chars, size_t len) { + MOZ_MUST_USE bool append(const JS::ConstCharPtr chars, size_t len) { return append(chars.get(), chars.get() + len); } - inline bool appendN(Latin1Char c, size_t n) { + MOZ_MUST_USE bool appendN(Latin1Char c, size_t n) { return isLatin1() ? latin1Chars().appendN(c, n) : twoByteChars().appendN(c, n); } - inline bool append(JSString* str); - inline bool append(JSLinearString* str); - inline bool appendSubstring(JSString* base, size_t off, size_t len); - inline bool appendSubstring(JSLinearString* base, size_t off, size_t len); + inline MOZ_MUST_USE bool append(JSString* str); + inline MOZ_MUST_USE bool append(JSLinearString* str); + inline MOZ_MUST_USE bool appendSubstring(JSString* base, size_t off, size_t len); + inline MOZ_MUST_USE bool appendSubstring(JSLinearString* base, size_t off, size_t len); - inline bool append(const char* chars, size_t len) { + MOZ_MUST_USE bool append(const char* chars, size_t len) { return append(reinterpret_cast(chars), len); } template - bool append(const char (&array)[ArrayLength]) { + MOZ_MUST_USE bool append(const char (&array)[ArrayLength]) { return append(array, ArrayLength - 1); /* No trailing '\0'. */ } diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 5633d21759..5f7658d063 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -743,7 +743,7 @@ bool SCOutput::extractBuffer(uint64_t** datap, size_t* sizep) { *sizep = buf.length() * sizeof(uint64_t); - return (*datap = buf.extractRawBuffer()) != nullptr; + return (*datap = buf.extractOrCopyRawBuffer()) != nullptr; } } /* namespace js */ @@ -995,7 +995,7 @@ JSStructuredCloneWriter::traverseObject(HandleObject obj) bool JSStructuredCloneWriter::traverseMap(HandleObject obj) { - AutoValueVector newEntries(context()); + Rooted> newEntries(context(), GCVector(context())); { // If there is no wrapper, the compartment munging is a no-op. RootedObject unwrapped(context(), CheckedUnwrap(obj)); @@ -1004,7 +1004,7 @@ JSStructuredCloneWriter::traverseMap(HandleObject obj) if (!MapObject::getKeysAndValuesInterleaved(context(), unwrapped, &newEntries)) return false; } - if (!context()->compartment()->wrap(context(), newEntries)) + if (!context()->compartment()->wrap(context(), &newEntries)) return false; for (size_t i = newEntries.length(); i > 0; --i) { @@ -1025,7 +1025,7 @@ JSStructuredCloneWriter::traverseMap(HandleObject obj) bool JSStructuredCloneWriter::traverseSet(HandleObject obj) { - AutoValueVector keys(context()); + Rooted> keys(context(), GCVector(context())); { // If there is no wrapper, the compartment munging is a no-op. RootedObject unwrapped(context(), CheckedUnwrap(obj)); @@ -1034,7 +1034,7 @@ JSStructuredCloneWriter::traverseSet(HandleObject obj) if (!SetObject::keys(context(), unwrapped, &keys)) return false; } - if (!context()->compartment()->wrap(context(), keys)) + if (!context()->compartment()->wrap(context(), &keys)) return false; for (size_t i = keys.length(); i > 0; --i) { diff --git a/js/src/vm/Symbol.cpp b/js/src/vm/Symbol.cpp index dfe6278d14..064e8473c3 100644 --- a/js/src/vm/Symbol.cpp +++ b/js/src/vm/Symbol.cpp @@ -37,7 +37,7 @@ Symbol::newInternal(ExclusiveContext* cx, JS::SymbolCode code, JSAtom* descripti Symbol* Symbol::new_(ExclusiveContext* cx, JS::SymbolCode code, JSString* description) { - RootedAtom atom(cx); + JSAtom* atom = nullptr; if (description) { atom = AtomizeString(cx, description); if (!atom) diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 19216ecb78..7995ee1d7c 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -340,36 +340,36 @@ TypeSet::mightBeMIRType(jit::MIRType type) const if (unknown()) return true; - if (type == jit::MIRType_Object) + if (type == jit::MIRType::Object) return unknownObject() || baseObjectCount() != 0; switch (type) { - case jit::MIRType_Undefined: + case jit::MIRType::Undefined: return baseFlags() & TYPE_FLAG_UNDEFINED; - case jit::MIRType_Null: + case jit::MIRType::Null: return baseFlags() & TYPE_FLAG_NULL; - case jit::MIRType_Boolean: + case jit::MIRType::Boolean: return baseFlags() & TYPE_FLAG_BOOLEAN; - case jit::MIRType_Int32: + case jit::MIRType::Int32: return baseFlags() & TYPE_FLAG_INT32; - case jit::MIRType_Float32: // Fall through, there's no JSVAL for Float32. - case jit::MIRType_Double: + case jit::MIRType::Float32: // Fall through, there's no JSVAL for Float32. + case jit::MIRType::Double: return baseFlags() & TYPE_FLAG_DOUBLE; - case jit::MIRType_String: + case jit::MIRType::String: return baseFlags() & TYPE_FLAG_STRING; - case jit::MIRType_Symbol: + case jit::MIRType::Symbol: return baseFlags() & TYPE_FLAG_SYMBOL; - case jit::MIRType_MagicOptimizedArguments: + case jit::MIRType::MagicOptimizedArguments: return baseFlags() & TYPE_FLAG_LAZYARGS; - case jit::MIRType_MagicHole: - case jit::MIRType_MagicIsConstructing: + case jit::MIRType::MagicHole: + case jit::MIRType::MagicIsConstructing: // These magic constants do not escape to script and are not observed // in the type sets. // // The reason we can return false here is subtle: if Ion is asking the // type set if it has seen such a magic constant, then the MIR in - // question is the most generic type, MIRType_Value. A magic constant - // could only be emitted by a MIR of MIRType_Value if that MIR is a + // question is the most generic type, MIRType::Value. A magic constant + // could only be emitted by a MIR of MIRType::Value if that MIR is a // phi, and we check that different magic constants do not flow to the // same join point in GuessPhiType. return false; @@ -1581,25 +1581,25 @@ GetMIRTypeFromTypeFlags(TypeFlags flags) { switch (flags) { case TYPE_FLAG_UNDEFINED: - return jit::MIRType_Undefined; + return jit::MIRType::Undefined; case TYPE_FLAG_NULL: - return jit::MIRType_Null; + return jit::MIRType::Null; case TYPE_FLAG_BOOLEAN: - return jit::MIRType_Boolean; + return jit::MIRType::Boolean; case TYPE_FLAG_INT32: - return jit::MIRType_Int32; + return jit::MIRType::Int32; case (TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE): - return jit::MIRType_Double; + return jit::MIRType::Double; case TYPE_FLAG_STRING: - return jit::MIRType_String; + return jit::MIRType::String; case TYPE_FLAG_SYMBOL: - return jit::MIRType_Symbol; + return jit::MIRType::Symbol; case TYPE_FLAG_LAZYARGS: - return jit::MIRType_MagicOptimizedArguments; + return jit::MIRType::MagicOptimizedArguments; case TYPE_FLAG_ANYOBJECT: - return jit::MIRType_Object; + return jit::MIRType::Object; default: - return jit::MIRType_Value; + return jit::MIRType::Value; } } @@ -1610,7 +1610,7 @@ TemporaryTypeSet::getKnownMIRType() jit::MIRType type; if (baseObjectCount()) - type = flags ? jit::MIRType_Value : jit::MIRType_Object; + type = flags ? jit::MIRType::Value : jit::MIRType::Object; else type = GetMIRTypeFromTypeFlags(flags); @@ -1622,7 +1622,7 @@ TemporaryTypeSet::getKnownMIRType() * added to the set. */ DebugOnly empty = flags == 0 && baseObjectCount() == 0; - MOZ_ASSERT_IF(empty, type == jit::MIRType_Value); + MOZ_ASSERT_IF(empty, type == jit::MIRType::Value); return type; } @@ -1633,17 +1633,17 @@ HeapTypeSetKey::knownMIRType(CompilerConstraintList* constraints) TypeSet* types = maybeTypes(); if (!types || types->unknown()) - return jit::MIRType_Value; + return jit::MIRType::Value; TypeFlags flags = types->baseFlags() & ~TYPE_FLAG_ANYOBJECT; jit::MIRType type; if (types->unknownObject() || types->getObjectCount()) - type = flags ? jit::MIRType_Value : jit::MIRType_Object; + type = flags ? jit::MIRType::Value : jit::MIRType::Object; else type = GetMIRTypeFromTypeFlags(flags); - if (type != jit::MIRType_Value) + if (type != jit::MIRType::Value) freeze(constraints); /* @@ -1653,7 +1653,7 @@ HeapTypeSetKey::knownMIRType(CompilerConstraintList* constraints) * that the exact tag is unknown, as it will stay unknown as more types are * added to the set. */ - MOZ_ASSERT_IF(types->empty(), type == jit::MIRType_Value); + MOZ_ASSERT_IF(types->empty(), type == jit::MIRType::Value); return type; } @@ -2225,7 +2225,7 @@ TemporaryTypeSet::convertDoubleElements(CompilerConstraintList* constraints) // Only bother with converting known packed arrays whose possible // element types are int or double. Other arrays require type tests // when elements are accessed regardless of the conversion. - if (property.knownMIRType(constraints) == jit::MIRType_Double && + if (property.knownMIRType(constraints) == jit::MIRType::Double && !key->hasFlags(constraints, OBJECT_FLAG_NON_PACKED)) { maybeConvert = true; @@ -4517,7 +4517,7 @@ TypeScript::printTypes(JSContext* cx, HandleScript script) const fprintf(stderr, " %p %s:%" PRIuSIZE " ", script.get(), script->filename(), script->lineno()); if (script->functionNonDelazifying()) { - if (js::PropertyName* name = script->functionNonDelazifying()->name()) + if (JSAtom* name = script->functionNonDelazifying()->name()) name->dumpCharsNoNewline(); } diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index e1000d96fa..640cdb98c1 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -665,7 +665,7 @@ class TemporaryTypeSet : public TypeSet TemporaryTypeSet(LifoAlloc* alloc, jit::MIRType type) : TemporaryTypeSet(alloc, PrimitiveType(ValueTypeFromMIRType(type))) { - MOZ_ASSERT(type != jit::MIRType_Value); + MOZ_ASSERT(type != jit::MIRType::Value); } /* @@ -680,7 +680,7 @@ class TemporaryTypeSet : public TypeSet /* Get any type tag which all values in this set must have. */ jit::MIRType getKnownMIRType(); - bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; } + bool isMagicArguments() { return getKnownMIRType() == jit::MIRType::MagicOptimizedArguments; } /* Whether this value may be an object. */ bool maybeObject() { return unknownObject() || baseObjectCount() > 0; } diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 336afda3b5..470178982f 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -41,6 +41,7 @@ #include "jsatominlines.h" +#include "gc/StoreBuffer-inl.h" #include "vm/ArrayBufferObject-inl.h" #include "vm/NativeObject-inl.h" #include "vm/Shape-inl.h" diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index a885cfb6b6..ad6af5c10c 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -9,6 +9,7 @@ #include "vm/UnboxedObject.h" +#include "gc/StoreBuffer-inl.h" #include "vm/ArrayObject-inl.h" #include "vm/NativeObject-inl.h" diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 90d7bff987..374869aedc 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -186,7 +186,7 @@ UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group) Label notObject; masm.branchTestObject(Assembler::NotEqual, valueOperand, - types->mightBeMIRType(MIRType_Null) ? ¬Object : &failureStoreObject); + types->mightBeMIRType(MIRType::Null) ? ¬Object : &failureStoreObject); Register payloadReg = masm.extractObject(valueOperand, scratch1); @@ -196,7 +196,7 @@ UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group) } masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT, - TypedOrValueRegister(MIRType_Object, + TypedOrValueRegister(MIRType::Object, AnyRegister(payloadReg)), nullptr); if (notObject.used()) { @@ -953,15 +953,16 @@ const Class UnboxedPlainObject::class_ = { template DenseElementResult -AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen, AutoValueVector* values) +AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen, + MutableHandle> values) { for (size_t i = 0; i < initlen; i++) - values->infallibleAppend(obj->getElementSpecific(i)); + values.infallibleAppend(obj->getElementSpecific(i)); return DenseElementResult::Success; } DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements, - UnboxedArrayObject*, uint32_t, AutoValueVector*); + UnboxedArrayObject*, uint32_t, MutableHandle>); /* static */ bool UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj, @@ -970,7 +971,7 @@ UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj size_t length = obj->as().length(); size_t initlen = obj->as().initializedLength(); - AutoValueVector values(cx); + Rooted> values(cx, GCVector(cx)); if (!values.reserve(initlen)) return false; @@ -1848,13 +1849,13 @@ SetLayoutTraceList(ExclusiveContext* cx, UnboxedLayout* layout) } static inline Value -NextValue(const AutoValueVector& values, size_t* valueCursor) +NextValue(Handle> values, size_t* valueCursor) { return values[(*valueCursor)++]; } static bool -GetValuesFromPreliminaryArrayObject(ArrayObject* obj, AutoValueVector& values) +GetValuesFromPreliminaryArrayObject(ArrayObject* obj, MutableHandle> values) { if (!values.append(Int32Value(obj->length()))) return false; @@ -1869,7 +1870,7 @@ GetValuesFromPreliminaryArrayObject(ArrayObject* obj, AutoValueVector& values) void UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, - const AutoValueVector& values, size_t* valueCursor) + Handle> values, size_t* valueCursor) { MOZ_ASSERT(CapacityArray[1] == 0); setCapacityIndex(1); @@ -1893,7 +1894,7 @@ UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, } static bool -GetValuesFromPreliminaryPlainObject(PlainObject* obj, AutoValueVector& values) +GetValuesFromPreliminaryPlainObject(PlainObject* obj, MutableHandle> values) { for (size_t i = 0; i < obj->slotSpan(); i++) { if (!values.append(obj->getSlot(i))) @@ -1904,7 +1905,7 @@ GetValuesFromPreliminaryPlainObject(PlainObject* obj, AutoValueVector& values) void UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, - const AutoValueVector& values, size_t* valueCursor) + Handle> values, size_t* valueCursor) { initExpando(); memset(data(), 0, layout().size()); @@ -2040,7 +2041,7 @@ js::TryConvertToUnboxedLayout(ExclusiveContext* cx, Shape* templateShape, // Accumulate a list of all the values in each preliminary object, and // update their shapes. - AutoValueVector values(cx); + Rooted> values(cx, GCVector(cx)); for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { JSObject* obj = objects->get(i); if (!obj) @@ -2048,9 +2049,9 @@ js::TryConvertToUnboxedLayout(ExclusiveContext* cx, Shape* templateShape, bool ok; if (isArray) - ok = GetValuesFromPreliminaryArrayObject(&obj->as(), values); + ok = GetValuesFromPreliminaryArrayObject(&obj->as(), &values); else - ok = GetValuesFromPreliminaryPlainObject(&obj->as(), values); + ok = GetValuesFromPreliminaryPlainObject(&obj->as(), &values); if (!ok) { cx->recoverFromOutOfMemory(); diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 6f86c09125..370aa7f592 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -303,7 +303,7 @@ class UnboxedPlainObject : public JSObject NewObjectKind newKind, IdValuePair* properties); void fillAfterConvert(ExclusiveContext* cx, - const AutoValueVector& values, size_t* valueCursor); + Handle> values, size_t* valueCursor); static void trace(JSTracer* trc, JSObject* object); @@ -426,7 +426,7 @@ class UnboxedArrayObject : public JSObject bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group); void fillAfterConvert(ExclusiveContext* cx, - const AutoValueVector& values, size_t* valueCursor); + Handle> values, size_t* valueCursor); static void trace(JSTracer* trc, JSObject* object); static void objectMoved(JSObject* obj, const JSObject* old); diff --git a/js/xpconnect/idl/moz.build b/js/xpconnect/idl/moz.build index 981b490495..32d59f44b7 100644 --- a/js/xpconnect/idl/moz.build +++ b/js/xpconnect/idl/moz.build @@ -7,7 +7,6 @@ XPIDL_SOURCES += [ 'mozIJSSubScriptLoader.idl', 'nsIAddonInterposition.idl', - 'nsIRemoteTagService.idl', 'nsIScriptError.idl', 'nsIXPConnect.idl', 'nsIXPCScriptable.idl', diff --git a/js/xpconnect/idl/nsIRemoteTagService.idl b/js/xpconnect/idl/nsIRemoteTagService.idl deleted file mode 100644 index 4602dfdb99..0000000000 --- a/js/xpconnect/idl/nsIRemoteTagService.idl +++ /dev/null @@ -1,13 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * 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 "nsISupports.idl" - -[scriptable,uuid(59dbe3d0-6084-11e4-9803-0800200c9a66)] -interface nsIRemoteTagService : nsISupports -{ - ACString getRemoteObjectTag(in jsval target); -}; diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp index f6f559b07d..88f05280f1 100644 --- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp @@ -726,7 +726,7 @@ private: NS_IMPL_ISUPPORTS(ScriptPrecompiler, nsIIncrementalStreamLoaderObserver); -class NotifyPrecompilationCompleteRunnable : public nsRunnable +class NotifyPrecompilationCompleteRunnable : public Runnable { public: NS_DECL_NSIRUNNABLE diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 8290049f39..6ae067587a 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -2620,7 +2620,7 @@ nsXPCComponents_Utils::ForceShrinkingGC() return NS_OK; } -class PreciseGCRunnable : public nsRunnable +class PreciseGCRunnable : public Runnable { public: PreciseGCRunnable(ScheduledGCCallback* aCallback, bool aShrinking) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index abfb194bb3..755b77b30d 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -144,7 +144,7 @@ XPCJSRuntime::CustomContextCallback(JSContext* cx, unsigned operation) return true; } -class AsyncFreeSnowWhite : public nsRunnable +class AsyncFreeSnowWhite : public Runnable { public: NS_IMETHOD Run() @@ -3603,12 +3603,7 @@ XPCJSRuntime::BeforeProcessTask(bool aMightBlock) // "while (condition) thread.processNextEvent(true)", in case the // condition is triggered here by a Promise "then" callback. - class DummyRunnable : public nsRunnable { - public: - NS_IMETHOD Run() { return NS_OK; } - }; - - NS_DispatchToMainThread(new DummyRunnable()); + NS_DispatchToMainThread(new Runnable()); } } diff --git a/js/xpconnect/src/XPCMaps.h b/js/xpconnect/src/XPCMaps.h index 23f8803362..4aa0f9498e 100644 --- a/js/xpconnect/src/XPCMaps.h +++ b/js/xpconnect/src/XPCMaps.h @@ -578,7 +578,7 @@ private: class JSObject2JSObjectMap { - using Map = js::GCHashMap, + using Map = JS::GCHashMap, JS::Heap, js::MovableCellHasher>, js::SystemAllocPolicy>; diff --git a/js/xpconnect/tests/unit/test_classesByID_instanceof.js b/js/xpconnect/tests/unit/test_classesByID_instanceof.js index 71fc8311c1..b0acf8016b 100644 --- a/js/xpconnect/tests/unit/test_classesByID_instanceof.js +++ b/js/xpconnect/tests/unit/test_classesByID_instanceof.js @@ -27,10 +27,53 @@ function testInheritedCrossGlobal(SimpleURIClassByID) do_check_eq(inheritedCross instanceof SimpleURIClassByID, true); } +function testCrossGlobalArbitraryGetPrototype(SimpleURIClassByID) +{ + var simpleURI = + Components.classes["@mozilla.org/network/simple-uri;1"].createInstance(); + + var sb = new Components.utils.Sandbox(this, { wantComponents: true }); + var firstLevel = Object.create(simpleURI); + + var obj = { shouldThrow: false }; + var secondLevel = + new sb.Proxy(Object.create(firstLevel), + { + getPrototypeOf: new sb.Function("obj", `return function(t) { + if (obj.shouldThrow) + throw 42; + return Reflect.getPrototypeOf(t); + };`)(obj) + }); + var thirdLevel = Object.create(secondLevel); + + obj.shouldThrow = true; + + var threw = false; + var err; + try + { + void (thirdLevel instanceof SimpleURIClassByID); + } + catch (e) + { + threw = true; + err = e; + } + + do_check_eq(threw, true); + do_check_eq(err, 42); + + obj.shouldThrow = false; + + do_check_eq(thirdLevel instanceof SimpleURIClassByID, true); +} + function run_test() { var SimpleURIClassByID = Components.classesByID["{e0da1d70-2f7b-11d3-8cd0-0060b0fc14a3}"]; testActual(SimpleURIClassByID); testInherited(SimpleURIClassByID); testInheritedCrossGlobal(SimpleURIClassByID); + testCrossGlobalArbitraryGetPrototype(SimpleURIClassByID); } diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp index e32dd389f7..27c010d341 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp @@ -94,4 +94,12 @@ WaiveXrayWrapper::getPrototype(JSContext* cx, HandleObject wrapper, MutableHandl (!protop || WrapperFactory::WaiveXrayAndWrap(cx, protop)); } +bool +WaiveXrayWrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper, bool* isOrdinary, + MutableHandleObject protop) const +{ + return CrossCompartmentWrapper::getPrototypeIfOrdinary(cx, wrapper, isOrdinary, protop) && + (!protop || WrapperFactory::WaiveXrayAndWrap(cx, protop)); +} + } // namespace xpc diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.h b/js/xpconnect/wrappers/WaiveXrayWrapper.h index 880c7e9005..be27156aa3 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.h +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h @@ -22,6 +22,9 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper { JS::MutableHandle desc) const override; virtual bool getPrototype(JSContext* cx, JS::Handle wrapper, JS::MutableHandle protop) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, JS::Handle wrapper, + bool* isOrdinary, + JS::MutableHandle protop) const override; virtual bool get(JSContext* cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const override; virtual bool call(JSContext* cx, JS::Handle wrapper, diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index f632a336c8..5a83602f60 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -2355,6 +2355,22 @@ XrayWrapper::setPrototype(JSContext* cx, JS::HandleObject wrapper, return result.succeed(); } +template +bool +XrayWrapper::getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject wrapper, + bool* isOrdinary, + JS::MutableHandleObject protop) const +{ + // We want to keep the Xray's prototype distinct from that of content, but + // only if there's been a set. This different-prototype-over-time behavior + // means that the [[GetPrototypeOf]] trap *can't* be ECMAScript's ordinary + // [[GetPrototypeOf]]. This also covers cross-origin Window behavior that + // per + // must be non-ordinary. + *isOrdinary = false; + return true; +} + template bool XrayWrapper::setImmutablePrototype(JSContext* cx, JS::HandleObject wrapper, diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 2024bcb95c..c18370dadc 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -437,6 +437,8 @@ class XrayWrapper : public Base { JS::MutableHandleObject protop) const override; virtual bool setPrototype(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject proto, JS::ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject wrapper, bool* isOrdinary, + JS::MutableHandleObject protop) const override; virtual bool setImmutablePrototype(JSContext* cx, JS::HandleObject wrapper, bool* succeeded) const override; virtual bool preventExtensions(JSContext* cx, JS::Handle wrapper, diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 3154598e34..63acecc84e 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -432,7 +432,7 @@ public: nsCOMPtr mTop; }; -class nsDocumentShownDispatcher : public nsRunnable +class nsDocumentShownDispatcher : public Runnable { public: explicit nsDocumentShownDispatcher(nsCOMPtr aDocument) diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 14d94c687b..4885ec0919 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2963,7 +2963,7 @@ void StrokeLineWithSnapping(const nsPoint& aP1, const nsPoint& aP2, } // namespace layout } // namespace mozilla -class nsSetAttrRunnable : public nsRunnable +class nsSetAttrRunnable : public mozilla::Runnable { public: nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName, @@ -2978,7 +2978,7 @@ public: nsAutoString mValue; }; -class nsUnsetAttrRunnable : public nsRunnable +class nsUnsetAttrRunnable : public mozilla::Runnable { public: nsUnsetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName); diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 2f1bb16d8e..4013147e8d 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -111,7 +111,7 @@ public: namespace { -class CharSetChangingRunnable : public nsRunnable +class CharSetChangingRunnable : public Runnable { public: CharSetChangingRunnable(nsPresContext* aPresContext, @@ -2404,7 +2404,7 @@ NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData) return true; } -class DelayedFireDOMPaintEvent : public nsRunnable { +class DelayedFireDOMPaintEvent : public Runnable { public: DelayedFireDOMPaintEvent(nsPresContext* aPresContext, nsInvalidateRequestList* aList, diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index deac75a994..447ae51290 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -1517,7 +1517,7 @@ protected: */ void CancelApplyPluginGeometryTimer(); - class RunWillPaintObservers : public nsRunnable { + class RunWillPaintObservers : public mozilla::Runnable { public: explicit RunWillPaintObservers(nsRootPresContext* aPresContext) : mPresContext(aPresContext) {} void Revoke() { mPresContext = nullptr; } diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 1f3f3da05d..5758bd994d 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -526,7 +526,7 @@ public: RefPtr mPresShell; }; -class nsBeforeFirstPaintDispatcher : public nsRunnable +class nsBeforeFirstPaintDispatcher : public Runnable { public: explicit nsBeforeFirstPaintDispatcher(nsIDocument* aDocument) @@ -1596,7 +1596,7 @@ PresShell::EndObservingDocument() char* nsPresShell_ReflowStackPointerTop; #endif -class XBLConstructorRunner : public nsRunnable +class XBLConstructorRunner : public Runnable { public: explicit XBLConstructorRunner(nsIDocument* aDocument) @@ -6433,7 +6433,7 @@ nsIPresShell::SetCapturingContent(nsIContent* aContent, uint8_t aFlags) } } -class AsyncCheckPointerCaptureStateCaller : public nsRunnable +class AsyncCheckPointerCaptureStateCaller : public Runnable { public: explicit AsyncCheckPointerCaptureStateCaller(int32_t aPointerId) diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp index 125fd97595..ec5023d7b9 100644 --- a/layout/forms/nsComboboxControlFrame.cpp +++ b/layout/forms/nsComboboxControlFrame.cpp @@ -378,7 +378,7 @@ nsComboboxControlFrame::ShowList(bool aShowList) } class nsResizeDropdownAtFinalPosition final - : public nsIReflowCallback, public nsRunnable + : public nsIReflowCallback, public Runnable { public: explicit nsResizeDropdownAtFinalPosition(nsComboboxControlFrame* aFrame) @@ -517,7 +517,7 @@ nsComboboxControlFrame::GetCSSTransformTranslation() return translation; } -class nsAsyncRollup : public nsRunnable +class nsAsyncRollup : public Runnable { public: explicit nsAsyncRollup(nsComboboxControlFrame* aFrame) : mFrame(aFrame) {} @@ -532,7 +532,7 @@ public: nsWeakFrame mFrame; }; -class nsAsyncResize : public nsRunnable +class nsAsyncResize : public Runnable { public: explicit nsAsyncResize(nsComboboxControlFrame* aFrame) : mFrame(aFrame) {} diff --git a/layout/forms/nsComboboxControlFrame.h b/layout/forms/nsComboboxControlFrame.h index 87c30ffb5e..ed32010c8c 100644 --- a/layout/forms/nsComboboxControlFrame.h +++ b/layout/forms/nsComboboxControlFrame.h @@ -233,7 +233,7 @@ protected: nscoord GetIntrinsicISize(nsRenderingContext* aRenderingContext, nsLayoutUtils::IntrinsicISizeType aType); - class RedisplayTextEvent : public nsRunnable { + class RedisplayTextEvent : public mozilla::Runnable { public: NS_DECL_NSIRUNNABLE explicit RedisplayTextEvent(nsComboboxControlFrame *c) : mControlFrame(c) {} diff --git a/layout/forms/nsFileControlFrame.h b/layout/forms/nsFileControlFrame.h index 864f33756c..290a20251e 100644 --- a/layout/forms/nsFileControlFrame.h +++ b/layout/forms/nsFileControlFrame.h @@ -89,7 +89,7 @@ protected: class SyncDisabledStateEvent; friend class SyncDisabledStateEvent; - class SyncDisabledStateEvent : public nsRunnable + class SyncDisabledStateEvent : public mozilla::Runnable { public: explicit SyncDisabledStateEvent(nsFileControlFrame* aFrame) diff --git a/layout/forms/nsNumberControlFrame.cpp b/layout/forms/nsNumberControlFrame.cpp index cc34f814a0..51c97e6525 100644 --- a/layout/forms/nsNumberControlFrame.cpp +++ b/layout/forms/nsNumberControlFrame.cpp @@ -300,7 +300,7 @@ nsNumberControlFrame::GetTextFieldFrame() return do_QueryFrame(GetAnonTextControl()->GetPrimaryFrame()); } -class FocusTextField : public nsRunnable +class FocusTextField : public Runnable { public: FocusTextField(nsIContent* aNumber, nsIContent* aTextField) diff --git a/layout/forms/nsNumberControlFrame.h b/layout/forms/nsNumberControlFrame.h index 1cec12dcd0..22b148ef61 100644 --- a/layout/forms/nsNumberControlFrame.h +++ b/layout/forms/nsNumberControlFrame.h @@ -203,7 +203,7 @@ private: class SyncDisabledStateEvent; friend class SyncDisabledStateEvent; - class SyncDisabledStateEvent : public nsRunnable + class SyncDisabledStateEvent : public mozilla::Runnable { public: explicit SyncDisabledStateEvent(nsNumberControlFrame* aFrame) diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index 47795a76b0..e4a8675329 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -205,7 +205,7 @@ protected: NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(TextControlInitializer, EditorInitializer) - class EditorInitializer : public nsRunnable { + class EditorInitializer : public mozilla::Runnable { public: explicit EditorInitializer(nsTextControlFrame* aFrame) : mFrame(aFrame) {} @@ -224,7 +224,7 @@ protected: class ScrollOnFocusEvent; friend class ScrollOnFocusEvent; - class ScrollOnFocusEvent : public nsRunnable { + class ScrollOnFocusEvent : public mozilla::Runnable { public: explicit ScrollOnFocusEvent(nsTextControlFrame* aFrame) : mFrame(aFrame) {} diff --git a/layout/generic/Selection.h b/layout/generic/Selection.h index ea23e5b9a7..3a20c1bb2c 100644 --- a/layout/generic/Selection.h +++ b/layout/generic/Selection.h @@ -255,7 +255,7 @@ private: class ScrollSelectionIntoViewEvent; friend class ScrollSelectionIntoViewEvent; - class ScrollSelectionIntoViewEvent : public nsRunnable { + class ScrollSelectionIntoViewEvent : public Runnable { public: NS_DECL_NSIRUNNABLE ScrollSelectionIntoViewEvent(Selection* aSelection, diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 40c988a3f4..c664407ea9 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -39,9 +39,6 @@ class Layer; namespace layout { class ScrollbarActivity; } // namespace layout -} // namespace mozilla - -namespace mozilla { class ScrollFrameHelper : public nsIReflowCallback { public: @@ -137,7 +134,7 @@ public: RefPtr mDriver; }; - class AsyncScrollPortEvent : public nsRunnable { + class AsyncScrollPortEvent : public Runnable { public: NS_DECL_NSIRUNNABLE explicit AsyncScrollPortEvent(ScrollFrameHelper *helper) : mHelper(helper) {} @@ -146,7 +143,7 @@ public: ScrollFrameHelper *mHelper; }; - class ScrolledAreaEvent : public nsRunnable { + class ScrolledAreaEvent : public Runnable { public: NS_DECL_NSIRUNNABLE explicit ScrolledAreaEvent(ScrollFrameHelper *helper) : mHelper(helper) {} diff --git a/layout/generic/nsPluginFrame.h b/layout/generic/nsPluginFrame.h index d640e450de..660f37280a 100644 --- a/layout/generic/nsPluginFrame.h +++ b/layout/generic/nsPluginFrame.h @@ -289,7 +289,7 @@ private: return region; } - class PluginEventNotifier : public nsRunnable { + class PluginEventNotifier : public mozilla::Runnable { public: explicit PluginEventNotifier(const nsString &aEventType) : mEventType(aEventType) {} diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 40e9cbbae0..e26ec302b7 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -77,7 +77,7 @@ NS_QUERYFRAME_HEAD(nsSubDocumentFrame) NS_QUERYFRAME_ENTRY(nsSubDocumentFrame) NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame) -class AsyncFrameInit : public nsRunnable +class AsyncFrameInit : public Runnable { public: explicit AsyncFrameInit(nsIFrame* aFrame) : mFrame(aFrame) {} @@ -927,7 +927,7 @@ NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame) -class nsHideViewer : public nsRunnable { +class nsHideViewer : public Runnable { public: nsHideViewer(nsIContent* aFrameElement, nsFrameLoader* aFrameLoader, diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index e0db7d6304..f987d29601 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -266,7 +266,7 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder, return result.forget(); } -class DispatchResizeToControls : public nsRunnable +class DispatchResizeToControls : public Runnable { public: explicit DispatchResizeToControls(nsIContent* aContent) @@ -348,7 +348,7 @@ nsVideoFrame::Reflow(nsPresContext* aPresContext, aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); if (child->GetSize() != size) { - RefPtr event = new DispatchResizeToControls(child->GetContent()); + RefPtr event = new DispatchResizeToControls(child->GetContent()); nsContentUtils::AddScriptRunner(event); } } else if (child->GetContent() == mCaptionDiv) { diff --git a/layout/printing/nsPagePrintTimer.cpp b/layout/printing/nsPagePrintTimer.cpp index 8e206e743a..a5cd7632b3 100644 --- a/layout/printing/nsPagePrintTimer.cpp +++ b/layout/printing/nsPagePrintTimer.cpp @@ -10,7 +10,7 @@ #include "nsIServiceManager.h" #include "nsPrintEngine.h" -NS_IMPL_ISUPPORTS_INHERITED(nsPagePrintTimer, nsRunnable, nsITimerCallback) +NS_IMPL_ISUPPORTS_INHERITED(nsPagePrintTimer, mozilla::Runnable, nsITimerCallback) nsPagePrintTimer::~nsPagePrintTimer() { diff --git a/layout/printing/nsPagePrintTimer.h b/layout/printing/nsPagePrintTimer.h index 6cd4332b01..a722fabf77 100644 --- a/layout/printing/nsPagePrintTimer.h +++ b/layout/printing/nsPagePrintTimer.h @@ -18,7 +18,7 @@ class nsPrintEngine; //--------------------------------------------------- //-- Page Timer Class //--------------------------------------------------- -class nsPagePrintTimer final : public nsRunnable, +class nsPagePrintTimer final : public mozilla::Runnable, public nsITimerCallback { public: diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp index dabb2150be..2f17125d10 100644 --- a/layout/printing/nsPrintEngine.cpp +++ b/layout/printing/nsPrintEngine.cpp @@ -3503,7 +3503,7 @@ nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const char16_t //--------------------------------------------------------------- //-- PLEvent Notification //--------------------------------------------------------------- -class nsPrintCompletionEvent : public nsRunnable { +class nsPrintCompletionEvent : public Runnable { public: explicit nsPrintCompletionEvent(nsIDocumentViewerPrint *docViewerPrint) : mDocViewerPrint(docViewerPrint) { diff --git a/layout/style/ErrorReporter.cpp b/layout/style/ErrorReporter.cpp index e3de99a234..e32bd4d2f7 100644 --- a/layout/style/ErrorReporter.cpp +++ b/layout/style/ErrorReporter.cpp @@ -26,7 +26,7 @@ using namespace mozilla; namespace { -class ShortTermURISpecCache : public nsRunnable { +class ShortTermURISpecCache : public Runnable { public: ShortTermURISpecCache() : mPending(false) {} diff --git a/layout/svg/AutoReferenceLimiter.h b/layout/svg/AutoReferenceLimiter.h index cff70aabba..5f822ba135 100644 --- a/layout/svg/AutoReferenceLimiter.h +++ b/layout/svg/AutoReferenceLimiter.h @@ -96,7 +96,7 @@ public: * within the specified limits), else returns false on failure (there is a * reference loop/the reference chain has exceeded the specified limits). */ - MOZ_WARN_UNUSED_RESULT bool Reference() { + MOZ_MUST_USE bool Reference() { // If we fail this assertion then either a consumer failed to break a // reference loop/chain, or else they called Reference() more than once MOZ_ASSERT(*mRefCounter >= 0); diff --git a/layout/svg/SVGTextFrame.h b/layout/svg/SVGTextFrame.h index bc29685309..3fbe030ad6 100644 --- a/layout/svg/SVGTextFrame.h +++ b/layout/svg/SVGTextFrame.h @@ -127,7 +127,7 @@ private: * A runnable to mark glyph positions as needing to be recomputed * and to invalid the bounds of the SVGTextFrame frame. */ -class GlyphMetricsUpdater : public nsRunnable { +class GlyphMetricsUpdater : public Runnable { public: NS_DECL_NSIRUNNABLE explicit GlyphMetricsUpdater(SVGTextFrame* aFrame) : mFrame(aFrame) { } diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 9e023a03b3..bc060efcf7 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -4797,7 +4797,7 @@ GetPaintStyleInfo(const nsIFrame* aFrame, } } -class nsDelayedCalcBCBorders : public nsRunnable { +class nsDelayedCalcBCBorders : public Runnable { public: explicit nsDelayedCalcBCBorders(nsIFrame* aFrame) : mFrame(aFrame) {} diff --git a/layout/xul/nsImageBoxFrame.cpp b/layout/xul/nsImageBoxFrame.cpp index 6349eb5ae7..83939ecabb 100644 --- a/layout/xul/nsImageBoxFrame.cpp +++ b/layout/xul/nsImageBoxFrame.cpp @@ -60,7 +60,7 @@ using namespace mozilla::gfx; using namespace mozilla::image; using namespace mozilla::layers; -class nsImageBoxFrameEvent : public nsRunnable +class nsImageBoxFrameEvent : public Runnable { public: nsImageBoxFrameEvent(nsIContent *content, EventMessage message) diff --git a/layout/xul/nsListBoxBodyFrame.h b/layout/xul/nsListBoxBodyFrame.h index 37fe5a563a..57bbf0257c 100644 --- a/layout/xul/nsListBoxBodyFrame.h +++ b/layout/xul/nsListBoxBodyFrame.h @@ -149,7 +149,7 @@ protected: class nsPositionChangedEvent; friend class nsPositionChangedEvent; - class nsPositionChangedEvent : public nsRunnable + class nsPositionChangedEvent : public mozilla::Runnable { public: nsPositionChangedEvent(nsListBoxBodyFrame* aFrame, diff --git a/layout/xul/nsMenuBarFrame.cpp b/layout/xul/nsMenuBarFrame.cpp index 03ce9fbe35..cc5813251a 100644 --- a/layout/xul/nsMenuBarFrame.cpp +++ b/layout/xul/nsMenuBarFrame.cpp @@ -269,7 +269,7 @@ nsMenuBarFrame::CurrentMenuIsBeingDestroyed() mCurrentMenu = nullptr; } -class nsMenuBarSwitchMenu : public nsRunnable +class nsMenuBarSwitchMenu : public Runnable { public: nsMenuBarSwitchMenu(nsIContent* aMenuBar, diff --git a/layout/xul/nsMenuFrame.cpp b/layout/xul/nsMenuFrame.cpp index 0624a35e95..7da16ac2ce 100644 --- a/layout/xul/nsMenuFrame.cpp +++ b/layout/xul/nsMenuFrame.cpp @@ -62,7 +62,7 @@ static int32_t gEatMouseMove = false; const int32_t kBlinkDelay = 67; // milliseconds // this class is used for dispatching menu activation events asynchronously. -class nsMenuActivateEvent : public nsRunnable +class nsMenuActivateEvent : public Runnable { public: nsMenuActivateEvent(nsIContent *aMenu, @@ -107,7 +107,7 @@ private: bool mIsActivate; }; -class nsMenuAttributeChangedEvent : public nsRunnable +class nsMenuAttributeChangedEvent : public Runnable { public: nsMenuAttributeChangedEvent(nsIFrame* aFrame, nsIAtom* aAttr) diff --git a/layout/xul/nsMenuPopupFrame.cpp b/layout/xul/nsMenuPopupFrame.cpp index 9217d64316..62966648ec 100644 --- a/layout/xul/nsMenuPopupFrame.cpp +++ b/layout/xul/nsMenuPopupFrame.cpp @@ -387,7 +387,7 @@ void nsXULPopupShownEvent::CancelListener() mPopup->RemoveSystemEventListener(NS_LITERAL_STRING("transitionend"), this, false); } -NS_IMPL_ISUPPORTS_INHERITED(nsXULPopupShownEvent, nsRunnable, nsIDOMEventListener); +NS_IMPL_ISUPPORTS_INHERITED(nsXULPopupShownEvent, Runnable, nsIDOMEventListener); void nsMenuPopupFrame::SetInitialChildList(ChildListID aListID, diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h index 159804fed5..64c1c725fe 100644 --- a/layout/xul/nsMenuPopupFrame.h +++ b/layout/xul/nsMenuPopupFrame.h @@ -130,7 +130,8 @@ class nsView; class nsMenuPopupFrame; // this class is used for dispatching popupshown events asynchronously. -class nsXULPopupShownEvent : public nsRunnable, public nsIDOMEventListener +class nsXULPopupShownEvent : public mozilla::Runnable, + public nsIDOMEventListener { public: nsXULPopupShownEvent(nsIContent *aPopup, nsPresContext* aPresContext) diff --git a/layout/xul/nsProgressMeterFrame.cpp b/layout/xul/nsProgressMeterFrame.cpp index d2ce346d30..a798d57178 100644 --- a/layout/xul/nsProgressMeterFrame.cpp +++ b/layout/xul/nsProgressMeterFrame.cpp @@ -22,7 +22,7 @@ #include "nsContentUtils.h" #include "mozilla/Attributes.h" -class nsReflowFrameRunnable : public nsRunnable +class nsReflowFrameRunnable : public mozilla::Runnable { public: nsReflowFrameRunnable(nsIFrame* aFrame, diff --git a/layout/xul/nsSliderFrame.cpp b/layout/xul/nsSliderFrame.cpp index 7d126b3eeb..4e451baf40 100644 --- a/layout/xul/nsSliderFrame.cpp +++ b/layout/xul/nsSliderFrame.cpp @@ -191,7 +191,7 @@ nsSliderFrame::GetIntegerAttribute(nsIContent* content, nsIAtom* atom, int32_t d return defaultValue; } -class nsValueChangedRunnable : public nsRunnable +class nsValueChangedRunnable : public Runnable { public: nsValueChangedRunnable(nsISliderListener* aListener, @@ -214,7 +214,7 @@ public: bool mUserChanged; }; -class nsDragStateChangedRunnable : public nsRunnable +class nsDragStateChangedRunnable : public Runnable { public: nsDragStateChangedRunnable(nsISliderListener* aListener, diff --git a/layout/xul/nsXULPopupManager.h b/layout/xul/nsXULPopupManager.h index 94c17fcb53..c16c70f573 100644 --- a/layout/xul/nsXULPopupManager.h +++ b/layout/xul/nsXULPopupManager.h @@ -183,7 +183,7 @@ public: }; // this class is used for dispatching popupshowing events asynchronously. -class nsXULPopupShowingEvent : public nsRunnable +class nsXULPopupShowingEvent : public mozilla::Runnable { public: nsXULPopupShowingEvent(nsIContent *aPopup, @@ -205,7 +205,7 @@ private: }; // this class is used for dispatching popuphiding events asynchronously. -class nsXULPopupHidingEvent : public nsRunnable +class nsXULPopupHidingEvent : public mozilla::Runnable { public: nsXULPopupHidingEvent(nsIContent *aPopup, @@ -237,7 +237,7 @@ private: }; // this class is used for dispatching menu command events asynchronously. -class nsXULMenuCommandEvent : public nsRunnable +class nsXULMenuCommandEvent : public mozilla::Runnable { public: nsXULMenuCommandEvent(nsIContent *aMenu, diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index fa34c6614f..739219dcd8 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -4842,7 +4842,7 @@ nsTreeBodyFrame::FireInvalidateEvent(int32_t aStartRowIdx, int32_t aEndRowIdx, } #endif -class nsOverflowChecker : public nsRunnable +class nsOverflowChecker : public Runnable { public: explicit nsOverflowChecker(nsTreeBodyFrame* aFrame) : mFrame(aFrame) {} diff --git a/layout/xul/tree/nsTreeBodyFrame.h b/layout/xul/tree/nsTreeBodyFrame.h index bf7a2fcba6..e85440198d 100644 --- a/layout/xul/tree/nsTreeBodyFrame.h +++ b/layout/xul/tree/nsTreeBodyFrame.h @@ -473,7 +473,7 @@ protected: static void ScrollCallback(nsITimer *aTimer, void *aClosure); - class ScrollEvent : public nsRunnable { + class ScrollEvent : public mozilla::Runnable { public: NS_DECL_NSIRUNNABLE explicit ScrollEvent(nsTreeBodyFrame *aInner) : mInner(aInner) {} diff --git a/media/mtransport/nr_socket_prsock.cpp b/media/mtransport/nr_socket_prsock.cpp index cc00fee424..20efd1e435 100644 --- a/media/mtransport/nr_socket_prsock.cpp +++ b/media/mtransport/nr_socket_prsock.cpp @@ -1622,7 +1622,7 @@ void NrUdpSocketIpc::recv_callback_s(RefPtr msg) { #if defined(MOZILLA_INTERNAL_API) // TCPSocket. -class NrTcpSocketIpc::TcpSocketReadyRunner: public nsRunnable +class NrTcpSocketIpc::TcpSocketReadyRunner: public Runnable { public: explicit TcpSocketReadyRunner(NrTcpSocketIpc *sck) diff --git a/media/mtransport/runnable_utils.h b/media/mtransport/runnable_utils.h index df0d42b8a9..0d7b1ce6f9 100644 --- a/media/mtransport/runnable_utils.h +++ b/media/mtransport/runnable_utils.h @@ -51,7 +51,7 @@ RunOnThreadInternal(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flag } template -class runnable_args_base : public nsRunnable { +class runnable_args_base : public Runnable { public: NS_IMETHOD Run() = 0; }; diff --git a/media/mtransport/test/TestSyncRunnable.cpp b/media/mtransport/test/TestSyncRunnable.cpp index d834812fc3..d488da8f5b 100644 --- a/media/mtransport/test/TestSyncRunnable.cpp +++ b/media/mtransport/test/TestSyncRunnable.cpp @@ -12,7 +12,7 @@ using namespace mozilla; nsIThread *gThread = nullptr; -class TestRunnable : public nsRunnable { +class TestRunnable : public Runnable { public: TestRunnable() : ran_(false) {} diff --git a/media/mtransport/test/runnable_utils_unittest.cpp b/media/mtransport/test/runnable_utils_unittest.cpp index 9def9b2a5b..28ca57aa14 100644 --- a/media/mtransport/test/runnable_utils_unittest.cpp +++ b/media/mtransport/test/runnable_utils_unittest.cpp @@ -87,13 +87,13 @@ class RunnableArgsTest : public MtransportTest { RunnableArgsTest() : MtransportTest(), ran_(0), cl_(&ran_){} void Test1Arg() { - nsRunnable * r = WrapRunnable(&cl_, &TargetClass::m1, 1); + Runnable * r = WrapRunnable(&cl_, &TargetClass::m1, 1); r->Run(); ASSERT_EQ(1, ran_); } void Test2Args() { - nsRunnable* r = WrapRunnable(&cl_, &TargetClass::m2, 1, 2); + Runnable* r = WrapRunnable(&cl_, &TargetClass::m2, 1, 2); r->Run(); ASSERT_EQ(2, ran_); } @@ -116,13 +116,13 @@ class DispatchTest : public MtransportTest { } void Test1Arg() { - nsRunnable* r = WrapRunnable(&cl_, &TargetClass::m1, 1); + Runnable* r = WrapRunnable(&cl_, &TargetClass::m1, 1); target_->Dispatch(r, NS_DISPATCH_SYNC); ASSERT_EQ(1, ran_); } void Test2Args() { - nsRunnable* r = WrapRunnable(&cl_, &TargetClass::m2, 1, 2); + Runnable* r = WrapRunnable(&cl_, &TargetClass::m2, 1, 2); target_->Dispatch(r, NS_DISPATCH_SYNC); ASSERT_EQ(2, ran_); } diff --git a/media/mtransport/test/sockettransportservice_unittest.cpp b/media/mtransport/test/sockettransportservice_unittest.cpp index c5e6a4a7b0..84caf62688 100644 --- a/media/mtransport/test/sockettransportservice_unittest.cpp +++ b/media/mtransport/test/sockettransportservice_unittest.cpp @@ -29,6 +29,8 @@ #include "gtest/gtest.h" #include "gtest_utils.h" +using namespace mozilla; + namespace { class SocketTransportServiceTest : public MtransportTest { public: @@ -74,7 +76,7 @@ class SocketTransportServiceTest : public MtransportTest { // Received an event. -class EventReceived : public nsRunnable { +class EventReceived : public Runnable { public: explicit EventReceived(SocketTransportServiceTest *test) : test_(test) {} @@ -89,7 +91,7 @@ public: // Register our listener on the socket -class RegisterEvent : public nsRunnable { +class RegisterEvent : public Runnable { public: explicit RegisterEvent(SocketTransportServiceTest *test) : test_(test) {} diff --git a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp index 32ac262f53..4ccd7fb1da 100644 --- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp +++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp @@ -1234,7 +1234,7 @@ WebrtcVideoConduit::SelectSendResolution(unsigned short width, new_frame->ShallowCopy(*frame); } RefPtr self(this); - RefPtr webrtc_runnable = + RefPtr webrtc_runnable = media::NewRunnableFrom([self, width, height, new_frame]() -> nsresult { UniquePtr local_frame(new_frame); // Simplify cleanup diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h index b81acebf7b..380ebd223e 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h @@ -76,7 +76,7 @@ class WebrtcGmpPCHandleSetter static std::string sCurrentHandle; }; -class GmpInitDoneRunnable : public nsRunnable +class GmpInitDoneRunnable : public Runnable { public: explicit GmpInitDoneRunnable(const std::string& aPCHandle) : diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp index d6375e10a4..e4444e7f79 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp @@ -71,7 +71,7 @@ ShutdownThread(nsCOMPtr& aThread) // should contains corresponding info such as image size and timestamps for // DrainOutput() implementation to construct data needed by encoded/decoded // callbacks. -class MediaCodecOutputDrain : public nsRunnable +class MediaCodecOutputDrain : public Runnable { public: void Start() { diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp index 7be8c31363..49aed35cd4 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp @@ -128,7 +128,7 @@ ShutdownThread(nsCOMPtr& aThread) // TODO: Bug 997110 - Revisit queue/drain logic. Current design assumes that // encoder only generate one output buffer per input frame and won't work // if encoder drops frames or generates multiple output per input. -class OMXOutputDrain : public nsRunnable +class OMXOutputDrain : public Runnable { public: void Start() { diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h index c1b10e893c..ba8a477a3a 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h @@ -275,7 +275,7 @@ class MediaPipeline : public sigslot::has_slots<> { bool IsRtp(const unsigned char *data, size_t len); }; -class ConduitDeleteEvent: public nsRunnable +class ConduitDeleteEvent: public Runnable { public: explicit ConduitDeleteEvent(already_AddRefed aConduit) : diff --git a/memory/mozalloc/mozalloc.h b/memory/mozalloc/mozalloc.h index b3b74d3c64..c9d8c4fefa 100644 --- a/memory/mozalloc/mozalloc.h +++ b/memory/mozalloc/mozalloc.h @@ -50,8 +50,8 @@ /* Workaround build problem with Sun Studio 12 */ #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# undef MOZ_WARN_UNUSED_RESULT -# define MOZ_WARN_UNUSED_RESULT +# undef MOZ_MUST_USE +# define MOZ_MUST_USE # undef MOZ_ALLOCATOR # define MOZ_ALLOCATOR #endif @@ -113,10 +113,10 @@ MOZALLOC_EXPORT char* moz_xstrndup(const char* str, size_t strsize) #if defined(HAVE_POSIX_MEMALIGN) -MOZALLOC_EXPORT MOZ_WARN_UNUSED_RESULT +MOZALLOC_EXPORT MOZ_MUST_USE int moz_xposix_memalign(void **ptr, size_t alignment, size_t size); -MOZALLOC_EXPORT MOZ_WARN_UNUSED_RESULT +MOZALLOC_EXPORT MOZ_MUST_USE int moz_posix_memalign(void **ptr, size_t alignment, size_t size); #endif /* if defined(HAVE_POSIX_MEMALIGN) */ diff --git a/mfbt/AlreadyAddRefed.h b/mfbt/AlreadyAddRefed.h index d02e8ae54f..0d7b0caed8 100644 --- a/mfbt/AlreadyAddRefed.h +++ b/mfbt/AlreadyAddRefed.h @@ -29,7 +29,7 @@ struct unused_t; * because of the sheer number of usages of already_AddRefed. */ template -struct MOZ_MUST_USE MOZ_NON_AUTOABLE already_AddRefed +struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed { /* * We want to allow returning nullptr from functions returning @@ -111,7 +111,7 @@ struct MOZ_MUST_USE MOZ_NON_AUTOABLE already_AddRefed aUnused << mutableAlreadyAddRefed->take(); } - MOZ_WARN_UNUSED_RESULT T* take() + MOZ_MUST_USE T* take() { T* rawPtr = mRawPtr; mRawPtr = nullptr; diff --git a/mfbt/Assertions.h b/mfbt/Assertions.h index 83caf96adc..f6dd45a335 100644 --- a/mfbt/Assertions.h +++ b/mfbt/Assertions.h @@ -547,14 +547,14 @@ struct AssertionConditionType #else # define MOZ_ALWAYS_TRUE(expr) \ do { \ - if ( ( expr ) ) { \ - /* Silence MOZ_WARN_UNUSED_RESULT. */ \ + if ( ( expr ) ) { \ + /* Silence MOZ_MUST_USE. */ \ } \ } while (0) # define MOZ_ALWAYS_FALSE(expr) \ do { \ - if ( ( expr ) ) { \ - /* Silence MOZ_WARN_UNUSED_RESULT. */ \ + if ( ( expr ) ) { \ + /* Silence MOZ_MUST_USE. */ \ } \ } while (0) #endif diff --git a/mfbt/Attributes.h b/mfbt/Attributes.h index d3a165b443..43a9f674bf 100644 --- a/mfbt/Attributes.h +++ b/mfbt/Attributes.h @@ -313,22 +313,22 @@ #endif /** - * MOZ_WARN_UNUSED_RESULT tells the compiler to emit a warning if a function's + * MOZ_MUST_USE tells the compiler to emit a warning if a function's * return value is not used by the caller. * - * Place this attribute at the very beginning of a function definition. For + * Place this attribute at the very beginning of a function declaration. For * example, write * - * MOZ_WARN_UNUSED_RESULT int foo(); + * MOZ_MUST_USE int foo(); * * or * - * MOZ_WARN_UNUSED_RESULT int foo() { return 42; } + * MOZ_MUST_USE int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +# define MOZ_MUST_USE __attribute__ ((warn_unused_result)) #else -# define MOZ_WARN_UNUSED_RESULT +# define MOZ_MUST_USE #endif /** @@ -508,9 +508,9 @@ * function. This is intended to be used with operator->() of our smart * pointer classes to ensure that the refcount of an object wrapped in a * smart pointer is not manipulated directly. - * MOZ_MUST_USE: Applies to type declarations. Makes it a compile time error to not - * use the return value of a function which has this type. This is intended to be - * used with types which it is an error to not use. + * MOZ_MUST_USE_TYPE: Applies to type declarations. Makes it a compile time + * error to not use the return value of a function which has this type. This + * is intended to be used with types which it is an error to not use. * MOZ_NEEDS_NO_VTABLE_TYPE: Applies to template class declarations. Makes it * a compile time error to instantiate this template with a type parameter which * has a VTable. @@ -526,7 +526,7 @@ * MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class * declarations where an instance of the template should be considered, for * static analysis purposes, to inherit any type annotations (such as - * MOZ_MUST_USE and MOZ_STACK_CLASS) from its template arguments. + * MOZ_MUST_USE_TYPE and MOZ_STACK_CLASS) from its template arguments. * MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time error to * use `auto` in place of this type in variable declarations. This is intended to * be used with types which are intended to be implicitly constructed into other @@ -552,7 +552,7 @@ # define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref"))) # define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref"))) # define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return"))) -# define MOZ_MUST_USE __attribute__((annotate("moz_must_use"))) +# define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type"))) # define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type"))) # define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) # define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) @@ -585,7 +585,7 @@ # define MOZ_NON_OWNING_REF /* nothing */ # define MOZ_UNSAFE_REF(reason) /* nothing */ # define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */ -# define MOZ_MUST_USE /* nothing */ +# define MOZ_MUST_USE_TYPE /* nothing */ # define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */ # define MOZ_NON_MEMMOVABLE /* nothing */ # define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */ diff --git a/mfbt/Endian.h b/mfbt/Endian.h index 8413ddbe68..e7674f4666 100644 --- a/mfbt/Endian.h +++ b/mfbt/Endian.h @@ -344,37 +344,37 @@ class Endian : private EndianUtils { protected: /** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* aPtr) + static MOZ_MUST_USE uint16_t readUint16(const void* aPtr) { return read(aPtr); } /** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* aPtr) + static MOZ_MUST_USE uint32_t readUint32(const void* aPtr) { return read(aPtr); } /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* aPtr) + static MOZ_MUST_USE uint64_t readUint64(const void* aPtr) { return read(aPtr); } /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* aPtr) + static MOZ_MUST_USE int16_t readInt16(const void* aPtr) { return read(aPtr); } /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* aPtr) + static MOZ_MUST_USE int32_t readInt32(const void* aPtr) { return read(aPtr); } /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* aPtr) + static MOZ_MUST_USE int64_t readInt64(const void* aPtr) { return read(aPtr); } @@ -423,7 +423,7 @@ protected: * format for transmission. */ template - MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T aValue) + MOZ_MUST_USE static T swapToLittleEndian(T aValue) { return maybeSwap(aValue); } @@ -453,7 +453,7 @@ protected: * Converts a value of type T to big-endian format. */ template - MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T aValue) + MOZ_MUST_USE static T swapToBigEndian(T aValue) { return maybeSwap(aValue); } @@ -485,7 +485,7 @@ protected: */ template - MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T aValue) + MOZ_MUST_USE static T swapToNetworkOrder(T aValue) { return swapToBigEndian(aValue); } @@ -508,7 +508,7 @@ protected: * Converts a value of type T from little-endian format. */ template - MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T aValue) + MOZ_MUST_USE static T swapFromLittleEndian(T aValue) { return maybeSwap(aValue); } @@ -538,7 +538,7 @@ protected: * Converts a value of type T from big-endian format. */ template - MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T aValue) + MOZ_MUST_USE static T swapFromBigEndian(T aValue) { return maybeSwap(aValue); } @@ -569,7 +569,7 @@ protected: * in network code. */ template - MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T aValue) + MOZ_MUST_USE static T swapFromNetworkOrder(T aValue) { return swapFromBigEndian(aValue); } diff --git a/mfbt/EnumSet.h b/mfbt/EnumSet.h index a445f976c8..90349b5f8a 100644 --- a/mfbt/EnumSet.h +++ b/mfbt/EnumSet.h @@ -11,6 +11,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/InitializerList.h" #include @@ -27,7 +28,9 @@ class EnumSet public: EnumSet() : mBitField(0) - { } + { + initVersion(); + } MOZ_IMPLICIT EnumSet(T aEnum) : mBitField(bitFor(aEnum)) @@ -36,30 +39,48 @@ public: EnumSet(T aEnum1, T aEnum2) : mBitField(bitFor(aEnum1) | bitFor(aEnum2)) - { } + { + initVersion(); + } EnumSet(T aEnum1, T aEnum2, T aEnum3) : mBitField(bitFor(aEnum1) | bitFor(aEnum2) | bitFor(aEnum3)) - { } + { + initVersion(); + } EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3) | - bitFor(aEnum4)) - { } + : mBitField(bitFor(aEnum1) | + bitFor(aEnum2) | + bitFor(aEnum3) | + bitFor(aEnum4)) + { + initVersion(); + } + + MOZ_IMPLICIT EnumSet(std::initializer_list list) + : mBitField(0) + { + for (auto value : list) { + (*this) += value; + } + initVersion(); + } EnumSet(const EnumSet& aEnumSet) - : mBitField(aEnumSet.mBitField) - { } + : mBitField(aEnumSet.mBitField) + { + initVersion(); + } /** * Add an element */ void operator+=(T aEnum) { + incVersion(); mBitField |= bitFor(aEnum); } @@ -78,6 +99,7 @@ public: */ void operator+=(const EnumSet aEnumSet) { + incVersion(); mBitField |= aEnumSet.mBitField; } @@ -96,6 +118,7 @@ public: */ void operator-=(T aEnum) { + incVersion(); mBitField &= ~(bitFor(aEnum)); } @@ -114,6 +137,7 @@ public: */ void operator-=(const EnumSet aEnumSet) { + incVersion(); mBitField &= ~(aEnumSet.mBitField); } @@ -132,6 +156,7 @@ public: */ void clear() { + incVersion(); mBitField = 0; } @@ -140,6 +165,7 @@ public: */ void operator&=(const EnumSet aEnumSet) { + incVersion(); mBitField &= aEnumSet.mBitField; } @@ -172,7 +198,7 @@ public: /** * Return the number of elements in the set. */ - uint8_t size() + uint8_t size() const { uint8_t count = 0; for (uint32_t bitField = mBitField; bitField; bitField >>= 1) { @@ -195,18 +221,121 @@ public: void deserialize(uint32_t aValue) { + incVersion(); mBitField = aValue; } + class ConstIterator + { + const EnumSet* mSet; + uint32_t mPos; +#ifdef DEBUG + uint64_t mVersion; +#endif + + void checkVersion() { + // Check that the set has not been modified while being iterated. + MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion); + } + + public: + ConstIterator(const EnumSet& aSet, uint32_t aPos) + : mSet(&aSet), mPos(aPos) + { +#ifdef DEBUG + mVersion = mSet->mVersion; +#endif + MOZ_ASSERT(aPos <= kMaxBits); + if (aPos != kMaxBits && !mSet->contains(T(mPos))) + ++*this; + } + + ConstIterator(const ConstIterator& aOther) + : mSet(aOther.mSet), mPos(aOther.mPos) + { +#ifdef DEBUG + mVersion = aOther.mVersion; + checkVersion(); +#endif + } + + ConstIterator(ConstIterator&& aOther) + : mSet(aOther.mSet), mPos(aOther.mPos) + { +#ifdef DEBUG + mVersion = aOther.mVersion; + checkVersion(); +#endif + aOther.mSet = nullptr; + } + + ~ConstIterator() { + checkVersion(); + } + + bool operator==(const ConstIterator& other) { + MOZ_ASSERT(mSet == other.mSet); + checkVersion(); + return mPos == other.mPos; + } + + bool operator!=(const ConstIterator& other) { + return !(*this == other); + } + + T operator*() { + MOZ_ASSERT(mSet); + MOZ_ASSERT(mPos < kMaxBits); + MOZ_ASSERT(mSet->contains(T(mPos))); + checkVersion(); + return T(mPos); + } + + ConstIterator& operator++() { + MOZ_ASSERT(mSet); + MOZ_ASSERT(mPos < kMaxBits); + checkVersion(); + do { + mPos++; + } while (mPos < kMaxBits && !mSet->contains(T(mPos))); + return *this; + } + }; + + ConstIterator begin() const { + return ConstIterator(*this, 0); + } + + ConstIterator end() const { + return ConstIterator(*this, kMaxBits); + } + private: static uint32_t bitFor(T aEnum) { uint32_t bitNumber = (uint32_t)aEnum; - MOZ_ASSERT(bitNumber < 32); + MOZ_ASSERT(bitNumber < kMaxBits); return 1U << bitNumber; } + void initVersion() { +#ifdef DEBUG + mVersion = 0; +#endif + } + + void incVersion() { +#ifdef DEBUG + mVersion++; +#endif + } + + static const size_t kMaxBits = 32; uint32_t mBitField; + +#ifdef DEBUG + uint64_t mVersion; +#endif }; } // namespace mozilla diff --git a/mfbt/FloatingPoint.h b/mfbt/FloatingPoint.h index abe261d5ca..ce0cd82a07 100644 --- a/mfbt/FloatingPoint.h +++ b/mfbt/FloatingPoint.h @@ -414,7 +414,7 @@ FuzzyEqualsMultiplicative(T aValue1, T aValue2, * * This function isn't inlined to avoid buggy optimizations by MSVC. */ -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE extern MFBT_API bool IsFloat32Representable(double aFloat32); diff --git a/mfbt/HashFunctions.h b/mfbt/HashFunctions.h index f490a28fee..45ecef6c59 100644 --- a/mfbt/HashFunctions.h +++ b/mfbt/HashFunctions.h @@ -156,7 +156,7 @@ AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue) * convert to uint32_t, data pointers, and function pointers. */ template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, A aA) { /* @@ -167,7 +167,7 @@ AddToHash(uint32_t aHash, A aA) } template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, A* aA) { /* @@ -181,14 +181,14 @@ AddToHash(uint32_t aHash, A* aA) } template<> -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, uintptr_t aA) { return detail::AddUintptrToHash(aHash, aA); } template -MOZ_WARN_UNUSED_RESULT uint32_t +MOZ_MUST_USE uint32_t AddToHash(uint32_t aHash, A aArg, Args... aArgs) { return AddToHash(AddToHash(aHash, aArg), aArgs...); @@ -202,7 +202,7 @@ AddToHash(uint32_t aHash, A aArg, Args... aArgs) * that x has already been hashed. */ template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashGeneric(Args... aArgs) { return AddToHash(0, aArgs...); @@ -240,45 +240,45 @@ HashKnownLength(const T* aStr, size_t aLength) * If you have the string's length, you might as well call the overload which * includes the length. It may be marginally faster. */ -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char* aStr) { return detail::HashUntilZero(reinterpret_cast(aStr)); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char* aStr, size_t aLength) { return detail::HashKnownLength(reinterpret_cast(aStr), aLength); } -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE inline uint32_t HashString(const unsigned char* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const uint16_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const uint16_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } #ifdef MOZ_CHAR16_IS_NOT_WCHAR -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); @@ -290,13 +290,13 @@ HashString(const char16_t* aStr, size_t aLength) * the same width! */ #ifdef WIN32 -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); @@ -309,7 +309,7 @@ HashString(const wchar_t* aStr, size_t aLength) * This hash walks word-by-word, rather than byte-by-byte, so you won't get the * same result out of HashBytes as you would out of HashString. */ -MOZ_WARN_UNUSED_RESULT extern MFBT_API uint32_t +MOZ_MUST_USE extern MFBT_API uint32_t HashBytes(const void* bytes, size_t aLength); } /* namespace mozilla */ diff --git a/mfbt/Poison.h b/mfbt/Poison.h index 75e0f081cd..aae567654d 100644 --- a/mfbt/Poison.h +++ b/mfbt/Poison.h @@ -59,4 +59,50 @@ extern MFBT_DATA uintptr_t gMozillaPoisonSize; MOZ_END_EXTERN_C +#if defined(__cplusplus) + +namespace mozilla { + +/** + * This class is designed to cause crashes when various kinds of memory + * corruption are observed. For instance, let's say we have a class C where we + * suspect out-of-bounds writes to some members. We can insert a member of type + * Poison near the members we suspect are being corrupted by out-of-bounds + * writes. Or perhaps we have a class K we suspect is subject to use-after-free + * violations, in which case it doesn't particularly matter where in the class + * we add the member of type Poison. + * + * In either case, we then insert calls to Check() throughout the code. Doing + * so enables us to narrow down the location where the corruption is occurring. + * A pleasant side-effect of these additional Check() calls is that crash + * signatures may become more regular, as crashes will ideally occur + * consolidated at the point of a Check(), rather than scattered about at + * various uses of the corrupted memory. + */ +class CorruptionCanary { +public: + CorruptionCanary() { + mValue = kCanarySet; + } + + ~CorruptionCanary() { + Check(); + mValue = mozPoisonValue(); + } + + void Check() const { + if (mValue != kCanarySet) { + MOZ_CRASH("Canary check failed, check lifetime"); + } + } + +private: + static const uintptr_t kCanarySet = 0x0f0b0f0b; + uintptr_t mValue; +}; + +} // mozilla + +#endif + #endif /* mozilla_Poison_h */ diff --git a/mfbt/SegmentedVector.h b/mfbt/SegmentedVector.h index 1a3b6e42bb..1bf60e46f4 100644 --- a/mfbt/SegmentedVector.h +++ b/mfbt/SegmentedVector.h @@ -159,7 +159,7 @@ public: // Returns false if the allocation failed. (If you are using an infallible // allocation policy, use InfallibleAppend() instead.) template - MOZ_WARN_UNUSED_RESULT bool Append(U&& aU) + MOZ_MUST_USE bool Append(U&& aU) { Segment* last = mSegments.getLast(); if (!last || last->Length() == kSegmentCapacity) { diff --git a/mfbt/ThreadLocal.h b/mfbt/ThreadLocal.h index 0ebe2917cb..880e677357 100644 --- a/mfbt/ThreadLocal.h +++ b/mfbt/ThreadLocal.h @@ -131,7 +131,7 @@ public: {} #endif - MOZ_WARN_UNUSED_RESULT inline bool init(); + MOZ_MUST_USE inline bool init(); inline T get() const; diff --git a/mfbt/UniquePtr.h b/mfbt/UniquePtr.h index 3f445a11e4..0c47ba6d52 100644 --- a/mfbt/UniquePtr.h +++ b/mfbt/UniquePtr.h @@ -328,7 +328,7 @@ public: DeleterType& get_deleter() { return del(); } const DeleterType& get_deleter() const { return del(); } - MOZ_WARN_UNUSED_RESULT Pointer release() + MOZ_MUST_USE Pointer release() { Pointer p = ptr(); ptr() = nullptr; @@ -463,7 +463,7 @@ public: DeleterType& get_deleter() { return mTuple.second(); } const DeleterType& get_deleter() const { return mTuple.second(); } - MOZ_WARN_UNUSED_RESULT Pointer release() + MOZ_MUST_USE Pointer release() { Pointer p = mTuple.first(); mTuple.first() = nullptr; diff --git a/mfbt/Vector.h b/mfbt/Vector.h index f26dbb1c93..a137845933 100644 --- a/mfbt/Vector.h +++ b/mfbt/Vector.h @@ -56,22 +56,13 @@ template struct VectorImpl { /* - * Constructs a default object in the uninitialized memory at *aDst. + * Constructs an object in the uninitialized memory at *aDst with aArgs. */ + template MOZ_NONNULL(1) - static inline void new_(T* aDst) + static inline void new_(T* aDst, Args&&... aArgs) { - new(aDst) T(); - } - - /* - * Constructs an object in the uninitialized memory at *aDst from aSrc. - */ - template - MOZ_NONNULL(1) - static inline void new_(T* aDst, U&& aU) - { - new(aDst) T(Forward(aU)); + new(aDst) T(Forward(aArgs)...); } /* Destroys constructed objects in the range [aBegin, aEnd). */ @@ -168,15 +159,11 @@ struct VectorImpl template struct VectorImpl { - static inline void new_(T* aDst) + template + MOZ_NONNULL(1) + static inline void new_(T* aDst, Args&&... aArgs) { - *aDst = T(); - } - - template - static inline void new_(T* aDst, U&& aU) - { - *aDst = Forward(aU); + *aDst = T(Forward(aArgs)...); } static inline void destroy(T*, T*) {} @@ -281,9 +268,9 @@ class Vector final : private AllocPolicy friend struct detail::VectorTesting; - MOZ_WARN_UNUSED_RESULT bool growStorageBy(size_t aIncr); - MOZ_WARN_UNUSED_RESULT bool convertToHeapStorage(size_t aNewCap); - MOZ_WARN_UNUSED_RESULT bool maybeCheckSimulatedOOM(size_t aRequestedSize); + MOZ_MUST_USE bool growStorageBy(size_t aIncr); + MOZ_MUST_USE bool convertToHeapStorage(size_t aNewCap); + MOZ_MUST_USE bool maybeCheckSimulatedOOM(size_t aRequestedSize); /* magic constants */ @@ -528,7 +515,7 @@ public: * Given that the vector is empty and has no inline storage, grow to * |capacity|. */ - MOZ_WARN_UNUSED_RESULT bool initCapacity(size_t aRequest); + MOZ_MUST_USE bool initCapacity(size_t aRequest); /** * If reserve(aRequest) succeeds and |aRequest >= length()|, then appending @@ -538,7 +525,7 @@ public: * A request to reserve an amount less than the current length does not affect * reserved space. */ - MOZ_WARN_UNUSED_RESULT bool reserve(size_t aRequest); + MOZ_MUST_USE bool reserve(size_t aRequest); /** * Destroy elements in the range [end() - aIncr, end()). Does not deallocate @@ -553,18 +540,18 @@ public: void shrinkTo(size_t aNewLength); /** Grow the vector by aIncr elements. */ - MOZ_WARN_UNUSED_RESULT bool growBy(size_t aIncr); + MOZ_MUST_USE bool growBy(size_t aIncr); /** Call shrinkBy or growBy based on whether newSize > length(). */ - MOZ_WARN_UNUSED_RESULT bool resize(size_t aNewLength); + MOZ_MUST_USE bool resize(size_t aNewLength); /** * Increase the length of the vector, but don't initialize the new elements * -- leave them as uninitialized memory. */ - MOZ_WARN_UNUSED_RESULT bool growByUninitialized(size_t aIncr); + MOZ_MUST_USE bool growByUninitialized(size_t aIncr); void infallibleGrowByUninitialized(size_t aIncr); - MOZ_WARN_UNUSED_RESULT bool resizeUninitialized(size_t aNewLength); + MOZ_MUST_USE bool resizeUninitialized(size_t aNewLength); /** Shorthand for shrinkBy(length()). */ void clear(); @@ -587,25 +574,25 @@ public: * vector, instead of copying it. If it fails, |aU| is left unmoved. ("We are * not amused.") */ - template MOZ_WARN_UNUSED_RESULT bool append(U&& aU); + template MOZ_MUST_USE bool append(U&& aU); /** * Construct a T in-place as a new entry at the end of this vector. */ template - MOZ_WARN_UNUSED_RESULT bool emplaceBack(Args&&... aArgs) + MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { if (!growByUninitialized(1)) return false; - new (&back()) T(Forward(aArgs)...); + Impl::new_(&back(), Forward(aArgs)...); return true; } template - MOZ_WARN_UNUSED_RESULT bool appendAll(const Vector& aU); - MOZ_WARN_UNUSED_RESULT bool appendN(const T& aT, size_t aN); - template MOZ_WARN_UNUSED_RESULT bool append(const U* aBegin, const U* aEnd); - template MOZ_WARN_UNUSED_RESULT bool append(const U* aBegin, size_t aLength); + MOZ_MUST_USE bool appendAll(const Vector& aU); + MOZ_MUST_USE bool appendN(const T& aT, size_t aN); + template MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd); + template MOZ_MUST_USE bool append(const U* aBegin, size_t aLength); /* * Guaranteed-infallible append operations for use upon vectors whose @@ -632,7 +619,7 @@ public: void infallibleEmplaceBack(Args&&... aArgs) { infallibleGrowByUninitialized(1); - new (&back()) T(Forward(aArgs)...); + Impl::new_(&back(), Forward(aArgs)...); } void popBack(); @@ -640,16 +627,34 @@ public: T popCopy(); /** - * Transfers ownership of the internal buffer used by this vector to the - * caller. (It's the caller's responsibility to properly deallocate this - * buffer, in accordance with this vector's AllocPolicy.) After this call, - * the vector is empty. Since the returned buffer may need to be allocated - * (if the elements are currently stored in-place), the call can fail, - * returning nullptr. + * If elements are stored in-place, return nullptr and leave this vector + * unmodified. + * + * Otherwise return this vector's elements buffer, and clear this vector as if + * by clearAndFree(). The caller now owns the buffer and is responsible for + * deallocating it consistent with this vector's AllocPolicy. * * N.B. Although a T*, only the range [0, length()) is constructed. */ - MOZ_WARN_UNUSED_RESULT T* extractRawBuffer(); + MOZ_MUST_USE T* extractRawBuffer(); + + /** + * If elements are stored in-place, allocate a new buffer, move this vector's + * elements into it, and return that buffer. + * + * Otherwise return this vector's elements buffer. The caller now owns the + * buffer and is responsible for deallocating it consistent with this vector's + * AllocPolicy. + * + * This vector is cleared, as if by clearAndFree(), when this method + * succeeds. This method fails and returns nullptr only if new elements buffer + * allocation fails. + * + * N.B. Only the range [0, length()) of the returned buffer is constructed. + * If any of these elements are uninitialized (as growByUninitialized + * enables), behavior is undefined. + */ + MOZ_MUST_USE T* extractOrCopyRawBuffer(); /** * Transfer ownership of an array of objects into the vector. The caller @@ -677,7 +682,7 @@ public: * This is inherently a linear-time operation. Be careful! */ template - MOZ_WARN_UNUSED_RESULT T* insert(T* aP, U&& aVal); + MOZ_MUST_USE T* insert(T* aP, U&& aVal); /** * Removes the element |aT|, which must fall in the bounds [begin, end), @@ -1303,28 +1308,48 @@ template inline T* Vector::extractRawBuffer() { - T* ret; + MOZ_REENTRANCY_GUARD_ET_AL; + if (usingInlineStorage()) { - ret = this->template pod_malloc(mLength); - if (!ret) { - return nullptr; - } - Impl::copyConstruct(ret, beginNoCheck(), endNoCheck()); - Impl::destroy(beginNoCheck(), endNoCheck()); - /* mBegin, mCapacity are unchanged. */ - mLength = 0; - } else { - ret = mBegin; - mBegin = static_cast(mStorage.addr()); - mLength = 0; - mCapacity = kInlineCapacity; -#ifdef DEBUG - mReserved = 0; -#endif + return nullptr; } + + T* ret = mBegin; + mBegin = static_cast(mStorage.addr()); + mLength = 0; + mCapacity = kInlineCapacity; +#ifdef DEBUG + mReserved = 0; +#endif return ret; } +template +inline T* +Vector::extractOrCopyRawBuffer() +{ + if (T* ret = extractRawBuffer()) { + return ret; + } + + MOZ_REENTRANCY_GUARD_ET_AL; + + T* copy = this->template pod_malloc(mLength); + if (!copy) { + return nullptr; + } + + Impl::moveConstruct(copy, beginNoCheck(), endNoCheck()); + Impl::destroy(beginNoCheck(), endNoCheck()); + mBegin = static_cast(mStorage.addr()); + mLength = 0; + mCapacity = kInlineCapacity; +#ifdef DEBUG + mReserved = 0; +#endif + return copy; +} + template inline void Vector::replaceRawBuffer(T* aP, size_t aLength) diff --git a/mfbt/tests/TestEnumSet.cpp b/mfbt/tests/TestEnumSet.cpp index 6d5b040dea..801295fd67 100644 --- a/mfbt/tests/TestEnumSet.cpp +++ b/mfbt/tests/TestEnumSet.cpp @@ -5,6 +5,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/EnumSet.h" +#include "mozilla/Vector.h" using namespace mozilla; @@ -59,6 +60,8 @@ public: testInsersection(); testEquality(); testDuplicates(); + testIteration(); + testInitializerListConstuctor(); } private: @@ -233,6 +236,43 @@ private: MOZ_RELEASE_ASSERT(likes == mPetrels); } + void testIteration() + { + EnumSet birds; + Vector vec; + + for (auto bird : birds) { + MOZ_RELEASE_ASSERT(vec.append(bird)); + } + MOZ_RELEASE_ASSERT(vec.length() == 0); + + birds += DIVING_PETREL; + birds += GADFLY_PETREL; + birds += STORM_PETREL; + birds += TRUE_PETREL; + for (auto bird : birds) { + MOZ_RELEASE_ASSERT(vec.append(bird)); + } + + MOZ_RELEASE_ASSERT(vec.length() == 4); + MOZ_RELEASE_ASSERT(vec[0] == GADFLY_PETREL); + MOZ_RELEASE_ASSERT(vec[1] == TRUE_PETREL); + MOZ_RELEASE_ASSERT(vec[2] == DIVING_PETREL); + MOZ_RELEASE_ASSERT(vec[3] == STORM_PETREL); + } + + void testInitializerListConstuctor() + { + EnumSet empty {}; + MOZ_RELEASE_ASSERT(empty.size() == 0); + + EnumSet someBirds { SKIMMER, GULL, BOOBY }; + MOZ_RELEASE_ASSERT(someBirds.size() == 3); + MOZ_RELEASE_ASSERT(someBirds.contains(SKIMMER)); + MOZ_RELEASE_ASSERT(someBirds.contains(GULL)); + MOZ_RELEASE_ASSERT(someBirds.contains(BOOBY)); + } + EnumSet mAlcidae; EnumSet mDiomedeidae; EnumSet mPetrelProcellariidae; diff --git a/mfbt/tests/TestSegmentedVector.cpp b/mfbt/tests/TestSegmentedVector.cpp index 95c4787481..2bf2540aa6 100644 --- a/mfbt/tests/TestSegmentedVector.cpp +++ b/mfbt/tests/TestSegmentedVector.cpp @@ -35,7 +35,7 @@ public: }; // We want to test Append(), which is fallible and marked with -// MOZ_WARN_UNUSED_RESULT. But we're using an infallible alloc policy, and so +// MOZ_MUST_USE. But we're using an infallible alloc policy, and so // don't really need to check the result. Casting to |void| works with clang // but not GCC, so we instead use this dummy variable which works with both // compilers. diff --git a/mfbt/tests/TestVector.cpp b/mfbt/tests/TestVector.cpp index 8ea43919b7..d969bcbc2c 100644 --- a/mfbt/tests/TestVector.cpp +++ b/mfbt/tests/TestVector.cpp @@ -20,6 +20,8 @@ struct mozilla::detail::VectorTesting static void testConstRange(); static void testEmplaceBack(); static void testReverse(); + static void testExtractRawBuffer(); + static void testExtractOrCopyRawBuffer(); }; void @@ -111,6 +113,13 @@ struct S static size_t constructCount; static size_t moveCount; + static size_t destructCount; + + static void resetCounts() { + constructCount = 0; + moveCount = 0; + destructCount = 0; + } S(size_t j, size_t k) : j(j) @@ -123,27 +132,35 @@ struct S : j(rhs.j) , k(Move(rhs.k)) { - rhs.~S(); + rhs.j = 0; + rhs.k.reset(0); moveCount++; } + ~S() { + destructCount++; + } + S(const S&) = delete; S& operator=(const S&) = delete; }; size_t S::constructCount = 0; size_t S::moveCount = 0; +size_t S::destructCount = 0; } void mozilla::detail::VectorTesting::testEmplaceBack() { + S::resetCounts(); + Vector vec; MOZ_RELEASE_ASSERT(vec.reserve(20)); for (size_t i = 0; i < 10; i++) { - S s(i, i*i); + S s(i, i * i); MOZ_RELEASE_ASSERT(vec.append(Move(s))); } @@ -152,7 +169,7 @@ mozilla::detail::VectorTesting::testEmplaceBack() MOZ_RELEASE_ASSERT(S::moveCount == 10); for (size_t i = 10; i < 20; i++) { - MOZ_RELEASE_ASSERT(vec.emplaceBack(i, i*i)); + MOZ_RELEASE_ASSERT(vec.emplaceBack(i, i * i)); } MOZ_RELEASE_ASSERT(vec.length() == 20); @@ -161,7 +178,7 @@ mozilla::detail::VectorTesting::testEmplaceBack() for (size_t i = 0; i < 20; i++) { MOZ_RELEASE_ASSERT(vec[i].j == i); - MOZ_RELEASE_ASSERT(*vec[i].k == i*i); + MOZ_RELEASE_ASSERT(*vec[i].k == i * i); } } @@ -222,6 +239,113 @@ mozilla::detail::VectorTesting::testReverse() MOZ_RELEASE_ASSERT(*vec2[4] == 0); } +void +mozilla::detail::VectorTesting::testExtractRawBuffer() +{ + S::resetCounts(); + + Vector vec; + MOZ_RELEASE_ASSERT(vec.reserve(5)); + for (size_t i = 0; i < 5; i++) { + vec.infallibleEmplaceBack(i, i * i); + } + MOZ_RELEASE_ASSERT(vec.length() == 5); + MOZ_ASSERT(vec.reserved() == 5); + MOZ_RELEASE_ASSERT(S::constructCount == 5); + MOZ_RELEASE_ASSERT(S::moveCount == 0); + MOZ_RELEASE_ASSERT(S::destructCount == 0); + + S* buf = vec.extractRawBuffer(); + MOZ_RELEASE_ASSERT(!buf); + MOZ_RELEASE_ASSERT(vec.length() == 5); + MOZ_ASSERT(vec.reserved() == 5); + MOZ_RELEASE_ASSERT(S::constructCount == 5); + MOZ_RELEASE_ASSERT(S::moveCount == 0); + MOZ_RELEASE_ASSERT(S::destructCount == 0); + + MOZ_RELEASE_ASSERT(vec.reserve(10)); + for (size_t i = 5; i < 10; i++) { + vec.infallibleEmplaceBack(i, i * i); + } + MOZ_RELEASE_ASSERT(vec.length() == 10); + MOZ_ASSERT(vec.reserved() == 10); + MOZ_RELEASE_ASSERT(S::constructCount == 10); + MOZ_RELEASE_ASSERT(S::moveCount == 5); + MOZ_RELEASE_ASSERT(S::destructCount == 5); + + buf = vec.extractRawBuffer(); + MOZ_RELEASE_ASSERT(buf); + MOZ_RELEASE_ASSERT(vec.length() == 0); + MOZ_ASSERT(vec.reserved() == 0); + MOZ_RELEASE_ASSERT(S::constructCount == 10); + MOZ_RELEASE_ASSERT(S::moveCount == 5); + MOZ_RELEASE_ASSERT(S::destructCount == 5); + + for (size_t i = 0; i < 10; i++) { + MOZ_RELEASE_ASSERT(buf[i].j == i); + MOZ_RELEASE_ASSERT(*buf[i].k == i * i); + } + + free(buf); +} + +void +mozilla::detail::VectorTesting::testExtractOrCopyRawBuffer() +{ + S::resetCounts(); + + Vector vec; + MOZ_RELEASE_ASSERT(vec.reserve(5)); + for (size_t i = 0; i < 5; i++) { + vec.infallibleEmplaceBack(i, i * i); + } + MOZ_RELEASE_ASSERT(vec.length() == 5); + MOZ_ASSERT(vec.reserved() == 5); + MOZ_RELEASE_ASSERT(S::constructCount == 5); + MOZ_RELEASE_ASSERT(S::moveCount == 0); + MOZ_RELEASE_ASSERT(S::destructCount == 0); + + S* buf = vec.extractOrCopyRawBuffer(); + MOZ_RELEASE_ASSERT(buf); + MOZ_RELEASE_ASSERT(vec.length() == 0); + MOZ_ASSERT(vec.reserved() == 0); + MOZ_RELEASE_ASSERT(S::constructCount == 5); + MOZ_RELEASE_ASSERT(S::moveCount == 5); + MOZ_RELEASE_ASSERT(S::destructCount == 5); + + for (size_t i = 0; i < 5; i++) { + MOZ_RELEASE_ASSERT(buf[i].j == i); + MOZ_RELEASE_ASSERT(*buf[i].k == i * i); + } + + S::resetCounts(); + + MOZ_RELEASE_ASSERT(vec.reserve(10)); + for (size_t i = 0; i < 10; i++) { + vec.infallibleEmplaceBack(i, i * i); + } + MOZ_RELEASE_ASSERT(vec.length() == 10); + MOZ_ASSERT(vec.reserved() == 10); + MOZ_RELEASE_ASSERT(S::constructCount == 10); + MOZ_RELEASE_ASSERT(S::moveCount == 0); + MOZ_RELEASE_ASSERT(S::destructCount == 0); + + buf = vec.extractOrCopyRawBuffer(); + MOZ_RELEASE_ASSERT(buf); + MOZ_RELEASE_ASSERT(vec.length() == 0); + MOZ_ASSERT(vec.reserved() == 0); + MOZ_RELEASE_ASSERT(S::constructCount == 10); + MOZ_RELEASE_ASSERT(S::moveCount == 0); + MOZ_RELEASE_ASSERT(S::destructCount == 0); + + for (size_t i = 0; i < 10; i++) { + MOZ_RELEASE_ASSERT(buf[i].j == i); + MOZ_RELEASE_ASSERT(*buf[i].k == i * i); + } + + free(buf); +} + int main() { @@ -229,4 +353,6 @@ main() VectorTesting::testConstRange(); VectorTesting::testEmplaceBack(); VectorTesting::testReverse(); + VectorTesting::testExtractRawBuffer(); + VectorTesting::testExtractOrCopyRawBuffer(); } diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp index add3dcabcb..18e09f5117 100644 --- a/modules/libpref/Preferences.cpp +++ b/modules/libpref/Preferences.cpp @@ -366,7 +366,7 @@ PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb, } namespace { -class AddPreferencesMemoryReporterRunnable : public nsRunnable +class AddPreferencesMemoryReporterRunnable : public Runnable { NS_IMETHOD Run() { diff --git a/netwerk/base/BackgroundFileSaver.cpp b/netwerk/base/BackgroundFileSaver.cpp index b48fb724b6..87d5691bf6 100644 --- a/netwerk/base/BackgroundFileSaver.cpp +++ b/netwerk/base/BackgroundFileSaver.cpp @@ -62,7 +62,7 @@ static LazyLogModule prlog("BackgroundFileSaver"); * Runnable object used to notify the control thread that file contents will now * be saved to the specified file. */ -class NotifyTargetChangeRunnable final : public nsRunnable +class NotifyTargetChangeRunnable final : public Runnable { public: NotifyTargetChangeRunnable(BackgroundFileSaver *aSaver, nsIFile *aTarget) diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index ba0cc88e8e..3301ed7ce9 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -72,6 +72,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, // if the load is sandboxed, we can not also inherit the principal if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) { mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; + mSecurityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL_WAS_DROPPED; } if (aLoadingContext) { @@ -164,6 +165,7 @@ LoadInfo::LoadInfo(nsPIDOMWindow* aOuterWindow, // if the load is sandboxed, we can not also inherit the principal if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) { mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; + mSecurityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL_WAS_DROPPED; } // NB: Ignore the current inner window since we're navigating away from it. diff --git a/netwerk/base/NetStatistics.h b/netwerk/base/NetStatistics.h index 3b91fe9157..cac93835c0 100644 --- a/netwerk/base/NetStatistics.h +++ b/netwerk/base/NetStatistics.h @@ -43,7 +43,7 @@ GetActiveNetworkInfo(nsCOMPtr &aNetworkInfo) return NS_OK; } -class SaveNetworkStatsEvent : public nsRunnable { +class SaveNetworkStatsEvent : public Runnable { public: SaveNetworkStatsEvent(uint32_t aAppId, bool aIsInBrowser, diff --git a/netwerk/base/NetworkActivityMonitor.cpp b/netwerk/base/NetworkActivityMonitor.cpp index 899363be0e..e50c007407 100644 --- a/netwerk/base/NetworkActivityMonitor.cpp +++ b/netwerk/base/NetworkActivityMonitor.cpp @@ -149,7 +149,7 @@ nsNetMon_AcceptRead(PRFileDesc *listenSock, } -class NotifyNetworkActivity : public nsRunnable { +class NotifyNetworkActivity : public mozilla::Runnable { public: explicit NotifyNetworkActivity(NetworkActivityMonitor::Direction aDirection) : mDirection(aDirection) diff --git a/netwerk/base/Predictor.cpp b/netwerk/base/Predictor.cpp index 210428d677..de14c32db9 100644 --- a/netwerk/base/Predictor.cpp +++ b/netwerk/base/Predictor.cpp @@ -532,7 +532,7 @@ Predictor::GetInterface(const nsIID &iid, void **result) #ifdef MOZ_NUWA_PROCESS namespace { -class NuwaMarkPredictorThreadRunner : public nsRunnable +class NuwaMarkPredictorThreadRunner : public Runnable { NS_IMETHODIMP Run() override { @@ -650,7 +650,7 @@ Predictor::Init() } namespace { -class PredictorThreadShutdownRunner : public nsRunnable +class PredictorThreadShutdownRunner : public Runnable { public: PredictorThreadShutdownRunner(nsIThread *ioThread, bool success) @@ -675,7 +675,7 @@ private: bool mSuccess; }; -class PredictorOldCleanupRunner : public nsRunnable +class PredictorOldCleanupRunner : public Runnable { public: PredictorOldCleanupRunner(nsIThread *ioThread, nsIFile *dbFile) diff --git a/netwerk/base/TLSServerSocket.cpp b/netwerk/base/TLSServerSocket.cpp index 06109652fb..e315c18fb0 100644 --- a/netwerk/base/TLSServerSocket.cpp +++ b/netwerk/base/TLSServerSocket.cpp @@ -263,7 +263,7 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSITLSSERVERSECURITYOBSERVER - class OnHandshakeDoneRunnable : public nsRunnable + class OnHandshakeDoneRunnable : public Runnable { public: OnHandshakeDoneRunnable(const nsMainThreadPtrHandle& aListener, diff --git a/netwerk/base/Tickler.cpp b/netwerk/base/Tickler.cpp index 896eaf6662..5d42440dca 100644 --- a/netwerk/base/Tickler.cpp +++ b/netwerk/base/Tickler.cpp @@ -33,7 +33,7 @@ Tickler::Tickler() MOZ_ASSERT(NS_IsMainThread()); } -class TicklerThreadDestructor : public nsRunnable +class TicklerThreadDestructor : public Runnable { public: explicit TicklerThreadDestructor(nsIThread *aThread) diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build index c11cc0e646..38dc97a421 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -155,7 +155,7 @@ EXPORTS += [ 'nsInputStreamPump.h', 'nsMIMEInputStream.h', 'nsNetUtil.h', - 'nsNetUtil.inl', + 'nsNetUtilInlines.h', 'nsReadLine.h', 'nsSerializationHelper.h', 'nsSimpleNestedURI.h', diff --git a/netwerk/base/nsAsyncRedirectVerifyHelper.cpp b/netwerk/base/nsAsyncRedirectVerifyHelper.cpp index 4d7994dfde..fed423ce74 100644 --- a/netwerk/base/nsAsyncRedirectVerifyHelper.cpp +++ b/netwerk/base/nsAsyncRedirectVerifyHelper.cpp @@ -22,7 +22,7 @@ NS_IMPL_ISUPPORTS(nsAsyncRedirectVerifyHelper, nsIAsyncVerifyRedirectCallback, nsIRunnable) -class nsAsyncVerifyRedirectCallbackEvent : public nsRunnable { +class nsAsyncVerifyRedirectCallbackEvent : public mozilla::Runnable { public: nsAsyncVerifyRedirectCallbackEvent(nsIAsyncVerifyRedirectCallback *cb, nsresult result) diff --git a/netwerk/base/nsAsyncStreamCopier.cpp b/netwerk/base/nsAsyncStreamCopier.cpp index 15ca9d5284..331dcc65a9 100644 --- a/netwerk/base/nsAsyncStreamCopier.cpp +++ b/netwerk/base/nsAsyncStreamCopier.cpp @@ -25,7 +25,7 @@ static LazyLogModule gStreamCopierLog("nsStreamCopier"); /** * An event used to perform initialization off the main thread. */ -class AsyncApplyBufferingPolicyEvent final: public nsRunnable +class AsyncApplyBufferingPolicyEvent final: public Runnable { public: /** diff --git a/netwerk/base/nsBaseChannel.cpp b/netwerk/base/nsBaseChannel.cpp index 08525dbbb9..9bbc3d6d34 100644 --- a/netwerk/base/nsBaseChannel.cpp +++ b/netwerk/base/nsBaseChannel.cpp @@ -855,7 +855,7 @@ nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, if (NS_IsMainThread()) { OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength); } else { - class OnTransportStatusAsyncEvent : public nsRunnable + class OnTransportStatusAsyncEvent : public mozilla::Runnable { RefPtr mChannel; int64_t mProgress; diff --git a/netwerk/base/nsBaseChannel.h b/netwerk/base/nsBaseChannel.h index f472d066e8..9de95bbbce 100644 --- a/netwerk/base/nsBaseChannel.h +++ b/netwerk/base/nsBaseChannel.h @@ -244,7 +244,7 @@ private: // start URI classifier if requested void ClassifyURI(); - class RedirectRunnable : public nsRunnable + class RedirectRunnable : public mozilla::Runnable { public: RedirectRunnable(nsBaseChannel* chan, nsIChannel* newChannel) diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index e5bcf0b25c..03e486c563 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -118,7 +118,10 @@ interface nsILoadInfo : nsISupports * is loading the URI "http://b.com/whatever", GetChannelResultPrincipal * will return a principal from "http://a.com/". * - * This flag can not be used together with SEC_SANDBOXED. + * This flag can not be used together with SEC_SANDBOXED. If both are passed + * to the LoadInfo constructor then this flag will be dropped. If you need + * to know whether this flag would have been present but was dropped due to + * sandboxing, check for the SEC_FORCE_INHERIT_PRINCIPAL_WAS_DROPPED flag. */ const unsigned long SEC_FORCE_INHERIT_PRINCIPAL = (1<<7); @@ -166,6 +169,14 @@ interface nsILoadInfo : nsISupports */ const unsigned long SEC_FORCE_PRIVATE_BROWSING = (1<<12); + /** + * The SEC_FORCE_INHERIT_PRINCIPAL flag may be dropped when a load info + * object is created. Specifically, it will be dropped if the SEC_SANDBOXED + * flag is also present. This flag is set if SEC_FORCE_INHERIT_PRINCIPAL was + * dropped. + */ + const unsigned long SEC_FORCE_INHERIT_PRINCIPAL_WAS_DROPPED = (1<<13); + /** * The loadingPrincipal is the principal that is responsible for the load. * It is *NOT* the principal tied to the resource/URI that this diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 8dd1b3fb15..cb6a6720c7 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -1347,7 +1347,7 @@ IsWifiActive() } class -nsWakeupNotifier : public nsRunnable +nsWakeupNotifier : public Runnable { public: explicit nsWakeupNotifier(nsIIOServiceInternal *ioService) @@ -1910,7 +1910,7 @@ nsIOService::NotifyAppOfflineStatus(uint32_t appId, int32_t state) namespace { -class SetAppOfflineMainThread : public nsRunnable +class SetAppOfflineMainThread : public Runnable { public: SetAppOfflineMainThread(uint32_t aAppId, int32_t aState) diff --git a/netwerk/base/nsIncrementalStreamLoader.cpp b/netwerk/base/nsIncrementalStreamLoader.cpp index 4f4e144b8f..b80446005f 100644 --- a/netwerk/base/nsIncrementalStreamLoader.cpp +++ b/netwerk/base/nsIncrementalStreamLoader.cpp @@ -94,7 +94,7 @@ nsIncrementalStreamLoader::OnStopRequest(nsIRequest* request, nsISupports *ctxt, // provide nsIIncrementalStreamLoader::request during call to OnStreamComplete mRequest = request; size_t length = mData.length(); - uint8_t* elems = mData.extractRawBuffer(); + uint8_t* elems = mData.extractOrCopyRawBuffer(); nsresult rv = mObserver->OnStreamComplete(this, mContext, aStatus, length, elems); if (rv != NS_SUCCESS_ADOPTED_DATA) { @@ -153,7 +153,7 @@ nsIncrementalStreamLoader::WriteSegmentFun(nsIInputStream *inStr, } size_t length = self->mData.length(); uint32_t reportCount = length > UINT32_MAX ? UINT32_MAX : (uint32_t)length; - uint8_t* elems = self->mData.extractRawBuffer(); + uint8_t* elems = self->mData.extractOrCopyRawBuffer(); rv = self->mObserver->OnIncrementalData(self, self->mContext, reportCount, elems, &consumedCount); diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index 08cfe9c533..7e76d554dc 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -12,7 +12,7 @@ #include "mozilla/BasePrincipal.h" #include "mozilla/Telemetry.h" #include "nsNetUtil.h" -#include "nsNetUtil.inl" +#include "nsNetUtilInlines.h" #include "mozIApplicationClearPrivateDataParams.h" #include "nsCategoryCache.h" #include "nsContentUtils.h" diff --git a/netwerk/base/nsNetUtil.h b/netwerk/base/nsNetUtil.h index c03b1c9e25..14a39e3a73 100644 --- a/netwerk/base/nsNetUtil.h +++ b/netwerk/base/nsNetUtil.h @@ -569,7 +569,7 @@ nsresult NS_BackgroundOutputStream(nsIOutputStream **result, uint32_t segmentSize = 0, uint32_t segmentCount = 0); -MOZ_WARN_UNUSED_RESULT nsresult +MOZ_MUST_USE nsresult NS_NewBufferedInputStream(nsIInputStream **result, nsIInputStream *str, uint32_t bufferSize); @@ -1023,7 +1023,7 @@ bool InScriptableRange(uint64_t val); // Include some function bodies for callers with external linkage #ifndef MOZILLA_INTERNAL_API -#include "nsNetUtil.inl" +#include "nsNetUtilInlines.h" #endif #endif // !nsNetUtil_h__ diff --git a/netwerk/base/nsNetUtil.inl b/netwerk/base/nsNetUtilInlines.h similarity index 99% rename from netwerk/base/nsNetUtil.inl rename to netwerk/base/nsNetUtilInlines.h index 65462e676b..7003814d59 100644 --- a/netwerk/base/nsNetUtil.inl +++ b/netwerk/base/nsNetUtilInlines.h @@ -326,7 +326,7 @@ NS_NewLocalFileOutputStream(nsIOutputStream **result, return rv; } -INLINE_IF_EXTERN MOZ_WARN_UNUSED_RESULT nsresult +INLINE_IF_EXTERN MOZ_MUST_USE nsresult NS_NewBufferedInputStream(nsIInputStream **result, nsIInputStream *str, uint32_t bufferSize) diff --git a/netwerk/base/nsPACMan.cpp b/netwerk/base/nsPACMan.cpp index 33b6be7d53..59ec94f851 100644 --- a/netwerk/base/nsPACMan.cpp +++ b/netwerk/base/nsPACMan.cpp @@ -61,7 +61,7 @@ HttpRequestSucceeded(nsIStreamLoader *loader) // nsPACManCallback::OnQueryComplete on the Main thread when its completion is // discovered on the pac thread -class ExecuteCallback final : public nsRunnable +class ExecuteCallback final : public Runnable { public: ExecuteCallback(nsPACManCallback *aCallback, @@ -101,7 +101,7 @@ private: // acts as a proxy to do that, as the PACMan is reference counted // and might be destroyed on either thread -class ShutdownThread final : public nsRunnable +class ShutdownThread final : public Runnable { public: explicit ShutdownThread(nsIThread *thread) @@ -122,7 +122,7 @@ private: // Dispatch this to wait until the PAC thread shuts down. -class WaitForThreadShutdown final : public nsRunnable +class WaitForThreadShutdown final : public Runnable { public: explicit WaitForThreadShutdown(nsPACMan *aPACMan) @@ -150,7 +150,7 @@ private: // the javascript PAC file has been installed (perhaps unsuccessfully) // and that there is no reason to queue executions anymore -class PACLoadComplete final : public nsRunnable +class PACLoadComplete final : public Runnable { public: explicit PACLoadComplete(nsPACMan *aPACMan) @@ -176,7 +176,7 @@ private: // thread onto the PAC thread. There are 3 options: process the queue, // cancel the queue, and setup the javascript context with a new PAC file -class ExecutePACThreadAction final : public nsRunnable +class ExecutePACThreadAction final : public Runnable { public: // by default we just process the queue diff --git a/netwerk/base/nsPACMan.h b/netwerk/base/nsPACMan.h index 1453550b11..1b979274d0 100644 --- a/netwerk/base/nsPACMan.h +++ b/netwerk/base/nsPACMan.h @@ -50,7 +50,7 @@ public: const nsCString &newPACURL) = 0; }; -class PendingPACQuery final : public nsRunnable, +class PendingPACQuery final : public mozilla::Runnable, public mozilla::LinkedListElement { public: @@ -67,7 +67,7 @@ public: nsCString mHost; int32_t mPort; - NS_IMETHOD Run(void); /* nsRunnable */ + NS_IMETHOD Run(void); /* Runnable */ private: nsPACMan *mPACMan; // weak reference diff --git a/netwerk/base/nsPreloadedStream.cpp b/netwerk/base/nsPreloadedStream.cpp index 9160a13a58..417bc3d960 100644 --- a/netwerk/base/nsPreloadedStream.cpp +++ b/netwerk/base/nsPreloadedStream.cpp @@ -107,7 +107,7 @@ nsPreloadedStream::CloseWithStatus(nsresult aStatus) return mStream->CloseWithStatus(aStatus); } -class RunOnThread : public nsRunnable +class RunOnThread : public Runnable { public: RunOnThread(nsIAsyncInputStream *aStream, diff --git a/netwerk/base/nsRequestObserverProxy.h b/netwerk/base/nsRequestObserverProxy.h index 92096853f0..044dbedd6a 100644 --- a/netwerk/base/nsRequestObserverProxy.h +++ b/netwerk/base/nsRequestObserverProxy.h @@ -38,7 +38,7 @@ protected: friend class nsOnStopRequestEvent; }; -class nsARequestObserverEvent : public nsRunnable +class nsARequestObserverEvent : public mozilla::Runnable { public: explicit nsARequestObserverEvent(nsIRequest *); diff --git a/netwerk/base/nsServerSocket.cpp b/netwerk/base/nsServerSocket.cpp index 6d50e26468..3822448263 100644 --- a/netwerk/base/nsServerSocket.cpp +++ b/netwerk/base/nsServerSocket.cpp @@ -435,7 +435,7 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSISERVERSOCKETLISTENER - class OnSocketAcceptedRunnable : public nsRunnable + class OnSocketAcceptedRunnable : public Runnable { public: OnSocketAcceptedRunnable(const nsMainThreadPtrHandle& aListener, @@ -454,7 +454,7 @@ public: nsCOMPtr mTransport; }; - class OnStopListeningRunnable : public nsRunnable + class OnStopListeningRunnable : public Runnable { public: OnStopListeningRunnable(const nsMainThreadPtrHandle& aListener, diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp index ca04e88b86..31269261e0 100644 --- a/netwerk/base/nsSocketTransport2.cpp +++ b/netwerk/base/nsSocketTransport2.cpp @@ -63,7 +63,7 @@ static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID); //----------------------------------------------------------------------------- -class nsSocketEvent : public nsRunnable +class nsSocketEvent : public Runnable { public: nsSocketEvent(nsSocketTransport *transport, uint32_t type, @@ -1724,7 +1724,7 @@ nsSocketTransport::GetFD_Locked() return mFD; } -class ThunkPRClose : public nsRunnable +class ThunkPRClose : public Runnable { public: explicit ThunkPRClose(PRFileDesc *fd) : mFD(fd) {} diff --git a/netwerk/base/nsStreamLoader.cpp b/netwerk/base/nsStreamLoader.cpp index c5b37477ed..b7abdde657 100644 --- a/netwerk/base/nsStreamLoader.cpp +++ b/netwerk/base/nsStreamLoader.cpp @@ -98,7 +98,7 @@ nsStreamLoader::OnStopRequest(nsIRequest* request, nsISupports *ctxt, // provide nsIStreamLoader::request during call to OnStreamComplete mRequest = request; size_t length = mData.length(); - uint8_t* elems = mData.extractRawBuffer(); + uint8_t* elems = mData.extractOrCopyRawBuffer(); nsresult rv = mObserver->OnStreamComplete(this, mContext, aStatus, length, elems); if (rv != NS_SUCCESS_ADOPTED_DATA) { diff --git a/netwerk/base/nsTransportUtils.cpp b/netwerk/base/nsTransportUtils.cpp index 7040914497..6b85c9d01d 100644 --- a/netwerk/base/nsTransportUtils.cpp +++ b/netwerk/base/nsTransportUtils.cpp @@ -47,7 +47,7 @@ public: nsTransportStatusEvent *mLastEvent; }; -class nsTransportStatusEvent : public nsRunnable +class nsTransportStatusEvent : public Runnable { public: nsTransportStatusEvent(nsTransportEventSinkProxy *proxy, diff --git a/netwerk/base/nsUDPSocket.cpp b/netwerk/base/nsUDPSocket.cpp index 804c81885f..e38b697c7d 100644 --- a/netwerk/base/nsUDPSocket.cpp +++ b/netwerk/base/nsUDPSocket.cpp @@ -74,7 +74,7 @@ ResolveHost(const nsACString &host, nsIDNSListener *listener) //----------------------------------------------------------------------------- -class SetSocketOptionRunnable : public nsRunnable +class SetSocketOptionRunnable : public Runnable { public: SetSocketOptionRunnable(nsUDPSocket* aSocket, const PRSocketOptionData& aOpt) @@ -761,7 +761,7 @@ nsUDPSocket::SaveNetworkStats(bool aEnforce) if (aEnforce || total > NETWORK_STATS_THRESHOLD) { // Create the event to save the network statistics. // the event is then dispathed to the main thread. - RefPtr event = + RefPtr event = new SaveNetworkStatsEvent(mAppId, mIsInBrowserElement, mActiveNetworkInfo, mByteReadCount, mByteWriteCount, false); NS_DispatchToMainThread(event); @@ -814,7 +814,7 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIUDPSOCKETLISTENER - class OnPacketReceivedRunnable : public nsRunnable + class OnPacketReceivedRunnable : public Runnable { public: OnPacketReceivedRunnable(const nsMainThreadPtrHandle& aListener, @@ -833,7 +833,7 @@ public: nsCOMPtr mMessage; }; - class OnStopListeningRunnable : public nsRunnable + class OnStopListeningRunnable : public Runnable { public: OnStopListeningRunnable(const nsMainThreadPtrHandle& aListener, @@ -919,7 +919,7 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIUDPSOCKETLISTENER - class OnPacketReceivedRunnable : public nsRunnable + class OnPacketReceivedRunnable : public Runnable { public: OnPacketReceivedRunnable(const nsCOMPtr& aListener, @@ -938,7 +938,7 @@ public: nsCOMPtr mMessage; }; - class OnStopListeningRunnable : public nsRunnable + class OnStopListeningRunnable : public Runnable { public: OnStopListeningRunnable(const nsCOMPtr& aListener, @@ -1098,7 +1098,7 @@ PendingSendStream::OnLookupComplete(nsICancelable *request, return NS_OK; } -class SendRequestRunnable: public nsRunnable { +class SendRequestRunnable: public Runnable { public: SendRequestRunnable(nsUDPSocket *aSocket, const NetAddr &aAddr, diff --git a/netwerk/cache/nsCacheEntryDescriptor.cpp b/netwerk/cache/nsCacheEntryDescriptor.cpp index b235ec2154..b4d613f461 100644 --- a/netwerk/cache/nsCacheEntryDescriptor.cpp +++ b/netwerk/cache/nsCacheEntryDescriptor.cpp @@ -23,7 +23,7 @@ * nsAsyncDoomEvent *****************************************************************************/ -class nsAsyncDoomEvent : public nsRunnable { +class nsAsyncDoomEvent : public mozilla::Runnable { public: nsAsyncDoomEvent(nsCacheEntryDescriptor *descriptor, nsICacheListener *listener) diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp index 6dee6b6159..c29457c8ef 100644 --- a/netwerk/cache/nsCacheService.cpp +++ b/netwerk/cache/nsCacheService.cpp @@ -222,7 +222,7 @@ NS_IMPL_ISUPPORTS(nsSetDiskSmartSizeCallback, nsITimerCallback) // Runnable sent to main thread after the cache IO thread calculates available // disk space, so that there is no race in setting mDiskCacheCapacity. -class nsSetSmartSizeEvent: public nsRunnable +class nsSetSmartSizeEvent: public Runnable { public: explicit nsSetSmartSizeEvent(int32_t smartSize) @@ -259,7 +259,7 @@ private: // Runnable sent from main thread to cacheIO thread -class nsGetSmartSizeEvent: public nsRunnable +class nsGetSmartSizeEvent: public Runnable { public: nsGetSmartSizeEvent(const nsAString& cachePath, uint32_t currentSize, @@ -287,7 +287,7 @@ private: bool mShouldUseOldMaxSmartSize; }; -class nsBlockOnCacheThreadEvent : public nsRunnable { +class nsBlockOnCacheThreadEvent : public Runnable { public: nsBlockOnCacheThreadEvent() { @@ -966,7 +966,7 @@ nsCacheProfilePrefObserver::CacheCompressionLevel() * nsProcessRequestEvent *****************************************************************************/ -class nsProcessRequestEvent : public nsRunnable { +class nsProcessRequestEvent : public Runnable { public: explicit nsProcessRequestEvent(nsCacheRequest *aRequest) { @@ -1004,7 +1004,7 @@ private: * nsDoomEvent *****************************************************************************/ -class nsDoomEvent : public nsRunnable { +class nsDoomEvent : public Runnable { public: nsDoomEvent(nsCacheSession *session, const nsACString &key, @@ -1318,7 +1318,7 @@ nsCacheService::EvictEntriesForSession(nsCacheSession * session) namespace { -class EvictionNotifierRunnable : public nsRunnable +class EvictionNotifierRunnable : public Runnable { public: explicit EvictionNotifierRunnable(nsISupports* aSubject) @@ -1632,7 +1632,7 @@ nsCacheService::CreateDiskDevice() } // Runnable sent from cache thread to main thread -class nsDisableOldMaxSmartSizePrefEvent: public nsRunnable +class nsDisableOldMaxSmartSizePrefEvent: public Runnable { public: nsDisableOldMaxSmartSizePrefEvent() {} @@ -1842,7 +1842,7 @@ nsCacheService::CreateRequest(nsCacheSession * session, } -class nsCacheListenerEvent : public nsRunnable +class nsCacheListenerEvent : public Runnable { public: nsCacheListenerEvent(nsICacheListener *listener, diff --git a/netwerk/cache/nsCacheService.h b/netwerk/cache/nsCacheService.h index 20eec1a159..e5fc389e44 100644 --- a/netwerk/cache/nsCacheService.h +++ b/netwerk/cache/nsCacheService.h @@ -38,7 +38,7 @@ class mozIStorageService; * nsNotifyDoomListener *****************************************************************************/ -class nsNotifyDoomListener : public nsRunnable { +class nsNotifyDoomListener : public mozilla::Runnable { public: nsNotifyDoomListener(nsICacheListener *listener, nsresult status) diff --git a/netwerk/cache/nsCacheUtils.cpp b/netwerk/cache/nsCacheUtils.cpp index d6865f521f..dbe3c39244 100644 --- a/netwerk/cache/nsCacheUtils.cpp +++ b/netwerk/cache/nsCacheUtils.cpp @@ -10,7 +10,7 @@ using namespace mozilla; -class nsDestroyThreadEvent : public nsRunnable { +class nsDestroyThreadEvent : public Runnable { public: explicit nsDestroyThreadEvent(nsIThread *thread) : mThread(thread) diff --git a/netwerk/cache/nsCacheUtils.h b/netwerk/cache/nsCacheUtils.h index 1ce27de8b4..497c74510b 100644 --- a/netwerk/cache/nsCacheUtils.h +++ b/netwerk/cache/nsCacheUtils.h @@ -17,7 +17,7 @@ class nsIThread; /** * A class with utility methods for shutting down nsIThreads easily. */ -class nsShutdownThread : public nsRunnable { +class nsShutdownThread : public mozilla::Runnable { public: explicit nsShutdownThread(nsIThread *aThread); ~nsShutdownThread(); diff --git a/netwerk/cache/nsDeleteDir.cpp b/netwerk/cache/nsDeleteDir.cpp index ee71b240ca..a54bec2d67 100644 --- a/netwerk/cache/nsDeleteDir.cpp +++ b/netwerk/cache/nsDeleteDir.cpp @@ -18,7 +18,7 @@ using namespace mozilla; -class nsBlockOnBackgroundThreadEvent : public nsRunnable { +class nsBlockOnBackgroundThreadEvent : public Runnable { public: nsBlockOnBackgroundThreadEvent() {} NS_IMETHOD Run() diff --git a/netwerk/cache/nsDiskCacheDevice.cpp b/netwerk/cache/nsDiskCacheDevice.cpp index b224ed0097..063fe2e53e 100644 --- a/netwerk/cache/nsDiskCacheDevice.cpp +++ b/netwerk/cache/nsDiskCacheDevice.cpp @@ -49,7 +49,7 @@ static const char DISK_CACHE_DEVICE_ID[] = { "disk" }; using namespace mozilla; -class nsDiskCacheDeviceDeactivateEntryEvent : public nsRunnable { +class nsDiskCacheDeviceDeactivateEntryEvent : public Runnable { public: nsDiskCacheDeviceDeactivateEntryEvent(nsDiskCacheDevice *device, nsCacheEntry * entry, @@ -79,7 +79,7 @@ private: nsDiskCacheBinding *mBinding; }; -class nsEvictDiskCacheEntriesEvent : public nsRunnable { +class nsEvictDiskCacheEntriesEvent : public Runnable { public: explicit nsEvictDiskCacheEntriesEvent(nsDiskCacheDevice *device) : mDevice(device) {} diff --git a/netwerk/cache/nsDiskCacheDeviceSQL.cpp b/netwerk/cache/nsDiskCacheDeviceSQL.cpp index 4fbbc6451f..0f8c3a1761 100644 --- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp +++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp @@ -244,7 +244,7 @@ nsOfflineCacheEvictionFunction::Apply() Reset(); } -class nsOfflineCacheDiscardCache : public nsRunnable +class nsOfflineCacheDiscardCache : public Runnable { public: nsOfflineCacheDiscardCache(nsOfflineCacheDevice *device, @@ -866,7 +866,7 @@ nsApplicationCache::GetUsage(uint32_t *usage) * nsCloseDBEvent *****************************************************************************/ -class nsCloseDBEvent : public nsRunnable { +class nsCloseDBEvent : public Runnable { public: explicit nsCloseDBEvent(mozIStorageConnection *aDB) { diff --git a/netwerk/cache2/CacheEntry.h b/netwerk/cache2/CacheEntry.h index 1aeed08117..7ff8d90849 100644 --- a/netwerk/cache2/CacheEntry.h +++ b/netwerk/cache2/CacheEntry.h @@ -181,7 +181,7 @@ private: // Since OnCacheEntryAvailable must be invoked on the main thread // we need a runnable for it... - class AvailableCallbackRunnable : public nsRunnable + class AvailableCallbackRunnable : public Runnable { public: AvailableCallbackRunnable(CacheEntry* aEntry, @@ -203,7 +203,7 @@ private: // Since OnCacheEntryDoomed must be invoked on the main thread // we need a runnable for it... - class DoomCallbackRunnable : public nsRunnable + class DoomCallbackRunnable : public Runnable { public: DoomCallbackRunnable(CacheEntry* aEntry, nsresult aRv) @@ -393,7 +393,7 @@ private: }; -class CacheOutputCloseListener final : public nsRunnable +class CacheOutputCloseListener final : public Runnable { public: void OnOutputClosed(); diff --git a/netwerk/cache2/CacheFile.cpp b/netwerk/cache2/CacheFile.cpp index 2fc4fae7fb..f6efda7b84 100644 --- a/netwerk/cache2/CacheFile.cpp +++ b/netwerk/cache2/CacheFile.cpp @@ -27,7 +27,7 @@ namespace mozilla { namespace net { -class NotifyCacheFileListenerEvent : public nsRunnable { +class NotifyCacheFileListenerEvent : public Runnable { public: NotifyCacheFileListenerEvent(CacheFileListener *aCallback, nsresult aResult, @@ -64,7 +64,7 @@ protected: bool mIsNew; }; -class NotifyChunkListenerEvent : public nsRunnable { +class NotifyChunkListenerEvent : public Runnable { public: NotifyChunkListenerEvent(CacheFileChunkListener *aCallback, nsresult aResult, diff --git a/netwerk/cache2/CacheFileChunk.cpp b/netwerk/cache2/CacheFileChunk.cpp index 97987f645d..4b090a846d 100644 --- a/netwerk/cache2/CacheFileChunk.cpp +++ b/netwerk/cache2/CacheFileChunk.cpp @@ -13,7 +13,7 @@ namespace net { #define kMinBufSize 512 -class NotifyUpdateListenerEvent : public nsRunnable { +class NotifyUpdateListenerEvent : public Runnable { public: NotifyUpdateListenerEvent(CacheFileChunkListener *aCallback, CacheFileChunk *aChunk) @@ -663,7 +663,7 @@ CacheFileChunk::BufForReading() const return mBuf ? mBuf : mRWBuf; } -MOZ_WARN_UNUSED_RESULT nsresult +MOZ_MUST_USE nsresult CacheFileChunk::EnsureBufSize(uint32_t aBufSize) { mFile->AssertOwnsLock(); diff --git a/netwerk/cache2/CacheFileIOManager.cpp b/netwerk/cache2/CacheFileIOManager.cpp index 706352d569..4b0ada8d42 100644 --- a/netwerk/cache2/CacheFileIOManager.cpp +++ b/netwerk/cache2/CacheFileIOManager.cpp @@ -530,7 +530,7 @@ CacheFileHandles::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const // Events -class ShutdownEvent : public nsRunnable { +class ShutdownEvent : public Runnable { public: ShutdownEvent() : mMonitor("ShutdownEvent.mMonitor") @@ -595,7 +595,7 @@ protected: bool mPrepare; }; -class OpenFileEvent : public nsRunnable { +class OpenFileEvent : public Runnable { public: OpenFileEvent(const nsACString &aKey, uint32_t aFlags, CacheFileIOListener *aCallback) @@ -655,7 +655,7 @@ protected: nsCString mKey; }; -class ReadEvent : public nsRunnable { +class ReadEvent : public Runnable { public: ReadEvent(CacheFileHandle *aHandle, int64_t aOffset, char *aBuf, int32_t aCount, CacheFileIOListener *aCallback) @@ -698,7 +698,7 @@ protected: nsCOMPtr mCallback; }; -class WriteEvent : public nsRunnable { +class WriteEvent : public Runnable { public: WriteEvent(CacheFileHandle *aHandle, int64_t aOffset, const char *aBuf, int32_t aCount, bool aValidate, bool aTruncate, @@ -765,7 +765,7 @@ protected: nsCOMPtr mCallback; }; -class DoomFileEvent : public nsRunnable { +class DoomFileEvent : public Runnable { public: DoomFileEvent(CacheFileHandle *aHandle, CacheFileIOListener *aCallback) @@ -805,7 +805,7 @@ protected: RefPtr mHandle; }; -class DoomFileByKeyEvent : public nsRunnable { +class DoomFileByKeyEvent : public Runnable { public: DoomFileByKeyEvent(const nsACString &aKey, CacheFileIOListener *aCallback) @@ -851,7 +851,7 @@ protected: RefPtr mIOMan; }; -class ReleaseNSPRHandleEvent : public nsRunnable { +class ReleaseNSPRHandleEvent : public Runnable { public: explicit ReleaseNSPRHandleEvent(CacheFileHandle *aHandle) : mHandle(aHandle) @@ -879,7 +879,7 @@ protected: RefPtr mHandle; }; -class TruncateSeekSetEOFEvent : public nsRunnable { +class TruncateSeekSetEOFEvent : public Runnable { public: TruncateSeekSetEOFEvent(CacheFileHandle *aHandle, int64_t aTruncatePos, int64_t aEOFPos, CacheFileIOListener *aCallback) @@ -923,7 +923,7 @@ protected: nsCOMPtr mCallback; }; -class RenameFileEvent : public nsRunnable { +class RenameFileEvent : public Runnable { public: RenameFileEvent(CacheFileHandle *aHandle, const nsACString &aNewName, CacheFileIOListener *aCallback) @@ -965,7 +965,7 @@ protected: nsCOMPtr mCallback; }; -class InitIndexEntryEvent : public nsRunnable { +class InitIndexEntryEvent : public Runnable { public: InitIndexEntryEvent(CacheFileHandle *aHandle, uint32_t aAppId, bool aAnonymous, bool aInBrowser, bool aPinning) @@ -1011,7 +1011,7 @@ protected: bool mPinning; }; -class UpdateIndexEntryEvent : public nsRunnable { +class UpdateIndexEntryEvent : public Runnable { public: UpdateIndexEntryEvent(CacheFileHandle *aHandle, const uint32_t *aFrecency, const uint32_t *aExpirationTime) @@ -1058,7 +1058,7 @@ protected: uint32_t mExpirationTime; }; -class MetadataWriteScheduleEvent : public nsRunnable +class MetadataWriteScheduleEvent : public Runnable { public: enum EMode { @@ -2848,7 +2848,7 @@ CacheFileIOManager::EvictAll() namespace { -class EvictionNotifierRunnable : public nsRunnable +class EvictionNotifierRunnable : public Runnable { public: NS_DECL_NSIRUNNABLE @@ -4025,7 +4025,7 @@ namespace { // to safely get handles memory report. // We must do this, since the handle list is only accessed and managed w/o // locking on the I/O thread. That is by design. -class SizeOfHandlesRunnable : public nsRunnable +class SizeOfHandlesRunnable : public Runnable { public: SizeOfHandlesRunnable(mozilla::MallocSizeOf mallocSizeOf, diff --git a/netwerk/cache2/CacheIndex.h b/netwerk/cache2/CacheIndex.h index 00b507434a..b67a97353f 100644 --- a/netwerk/cache2/CacheIndex.h +++ b/netwerk/cache2/CacheIndex.h @@ -1029,7 +1029,7 @@ private: // any intermediate cache size. bool mAsyncGetDiskConsumptionBlocked; - class DiskConsumptionObserver : public nsRunnable + class DiskConsumptionObserver : public Runnable { public: static DiskConsumptionObserver* Init(nsICacheStorageConsumptionObserver* aObserver) diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp index 3ec729df8f..a71d76ab12 100644 --- a/netwerk/cache2/CacheStorageService.cpp +++ b/netwerk/cache2/CacheStorageService.cpp @@ -175,7 +175,7 @@ namespace { // WalkCacheRunnable // Base class for particular storage entries visiting -class WalkCacheRunnable : public nsRunnable +class WalkCacheRunnable : public Runnable , public CacheStorageService::EntryInfoCallback { protected: @@ -357,7 +357,7 @@ public: private: // Invokes OnCacheEntryInfo callback for each single found entry. // There is one instance of this class per one entry. - class OnCacheEntryInfoRunnable : public nsRunnable + class OnCacheEntryInfoRunnable : public Runnable { public: explicit OnCacheEntryInfoRunnable(WalkDiskCacheRunnable* aWalker) @@ -526,7 +526,7 @@ void CacheStorageService::DropPrivateBrowsingEntries() namespace { -class CleaupCacheDirectoriesRunnable : public nsRunnable +class CleaupCacheDirectoriesRunnable : public Runnable { public: NS_DECL_NSIRUNNABLE @@ -1700,7 +1700,7 @@ CacheStorageService::DoomStorageEntry(CacheStorage const* aStorage, return NS_OK; } - class Callback : public nsRunnable + class Callback : public Runnable { public: explicit Callback(nsICacheEntryDoomCallback* aCallback) : mCallback(aCallback) { } @@ -1713,7 +1713,7 @@ CacheStorageService::DoomStorageEntry(CacheStorage const* aStorage, }; if (aCallback) { - RefPtr callback = new Callback(aCallback); + RefPtr callback = new Callback(aCallback); return NS_DispatchToMainThread(callback); } @@ -1824,7 +1824,7 @@ CacheStorageService::DoomStorageEntries(nsCSubstring const& aContextKey, // probably no need for a callback - has no meaning. But for compatibility // with the old cache that is still in the tree we keep the API similar to be // able to make tests as well as other consumers work for now. - class Callback : public nsRunnable + class Callback : public Runnable { public: explicit Callback(nsICacheEntryDoomCallback* aCallback) : mCallback(aCallback) { } @@ -1837,7 +1837,7 @@ CacheStorageService::DoomStorageEntries(nsCSubstring const& aContextKey, }; if (aCallback) { - RefPtr callback = new Callback(aCallback); + RefPtr callback = new Callback(aCallback); return NS_DispatchToMainThread(callback); } diff --git a/netwerk/cache2/CacheStorageService.h b/netwerk/cache2/CacheStorageService.h index 229fb57f0f..2b2da46f3b 100644 --- a/netwerk/cache2/CacheStorageService.h +++ b/netwerk/cache2/CacheStorageService.h @@ -347,7 +347,7 @@ private: nsCOMPtr mPurgeTimer; - class PurgeFromMemoryRunnable : public nsRunnable + class PurgeFromMemoryRunnable : public Runnable { public: PurgeFromMemoryRunnable(CacheStorageService* aService, uint32_t aWhat) @@ -363,7 +363,7 @@ private: }; // nsICacheTesting - class IOThreadSuspender : public nsRunnable + class IOThreadSuspender : public Runnable { public: IOThreadSuspender() : mMon("IOThreadSuspender"), mSignaled(false) { } diff --git a/netwerk/cache2/OldWrappers.cpp b/netwerk/cache2/OldWrappers.cpp index 8a12c03dee..da23efcd25 100644 --- a/netwerk/cache2/OldWrappers.cpp +++ b/netwerk/cache2/OldWrappers.cpp @@ -35,7 +35,7 @@ namespace { // Fires the doom callback back on the main thread // after the cache I/O thread is looped. -class DoomCallbackSynchronizer : public nsRunnable +class DoomCallbackSynchronizer : public Runnable { public: explicit DoomCallbackSynchronizer(nsICacheEntryDoomCallback* cb) : mCB(cb) @@ -300,7 +300,7 @@ nsresult _OldGetDiskConsumption::Get(nsICacheStorageConsumptionObserver* aCallba } NS_IMPL_ISUPPORTS_INHERITED(_OldGetDiskConsumption, - nsRunnable, + Runnable, nsICacheVisitor) _OldGetDiskConsumption::_OldGetDiskConsumption( @@ -652,7 +652,7 @@ GetCacheSession(nsCSubstring const &aScheme, } // namespace -NS_IMPL_ISUPPORTS_INHERITED(_OldCacheLoad, nsRunnable, nsICacheListener) +NS_IMPL_ISUPPORTS_INHERITED(_OldCacheLoad, Runnable, nsICacheListener) _OldCacheLoad::_OldCacheLoad(nsCSubstring const& aScheme, nsCSubstring const& aCacheKey, diff --git a/netwerk/cache2/OldWrappers.h b/netwerk/cache2/OldWrappers.h index b1979a8808..33c7d9b71e 100644 --- a/netwerk/cache2/OldWrappers.h +++ b/netwerk/cache2/OldWrappers.h @@ -148,7 +148,7 @@ private: }; -class _OldCacheLoad : public nsRunnable +class _OldCacheLoad : public Runnable , public nsICacheListener { public: @@ -246,7 +246,7 @@ private: bool mHit; // set to true when the device was found }; -class _OldGetDiskConsumption : public nsRunnable, +class _OldGetDiskConsumption : public Runnable, public nsICacheVisitor { public: diff --git a/netwerk/cookie/CookieServiceParent.cpp b/netwerk/cookie/CookieServiceParent.cpp index 5eca99d3a4..9d4295c420 100644 --- a/netwerk/cookie/CookieServiceParent.cpp +++ b/netwerk/cookie/CookieServiceParent.cpp @@ -66,7 +66,7 @@ CreateDummyChannel(nsIURI* aHostURI, OriginAttributes &aAttrs, bool aIsPrivate, namespace mozilla { namespace net { -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE bool CookieServiceParent::GetOriginAttributesFromParams(const IPC::SerializedLoadContext &aLoadContext, OriginAttributes& aAttrs, diff --git a/netwerk/cookie/CookieServiceParent.h b/netwerk/cookie/CookieServiceParent.h index cf71f9f5d7..294381a07d 100644 --- a/netwerk/cookie/CookieServiceParent.h +++ b/netwerk/cookie/CookieServiceParent.h @@ -22,7 +22,7 @@ public: virtual ~CookieServiceParent(); protected: - MOZ_WARN_UNUSED_RESULT bool + MOZ_MUST_USE bool GetOriginAttributesFromParams(const IPC::SerializedLoadContext &aLoadContext, OriginAttributes& aAttrs, bool& aIsPrivate); diff --git a/netwerk/dns/DNSListenerProxy.h b/netwerk/dns/DNSListenerProxy.h index 76761a7732..307dde0f71 100644 --- a/netwerk/dns/DNSListenerProxy.h +++ b/netwerk/dns/DNSListenerProxy.h @@ -36,7 +36,7 @@ public: NS_DECL_NSIDNSLISTENER NS_DECL_NSIDNSLISTENERPROXY - class OnLookupCompleteRunnable : public nsRunnable + class OnLookupCompleteRunnable : public Runnable { public: OnLookupCompleteRunnable(const nsMainThreadPtrHandle& aListener, diff --git a/netwerk/dns/DNSRequestChild.cpp b/netwerk/dns/DNSRequestChild.cpp index 3550955810..44b27eb8fe 100644 --- a/netwerk/dns/DNSRequestChild.cpp +++ b/netwerk/dns/DNSRequestChild.cpp @@ -159,7 +159,7 @@ ChildDNSRecord::ReportUnusable(uint16_t aPort) // CancelDNSRequestEvent //----------------------------------------------------------------------------- -class CancelDNSRequestEvent : public nsRunnable +class CancelDNSRequestEvent : public Runnable { public: CancelDNSRequestEvent(DNSRequestChild* aDnsReq, nsresult aReason) diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderReply.h b/netwerk/dns/mdns/libmdns/MDNSResponderReply.h index 57d3cb02ef..f412bc46b1 100644 --- a/netwerk/dns/mdns/libmdns/MDNSResponderReply.h +++ b/netwerk/dns/mdns/libmdns/MDNSResponderReply.h @@ -17,7 +17,7 @@ namespace mozilla { namespace net { -class BrowseReplyRunnable final : public nsRunnable +class BrowseReplyRunnable final : public Runnable { public: BrowseReplyRunnable(DNSServiceRef aSdRef, @@ -51,7 +51,7 @@ private: RefPtr mContext; }; -class RegisterReplyRunnable final : public nsRunnable +class RegisterReplyRunnable final : public Runnable { public: RegisterReplyRunnable(DNSServiceRef aSdRef, @@ -82,7 +82,7 @@ private: RefPtr mContext; }; -class ResolveReplyRunnable final : public nsRunnable +class ResolveReplyRunnable final : public Runnable { public: ResolveReplyRunnable(DNSServiceRef aSdRef, @@ -123,7 +123,7 @@ private: RefPtr mContext; }; -class GetAddrInfoReplyRunnable final : public nsRunnable +class GetAddrInfoReplyRunnable final : public Runnable { public: GetAddrInfoReplyRunnable(DNSServiceRef aSdRef, diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index 37f4b35676..d205bd65e6 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -450,7 +450,7 @@ nsDNSSyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const return n; } -class NotifyDNSResolution: public nsRunnable +class NotifyDNSResolution: public Runnable { public: explicit NotifyDNSResolution(const nsACString &aHostname) diff --git a/netwerk/ipc/NeckoParent.h b/netwerk/ipc/NeckoParent.h index c548b1b6e0..f9795748a0 100644 --- a/netwerk/ipc/NeckoParent.h +++ b/netwerk/ipc/NeckoParent.h @@ -35,7 +35,7 @@ public: NeckoParent(); virtual ~NeckoParent(); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static const char * GetValidatedAppInfo(const SerializedLoadContext& aSerialized, PContentParent* aBrowser, @@ -48,7 +48,7 @@ public: * * Returns null if successful, or an error string if failed. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE static const char* CreateChannelLoadContext(const PBrowserOrId& aBrowser, PContentParent* aContent, diff --git a/netwerk/ipc/RemoteOpenFileChild.cpp b/netwerk/ipc/RemoteOpenFileChild.cpp index 8678036652..e74da98b57 100644 --- a/netwerk/ipc/RemoteOpenFileChild.cpp +++ b/netwerk/ipc/RemoteOpenFileChild.cpp @@ -35,7 +35,7 @@ namespace net { // Helper class to dispatch events async on windows/OSX //----------------------------------------------------------------------------- -class CallsListenerInNewEvent : public nsRunnable +class CallsListenerInNewEvent : public Runnable { public: CallsListenerInNewEvent(nsIRemoteOpenFileListener *aListener, nsresult aRv) diff --git a/netwerk/protocol/app/AppProtocolHandler.cpp b/netwerk/protocol/app/AppProtocolHandler.cpp index a7291a8a58..27235f4892 100644 --- a/netwerk/protocol/app/AppProtocolHandler.cpp +++ b/netwerk/protocol/app/AppProtocolHandler.cpp @@ -28,7 +28,7 @@ using namespace mozilla; * containing an unknown appId. */ class DummyChannel : public nsIJARChannel - , nsRunnable + , Runnable { public: NS_DECL_ISUPPORTS_INHERITED @@ -52,7 +52,7 @@ private: nsCOMPtr mLoadInfo; }; -NS_IMPL_ISUPPORTS_INHERITED(DummyChannel, nsRunnable, nsIRequest, nsIChannel, nsIJARChannel) +NS_IMPL_ISUPPORTS_INHERITED(DummyChannel, Runnable, nsIRequest, nsIChannel, nsIJARChannel) DummyChannel::DummyChannel() : mPending(false) , mSuspendCount(0) diff --git a/netwerk/protocol/file/nsFileChannel.cpp b/netwerk/protocol/file/nsFileChannel.cpp index 5103cf0e87..8368161a01 100644 --- a/netwerk/protocol/file/nsFileChannel.cpp +++ b/netwerk/protocol/file/nsFileChannel.cpp @@ -33,7 +33,7 @@ using namespace mozilla::net; //----------------------------------------------------------------------------- -class nsFileCopyEvent : public nsRunnable { +class nsFileCopyEvent : public Runnable { public: nsFileCopyEvent(nsIOutputStream *dest, nsIInputStream *source, int64_t len) : mDest(dest) diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp index 037d9f4ea1..cd2013c602 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -782,7 +782,7 @@ FTPChannelParent::StartDiversion() } } -class FTPFailDiversionEvent : public nsRunnable +class FTPFailDiversionEvent : public Runnable { public: FTPFailDiversionEvent(FTPChannelParent *aChannelParent, diff --git a/netwerk/protocol/ftp/nsFTPChannel.cpp b/netwerk/protocol/ftp/nsFTPChannel.cpp index 8f0ad71dee..2a0f049153 100644 --- a/netwerk/protocol/ftp/nsFTPChannel.cpp +++ b/netwerk/protocol/ftp/nsFTPChannel.cpp @@ -145,7 +145,7 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIFTPEVENTSINK - class OnFTPControlLogRunnable : public nsRunnable + class OnFTPControlLogRunnable : public Runnable { public: OnFTPControlLogRunnable(nsIFTPEventSink* aTarget, diff --git a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp index 317495863e..fc08ab1d3b 100644 --- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp @@ -1793,7 +1793,7 @@ nsFtpState::KillControlConnection() mControlConnection = nullptr; } -class nsFtpAsyncAlert : public nsRunnable +class nsFtpAsyncAlert : public Runnable { public: nsFtpAsyncAlert(nsIPrompt *aPrompter, nsString aResponseMsg) @@ -2131,7 +2131,7 @@ nsFtpState::SaveNetworkStats(bool enforce) // Create the event to save the network statistics. // the event is then dispathed to the main thread. - RefPtr event = + RefPtr event = new SaveNetworkStatsEvent(appId, isInBrowser, mActiveNetworkInfo, mCountRecv, 0, false); NS_DispatchToMainThread(event); diff --git a/netwerk/protocol/http/AlternateServices.cpp b/netwerk/protocol/http/AlternateServices.cpp index bfe97a8446..0464db8c8a 100644 --- a/netwerk/protocol/http/AlternateServices.cpp +++ b/netwerk/protocol/http/AlternateServices.cpp @@ -463,7 +463,7 @@ AltSvcCache::GetAltServiceMapping(const nsACString &scheme, const nsACString &ho return nullptr; } -class ProxyClearHostMapping : public nsRunnable { +class ProxyClearHostMapping : public Runnable { public: explicit ProxyClearHostMapping(const nsACString &host, int32_t port) : mHost(host) diff --git a/netwerk/protocol/http/Http2Push.cpp b/netwerk/protocol/http/Http2Push.cpp index e81b8be332..1335521ac0 100644 --- a/netwerk/protocol/http/Http2Push.cpp +++ b/netwerk/protocol/http/Http2Push.cpp @@ -23,7 +23,7 @@ namespace mozilla { namespace net { -class CallChannelOnPush final : public nsRunnable { +class CallChannelOnPush final : public Runnable { public: CallChannelOnPush(nsIHttpChannelInternal *associatedChannel, const nsACString &pushedURI, diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index 6603cb4dd1..2cd352e517 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -2005,7 +2005,7 @@ Http2Session::RecvContinuation(Http2Session *self) return RecvPushPromise(self); } -class UpdateAltSvcEvent : public nsRunnable +class UpdateAltSvcEvent : public Runnable { public: UpdateAltSvcEvent(const nsCString &header, diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index fda0cea33c..cd500826c1 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -1949,7 +1949,7 @@ HttpBaseChannel::GetResponseVersion(uint32_t *major, uint32_t *minor) namespace { -class CookieNotifierRunnable : public nsRunnable +class CookieNotifierRunnable : public Runnable { public: CookieNotifierRunnable(HttpBaseChannel* aChannel, char const * aCookie) diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index bea1ec6d04..4a1458c963 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1500,7 +1500,7 @@ HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener, // HttpChannelChild::nsIAsyncVerifyRedirectCallback //----------------------------------------------------------------------------- -class OverrideRunnable : public nsRunnable { +class OverrideRunnable : public Runnable { RefPtr mChannel; RefPtr mNewChannel; RefPtr mListener; diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 318c902560..0963734fe5 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -1493,7 +1493,7 @@ HttpChannelParent::StartDiversion() } } -class HTTPFailDiversionEvent : public nsRunnable +class HTTPFailDiversionEvent : public Runnable { public: HTTPFailDiversionEvent(HttpChannelParent *aChannelParent, diff --git a/netwerk/protocol/http/HttpChannelParentListener.cpp b/netwerk/protocol/http/HttpChannelParentListener.cpp index ab7e54881b..37b0ad9a8f 100644 --- a/netwerk/protocol/http/HttpChannelParentListener.cpp +++ b/netwerk/protocol/http/HttpChannelParentListener.cpp @@ -277,7 +277,7 @@ public: NS_IMPL_ISUPPORTS(HeaderVisitor, nsIHttpHeaderVisitor) -class FinishSynthesizedResponse : public nsRunnable +class FinishSynthesizedResponse : public Runnable { nsCOMPtr mChannel; public: diff --git a/netwerk/protocol/http/nsHttpActivityDistributor.cpp b/netwerk/protocol/http/nsHttpActivityDistributor.cpp index ab13509775..414326179c 100644 --- a/netwerk/protocol/http/nsHttpActivityDistributor.cpp +++ b/netwerk/protocol/http/nsHttpActivityDistributor.cpp @@ -17,7 +17,7 @@ typedef nsMainThreadPtrHolder ObserverHolder; typedef nsMainThreadPtrHandle ObserverHandle; typedef nsTArray ObserverArray; -class nsHttpActivityEvent : public nsRunnable +class nsHttpActivityEvent : public Runnable { public: nsHttpActivityEvent(nsISupports *aHttpChannel, diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 3090ac7e5a..9420abe779 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -6184,7 +6184,7 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st // nsHttpChannel::nsIStreamListener //----------------------------------------------------------------------------- -class OnTransportStatusAsyncEvent : public nsRunnable +class OnTransportStatusAsyncEvent : public Runnable { public: OnTransportStatusAsyncEvent(nsITransportEventSink* aEventSink, diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index 6e420f3c0b..cf3f12dd60 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -1447,7 +1447,7 @@ nsHttpConnection::ResumeRecv() } -class HttpConnectionForceIO : public nsRunnable +class HttpConnectionForceIO : public Runnable { public: HttpConnectionForceIO(nsHttpConnection *aConn, bool doRecv) diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index d94fdf4bc8..4e47f8def0 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -191,7 +191,7 @@ nsHttpConnectionMgr::Shutdown() return NS_OK; } -class ConnEvent : public nsRunnable +class ConnEvent : public Runnable { public: ConnEvent(nsHttpConnectionMgr *mgr, diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 1a834ae89f..94e6163cc8 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -917,7 +917,7 @@ nsHttpTransaction::SaveNetworkStats(bool enforce) // Create the event to save the network statistics. // the event is then dispathed to the main thread. - RefPtr event = + RefPtr event = new SaveNetworkStatsEvent(mAppId, mIsInBrowser, mActiveNetworkInfo, mCountRecv, mCountSent, false); NS_DispatchToMainThread(event); @@ -2129,7 +2129,7 @@ nsHttpTransaction::GetResponseEnd() // nsHttpTransaction deletion event //----------------------------------------------------------------------------- -class DeleteHttpTransaction : public nsRunnable { +class DeleteHttpTransaction : public Runnable { public: explicit DeleteHttpTransaction(nsHttpTransaction *trans) : mTrans(trans) diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index aa2473c221..a052b647a0 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -201,7 +201,7 @@ private: void ReuseConnectionOnRestartOK(bool reuseOk) override { mReuseOnRestart = reuseOk; } private: - class UpdateSecurityCallbacks : public nsRunnable + class UpdateSecurityCallbacks : public Runnable { public: UpdateSecurityCallbacks(nsHttpTransaction* aTrans, diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index d87a1e64f4..ea25ec73cd 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -2241,7 +2241,7 @@ WebSocketChannel::EnsureHdrOut(uint32_t size) namespace { -class RemoveObserverRunnable : public nsRunnable +class RemoveObserverRunnable : public Runnable { RefPtr mChannel; @@ -3943,7 +3943,7 @@ WebSocketChannel::SaveNetworkStats(bool enforce) // Create the event to save the network statistics. // the event is then dispathed to the main thread. - RefPtr event = + RefPtr event = new SaveNetworkStatsEvent(mAppId, mIsInBrowser, mActiveNetworkInfo, countRecv, countSent, false); NS_DispatchToMainThread(event); diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.cpp b/netwerk/protocol/websocket/WebSocketChannelChild.cpp index 48f02ee8aa..d98167db75 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp @@ -128,7 +128,7 @@ WebSocketChannelChild::IsEncrypted() const return mEncrypted; } -class WrappedChannelEvent : public nsRunnable +class WrappedChannelEvent : public Runnable { public: explicit WrappedChannelEvent(ChannelEvent *aChannelEvent) @@ -479,7 +479,7 @@ WebSocketChannelChild::AsyncOpen(nsIURI *aURI, return NS_OK; } -class CloseEvent : public nsRunnable +class CloseEvent : public Runnable { public: CloseEvent(WebSocketChannelChild *aChild, @@ -527,7 +527,7 @@ WebSocketChannelChild::Close(uint16_t code, const nsACString & reason) return NS_OK; } -class MsgEvent : public nsRunnable +class MsgEvent : public Runnable { public: MsgEvent(WebSocketChannelChild *aChild, @@ -602,7 +602,7 @@ WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg) return NS_OK; } -class BinaryStreamEvent : public nsRunnable +class BinaryStreamEvent : public Runnable { public: BinaryStreamEvent(WebSocketChannelChild *aChild, diff --git a/netwerk/protocol/websocket/WebSocketEventService.cpp b/netwerk/protocol/websocket/WebSocketEventService.cpp index 79f74e0170..a7c9723809 100644 --- a/netwerk/protocol/websocket/WebSocketEventService.cpp +++ b/netwerk/protocol/websocket/WebSocketEventService.cpp @@ -32,7 +32,7 @@ IsChildProcess() } // anonymous namespace -class WebSocketBaseRunnable : public nsRunnable +class WebSocketBaseRunnable : public Runnable { public: WebSocketBaseRunnable(uint32_t aWebSocketSerialID, diff --git a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp index 4e15668756..c73bf4287d 100644 --- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp +++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp @@ -34,7 +34,7 @@ typedef mozilla::net::LoadContextInfo LoadContextInfo; // Must release mChannel on the main thread -class nsWyciwygAsyncEvent : public nsRunnable { +class nsWyciwygAsyncEvent : public mozilla::Runnable { public: explicit nsWyciwygAsyncEvent(nsWyciwygChannel *aChannel) : mChannel(aChannel) {} diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp index 4df90e6946..ef8e297397 100644 --- a/netwerk/sctp/datachannel/DataChannel.cpp +++ b/netwerk/sctp/datachannel/DataChannel.cpp @@ -2307,7 +2307,7 @@ DataChannelConnection::SendBinary(DataChannel *channel, const char *data, return SendMsgInternal(channel, data, len, ppid_final); } -class ReadBlobRunnable : public nsRunnable { +class ReadBlobRunnable : public Runnable { public: ReadBlobRunnable(DataChannelConnection* aConnection, uint16_t aStream, nsIInputStream* aBlob) : @@ -2352,7 +2352,7 @@ DataChannelConnection::SendBlob(uint16_t stream, nsIInputStream *aBlob) return 0; } -class DataChannelBlobSendRunnable : public nsRunnable +class DataChannelBlobSendRunnable : public Runnable { public: DataChannelBlobSendRunnable(already_AddRefed& aConnection, diff --git a/netwerk/sctp/datachannel/DataChannel.h b/netwerk/sctp/datachannel/DataChannel.h index f4412973e2..d5fa3fb0e6 100644 --- a/netwerk/sctp/datachannel/DataChannel.h +++ b/netwerk/sctp/datachannel/DataChannel.h @@ -143,7 +143,7 @@ public: PARTIAL_RELIABLE_TIMED = 2 } Type; - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE already_AddRefed Open(const nsACString& label, const nsACString& protocol, Type type, bool inOrder, @@ -444,7 +444,7 @@ private: // used to dispatch notifications of incoming data to the main thread // Patterned on CallOnMessageAvailable in WebSockets // Also used to proxy other items to MainThread -class DataChannelOnMessageAvailable : public nsRunnable +class DataChannelOnMessageAvailable : public Runnable { public: enum { diff --git a/netwerk/system/linux/nsNotifyAddrListener_Linux.cpp b/netwerk/system/linux/nsNotifyAddrListener_Linux.cpp index 7099c02565..ef919f8190 100644 --- a/netwerk/system/linux/nsNotifyAddrListener_Linux.cpp +++ b/netwerk/system/linux/nsNotifyAddrListener_Linux.cpp @@ -340,7 +340,7 @@ nsNotifyAddrListener::Observe(nsISupports *subject, } #ifdef MOZ_NUWA_PROCESS -class NuwaMarkLinkMonitorThreadRunner : public nsRunnable +class NuwaMarkLinkMonitorThreadRunner : public Runnable { NS_IMETHODIMP Run() override { diff --git a/netwerk/system/linux/nsNotifyAddrListener_Linux.h b/netwerk/system/linux/nsNotifyAddrListener_Linux.h index 1b3a5006ff..dcbfee94a5 100644 --- a/netwerk/system/linux/nsNotifyAddrListener_Linux.h +++ b/netwerk/system/linux/nsNotifyAddrListener_Linux.h @@ -41,7 +41,7 @@ public: nsresult Init(void); private: - class ChangeEvent : public nsRunnable { + class ChangeEvent : public mozilla::Runnable { public: NS_DECL_NSIRUNNABLE ChangeEvent(nsINetworkLinkService *aService, const char *aEventID) diff --git a/netwerk/system/win32/nsNotifyAddrListener.h b/netwerk/system/win32/nsNotifyAddrListener.h index 702d7132d2..5521ecf19a 100644 --- a/netwerk/system/win32/nsNotifyAddrListener.h +++ b/netwerk/system/win32/nsNotifyAddrListener.h @@ -34,7 +34,7 @@ public: void CheckLinkStatus(void); protected: - class ChangeEvent : public nsRunnable { + class ChangeEvent : public mozilla::Runnable { public: NS_DECL_NSIRUNNABLE ChangeEvent(nsINetworkLinkService *aService, const char *aEventID) diff --git a/parser/html/nsHtml5RefPtr.h b/parser/html/nsHtml5RefPtr.h index 89e5692481..27f8de65e7 100644 --- a/parser/html/nsHtml5RefPtr.h +++ b/parser/html/nsHtml5RefPtr.h @@ -9,7 +9,7 @@ #include "nsThreadUtils.h" template -class nsHtml5RefPtrReleaser : public nsRunnable +class nsHtml5RefPtrReleaser : public mozilla::Runnable { private: T* mPtr; diff --git a/parser/html/nsHtml5SVGLoadDispatcher.h b/parser/html/nsHtml5SVGLoadDispatcher.h index 475ae7645c..3f1b1cd045 100644 --- a/parser/html/nsHtml5SVGLoadDispatcher.h +++ b/parser/html/nsHtml5SVGLoadDispatcher.h @@ -8,7 +8,7 @@ #include "nsThreadUtils.h" #include "nsIContent.h" -class nsHtml5SVGLoadDispatcher : public nsRunnable +class nsHtml5SVGLoadDispatcher : public mozilla::Runnable { private: nsCOMPtr mElement; diff --git a/parser/html/nsHtml5StreamParser.cpp b/parser/html/nsHtml5StreamParser.cpp index f17bd46afd..bc17e23844 100644 --- a/parser/html/nsHtml5StreamParser.cpp +++ b/parser/html/nsHtml5StreamParser.cpp @@ -114,7 +114,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHtml5StreamParser) } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -class nsHtml5ExecutorFlusher : public nsRunnable +class nsHtml5ExecutorFlusher : public Runnable { private: RefPtr mExecutor; @@ -131,7 +131,7 @@ class nsHtml5ExecutorFlusher : public nsRunnable } }; -class nsHtml5LoadFlusher : public nsRunnable +class nsHtml5LoadFlusher : public Runnable { private: RefPtr mExecutor; @@ -1041,7 +1041,7 @@ nsHtml5StreamParser::DoStopRequest() ParseAvailableData(); } -class nsHtml5RequestStopper : public nsRunnable +class nsHtml5RequestStopper : public Runnable { private: nsHtml5RefPtr mStreamParser; @@ -1123,7 +1123,7 @@ nsHtml5StreamParser::DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength) mFlushTimerArmed = true; } -class nsHtml5DataAvailable : public nsRunnable +class nsHtml5DataAvailable : public Runnable { private: nsHtml5RefPtr mStreamParser; @@ -1446,7 +1446,7 @@ nsHtml5StreamParser::ParseAvailableData() } } -class nsHtml5StreamParserContinuation : public nsRunnable +class nsHtml5StreamParserContinuation : public Runnable { private: nsHtml5RefPtr mStreamParser; @@ -1612,7 +1612,7 @@ nsHtml5StreamParser::ContinueAfterFailedCharsetSwitch() } } -class nsHtml5TimerKungFu : public nsRunnable +class nsHtml5TimerKungFu : public Runnable { private: nsHtml5RefPtr mStreamParser; diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 72c710edba..d3d8c8e34a 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -45,7 +45,7 @@ NS_IMPL_ADDREF_INHERITED(nsHtml5TreeOpExecutor, nsContentSink) NS_IMPL_RELEASE_INHERITED(nsHtml5TreeOpExecutor, nsContentSink) -class nsHtml5ExecutorReflusher : public nsRunnable +class nsHtml5ExecutorReflusher : public Runnable { private: RefPtr mExecutor; diff --git a/parser/htmlparser/nsParser.cpp b/parser/htmlparser/nsParser.cpp index 69c503e2f0..624a983f0d 100644 --- a/parser/htmlparser/nsParser.cpp +++ b/parser/htmlparser/nsParser.cpp @@ -108,7 +108,7 @@ For more details @see bugzilla bug 76722 */ -class nsParserContinueEvent : public nsRunnable +class nsParserContinueEvent : public Runnable { public: RefPtr mParser; diff --git a/security/manager/ssl/CryptoTask.h b/security/manager/ssl/CryptoTask.h index ce282d4be8..ae107fe307 100644 --- a/security/manager/ssl/CryptoTask.h +++ b/security/manager/ssl/CryptoTask.h @@ -41,7 +41,7 @@ namespace mozilla { * Dispatch or Skip. * */ -class CryptoTask : public nsRunnable, +class CryptoTask : public Runnable, public nsNSSShutDownObject { public: diff --git a/security/manager/ssl/DataStorage.cpp b/security/manager/ssl/DataStorage.cpp index 98efbdd490..72c9717a85 100644 --- a/security/manager/ssl/DataStorage.cpp +++ b/security/manager/ssl/DataStorage.cpp @@ -163,7 +163,7 @@ DataStorage::Init(bool& aDataWillPersist) return NS_OK; } -class DataStorage::Reader : public nsRunnable +class DataStorage::Reader : public Runnable { public: explicit Reader(DataStorage* aDataStorage) @@ -629,7 +629,7 @@ DataStorage::Remove(const nsCString& aKey, DataStorageType aType) }); } -class DataStorage::Writer : public nsRunnable +class DataStorage::Writer : public Runnable { public: Writer(nsCString& aData, DataStorage* aDataStorage) diff --git a/security/manager/ssl/PSMRunnable.h b/security/manager/ssl/PSMRunnable.h index d25b165cec..b43bc62c6b 100644 --- a/security/manager/ssl/PSMRunnable.h +++ b/security/manager/ssl/PSMRunnable.h @@ -15,7 +15,7 @@ namespace mozilla { namespace psm { // Wait for the event to run on the target thread without spinning the event // loop on the calling thread. (Dispatching events to a thread using // NS_DISPATCH_SYNC would cause the event loop on the calling thread to spin.) -class SyncRunnableBase : public nsRunnable +class SyncRunnableBase : public Runnable { public: NS_DECL_NSIRUNNABLE @@ -27,7 +27,7 @@ private: mozilla::Monitor monitor; }; -class NotifyObserverRunnable : public nsRunnable +class NotifyObserverRunnable : public Runnable { public: NotifyObserverRunnable(nsIObserver * observer, diff --git a/security/manager/ssl/SSLServerCertVerification.cpp b/security/manager/ssl/SSLServerCertVerification.cpp index 80033e52d5..c2b74c546a 100644 --- a/security/manager/ssl/SSLServerCertVerification.cpp +++ b/security/manager/ssl/SSLServerCertVerification.cpp @@ -231,7 +231,7 @@ LogInvalidCertError(nsNSSSocketInfo* socketInfo, // This will cause the PR_Poll in the STS thread to return, so things work // correctly even if the STS thread is blocked polling (only) on the file // descriptor that is waiting for this result. -class SSLServerCertVerificationResult : public nsRunnable +class SSLServerCertVerificationResult : public Runnable { public: NS_DECL_NSIRUNNABLE @@ -704,7 +704,7 @@ CreateCertErrorRunnable(CertVerifier& certVerifier, // TransportSecurityInfo::mCallbacks. nsHttpConnection::GetInterface must always // execute on the main thread, with the socket transport service thread // blocked. -class CertErrorRunnableRunnable : public nsRunnable +class CertErrorRunnableRunnable : public Runnable { public: explicit CertErrorRunnableRunnable(CertErrorRunnable* certErrorRunnable) @@ -726,7 +726,7 @@ private: RefPtr mCertErrorRunnable; }; -class SSLServerCertVerificationJob : public nsRunnable +class SSLServerCertVerificationJob : public Runnable { public: // Must be called only on the socket transport thread diff --git a/security/manager/ssl/nsCertVerificationThread.cpp b/security/manager/ssl/nsCertVerificationThread.cpp index 6f26d6b0b8..3cd67669c4 100644 --- a/security/manager/ssl/nsCertVerificationThread.cpp +++ b/security/manager/ssl/nsCertVerificationThread.cpp @@ -13,7 +13,7 @@ nsCertVerificationThread *nsCertVerificationThread::verification_thread_singleto NS_IMPL_ISUPPORTS(nsCertVerificationResult, nsICertVerificationResult) namespace { -class DispatchCertVerificationResult : public nsRunnable +class DispatchCertVerificationResult : public Runnable { public: DispatchCertVerificationResult(const nsMainThreadPtrHandle& aListener, diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp index 232baceeb4..587a6ec119 100644 --- a/security/manager/ssl/nsNSSCallbacks.cpp +++ b/security/manager/ssl/nsNSSCallbacks.cpp @@ -36,7 +36,7 @@ namespace { } // namespace -class nsHTTPDownloadEvent : public nsRunnable { +class nsHTTPDownloadEvent : public Runnable { public: nsHTTPDownloadEvent(); ~nsHTTPDownloadEvent(); @@ -163,7 +163,7 @@ nsHTTPDownloadEvent::Run() return NS_OK; } -struct nsCancelHTTPDownloadEvent : nsRunnable { +struct nsCancelHTTPDownloadEvent : Runnable { RefPtr mListener; NS_IMETHOD Run() { diff --git a/security/manager/ssl/nsNSSComponent.h b/security/manager/ssl/nsNSSComponent.h index d129ed43a7..e76d280a81 100644 --- a/security/manager/ssl/nsNSSComponent.h +++ b/security/manager/ssl/nsNSSComponent.h @@ -24,7 +24,7 @@ class SmartCardThreadList; namespace mozilla { namespace psm { -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE ::already_AddRefed GetDefaultCertVerifier(); diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp index 03aecf775d..eaff505e53 100644 --- a/security/manager/ssl/nsNSSIOLayer.cpp +++ b/security/manager/ssl/nsNSSIOLayer.cpp @@ -1702,7 +1702,7 @@ nsSSLIOLayerHelpers::addInsecureFallbackSite(const nsCString& hostname, Preferences::SetCString("security.tls.insecure_fallback_hosts", value); } -class FallbackPrefRemover final : public nsRunnable +class FallbackPrefRemover final : public Runnable { public: explicit FallbackPrefRemover(const nsACString& aHost) @@ -1750,7 +1750,7 @@ nsSSLIOLayerHelpers::removeInsecureFallbackSite(const nsACString& hostname, if (!isPublic()) { return; } - RefPtr runnable = new FallbackPrefRemover(hostname); + RefPtr runnable = new FallbackPrefRemover(hostname); if (NS_IsMainThread()) { runnable->Run(); } else { diff --git a/security/manager/ssl/nsPSMBackgroundThread.cpp b/security/manager/ssl/nsPSMBackgroundThread.cpp index 82dadbf7a8..bc2fb5523d 100644 --- a/security/manager/ssl/nsPSMBackgroundThread.cpp +++ b/security/manager/ssl/nsPSMBackgroundThread.cpp @@ -56,7 +56,7 @@ nsPSMBackgroundThread::postStoppedEventToMainThread( mExitState = ePSMThreadStopped; // requestExit is waiting for an event, so give it one. - return NS_DispatchToMainThread(new nsRunnable()); + return NS_DispatchToMainThread(new Runnable()); } void nsPSMBackgroundThread::requestExit() diff --git a/security/sandbox/linux/Sandbox.cpp b/security/sandbox/linux/Sandbox.cpp index 7754e2d333..e2a6ee9b3a 100644 --- a/security/sandbox/linux/Sandbox.cpp +++ b/security/sandbox/linux/Sandbox.cpp @@ -212,7 +212,7 @@ InstallSigSysHandler(void) * @see SandboxInfo * @see BroadcastSetThreadSandbox */ -static bool MOZ_WARN_UNUSED_RESULT +static bool MOZ_MUST_USE InstallSyscallFilter(const sock_fprog *aProg, bool aUseTSync) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { diff --git a/storage/StorageBaseStatementInternal.cpp b/storage/StorageBaseStatementInternal.cpp index f2c2bb5222..816881694f 100644 --- a/storage/StorageBaseStatementInternal.cpp +++ b/storage/StorageBaseStatementInternal.cpp @@ -21,7 +21,7 @@ namespace storage { /** * Used to finalize an asynchronous statement on the background thread. */ -class AsyncStatementFinalizer : public nsRunnable +class AsyncStatementFinalizer : public Runnable { public: /** @@ -62,7 +62,7 @@ private: * Finalize a sqlite3_stmt on the background thread for a statement whose * destructor was invoked and the statement was non-null. */ -class LastDitchSqliteStatementFinalizer : public nsRunnable +class LastDitchSqliteStatementFinalizer : public Runnable { public: /** diff --git a/storage/mozStorageAsyncStatementExecution.cpp b/storage/mozStorageAsyncStatementExecution.cpp index f8c1649b60..3b320fa671 100644 --- a/storage/mozStorageAsyncStatementExecution.cpp +++ b/storage/mozStorageAsyncStatementExecution.cpp @@ -50,7 +50,7 @@ typedef AsyncExecuteStatements::StatementDataArray StatementDataArray; /** * Notifies a callback with a result set. */ -class CallbackResultNotifier : public nsRunnable +class CallbackResultNotifier : public Runnable { public: CallbackResultNotifier(mozIStorageStatementCallback *aCallback, @@ -88,7 +88,7 @@ private: /** * Notifies the calling thread that an error has occurred. */ -class ErrorNotifier : public nsRunnable +class ErrorNotifier : public Runnable { public: ErrorNotifier(mozIStorageStatementCallback *aCallback, @@ -125,7 +125,7 @@ private: * Notifies the calling thread that the statement has finished executing. Takes * ownership of the StatementData so it is released on the proper thread. */ -class CompletionNotifier : public nsRunnable +class CompletionNotifier : public Runnable { public: /** diff --git a/storage/mozStorageConnection.cpp b/storage/mozStorageConnection.cpp index 147b88bf85..64825f11ff 100644 --- a/storage/mozStorageConnection.cpp +++ b/storage/mozStorageConnection.cpp @@ -344,7 +344,7 @@ WaitForUnlockNotify(sqlite3* aDatabase) namespace { -class AsyncCloseConnection final: public nsRunnable +class AsyncCloseConnection final: public Runnable { public: AsyncCloseConnection(Connection *aConnection, @@ -400,7 +400,7 @@ private: * * Must be executed on the clone's async execution thread. */ -class AsyncInitializeClone final: public nsRunnable +class AsyncInitializeClone final: public Runnable { public: /** diff --git a/storage/mozStorageConnection.h b/storage/mozStorageConnection.h index 93ce0a4d3f..c1a1f0025b 100644 --- a/storage/mozStorageConnection.h +++ b/storage/mozStorageConnection.h @@ -373,7 +373,7 @@ private: * A Runnable designed to call a mozIStorageCompletionCallback on * the appropriate thread. */ -class CallbackComplete final : public nsRunnable +class CallbackComplete final : public Runnable { public: /** diff --git a/storage/mozStoragePrivateHelpers.cpp b/storage/mozStoragePrivateHelpers.cpp index a89e1523be..29130e1d64 100644 --- a/storage/mozStoragePrivateHelpers.cpp +++ b/storage/mozStoragePrivateHelpers.cpp @@ -248,7 +248,7 @@ convertVariantToStorageVariant(nsIVariant* aVariant) } namespace { -class CallbackEvent : public nsRunnable +class CallbackEvent : public Runnable { public: explicit CallbackEvent(mozIStorageCompletionCallback *aCallback) diff --git a/storage/mozStorageService.cpp b/storage/mozStorageService.cpp index 1b0b33ddbf..ee38a096d6 100644 --- a/storage/mozStorageService.cpp +++ b/storage/mozStorageService.cpp @@ -680,7 +680,7 @@ Service::OpenSpecialDatabase(const char *aStorageKey, namespace { -class AsyncInitDatabase final : public nsRunnable +class AsyncInitDatabase final : public Runnable { public: AsyncInitDatabase(Connection* aConnection, diff --git a/storage/test/storage_test_harness.h b/storage/test/storage_test_harness.h index bc0fc00abd..fcf630e896 100644 --- a/storage/test/storage_test_harness.h +++ b/storage/test/storage_test_harness.h @@ -318,7 +318,7 @@ void watch_for_mutex_use_on_this_thread() * * The wedger is self-dispatching, just construct it with its target. */ -class ThreadWedger : public nsRunnable +class ThreadWedger : public mozilla::Runnable { public: explicit ThreadWedger(nsIEventTarget *aTarget) diff --git a/storage/test/test_service_init_background_thread.cpp b/storage/test/test_service_init_background_thread.cpp index 566c59ebf3..e4a60fea2f 100644 --- a/storage/test/test_service_init_background_thread.cpp +++ b/storage/test/test_service_init_background_thread.cpp @@ -16,7 +16,7 @@ //////////////////////////////////////////////////////////////////////////////// //// Helpers -class ServiceInitializer : public nsRunnable +class ServiceInitializer : public mozilla::Runnable { public: NS_IMETHOD Run() diff --git a/storage/test/test_unlock_notify.cpp b/storage/test/test_unlock_notify.cpp index 820ccec5a9..47d49deac6 100644 --- a/storage/test/test_unlock_notify.cpp +++ b/storage/test/test_unlock_notify.cpp @@ -25,7 +25,7 @@ enum State { TEST_DONE }; -class DatabaseLocker : public nsRunnable +class DatabaseLocker : public mozilla::Runnable { public: explicit DatabaseLocker(const char* aSQL) diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 1f6d359b59..b8f5f894b7 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -11907,6 +11907,10 @@ "path": "XMLHttpRequest/send-send.htm", "url": "/XMLHttpRequest/send-send.htm" }, + { + "path": "XMLHttpRequest/send-send.worker.js", + "url": "/XMLHttpRequest/send-send.worker" + }, { "path": "XMLHttpRequest/send-sync-blocks-async.htm", "url": "/XMLHttpRequest/send-sync-blocks-async.htm" diff --git a/testing/web-platform/meta/XMLHttpRequest/abort-during-open.htm.ini b/testing/web-platform/meta/XMLHttpRequest/abort-during-open.htm.ini deleted file mode 100644 index eac211dc53..0000000000 --- a/testing/web-platform/meta/XMLHttpRequest/abort-during-open.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[abort-during-open.htm] - type: testharness - [XMLHttpRequest: abort() during OPEN] - expected: FAIL - diff --git a/testing/web-platform/meta/XMLHttpRequest/abort-event-abort.htm.ini b/testing/web-platform/meta/XMLHttpRequest/abort-event-abort.htm.ini deleted file mode 100644 index 098804be36..0000000000 --- a/testing/web-platform/meta/XMLHttpRequest/abort-event-abort.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[abort-event-abort.htm] - type: testharness - [XMLHttpRequest: The abort() method: do not fire abort event in OPENED state when send() flag is unset. send() throws after abort().] - expected: FAIL - diff --git a/testing/web-platform/meta/XMLHttpRequest/send-data-unexpected-tostring.htm.ini b/testing/web-platform/meta/XMLHttpRequest/send-data-unexpected-tostring.htm.ini deleted file mode 100644 index 7665460623..0000000000 --- a/testing/web-platform/meta/XMLHttpRequest/send-data-unexpected-tostring.htm.ini +++ /dev/null @@ -1,8 +0,0 @@ -[send-data-unexpected-tostring.htm] - type: testharness - [abort() called from data stringification] - expected: FAIL - - [send() called from data stringification] - expected: FAIL - diff --git a/testing/web-platform/meta/XMLHttpRequest/send-send.htm.ini b/testing/web-platform/meta/XMLHttpRequest/send-send.htm.ini deleted file mode 100644 index fbf686aa19..0000000000 --- a/testing/web-platform/meta/XMLHttpRequest/send-send.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[send-send.htm] - type: testharness - [XMLHttpRequest: send() - send()] - expected: FAIL - diff --git a/testing/web-platform/meta/XMLHttpRequest/xmlhttprequest-unsent.htm.ini b/testing/web-platform/meta/XMLHttpRequest/xmlhttprequest-unsent.htm.ini deleted file mode 100644 index fcea5fe784..0000000000 --- a/testing/web-platform/meta/XMLHttpRequest/xmlhttprequest-unsent.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[xmlhttprequest-unsent.htm] - type: testharness - [XMLHttpRequest: members during UNSENT] - expected: FAIL - diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-during-open.htm b/testing/web-platform/tests/XMLHttpRequest/abort-during-open.htm index 60a6eeecd8..dde94f2398 100644 --- a/testing/web-platform/tests/XMLHttpRequest/abort-during-open.htm +++ b/testing/web-platform/tests/XMLHttpRequest/abort-during-open.htm @@ -9,21 +9,6 @@
- + diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-during-open.js b/testing/web-platform/tests/XMLHttpRequest/abort-during-open.js new file mode 100644 index 0000000000..4ddb84fe8b --- /dev/null +++ b/testing/web-platform/tests/XMLHttpRequest/abort-during-open.js @@ -0,0 +1,14 @@ +var test = async_test() +test.step(function() { + var client = new XMLHttpRequest() + client.open("GET", "...") + client.onreadystatechange = function() { + test.step(function() { + assert_unreached() + }) + } + client.abort() + assert_equals(client.readyState, 0) + assert_throws("InvalidStateError", function() { client.send("test") }, "calling send() after abort()") +}) +test.done() diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-during-open.worker.js b/testing/web-platform/tests/XMLHttpRequest/abort-during-open.worker.js new file mode 100644 index 0000000000..ffb687d0c8 --- /dev/null +++ b/testing/web-platform/tests/XMLHttpRequest/abort-during-open.worker.js @@ -0,0 +1,3 @@ +importScripts("/resources/testharness.js"); +importScripts("abort-during-open.js"); +done(); diff --git a/testing/web-platform/tests/XMLHttpRequest/send-send.htm b/testing/web-platform/tests/XMLHttpRequest/send-send.htm index 5b22a3da87..cbcbdb44e0 100644 --- a/testing/web-platform/tests/XMLHttpRequest/send-send.htm +++ b/testing/web-platform/tests/XMLHttpRequest/send-send.htm @@ -8,14 +8,6 @@
- + diff --git a/testing/web-platform/tests/XMLHttpRequest/send-send.js b/testing/web-platform/tests/XMLHttpRequest/send-send.js new file mode 100644 index 0000000000..2e7fe865f3 --- /dev/null +++ b/testing/web-platform/tests/XMLHttpRequest/send-send.js @@ -0,0 +1,7 @@ +test(function() { + var client = new XMLHttpRequest() + client.open("GET", "resources/well-formed.xml") + client.send(null) + assert_throws("InvalidStateError", function() { client.send(null) }) + client.abort() +}) diff --git a/testing/web-platform/tests/XMLHttpRequest/send-send.worker.js b/testing/web-platform/tests/XMLHttpRequest/send-send.worker.js new file mode 100644 index 0000000000..9d34ce63df --- /dev/null +++ b/testing/web-platform/tests/XMLHttpRequest/send-send.worker.js @@ -0,0 +1,3 @@ +importScripts("/resources/testharness.js"); +importScripts("send-send.js"); +done(); diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp index a737d7a888..3af665fa14 100644 --- a/toolkit/components/downloads/nsDownloadManager.cpp +++ b/toolkit/components/downloads/nsDownloadManager.cpp @@ -1709,7 +1709,7 @@ nsDownloadManager::GetDownload(uint32_t aID, nsIDownload **aDownloadItem) } namespace { -class AsyncResult : public nsRunnable +class AsyncResult : public Runnable { public: AsyncResult(nsresult aStatus, nsIDownload* aResult, diff --git a/toolkit/components/downloads/nsDownloadScanner.cpp b/toolkit/components/downloads/nsDownloadScanner.cpp index 0e689ac17a..1ef5b36602 100644 --- a/toolkit/components/downloads/nsDownloadScanner.cpp +++ b/toolkit/components/downloads/nsDownloadScanner.cpp @@ -289,7 +289,7 @@ nsDownloadScanner::ScannerThreadFunction(void *p) // The sole purpose of this class is to release an object on the main thread // It assumes that its creator will addref it and it will release itself on // the main thread too -class ReleaseDispatcher : public nsRunnable { +class ReleaseDispatcher : public mozilla::Runnable { public: ReleaseDispatcher(nsISupports *ptr) : mPtr(ptr) {} diff --git a/toolkit/components/downloads/nsDownloadScanner.h b/toolkit/components/downloads/nsDownloadScanner.h index 42a86b2dbf..3301489fe6 100644 --- a/toolkit/components/downloads/nsDownloadScanner.h +++ b/toolkit/components/downloads/nsDownloadScanner.h @@ -63,7 +63,7 @@ private: nsAutoPtr mWatchdog; static unsigned int __stdcall ScannerThreadFunction(void *p); - class Scan : public nsRunnable + class Scan : public mozilla::Runnable { public: Scan(nsDownloadScanner *scanner, nsDownload *download); diff --git a/toolkit/components/filewatcher/NativeFileWatcherWin.cpp b/toolkit/components/filewatcher/NativeFileWatcherWin.cpp index e895c68629..efeb3eecf0 100644 --- a/toolkit/components/filewatcher/NativeFileWatcherWin.cpp +++ b/toolkit/components/filewatcher/NativeFileWatcherWin.cpp @@ -27,7 +27,7 @@ namespace { /** * An event used to notify the main thread when an error happens. */ -class WatchedErrorEvent final : public nsRunnable +class WatchedErrorEvent final : public Runnable { public: /** @@ -65,7 +65,7 @@ public: /** * An event used to notify the main thread when an operation is successful. */ -class WatchedSuccessEvent final : public nsRunnable +class WatchedSuccessEvent final : public Runnable { public: /** @@ -103,7 +103,7 @@ public: * An event used to notify the main thread of a change in a watched * resource. */ -class WatchedChangeEvent final : public nsRunnable +class WatchedChangeEvent final : public Runnable { public: /** @@ -232,7 +232,7 @@ struct PathRunnablesParametersWrapper { * This runnable is dispatched to the main thread in order to safely * shutdown the worker thread. */ -class NativeWatcherIOShutdownTask : public nsRunnable +class NativeWatcherIOShutdownTask : public Runnable { public: NativeWatcherIOShutdownTask() @@ -263,7 +263,7 @@ private: * by issuing a NS_DispatchToCurrentThread(this) before exiting. This is done to allow * the execution of other runnables enqueued within the thread task queue. */ -class NativeFileWatcherIOTask : public nsRunnable +class NativeFileWatcherIOTask : public Runnable { public: NativeFileWatcherIOTask(HANDLE aIOCompletionPort) diff --git a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp index 1cee9dd3c8..1e683677c6 100644 --- a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp +++ b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp @@ -32,7 +32,7 @@ namespace { * Important note: we maintain the invariant that these private data * slots are already addrefed. */ -class FinalizationEvent final: public nsRunnable +class FinalizationEvent final: public Runnable { public: FinalizationEvent(const char* aTopic, diff --git a/toolkit/components/osfile/NativeOSFileInternals.cpp b/toolkit/components/osfile/NativeOSFileInternals.cpp index d2452619b3..cc791bcbb6 100644 --- a/toolkit/components/osfile/NativeOSFileInternals.cpp +++ b/toolkit/components/osfile/NativeOSFileInternals.cpp @@ -390,7 +390,7 @@ TypedArrayResult::GetCacheableResult(JSContext* cx, JS::MutableHandle /** * An event used to notify asynchronously of an error. */ -class ErrorEvent final : public nsRunnable { +class ErrorEvent final : public Runnable { public: /** * @param aOnSuccess The success callback. @@ -448,7 +448,7 @@ public: /** * An event used to notify of a success. */ -class SuccessEvent final : public nsRunnable { +class SuccessEvent final : public Runnable { public: /** * @param aOnSuccess The success callback. @@ -499,7 +499,7 @@ public: /** * Base class shared by actions. */ -class AbstractDoEvent: public nsRunnable { +class AbstractDoEvent: public Runnable { public: AbstractDoEvent(nsMainThreadPtrHandle& aOnSuccess, nsMainThreadPtrHandle& aOnError) diff --git a/toolkit/components/places/AsyncFaviconHelpers.cpp b/toolkit/components/places/AsyncFaviconHelpers.cpp index 9227b4b43c..8c89b98229 100644 --- a/toolkit/components/places/AsyncFaviconHelpers.cpp +++ b/toolkit/components/places/AsyncFaviconHelpers.cpp @@ -501,7 +501,7 @@ AsyncFetchAndSetIconForPage::Run() NS_IMPL_ISUPPORTS_INHERITED( AsyncFetchAndSetIconFromNetwork -, nsRunnable +, Runnable , nsIStreamListener , nsIInterfaceRequestor , nsIChannelEventSink diff --git a/toolkit/components/places/AsyncFaviconHelpers.h b/toolkit/components/places/AsyncFaviconHelpers.h index 86c3ca63fb..01e147ba07 100644 --- a/toolkit/components/places/AsyncFaviconHelpers.h +++ b/toolkit/components/places/AsyncFaviconHelpers.h @@ -97,7 +97,7 @@ struct PageData * Base class for events declared in this file. This class's main purpose is * to declare a destructor which releases mCallback on the main thread. */ -class AsyncFaviconHelperBase : public nsRunnable +class AsyncFaviconHelperBase : public Runnable { protected: explicit AsyncFaviconHelperBase(nsCOMPtr& aCallback); diff --git a/toolkit/components/places/Helpers.cpp b/toolkit/components/places/Helpers.cpp index e3e8d96ab6..93176f02a6 100644 --- a/toolkit/components/places/Helpers.cpp +++ b/toolkit/components/places/Helpers.cpp @@ -382,7 +382,7 @@ PlacesEvent::Notify() NS_IMPL_ISUPPORTS_INHERITED0( PlacesEvent -, nsRunnable +, Runnable ) //////////////////////////////////////////////////////////////////////////////// diff --git a/toolkit/components/places/Helpers.h b/toolkit/components/places/Helpers.h index 8bd3161ae6..dd6de65e7b 100644 --- a/toolkit/components/places/Helpers.h +++ b/toolkit/components/places/Helpers.h @@ -169,7 +169,7 @@ PRTime RoundedPRNow(); * Used to finalize a statementCache on a specified thread. */ template -class FinalizeStatementCacheProxy : public nsRunnable +class FinalizeStatementCacheProxy : public Runnable { public: /** @@ -230,7 +230,7 @@ bool GetHiddenState(bool aIsRedirect, /** * Notifies a specified topic via the observer service. */ -class PlacesEvent : public nsRunnable +class PlacesEvent : public Runnable { public: NS_DECL_ISUPPORTS_INHERITED diff --git a/toolkit/components/places/History.cpp b/toolkit/components/places/History.cpp index 38a9bb442b..a3c2f77acf 100644 --- a/toolkit/components/places/History.cpp +++ b/toolkit/components/places/History.cpp @@ -622,7 +622,7 @@ NS_IMPL_ISUPPORTS_INHERITED( /** * Notifies observers about a visit. */ -class NotifyVisitObservers : public nsRunnable +class NotifyVisitObservers : public Runnable { public: NotifyVisitObservers(VisitData& aPlace, @@ -687,7 +687,7 @@ private: /** * Notifies observers about a pages title changing. */ -class NotifyTitleObservers : public nsRunnable +class NotifyTitleObservers : public Runnable { public: /** @@ -733,7 +733,7 @@ private: * Helper class for methods which notify their callers through the * mozIVisitInfoCallback interface. */ -class NotifyPlaceInfoCallback : public nsRunnable +class NotifyPlaceInfoCallback : public Runnable { public: NotifyPlaceInfoCallback(const nsMainThreadPtrHandle& aCallback, @@ -803,7 +803,7 @@ private: /** * Notifies a callback object when the operation is complete. */ -class NotifyCompletion : public nsRunnable +class NotifyCompletion : public Runnable { public: explicit NotifyCompletion(const nsMainThreadPtrHandle& aCallback) @@ -871,7 +871,7 @@ CanAddURI(nsIURI* aURI, /** * Adds a visit to the database. */ -class InsertVisitedURIs final: public nsRunnable +class InsertVisitedURIs final: public Runnable { public: /** @@ -1320,7 +1320,7 @@ private: RefPtr mHistory; }; -class GetPlaceInfo final : public nsRunnable { +class GetPlaceInfo final : public Runnable { public: /** * Get the place info for a given place (by GUID or URI) asynchronously. @@ -1380,7 +1380,7 @@ private: /** * Sets the page title for a page in moz_places (if necessary). */ -class SetPageTitle : public nsRunnable +class SetPageTitle : public Runnable { public: /** @@ -1594,7 +1594,7 @@ NS_IMPL_ISUPPORTS( /** * Notify removed visits to observers. */ -class NotifyRemoveVisits : public nsRunnable +class NotifyRemoveVisits : public Runnable { public: @@ -1679,7 +1679,7 @@ private: /** * Remove visits from history. */ -class RemoveVisits : public nsRunnable +class RemoveVisits : public Runnable { public: /** diff --git a/toolkit/components/places/nsNavHistory.cpp b/toolkit/components/places/nsNavHistory.cpp index 4ec801b92b..3e41c15ae1 100644 --- a/toolkit/components/places/nsNavHistory.cpp +++ b/toolkit/components/places/nsNavHistory.cpp @@ -543,7 +543,7 @@ nsNavHistory::NotifyManyFrecenciesChanged() namespace { -class FrecencyNotification : public nsRunnable +class FrecencyNotification : public Runnable { public: FrecencyNotification(const nsACString& aSpec, diff --git a/toolkit/components/places/tests/cpp/places_test_harness_tail.h b/toolkit/components/places/tests/cpp/places_test_harness_tail.h index 2c40dd75d7..fcf7249bae 100644 --- a/toolkit/components/places/tests/cpp/places_test_harness_tail.h +++ b/toolkit/components/places/tests/cpp/places_test_harness_tail.h @@ -19,7 +19,7 @@ int gTestsIndex = 0; #define TEST_INFO_STR "TEST-INFO | (%s) | " -class RunNextTest : public nsRunnable +class RunNextTest : public mozilla::Runnable { public: NS_IMETHOD Run() diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp index d0fae28a2f..7fd8f6a6a2 100644 --- a/toolkit/components/satchel/nsFormFillController.cpp +++ b/toolkit/components/satchel/nsFormFillController.cpp @@ -717,7 +717,7 @@ nsFormFillController::PerformInputListAutoComplete(const nsAString& aSearch, return NS_OK; } -class UpdateSearchResultRunnable : public nsRunnable +class UpdateSearchResultRunnable : public mozilla::Runnable { public: UpdateSearchResultRunnable(nsIAutoCompleteObserver* aObserver, diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp index ec386fc505..16f1ad6c76 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -97,7 +97,7 @@ using namespace mozilla; uint32_t gRestartMode = 0; -class nsAppExitEvent : public nsRunnable { +class nsAppExitEvent : public mozilla::Runnable { private: RefPtr mService; diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 00088bc0a1..22a7c04751 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -1726,7 +1726,7 @@ GetFailedProfileLockFile(nsIFile* *aFile, nsIFile* aProfileDir) return NS_OK; } -class nsFetchTelemetryData : public nsRunnable +class nsFetchTelemetryData : public Runnable { public: nsFetchTelemetryData(const char* aShutdownTimeFilename, diff --git a/toolkit/components/url-classifier/Entries.h b/toolkit/components/url-classifier/Entries.h index fa5aaea684..29b5d3c9f0 100644 --- a/toolkit/components/url-classifier/Entries.h +++ b/toolkit/components/url-classifier/Entries.h @@ -181,6 +181,13 @@ struct AddComplete { } return addChunk - other.addChunk; } + + bool operator!=(const AddComplete& aOther) const { + if (addChunk != aOther.addChunk) { + return true; + } + return complete != aOther.complete; + } }; struct SubPrefix { diff --git a/toolkit/components/url-classifier/HashStore.h b/toolkit/components/url-classifier/HashStore.h index f8799c30e4..70b937d50c 100644 --- a/toolkit/components/url-classifier/HashStore.h +++ b/toolkit/components/url-classifier/HashStore.h @@ -39,28 +39,27 @@ public: // Throughout, uint32_t aChunk refers only to the chunk number. Chunk data is // stored in the Prefix structures. - MOZ_WARN_UNUSED_RESULT nsresult NewAddChunk(uint32_t aChunk) { + MOZ_MUST_USE nsresult NewAddChunk(uint32_t aChunk) { return mAddChunks.Set(aChunk); }; - MOZ_WARN_UNUSED_RESULT nsresult NewSubChunk(uint32_t aChunk) { + MOZ_MUST_USE nsresult NewSubChunk(uint32_t aChunk) { return mSubChunks.Set(aChunk); }; - MOZ_WARN_UNUSED_RESULT nsresult NewAddExpiration(uint32_t aChunk) { + MOZ_MUST_USE nsresult NewAddExpiration(uint32_t aChunk) { return mAddExpirations.Set(aChunk); }; - MOZ_WARN_UNUSED_RESULT nsresult NewSubExpiration(uint32_t aChunk) { + MOZ_MUST_USE nsresult NewSubExpiration(uint32_t aChunk) { return mSubExpirations.Set(aChunk); }; - MOZ_WARN_UNUSED_RESULT nsresult NewAddPrefix(uint32_t aAddChunk, - const Prefix& aPrefix); - MOZ_WARN_UNUSED_RESULT nsresult NewSubPrefix(uint32_t aAddChunk, - const Prefix& aPrefix, - uint32_t aSubChunk); - MOZ_WARN_UNUSED_RESULT nsresult NewAddComplete(uint32_t aChunk, - const Completion& aCompletion); - MOZ_WARN_UNUSED_RESULT nsresult NewSubComplete(uint32_t aAddChunk, - const Completion& aCompletion, - uint32_t aSubChunk); + MOZ_MUST_USE nsresult NewAddPrefix(uint32_t aAddChunk, const Prefix& aPrefix); + MOZ_MUST_USE nsresult NewSubPrefix(uint32_t aAddChunk, + const Prefix& aPrefix, + uint32_t aSubChunk); + MOZ_MUST_USE nsresult NewAddComplete(uint32_t aChunk, + const Completion& aCompletion); + MOZ_MUST_USE nsresult NewSubComplete(uint32_t aAddChunk, + const Completion& aCompletion, + uint32_t aSubChunk); void SetLocalUpdate(void) { mLocalUpdate = true; } bool IsLocalUpdate(void) { return mLocalUpdate; } diff --git a/toolkit/components/url-classifier/LookupCache.h b/toolkit/components/url-classifier/LookupCache.h index 885c352e60..85702a7cb9 100644 --- a/toolkit/components/url-classifier/LookupCache.h +++ b/toolkit/components/url-classifier/LookupCache.h @@ -67,6 +67,13 @@ typedef nsTArray LookupResultArray; struct CacheResult { AddComplete entry; nsCString table; + + bool operator==(const CacheResult& aOther) const { + if (entry != aOther.entry) { + return false; + } + return table == aOther.table; + } }; typedef nsTArray CacheResultArray; diff --git a/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl b/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl index 2cb7a084cf..ae0c66e86d 100644 --- a/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl +++ b/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl @@ -107,6 +107,11 @@ interface nsIUrlClassifierDBService : nsISupports void setLastUpdateTime(in ACString tableName, in unsigned long long lastUpdateTime); + /** + * Forget the results that were used in the last DB update. + */ + void clearLastResults(); + //////////////////////////////////////////////////////////////////////////// // Incremental update methods. // diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index e3112eb37d..e955f6882b 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -656,6 +656,11 @@ nsUrlClassifierDBServiceWorker::CacheCompletions(CacheResultArray *results) // Ownership is transferred in to us nsAutoPtr resultsPtr(results); + if (mLastResults == *resultsPtr) { + LOG(("Skipping completions that have just been cached already.")); + return NS_OK; + } + nsAutoPtr pParse(new ProtocolParser()); nsTArray updates; @@ -698,6 +703,7 @@ nsUrlClassifierDBServiceWorker::CacheCompletions(CacheResultArray *results) } mClassifier->ApplyUpdates(&updates); + mLastResults = *resultsPtr; return NS_OK; } @@ -754,6 +760,15 @@ nsUrlClassifierDBServiceWorker::SetLastUpdateTime(const nsACString &table, return NS_OK; } +NS_IMETHODIMP +nsUrlClassifierDBServiceWorker::ClearLastResults() +{ + MOZ_ASSERT(!NS_IsMainThread(), "Must be on the background thread"); + mLastResults.Clear(); + return NS_OK; +} + + // ------------------------------------------------------------------------- // nsUrlClassifierLookupCallback // @@ -1451,7 +1466,7 @@ nsUrlClassifierDBService::SetHashCompleter(const nsACString &tableName, } else { mCompleters.Remove(tableName); } - + ClearLastResults(); return NS_OK; } @@ -1464,6 +1479,14 @@ nsUrlClassifierDBService::SetLastUpdateTime(const nsACString &tableName, return mWorkerProxy->SetLastUpdateTime(tableName, lastUpdateTime); } +NS_IMETHODIMP +nsUrlClassifierDBService::ClearLastResults() +{ + NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED); + + return mWorkerProxy->ClearLastResults(); +} + NS_IMETHODIMP nsUrlClassifierDBService::BeginUpdate(nsIUrlClassifierUpdateObserver *observer, const nsACString &updateTables) diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.h b/toolkit/components/url-classifier/nsUrlClassifierDBService.h index 5543d344a7..3c15cdc3d4 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h @@ -212,6 +212,9 @@ private: // the next update PrefixArray mMissCache; + // Stores the last results that triggered a table update. + CacheResultArray mLastResults; + nsresult mUpdateStatus; nsTArray mUpdateTables; diff --git a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp index 73330d66da..96fdfea720 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp @@ -232,6 +232,19 @@ UrlClassifierDBServiceWorkerProxy::SetLastUpdateTimeRunnable::Run() return NS_OK; } +NS_IMETHODIMP +UrlClassifierDBServiceWorkerProxy::ClearLastResults() +{ + nsCOMPtr r = new ClearLastResultsRunnable(mTarget); + return DispatchToWorkerThread(r); +} + +NS_IMETHODIMP +UrlClassifierDBServiceWorkerProxy::ClearLastResultsRunnable::Run() +{ + return mTarget->ClearLastResults(); +} + NS_IMPL_ISUPPORTS(UrlClassifierLookupCallbackProxy, nsIUrlClassifierLookupCallback) diff --git a/toolkit/components/url-classifier/nsUrlClassifierProxies.h b/toolkit/components/url-classifier/nsUrlClassifierProxies.h index 087cd5df7b..aa5945ab1c 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierProxies.h +++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.h @@ -30,7 +30,7 @@ public: NS_DECL_NSIURLCLASSIFIERDBSERVICE NS_DECL_NSIURLCLASSIFIERDBSERVICEWORKER - class LookupRunnable : public nsRunnable + class LookupRunnable : public mozilla::Runnable { public: LookupRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -52,7 +52,7 @@ public: nsCOMPtr mCB; }; - class GetTablesRunnable : public nsRunnable + class GetTablesRunnable : public mozilla::Runnable { public: GetTablesRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -68,7 +68,7 @@ public: nsCOMPtr mCB; }; - class BeginUpdateRunnable : public nsRunnable + class BeginUpdateRunnable : public mozilla::Runnable { public: BeginUpdateRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -87,7 +87,7 @@ public: nsCString mTables; }; - class BeginStreamRunnable : public nsRunnable + class BeginStreamRunnable : public mozilla::Runnable { public: BeginStreamRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -103,7 +103,7 @@ public: nsCString mTable; }; - class UpdateStreamRunnable : public nsRunnable + class UpdateStreamRunnable : public mozilla::Runnable { public: UpdateStreamRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -119,7 +119,7 @@ public: nsCString mUpdateChunk; }; - class CacheCompletionsRunnable : public nsRunnable + class CacheCompletionsRunnable : public mozilla::Runnable { public: CacheCompletionsRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -135,7 +135,7 @@ public: mozilla::safebrowsing::CacheResultArray *mEntries; }; - class CacheMissesRunnable : public nsRunnable + class CacheMissesRunnable : public mozilla::Runnable { public: CacheMissesRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -151,7 +151,7 @@ public: mozilla::safebrowsing::PrefixArray *mEntries; }; - class DoLocalLookupRunnable : public nsRunnable + class DoLocalLookupRunnable : public mozilla::Runnable { public: DoLocalLookupRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -173,7 +173,7 @@ public: mozilla::safebrowsing::LookupResultArray* mResults; }; - class SetLastUpdateTimeRunnable : public nsRunnable + class SetLastUpdateTimeRunnable : public mozilla::Runnable { public: SetLastUpdateTimeRunnable(nsUrlClassifierDBServiceWorker* aTarget, @@ -191,6 +191,18 @@ public: uint64_t mUpdateTime; }; + class ClearLastResultsRunnable : public mozilla::Runnable + { + public: + explicit ClearLastResultsRunnable(nsUrlClassifierDBServiceWorker* aTarget) + : mTarget(aTarget) + { } + + NS_DECL_NSIRUNNABLE + private: + RefPtr mTarget; + }; + public: nsresult DoLocalLookup(const nsACString& spec, const nsACString& tables, @@ -215,7 +227,7 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIURLCLASSIFIERLOOKUPCALLBACK - class LookupCompleteRunnable : public nsRunnable + class LookupCompleteRunnable : public mozilla::Runnable { public: LookupCompleteRunnable(const nsMainThreadPtrHandle& aTarget, @@ -247,7 +259,7 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIURLCLASSIFIERCALLBACK - class HandleEventRunnable : public nsRunnable + class HandleEventRunnable : public mozilla::Runnable { public: HandleEventRunnable(const nsMainThreadPtrHandle& aTarget, @@ -280,7 +292,7 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIURLCLASSIFIERUPDATEOBSERVER - class UpdateUrlRequestedRunnable : public nsRunnable + class UpdateUrlRequestedRunnable : public mozilla::Runnable { public: UpdateUrlRequestedRunnable(const nsMainThreadPtrHandle& aTarget, @@ -298,7 +310,7 @@ public: nsCString mURL, mTable; }; - class StreamFinishedRunnable : public nsRunnable + class StreamFinishedRunnable : public mozilla::Runnable { public: StreamFinishedRunnable(const nsMainThreadPtrHandle& aTarget, @@ -316,7 +328,7 @@ public: uint32_t mDelay; }; - class UpdateErrorRunnable : public nsRunnable + class UpdateErrorRunnable : public mozilla::Runnable { public: UpdateErrorRunnable(const nsMainThreadPtrHandle& aTarget, @@ -332,7 +344,7 @@ public: nsresult mError; }; - class UpdateSuccessRunnable : public nsRunnable + class UpdateSuccessRunnable : public mozilla::Runnable { public: UpdateSuccessRunnable(const nsMainThreadPtrHandle& aTarget, diff --git a/toolkit/components/utils/simpleServices.js b/toolkit/components/utils/simpleServices.js index 69b727d9ec..c7fc79b252 100644 --- a/toolkit/components/utils/simpleServices.js +++ b/toolkit/components/utils/simpleServices.js @@ -17,33 +17,6 @@ const Ci = Components.interfaces; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -function RemoteTagServiceService() -{ -} - -RemoteTagServiceService.prototype = { - classID: Components.ID("{dfd07380-6083-11e4-9803-0800200c9a66}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRemoteTagService, Ci.nsISupportsWeakReference]), - - /** - * CPOWs can have user data attached to them. This data originates - * in the local process from this function, getRemoteObjectTag. It's - * sent along with the CPOW to the remote process, where it can be - * fetched with Components.utils.getCrossProcessWrapperTag. - */ - getRemoteObjectTag: function(target) { - if (target instanceof Ci.nsIDocShellTreeItem) { - return "ContentDocShellTreeItem"; - } - - if (target instanceof Ci.nsIDOMDocument) { - return "ContentDocument"; - } - - return "generic"; - } -}; - function AddonPolicyService() { this.wrappedJSObject = this; @@ -130,4 +103,5 @@ AddonPolicyService.prototype = { } }; -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RemoteTagServiceService, AddonPolicyService]); +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AddonPolicyService, + AddonLocalizationConverter]); diff --git a/toolkit/crashreporter/InjectCrashReporter.h b/toolkit/crashreporter/InjectCrashReporter.h index 87015603cc..5b40b49e32 100644 --- a/toolkit/crashreporter/InjectCrashReporter.h +++ b/toolkit/crashreporter/InjectCrashReporter.h @@ -11,7 +11,7 @@ namespace mozilla { -class InjectCrashRunnable : public nsRunnable +class InjectCrashRunnable : public Runnable { public: InjectCrashRunnable(DWORD pid); diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 62472ae914..ba2b9eebca 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -316,7 +316,7 @@ static bool OOPInitialized(); #ifdef MOZ_CRASHREPORTER_INJECTOR static nsIThread* sInjectorThread; -class ReportInjectedCrash : public nsRunnable +class ReportInjectedCrash : public Runnable { public: explicit ReportInjectedCrash(uint32_t pid) : mPID(pid) { } @@ -3179,7 +3179,7 @@ OOPInitialized() void OOPInit() { - class ProxyToMainThread : public nsRunnable + class ProxyToMainThread : public Runnable { public: NS_IMETHOD Run() { diff --git a/toolkit/identity/IdentityCryptoService.cpp b/toolkit/identity/IdentityCryptoService.cpp index b110c2da89..71616a71a1 100644 --- a/toolkit/identity/IdentityCryptoService.cpp +++ b/toolkit/identity/IdentityCryptoService.cpp @@ -90,7 +90,7 @@ private: NS_IMPL_ISUPPORTS(KeyPair, nsIIdentityKeyPair) -class KeyGenRunnable : public nsRunnable, public nsNSSShutDownObject +class KeyGenRunnable : public Runnable, public nsNSSShutDownObject { public: NS_DECL_NSIRUNNABLE @@ -128,7 +128,7 @@ private: void operator=(const KeyGenRunnable &) = delete; }; -class SignRunnable : public nsRunnable, public nsNSSShutDownObject +class SignRunnable : public Runnable, public nsNSSShutDownObject { public: NS_DECL_NSIRUNNABLE @@ -336,7 +336,7 @@ KeyGenRunnable::KeyGenRunnable(KeyType keyType, { } -MOZ_WARN_UNUSED_RESULT nsresult +MOZ_MUST_USE nsresult GenerateKeyPair(PK11SlotInfo * slot, SECKEYPrivateKey ** privateKey, SECKEYPublicKey ** publicKey, @@ -362,7 +362,7 @@ GenerateKeyPair(PK11SlotInfo * slot, } -MOZ_WARN_UNUSED_RESULT nsresult +MOZ_MUST_USE nsresult GenerateRSAKeyPair(PK11SlotInfo * slot, SECKEYPrivateKey ** privateKey, SECKEYPublicKey ** publicKey) @@ -376,7 +376,7 @@ GenerateRSAKeyPair(PK11SlotInfo * slot, &rsaParams); } -MOZ_WARN_UNUSED_RESULT nsresult +MOZ_MUST_USE nsresult GenerateDSAKeyPair(PK11SlotInfo * slot, SECKEYPrivateKey ** privateKey, SECKEYPublicKey ** publicKey) diff --git a/toolkit/xre/ProfileReset.h b/toolkit/xre/ProfileReset.h index de433d0a4e..a06ee557e3 100644 --- a/toolkit/xre/ProfileReset.h +++ b/toolkit/xre/ProfileReset.h @@ -16,7 +16,7 @@ nsresult CreateResetProfile(nsIToolkitProfileService* aProfileSvc, nsresult ProfileResetCleanup(nsIToolkitProfile* aOldProfile); -class ProfileResetCleanupResultTask : public nsRunnable +class ProfileResetCleanupResultTask : public mozilla::Runnable { public: ProfileResetCleanupResultTask() @@ -35,7 +35,7 @@ private: nsCOMPtr mWorkerThread; }; -class ProfileResetCleanupAsyncTask : public nsRunnable +class ProfileResetCleanupAsyncTask : public mozilla::Runnable { public: ProfileResetCleanupAsyncTask(nsIFile* aProfileDir, nsIFile* aProfileLocalDir, diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index f2e628c998..57475bac97 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -660,7 +660,7 @@ XRE_GetIOMessageLoop() namespace { -class MainFunctionRunnable : public nsRunnable +class MainFunctionRunnable : public Runnable { public: NS_DECL_NSIRUNNABLE diff --git a/tools/profiler/gecko/SaveProfileTask.h b/tools/profiler/gecko/SaveProfileTask.h index 7bf9badd54..4a215bba08 100644 --- a/tools/profiler/gecko/SaveProfileTask.h +++ b/tools/profiler/gecko/SaveProfileTask.h @@ -25,7 +25,7 @@ * This is an event used to save the profile on the main thread * to be sure that it is not being modified while saving. */ -class SaveProfileTask : public nsRunnable { +class SaveProfileTask : public mozilla::Runnable { public: SaveProfileTask() {} diff --git a/tools/profiler/gecko/ThreadResponsiveness.cpp b/tools/profiler/gecko/ThreadResponsiveness.cpp index f0c009ba47..78103f7796 100644 --- a/tools/profiler/gecko/ThreadResponsiveness.cpp +++ b/tools/profiler/gecko/ThreadResponsiveness.cpp @@ -16,7 +16,7 @@ using mozilla::Monitor; using mozilla::MonitorAutoLock; using mozilla::TimeStamp; -class CheckResponsivenessTask : public nsRunnable, +class CheckResponsivenessTask : public mozilla::Runnable, public nsITimerCallback { public: CheckResponsivenessTask() @@ -79,7 +79,8 @@ private: bool mStop; }; -NS_IMPL_ISUPPORTS_INHERITED(CheckResponsivenessTask, nsRunnable, nsITimerCallback) +NS_IMPL_ISUPPORTS_INHERITED(CheckResponsivenessTask, mozilla::Runnable, + nsITimerCallback) ThreadResponsiveness::ThreadResponsiveness(ThreadProfile *aThreadProfile) : mThreadProfile(aThreadProfile) diff --git a/view/nsView.cpp b/view/nsView.cpp index ed736a23cf..5155b51fcf 100644 --- a/view/nsView.cpp +++ b/view/nsView.cpp @@ -102,7 +102,7 @@ nsView::~nsView() delete mDirtyRegion; } -class DestroyWidgetRunnable : public nsRunnable { +class DestroyWidgetRunnable : public Runnable { public: NS_DECL_NSIRUNNABLE diff --git a/widget/PuppetWidget.h b/widget/PuppetWidget.h index c6e05954a5..fcbbfe1415 100644 --- a/widget/PuppetWidget.h +++ b/widget/PuppetWidget.h @@ -296,7 +296,7 @@ private: nsIWidgetListener* GetCurrentWidgetListener(); - class PaintTask : public nsRunnable { + class PaintTask : public Runnable { public: NS_DECL_NSIRUNNABLE explicit PaintTask(PuppetWidget* widget) : mWidget(widget) {} diff --git a/widget/nsBaseAppShell.cpp b/widget/nsBaseAppShell.cpp index eee3eaf3d0..1557498b71 100644 --- a/widget/nsBaseAppShell.cpp +++ b/widget/nsBaseAppShell.cpp @@ -308,7 +308,7 @@ nsBaseAppShell::DispatchDummyEvent(nsIThread* aTarget) NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (!mDummyEvent) - mDummyEvent = new nsRunnable(); + mDummyEvent = new mozilla::Runnable(); return NS_SUCCEEDED(aTarget->Dispatch(mDummyEvent, NS_DISPATCH_NORMAL)); } diff --git a/widget/nsBaseFilePicker.cpp b/widget/nsBaseFilePicker.cpp index 5d11fbcfc7..8b0ef15c76 100644 --- a/widget/nsBaseFilePicker.cpp +++ b/widget/nsBaseFilePicker.cpp @@ -64,7 +64,7 @@ LocalFileToDirectoryOrBlob(nsPIDOMWindow* aWindow, * A runnable to dispatch from the main thread to the main thread to display * the file picker while letting the showAsync method return right away. */ -class AsyncShowFilePicker : public nsRunnable +class AsyncShowFilePicker : public mozilla::Runnable { public: AsyncShowFilePicker(nsIFilePicker *aFilePicker, diff --git a/widget/tests/TestAppShellSteadyState.cpp b/widget/tests/TestAppShellSteadyState.cpp index b7e05a976c..16767d0d63 100644 --- a/widget/tests/TestAppShellSteadyState.cpp +++ b/widget/tests/TestAppShellSteadyState.cpp @@ -35,7 +35,7 @@ typedef void (*TestFunc)(nsIAppShell*); bool gStableStateEventHasRun = false; -class ExitAppShellRunnable : public nsRunnable +class ExitAppShellRunnable : public Runnable { nsCOMPtr mAppShell; @@ -51,7 +51,7 @@ public: } }; -class StableStateRunnable : public nsRunnable +class StableStateRunnable : public Runnable { public: NS_IMETHOD @@ -65,7 +65,7 @@ public: } }; -class CheckStableStateRunnable : public nsRunnable +class CheckStableStateRunnable : public Runnable { bool mShouldHaveRun; @@ -112,7 +112,7 @@ public: } }; -class NextTestRunnable : public nsRunnable +class NextTestRunnable : public Runnable { nsCOMPtr mAppShell; diff --git a/widget/windows/LSPAnnotator.cpp b/widget/windows/LSPAnnotator.cpp index f440e798f3..bbe55563e5 100644 --- a/widget/windows/LSPAnnotator.cpp +++ b/widget/windows/LSPAnnotator.cpp @@ -29,7 +29,7 @@ namespace mozilla { namespace crashreporter { -class LSPAnnotationGatherer : public nsRunnable +class LSPAnnotationGatherer : public Runnable { ~LSPAnnotationGatherer() {} diff --git a/widget/windows/WidgetTraceEvent.cpp b/widget/windows/WidgetTraceEvent.cpp index d4570cbd0d..8c6b6eb2ce 100644 --- a/widget/windows/WidgetTraceEvent.cpp +++ b/widget/windows/WidgetTraceEvent.cpp @@ -32,7 +32,7 @@ HANDLE sEventHandle = nullptr; // We need a runnable in order to find the hidden window on the main // thread. -class HWNDGetter : public nsRunnable { +class HWNDGetter : public mozilla::Runnable { public: HWNDGetter() : hidden_window_hwnd(nullptr) { MOZ_COUNT_CTOR(HWNDGetter); diff --git a/widget/windows/nsColorPicker.h b/widget/windows/nsColorPicker.h index 33deed3bb0..1fb189210f 100644 --- a/widget/windows/nsColorPicker.h +++ b/widget/windows/nsColorPicker.h @@ -17,7 +17,7 @@ class nsIWidget; class AsyncColorChooser : - public nsRunnable + public mozilla::Runnable { public: AsyncColorChooser(COLORREF aInitialColor, diff --git a/widget/windows/nsNativeThemeWin.cpp b/widget/windows/nsNativeThemeWin.cpp index a8505c4965..f36da274a5 100644 --- a/widget/windows/nsNativeThemeWin.cpp +++ b/widget/windows/nsNativeThemeWin.cpp @@ -1556,7 +1556,7 @@ AssumeThemePartAndStateAreTransparent(int32_t aPart, int32_t aState) static inline double GetThemeDpiScaleFactor(nsIFrame* aFrame) { - if (WinUtils::IsPerMonitorDPIAware() && GetSystemMetrics(SM_CMONITORS) > 1) { + if (WinUtils::IsPerMonitorDPIAware()) { nsIWidget* rootWidget = aFrame->PresContext()->GetRootWidget(); if (rootWidget) { double systemScale = WinUtils::SystemScaleFactor(); @@ -2155,7 +2155,6 @@ nsNativeThemeWin::GetWidgetPadding(nsDeviceContext* aContext, if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) aResult->top = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); - ScaleForFrameDPI(aResult, aFrame); return ok; } @@ -2506,7 +2505,6 @@ nsNativeThemeWin::GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aF aResult->height += GetSystemMetrics(SM_CYFRAME); aResult->height += GetSystemMetrics(SM_CXPADDEDBORDER); *aIsOverridable = false; - ScaleForFrameDPI(aResult, aFrame); return rv; case NS_THEME_WINDOW_BUTTON_BOX: diff --git a/widget/windows/nsSound.cpp b/widget/windows/nsSound.cpp index bfc8e9f4c7..ef4efcc78f 100644 --- a/widget/windows/nsSound.cpp +++ b/widget/windows/nsSound.cpp @@ -32,7 +32,7 @@ using mozilla::LogLevel; PRLogModuleInfo* gWin32SoundLog = nullptr; -class nsSoundPlayer: public nsRunnable { +class nsSoundPlayer: public mozilla::Runnable { public: nsSoundPlayer(nsSound *aSound, const wchar_t* aSoundName) : mSoundName(aSoundName), mSound(aSound) @@ -60,7 +60,7 @@ protected: NS_IF_ADDREF(mSound); } - class SoundReleaser: public nsRunnable { + class SoundReleaser: public mozilla::Runnable { public: SoundReleaser(nsSound* aSound) : mSound(aSound) diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 391677616c..950f37b5cf 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -101,7 +101,7 @@ struct DeferredFinalizeFunctionHolder void* data; }; -class IncrementalFinalizeRunnable : public nsRunnable +class IncrementalFinalizeRunnable : public Runnable { typedef AutoTArray DeferredFinalizeArray; typedef CycleCollectedJSRuntime::DeferredFinalizerTable DeferredFinalizerTable; @@ -299,7 +299,7 @@ JSGCThingParticipant::Traverse(void* aPtr, reinterpret_cast(this) - offsetof(CycleCollectedJSRuntime, mGCThingCycleCollectorGlobal)); - JS::GCCellPtr cellPtr(aPtr, js::GCThingTraceKind(aPtr)); + JS::GCCellPtr cellPtr(aPtr, JS::GCThingTraceKind(aPtr)); runtime->TraverseGCThing(CycleCollectedJSRuntime::TRAVERSE_FULL, cellPtr, aCb); return NS_OK; } @@ -915,7 +915,7 @@ CycleCollectedJSRuntime::ContextCallback(JSContext* aContext, return self->CustomContextCallback(aContext, aOperation); } -class PromiseJobRunnable final : public nsRunnable +class PromiseJobRunnable final : public Runnable { public: PromiseJobRunnable(JSContext* aCx, JS::HandleObject aCallback) diff --git a/xpcom/base/nsConsoleService.cpp b/xpcom/base/nsConsoleService.cpp index 58e88e3746..f98fd542ba 100644 --- a/xpcom/base/nsConsoleService.cpp +++ b/xpcom/base/nsConsoleService.cpp @@ -121,7 +121,7 @@ nsConsoleService::~nsConsoleService() ClearMessages(); } -class AddConsolePrefWatchers : public nsRunnable +class AddConsolePrefWatchers : public Runnable { public: explicit AddConsolePrefWatchers(nsConsoleService* aConsole) : mConsole(aConsole) @@ -161,7 +161,7 @@ nsConsoleService::Init() namespace { -class LogMessageRunnable : public nsRunnable +class LogMessageRunnable : public Runnable { public: LogMessageRunnable(nsIConsoleMessage* aMessage, nsConsoleService* aService) diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index e68af661f5..b1b74492f9 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -3066,7 +3066,7 @@ nsCycleCollector::ScanIncrementalRoots() // If the object is still marked gray by the GC, nothing could have gotten // hold of it, so it isn't an incremental root. if (pi->mParticipant == jsParticipant) { - JS::GCCellPtr ptr(pi->mPointer, js::GCThingTraceKind(pi->mPointer)); + JS::GCCellPtr ptr(pi->mPointer, JS::GCThingTraceKind(pi->mPointer)); if (GCThingIsGrayCCThing(ptr)) { continue; } @@ -3279,7 +3279,7 @@ nsCycleCollector::CollectWhite() ++numWhiteJSZones; zone = static_cast(pinfo->mPointer); } else { - JS::GCCellPtr ptr(pinfo->mPointer, js::GCThingTraceKind(pinfo->mPointer)); + JS::GCCellPtr ptr(pinfo->mPointer, JS::GCThingTraceKind(pinfo->mPointer)); zone = JS::GetTenuredGCThingZone(ptr); } mJSRuntime->AddZoneWaitingForGC(zone); diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp index 0983990e6a..46b8863971 100644 --- a/xpcom/base/nsMemoryInfoDumper.cpp +++ b/xpcom/base/nsMemoryInfoDumper.cpp @@ -57,7 +57,7 @@ using namespace mozilla::dom; namespace { -class DumpMemoryInfoToTempDirRunnable : public nsRunnable +class DumpMemoryInfoToTempDirRunnable : public Runnable { public: DumpMemoryInfoToTempDirRunnable(const nsAString& aIdentifier, @@ -84,7 +84,7 @@ private: }; class GCAndCCLogDumpRunnable final - : public nsRunnable + : public Runnable , public nsIDumpGCAndCCLogsCallback { public: @@ -127,7 +127,7 @@ private: const bool mDumpChildProcesses; }; -NS_IMPL_ISUPPORTS_INHERITED(GCAndCCLogDumpRunnable, nsRunnable, +NS_IMPL_ISUPPORTS_INHERITED(GCAndCCLogDumpRunnable, Runnable, nsIDumpGCAndCCLogsCallback) } // namespace diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 6b540fd872..c48c18a59c 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -2523,7 +2523,7 @@ namespace { * When this sequence finishes, we invoke the callback function passed to the * runnable's constructor. */ -class MinimizeMemoryUsageRunnable : public nsRunnable +class MinimizeMemoryUsageRunnable : public Runnable { public: explicit MinimizeMemoryUsageRunnable(nsIRunnable* aCallback) diff --git a/xpcom/base/nsStatusReporterManager.cpp b/xpcom/base/nsStatusReporterManager.cpp index 565263b6ea..86b5e5b02b 100644 --- a/xpcom/base/nsStatusReporterManager.cpp +++ b/xpcom/base/nsStatusReporterManager.cpp @@ -28,7 +28,7 @@ #ifdef DO_STATUS_REPORT // { namespace { -class DumpStatusInfoToTempDirRunnable : public nsRunnable +class DumpStatusInfoToTempDirRunnable : public mozilla::Runnable { public: DumpStatusInfoToTempDirRunnable() diff --git a/xpcom/components/nsCategoryManager.cpp b/xpcom/components/nsCategoryManager.cpp index 1eecffc6fd..042305cee7 100644 --- a/xpcom/components/nsCategoryManager.cpp +++ b/xpcom/components/nsCategoryManager.cpp @@ -471,7 +471,7 @@ nsCategoryManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) namespace { -class CategoryNotificationRunnable : public nsRunnable +class CategoryNotificationRunnable : public Runnable { public: CategoryNotificationRunnable(nsISupports* aSubject, diff --git a/xpcom/components/nsNativeModuleLoader.cpp b/xpcom/components/nsNativeModuleLoader.cpp index 7c9e331e91..e10c032b92 100644 --- a/xpcom/components/nsNativeModuleLoader.cpp +++ b/xpcom/components/nsNativeModuleLoader.cpp @@ -55,7 +55,7 @@ nsNativeModuleLoader::Init() return NS_OK; } -class LoadModuleMainThreadRunnable : public nsRunnable +class LoadModuleMainThreadRunnable : public Runnable { public: LoadModuleMainThreadRunnable(nsNativeModuleLoader* aLoader, diff --git a/xpcom/ds/Tokenizer.h b/xpcom/ds/Tokenizer.h index 9e8543e24d..831b96b3fb 100644 --- a/xpcom/ds/Tokenizer.h +++ b/xpcom/ds/Tokenizer.h @@ -115,7 +115,7 @@ public: * to Next() reads another token from the input and shifts the cursor. * Returns false if we have passed the end of the input. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool Next(Token& aToken); /** @@ -123,21 +123,21 @@ public: * and if so, put it into aResult, shift the cursor and return true. Otherwise, leave * the input read cursor position intact and return false. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool Check(const TokenType aTokenType, Token& aResult); /** * Same as above method, just compares both token type and token value passed in aToken. * When both the type and the value equals, shift the cursor and return true. Otherwise * return false. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool Check(const Token& aToken); /** * Return false iff the last Check*() call has returned false or when we've read past * the end of the input string. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool HasFailed() const; /** @@ -166,13 +166,13 @@ public: /** * Check whitespace character is present. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool CheckWhite() { return Check(Token::Whitespace()); } /** * Check there is a single character on the read cursor position. If so, shift the read * cursor position and return true. Otherwise false. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool CheckChar(const char aChar) { return Check(Token::Char(aChar)); } /** * This is a customizable version of CheckChar. aClassifier is a function called with @@ -181,29 +181,29 @@ public: * The user classifiction function is not called when we are at or past the end and * false is immediately returned. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool CheckChar(bool (*aClassifier)(const char aChar)); /** * Check for a whole expected word. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool CheckWord(const nsACString& aWord) { return Check(Token::Word(aWord)); } /** * Shortcut for literal const word check with compile time length calculation. */ template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool CheckWord(const char (&aWord)[N]) { return Check(Token::Word(nsDependentCString(aWord, N - 1))); } /** * Checks \r, \n or \r\n. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool CheckEOL() { return Check(Token::NewLine()); } /** * Checks we are at the end of the input string reading. If so, shift past the end * and returns true. Otherwise does nothing and returns false. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool CheckEOF() { return Check(Token::EndOfFile()); } /** diff --git a/xpcom/glue/nsBaseHashtable.h b/xpcom/glue/nsBaseHashtable.h index d4a708b161..1976704dc2 100644 --- a/xpcom/glue/nsBaseHashtable.h +++ b/xpcom/glue/nsBaseHashtable.h @@ -127,8 +127,8 @@ public: } } - MOZ_WARN_UNUSED_RESULT bool Put(KeyType aKey, const UserDataType& aData, - const fallible_t&) + MOZ_MUST_USE bool Put(KeyType aKey, const UserDataType& aData, + const fallible_t&) { EntryType* ent = this->PutEntry(aKey); if (!ent) { diff --git a/xpcom/glue/nsDeque.h b/xpcom/glue/nsDeque.h index 86410c7975..d66383687d 100644 --- a/xpcom/glue/nsDeque.h +++ b/xpcom/glue/nsDeque.h @@ -88,7 +88,7 @@ public: } } - MOZ_WARN_UNUSED_RESULT bool Push(void* aItem, const fallible_t&); + MOZ_MUST_USE bool Push(void* aItem, const fallible_t&); /** * Inserts new member at the front of the deque. @@ -102,7 +102,7 @@ public: } } - MOZ_WARN_UNUSED_RESULT bool PushFront(void* aItem, const fallible_t&); + MOZ_MUST_USE bool PushFront(void* aItem, const fallible_t&); /** * Remove and return the last item in the container. diff --git a/xpcom/glue/nsProxyRelease.h b/xpcom/glue/nsProxyRelease.h index 9feb357d60..5586e2e816 100644 --- a/xpcom/glue/nsProxyRelease.h +++ b/xpcom/glue/nsProxyRelease.h @@ -22,7 +22,7 @@ template -class nsProxyReleaseEvent : public nsRunnable +class nsProxyReleaseEvent : public mozilla::Runnable { public: explicit nsProxyReleaseEvent(already_AddRefed aDoomed) diff --git a/xpcom/glue/nsRefPtrHashtable.h b/xpcom/glue/nsRefPtrHashtable.h index cf840b20be..0ff1e0181d 100644 --- a/xpcom/glue/nsRefPtrHashtable.h +++ b/xpcom/glue/nsRefPtrHashtable.h @@ -54,8 +54,8 @@ public: void Put(KeyType aKey, already_AddRefed aData); - MOZ_WARN_UNUSED_RESULT bool Put(KeyType aKey, already_AddRefed aData, - const mozilla::fallible_t&); + MOZ_MUST_USE bool Put(KeyType aKey, already_AddRefed aData, + const mozilla::fallible_t&); // Overload Remove, rather than overriding it. using base_type::Remove; diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index 402ea2db85..b9c427807b 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -1209,7 +1209,7 @@ public: } template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool Assign(const nsTArray_Impl& aOther, const mozilla::fallible_t&) { @@ -1292,7 +1292,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* ReplaceElementsAt(index_type aStart, size_type aCount, const Item* aArray, size_type aArrayLen, const mozilla::fallible_t&) @@ -1313,7 +1313,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* ReplaceElementsAt(index_type aStart, size_type aCount, const nsTArray& aArray, const mozilla::fallible_t&) @@ -1332,7 +1332,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* ReplaceElementsAt(index_type aStart, size_type aCount, const Item& aItem, const mozilla::fallible_t&) { @@ -1357,7 +1357,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* InsertElementsAt(index_type aIndex, const Item* aArray, size_type aArrayLen, const mozilla::fallible_t&) { @@ -1376,7 +1376,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* InsertElementsAt(index_type aIndex, const nsTArray_Impl& aArray, const mozilla::fallible_t&) @@ -1404,7 +1404,7 @@ protected: } public: - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* InsertElementAt(index_type aIndex, const mozilla::fallible_t&) { return InsertElementAt(aIndex); @@ -1429,7 +1429,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* InsertElementAt(index_type aIndex, Item&& aItem, const mozilla::fallible_t&) { @@ -1486,7 +1486,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* InsertElementSorted(Item&& aItem, const Comparator& aComp, const mozilla::fallible_t&) { @@ -1506,7 +1506,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* InsertElementSorted(Item&& aItem, const mozilla::fallible_t&) { return InsertElementSorted( @@ -1534,7 +1534,7 @@ protected: public: template - /* MOZ_WARN_UNUSED_RESULT */ + /* MOZ_MUST_USE */ elem_type* AppendElements(const Item* aArray, size_type aArrayLen, const mozilla::fallible_t&) { @@ -1551,7 +1551,7 @@ protected: public: template - /* MOZ_WARN_UNUSED_RESULT */ + /* MOZ_MUST_USE */ elem_type* AppendElements(const nsTArray_Impl& aArray, const mozilla::fallible_t&) { @@ -1586,7 +1586,7 @@ protected: public: template - /* MOZ_WARN_UNUSED_RESULT */ + /* MOZ_MUST_USE */ elem_type* AppendElements(nsTArray_Impl&& aArray, const mozilla::fallible_t&) { @@ -1611,7 +1611,7 @@ protected: public: template - /* MOZ_WARN_UNUSED_RESULT */ + /* MOZ_MUST_USE */ elem_type* AppendElement(Item&& aItem, const mozilla::fallible_t&) { @@ -1638,7 +1638,7 @@ protected: } public: - /* MOZ_WARN_UNUSED_RESULT */ + /* MOZ_MUST_USE */ elem_type* AppendElements(size_type aCount, const mozilla::fallible_t&) { @@ -1656,7 +1656,7 @@ protected: } public: - /* MOZ_WARN_UNUSED_RESULT */ + /* MOZ_MUST_USE */ elem_type* AppendElement(const mozilla::fallible_t&) { return AppendElement(); @@ -1760,7 +1760,7 @@ protected: } public: - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool SetCapacity(size_type aCapacity, const mozilla::fallible_t&) { return SetCapacity(aCapacity); @@ -1789,7 +1789,7 @@ protected: } public: - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool SetLength(size_type aNewLen, const mozilla::fallible_t&) { return SetLength(aNewLen); @@ -1828,7 +1828,7 @@ protected: } public: - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool EnsureLengthAtLeast(size_type aMinLen, const mozilla::fallible_t&) { return EnsureLengthAtLeast(aMinLen); @@ -1859,7 +1859,7 @@ protected: } public: - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* InsertElementsAt(index_type aIndex, size_type aCount, const mozilla::fallible_t&) { @@ -1895,7 +1895,7 @@ protected: public: template - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE elem_type* InsertElementsAt(index_type aIndex, size_type aCount, const Item& aItem, const mozilla::fallible_t&) { diff --git a/xpcom/glue/nsTHashtable.h b/xpcom/glue/nsTHashtable.h index ba359a51df..c2509e036a 100644 --- a/xpcom/glue/nsTHashtable.h +++ b/xpcom/glue/nsTHashtable.h @@ -153,7 +153,7 @@ public: return static_cast(mTable.Add(EntryType::KeyToPointer(aKey))); } - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE EntryType* PutEntry(KeyType aKey, const fallible_t&) { return static_cast(mTable.Add(EntryType::KeyToPointer(aKey), diff --git a/xpcom/glue/nsThreadUtils.cpp b/xpcom/glue/nsThreadUtils.cpp index 3a0bb986c1..8f80cfebb5 100644 --- a/xpcom/glue/nsThreadUtils.cpp +++ b/xpcom/glue/nsThreadUtils.cpp @@ -32,16 +32,16 @@ using namespace mozilla; #ifndef XPCOM_GLUE_AVOID_NSPR -NS_IMPL_ISUPPORTS(nsRunnable, nsIRunnable) +NS_IMPL_ISUPPORTS(Runnable, nsIRunnable) NS_IMETHODIMP -nsRunnable::Run() +Runnable::Run() { // Do nothing return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED(CancelableRunnable, nsRunnable, +NS_IMPL_ISUPPORTS_INHERITED(CancelableRunnable, Runnable, nsICancelableRunnable) nsresult diff --git a/xpcom/glue/nsThreadUtils.h b/xpcom/glue/nsThreadUtils.h index 3b98aded32..b9bb171ab1 100644 --- a/xpcom/glue/nsThreadUtils.h +++ b/xpcom/glue/nsThreadUtils.h @@ -219,22 +219,24 @@ extern nsIThread* NS_GetCurrentThread(); #ifndef XPCOM_GLUE_AVOID_NSPR +namespace mozilla { + // This class is designed to be subclassed. -class nsRunnable : public nsIRunnable +class Runnable : public nsIRunnable { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIRUNNABLE - nsRunnable() {} + Runnable() {} protected: - virtual ~nsRunnable() {} + virtual ~Runnable() {} }; // This class is designed to be subclassed. -class CancelableRunnable : public nsRunnable, - public nsICancelableRunnable +class CancelableRunnable : public Runnable, + public nsICancelableRunnable { public: NS_DECL_ISUPPORTS_INHERITED @@ -247,11 +249,13 @@ protected: virtual ~CancelableRunnable() {} }; +} // namespace mozilla + // An event that can be used to call a C++11 functions or function objects, // including lambdas. The function must have no required arguments, and must // return void. template -class nsRunnableFunction : public nsRunnable +class nsRunnableFunction : public mozilla::Runnable { public: explicit nsRunnableFunction(const Function& aFunction) @@ -280,7 +284,7 @@ nsRunnableFunction* NS_NewRunnableFunction(const Function& aFunction) template -class nsRunnableMethod : public nsRunnable +class nsRunnableMethod : public mozilla::Runnable { public: virtual void Revoke() = 0; @@ -780,7 +784,7 @@ NS_NewNonOwningRunnableMethodWithArgs(PtrType&& aPtr, Method aMethod, // // class R; // -// class E : public nsRunnable { +// class E : public mozilla::Runnable { // public: // void Revoke() { // mResource = nullptr; diff --git a/xpcom/io/nsAnonymousTemporaryFile.cpp b/xpcom/io/nsAnonymousTemporaryFile.cpp index f0223ad7d1..2ef219fe31 100644 --- a/xpcom/io/nsAnonymousTemporaryFile.cpp +++ b/xpcom/io/nsAnonymousTemporaryFile.cpp @@ -85,7 +85,7 @@ GetTempDir(nsIFile** aTempDir) namespace { -class nsRemoteAnonymousTemporaryFileRunnable : public nsRunnable +class nsRemoteAnonymousTemporaryFileRunnable : public Runnable { public: dom::FileDescOrError *mResultPtr; diff --git a/xpcom/io/nsInputStreamTee.cpp b/xpcom/io/nsInputStreamTee.cpp index 6d2ae8df3a..1d01fdb940 100644 --- a/xpcom/io/nsInputStreamTee.cpp +++ b/xpcom/io/nsInputStreamTee.cpp @@ -57,7 +57,7 @@ private: bool mSinkIsValid; // False if TeeWriteEvent fails }; -class nsInputStreamTeeWriteEvent : public nsRunnable +class nsInputStreamTeeWriteEvent : public Runnable { public: // aTee's lock is held across construction of this object diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index e8b5c5be1d..aa908d6eab 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -78,7 +78,7 @@ using namespace mozilla; * A runnable to dispatch back to the main thread when * AsyncLocalFileWinOperation completes. */ -class AsyncLocalFileWinDone : public nsRunnable +class AsyncLocalFileWinDone : public Runnable { public: AsyncLocalFileWinDone() : @@ -107,7 +107,7 @@ private: * A runnable to dispatch from the main thread when an async operation should * be performed. */ -class AsyncLocalFileWinOperation : public nsRunnable +class AsyncLocalFileWinOperation : public Runnable { public: enum FileOp { RevealOp, LaunchOp }; diff --git a/xpcom/string/nsReadableUtils.h b/xpcom/string/nsReadableUtils.h index a016e8528a..24824d9278 100644 --- a/xpcom/string/nsReadableUtils.h +++ b/xpcom/string/nsReadableUtils.h @@ -40,9 +40,8 @@ void LossyCopyUTF16toASCII(const char16ptr_t aSource, nsACString& aDest); void CopyASCIItoUTF16(const char* aSource, nsAString& aDest); void CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest); -MOZ_WARN_UNUSED_RESULT bool CopyUTF16toUTF8(const nsAString& aSource, - nsACString& aDest, - const mozilla::fallible_t&); +MOZ_MUST_USE bool CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest, + const mozilla::fallible_t&); void CopyUTF8toUTF16(const nsACString& aSource, nsAString& aDest); void CopyUTF16toUTF8(const char16ptr_t aSource, nsACString& aDest); @@ -50,24 +49,24 @@ void CopyUTF8toUTF16(const char* aSource, nsAString& aDest); void LossyAppendUTF16toASCII(const nsAString& aSource, nsACString& aDest); void AppendASCIItoUTF16(const nsACString& aSource, nsAString& aDest); -MOZ_WARN_UNUSED_RESULT bool AppendASCIItoUTF16(const nsACString& aSource, - nsAString& aDest, - const mozilla::fallible_t&); +MOZ_MUST_USE bool AppendASCIItoUTF16(const nsACString& aSource, + nsAString& aDest, + const mozilla::fallible_t&); void LossyAppendUTF16toASCII(const char16ptr_t aSource, nsACString& aDest); -MOZ_WARN_UNUSED_RESULT bool AppendASCIItoUTF16(const char* aSource, - nsAString& aDest, - const mozilla::fallible_t&); +MOZ_MUST_USE bool AppendASCIItoUTF16(const char* aSource, + nsAString& aDest, + const mozilla::fallible_t&); void AppendASCIItoUTF16(const char* aSource, nsAString& aDest); void AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest); -MOZ_WARN_UNUSED_RESULT bool AppendUTF16toUTF8(const nsAString& aSource, - nsACString& aDest, - const mozilla::fallible_t&); +MOZ_MUST_USE bool AppendUTF16toUTF8(const nsAString& aSource, + nsACString& aDest, + const mozilla::fallible_t&); void AppendUTF8toUTF16(const nsACString& aSource, nsAString& aDest); -MOZ_WARN_UNUSED_RESULT bool AppendUTF8toUTF16(const nsACString& aSource, - nsAString& aDest, - const mozilla::fallible_t&); +MOZ_MUST_USE bool AppendUTF8toUTF16(const nsACString& aSource, + nsAString& aDest, + const mozilla::fallible_t&); void AppendUTF16toUTF8(const char16ptr_t aSource, nsACString& aDest); void AppendUTF8toUTF16(const char* aSource, nsAString& aDest); diff --git a/xpcom/string/nsTString.h b/xpcom/string/nsTString.h index 8b1072beb1..a558a5864b 100644 --- a/xpcom/string/nsTString.h +++ b/xpcom/string/nsTString.h @@ -393,12 +393,12 @@ public: */ void ReplaceSubstring(const self_type& aTarget, const self_type& aNewValue); void ReplaceSubstring(const char_type* aTarget, const char_type* aNewValue); - MOZ_WARN_UNUSED_RESULT bool ReplaceSubstring(const self_type& aTarget, - const self_type& aNewValue, - const fallible_t&); - MOZ_WARN_UNUSED_RESULT bool ReplaceSubstring(const char_type* aTarget, - const char_type* aNewValue, - const fallible_t&); + MOZ_MUST_USE bool ReplaceSubstring(const self_type& aTarget, + const self_type& aNewValue, + const fallible_t&); + MOZ_MUST_USE bool ReplaceSubstring(const char_type* aTarget, + const char_type* aNewValue, + const fallible_t&); /** diff --git a/xpcom/string/nsTSubstring.h b/xpcom/string/nsTSubstring.h index a04654f5a3..7606d27baf 100644 --- a/xpcom/string/nsTSubstring.h +++ b/xpcom/string/nsTSubstring.h @@ -361,25 +361,22 @@ public: */ void NS_FASTCALL Assign(char_type aChar); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(char_type aChar, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL Assign(char_type aChar, const fallible_t&); void NS_FASTCALL Assign(const char_type* aData); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(const char_type* aData, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL Assign(const char_type* aData, + const fallible_t&); void NS_FASTCALL Assign(const char_type* aData, size_type aLength); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(const char_type* aData, - size_type aLength, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL Assign(const char_type* aData, + size_type aLength, const fallible_t&); void NS_FASTCALL Assign(const self_type&); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(const self_type&, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL Assign(const self_type&, const fallible_t&); void NS_FASTCALL Assign(const substring_tuple_type&); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(const substring_tuple_type&, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL Assign(const substring_tuple_type&, + const fallible_t&); #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) void Assign(char16ptr_t aData) @@ -392,8 +389,8 @@ public: Assign(static_cast(aData), aLength); } - MOZ_WARN_UNUSED_RESULT bool Assign(char16ptr_t aData, size_type aLength, - const fallible_t& aFallible) + MOZ_MUST_USE bool Assign(char16ptr_t aData, size_type aLength, + const fallible_t& aFallible) { return Assign(static_cast(aData), aLength, aFallible); @@ -401,16 +398,16 @@ public: #endif void NS_FASTCALL AssignASCII(const char* aData, size_type aLength); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL AssignASCII(const char* aData, - size_type aLength, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL AssignASCII(const char* aData, + size_type aLength, + const fallible_t&); void NS_FASTCALL AssignASCII(const char* aData) { AssignASCII(aData, mozilla::AssertedCast(strlen(aData))); } - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL AssignASCII(const char* aData, - const fallible_t& aFallible) + MOZ_MUST_USE bool NS_FASTCALL AssignASCII(const char* aData, + const fallible_t& aFallible) { return AssignASCII(aData, mozilla::AssertedCast(strlen(aData)), @@ -473,27 +470,27 @@ public: void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength, char_type aChar); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL Replace(index_type aCutStart, - size_type aCutLength, - char_type aChar, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL Replace(index_type aCutStart, + size_type aCutLength, + char_type aChar, + const fallible_t&); void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength, const char_type* aData, size_type aLength = size_type(-1)); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL Replace(index_type aCutStart, - size_type aCutLength, - const char_type* aData, - size_type aLength, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL Replace(index_type aCutStart, + size_type aCutLength, + const char_type* aData, + size_type aLength, + const fallible_t&); void Replace(index_type aCutStart, size_type aCutLength, const self_type& aStr) { Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length()); } - MOZ_WARN_UNUSED_RESULT bool Replace(index_type aCutStart, - size_type aCutLength, - const self_type& aStr, - const fallible_t& aFallible) + MOZ_MUST_USE bool Replace(index_type aCutStart, + size_type aCutLength, + const self_type& aStr, + const fallible_t& aFallible) { return Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length(), aFallible); @@ -505,10 +502,10 @@ public: const char* aData, size_type aLength = size_type(-1)); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL ReplaceASCII(index_type aCutStart, size_type aCutLength, - const char* aData, - size_type aLength, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL ReplaceASCII(index_type aCutStart, size_type aCutLength, + const char* aData, + size_type aLength, + const fallible_t&); // ReplaceLiteral must ONLY be applied to an actual literal string. // Do not attempt to use it with a regular char* pointer, or with a char @@ -524,8 +521,7 @@ public: { Replace(mLength, 0, aChar); } - MOZ_WARN_UNUSED_RESULT bool Append(char_type aChar, - const fallible_t& aFallible) + MOZ_MUST_USE bool Append(char_type aChar, const fallible_t& aFallible) { return Replace(mLength, 0, aChar, aFallible); } @@ -533,8 +529,8 @@ public: { Replace(mLength, 0, aData, aLength); } - MOZ_WARN_UNUSED_RESULT bool Append(const char_type* aData, size_type aLength, - const fallible_t& aFallible) + MOZ_MUST_USE bool Append(const char_type* aData, size_type aLength, + const fallible_t& aFallible) { return Replace(mLength, 0, aData, aLength, aFallible); } @@ -550,7 +546,7 @@ public: { Replace(mLength, 0, aStr); } - MOZ_WARN_UNUSED_RESULT bool Append(const self_type& aStr, const fallible_t& aFallible) + MOZ_MUST_USE bool Append(const self_type& aStr, const fallible_t& aFallible) { return Replace(mLength, 0, aStr, aFallible); } @@ -564,12 +560,12 @@ public: ReplaceASCII(mLength, 0, aData, aLength); } - MOZ_WARN_UNUSED_RESULT bool AppendASCII(const char* aData, const fallible_t& aFallible) + MOZ_MUST_USE bool AppendASCII(const char* aData, const fallible_t& aFallible) { return ReplaceASCII(mLength, 0, aData, size_type(-1), aFallible); } - MOZ_WARN_UNUSED_RESULT bool AppendASCII(const char* aData, size_type aLength, const fallible_t& aFallible) + MOZ_MUST_USE bool AppendASCII(const char* aData, size_type aLength, const fallible_t& aFallible) { return ReplaceASCII(mLength, 0, aData, aLength, aFallible); } @@ -640,7 +636,7 @@ public: } template - MOZ_WARN_UNUSED_RESULT bool AppendLiteral(const char (&aStr)[N], const fallible_t& aFallible) + MOZ_MUST_USE bool AppendLiteral(const char (&aStr)[N], const fallible_t& aFallible) { return AppendASCII(aStr, N - 1, aFallible); } @@ -726,12 +722,12 @@ public: * Also ensures that the buffer is mutable. */ void NS_FASTCALL SetCapacity(size_type aNewCapacity); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL SetCapacity(size_type aNewCapacity, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL SetCapacity(size_type aNewCapacity, + const fallible_t&); void NS_FASTCALL SetLength(size_type aNewLength); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL SetLength(size_type aNewLength, - const fallible_t&); + MOZ_MUST_USE bool NS_FASTCALL SetLength(size_type aNewLength, + const fallible_t&); void Truncate(size_type aNewLength = 0) { @@ -991,11 +987,11 @@ protected: * this function returns false if is unable to allocate sufficient * memory. */ - MOZ_WARN_UNUSED_RESULT bool ReplacePrep(index_type aCutStart, - size_type aCutLength, - size_type aNewLength); + MOZ_MUST_USE bool ReplacePrep(index_type aCutStart, + size_type aCutLength, + size_type aNewLength); - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL ReplacePrepInternal( + MOZ_MUST_USE bool NS_FASTCALL ReplacePrepInternal( index_type aCutStart, size_type aCutLength, size_type aNewFragLength, @@ -1014,7 +1010,7 @@ protected: * this helper function can be called prior to directly manipulating * the contents of mData. see, for example, BeginWriting. */ - MOZ_WARN_UNUSED_RESULT bool NS_FASTCALL EnsureMutable( + MOZ_MUST_USE bool NS_FASTCALL EnsureMutable( size_type aNewLen = size_type(-1)); /** diff --git a/xpcom/tests/TestRacingServiceManager.cpp b/xpcom/tests/TestRacingServiceManager.cpp index 867c699d71..0026d2dd07 100644 --- a/xpcom/tests/TestRacingServiceManager.cpp +++ b/xpcom/tests/TestRacingServiceManager.cpp @@ -186,18 +186,18 @@ Factory::CreateInstance(nsISupports* aDelegate, return NS_OK; } -class Runnable : public nsRunnable +class TestRunnable : public Runnable { public: NS_DECL_NSIRUNNABLE - Runnable() : mFirstRunnableDone(false) { } + TestRunnable() : mFirstRunnableDone(false) { } bool mFirstRunnableDone; }; NS_IMETHODIMP -Runnable::Run() +TestRunnable::Run() { { ReentrantMonitorAutoEnter mon(*gReentrantMonitor); @@ -261,7 +261,7 @@ int main(int argc, char** argv) AutoCreateAndDestroyReentrantMonitor mon1(&gReentrantMonitor); - RefPtr runnable = new Runnable(); + RefPtr runnable = new TestRunnable(); NS_ENSURE_TRUE(runnable, 1); // Run the classID test diff --git a/xpcom/tests/TestThreadPoolListener.cpp b/xpcom/tests/TestThreadPoolListener.cpp index e0f8c2b370..e81cdc93a3 100644 --- a/xpcom/tests/TestThreadPoolListener.cpp +++ b/xpcom/tests/TestThreadPoolListener.cpp @@ -169,7 +169,7 @@ int main(int argc, char** argv) ReentrantMonitorAutoEnter mon(*gReentrantMonitor); for (uint32_t i = 0; i < NUMBER_OF_THREADS; i++) { - nsCOMPtr runnable = new nsRunnable(); + nsCOMPtr runnable = new Runnable(); NS_ENSURE_TRUE(runnable, 1); rv = pool->Dispatch(runnable, NS_DISPATCH_NORMAL); diff --git a/xpcom/tests/TestThreadUtils.cpp b/xpcom/tests/TestThreadUtils.cpp index c180545725..e26f9d6821 100644 --- a/xpcom/tests/TestThreadUtils.cpp +++ b/xpcom/tests/TestThreadUtils.cpp @@ -38,7 +38,7 @@ private: NS_IMPL_ISUPPORTS0(nsFoo) -class TestSuicide : public nsRunnable { +class TestSuicide : public mozilla::Runnable { NS_IMETHOD Run() { // Runs first time on thread "Suicide", then dies on MainThread if (!NS_IsMainThread()) { diff --git a/xpcom/tests/TestTimers.cpp b/xpcom/tests/TestTimers.cpp index 339592cd8a..a07ae90ed7 100644 --- a/xpcom/tests/TestTimers.cpp +++ b/xpcom/tests/TestTimers.cpp @@ -181,7 +181,7 @@ class FuzzTestThreadState final : public nsITimerCallback { mStopped(false) {} - class StartRunnable final : public nsRunnable { + class StartRunnable final : public mozilla::Runnable { public: explicit StartRunnable(FuzzTestThreadState* threadState) : mThreadState(threadState) diff --git a/xpcom/tests/gtest/TestThreadPool.cpp b/xpcom/tests/gtest/TestThreadPool.cpp index b0ce54c3ab..56abf7608d 100644 --- a/xpcom/tests/gtest/TestThreadPool.cpp +++ b/xpcom/tests/gtest/TestThreadPool.cpp @@ -69,11 +69,11 @@ TEST(ThreadPool, Parallelism) EXPECT_TRUE(pool); // Dispatch and sleep to ensure we have an idle thread - nsCOMPtr r0 = new nsRunnable(); + nsCOMPtr r0 = new Runnable(); pool->Dispatch(r0, NS_DISPATCH_SYNC); PR_Sleep(PR_SecondsToInterval(2)); - class Runnable1 : public nsRunnable { + class Runnable1 : public Runnable { public: Runnable1(Monitor& aMonitor, bool& aDone) : mMonitor(aMonitor), mDone(aDone) {} @@ -93,7 +93,7 @@ TEST(ThreadPool, Parallelism) bool& mDone; }; - class Runnable2 : public nsRunnable { + class Runnable2 : public Runnable { public: Runnable2(Monitor& aMonitor, bool& aDone) : mMonitor(aMonitor), mDone(aDone) {} diff --git a/xpcom/threads/LazyIdleThread.cpp b/xpcom/threads/LazyIdleThread.cpp index d65dfd3031..43d8857aa1 100644 --- a/xpcom/threads/LazyIdleThread.cpp +++ b/xpcom/threads/LazyIdleThread.cpp @@ -108,7 +108,7 @@ LazyIdleThread::EnableIdleTimeout() } if (mThread) { - nsCOMPtr runnable(new nsRunnable()); + nsCOMPtr runnable(new Runnable()); if (NS_FAILED(Dispatch(runnable.forget(), NS_DISPATCH_NORMAL))) { NS_WARNING("Failed to dispatch!"); } diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index 836f9fe1d1..bf1775a6a3 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -307,7 +307,7 @@ protected: class ThenValueBase : public Request { public: - class ResolveOrRejectRunnable : public nsRunnable + class ResolveOrRejectRunnable : public Runnable { public: ResolveOrRejectRunnable(ThenValueBase* aThenValue, MozPromise* aPromise) @@ -373,8 +373,8 @@ protected: aPromise->mMutex.AssertCurrentThreadOwns(); MOZ_ASSERT(!aPromise->IsPending()); - RefPtr runnable = - static_cast(new (typename ThenValueBase::ResolveOrRejectRunnable)(this, aPromise)); + RefPtr runnable = + static_cast(new (typename ThenValueBase::ResolveOrRejectRunnable)(this, aPromise)); PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]", aPromise->mValue.IsResolve() ? "Resolving" : "Rejecting", ThenValueBase::mCallSite, runnable.get(), aPromise, this); @@ -956,7 +956,7 @@ private: }; template -class ProxyRunnable : public nsRunnable +class ProxyRunnable : public Runnable { public: ProxyRunnable(typename PromiseType::Private* aProxyPromise, MethodCall* aMethodCall) diff --git a/xpcom/threads/SyncRunnable.h b/xpcom/threads/SyncRunnable.h index 7936016b0e..9c493d9dcc 100644 --- a/xpcom/threads/SyncRunnable.h +++ b/xpcom/threads/SyncRunnable.h @@ -28,7 +28,7 @@ namespace mozilla { * SyncRunnable::DispatchToThread(new myrunnable...()); * */ -class SyncRunnable : public nsRunnable +class SyncRunnable : public Runnable { public: explicit SyncRunnable(nsIRunnable* aRunnable) diff --git a/xpcom/threads/TaskDispatcher.h b/xpcom/threads/TaskDispatcher.h index d7005c35bc..6fccd991f1 100644 --- a/xpcom/threads/TaskDispatcher.h +++ b/xpcom/threads/TaskDispatcher.h @@ -169,7 +169,7 @@ private: AbstractThread::DispatchFailureHandling mFailureHandling; }; - class TaskGroupRunnable : public nsRunnable + class TaskGroupRunnable : public Runnable { public: explicit TaskGroupRunnable(UniquePtr&& aTasks) : mTasks(Move(aTasks)) {} diff --git a/xpcom/threads/TaskQueue.h b/xpcom/threads/TaskQueue.h index 279652f668..6f40cfe3fc 100644 --- a/xpcom/threads/TaskQueue.h +++ b/xpcom/threads/TaskQueue.h @@ -167,7 +167,7 @@ protected: // True if we're flushing; we reject new tasks if we're flushing. bool mIsFlushing; - class Runner : public nsRunnable { + class Runner : public Runnable { public: explicit Runner(TaskQueue* aQueue) : mQueue(aQueue) diff --git a/xpcom/threads/TimerThread.cpp b/xpcom/threads/TimerThread.cpp index 3189967c89..29ebbfcdca 100644 --- a/xpcom/threads/TimerThread.cpp +++ b/xpcom/threads/TimerThread.cpp @@ -54,7 +54,7 @@ TimerThread::InitLocks() namespace { -class TimerObserverRunnable : public nsRunnable +class TimerObserverRunnable : public Runnable { public: explicit TimerObserverRunnable(nsIObserver* aObserver) diff --git a/xpcom/threads/nsMemoryPressure.cpp b/xpcom/threads/nsMemoryPressure.cpp index 18e71b48be..fea9b04378 100644 --- a/xpcom/threads/nsMemoryPressure.cpp +++ b/xpcom/threads/nsMemoryPressure.cpp @@ -49,6 +49,6 @@ nsresult NS_DispatchMemoryPressure(MemoryPressureState aState) { NS_DispatchEventualMemoryPressure(aState); - nsCOMPtr event = new nsRunnable; + nsCOMPtr event = new Runnable; return NS_DispatchToMainThread(event); } diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 008c3bcdc0..56bbc84181 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -190,7 +190,7 @@ NS_IMPL_CI_INTERFACE_GETTER(nsThread, nsIThread, nsIThreadInternal, //----------------------------------------------------------------------------- -class nsThreadStartupEvent : public nsRunnable +class nsThreadStartupEvent : public Runnable { public: nsThreadStartupEvent() @@ -254,15 +254,13 @@ struct nsThreadShutdownContext // to call PR_JoinThread. It implements nsICancelableRunnable so that it can // run on a DOM Worker thread (where all events must implement // nsICancelableRunnable.) -class nsThreadShutdownAckEvent : public nsRunnable, - public nsICancelableRunnable +class nsThreadShutdownAckEvent : public CancelableRunnable { public: explicit nsThreadShutdownAckEvent(nsThreadShutdownContext* aCtx) : mShutdownContext(aCtx) { } - NS_DECL_ISUPPORTS_INHERITED NS_IMETHOD Run() override { mShutdownContext->terminatingThread->ShutdownComplete(mShutdownContext); @@ -278,11 +276,8 @@ private: nsThreadShutdownContext* mShutdownContext; }; -NS_IMPL_ISUPPORTS_INHERITED(nsThreadShutdownAckEvent, nsRunnable, - nsICancelableRunnable) - // This event is responsible for setting mShutdownContext -class nsThreadShutdownEvent : public nsRunnable +class nsThreadShutdownEvent : public Runnable { public: nsThreadShutdownEvent(nsThread* aThr, nsThreadShutdownContext* aCtx) diff --git a/xpcom/threads/nsThreadSyncDispatch.h b/xpcom/threads/nsThreadSyncDispatch.h index 5e010f6d40..ae5e854640 100644 --- a/xpcom/threads/nsThreadSyncDispatch.h +++ b/xpcom/threads/nsThreadSyncDispatch.h @@ -11,7 +11,7 @@ #include "LeakRefPtr.h" #include "mozilla/DebugOnly.h" -class nsThreadSyncDispatch : public nsRunnable +class nsThreadSyncDispatch : public mozilla::Runnable { public: nsThreadSyncDispatch(nsIThread* aOrigin, already_AddRefed&& aTask) diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index 74c6b9ff0c..e5a6a938ed 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -409,7 +409,7 @@ WebBrowserChrome2Stub::Blur() return NS_ERROR_NOT_IMPLEMENTED; } -class BrowserDestroyer final : public nsRunnable +class BrowserDestroyer final : public Runnable { public: BrowserDestroyer(nsIWebBrowser *aBrowser, nsISupports *aContainer) : diff --git a/xpfe/appshell/nsContentTreeOwner.cpp b/xpfe/appshell/nsContentTreeOwner.cpp index 0ca5749b48..f839064c32 100644 --- a/xpfe/appshell/nsContentTreeOwner.cpp +++ b/xpfe/appshell/nsContentTreeOwner.cpp @@ -962,7 +962,7 @@ nsContentTreeOwner::ProvideWindow(nsIDOMWindow* aParent, //***************************************************************************** #if defined(XP_MACOSX) -class nsContentTitleSettingEvent : public nsRunnable +class nsContentTitleSettingEvent : public Runnable { public: nsContentTitleSettingEvent(dom::Element* dse, const nsAString& wtm)